fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / ipv4 / netfilter / ipt_TCPMSS.c
index c122841..93eb5c3 100644 (file)
@@ -21,26 +21,14 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
 MODULE_DESCRIPTION("iptables TCP MSS modification module");
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static u_int16_t
-cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
-{
-       u_int32_t diffs[] = { oldvalinv, newval };
-       return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
-                                      oldcheck^0xFFFF));
-}
-
 static inline unsigned int
 optlen(const u_int8_t *opt, unsigned int offset)
 {
        /* Beware zero-length options: make finite progress */
-       if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1;
-       else return opt[offset+1];
+       if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
+               return 1;
+       else
+               return opt[offset+1];
 }
 
 static unsigned int
@@ -48,26 +36,22 @@ ipt_tcpmss_target(struct sk_buff **pskb,
                  const struct net_device *in,
                  const struct net_device *out,
                  unsigned int hooknum,
-                 const void *targinfo,
-                 void *userinfo)
+                 const struct xt_target *target,
+                 const void *targinfo)
 {
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
        struct tcphdr *tcph;
        struct iphdr *iph;
-       u_int16_t tcplen, newtotlen, oldval, newmss;
+       u_int16_t tcplen, newmss;
+       __be16 newtotlen, oldval;
        unsigned int i;
        u_int8_t *opt;
 
        if (!skb_make_writable(pskb, (*pskb)->len))
                return NF_DROP;
 
-       if ((*pskb)->ip_summed == CHECKSUM_HW &&
-           skb_checksum_help(*pskb, out == NULL))
-               return NF_DROP;
-
        iph = (*pskb)->nh.iph;
        tcplen = (*pskb)->len - iph->ihl*4;
-
        tcph = (void *)iph + iph->ihl*4;
 
        /* Since it passed flags test in tcp match, we know it is is
@@ -83,54 +67,39 @@ ipt_tcpmss_target(struct sk_buff **pskb,
                return NF_DROP;
        }
 
-       if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
-               if(!(*pskb)->dst) {
-                       if (net_ratelimit())
-                               printk(KERN_ERR
-                                       "ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
-                       return NF_DROP; /* or IPT_CONTINUE ?? */
-               }
-
-               if(dst_mtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
+       if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
+               if (dst_mtu((*pskb)->dst) <= sizeof(struct iphdr) +
+                                            sizeof(struct tcphdr)) {
                        if (net_ratelimit())
-                               printk(KERN_ERR
-                                       "ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_mtu((*pskb)->dst));
+                               printk(KERN_ERR "ipt_tcpmss_target: "
+                                      "unknown or invalid path-MTU (%d)\n",
+                                      dst_mtu((*pskb)->dst));
                        return NF_DROP; /* or IPT_CONTINUE ?? */
                }
 
-               newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) - sizeof(struct tcphdr);
+               newmss = dst_mtu((*pskb)->dst) - sizeof(struct iphdr) -
+                                                sizeof(struct tcphdr);
        } else
                newmss = tcpmssinfo->mss;
 
        opt = (u_int8_t *)tcph;
-       for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
-               if ((opt[i] == TCPOPT_MSS) &&
-                   ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
-                   (opt[i+1] == TCPOLEN_MSS)) {
+       for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
+               if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
+                   opt[i+1] == TCPOLEN_MSS) {
                        u_int16_t oldmss;
 
                        oldmss = (opt[i+2] << 8) | opt[i+3];
 
-                       if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
-                               (oldmss <= newmss))
-                                       return IPT_CONTINUE;
+                       if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
+                           oldmss <= newmss)
+                               return IPT_CONTINUE;
 
                        opt[i+2] = (newmss & 0xff00) >> 8;
                        opt[i+3] = (newmss & 0x00ff);
 
-                       tcph->check = cheat_check(htons(oldmss)^0xFFFF,
-                                                 htons(newmss),
-                                                 tcph->check);
-
-                       DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
-                              "->%u.%u.%u.%u:%hu changed TCP MSS option"
-                              " (from %u to %u)\n", 
-                              NIPQUAD((*pskb)->nh.iph->saddr),
-                              ntohs(tcph->source),
-                              NIPQUAD((*pskb)->nh.iph->daddr),
-                              ntohs(tcph->dest),
-                              oldmss, newmss);
-                       goto retmodified;
+                       nf_proto_csum_replace2(&tcph->check, *pskb,
+                                               htons(oldmss), htons(newmss), 0);
+                       return IPT_CONTINUE;
                }
        }
 
@@ -142,13 +111,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
 
                newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
                                         TCPOLEN_MSS, GFP_ATOMIC);
