Commit 356d7d88 authored by Yuchung Cheng's avatar Yuchung Cheng Committed by Pablo Neira Ayuso

netfilter: nf_conntrack: fix tcp_in_window for Fast Open

Currently the conntrack checks if the ending sequence of a packet
falls within the observed receive window. However it does so even
if it has not observe any packet from the remote yet and uses an
uninitialized receive window (td_maxwin).

If a connection uses Fast Open to send a SYN-data packet which is
dropped afterward in the network. The subsequent SYNs retransmits
will all fail this check and be discarded, leading to a connection
timeout. This is because the SYN retransmit does not contain data
payload so

end == initial sequence number (isn) + 1
sender->td_end == isn + syn_data_len
receiver->td_maxwin == 0

The fix is to only apply this check after td_maxwin is initialized.
Reported-by: default avatarMichael Chan <mcfchan@stanford.edu>
Signed-off-by: default avatarYuchung Cheng <ycheng@google.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent e4d091d7
...@@ -526,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct, ...@@ -526,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
__u32 seq, ack, sack, end, win, swin; __u32 seq, ack, sack, end, win, swin;
s16 receiver_offset; s16 receiver_offset;
bool res; bool res, in_recv_win;
/* /*
* Get the required data from the packet. * Get the required data from the packet.
...@@ -649,14 +649,18 @@ static bool tcp_in_window(const struct nf_conn *ct, ...@@ -649,14 +649,18 @@ static bool tcp_in_window(const struct nf_conn *ct,
receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
receiver->td_scale); receiver->td_scale);
/* Is the ending sequence in the receive window (if available)? */
in_recv_win = !receiver->td_maxwin ||
after(end, sender->td_end - receiver->td_maxwin - 1);
pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n", pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
before(seq, sender->td_maxend + 1), before(seq, sender->td_maxend + 1),
after(end, sender->td_end - receiver->td_maxwin - 1), (in_recv_win ? 1 : 0),
before(sack, receiver->td_end + 1), before(sack, receiver->td_end + 1),
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)); after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1));
if (before(seq, sender->td_maxend + 1) && if (before(seq, sender->td_maxend + 1) &&
after(end, sender->td_end - receiver->td_maxwin - 1) && in_recv_win &&
before(sack, receiver->td_end + 1) && before(sack, receiver->td_end + 1) &&
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) { after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) {
/* /*
...@@ -725,7 +729,7 @@ static bool tcp_in_window(const struct nf_conn *ct, ...@@ -725,7 +729,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: %s ", "nf_ct_tcp: %s ",
before(seq, sender->td_maxend + 1) ? before(seq, sender->td_maxend + 1) ?
after(end, sender->td_end - receiver->td_maxwin - 1) ? in_recv_win ?
before(sack, receiver->td_end + 1) ? before(sack, receiver->td_end + 1) ?
after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG"
: "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is under the lower bound (possible overly delayed ACK)"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment