Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_nat: place conntrack in source hash after SNAT is done

If SNAT isn't done, the wrong info maybe got by the other cts.

As the filter table is after DNAT table, the packets dropped in filter
table also bother bysource hash table.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Changli Gao and committed by
Patrick McHardy
41a7cab6 4cda47d2

+11 -7
+11 -7
net/ipv4/netfilter/nf_nat_core.c
··· 221 221 manips not an issue. */ 222 222 if (maniptype == IP_NAT_MANIP_SRC && 223 223 !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) { 224 - if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) { 224 + /* try the original tuple first */ 225 + if (in_range(orig_tuple, range)) { 226 + if (!nf_nat_used_tuple(orig_tuple, ct)) { 227 + *tuple = *orig_tuple; 228 + return; 229 + } 230 + } else if (find_appropriate_src(net, zone, orig_tuple, tuple, 231 + range)) { 225 232 pr_debug("get_unique_tuple: Found current src map\n"); 226 233 if (!nf_nat_used_tuple(tuple, ct)) 227 234 return; ··· 273 266 struct net *net = nf_ct_net(ct); 274 267 struct nf_conntrack_tuple curr_tuple, new_tuple; 275 268 struct nf_conn_nat *nat; 276 - int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); 277 269 278 270 /* nat helper or nfctnetlink also setup binding */ 279 271 nat = nfct_nat(ct); ··· 312 306 ct->status |= IPS_DST_NAT; 313 307 } 314 308 315 - /* Place in source hash if this is the first time. */ 316 - if (have_to_hash) { 309 + if (maniptype == IP_NAT_MANIP_SRC) { 317 310 unsigned int srchash; 318 311 319 312 srchash = hash_by_src(net, nf_ct_zone(ct), ··· 540 535 if (nat == NULL || nat->ct == NULL) 541 536 return; 542 537 543 - NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK); 538 + NF_CT_ASSERT(nat->ct->status & IPS_SRC_NAT_DONE); 544 539 545 540 spin_lock_bh(&nf_nat_lock); 546 541 hlist_del_rcu(&nat->bysource); ··· 553 548 struct nf_conn_nat *old_nat = old; 554 549 struct nf_conn *ct = old_nat->ct; 555 550 556 - if (!ct || !(ct->status & IPS_NAT_DONE_MASK)) 551 + if (!ct || !(ct->status & IPS_SRC_NAT_DONE)) 557 552 return; 558 553 559 554 spin_lock_bh(&nf_nat_lock); 560 - new_nat->ct = ct; 561 555 hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource); 562 556 spin_unlock_bh(&nf_nat_lock); 563 557 }