Commit 4125458a authored by Rusty Russell's avatar Rusty Russell Committed by Patrick McHardy

[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.
parent 0379e92f
......@@ -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 */
......@@ -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;
}
......
......@@ -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)
......
......@@ -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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment