Refined state machine update placement to (1) properly deal with gaps capped

by clean FIN handshakes, and (1) fix failure to detect split routing.

Fixed typo flagged by Pierre Lalet.
This commit is contained in:
Vern Paxson 2019-04-22 09:13:23 -07:00
parent 915189a06a
commit 9c8ad11d92
6 changed files with 42 additions and 29 deletions

View file

@ -1321,14 +1321,6 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
PacketWithRST();
}
int32 delta_last = update_last_seq(endpoint, seq_one_past_segment, flags, len);
endpoint->last_time = current_timestamp;
int do_close;
int gen_event;
UpdateStateMachine(current_timestamp, endpoint, peer, base_seq, ack_seq,
len, delta_last, is_orig, flags, do_close, gen_event);
uint64 rel_ack = 0;
if ( flags.ACK() )
@ -1361,10 +1353,25 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
// Don't trust ack's in RST packets.
update_ack_seq(peer, ack_seq);
}
peer->AckReceived(rel_ack);
}
int32 delta_last = update_last_seq(endpoint, seq_one_past_segment, flags, len);
endpoint->last_time = current_timestamp;
int do_close;
int gen_event;
UpdateStateMachine(current_timestamp, endpoint, peer, base_seq, ack_seq,
len, delta_last, is_orig, flags, do_close, gen_event);
if ( flags.ACK() )
// We wait on doing this until we've updated the state
// machine so that if the ack reveals a content gap,
// we can tell whether it came at the very end of the
// connection (in a FIN or RST). Those gaps aren't
// reliable - especially those for RSTs - and we refrain
// from flagging them in the connection history.
peer->AckReceived(rel_ack);
if ( tcp_packet )
GeneratePacketEvent(rel_seq, rel_ack, data, len, caplen, is_orig,
flags);

View file

@ -175,7 +175,7 @@ public:
// Called to inform endpoint that it has offered a zero window.
void ZeroWindow();
// Called to inform endpoint that it a gap occurred.
// Called to inform endpoint that a gap occurred.
void Gap(uint64 seq, uint64 len);
// Returns true if the data was used (and hence should be recorded

View file

@ -112,29 +112,35 @@ void TCP_Reassembler::SetContentsFile(BroFile* f)
record_contents_file = f;
}
static inline bool established(const TCP_Endpoint* a, const TCP_Endpoint* b)
static inline bool is_clean(const TCP_Endpoint* a)
{
return a->state == TCP_ENDPOINT_ESTABLISHED &&
b->state == TCP_ENDPOINT_ESTABLISHED;
return a->state == TCP_ENDPOINT_ESTABLISHED ||
(a->state == TCP_ENDPOINT_CLOSED &&
a->prev_state == TCP_ENDPOINT_ESTABLISHED);
}
static inline bool established_or_cleanly_closing(const TCP_Endpoint* a,
const TCP_Endpoint* b)
{
return is_clean(a) && is_clean(b);
}
static inline bool report_gap(const TCP_Endpoint* a, const TCP_Endpoint* b)
{
return content_gap &&
( BifConst::report_gaps_for_partial || established(a, b) );
( BifConst::report_gaps_for_partial ||
established_or_cleanly_closing(a, b) );
}
void TCP_Reassembler::Gap(uint64 seq, uint64 len)
{
// Only report on content gaps for connections that
// are in a cleanly established state. In other
// states, these can arise falsely due to things
// are in a cleanly established or closing state. In
// other states, these can arise falsely due to things
// like sequence number mismatches in RSTs, or
// unseen previous packets in partial connections.
// The one opportunity we lose here is on clean FIN
// handshakes, but Oh Well.
if ( established(endp, endp->peer) )
if ( established_or_cleanly_closing(endp, endp->peer) )
endp->Gap(seq, len);
if ( report_gap(endp, endp->peer) )