Disregard TCP FIN flag if it arrives in a segment not at window start.

Fixes #111.
This commit is contained in:
whitequark 2018-01-05 20:54:06 +00:00
parent b653a6e421
commit f494200c8c
1 changed files with 45 additions and 6 deletions

View File

@ -887,6 +887,11 @@ impl<'a> TcpSocket<'a> {
}
}
let window_start = self.remote_seq_no + self.rx_buffer.len();
let window_end = self.remote_seq_no + self.rx_buffer.capacity();
let segment_start = repr.seq_number;
let segment_end = repr.seq_number + repr.segment_len();
let payload_offset;
match self.state {
// In LISTEN and SYN-SENT states, we have not yet synchronized with the remote end.
@ -896,11 +901,6 @@ impl<'a> TcpSocket<'a> {
_ => {
let mut segment_in_window = true;
let window_start = self.remote_seq_no + self.rx_buffer.len();
let window_end = self.remote_seq_no + self.rx_buffer.capacity();
let segment_start = repr.seq_number;
let segment_end = repr.seq_number + repr.segment_len();
if window_start == window_end && segment_start != segment_end {
net_debug!("{}:{}:{}: non-zero-length segment with zero receive window, \
will only send an ACK",
@ -960,8 +960,18 @@ impl<'a> TcpSocket<'a> {
}
}
// Disregard control flags we don't care about or shouldn't act on yet.
let mut control = repr.control;
control = control.quash_psh();
// If a FIN is received at the end of the current segment but the start of the segment
// is not at the start of the receive window, disregard this FIN.
if control == TcpControl::Fin && window_start != segment_start {
control = TcpControl::None;
}
// Validate and update the state.
match (self.state, repr.control.quash_psh()) {
match (self.state, control) {
// RSTs are not accepted in the LISTEN state.
(State::Listen, TcpControl::Rst) =>
return Err(Error::Dropped),
@ -2289,6 +2299,35 @@ mod test {
sanity!(s, socket_close_wait());
}
#[test]
fn test_established_fin_after_missing() {
let mut s = socket_established();
send!(s, TcpRepr {
control: TcpControl::Fin,
seq_number: REMOTE_SEQ + 1 + 6,
ack_number: Some(LOCAL_SEQ + 1),
payload: &b"123456"[..],
..SEND_TEMPL
}, Ok(Some(TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1),
..RECV_TEMPL
})));
assert_eq!(s.state, State::Established);
send!(s, TcpRepr {
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1),
payload: &b"abcdef"[..],
..SEND_TEMPL
}, Ok(Some(TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1 + 6 + 6),
window_len: 52,
..RECV_TEMPL
})));
assert_eq!(s.state, State::Established);
}
#[test]
fn test_established_send_fin() {
let mut s = socket_established();