Re: about conntrack for oracle tns

From: Jan Engelhardt
Date: Sun Jul 25 2010 - 12:46:14 EST



On Thursday 2010-07-08 09:56, Neco.F wrote:

>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...........

The panic info usually includes more info, which you should post.


>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);

Questionable whether this is safe without a length limit. But you tell me.

> 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);

Use pr_debug instead.

> 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;

You also want const here.

> 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;

Drop the cast, it seems to serve no purpose.

> 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;
> }
> }

You could be using simple_strtoul here.

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

"return port != 0;" is sufficient.

>}
>
>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);

Don't use BUG_ON, handle the problem correctly and return from the
function.

> //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) {

==NFPROTO_IPV4.

> 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;

NFPROTO_IPV4.

>...
>}
>
>module_init(nf_conntrack_tns_init);
>module_exit(nf_conntrack_tns_fini);

You need to do something about the coding style, this is hard to read.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/