-               if (!newskb) {
-                       if (net_ratelimit())
-                               printk(KERN_ERR "ipt_tcpmss_target:"
-                                      " unable to allocate larger skb\n");
+               if (!newskb)
                        return NF_DROP;
-               }
-
                kfree_skb(*pskb);
                *pskb = newskb;
                iph = (*pskb)->nh.iph;
@@ -160,36 +124,23 @@ ipt_tcpmss_target(struct sk_buff **pskb,
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
        memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
 
-       tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF,
-                                 htons(tcplen + TCPOLEN_MSS), tcph->check);
-       tcplen += TCPOLEN_MSS;
-
+       nf_proto_csum_replace2(&tcph->check, *pskb,
+                               htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
        opt[0] = TCPOPT_MSS;
        opt[1] = TCPOLEN_MSS;
        opt[2] = (newmss & 0xff00) >> 8;
        opt[3] = (newmss & 0x00ff);
 
-       tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check);
+       nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
 
-       oldval = ((u_int16_t *)tcph)[6];
+       oldval = ((__be16 *)tcph)[6];
        tcph->doff += TCPOLEN_MSS/4;
-       tcph->check = cheat_check(oldval ^ 0xFFFF,
-                                 ((u_int16_t *)tcph)[6], tcph->check);
+       nf_proto_csum_replace2(&tcph->check, *pskb,
+                               oldval, ((__be16 *)tcph)[6], 0);
 
        newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
-       iph->check = cheat_check(iph->tot_len ^ 0xFFFF,
-                                newtotlen, iph->check);
+       nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
        iph->tot_len = newtotlen;
-
-       DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
-              "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n",
-              NIPQUAD((*pskb)->nh.iph->saddr),
-              ntohs(tcph->source),
-              NIPQUAD((*pskb)->nh.iph->daddr),
-              ntohs(tcph->dest),
-              newmss);
-
- retmodified:
        return IPT_CONTINUE;
 }
 
@@ -199,9 +150,9 @@ static inline int find_syn_match(const struct ipt_entry_match *m)
 {
        const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
 
-       if (strcmp(m->u.kernel.match->name, "tcp") == 0
-           && (tcpinfo->flg_cmp & TH_SYN)
-           && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
+       if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
+           tcpinfo->flg_cmp & TH_SYN &&
+           !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
                return 1;
 
        return 0;
@@ -211,33 +162,24 @@ static inline int find_syn_match(const struct ipt_entry_match *m)
 static int
 ipt_tcpmss_checkentry(const char *tablename,
                      const void *e_void,
+                     const struct xt_target *target,
                      void *targinfo,
-                     unsigned int targinfosize,
                      unsigned int hook_mask)
 {
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
        const struct ipt_entry *e = e_void;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
-               DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
-                      targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
+       if (tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU &&
+           (hook_mask & ~((1 << NF_IP_FORWARD) |
+                          (1 << NF_IP_LOCAL_OUT) |
+                          (1 << NF_IP_POST_ROUTING))) != 0) {
+               printk("TCPMSS: path-MTU clamping only supported in "
+                      "FORWARD, OUTPUT and POSTROUTING hooks\n");
                return 0;
        }
 
-
-       if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && 
-                       ((hook_mask & ~((1 << NF_IP_FORWARD)
-                               | (1 << NF_IP_LOCAL_OUT)
-                               | (1 << NF_IP_POST_ROUTING))) != 0)) {
-               printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
-               return 0;
-       }
-
-       if (e->ip.proto == IPPROTO_TCP
-           && !(e->ip.invflags & IPT_INV_PROTO)
-           && IPT_MATCH_ITERATE(e, find_syn_match))
+       if (IPT_MATCH_ITERATE(e, find_syn_match))
                return 1;
-
        printk("TCPMSS: Only works on TCP SYN packets\n");
        return 0;
 }
@@ -245,19 +187,21 @@ ipt_tcpmss_checkentry(const char *tablename,
 static struct ipt_target ipt_tcpmss_reg = {
        .name           = "TCPMSS",
        .target         = ipt_tcpmss_target,
+       .targetsize     = sizeof(struct ipt_tcpmss_info),
+       .proto          = IPPROTO_TCP,
        .checkentry     = ipt_tcpmss_checkentry,
        .me             = THIS_MODULE,
 };
 
-static int __init init(void)
+static int __init ipt_tcpmss_init(void)
 {
        return ipt_register_target(&ipt_tcpmss_reg);
 }
 
-static void __exit fini(void)
+static void __exit ipt_tcpmss_fini(void)
 {
        ipt_unregister_target(&ipt_tcpmss_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_tcpmss_init);
+module_exit(ipt_tcpmss_fini);