zeek/src/analyzer/protocol/bittorrent/BitTorrent.cc
Jon Siwek 2b3c2bd394 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.
2014-04-09 13:03:24 -05:00

131 lines
3.4 KiB
C++

// This code contributed by Nadi Sarrar.
#include "BitTorrent.h"
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
#include "events.bif.h"
using namespace analyzer::bittorrent;
BitTorrent_Analyzer::BitTorrent_Analyzer(Connection* c)
: tcp::TCP_ApplicationAnalyzer("BITTORRENT", c)
{
interp = new binpac::BitTorrent::BitTorrent_Conn(this);
stop_orig = stop_resp = false;
stream_len_orig = stream_len_resp = 0;
}
BitTorrent_Analyzer::~BitTorrent_Analyzer()
{
delete interp;
}
void BitTorrent_Analyzer::Done()
{
tcp::TCP_ApplicationAnalyzer::Done();
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void BitTorrent_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
bool& this_stop = orig ? stop_orig : stop_resp;
tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
assert(TCP());
if ( TCP()->IsPartial() )
// punt on partial.
return;
if ( this_stop )
return;
this_stream_len += len;
try
{
interp->NewData(orig, data, data + len);
}
catch ( binpac::Exception const &e )
{
const char except[] = "binpac exception: invalid handshake";
if ( ! strncmp(e.c_msg(), except, strlen(except)) )
// Does not look like bittorrent - silently
// drop the connection.
Parent()->RemoveChildAnalyzer(this);
else
{
DeliverWeird(fmt("Stopping BitTorrent analysis: protocol violation (%s)",
e.c_msg()), orig);
this_stop = true;
if ( stop_orig && stop_resp )
ProtocolViolation("BitTorrent: content gap and/or protocol violation");
}
}
}
void BitTorrent_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
// TODO: Code commented out for now. I think that shoving data that
// is definitely wrong into the parser seems like a really bad idea.
// The way it's currently tracking the next message offset isn't
// compatible with new 64bit int support in binpac either.
//uint64 entry_offset = orig ?
// *interp->upflow()->next_message_offset() :
// *interp->downflow()->next_message_offset();
//uint64& this_stream_len = orig ? stream_len_orig : stream_len_resp;
//bool& this_stop = orig ? stop_orig : stop_resp;
//
//this_stream_len += len;
//
//if ( entry_offset < this_stream_len )
// { // entry point is somewhere in the gap
// DeliverWeird("Stopping BitTorrent analysis: cannot recover from content gap", orig);
// this_stop = true;
// if ( stop_orig && stop_resp )
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
// }
//else
// { // fill the gap
// try
// {
// u_char gap[len];
// memset(gap, 0, len);
// interp->NewData(orig, gap, gap + len);
// }
// catch ( binpac::Exception const &e )
// {
// DeliverWeird("Stopping BitTorrent analysis: filling content gap failed", orig);
// this_stop = true;
// if ( stop_orig && stop_resp )
// ProtocolViolation("BitTorrent: content gap and/or protocol violation");
// }
// }
}
void BitTorrent_Analyzer::EndpointEOF(bool is_orig)
{
tcp::TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
interp->FlowEOF(is_orig);
}
void BitTorrent_Analyzer::DeliverWeird(const char* msg, bool orig)
{
if ( bittorrent_peer_weird )
{
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(new Val(orig, TYPE_BOOL));
vl->append(new StringVal(msg));
ConnectionEvent(bittorrent_peer_weird, vl);
}
else
Weird(msg);
}