diff options
author | Patrick McHardy <kaber@trash.net> | 2009-06-29 08:07:56 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2009-06-29 08:07:56 -0400 |
commit | a3a9f79e361e864f0e9d75ebe2a0cb43d17c4272 (patch) | |
tree | e38bb7cc051cf197a813d553713e3071d375a1b9 /net/ipv4 | |
parent | 308ff823ebd749a94d3b6ac26b95bc0eb114c39e (diff) |
netfilter: tcp conntrack: fix unacknowledged data detection with NAT
When NAT helpers change the TCP packet size, the highest seen sequence
number needs to be corrected. This is currently only done upwards, when
the packet size is reduced the sequence number is unchanged. This causes
TCP conntrack to falsely detect unacknowledged data and decrease the
timeout.
Fix by updating the highest seen sequence number in both directions after
packet mangling.
Tested-by: Krzysztof Piotr Oledzki <ole@ans.pl>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_helper.c | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 155c008626c8..09172a65d9b6 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c | |||
@@ -191,7 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, | |||
191 | ct, ctinfo); | 191 | ct, ctinfo); |
192 | /* Tell TCP window tracking about seq change */ | 192 | /* Tell TCP window tracking about seq change */ |
193 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), | 193 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), |
194 | ct, CTINFO2DIR(ctinfo)); | 194 | ct, CTINFO2DIR(ctinfo), |
195 | (int)rep_len - (int)match_len); | ||
195 | 196 | ||
196 | nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); | 197 | nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); |
197 | } | 198 | } |
@@ -377,6 +378,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, | |||
377 | struct tcphdr *tcph; | 378 | struct tcphdr *tcph; |
378 | int dir; | 379 | int dir; |
379 | __be32 newseq, newack; | 380 | __be32 newseq, newack; |
381 | s16 seqoff, ackoff; | ||
380 | struct nf_conn_nat *nat = nfct_nat(ct); | 382 | struct nf_conn_nat *nat = nfct_nat(ct); |
381 | struct nf_nat_seq *this_way, *other_way; | 383 | struct nf_nat_seq *this_way, *other_way; |
382 | 384 | ||
@@ -390,15 +392,18 @@ nf_nat_seq_adjust(struct sk_buff *skb, | |||
390 | 392 | ||
391 | tcph = (void *)skb->data + ip_hdrlen(skb); | 393 | tcph = (void *)skb->data + ip_hdrlen(skb); |
392 | if (after(ntohl(tcph->seq), this_way->correction_pos)) | 394 | if (after(ntohl(tcph->seq), this_way->correction_pos)) |
393 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); | 395 | seqoff = this_way->offset_after; |
394 | else | 396 | else |
395 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); | 397 | seqoff = this_way->offset_before; |
396 | 398 | ||
397 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, | 399 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, |
398 | other_way->correction_pos)) | 400 | other_way->correction_pos)) |
399 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); | 401 | ackoff = other_way->offset_after; |
400 | else | 402 | else |
401 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); | 403 | ackoff = other_way->offset_before; |
404 | |||
405 | newseq = htonl(ntohl(tcph->seq) + seqoff); | ||
406 | newack = htonl(ntohl(tcph->ack_seq) - ackoff); | ||
402 | 407 | ||
403 | inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); | 408 | inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0); |
404 | inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); | 409 | inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0); |
@@ -413,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, | |||
413 | if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo)) | 418 | if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo)) |
414 | return 0; | 419 | return 0; |
415 | 420 | ||
416 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir); | 421 | nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff); |
417 | 422 | ||
418 | return 1; | 423 | return 1; |
419 | } | 424 | } |