Skip to content

Commit

Permalink
netfilter: tcp conntrack: fix unacknowledged data detection with NAT
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Patrick McHardy <[email protected]>
  • Loading branch information
kaber committed Jun 29, 2009
1 parent 308ff82 commit a3a9f79
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 11 deletions.
4 changes: 2 additions & 2 deletions include/net/netfilter/nf_conntrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
/* 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);
struct nf_conn *ct, int dir,
s16 offset);

/* Fake conntrack entry for untracked connections */
extern struct nf_conn nf_conntrack_untracked;
Expand Down
17 changes: 11 additions & 6 deletions net/ipv4/netfilter/nf_nat_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
ct, ctinfo);
/* Tell TCP window tracking about seq change */
nf_conntrack_tcp_update(skb, ip_hdrlen(skb),
ct, CTINFO2DIR(ctinfo));
ct, CTINFO2DIR(ctinfo),
(int)rep_len - (int)match_len);

nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
}
Expand Down Expand Up @@ -377,6 +378,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
struct tcphdr *tcph;
int dir;
__be32 newseq, newack;
s16 seqoff, ackoff;
struct nf_conn_nat *nat = nfct_nat(ct);
struct nf_nat_seq *this_way, *other_way;

Expand All @@ -390,15 +392,18 @@ nf_nat_seq_adjust(struct sk_buff *skb,

tcph = (void *)skb->data + ip_hdrlen(skb);
if (after(ntohl(tcph->seq), this_way->correction_pos))
newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
seqoff = this_way->offset_after;
else
newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
seqoff = this_way->offset_before;

if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
other_way->correction_pos))
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
ackoff = other_way->offset_after;
else
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
ackoff = other_way->offset_before;

newseq = htonl(ntohl(tcph->seq) + seqoff);
newack = htonl(ntohl(tcph->ack_seq) - ackoff);

inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
Expand All @@ -413,7 +418,7 @@ nf_nat_seq_adjust(struct sk_buff *skb,
if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo))
return 0;

nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir);
nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff);

return 1;
}
Expand Down
6 changes: 3 additions & 3 deletions net/netfilter/nf_conntrack_proto_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,8 +720,8 @@ static bool tcp_in_window(const struct nf_conn *ct,
/* Caller must linearize skb at tcp header. */
void nf_conntrack_tcp_update(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conn *ct,
int dir)
struct nf_conn *ct, int dir,
s16 offset)
{
const struct tcphdr *tcph = (const void *)skb->data + dataoff;
const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
Expand All @@ -734,7 +734,7 @@ void nf_conntrack_tcp_update(const struct sk_buff *skb,
/*
* We have to worry for the ack in the reply packet only...
*/
if (after(end, ct->proto.tcp.seen[dir].td_end))
if (ct->proto.tcp.seen[dir].td_end + offset == end)
ct->proto.tcp.seen[dir].td_end = end;
ct->proto.tcp.last_end = end;
spin_unlock_bh(&ct->lock);
Expand Down

0 comments on commit a3a9f79

Please sign in to comment.