[NETFILTER]: Fix NAT sequence number adjustment
authorPatrick McHardy <kaber@trash.net>
Mon, 25 Apr 2005 01:41:38 +0000 (18:41 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 Apr 2005 01:41:38 +0000 (18:41 -0700)
The NAT changes in 2.6.11 changed the position where helpers
are called and perform packet mangling. Before 2.6.11, a NAT
helper was called before the packet was NATed and had its
sequence number adjusted. Since 2.6.11, the helpers get packets
with already adjusted sequence numbers.

This breaks sequence number adjustment, adjust_tcp_sequence()
needs the original sequence number to determine whether
a packet was a retransmission and to store it for further
corrections. It can't be reconstructed without more information
than available, so this patch restores the old order by
calling helpers from a new conntrack hook two priorities
below ip_conntrack_confirm() and adjusting the sequence number
from a new NAT hook one priority below ip_conntrack_confirm().

Tracked down by Phil Oester <kernel@linuxace.com>

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netfilter_ipv4.h
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_nat_core.c
net/ipv4/netfilter/ip_nat_standalone.c

index c9bacf9b2431ae7db55f6f06bc54b7c87bd3c4be..9e5750079e09abc0956bc0617e16d282840ea07d 100644 (file)
@@ -62,6 +62,9 @@ enum nf_ip_hook_priorities {
        NF_IP_PRI_FILTER = 0,
        NF_IP_PRI_NAT_SRC = 100,
        NF_IP_PRI_SELINUX_LAST = 225,
+       NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2,
+       NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1,
+       NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
        NF_IP_PRI_LAST = INT_MAX,
 };
 
index 80a7bde2a57a75a6db3882383637d8efd39f9f9c..0c29ccf62a897862a70ae135506e11378b2da3e2 100644 (file)
@@ -400,6 +400,16 @@ static unsigned int ip_confirm(unsigned int hooknum,
                               const struct net_device *in,
                               const struct net_device *out,
                               int (*okfn)(struct sk_buff *))
+{
+       /* We've seen it coming out the other side: confirm it */
+       return ip_conntrack_confirm(pskb);
+}
+
+static unsigned int ip_conntrack_help(unsigned int hooknum,
+                                     struct sk_buff **pskb,
+                                     const struct net_device *in,
+                                     const struct net_device *out,
+                                     int (*okfn)(struct sk_buff *))
 {
        struct ip_conntrack *ct;
        enum ip_conntrack_info ctinfo;
@@ -412,9 +422,7 @@ static unsigned int ip_confirm(unsigned int hooknum,
                if (ret != NF_ACCEPT)
                        return ret;
        }
-
-       /* We've seen it coming out the other side: confirm it */
-       return ip_conntrack_confirm(pskb);
+       return NF_ACCEPT;
 }
 
 static unsigned int ip_conntrack_defrag(unsigned int hooknum,
@@ -516,13 +524,30 @@ static struct nf_hook_ops ip_conntrack_local_out_ops = {
        .priority       = NF_IP_PRI_CONNTRACK,
 };
 
+/* helpers */
+static struct nf_hook_ops ip_conntrack_helper_out_ops = {
+       .hook           = ip_conntrack_help,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_POST_ROUTING,
+       .priority       = NF_IP_PRI_CONNTRACK_HELPER,
+};
+
+static struct nf_hook_ops ip_conntrack_helper_in_ops = {
+       .hook           = ip_conntrack_help,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_LOCAL_IN,
+       .priority       = NF_IP_PRI_CONNTRACK_HELPER,
+};
+
 /* Refragmenter; last chance. */
 static struct nf_hook_ops ip_conntrack_out_ops = {
        .hook           = ip_refrag,
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_POST_ROUTING,
-       .priority       = NF_IP_PRI_LAST,
+       .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 static struct nf_hook_ops ip_conntrack_local_in_ops = {
@@ -530,7 +555,7 @@ static struct nf_hook_ops ip_conntrack_local_in_ops = {
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_LOCAL_IN,
-       .priority       = NF_IP_PRI_LAST-1,
+       .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 };
 
 /* Sysctl support */
@@ -831,10 +856,20 @@ static int init_or_cleanup(int init)
                printk("ip_conntrack: can't register local out hook.\n");
                goto cleanup_inops;
        }
+       ret = nf_register_hook(&ip_conntrack_helper_in_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register local in helper hook.\n");
+               goto cleanup_inandlocalops;
+       }
+       ret = nf_register_hook(&ip_conntrack_helper_out_ops);
+       if (ret < 0) {
+               printk("ip_conntrack: can't register postrouting helper hook.\n");
+               goto cleanup_helperinops;
+       }
        ret = nf_register_hook(&ip_conntrack_out_ops);
        if (ret < 0) {
                printk("ip_conntrack: can't register post-routing hook.\n");
-               goto cleanup_inandlocalops;
+               goto cleanup_helperoutops;
        }
        ret = nf_register_hook(&ip_conntrack_local_in_ops);
        if (ret < 0) {
@@ -860,6 +895,10 @@ static int init_or_cleanup(int init)
        nf_unregister_hook(&ip_conntrack_local_in_ops);
  cleanup_inoutandlocalops:
        nf_unregister_hook(&ip_conntrack_out_ops);
+ cleanup_helperoutops:
+       nf_unregister_hook(&ip_conntrack_helper_out_ops);
+ cleanup_helperinops:
+       nf_unregister_hook(&ip_conntrack_helper_in_ops);
  cleanup_inandlocalops:
        nf_unregister_hook(&ip_conntrack_local_out_ops);
  cleanup_inops:
index 162ceacfc29a86f8f0f44886a5c5f9d4c4601f30..9fc6f93af0dd15de8933a14e053bf8cdf41dfb69 100644 (file)
@@ -356,15 +356,6 @@ unsigned int nat_packet(struct ip_conntrack *ct,
        unsigned long statusbit;
        enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
 
-       if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)
-           && (hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_IN)) {
-               DEBUGP("ip_nat_core: adjusting sequence number\n");
-               /* future: put this in a l4-proto specific function,
-                * and call this function here. */
-               if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
-                       return NF_DROP;
-       }
-
        if (mtype == IP_NAT_MANIP_SRC)
                statusbit = IPS_SRC_NAT;
        else
index dec4a74212cd51cea0ca9b5af1a0b471add844fe..79f56f662b336bb1a48298af7c0d03c1e1d73b89 100644 (file)
@@ -230,6 +230,25 @@ ip_nat_local_fn(unsigned int hooknum,
        return ret;
 }
 
+static unsigned int
+ip_nat_adjust(unsigned int hooknum,
+             struct sk_buff **pskb,
+             const struct net_device *in,
+             const struct net_device *out,
+             int (*okfn)(struct sk_buff *))
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+       if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
+               DEBUGP("ip_nat_standalone: adjusting sequence number\n");
+               if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
+                       return NF_DROP;
+       }
+       return NF_ACCEPT;
+}
+
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
@@ -250,6 +269,15 @@ static struct nf_hook_ops ip_nat_out_ops = {
        .priority       = NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_out_ops = {
+       .hook           = ip_nat_adjust,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_POST_ROUTING,
+       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops = {
        .hook           = ip_nat_local_fn,
@@ -268,6 +296,16 @@ static struct nf_hook_ops ip_nat_local_in_ops = {
        .priority       = NF_IP_PRI_NAT_SRC,
 };
 
+/* After conntrack, adjust sequence number */
+static struct nf_hook_ops ip_nat_adjust_in_ops = {
+       .hook           = ip_nat_adjust,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_IP_LOCAL_IN,
+       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
+};
+
+
 static int init_or_cleanup(int init)
 {
        int ret = 0;
@@ -296,10 +334,20 @@ static int init_or_cleanup(int init)
                printk("ip_nat_init: can't register out hook.\n");
                goto cleanup_inops;
        }
+       ret = nf_register_hook(&ip_nat_adjust_in_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register adjust in hook.\n");
+               goto cleanup_outops;
+       }
+       ret = nf_register_hook(&ip_nat_adjust_out_ops);
+       if (ret < 0) {
+               printk("ip_nat_init: can't register adjust out hook.\n");
+               goto cleanup_adjustin_ops;
+       }
        ret = nf_register_hook(&ip_nat_local_out_ops);
        if (ret < 0) {
                printk("ip_nat_init: can't register local out hook.\n");
-               goto cleanup_outops;
+               goto cleanup_adjustout_ops;;
        }
        ret = nf_register_hook(&ip_nat_local_in_ops);
        if (ret < 0) {
@@ -312,6 +360,10 @@ static int init_or_cleanup(int init)
        nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
        nf_unregister_hook(&ip_nat_local_out_ops);
+ cleanup_adjustout_ops:
+       nf_unregister_hook(&ip_nat_adjust_out_ops);
+ cleanup_adjustin_ops:
+       nf_unregister_hook(&ip_nat_adjust_in_ops);
  cleanup_outops:
        nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops: