mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Rename analyzer/protocols -> analyzer/protocol
This commit is contained in:
parent
f7a10d915b
commit
4bc2ba60c9
279 changed files with 114 additions and 116 deletions
|
@ -1,337 +0,0 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "ContentLine.h"
|
||||
#include "analyzer/protocols/tcp/TCP.h"
|
||||
|
||||
#include "events.bif.h"
|
||||
|
||||
using namespace analyzer::tcp;
|
||||
|
||||
ContentLine_Analyzer::ContentLine_Analyzer(Connection* conn, bool orig)
|
||||
: TCP_SupportAnalyzer("CONTENTLINE", conn, orig)
|
||||
{
|
||||
InitState();
|
||||
}
|
||||
|
||||
ContentLine_Analyzer::ContentLine_Analyzer(const char* name, Connection* conn, bool orig)
|
||||
: TCP_SupportAnalyzer(name, conn, orig)
|
||||
{
|
||||
InitState();
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::InitState()
|
||||
{
|
||||
flag_NULs = 0;
|
||||
CR_LF_as_EOL = (CR_as_EOL | LF_as_EOL);
|
||||
skip_deliveries = 0;
|
||||
skip_partial = 0;
|
||||
buf = 0;
|
||||
seq_delivered_in_lines = 0;
|
||||
skip_pending = 0;
|
||||
seq = 0;
|
||||
seq_to_skip = 0;
|
||||
plain_delivery_length = 0;
|
||||
is_plain = 0;
|
||||
|
||||
InitBuffer(0);
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::InitBuffer(int size)
|
||||
{
|
||||
if ( buf && buf_len >= size )
|
||||
// Don't shrink the buffer, because it's not clear in that
|
||||
// case how to deal with characters in it that no longer fit.
|
||||
return;
|
||||
|
||||
if ( size < 128 )
|
||||
size = 128;
|
||||
|
||||
u_char* b = new u_char[size];
|
||||
|
||||
if ( buf )
|
||||
{
|
||||
if ( offset > 0 )
|
||||
memcpy(b, buf, offset);
|
||||
delete [] buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 0;
|
||||
last_char = 0;
|
||||
}
|
||||
|
||||
buf = b;
|
||||
buf_len = size;
|
||||
}
|
||||
|
||||
ContentLine_Analyzer::~ContentLine_Analyzer()
|
||||
{
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
int ContentLine_Analyzer::HasPartialLine() const
|
||||
{
|
||||
return buf && offset > 0;
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::DeliverStream(int len, const u_char* data,
|
||||
bool is_orig)
|
||||
{
|
||||
TCP_SupportAnalyzer::DeliverStream(len, data, is_orig);
|
||||
|
||||
if ( len <= 0 || SkipDeliveries() )
|
||||
return;
|
||||
|
||||
if ( skip_partial )
|
||||
{
|
||||
TCP_Analyzer* tcp =
|
||||
static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
|
||||
|
||||
if ( tcp && tcp->IsPartial() )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( buf && len + offset >= buf_len )
|
||||
{ // Make sure we have enough room to accommodate the new stuff.
|
||||
int old_buf_len = buf_len;
|
||||
buf_len = ((offset + len) * 3) / 2 + 1;
|
||||
|
||||
u_char* tmp = new u_char[buf_len];
|
||||
for ( int i = 0; i < old_buf_len; ++i )
|
||||
tmp[i] = buf[i];
|
||||
|
||||
delete [] buf;
|
||||
buf = tmp;
|
||||
|
||||
if ( ! buf )
|
||||
reporter->InternalError("out of memory delivering endpoint line");
|
||||
}
|
||||
|
||||
DoDeliver(len, data);
|
||||
|
||||
seq += len;
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::Undelivered(int seq, int len, bool orig)
|
||||
{
|
||||
ForwardUndelivered(seq, len, orig);
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::EndpointEOF(bool is_orig)
|
||||
{
|
||||
if ( offset > 0 )
|
||||
DeliverStream(1, (const u_char*) "\n", is_orig);
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::SetPlainDelivery(int64_t length)
|
||||
{
|
||||
if ( length < 0 )
|
||||
reporter->InternalError("negative length for plain delivery");
|
||||
|
||||
plain_delivery_length = length;
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::DoDeliver(int len, const u_char* data)
|
||||
{
|
||||
seq_delivered_in_lines = seq;
|
||||
|
||||
while ( len > 0 && ! SkipDeliveries() )
|
||||
{
|
||||
if ( (CR_LF_as_EOL & CR_as_EOL) &&
|
||||
last_char == '\r' && *data == '\n' )
|
||||
{
|
||||
// CR is already considered as EOL.
|
||||
// Compress CRLF to just one line termination.
|
||||
//
|
||||
// Note, we test this prior to checking for
|
||||
// "plain delivery" because (1) we might have
|
||||
// made the decision to switch to plain delivery
|
||||
// based on a line terminated with '\r' for
|
||||
// which a '\n' then arrived, and (2) we are
|
||||
// careful when executing plain delivery to
|
||||
// clear last_char once we do so.
|
||||
last_char = *data;
|
||||
--len; ++data; ++seq;
|
||||
++seq_delivered_in_lines;
|
||||
}
|
||||
|
||||
if ( plain_delivery_length > 0 )
|
||||
{
|
||||
int deliver_plain = min(plain_delivery_length, (int64_t)len);
|
||||
|
||||
last_char = 0; // clear last_char
|
||||
plain_delivery_length -= deliver_plain;
|
||||
is_plain = 1;
|
||||
|
||||
ForwardStream(deliver_plain, data, IsOrig());
|
||||
|
||||
is_plain = 0;
|
||||
|
||||
data += deliver_plain;
|
||||
len -= deliver_plain;
|
||||
if ( len == 0 )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( skip_pending > 0 )
|
||||
SkipBytes(skip_pending);
|
||||
|
||||
// Note that the skipping must take place *after*
|
||||
// the CR/LF check above, so that the '\n' of the
|
||||
// previous line is skipped first.
|
||||
if ( seq < seq_to_skip )
|
||||
{
|
||||
// Skip rest of the data and return
|
||||
int64_t skip_len = seq_to_skip - seq;
|
||||
if ( skip_len > len )
|
||||
skip_len = len;
|
||||
|
||||
ForwardUndelivered(seq, skip_len, IsOrig());
|
||||
|
||||
len -= skip_len; data += skip_len; seq += skip_len;
|
||||
seq_delivered_in_lines += skip_len;
|
||||
}
|
||||
|
||||
if ( len <= 0 )
|
||||
break;
|
||||
|
||||
int n = DoDeliverOnce(len, data);
|
||||
len -= n;
|
||||
data += n;
|
||||
seq += n;
|
||||
}
|
||||
}
|
||||
|
||||
int ContentLine_Analyzer::DoDeliverOnce(int len, const u_char* data)
|
||||
{
|
||||
const u_char* data_start = data;
|
||||
|
||||
if ( len <= 0 )
|
||||
return 0;
|
||||
|
||||
for ( ; len > 0; --len, ++data )
|
||||
{
|
||||
if ( offset >= buf_len )
|
||||
InitBuffer(buf_len * 2);
|
||||
|
||||
int c = data[0];
|
||||
|
||||
#define EMIT_LINE \
|
||||
{ \
|
||||
buf[offset] = '\0'; \
|
||||
int seq_len = data + 1 - data_start; \
|
||||
seq_delivered_in_lines = seq + seq_len; \
|
||||
last_char = c; \
|
||||
ForwardStream(offset, buf, IsOrig()); \
|
||||
offset = 0; \
|
||||
return seq_len; \
|
||||
}
|
||||
|
||||
switch ( c ) {
|
||||
case '\r':
|
||||
// Look ahead for '\n'.
|
||||
if ( len > 1 && data[1] == '\n' )
|
||||
{
|
||||
--len; ++data;
|
||||
last_char = c;
|
||||
c = data[0];
|
||||
EMIT_LINE
|
||||
}
|
||||
|
||||
else if ( CR_LF_as_EOL & CR_as_EOL )
|
||||
EMIT_LINE
|
||||
|
||||
else
|
||||
buf[offset++] = c;
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
if ( last_char == '\r' )
|
||||
{
|
||||
--offset; // remove '\r'
|
||||
EMIT_LINE
|
||||
}
|
||||
|
||||
else if ( CR_LF_as_EOL & LF_as_EOL )
|
||||
EMIT_LINE
|
||||
|
||||
else
|
||||
{
|
||||
if ( Conn()->FlagEvent(SINGULAR_LF) )
|
||||
Conn()->Weird("line_terminated_with_single_LF");
|
||||
buf[offset++] = c;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
if ( flag_NULs )
|
||||
CheckNUL();
|
||||
else
|
||||
buf[offset++] = c;
|
||||
break;
|
||||
|
||||
default:
|
||||
buf[offset++] = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( last_char == '\r' )
|
||||
if ( Conn()->FlagEvent(SINGULAR_CR) )
|
||||
Conn()->Weird("line_terminated_with_single_CR");
|
||||
|
||||
last_char = c;
|
||||
}
|
||||
|
||||
return data - data_start;
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::CheckNUL()
|
||||
{
|
||||
// If this is the first byte seen on this connection,
|
||||
// and if the connection's state is PARTIAL, then we've
|
||||
// intercepted a keep-alive, and shouldn't complain
|
||||
// about it. Note that for PARTIAL connections, the
|
||||
// starting sequence number is adjusted as though there
|
||||
// had been an initial SYN, so we check for whether
|
||||
// the connection has at most two bytes so far.
|
||||
|
||||
TCP_Analyzer* tcp =
|
||||
static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
|
||||
|
||||
if ( tcp )
|
||||
{
|
||||
TCP_Endpoint* endp = IsOrig() ? tcp->Orig() : tcp->Resp();
|
||||
if ( endp->state == TCP_ENDPOINT_PARTIAL &&
|
||||
endp->LastSeq() - endp->StartSeq() <= 2 )
|
||||
; // Ignore it.
|
||||
else
|
||||
{
|
||||
if ( Conn()->FlagEvent(NUL_IN_LINE) )
|
||||
Conn()->Weird("NUL_in_line");
|
||||
flag_NULs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::SkipBytesAfterThisLine(int64_t length)
|
||||
{
|
||||
// This is a little complicated because Bro has to handle
|
||||
// both CR and CRLF as a line break. When a line is delivered,
|
||||
// it's possible that only a CR is seen, and we may not know
|
||||
// if an LF is following until we see the next packet. If an
|
||||
// LF follows, we should start skipping bytes *after* the LF.
|
||||
// So we keep the skip as 'pending' until we see the next
|
||||
// character in DoDeliver().
|
||||
|
||||
if ( last_char == '\r' )
|
||||
skip_pending = length;
|
||||
else
|
||||
SkipBytes(length);
|
||||
}
|
||||
|
||||
void ContentLine_Analyzer::SkipBytes(int64_t length)
|
||||
{
|
||||
skip_pending = 0;
|
||||
seq_to_skip = SeqDelivered() + length;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue