aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2005-09-06 18:09:43 -0400
committerDavid S. Miller <davem@davemloft.net>2005-09-06 18:09:43 -0400
commit03486a4f838c55481317fca5ac2e7d12550a4fb7 (patch)
tree9c5e5cd835102d67198e5fd1c6756f3b0de65a2c
parent31c913e7fd48000163a88cfe10383fd3be20910e (diff)
[NETFILTER]: Handle NAT module load race
When the NAT module is loaded when connections are already confirmed it must not change their tuples anymore. This is especially important with CONFIG_NETFILTER_DEBUG, the netfilter listhelp functions will refuse to remove an entry from a list when it can not be found on the list, so when a changed tuple hashes to a new bucket the entry is kept in the list until and after the conntrack is freed. Allocate the exact conntrack tuple for NAT for already confirmed connections or drop them if that fails. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter_ipv4/ip_nat_rule.h5
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c21
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c8
3 files changed, 32 insertions, 2 deletions
diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h
index fecd2a06dcd8..73b9552e6a89 100644
--- a/include/linux/netfilter_ipv4/ip_nat_rule.h
+++ b/include/linux/netfilter_ipv4/ip_nat_rule.h
@@ -19,5 +19,10 @@ extern unsigned int
19alloc_null_binding(struct ip_conntrack *conntrack, 19alloc_null_binding(struct ip_conntrack *conntrack,
20 struct ip_nat_info *info, 20 struct ip_nat_info *info,
21 unsigned int hooknum); 21 unsigned int hooknum);
22
23extern unsigned int
24alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
25 struct ip_nat_info *info,
26 unsigned int hooknum);
22#endif 27#endif
23#endif /* _IP_NAT_RULE_H */ 28#endif /* _IP_NAT_RULE_H */
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 60d70fa41a15..cb66b8bddeb3 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -255,6 +255,27 @@ alloc_null_binding(struct ip_conntrack *conntrack,
255 return ip_nat_setup_info(conntrack, &range, hooknum); 255 return ip_nat_setup_info(conntrack, &range, hooknum);
256} 256}
257 257
258unsigned int
259alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
260 struct ip_nat_info *info,
261 unsigned int hooknum)
262{
263 u_int32_t ip
264 = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
265 ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
266 : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
267 u_int16_t all
268 = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
269 ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
270 : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
271 struct ip_nat_range range
272 = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
273
274 DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
275 conntrack, NIPQUAD(ip));
276 return ip_nat_setup_info(conntrack, &range, hooknum);
277}
278
258int ip_nat_rule_find(struct sk_buff **pskb, 279int ip_nat_rule_find(struct sk_buff **pskb,
259 unsigned int hooknum, 280 unsigned int hooknum,
260 const struct net_device *in, 281 const struct net_device *in,
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 89db052add81..0ff368b131f6 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -123,8 +123,12 @@ ip_nat_fn(unsigned int hooknum,
123 if (!ip_nat_initialized(ct, maniptype)) { 123 if (!ip_nat_initialized(ct, maniptype)) {
124 unsigned int ret; 124 unsigned int ret;
125 125
126 /* LOCAL_IN hook doesn't have a chain! */ 126 if (unlikely(is_confirmed(ct)))
127 if (hooknum == NF_IP_LOCAL_IN) 127 /* NAT module was loaded late */
128 ret = alloc_null_binding_confirmed(ct, info,
129 hooknum);
130 else if (hooknum == NF_IP_LOCAL_IN)
131 /* LOCAL_IN hook doesn't have a chain! */
128 ret = alloc_null_binding(ct, info, hooknum); 132 ret = alloc_null_binding(ct, info, hooknum);
129 else 133 else
130 ret = ip_nat_rule_find(pskb, hooknum, 134 ret = ip_nat_rule_find(pskb, hooknum,