www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_nat_h323.c
index ef27a99..130c417 100755 (executable)
@@ -1,6 +1,7 @@
-/* 
- * H.323 'brute force' extension for NAT alteration. 
+/*
+ * H.323 'brute force' extension for NAT alteration.
  * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * (c) 2005 Max Kellermann <max@duempel.org>
  *
  * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
  * (http://www.coritel.it/projects/sofia/nat.html)
@@ -38,7 +39,7 @@ struct module *ip_nat_h323 = THIS_MODULE;
 
 /* FIXME: Time out? --RR */
 
-static unsigned int 
+static unsigned int
 h225_nat_expected(struct sk_buff **pskb,
                  unsigned int hooknum,
                  struct ip_conntrack *ct,
@@ -46,23 +47,35 @@ h225_nat_expected(struct sk_buff **pskb,
 
 static unsigned int h225_nat_help(struct ip_conntrack *ct,
                                  struct ip_conntrack_expect *exp,
-                                 struct ip_nat_info *info,
-                                 enum ip_conntrack_info ctinfo,
-                                 unsigned int hooknum,
-                                 struct sk_buff **pskb);
-                 
-static struct ip_nat_helper h245 = 
-       { { NULL, NULL },
-          "H.245",                             /* name */
-         0,                                    /* flags */
-         NULL,                                 /* module */
-         { { 0, { 0 } },                       /* tuple */
-           { 0, { 0 }, IPPROTO_TCP } },
-         { { 0, { 0xFFFF } },                  /* mask */
-           { 0, { 0 }, 0xFFFF } },
-         h225_nat_help,                        /* helper */
-         h225_nat_expected                     /* expectfn */
-       };
+                                 struct ip_nat_info *info,
+                                 enum ip_conntrack_info ctinfo,
+                                 unsigned int hooknum,
+                                 struct sk_buff **pskb);
+
+static struct ip_nat_helper h245 = {
+       .list = { NULL, NULL },
+       .name = "H.245",
+       .flags = 0,
+       .me = THIS_MODULE,
+       .tuple = { .src = { .ip = 0, 
+                           .u = { .tcp = { .port = 0 } } 
+                         }, 
+                  .dst = { .ip = 0, 
+                           .u = { .all = 0 },
+                           .protonum = IPPROTO_TCP
+                         } 
+                },
+       .mask = { .src = { .ip = 0, 
+                          .u = { .tcp = { .port = 0xffff } } 
+                        }, 
+                 .dst = { .ip = 0, 
+                          .u = { .all = 0 },
+                          .protonum = 0xffff 
+                        } 
+               },
+       .help = h225_nat_help,
+       .expect = h225_nat_expected
+};
 
 static unsigned int
 h225_nat_expected(struct sk_buff **pskb,
@@ -77,7 +90,7 @@ h225_nat_expected(struct sk_buff **pskb,
        struct ip_ct_h225_master *master_info;
        struct ip_conntrack *master = master_ct(ct);
        unsigned int is_h225, ret;
-       
+
        IP_NF_ASSERT(info);
        IP_NF_ASSERT(master);
 
@@ -110,7 +123,7 @@ h225_nat_expected(struct sk_buff **pskb,
        port = exp_info->port;
        is_h225 = master_info->is_h225 == H225_PORT;
        UNLOCK_BH(&ip_h323_lock);
-       
+
        if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
                newip = newsrcip;
        else
@@ -118,8 +131,8 @@ h225_nat_expected(struct sk_buff **pskb,
 
        DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
 
-       mr.rangesize = 1;
        /* We don't want to manip the per-protocol, just the IPs... */
+       mr.rangesize = 1;
        mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
        mr.range[0].min_ip = mr.range[0].max_ip = newip;
 
@@ -133,7 +146,7 @@ h225_nat_expected(struct sk_buff **pskb,
        }
 
        ret = ip_nat_setup_info(ct, &mr, hooknum);
-       
+
        if (is_h225) {
                DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
                /* NAT expectfn called with ip_nat_lock write-locked */
@@ -143,18 +156,26 @@ h225_nat_expected(struct sk_buff **pskb,
 }
 
 static int h323_signal_address_fixup(struct ip_conntrack *ct,
-                                    struct sk_buff **pskb,
-                                    enum ip_conntrack_info ctinfo)
+                                    struct sk_buff **pskb,
+                                    enum ip_conntrack_info ctinfo)
 {
        struct iphdr *iph = (*pskb)->nh.iph;
-       struct tcphdr *tcph = (void *)iph + iph->ihl*4;
-       char *data = (char *) tcph + tcph->doff * 4;
-       u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
-       u_int32_t datalen = tcplen - tcph->doff*4;
-       struct ip_ct_h225_master *info = &ct->help.ct_h225_info; 
-       u_int32_t newip;
-       u_int16_t port;
+       struct tcphdr _tcph, *tcph;
+       u_int32_t tcplen, datalen;
+       struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
+       struct {
+               u_int32_t ip;
+               u_int16_t port;
+       } __attribute__ ((__packed__)) newdata;
        int i;
+       int ret;
+
+       tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
+       if (tcph == NULL)
+               return NF_ACCEPT;
+
+       tcplen = (*pskb)->len - iph->ihl * 4;
+       datalen = tcplen - tcph->doff * 4;
 
        MUST_BE_LOCKED(&ip_h323_lock);
 
@@ -167,8 +188,8 @@ static int h323_signal_address_fixup(struct ip_conntrack *ct,
                || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
                return 1;
 
-       DEBUGP("h323_signal_address_fixup: offsets %u + 6  and %u + 6 in %u\n", 
-               info->offset[IP_CT_DIR_ORIGINAL], 
+       DEBUGP("h323_signal_address_fixup: offsets %u + 6  and %u + 6 in %u\n",
+               info->offset[IP_CT_DIR_ORIGINAL],
                info->offset[IP_CT_DIR_REPLY],
                tcplen);
        DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
@@ -178,7 +199,7 @@ static int h323_signal_address_fixup(struct ip_conntrack *ct,
                DEBUGP("h323_signal_address_fixup: %s %s\n",
                        info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
                        i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
-               if (!between(info->seq[i], ntohl(tcph->seq), 
+               if (!between(info->seq[i], ntohl(tcph->seq),
                             ntohl(tcph->seq) + datalen))
                        continue;
                if (!between(info->seq[i] + 6, ntohl(tcph->seq),
@@ -196,39 +217,22 @@ static int h323_signal_address_fixup(struct ip_conntrack *ct,
                /* Change address inside packet to match way we're mapping
                   this connection. */
                if (i == IP_CT_DIR_ORIGINAL) {
-                       newip = ct->tuplehash[!info->dir].tuple.dst.ip;
-                       port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
+                       newdata.ip = ct->tuplehash[!info->dir].tuple.dst.ip;
+                       newdata.port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
                } else {
-                       newip = ct->tuplehash[!info->dir].tuple.src.ip;
-                       port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
+                       newdata.ip = ct->tuplehash[!info->dir].tuple.src.ip;
+                       newdata.port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
                }
 
-               DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", 
-                       i == IP_CT_DIR_ORIGINAL ? "source" : "dest  ", 
-                       NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), 
-                       ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
-
                /* Modify the packet */
-               *(u_int32_t *)(data + info->offset[i]) = newip;
-               *(u_int16_t *)(data + info->offset[i] + 4) = port;
-       
-               DEBUGP("h323_signal_address_fixup:  new %s IP:port %u.%u.%u.%u:%u\n", 
-                       i == IP_CT_DIR_ORIGINAL ? "source" : "dest  ", 
-                       NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), 
-                       ntohs(*((u_int16_t *)(data + info->offset[i] + 4))));
+               ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+                                              info->seq[i] - ntohl(tcph->seq),
+                                              sizeof(newdata),
+                                              (const char*)&newdata, sizeof(newdata));
+               if (!ret)
+                       return 0;
        }
 
-       /* fix checksum information */
-
-       (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-                                    datalen, 0);
-
-       tcph->check = 0;
-       tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
-                                  csum_partial((char *)tcph, tcph->doff*4,
-                                          (*pskb)->csum));
-       ip_send_check(iph);
-
        return 1;
 }
 
@@ -238,15 +242,23 @@ static int h323_data_fixup(struct ip_ct_h225_expect *info,
                           enum ip_conntrack_info ctinfo,
                           struct ip_conntrack_expect *expect)
 {
-       u_int32_t newip;
-       u_int16_t port;
+       struct {
+               u_int32_t ip;
+               u_int16_t port;
+       } __attribute__ ((__packed__)) newdata;
        struct ip_conntrack_tuple newtuple;
        struct iphdr *iph = (*pskb)->nh.iph;
-       struct tcphdr *tcph = (void *)iph + iph->ihl*4;
-       char *data = (char *) tcph + tcph->doff * 4;
-       u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
+       struct tcphdr _tcph, *tcph;
+       u_int32_t tcplen;
        struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
        int is_h225;
+       int ret;
+
+       tcph = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_tcph), &_tcph);
+       if (tcph == NULL)
+               return NF_ACCEPT;
+
+       tcplen = (*pskb)->len - iph->ihl * 4;
 
        MUST_BE_LOCKED(&ip_h323_lock);
        DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
@@ -269,13 +281,13 @@ static int h323_data_fixup(struct ip_ct_h225_expect *info,
           this connection. */
        if (info->dir == IP_CT_DIR_REPLY) {
                /* Must be where client thinks server is */
-               newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+               newdata.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
                /* Expect something from client->server */
                newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
                newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
        } else {
                /* Must be where server thinks client is */
-               newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+               newdata.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
                /* Expect something from server->client */
                newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
                newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
@@ -290,61 +302,45 @@ static int h323_data_fixup(struct ip_ct_h225_expect *info,
                newtuple.dst.protonum = IPPROTO_UDP;
                newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
        }
-       
+
        /* Try to get same port: if not, try to change it. */
-       for (port = ntohs(info->port); port != 0; port++) {
+       for (newdata.port = ntohs(info->port); newdata.port != 0; newdata.port++) {
                if (is_h225)
-                       newtuple.dst.u.tcp.port = htons(port);
+                       newtuple.dst.u.tcp.port = htons(newdata.port);
                else
-                       newtuple.dst.u.udp.port = htons(port);
+                       newtuple.dst.u.udp.port = htons(newdata.port);
 
                if (ip_conntrack_change_expect(expect, &newtuple) == 0)
                        break;
        }
-       if (port == 0) {
+       if (newdata.port == 0) {
                DEBUGP("h323_data_fixup: no free port found!\n");
                return 0;
        }
 
-       port = htons(port);
-
-       DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", 
-               NIPQUAD(*((u_int32_t *)(data + info->offset))), 
-               ntohs(*((u_int16_t *)(data + info->offset + 4))));
+       newdata.port = htons(newdata.port);
 
        /* Modify the packet */
-       *(u_int32_t *)(data + info->offset) = newip;
-       *(u_int16_t *)(data + info->offset + 4) = port;
-       
-       DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", 
-               NIPQUAD(*((u_int32_t *)(data + info->offset))), 
-               ntohs(*((u_int16_t *)(data + info->offset + 4))));
-
-       /* fix checksum information  */
-       /* FIXME: usually repeated multiple times in the case of H.245! */
-
-       (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-                                    tcplen - tcph->doff*4, 0);
-
-       tcph->check = 0;
-       tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
-                                  csum_partial((char *)tcph, tcph->doff*4,
-                                          (*pskb)->csum));
-       ip_send_check(iph);
+       ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+                                      expect->seq - ntohl(tcph->seq),
+                                      sizeof(newdata),
+                                      (const char*)&newdata, sizeof(newdata));
+       if (!ret)
+               return 0;
 
        return 1;
 }
 
 static unsigned int h225_nat_help(struct ip_conntrack *ct,
                                  struct ip_conntrack_expect *exp,
-                                 struct ip_nat_info *info,
-                                 enum ip_conntrack_info ctinfo,
-                                 unsigned int hooknum,
-                                 struct sk_buff **pskb)
+                                 struct ip_nat_info *info,
+                                 enum ip_conntrack_info ctinfo,
+                                 unsigned int hooknum,
+                                 struct sk_buff **pskb)
 {
        int dir;
        struct ip_ct_h225_expect *exp_info;
-       
+
        /* Only mangle things once: original direction in POST_ROUTING
           and reply direction on PRE_ROUTING. */
        dir = CTINFO2DIR(ctinfo);
@@ -372,7 +368,7 @@ static unsigned int h225_nat_help(struct ip_conntrack *ct,
                UNLOCK_BH(&ip_h323_lock);
                return NF_ACCEPT;
        }
-               
+
        exp_info = &exp->help.exp_h225_info;
 
        LOCK_BH(&ip_h323_lock);
@@ -385,23 +381,37 @@ static unsigned int h225_nat_help(struct ip_conntrack *ct,
        return NF_ACCEPT;
 }
 
-static struct ip_nat_helper h225 = 
-       { { NULL, NULL },
-         "H.225",                                      /* name */
-         IP_NAT_HELPER_F_ALWAYS,                       /* flags */
-         THIS_MODULE,                                  /* module */
-         { { 0, { .tcp = { __constant_htons(H225_PORT) } } },  /* tuple */
-           { 0, { 0 }, IPPROTO_TCP } },
-         { { 0, { .tcp = { 0xFFFF } } },               /* mask */
-           { 0, { 0 }, 0xFFFF } },
-         h225_nat_help,                                /* helper */
-         h225_nat_expected                             /* expectfn */
-       };
+static struct ip_nat_helper h225 = {
+       .list = { NULL, NULL },
+       .name = "H.225",
+       .flags = IP_NAT_HELPER_F_ALWAYS,
+       .me = THIS_MODULE,
+       .tuple = { .src = { .ip = 0, 
+                           .u = { .tcp = { .port =  
+                                   __constant_htons(H225_PORT) } } 
+                         }, 
+                  .dst = { .ip = 0, 
+                           .u = { .all = 0 },
+                           .protonum = IPPROTO_TCP
+                         } 
+                },
+       .mask = { .src = { .ip = 0, 
+                          .u = { .tcp = { .port = 0xffff } } 
+                        }, 
+                 .dst = { .ip = 0, 
+                          .u = { .all = 0 },
+                          .protonum = 0xffff 
+                        } 
+               },
+       .help = h225_nat_help,
+       .expect = h225_nat_expected
+};
 
 static int __init init(void)
 {
        int ret;
-       
+
+       printk("ip_nat_h323: initialize the module!\n");
        ret = ip_nat_helper_register(&h225);
 
        if (ret != 0)
@@ -415,5 +425,7 @@ static void __exit fini(void)
        ip_nat_helper_unregister(&h225);
 }
 
+NEEDS_CONNTRACK(h225);
+NEEDS_CONNTRACK(h245);
 module_init(init);
 module_exit(fini);