Skip to content

Commit

Permalink
[NETFILTER]: Handle NAT module load race
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Sep 6, 2005
1 parent 31c913e commit 03486a4
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
5 changes: 5 additions & 0 deletions include/linux/netfilter_ipv4/ip_nat_rule.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,10 @@ extern unsigned int
alloc_null_binding(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum);

extern unsigned int
alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum);
#endif
#endif /* _IP_NAT_RULE_H */
21 changes: 21 additions & 0 deletions net/ipv4/netfilter/ip_nat_rule.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,27 @@ alloc_null_binding(struct ip_conntrack *conntrack,
return ip_nat_setup_info(conntrack, &range, hooknum);
}

unsigned int
alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum)
{
u_int32_t ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
u_int16_t all
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
struct ip_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };

DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
conntrack, NIPQUAD(ip));
return ip_nat_setup_info(conntrack, &range, hooknum);
}

int ip_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
Expand Down
8 changes: 6 additions & 2 deletions net/ipv4/netfilter/ip_nat_standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,12 @@ ip_nat_fn(unsigned int hooknum,
if (!ip_nat_initialized(ct, maniptype)) {
unsigned int ret;

/* LOCAL_IN hook doesn't have a chain! */
if (hooknum == NF_IP_LOCAL_IN)
if (unlikely(is_confirmed(ct)))
/* NAT module was loaded late */
ret = alloc_null_binding_confirmed(ct, info,
hooknum);
else if (hooknum == NF_IP_LOCAL_IN)
/* LOCAL_IN hook doesn't have a chain! */
ret = alloc_null_binding(ct, info, hooknum);
else
ret = ip_nat_rule_find(pskb, hooknum,
Expand Down

0 comments on commit 03486a4

Please sign in to comment.