[NETFILTER]: Redo policy lookups after NAT when neccessary When NAT changes the key used for the xfrm lookup it needs to be done again.
Signed-off-by: Patrick McHardy <[EMAIL PROTECTED]> --- commit 8cb6cfa80dd5dc4da1de280a0278746c262a2d8d tree efffac2335bd21d0a0c2aa848df544002e4316f4 parent 864cef1bc7d011f4a07b01043786107ad570c820 author Patrick McHardy <[EMAIL PROTECTED]> Sat, 19 Nov 2005 22:07:34 +0100 committer Patrick McHardy <[EMAIL PROTECTED]> Sat, 19 Nov 2005 22:07:34 +0100 include/net/dst.h | 1 + net/ipv4/ip_output.c | 7 ++++++- net/ipv4/netfilter.c | 2 +- net/ipv4/netfilter/ip_nat_standalone.c | 27 +++++++++++++++++++++++++-- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 7eadd0c..4630e17 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -237,6 +237,7 @@ static inline int dst_output(struct sk_b } #if defined(CONFIG_XFRM) && defined(CONFIG_NETFILTER) +extern int __ip_dst_output(struct sk_buff *skb); extern int ip_dst_output(struct sk_buff *skb); extern int ip6_dst_output(struct sk_buff *skb); #else diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2c91f03..6836389 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -195,13 +195,18 @@ static inline int ip_finish_output2(stru return dst->neighbour->output(skb); if (net_ratelimit()) - printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); + printk(KERN_DEBUG "ip_finish_output3: No header cache and no neighbour!\n"); kfree_skb(skb); return -EINVAL; } static inline int ip_finish_output(struct sk_buff *skb) { +#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) + /* Policy lookup after SNAT yielded a new policy */ + if (skb->dst->xfrm != NULL) + return __ip_dst_output(skb); +#endif if (skb->len > dst_mtu(skb->dst) && !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) return ip_fragment(skb, ip_finish_output2); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index db330b6..8fda96a 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -87,7 +87,7 @@ int ip_route_me_harder(struct sk_buff ** EXPORT_SYMBOL(ip_route_me_harder); #ifdef CONFIG_XFRM -static inline int __ip_dst_output(struct sk_buff *skb) +inline int __ip_dst_output(struct sk_buff *skb) { int err; diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 1bb5089..b518697 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -187,12 +187,30 @@ ip_nat_out(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + unsigned int ret; + /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; - return ip_nat_fn(hooknum, pskb, in, out, okfn); + ret = ip_nat_fn(hooknum, pskb, in, out, okfn); + if (ret != NF_DROP && ret != NF_STOLEN + && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + + if (ct->tuplehash[dir].tuple.src.ip != + ct->tuplehash[!dir].tuple.dst.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.src.u.all != + ct->tuplehash[!dir].tuple.dst.u.all +#endif + ) + return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; + } + return ret; } static unsigned int @@ -217,7 +235,12 @@ ip_nat_local_fn(unsigned int hooknum, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.ip != - ct->tuplehash[!dir].tuple.src.ip) + ct->tuplehash[!dir].tuple.src.ip +#ifdef CONFIG_XFRM + || ct->tuplehash[dir].tuple.dst.u.all != + ct->tuplehash[dir].tuple.src.u.all +#endif + ) return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; } return ret; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html