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@xxxxxxxxxxx>"); 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 netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html