mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00

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.
236 lines
5 KiB
C++
236 lines
5 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
#include <map>
|
|
|
|
#include "NCP.h"
|
|
|
|
#include "events.bif.h"
|
|
|
|
using namespace std;
|
|
using namespace analyzer::ncp;
|
|
|
|
#include "NCP.h"
|
|
#include "Sessions.h"
|
|
|
|
#define xbyte(b, n) (((const u_char*) (b))[n])
|
|
#define extract_uint16(little_endian, bytes) \
|
|
((little_endian) ? \
|
|
uint16(xbyte(bytes, 0)) | ((uint16(xbyte(bytes, 1))) << 8) : \
|
|
uint16(xbyte(bytes, 1)) | ((uint16(xbyte(bytes, 0))) << 8))
|
|
|
|
NCP_Session::NCP_Session(analyzer::Analyzer* a)
|
|
: analyzer(a)
|
|
{
|
|
req_frame_type = 0;
|
|
req_func = 0;
|
|
}
|
|
|
|
void NCP_Session::Deliver(int is_orig, int len, const u_char* data)
|
|
{
|
|
try
|
|
{
|
|
binpac::NCP::ncp_over_tcpip_frame frame(is_orig);
|
|
frame.Parse(data, data + len);
|
|
|
|
DeliverFrame(frame.ncp());
|
|
}
|
|
catch ( const binpac::Exception& e )
|
|
{
|
|
analyzer->Weird(e.msg().c_str());
|
|
}
|
|
}
|
|
|
|
void NCP_Session::DeliverFrame(const binpac::NCP::ncp_frame* frame)
|
|
{
|
|
if ( frame->is_orig() )
|
|
{
|
|
req_frame_type = frame->frame_type();
|
|
req_func = frame->request()->function();
|
|
if ( req_func == 0x57 ) // enhanced FILE_DIR services
|
|
{
|
|
req_func = (req_func << 8) |
|
|
frame->request()->subfunction();
|
|
}
|
|
}
|
|
|
|
EventHandlerPtr f = frame->is_orig() ? ncp_request : ncp_reply;
|
|
if ( f )
|
|
{
|
|
val_list* vl = new val_list;
|
|
vl->append(analyzer->BuildConnVal());
|
|
vl->append(new Val(frame->frame_type(), TYPE_COUNT));
|
|
vl->append(new Val(frame->body_length(), TYPE_COUNT));
|
|
|
|
if ( frame->is_orig() )
|
|
vl->append(new Val(req_func, TYPE_COUNT));
|
|
else
|
|
{
|
|
vl->append(new Val(req_frame_type, TYPE_COUNT));
|
|
vl->append(new Val(req_func, TYPE_COUNT));
|
|
vl->append(new Val(frame->reply()->completion_code(),
|
|
TYPE_COUNT));
|
|
}
|
|
|
|
analyzer->ConnectionEvent(f, vl);
|
|
}
|
|
}
|
|
|
|
FrameBuffer::FrameBuffer(int header_length)
|
|
{
|
|
hdr_len = header_length;
|
|
msg_buf = 0;
|
|
buf_len = 0;
|
|
Reset();
|
|
}
|
|
|
|
FrameBuffer::~FrameBuffer()
|
|
{
|
|
delete [] msg_buf;
|
|
}
|
|
|
|
void FrameBuffer::Reset()
|
|
{
|
|
// Allocate space for header.
|
|
if ( ! msg_buf )
|
|
{
|
|
buf_len = hdr_len;
|
|
msg_buf = new u_char[buf_len];
|
|
}
|
|
|
|
buf_n = 0;
|
|
msg_len = 0;
|
|
}
|
|
|
|
// Returns true if we have a complete frame
|
|
bool FrameBuffer::Deliver(int &len, const u_char* &data)
|
|
{
|
|
ASSERT(buf_len >= hdr_len);
|
|
|
|
if ( len == 0 )
|
|
return false;
|
|
|
|
if ( buf_n < hdr_len )
|
|
{
|
|
while ( buf_n < hdr_len && len > 0 )
|
|
{
|
|
ASSERT(buf_n < buf_len);
|
|
msg_buf[buf_n] = *data;
|
|
++buf_n; ++data; --len;
|
|
}
|
|
|
|
if ( buf_n < hdr_len )
|
|
return false;
|
|
|
|
compute_msg_length();
|
|
|
|
if ( msg_len > buf_len )
|
|
{
|
|
buf_len = msg_len * 2;
|
|
u_char* new_buf = new u_char[buf_len];
|
|
memcpy(new_buf, msg_buf, buf_n);
|
|
delete [] msg_buf;
|
|
msg_buf = new_buf;
|
|
}
|
|
}
|
|
|
|
while ( buf_n < msg_len && len > 0 )
|
|
{
|
|
msg_buf[buf_n] = *data;
|
|
++buf_n; ++data; --len;
|
|
}
|
|
|
|
return buf_n >= msg_len;
|
|
}
|
|
|
|
void NCP_FrameBuffer::compute_msg_length()
|
|
{
|
|
const u_char* data = Data();
|
|
msg_len = 0;
|
|
for ( int i = 0; i < 4; ++i )
|
|
msg_len = (msg_len << 8) | data[4+i];
|
|
}
|
|
|
|
Contents_NCP_Analyzer::Contents_NCP_Analyzer(Connection* conn, bool orig, NCP_Session* arg_session)
|
|
: tcp::TCP_SupportAnalyzer("CONTENTS_NCP", conn, orig)
|
|
{
|
|
session = arg_session;
|
|
resync = true;
|
|
|
|
tcp::TCP_Analyzer* tcp = static_cast<tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
|
|
if ( tcp )
|
|
resync = (orig ? tcp->OrigState() : tcp->RespState()) !=
|
|
tcp::TCP_ENDPOINT_ESTABLISHED;
|
|
}
|
|
|
|
Contents_NCP_Analyzer::~Contents_NCP_Analyzer()
|
|
{
|
|
}
|
|
|
|
void Contents_NCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
|
|
{
|
|
tcp::TCP_SupportAnalyzer::DeliverStream(len, data, orig);
|
|
|
|
tcp::TCP_Analyzer* tcp = static_cast<tcp::TCP_ApplicationAnalyzer*>(Parent())->TCP();
|
|
|
|
if ( tcp && tcp->HadGap(orig) )
|
|
return;
|
|
|
|
DEBUG_MSG("NCP deliver: len = %d resync = %d buffer.empty = %d\n",
|
|
len, resync, buffer.empty());
|
|
|
|
if ( buffer.empty() && resync )
|
|
{
|
|
// Assume NCP frames align with packet boundary.
|
|
if ( (IsOrig() && len < 22) || (! IsOrig() && len < 16) )
|
|
{ // ignore small fragmeents
|
|
DEBUG_MSG("NCP discard small pieces: %d\n", len);
|
|
return;
|
|
}
|
|
|
|
int frame_type_index = IsOrig() ? 16 : 8;
|
|
int frame_type = ((int) data[frame_type_index]) << 8 |
|
|
data[frame_type_index + 1];
|
|
|
|
if ( frame_type != 0x1111 && frame_type != 0x2222 &&
|
|
frame_type != 0x3333 && frame_type != 0x5555 &&
|
|
frame_type != 0x7777 && frame_type != 0x9999 )
|
|
// Skip this packet
|
|
return;
|
|
|
|
resync = false;
|
|
}
|
|
|
|
while ( buffer.Deliver(len, data) )
|
|
{
|
|
session->Deliver(IsOrig(), buffer.Len(), buffer.Data());
|
|
buffer.Reset();
|
|
}
|
|
}
|
|
|
|
void Contents_NCP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
|
|
{
|
|
tcp::TCP_SupportAnalyzer::Undelivered(seq, len, orig);
|
|
|
|
buffer.Reset();
|
|
resync = true;
|
|
}
|
|
|
|
NCP_Analyzer::NCP_Analyzer(Connection* conn)
|
|
: tcp::TCP_ApplicationAnalyzer("NCP", conn)
|
|
{
|
|
session = new NCP_Session(this);
|
|
o_ncp = new Contents_NCP_Analyzer(conn, true, session);
|
|
r_ncp = new Contents_NCP_Analyzer(conn, false, session);
|
|
}
|
|
|
|
NCP_Analyzer::~NCP_Analyzer()
|
|
{
|
|
delete session;
|
|
delete o_ncp;
|
|
delete r_ncp;
|
|
}
|
|
|