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

netfilter: nf_nat: avoid double seq_adjust for loopback

Avoid double seq adjustment for loopback traffic
because it causes silent repetition of TCP data. One
example is passive FTP with DNAT rule and difference in the
length of IP addresses.

This patch adds check if packet is sent and
received via loopback device. As the same conntrack is
used both for outgoing and incoming direction, we restrict
seq adjustment to happen only in POSTROUTING.

Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Julian Anastasov and committed by
Patrick McHardy
42c1edd3 2c38de4c

+9 -1
+6
include/net/netfilter/nf_conntrack.h
··· 307 307 return test_bit(IPS_UNTRACKED_BIT, &ct->status); 308 308 } 309 309 310 + /* Packet is received from loopback */ 311 + static inline bool nf_is_loopback_packet(const struct sk_buff *skb) 312 + { 313 + return skb->dev && skb->skb_iif && skb->dev->flags & IFF_LOOPBACK; 314 + } 315 + 310 316 extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); 311 317 extern unsigned int nf_conntrack_htable_size; 312 318 extern unsigned int nf_conntrack_max;
+3 -1
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
··· 121 121 return ret; 122 122 } 123 123 124 - if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { 124 + /* adjust seqs for loopback traffic only in outgoing direction */ 125 + if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 126 + !nf_is_loopback_packet(skb)) { 125 127 typeof(nf_nat_seq_adjust_hook) seq_adjust; 126 128 127 129 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);