lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 8 Jul 2010 15:56:07 +0800
From:	"Neco.F" <necofang@...il.com>
To:	linux-kernel@...r.kernel.org, netfilter@...r.kernel.org,
	netfilter-devel@...r.kernel.org
Subject: about conntrack for oracle tns

hi,
  I have a conntrack module for oracle tns. the kernel version is 2.6.26.5.
 sometimes when I use this module to access the oracle server, the kernel panic.
 panic info: EIP:[xxx] get_next_timer_interrupt...........

 my source:

 #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netfilter.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <net/checksum.h>
#include <net/tcp.h>
#include "conntrack_tns.h"
#include "debug.h"

#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_nat_helper.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Neco Fang <necofang@...mail.com>");
MODULE_DESCRIPTION("oracle tns connection tracking helper");
MODULE_ALIAS("ip_conntrack_tns");

static char *tns_buffer = NULL;

static DEFINE_SPINLOCK(nf_tns_lock);

static u_int16_t ports[MAX_PORTS];
static unsigned int ports_c;
module_param_array(ports, ushort, &ports_c, 0400);

static int mangle_packet (struct sk_buff *skb,
			  __be32 newip,
			  u_int16_t port,
			  unsigned int matchoff,
			  unsigned int matchlen,
			  struct nf_conn *ct,
			  enum ip_conntrack_info ctinfo)
{
  char buffer[128];
  struct tnshdr_redirect * ptnshdr = (struct tnshdr_redirect * )buffer;

  sprintf (ptnshdr->datas,
"(ADDRESS=(PROTOCOL=tcp)(HOST=%u.%u.%u.%u)(PORT=%u))", NIPQUAD(newip),
port);
  ptnshdr->pkt_len = htons (sizeof (struct tnshdr_redirect) +
strlen(ptnshdr->datas) - 1);
  ptnshdr->pkt_checksum = 0x00;
  ptnshdr->tns_type = NF_CT_TNS_REDIRECT;
  ptnshdr->pkt_flags = 0;
  ptnshdr->head_checksum = 0x00;
  ptnshdr->data_len = htons (strlen(ptnshdr->datas));

  TNS_PRINT ("calling nf_nat_mangle_tcp_packet (%s) matchoff: %u
matchlen: %u", ptnshdr->datas, matchoff, matchlen);

  return (nf_nat_mangle_tcp_packet (skb, ct, ctinfo, matchoff,
matchlen, buffer, sizeof (struct
tnshdr_redirect)+strlen(ptnshdr->datas)-1));
}

static u_int nf_nat_tns (struct sk_buff *skb,
			 enum ip_conntrack_info ctinfo,
			 unsigned int matchoff,
			 unsigned int matchlen,
			 struct nf_conntrack_expect *exp)
{
  __be32 newip;
  u_int16_t port;
  struct nf_conn *ct = exp->master;
  enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);

  newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
  exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;

  exp->dir = !dir;

  exp->expectfn = nf_nat_follow_master;

  TNS_PRINT ("exp->saved_proto.tcp.port: %u exp->tuple.src.u.tcp.port:
%u exp->tuple.dst.u.tcp.port: %u exp->dir: %u",
                 ntohs (exp->saved_proto.tcp.port),
                 ntohs (exp->tuple.src.u.tcp.port),
                 ntohs (exp->tuple.dst.u.tcp.port),
                 exp->dir);

  for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
    exp->tuple.dst.u.tcp.port = htons(port);
    TNS_PRINT ("tuple %p: %u " NIPQUAD_FMT ":%hu -> " NIPQUAD_FMT ":%hu",
		   &exp->tuple, exp->tuple.dst.protonum,
		   NIPQUAD(exp->tuple.src.u3.ip), ntohs(exp->tuple.src.u.all),
		   NIPQUAD(exp->tuple.dst.u3.ip), ntohs(exp->tuple.dst.u.all));

