Skip to content

Commit

Permalink
[NETFILTER]: Fix NAT sequence number adjustment
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Apr 25, 2005
1 parent 8e293ad commit e281e3a
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 16 deletions.
3 changes: 3 additions & 0 deletions include/linux/netfilter_ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down
51 changes: 45 additions & 6 deletions net/ipv4/netfilter/ip_conntrack_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -516,21 +524,38 @@ 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 = {
.hook = ip_confirm,
.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 */
Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand Down
9 changes: 0 additions & 9 deletions net/ipv4/netfilter/ip_nat_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 53 additions & 1 deletion net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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:
Expand Down

0 comments on commit e281e3a

Please sign in to comment.