Fix reassembly of data w/ sizes beyond 32-bit capacities (BIT-348).

The main change is that reassembly code (e.g. for TCP) now uses
int64/uint64 (signedness is situational) data types in place of int
types in order to support delivering data to analyzers that pass 2GB
thresholds.  There's also changes in logic that accompany the change in
data types, e.g. to fix TCP sequence space arithmetic inconsistencies.

Another significant change is in the Analyzer API: the *Packet and
*Undelivered methods now use a uint64 in place of an int for the
relative sequence space offset parameter.
This commit is contained in:
Jon Siwek 2014-04-09 13:03:24 -05:00
parent 2f57c26d5b
commit 2b3c2bd394
75 changed files with 1627 additions and 1540 deletions

View file

@ -38,32 +38,92 @@ public:
EndpointState State() const { return state; }
void SetState(EndpointState new_state);
bro_int_t Size() const;
uint64 Size() const;
int IsActive() const
{ return state != TCP_ENDPOINT_INACTIVE && ! did_close; }
double StartTime() const { return start_time; }
double LastTime() const { return last_time; }
uint32 StartSeq() const { return start_seq; }
/**
* @return The starting TCP sequence number for this endpoint.
*/
uint32 StartSeq() const { return static_cast<uint32>(start_seq); }
/**
* @return The starting TCP sequence number for this endpoint, in terms
* of a signed sequence space, which may account for initial
* sequence space wraparounds (underflow/overflow).
*/
int64 StartSeqI64() const { return start_seq; }
/**
* @return The sequence number after the last TCP sequence number seen
* from this endpoint.
*/
uint32 LastSeq() const { return last_seq; }
/**
* @return The last TCP acknowledgement number seen from this endpoint.
*/
uint32 AckSeq() const { return ack_seq; }
void InitStartSeq(uint32 seq) { start_seq = seq; }
/**
* @return The number of times the TCP sequence has wrapped around
* for this endpoint (i.e. overflowed a uint32).
*/
uint32 SeqWraps() const { return seq_wraps; }
/**
* @return The number of times the TCP acknowledgement sequence has
* wrapped around for this endpoint (i.e. overflowed a uint32).
*/
uint32 AckWraps() const { return ack_wraps; }
/**
* @param wraps Number of times a 32-bit sequence space has wrapped.
* @return A 64-bit sequence space number it would take to overflow
* a 32-bit sequence space \a wraps number of times.
*/
static uint64 ToFullSeqSpace(uint32 wraps)
{ return (uint64(wraps) << 32); }
/**
* @param tcp_seq_num A 32-bit TCP sequence space number.
* @param wraparounds Number of times a 32-bit sequence space has wrapped.
* @return \a tcp_seq_num expanded out in to a 64-bit sequence space,
* accounting for the number of times the 32-bit space overflowed.
*/
static uint64 ToFullSeqSpace(uint32 tcp_seq_num, uint32 wraparounds)
{ return ToFullSeqSpace(wraparounds) + tcp_seq_num; }
/**
* @param tcp_seq_num A 32-bit TCP sequence space number.
* @param wraparounds Number of times a 32-bit sequence space has wrapped.
* @return \a tcp_seq_num expanded out in to a 64-bit sequence space,
* accounting for the number of times the 32-bit space overflowed
* and relative the the starting sequence number for this endpoint.
*/
uint64 ToRelativeSeqSpace(uint32 tcp_seq_num, uint32 wraparounds) const
{
return ToFullSeqSpace(tcp_seq_num, wraparounds) - StartSeqI64();
}
void InitStartSeq(int64 seq) { start_seq = seq; }
void InitLastSeq(uint32 seq) { last_seq = seq; }
void InitAckSeq(uint32 seq) { ack_seq = seq; }
void UpdateLastSeq(uint32 seq)
{
if ( seq < last_seq )
++last_seq_high;
++seq_wraps;
last_seq = seq;
}
void UpdateAckSeq(uint32 seq)
{
if ( seq < ack_seq )
++ack_seq_high;
++ack_wraps;
ack_seq = seq;
}
@ -71,7 +131,10 @@ public:
// We allow for possibly one octet being ack'd in the case of
// an initial SYN exchange.
int NoDataAcked() const
{ return ack_seq == start_seq || ack_seq == start_seq + 1; }
{
uint64 ack = ToFullSeqSpace(ack_seq, ack_wraps);
return ack == StartSeqI64() || ack == StartSeqI64() + 1;
}
Connection* Conn() const;
@ -96,16 +159,16 @@ public:
//
// If we're not processing contents, then naturally each of
// these is empty.
void SizeBufferedData(int& waiting_on_hole, int& waiting_on_ack);
void SizeBufferedData(uint64& waiting_on_hole, uint64& waiting_on_ack);
int ValidChecksum(const struct tcphdr* tp, int len) const;
// Returns true if the data was used (and hence should be recorded
// in the save file), false otherwise.
int DataSent(double t, int seq, int len, int caplen, const u_char* data,
int DataSent(double t, uint64 seq, int len, int caplen, const u_char* data,
const IP_Hdr* ip, const struct tcphdr* tp);
void AckReceived(int seq);
void AckReceived(uint64 seq);
void SetContentsFile(BroFile* f);
BroFile* GetContentsFile() const { return contents_file; }
@ -139,20 +202,25 @@ public:
int window_scale; // from the TCP option
uint32 window_ack_seq; // at which ack_seq number did we record 'window'
uint32 window_seq; // at which sending sequence number did we record 'window'
int contents_start_seq; // relative seq # where contents file starts
int FIN_seq; // relative seq # to start_seq
uint64 contents_start_seq; // relative seq # where contents file starts
uint64 FIN_seq; // relative seq # to start_seq
int SYN_cnt, FIN_cnt, RST_cnt;
int did_close; // whether we've reported it closing
int is_orig;
// Sequence numbers associated with last control packets.
// Relative sequence numbers associated with last control packets.
// Used to determine whether ones seen again are interesting,
// for tracking history.
uint32 hist_last_SYN, hist_last_FIN, hist_last_RST;
uint64 hist_last_SYN, hist_last_FIN, hist_last_RST;
protected:
uint32 start_seq, last_seq, ack_seq; // in host order
uint32 last_seq_high, ack_seq_high;
int64 start_seq; // Initial TCP sequence number in host order.
// Signed 64-bit to detect initial sequence wrapping.
// Use StartSeq() accessor if need it in terms of
// an absolute TCP sequence number.
uint32 last_seq, ack_seq; // in host order
uint32 seq_wraps, ack_wraps; // Number of times 32-bit TCP sequence space
// has wrapped around (overflowed).
};
#define ENDIAN_UNKNOWN 0