    if (0 == nf_ct_expect_related(exp)) {TNS_PRINT
("nf_ct_expect_related succ"); break;}
  }

  if (0 == port) return NF_DROP;

  if (!mangle_packet (skb, newip, port, matchoff, matchlen, ct, ctinfo)) {
    TNS_PRINT ("mangle packet failed, nf_ct_unexpect_related");
    nf_ct_unexpect_related(exp);
    return NF_DROP;
  }
  return NF_ACCEPT;
}

/* Return 1 for match, 0 for accept*/
static int find_pattern (const char *data, size_t dlen, struct
nf_conntrack_man *cmd, u_int * matchoff, u_int * matchlen)
{
  struct tnshdr_redirect * ptnshdr = (struct tnshdr_redirect*) data;
  int len = 0;
  int level = 1;
  __be16 port = 0;
  char * data_ptr = NULL;

  //check TNS TYPE
  if (NF_CT_TNS_REDIRECT != ptnshdr->tns_type) {
    TNS_PRINT ("current data is not tns packet");
    return (0);
  }

  *matchoff = 0;
  *matchlen = ntohs (ptnshdr->pkt_len);

  data_ptr =  (char*)data + dlen - 1;
  port = 0;
  for (len = 0; len < dlen; len++, data_ptr--) {
    if ('=' == *data_ptr) break;
    if (*data_ptr >= '0' && *data_ptr <= '9') {
      port = port + (*data_ptr -'0') * level;
      level *= 10;
    }
  }

  cmd->u.tcp.port = htons (port);

  TNS_PRINT ("ip = "NIPQUAD_FMT" port = %u", NIPQUAD(cmd->u3.ip), port);
  return ((0==port) ? 0 : 1);
}

static int help (struct sk_buff *skb,
		 unsigned int protoff,
		 struct nf_conn *ct,
		 enum ip_conntrack_info ctinfo)
{
  u_int dataoff = 0, datalen = 0;
  const struct tcphdr *th = NULL;
  struct tcphdr _tcph;
  const char *buf_ptr = NULL;
  int ret = NF_ACCEPT;
  int found = 0;
  struct nf_conntrack_expect * exp = NULL;
  u_int matchlen = 0, matchoff = 0;
  enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
  struct nf_conntrack_man cmd = {};
  union nf_inet_addr *daddr = NULL;

  if (ctinfo != IP_CT_ESTABLISHED && ctinfo !=
IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
    TNS_PRINT ("tns: Conntrackinfo = %u", ctinfo);
    return NF_ACCEPT;
  }

  th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
  if (th == NULL) return (NF_ACCEPT);

  dataoff = protoff + th->doff * 4;
  /* No data? */
  if (dataoff >= skb->len) {
    TNS_PRINT ("tns: dataoff(%u) >= skblen(%u)", dataoff, skb->len);
    return NF_ACCEPT;
  }
  datalen = skb->len - dataoff;

  spin_lock_bh (&nf_tns_lock);

  TNS_PRINT ("skb_headlen(skb)= %u offset: %u datalen: %u",
skb_headlen(skb), dataoff, datalen);
  buf_ptr = skb_header_pointer (skb, dataoff, datalen, tns_buffer);
  BUG_ON(buf_ptr == NULL);
  //tns_dump_block ("buf_ptr", (caddr_t)buf_ptr, datalen);
  //tns_dump_block ("tns_buffer", (caddr_t)tns_buffer, datalen);

  cmd.l3num = nf_ct_l3num(ct);
  memcpy (cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all, sizeof(cmd.u3.all));

  found = find_pattern (buf_ptr, datalen, &cmd, &matchoff, &matchlen);

  /*no match */
  if (0 == found) {ret = NF_ACCEPT; TNS_PRINT ("unfound pattern"); goto out;}

  //proto: 2 192.168.100.100-> 192.168.100.103 port: 3747
  TNS_PRINT ("proto: %u " NIPQUAD_FMT "-> " NIPQUAD_FMT " port: %u",
		 nf_ct_l3num (ct),
		 NIPQUAD(ct->tuplehash[!dir].tuple.src.u3.ip),
		 NIPQUAD (ct->tuplehash[!dir].tuple.dst.u3.ip),
		 ntohs(cmd.u.tcp.port ));

  daddr = &ct->tuplehash[!dir].tuple.dst.u3;

