From 4125458a853fe47430ad5ade363ef1384665f0d5 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 2 Oct 2003 09:27:04 -0700 Subject: [PATCH] [NETFILTER]: LOCAL_OUT NAT fix, part 2. Balazs Scheidler pointed out that we can fail to call ip_nat_setup_info for local NAT, which causes the connection to be added twice. Boom. Also move the hash table insertion into ip_nat_setup_info. --- include/linux/netfilter_ipv4/ip_nat_rule.h | 5 +++++ net/ipv4/netfilter/ip_nat_core.c | 10 ++++++++++ net/ipv4/netfilter/ip_nat_rule.c | 2 +- net/ipv4/netfilter/ip_nat_standalone.c | 15 ++++----------- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h index 488efcee2f3ce..fecd2a06dcd81 100644 --- a/include/linux/netfilter_ipv4/ip_nat_rule.h +++ b/include/linux/netfilter_ipv4/ip_nat_rule.h @@ -14,5 +14,10 @@ extern int ip_nat_rule_find(struct sk_buff **pskb, const struct net_device *out, struct ip_conntrack *ct, struct ip_nat_info *info); + +extern unsigned int +alloc_null_binding(struct ip_conntrack *conntrack, + struct ip_nat_info *info, + unsigned int hooknum); #endif #endif /* _IP_NAT_RULE_H */ diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index efd0e23300e13..a6a427dbbe272 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -516,12 +516,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, struct ip_conntrack_tuple new_tuple, inv_tuple, reply; struct ip_conntrack_tuple orig_tp; struct ip_nat_info *info = &conntrack->nat.info; + int in_hashes = info->initialized; MUST_BE_WRITE_LOCKED(&ip_nat_lock); IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_OUT); IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); /* What we've got will look like inverse of reply. Normally this is what is in the conntrack, except for prior @@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, /* It's done. */ info->initialized |= (1 << HOOK2MANIP(hooknum)); + + if (in_hashes) { + IP_NF_ASSERT(info->bysource.conntrack); + replace_in_hashes(conntrack, info); + } else { + place_in_hashes(conntrack, info); + } + return NF_ACCEPT; } diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c index f3416f718a23d..f88c208796234 100644 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ b/net/ipv4/netfilter/ip_nat_rule.c @@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const char *tablename, return 1; } -static inline unsigned int +inline unsigned int alloc_null_binding(struct ip_conntrack *conntrack, struct ip_nat_info *info, unsigned int hooknum) diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index e9e1190b2679a..bb45edc99c48b 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum, /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!(info->initialized & (1 << maniptype))) { - int in_hashes = info->initialized; unsigned int ret; if (ct->master @@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum, } else { #ifdef CONFIG_IP_NF_NAT_LOCAL /* LOCAL_IN hook doesn't have a chain! */ - if (hooknum == NF_IP_LOCAL_IN) { - ret = NF_ACCEPT; - } else + if (hooknum == NF_IP_LOCAL_IN) + ret = alloc_null_binding(ct, info, + hooknum); + else #endif ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); @@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum, WRITE_UNLOCK(&ip_nat_lock); return ret; } - - if (in_hashes) { - IP_NF_ASSERT(info->bysource.conntrack); - replace_in_hashes(ct, info); - } else { - place_in_hashes(ct, info); - } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", -- 2.53.0