netfilter 01/02: nf_nat: fix NAT issue in 2.6.30.4+
Subsystems (3)
Hi Dave,
the following two patches fix two netfilter bugs:
- incorrect sequence number tracking in TCP conntrack in combination with NAT helpers that enlarge the packet, causing incorrectly detected out of window packets
- a regression in the connlimit match
The first patch is quite large for this late in the release cycle, so if you prefer, I'll queue it up for net-next instead.
I'll pass on both to -stable once they hit upstream.
Please apply, thanks!
commit 0132f9835c1c19a369954e1eb56dca80a1382369
Author: Jozsef Kadlecsik <[email protected]> Date: Thu Sep 17 13:05:15 2009 +0200
netfilter: nf_nat: fix NAT issue in 2.6.30.4+
Vitezslav Samel discovered that since 2.6.30.4+ active FTP can not work over NAT. The "cause" of the problem was a fix of unacknowledged data detection with NAT (commit a3a9f79e361e864f0e9d75ebe2a0cb43d17c4272). However, actually, that fix uncovered a long standing bug in TCP conntrack:
when NAT was enabled, we simply updated the max of the right edge of the segments we have seen (td_end), by the offset NAT produced with changing IP/port in the data. However, we did not update the other parameter (td_maxend) which is affected by the NAT offset. Thus that could drift away from the correct value and thus resulted breaking active FTP.
The patch below fixes the issue by *not* updating the conntrack parameters from NAT, but instead taking into account the NAT offsets in conntrack in a consistent way. (Updating from NAT would be more harder and expensive because it'd need to re-calculate parameters we already calculated in conntrack.)
include/net/netfilter/nf_conntrack.h +3 -5
@@ -255,11 +255,9 @@ static inline bool nf_ct_kill(struct nf_conn *ct) }/* These are for NAT. Icky. */ -/* Update TCP window tracking data when NAT mangles the packet */ -extern void nf_conntrack_tcp_update (const struct sk_buff *skb, -unsigned int dataoff, -struct nf_conn *ct,int dir, -s16 offset); +extern s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, +enum ip_conntrack_dir dir, +u32 seq);/* Fake conntrack entry for untracked connections */ extern struct nf_conn nf_conntrack_untracked;
include/net/netfilter/nf_nat_helper.h +4 -0
@@ -32,4 +32,8 @@ extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,* to port ct->master->saved_proto. */ extern void nf_nat_follow_master (struct nf_conn *ct,struct nf_conntrack_expect *this); + +extern s16 nf_nat_get_offset (const struct nf_conn *ct, +enum ip_conntrack_dir dir, +u32 seq);#endif
net/ipv4/netfilter/nf_nat_core.c +3 -0
@@ -750,6 +750,8 @@ static int __init nf_nat_init(void)BUG_ON (nfnetlink_parse_nat_setup_hook !=NULL );rcu_assign_pointer (nfnetlink_parse_nat_setup_hook, nfnetlink_parse_nat_setup); +BUG_ON (nf_ct_nat_offset !=NULL ); +rcu_assign_pointer (nf_ct_nat_offset, nf_nat_get_offset);return 0 ; cleanup_extend:
@@ -764,6 +766,7 @@ static void __exit nf_nat_cleanup(void)nf_ct_extend_unregister (&nat_extend);rcu_assign_pointer (nf_nat_seq_adjust_hook,NULL );rcu_assign_pointer (nfnetlink_parse_nat_setup_hook,NULL ); +rcu_assign_pointer (nf_ct_nat_offset,NULL );synchronize_net (); }
net/ipv4/netfilter/nf_nat_helper.c +23 -11
@@ -73,6 +73,28 @@ adjust_tcp_sequence(u32 seq,DUMP_OFFSET (this_way); } +/* Get the offset value, for conntrack */ +s16 nf_nat_get_offset (const struct nf_conn *ct, +enum ip_conntrack_dir dir, +u32 seq) +{ +struct nf_conn_nat *nat =nfct_nat (ct); +struct nf_nat_seq *this_way; +s16 offset; + +if (!nat) +return 0 ; + + this_way = &nat->seq[dir]; +spin_lock_bh (&nf_nat_seqofs_lock); + offset =after (seq, this_way->correction_pos) + ? this_way->offset_after : this_way->offset_before; +spin_unlock_bh (&nf_nat_seqofs_lock); + +return offset; +} +EXPORT_SYMBOL_GPL (nf_nat_get_offset); +/* Frobs data inside this packet, which is linear. */ static void mangle_contents(struct sk_buff *skb, unsigned int dataoff,
@@ -189,11 +211,6 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,adjust_tcp_sequence (ntohl (tcph->seq), (int )rep_len - (int )match_len, ct, ctinfo); -/* Tell TCP window tracking about seq change */ -nf_conntrack_tcp_update (skb,ip_hdrlen (skb), - ct,CTINFO2DIR (ctinfo), - (int )rep_len - (int )match_len); -nf_conntrack_event_cache (IPCT_NATSEQADJ , ct); }return 1 ;
@@ -415,12 +432,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, tcph->seq = newseq; tcph->ack_seq = newack; -if (!nf_nat_sack_adjust (skb, tcph, ct, ctinfo)) -return 0 ; - -nf_conntrack_tcp_update (skb,ip_hdrlen (skb), ct, dir, seqoff); - -return 1 ; +return nf_nat_sack_adjust (skb, tcph, ct, ctinfo); }/* Setup NAT on this expected conntrack so it follows master. */
net/netfilter/nf_conntrack_core.c +8 -0
@@ -1350,6 +1350,11 @@ err_stat:return ret; } +s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, +enum ip_conntrack_dir dir, +u32 seq); +EXPORT_SYMBOL_GPL (nf_ct_nat_offset); +int nf_conntrack_init (struct net *net) {int ret;
@@ -1367,6 +1372,9 @@ int nf_conntrack_init(struct net *net)/* For use by REJECT target */ rcu_assign_pointer (ip_ct_attach, nf_conntrack_attach);rcu_assign_pointer (nf_ct_destroy, destroy_conntrack); + +/* Howto get NAT offsets */ +rcu_assign_pointer (nf_ct_nat_offset,NULL ); }return 0 ;
net/netfilter/nf_conntrack_proto_tcp.c +26 -38
103 lines not on this page · raw message
From: Patrick McHardy <[email protected]>
Date: Thu, 05 Nov 2009 19:23:46 +0100
Quoted 1 line
netfilter: nf_nat: fix NAT issue in 2.6.30.4+
...
Quoted 2 lines
Signed-off-by Jozsef Kadlecsik <[email protected]>Signed-off-by Patrick McHardy <[email protected]>
Applied to net-2.6