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, ...@@ -14,5 +14,10 @@ extern int ip_nat_rule_find(struct sk_buff **pskb,
const struct net_device *out, const struct net_device *out,
struct ip_conntrack *ct, struct ip_conntrack *ct,
struct ip_nat_info *info); 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
#endif /* _IP_NAT_RULE_H */ #endif /* _IP_NAT_RULE_H */
...@@ -516,12 +516,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, ...@@ -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 new_tuple, inv_tuple, reply;
struct ip_conntrack_tuple orig_tp; struct ip_conntrack_tuple orig_tp;
struct ip_nat_info *info = &conntrack->nat.info; struct ip_nat_info *info = &conntrack->nat.info;
int in_hashes = info->initialized;
MUST_BE_WRITE_LOCKED(&ip_nat_lock); MUST_BE_WRITE_LOCKED(&ip_nat_lock);
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|| hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_POST_ROUTING
|| hooknum == NF_IP_LOCAL_OUT); || hooknum == NF_IP_LOCAL_OUT);
IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); 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 /* What we've got will look like inverse of reply. Normally
this is what is in the conntrack, except for prior this is what is in the conntrack, except for prior
...@@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, ...@@ -638,6 +640,14 @@ ip_nat_setup_info(struct ip_conntrack *conntrack,
/* It's done. */ /* It's done. */
info->initialized |= (1 << HOOK2MANIP(hooknum)); 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; return NF_ACCEPT;
} }
......
...@@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const char *tablename, ...@@ -233,7 +233,7 @@ static int ipt_dnat_checkentry(const char *tablename,
return 1; return 1;
} }
static inline unsigned int inline unsigned int
alloc_null_binding(struct ip_conntrack *conntrack, alloc_null_binding(struct ip_conntrack *conntrack,
struct ip_nat_info *info, struct ip_nat_info *info,
unsigned int hooknum) unsigned int hooknum)
......
...@@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum, ...@@ -119,7 +119,6 @@ ip_nat_fn(unsigned int hooknum,
/* Seen it before? This can happen for loopback, retrans, /* Seen it before? This can happen for loopback, retrans,
or local packets.. */ or local packets.. */
if (!(info->initialized & (1 << maniptype))) { if (!(info->initialized & (1 << maniptype))) {
int in_hashes = info->initialized;
unsigned int ret; unsigned int ret;
if (ct->master if (ct->master
...@@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum, ...@@ -130,9 +129,10 @@ ip_nat_fn(unsigned int hooknum,
} else { } else {
#ifdef CONFIG_IP_NF_NAT_LOCAL #ifdef CONFIG_IP_NF_NAT_LOCAL
/* LOCAL_IN hook doesn't have a chain! */ /* LOCAL_IN hook doesn't have a chain! */
if (hooknum == NF_IP_LOCAL_IN) { if (hooknum == NF_IP_LOCAL_IN)
ret = NF_ACCEPT; ret = alloc_null_binding(ct, info,
} else hooknum);
else
#endif #endif
ret = ip_nat_rule_find(pskb, hooknum, in, out, ret = ip_nat_rule_find(pskb, hooknum, in, out,
ct, info); ct, info);
...@@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum, ...@@ -142,13 +142,6 @@ ip_nat_fn(unsigned int hooknum,
WRITE_UNLOCK(&ip_nat_lock); WRITE_UNLOCK(&ip_nat_lock);
return ret; return ret;
} }
if (in_hashes) {
IP_NF_ASSERT(info->bysource.conntrack);
replace_in_hashes(ct, info);
} else {
place_in_hashes(ct, info);
}
} else } else
DEBUGP("Already setup manip %s for ct %p\n", DEBUGP("Already setup manip %s for ct %p\n",
maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", 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