  /* Update the tns info */
  if ((cmd.l3num == nf_ct_l3num(ct)) && memcmp(&cmd.u3.all,
&ct->tuplehash[dir].tuple.src.u3.all, sizeof(cmd.u3.all))) {
    if (cmd.l3num == PF_INET) {
      TNS_PRINT ("NOT RECORDING: " NIPQUAD_FMT " != " NIPQUAD_FMT,
		     NIPQUAD(cmd.u3.ip),
		     NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
    }
    TNS_PRINT ("update the tns info");
    daddr = &cmd.u3;
  }

#if 1
  exp = nf_ct_expect_alloc (ct);
  if (NULL == exp) {
    ret = NF_DROP;
    TNS_PRINT ("nf_ct_expect_alloc failed");
    goto out;
  }

  nf_ct_expect_init (exp, NF_CT_EXPECT_CLASS_DEFAULT, cmd.l3num,
		     &ct->tuplehash[!dir].tuple.src.u3, daddr,
		     IPPROTO_TCP, NULL, &cmd.u.tcp.port);

  if (ct->status & IPS_NAT_MASK) {
    TNS_PRINT ("match nat mask");
    ret = nf_nat_tns (skb, ctinfo, matchoff, matchlen, exp);
  } else {
    TNS_PRINT ("no nat");
    if (0 != nf_ct_expect_related (exp)) {
     ret = NF_DROP;
     TNS_PRINT ("nf_ct_expect_related failed");
    } else {
      ret = NF_ACCEPT;
     TNS_PRINT ("nf_ct_expect_related succ");
    }
  }

  nf_ct_expect_put (exp);
#endif
 out:
  spin_unlock_bh (&nf_tns_lock);
  return (ret);
}

static struct nf_conntrack_helper tns[MAX_PORTS] __read_mostly;
static char tns_names[MAX_PORTS][sizeof("tns-65535")] __read_mostly;

static const struct nf_conntrack_expect_policy tns_exp_policy = {
  .max_expected	= 1,
  .timeout	= 5 * 60,
};

/* don't make this __exit, since it's called from __init ! */
static void nf_conntrack_tns_fini(void)
{
  int i = 0;

  for (i = 0; i < ports_c; i++) {
    if (tns[i].me == NULL) continue;
    TNS_PRINT ("nf_ct_tns: unregistering helper for pf: %d port: %d",
tns[i].tuple.src.l3num, ports[i]);
    nf_conntrack_helper_unregister(&tns[i]);
  }

  if (NULL != tns_buffer) kfree(tns_buffer);
}

static int __init nf_conntrack_tns_init(void)
{
  int i = 0, ret = 0;
  char *tmpname;

  tns_buffer = kmalloc(65536, GFP_KERNEL);

  if (!tns_buffer) return -ENOMEM;

  if (ports_c == 0) ports[ports_c++] = TNS_PORT;

  for (i = 0; i < ports_c; i++) {
    tns[i].tuple.src.l3num = PF_INET;
    tns[i].tuple.src.u.tcp.port = htons(ports[i]);
    tns[i].tuple.dst.protonum = IPPROTO_TCP;
    tns[i].expect_policy = &tns_exp_policy;
    tns[i].me = THIS_MODULE;
    tns[i].help = help;
    tmpname = &tns_names[i][0];
    if (ports[i] == TNS_PORT)
      sprintf(tmpname, "tns");
    else
      sprintf(tmpname, "tns-%d", ports[i]);
    tns[i].name = tmpname;

    TNS_PRINT ("nf_ct_tns: registering helper for pf: %d port: %d",
tns[i].tuple.src.l3num, ports[i]);
    ret = nf_conntrack_helper_register(&tns[i]);
    if (ret) {
      TNS_PRINT ("nf_ct_tns: failed to register helper for pf: %d
port: %d", tns[i].tuple.src.l3num, ports[i]);
      nf_conntrack_tns_fini();
      return ret;
    }
  }

  return 0;
}

module_init(nf_conntrack_tns_init);
module_exit(nf_conntrack_tns_fini);

thanks,
Neco.F
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