Merge origin/master into topic/vladg/radius

This commit is contained in:
Vlad Grigorescu 2014-05-14 23:23:08 -04:00
commit df99f87dbf
617 changed files with 20195 additions and 5690 deletions

@ -1 +1 @@
Subproject commit 12b5cb446c8128bb22e5cbd7baa7d53669539487
Subproject commit 3b3e189dab3801cd0474dfdd376d9de633cd3766

View file

@ -317,8 +317,9 @@ void Attributes::CheckAttr(Attr* a)
break;
// Table defaults may be promotable.
if ( (ytype->Tag() == TYPE_RECORD && atype->Tag() == TYPE_RECORD &&
record_promotion_compatible(atype->AsRecordType(), ytype->AsRecordType())) )
if ( ytype && ytype->Tag() == TYPE_RECORD &&
atype->Tag() == TYPE_RECORD &&
record_promotion_compatible(atype->AsRecordType(), ytype->AsRecordType()) )
// Ok.
break;

View file

@ -104,7 +104,7 @@ Base64Converter::Base64Converter(analyzer::Analyzer* arg_analyzer, const string&
Base64Converter::~Base64Converter()
{
if ( base64_table != default_base64_table )
delete base64_table;
delete [] base64_table;
}
int Base64Converter::Decode(int len, const char* data, int* pblen, char** pbuf)

View file

@ -9,6 +9,9 @@ set(bro_ALL_GENERATED_OUTPUTS CACHE INTERNAL "automatically generated files" FO
# This collects bif inputs that we'll load automatically.
set(bro_AUTO_BIFS CACHE INTERNAL "BIFs for automatic inclusion" FORCE)
set(bro_BASE_BIF_SCRIPTS CACHE INTERNAL "Bro script stubs for BIFs in base distribution of Bro" FORCE)
set(bro_PLUGIN_BIF_SCRIPTS CACHE INTERNAL "Bro script stubs for BIFs in Bro plugins" FORCE)
# If TRUE, use CMake's object libraries for sub-directories instead of
# static libraries. This requires CMake >= 2.8.8.
set(bro_HAVE_OBJECT_LIBRARIES FALSE)
@ -293,7 +296,6 @@ set(bro_SRCS
OpaqueVal.cc
OSFinger.cc
PacketFilter.cc
PacketSort.cc
PersistenceSerializer.cc
PktSrc.cc
PolicyFile.cc
@ -336,11 +338,13 @@ set(bro_SRCS
strsep.c
modp_numtoa.c
threading/AsciiFormatter.cc
threading/BasicThread.cc
threading/Formatter.cc
threading/Manager.cc
threading/MsgThread.cc
threading/SerialTypes.cc
threading/formatters/Ascii.cc
threading/formatters/JSON.cc
logging/Manager.cc
logging/WriterBackend.cc
@ -401,12 +405,12 @@ add_custom_target(generate_outputs)
add_dependencies(generate_outputs generate_outputs_stage2)
# Build __load__.bro files for standard *.bif.bro.
bro_bif_create_loader(bif_loader ${CMAKE_BINARY_DIR}/scripts/base/bif)
bro_bif_create_loader(bif_loader "${bro_BASE_BIF_SCRIPTS}")
add_dependencies(bif_loader ${bro_SUBDIRS})
add_dependencies(bro bif_loader)
# Build __load__.bro files for plugins/*.bif.bro.
bro_bif_create_loader(bif_loader_plugins ${CMAKE_BINARY_DIR}/scripts/base/bif/plugins)
bro_bif_create_loader(bif_loader_plugins "${bro_PLUGIN_BIF_SCRIPTS}")
add_dependencies(bif_loader_plugins ${bro_SUBDIRS})
add_dependencies(bro bif_loader_plugins)

View file

@ -127,12 +127,7 @@ ChunkedIOFd::~ChunkedIOFd()
delete [] read_buffer;
delete [] write_buffer;
safe_close(fd);
if ( partial )
{
delete [] partial->data;
delete partial;
}
delete partial;
}
bool ChunkedIOFd::Write(Chunk* chunk)
@ -169,10 +164,9 @@ bool ChunkedIOFd::Write(Chunk* chunk)
while ( left )
{
Chunk* part = new Chunk;
uint32 sz = min<uint32>(BUFFER_SIZE - sizeof(uint32), left);
Chunk* part = new Chunk(new char[sz], sz);
part->len = min<uint32>(BUFFER_SIZE - sizeof(uint32), left);
part->data = new char[part->len];
memcpy(part->data, p, part->len);
left -= part->len;
p += part->len;
@ -181,9 +175,7 @@ bool ChunkedIOFd::Write(Chunk* chunk)
return false;
}
delete [] chunk->data;
delete chunk;
return true;
}
@ -239,7 +231,6 @@ bool ChunkedIOFd::PutIntoWriteBuffer(Chunk* chunk)
memcpy(write_buffer + write_len, chunk->data, len);
write_len += len;
delete [] chunk->data;
delete chunk;
if ( network_time - last_flush > 0.005 )
@ -362,9 +353,7 @@ ChunkedIO::Chunk* ChunkedIOFd::ExtractChunk()
read_pos += sizeof(uint32);
Chunk* chunk = new Chunk;
chunk->len = len;
chunk->data = new char[real_len];
Chunk* chunk = new Chunk(new char[real_len], len);
memcpy(chunk->data, read_buffer + read_pos, real_len);
read_pos += real_len;
@ -375,17 +364,13 @@ ChunkedIO::Chunk* ChunkedIOFd::ExtractChunk()
ChunkedIO::Chunk* ChunkedIOFd::ConcatChunks(Chunk* c1, Chunk* c2)
{
Chunk* c = new Chunk;
c->len = c1->len + c2->len;
c->data = new char[c->len];
uint32 sz = c1->len + c2->len;
Chunk* c = new Chunk(new char[sz], sz);
memcpy(c->data, c1->data, c1->len);
memcpy(c->data + c1->len, c2->data, c2->len);
delete [] c1->data;
delete c1;
delete [] c2->data;
delete c2;
return c;
@ -627,7 +612,6 @@ void ChunkedIOFd::Clear()
while ( pending_head )
{
ChunkQueue* next = pending_head->next;
delete [] pending_head->chunk->data;
delete pending_head->chunk;
delete pending_head;
pending_head = next;
@ -946,7 +930,6 @@ bool ChunkedIOSSL::Flush()
--stats.pending;
delete q;
delete [] c->data;
delete c;
write_state = LEN;
@ -1063,7 +1046,10 @@ bool ChunkedIOSSL::Read(Chunk** chunk, bool mayblock)
}
if ( ! read_chunk->data )
{
read_chunk->data = new char[read_chunk->len];
read_chunk->free_func = Chunk::free_func_delete;
}
if ( ! ReadData(read_chunk->data, read_chunk->len, &error) )
return ! error;
@ -1123,7 +1109,6 @@ void ChunkedIOSSL::Clear()
while ( write_head )
{
Queue* next = write_head->next;
delete [] write_head->chunk->data;
delete write_head->chunk;
delete write_head;
write_head = next;
@ -1231,12 +1216,13 @@ bool CompressedChunkedIO::Read(Chunk** chunk, bool may_block)
return false;
}
delete [] (*chunk)->data;
(*chunk)->free_func((*chunk)->data);
uncompressed_bytes_read += uncompressed_len;
(*chunk)->len = uncompressed_len;
(*chunk)->data = uncompressed;
(*chunk)->free_func = Chunk::free_func_delete;
return true;
}
@ -1280,8 +1266,9 @@ bool CompressedChunkedIO::Write(Chunk* chunk)
memcpy(compressed, chunk->data, chunk->len);
*(uint32*) (compressed + chunk->len) = 0; // uncompressed_length
delete [] chunk->data;
chunk->free_func(chunk->data);
chunk->data = compressed;
chunk->free_func = Chunk::free_func_delete;
chunk->len += 4;
DBG_LOG(DBG_CHUNKEDIO, "zlib write pass-through: size=%d", chunk->len);
@ -1322,8 +1309,9 @@ bool CompressedChunkedIO::Write(Chunk* chunk)
*(uint32*) zout.next_out = original_size; // uncompressed_length
delete [] chunk->data;
chunk->free_func(chunk->data);
chunk->data = compressed;
chunk->free_func = Chunk::free_func_delete;
chunk->len =
((char*) zout.next_out - compressed) + sizeof(uint32);

View file

@ -11,7 +11,7 @@
#ifdef NEED_KRB5_H
# include <krb5.h>
#endif
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
@ -26,10 +26,28 @@ public:
ChunkedIO();
virtual ~ChunkedIO() { }
typedef struct {
struct Chunk {
typedef void (*FreeFunc)(char*);
static void free_func_free(char* data) { free(data); }
static void free_func_delete(char* data) { delete [] data; }
Chunk()
: data(), len(), free_func(free_func_delete)
{ }
// Takes ownership of data.
Chunk(char* arg_data, uint32 arg_len,
FreeFunc arg_ff = free_func_delete)
: data(arg_data), len(arg_len), free_func(arg_ff)
{ }
~Chunk()
{ free_func(data); }
char* data;
uint32 len;
} Chunk;
FreeFunc free_func;
};
// Initialization before any I/O operation is performed. Returns false
// on any form of error.

View file

@ -15,6 +15,7 @@
#include "binpac.h"
#include "TunnelEncapsulation.h"
#include "analyzer/Analyzer.h"
#include "analyzer/Manager.h"
void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer,
int arg_do_expire)
@ -722,8 +723,8 @@ TimerMgr* Connection::GetTimerMgr() const
void Connection::FlipRoles()
{
IPAddr tmp_addr = resp_addr;
orig_addr = resp_addr;
resp_addr = tmp_addr;
resp_addr = orig_addr;
orig_addr = tmp_addr;
uint32 tmp_port = resp_port;
resp_port = orig_port;
@ -742,6 +743,8 @@ void Connection::FlipRoles()
if ( root_analyzer )
root_analyzer->FlipRoles();
analyzer_mgr->ApplyScheduledAnalyzers(this);
}
unsigned int Connection::MemoryAllocation() const
@ -808,6 +811,17 @@ void Connection::Describe(ODesc* d) const
d->NL();
}
void Connection::IDString(ODesc* d) const
{
d->Add(orig_addr);
d->AddRaw(":", 1);
d->Add(ntohs(orig_port));
d->AddRaw(" > ", 3);
d->Add(resp_addr);
d->AddRaw(":", 1);
d->Add(ntohs(resp_port));
}
bool Connection::Serialize(SerialInfo* info) const
{
return SerialObj::Serialize(info);

View file

@ -204,6 +204,7 @@ public:
bool IsPersistent() { return persistent; }
void Describe(ODesc* d) const;
void IDString(ODesc* d) const;
TimerMgr* GetTimerMgr() const;

View file

@ -211,9 +211,10 @@ void DFA_State::Dump(FILE* f, DFA_Machine* m)
if ( accept )
{
for ( int i = 0; i < accept->length(); ++i )
fprintf(f, "%s accept #%d",
i > 0 ? "," : "", int((*accept)[i]));
AcceptingSet::const_iterator it;
for ( it = accept->begin(); it != accept->end(); ++it )
fprintf(f, "%s accept #%d", it == accept->begin() ? "" : ",", *it);
}
fprintf(f, "\n");
@ -285,7 +286,7 @@ unsigned int DFA_State::Size()
{
return sizeof(*this)
+ pad_size(sizeof(DFA_State*) * num_sym)
+ (accept ? pad_size(sizeof(int) * accept->length()) : 0)
+ (accept ? pad_size(sizeof(int) * accept->size()) : 0)
+ (nfa_states ? pad_size(sizeof(NFA_State*) * nfa_states->length()) : 0)
+ (meta_ec ? meta_ec->Size() : 0)
+ (centry ? padded_sizeof(CacheEntry) : 0);
@ -470,33 +471,20 @@ int DFA_Machine::StateSetToDFA_State(NFA_state_list* state_set,
return 0;
AcceptingSet* accept = new AcceptingSet;
for ( int i = 0; i < state_set->length(); ++i )
{
int acc = (*state_set)[i]->Accept();
if ( acc != NO_ACCEPT )
{
int j;
for ( j = 0; j < accept->length(); ++j )
if ( (*accept)[j] == acc )
break;
if ( j >= accept->length() )
// It's not already present.
accept->append(acc);
}
accept->insert(acc);
}
if ( accept->length() == 0 )
if ( accept->empty() )
{
delete accept;
accept = 0;
}
else
{
accept->sort(int_list_cmp);
accept->resize(0);
}
DFA_State* ds = new DFA_State(state_count++, ec, state_set, accept);
d = dfa_state_cache->Insert(ds, hash);

View file

@ -2,6 +2,7 @@
#include "config.h"
#include <openssl/md5.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef TIME_WITH_SYS_TIME
@ -385,7 +386,6 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode)
dns_mapping_altered = 0;
dm_rec = 0;
dns_fake_count = 0;
cache_name = dir = 0;
@ -443,6 +443,33 @@ bool DNS_Mgr::Init()
return true;
}
static TableVal* fake_name_lookup_result(const char* name)
{
uint32 hash[4];
MD5(reinterpret_cast<const u_char*>(name), strlen(name),
reinterpret_cast<u_char*>(hash));
ListVal* hv = new ListVal(TYPE_ADDR);
hv->Append(new AddrVal(hash));
TableVal* tv = hv->ConvertToSet();
Unref(hv);
return tv;
}
static const char* fake_text_lookup_result(const char* name)
{
static char tmp[32 + 256];
snprintf(tmp, sizeof(tmp), "fake_text_lookup_result_%s", name);
return tmp;
}
static const char* fake_addr_lookup_result(const IPAddr& addr)
{
static char tmp[128];
snprintf(tmp, sizeof(tmp), "fake_addr_lookup_result_%s",
addr.AsString().c_str());
return tmp;
}
TableVal* DNS_Mgr::LookupHost(const char* name)
{
if ( ! nb_dns )
@ -452,11 +479,7 @@ TableVal* DNS_Mgr::LookupHost(const char* name)
Init();
if ( mode == DNS_FAKE )
{
ListVal* hv = new ListVal(TYPE_ADDR);
hv->Append(new AddrVal(uint32(++dns_fake_count)));
return hv->ConvertToSet();
}
return fake_name_lookup_result(name);
if ( mode != DNS_PRIME )
{
@ -960,7 +983,7 @@ const char* DNS_Mgr::LookupAddrInCache(const IPAddr& addr)
return d->names ? d->names[0] : "<\?\?\?>";
}
TableVal* DNS_Mgr::LookupNameInCache(string name)
TableVal* DNS_Mgr::LookupNameInCache(const string& name)
{
HostMap::iterator it = host_mappings.find(name);
if ( it == host_mappings.end() )
@ -990,7 +1013,7 @@ TableVal* DNS_Mgr::LookupNameInCache(string name)
return tv6;
}
const char* DNS_Mgr::LookupTextInCache(string name)
const char* DNS_Mgr::LookupTextInCache(const string& name)
{
TextMap::iterator it = text_mappings.find(name);
if ( it == text_mappings.end() )
@ -1010,17 +1033,37 @@ const char* DNS_Mgr::LookupTextInCache(string name)
return d->names ? d->names[0] : "<\?\?\?>";
}
static void resolve_lookup_cb(DNS_Mgr::LookupCallback* callback,
TableVal* result)
{
callback->Resolved(result);
Unref(result);
delete callback;
}
static void resolve_lookup_cb(DNS_Mgr::LookupCallback* callback,
const char* result)
{
callback->Resolved(result);
delete callback;
}
void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
{
if ( ! did_init )
Init();
if ( mode == DNS_FAKE )
{
resolve_lookup_cb(callback, fake_addr_lookup_result(host));
return;
}
// Do we already know the answer?
const char* name = LookupAddrInCache(host);
if ( name )
{
callback->Resolved(name);
delete callback;
resolve_lookup_cb(callback, name);
return;
}
@ -1044,18 +1087,22 @@ void DNS_Mgr::AsyncLookupAddr(const IPAddr& host, LookupCallback* callback)
IssueAsyncRequests();
}
void DNS_Mgr::AsyncLookupName(string name, LookupCallback* callback)
void DNS_Mgr::AsyncLookupName(const string& name, LookupCallback* callback)
{
if ( ! did_init )
Init();
if ( mode == DNS_FAKE )
{
resolve_lookup_cb(callback, fake_name_lookup_result(name.c_str()));
return;
}
// Do we already know the answer?
TableVal* addrs = LookupNameInCache(name);
if ( addrs )
{
callback->Resolved(addrs);
Unref(addrs);
delete callback;
resolve_lookup_cb(callback, addrs);
return;
}
@ -1079,13 +1126,25 @@ void DNS_Mgr::AsyncLookupName(string name, LookupCallback* callback)
IssueAsyncRequests();
}
void DNS_Mgr::AsyncLookupNameText(string name, LookupCallback* callback)
void DNS_Mgr::AsyncLookupNameText(const string& name, LookupCallback* callback)
{
if ( ! did_init )
Init();
if ( mode == DNS_FAKE )
{
resolve_lookup_cb(callback, fake_text_lookup_result(name.c_str()));
return;
}
// Do we already know the answer?
TableVal* addrs;
const char* txt = LookupTextInCache(name);
if ( txt )
{
resolve_lookup_cb(callback, txt);
return;
}
AsyncRequest* req = 0;

View file

@ -62,8 +62,8 @@ public:
int Save();
const char* LookupAddrInCache(const IPAddr& addr);
TableVal* LookupNameInCache(string name);
const char* LookupTextInCache(string name);
TableVal* LookupNameInCache(const string& name);
const char* LookupTextInCache(const string& name);
// Support for async lookups.
class LookupCallback {
@ -77,8 +77,8 @@ public:
};
void AsyncLookupAddr(const IPAddr& host, LookupCallback* callback);
void AsyncLookupName(string name, LookupCallback* callback);
void AsyncLookupNameText(string name, LookupCallback* callback);
void AsyncLookupName(const string& name, LookupCallback* callback);
void AsyncLookupNameText(const string& name, LookupCallback* callback);
struct Stats {
unsigned long requests; // These count only async requests.
@ -163,8 +163,6 @@ protected:
RecordType* dm_rec;
int dns_fake_count; // used to generate unique fake replies
typedef list<LookupCallback*> CallbackList;
struct AsyncRequest {

View file

@ -192,6 +192,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
string fullname = make_full_var_name(current_module.c_str(), s.c_str());
debug_msg("Function %s not defined.\n", fullname.c_str());
plr.type = plrUnknown;
Unref(id);
return;
}
@ -199,6 +200,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
{
debug_msg("Function %s not declared.\n", id->Name());
plr.type = plrUnknown;
Unref(id);
return;
}
@ -206,6 +208,7 @@ static void parse_function_name(vector<ParseLocationRec>& result,
{
debug_msg("Function %s declared but not defined.\n", id->Name());
plr.type = plrUnknown;
Unref(id);
return;
}
@ -216,9 +219,12 @@ static void parse_function_name(vector<ParseLocationRec>& result,
{
debug_msg("Function %s is a built-in function\n", id->Name());
plr.type = plrUnknown;
Unref(id);
return;
}
Unref(id);
Stmt* body = 0; // the particular body we care about; 0 = all
if ( bodies.size() == 1 )

View file

@ -33,10 +33,12 @@ enum DebugStream {
NUM_DBGS // Has to be last
};
#define DBG_LOG(args...) debug_logger.Log(args)
#define DBG_LOG_VERBOSE(args...) \
if ( debug_logger.IsVerbose() ) \
debug_logger.Log(args)
#define DBG_LOG(stream, args...) \
if ( debug_logger.IsEnabled(stream) ) \
debug_logger.Log(stream, args)
#define DBG_LOG_VERBOSE(stream, args...) \
if ( debug_logger.IsVerbose() && debug_logger.IsEnabled(stream) ) \
debug_logger.Log(stream, args)
#define DBG_PUSH(stream) debug_logger.PushIndent(stream)
#define DBG_POP(stream) debug_logger.PopIndent(stream)

View file

@ -216,18 +216,32 @@ void ODesc::Indent()
}
}
static const char hex_chars[] = "0123456789abcdef";
static const char* find_first_unprintable(ODesc* d, const char* bytes, unsigned int n)
static bool starts_with(const char* str1, const char* str2, size_t len)
{
if ( d->IsBinary() )
for ( size_t i = 0; i < len; ++i )
if ( str1[i] != str2[i] )
return false;
return true;
}
size_t ODesc::StartsWithEscapeSequence(const char* start, const char* end)
{
if ( escape_sequences.empty() )
return 0;
while ( n-- )
escape_set::const_iterator it;
for ( it = escape_sequences.begin(); it != escape_sequences.end(); ++it )
{
if ( ! isprint(*bytes) )
return bytes;
++bytes;
const string& esc_str = *it;
size_t esc_len = esc_str.length();
if ( start + esc_len > end )
continue;
if ( starts_with(start, esc_str.c_str(), esc_len) )
return esc_len;
}
return 0;
@ -235,21 +249,23 @@ static const char* find_first_unprintable(ODesc* d, const char* bytes, unsigned
pair<const char*, size_t> ODesc::FirstEscapeLoc(const char* bytes, size_t n)
{
pair<const char*, size_t> p(find_first_unprintable(this, bytes, n), 1);
typedef pair<const char*, size_t> escape_pos;
string str(bytes, n);
list<string>::const_iterator it;
for ( it = escape_sequences.begin(); it != escape_sequences.end(); ++it )
if ( IsBinary() )
return escape_pos(0, 0);
for ( size_t i = 0; i < n; ++i )
{
size_t pos = str.find(*it);
if ( pos != string::npos && (p.first == 0 || bytes + pos < p.first) )
{
p.first = bytes + pos;
p.second = it->size();
}
if ( ! isprint(bytes[i]) )
return escape_pos(bytes + i, 1);
size_t len = StartsWithEscapeSequence(bytes + i, bytes + n);
if ( len )
return escape_pos(bytes + i, len);
}
return p;
return escape_pos(0, 0);
}
void ODesc::AddBytes(const void* bytes, unsigned int n)
@ -266,21 +282,11 @@ void ODesc::AddBytes(const void* bytes, unsigned int n)
while ( s < e )
{
pair<const char*, size_t> p = FirstEscapeLoc(s, e - s);
if ( p.first )
{
AddBytesRaw(s, p.first - s);
if ( p.second == 1 )
{
char hex[6] = "\\x00";
hex[2] = hex_chars[((*p.first) & 0xf0) >> 4];
hex[3] = hex_chars[(*p.first) & 0x0f];
AddBytesRaw(hex, 4);
}
else
{
string esc_str = get_escaped_string(string(p.first, p.second), true);
AddBytesRaw(esc_str.c_str(), esc_str.size());
}
get_escaped_string(this, p.first, p.second, true);
s = p.first + p.second;
}
else

View file

@ -4,7 +4,7 @@
#define descriptor_h
#include <stdio.h>
#include <list>
#include <set>
#include <utility>
#include "BroString.h"
@ -54,16 +54,16 @@ public:
void SetFlush(int arg_do_flush) { do_flush = arg_do_flush; }
void EnableEscaping();
void AddEscapeSequence(const char* s) { escape_sequences.push_back(s); }
void AddEscapeSequence(const char* s) { escape_sequences.insert(s); }
void AddEscapeSequence(const char* s, size_t n)
{ escape_sequences.push_back(string(s, n)); }
{ escape_sequences.insert(string(s, n)); }
void AddEscapeSequence(const string & s)
{ escape_sequences.push_back(s); }
void RemoveEscapeSequence(const char* s) { escape_sequences.remove(s); }
{ escape_sequences.insert(s); }
void RemoveEscapeSequence(const char* s) { escape_sequences.erase(s); }
void RemoveEscapeSequence(const char* s, size_t n)
{ escape_sequences.remove(string(s, n)); }
{ escape_sequences.erase(string(s, n)); }
void RemoveEscapeSequence(const string & s)
{ escape_sequences.remove(s); }
{ escape_sequences.erase(s); }
void PushIndent();
void PopIndent();
@ -163,6 +163,15 @@ protected:
*/
pair<const char*, size_t> FirstEscapeLoc(const char* bytes, size_t n);
/**
* @param start start of string to check for starting with an espace
* sequence.
* @param end one byte past the last character in the string.
* @return The number of bytes in the escape sequence that the string
* starts with.
*/
size_t StartsWithEscapeSequence(const char* start, const char* end);
desc_type type;
desc_style style;
@ -171,7 +180,8 @@ protected:
unsigned int size; // size of buffer in bytes
bool escape; // escape unprintable characters in output?
list<string> escape_sequences; // additional sequences of chars to escape
typedef set<string> escape_set;
escape_set escape_sequences; // additional sequences of chars to escape
BroFile* f; // or the file we're using.

View file

@ -39,7 +39,10 @@ FuncType* EventHandler::FType()
if ( id->Type()->Tag() != TYPE_FUNC )
return 0;
return type = id->Type()->AsFuncType();
type = id->Type()->AsFuncType();
Unref(id);
return type;
}
void EventHandler::SetLocalHandler(Func* f)

View file

@ -3392,22 +3392,12 @@ bool HasFieldExpr::DoUnserialize(UnserialInfo* info)
return UNSERIALIZE(&not_used) && UNSERIALIZE_STR(&field_name, 0) && UNSERIALIZE(&field);
}
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list,
BroType* arg_type)
RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
: UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list)
{
ctor_type = 0;
if ( IsError() )
return;
if ( arg_type && arg_type->Tag() != TYPE_RECORD )
{
Error("bad record constructor type", arg_type);
SetError();
return;
}
// Spin through the list, which should be comprised of
// either record's or record-field-assign, and build up a
// record type to associate with this constructor.
@ -3447,17 +3437,11 @@ RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list,
}
}
ctor_type = new RecordType(record_types);
if ( arg_type )
SetType(arg_type->Ref());
else
SetType(ctor_type->Ref());
SetType(new RecordType(record_types));
}
RecordConstructorExpr::~RecordConstructorExpr()
{
Unref(ctor_type);
}
Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
@ -3483,7 +3467,7 @@ Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
Val* RecordConstructorExpr::Fold(Val* v) const
{
ListVal* lv = v->AsListVal();
RecordType* rt = ctor_type->AsRecordType();
RecordType* rt = type->AsRecordType();
if ( lv->Length() != rt->NumFields() )
Internal("inconsistency evaluating record constructor");
@ -3493,19 +3477,6 @@ Val* RecordConstructorExpr::Fold(Val* v) const
for ( int i = 0; i < lv->Length(); ++i )
rv->Assign(i, lv->Index(i)->Ref());
if ( ! same_type(rt, type) )
{
RecordVal* new_val = rv->CoerceTo(type->AsRecordType());
if ( new_val )
{
Unref(rv);
rv = new_val;
}
else
Internal("record constructor coercion failed");
}
return rv;
}
@ -3521,16 +3492,12 @@ IMPLEMENT_SERIAL(RecordConstructorExpr, SER_RECORD_CONSTRUCTOR_EXPR);
bool RecordConstructorExpr::DoSerialize(SerialInfo* info) const
{
DO_SERIALIZE(SER_RECORD_CONSTRUCTOR_EXPR, UnaryExpr);
SERIALIZE_OPTIONAL(ctor_type);
return true;
}
bool RecordConstructorExpr::DoUnserialize(UnserialInfo* info)
{
DO_UNSERIALIZE(UnaryExpr);
BroType* t = 0;
UNSERIALIZE_OPTIONAL(t, RecordType::Unserialize(info));
ctor_type = t->AsRecordType();
return true;
}
@ -3819,7 +3786,9 @@ VectorConstructorExpr::VectorConstructorExpr(ListExpr* constructor_list,
if ( constructor_list->Exprs().length() == 0 )
{
// vector().
SetType(new ::VectorType(base_type(TYPE_ANY)));
// By default, assign VOID type here. A vector with
// void type set is seen as an unspecified vector.
SetType(new ::VectorType(base_type(TYPE_VOID)));
return;
}
@ -4212,6 +4181,26 @@ RecordCoerceExpr::~RecordCoerceExpr()
delete [] map;
}
Val* RecordCoerceExpr::InitVal(const BroType* t, Val* aggr) const
{
Val* v = Eval(0);
if ( v )
{
RecordVal* rv = v->AsRecordVal();
RecordVal* ar = rv->CoerceTo(t->AsRecordType(), aggr);
if ( ar )
{
Unref(rv);
return ar;
}
}
Error("bad record initializer");
return 0;
}
Val* RecordCoerceExpr::Fold(Val* v) const
{
RecordVal* val = new RecordVal(Type()->AsRecordType());
@ -4236,6 +4225,13 @@ Val* RecordCoerceExpr::Fold(Val* v) const
assert(rhs || Type()->AsRecordType()->FieldDecl(i)->FindAttr(ATTR_OPTIONAL));
if ( ! rhs )
{
// Optional field is missing.
val->Assign(i, 0);
continue;
}
BroType* rhs_type = rhs->Type();
RecordType* val_type = val->Type()->AsRecordType();
BroType* field_type = val_type->FieldType(i);

View file

@ -753,7 +753,7 @@ protected:
class RecordConstructorExpr : public UnaryExpr {
public:
RecordConstructorExpr(ListExpr* constructor_list, BroType* arg_type = 0);
RecordConstructorExpr(ListExpr* constructor_list);
~RecordConstructorExpr();
protected:
@ -766,8 +766,6 @@ protected:
void ExprDescribe(ODesc* d) const;
DECLARE_SERIAL(RecordConstructorExpr);
RecordType* ctor_type; // type inferred from the ctor expression list args
};
class TableConstructorExpr : public UnaryExpr {
@ -878,6 +876,7 @@ protected:
friend class Expr;
RecordCoerceExpr() { map = 0; }
Val* InitVal(const BroType* t, Val* aggr) const;
Val* Fold(Val* v) const;
DECLARE_SERIAL(RecordCoerceExpr);

View file

@ -97,9 +97,9 @@ void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
// Linux MTU discovery for UDP can do this, for example.
s->Weird("fragment_with_DF", ip);
int offset = ip->FragOffset();
int len = ip->TotalLen();
int hdr_len = ip->HdrLen();
uint16 offset = ip->FragOffset();
uint32 len = ip->TotalLen();
uint16 hdr_len = ip->HdrLen();
if ( len < hdr_len )
{
@ -107,7 +107,7 @@ void FragReassembler::AddFragment(double t, const IP_Hdr* ip, const u_char* pkt)
return;
}
int upper_seq = offset + len - hdr_len;
uint64 upper_seq = offset + len - hdr_len;
if ( ! offset )
// Make sure to use the first fragment header's next field.
@ -178,7 +178,7 @@ void FragReassembler::Weird(const char* name) const
}
}
void FragReassembler::Overlap(const u_char* b1, const u_char* b2, int n)
void FragReassembler::Overlap(const u_char* b1, const u_char* b2, uint64 n)
{
if ( memcmp((const void*) b1, (const void*) b2, n) )
Weird("fragment_inconsistency");
@ -231,7 +231,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
return;
// We have it all. Compute the expected size of the fragment.
int n = proto_hdr_len + frag_size;
uint64 n = proto_hdr_len + frag_size;
// It's possible that we have blocks associated with this fragment
// that exceed this size, if we saw MF fragments (which don't lead
@ -260,6 +260,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */)
reporter->InternalWarning("bad fragment reassembly");
DeleteTimer();
Expire(network_time);
delete [] pkt_start;
return;
}

View file

@ -34,14 +34,14 @@ public:
protected:
void BlockInserted(DataBlock* start_block);
void Overlap(const u_char* b1, const u_char* b2, int n);
void Overlap(const u_char* b1, const u_char* b2, uint64 n);
void Weird(const char* name) const;
u_char* proto_hdr;
IP_Hdr* reassembled_pkt;
int proto_hdr_len;
uint16 proto_hdr_len;
NetSessions* s;
int frag_size; // size of fully reassembled fragment
uint64 frag_size; // size of fully reassembled fragment
uint16 next_proto; // first IPv6 fragment header's next proto field
HashKey* key;

View file

@ -475,6 +475,7 @@ BuiltinFunc::BuiltinFunc(built_in_func arg_func, const char* arg_name,
type = id->Type()->Ref();
id->SetVal(new Val(this));
Unref(id);
}
BuiltinFunc::~BuiltinFunc()

View file

@ -1,5 +1,6 @@
// See the file "COPYING" in the main distribution directory for copyright.
#include <cstdlib>
#include <string>
#include <vector>
#include "IPAddr.h"
@ -45,6 +46,14 @@ HashKey* BuildConnIDHashKey(const ConnID& id)
return new HashKey(&key, sizeof(key));
}
static inline uint32_t bit_mask32(int bottom_bits)
{
if ( bottom_bits >= 32 )
return 0xffffffff;
return (((uint32_t) 1) << bottom_bits) - 1;
}
void IPAddr::Mask(int top_bits_to_keep)
{
if ( top_bits_to_keep < 0 || top_bits_to_keep > 128 )
@ -53,25 +62,20 @@ void IPAddr::Mask(int top_bits_to_keep)
return;
}
uint32_t tmp[4];
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
uint32_t mask_bits[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
std::ldiv_t res = std::ldiv(top_bits_to_keep, 32);
int word = 3;
int bits_to_chop = 128 - top_bits_to_keep;
if ( res.quot < 4 )
mask_bits[res.quot] =
htonl(mask_bits[res.quot] & ~bit_mask32(32 - res.rem));
while ( bits_to_chop >= 32 )
{
tmp[word] = 0;
--word;
bits_to_chop -= 32;
}
for ( unsigned int i = res.quot + 1; i < 4; ++i )
mask_bits[i] = 0;
uint32_t w = ntohl(tmp[word]);
w >>= bits_to_chop;
w <<= bits_to_chop;
tmp[word] = htonl(w);
uint32_t* p = reinterpret_cast<uint32_t*>(in6.s6_addr);
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
for ( unsigned int i = 0; i < 4; ++i )
p[i] &= mask_bits[i];
}
void IPAddr::ReverseMask(int top_bits_to_chop)
@ -82,25 +86,19 @@ void IPAddr::ReverseMask(int top_bits_to_chop)
return;
}
uint32_t tmp[4];
memcpy(tmp, in6.s6_addr, sizeof(in6.s6_addr));
uint32_t mask_bits[4] = { 0, 0, 0, 0 };
std::ldiv_t res = std::ldiv(top_bits_to_chop, 32);
int word = 0;
int bits_to_chop = top_bits_to_chop;
if ( res.quot < 4 )
mask_bits[res.quot] = htonl(bit_mask32(32 - res.rem));
while ( bits_to_chop >= 32 )
{
tmp[word] = 0;
++word;
bits_to_chop -= 32;
}
for ( unsigned int i = res.quot + 1; i < 4; ++i )
mask_bits[i] = 0xffffffff;
uint32_t w = ntohl(tmp[word]);
w <<= bits_to_chop;
w >>= bits_to_chop;
tmp[word] = htonl(w);
uint32_t* p = reinterpret_cast<uint32_t*>(in6.s6_addr);
memcpy(in6.s6_addr, tmp, sizeof(in6.s6_addr));
for ( unsigned int i = 0; i < 4; ++i )
p[i] &= mask_bits[i];
}
void IPAddr::Init(const std::string& s)

View file

@ -27,7 +27,6 @@
#include "Reporter.h"
#include "Net.h"
#include "Anon.h"
#include "PacketSort.h"
#include "Serializer.h"
#include "PacketDumper.h"
@ -58,8 +57,6 @@ double bro_start_network_time; // timestamp of first packet
double last_watchdog_proc_time = 0.0; // value of above during last watchdog
bool terminating = false; // whether we're done reading and finishing up
PacketSortGlobalPQ* packet_sorter = 0;
const struct pcap_pkthdr* current_hdr = 0;
const u_char* current_pkt = 0;
int current_dispatched = 0;
@ -286,9 +283,6 @@ void net_init(name_list& interfaces, name_list& readfiles,
init_ip_addr_anonymizers();
if ( packet_sort_window > 0 )
packet_sorter = new PacketSortGlobalPQ();
sessions = new NetSessions();
if ( do_watchdog )
@ -313,14 +307,12 @@ void expire_timers(PktSrc* src_ps)
void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr,
const u_char* pkt, int hdr_size,
PktSrc* src_ps, PacketSortElement* pkt_elem)
PktSrc* src_ps)
{
if ( ! bro_start_network_time )
bro_start_network_time = t;
TimerMgr* tmgr =
src_ps ? sessions->LookupTimerMgr(src_ps->GetCurrentTag())
: timer_mgr;
TimerMgr* tmgr = sessions->LookupTimerMgr(src_ps->GetCurrentTag());
// network_time never goes back.
network_time = tmgr->Time() < t ? t : tmgr->Time();
@ -351,7 +343,7 @@ void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr,
}
}
sessions->DispatchPacket(t, hdr, pkt, hdr_size, src_ps, pkt_elem);
sessions->DispatchPacket(t, hdr, pkt, hdr_size, src_ps);
mgr.Drain();
if ( sp )
@ -367,62 +359,11 @@ void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr,
current_pktsrc = 0;
}
int process_packet_sorter(double latest_packet_time)
{
if ( ! packet_sorter )
return 0;
double min_t = latest_packet_time - packet_sort_window;
int num_pkts_dispatched = 0;
PacketSortElement* pkt_elem;
// Dispatch packets in the packet_sorter until timestamp min_t.
// It's possible that zero or multiple packets are dispatched.
while ( (pkt_elem = packet_sorter->RemoveMin(min_t)) != 0 )
{
net_packet_dispatch(pkt_elem->TimeStamp(),
pkt_elem->Hdr(), pkt_elem->Pkt(),
pkt_elem->HdrSize(), pkt_elem->Src(),
pkt_elem);
++num_pkts_dispatched;
delete pkt_elem;
}
return num_pkts_dispatched;
}
void net_packet_arrival(double t, const struct pcap_pkthdr* hdr,
const u_char* pkt, int hdr_size,
PktSrc* src_ps)
{
if ( packet_sorter )
{
// Note that when we enable packet sorter, there will
// be a small window between the time packet arrives
// to Bro and when it is processed ("dispatched"). We
// define network_time to be the latest timestamp for
// packets *dispatched* so far (usually that's the
// timestamp of the current packet).
// Add the packet to the packet_sorter.
packet_sorter->Add(
new PacketSortElement(src_ps, t, hdr, pkt, hdr_size));
// Do we have any packets to dispatch from packet_sorter?
process_packet_sorter(t);
}
else
// Otherwise we dispatch the packet immediately
net_packet_dispatch(t, hdr, pkt, hdr_size, src_ps, 0);
}
void net_run()
{
set_processing_status("RUNNING", "net_run");
while ( io_sources.Size() ||
(packet_sorter && ! packet_sorter->Empty()) ||
(BifConst::exit_only_after_terminate && ! terminating) )
{
double ts;
@ -445,14 +386,12 @@ void net_run()
current_iosrc = src;
if ( src )
src->Process(); // which will call net_packet_arrival()
src->Process(); // which will call net_packet_dispatch()
else if ( reading_live && ! pseudo_realtime)
{ // live but no source is currently active
double ct = current_time();
if ( packet_sorter && ! packet_sorter->Empty() )
process_packet_sorter(ct);
else if ( ! net_is_processing_suspended() )
if ( ! net_is_processing_suspended() )
{
// Take advantage of the lull to get up to
// date on timers and events.
@ -462,15 +401,6 @@ void net_run()
}
}
else if ( packet_sorter && ! packet_sorter->Empty() )
{
// We are no longer reading live; done with all the
// sources.
// Drain packets remaining in the packet sorter.
process_packet_sorter(
network_time + packet_sort_window + 1000000);
}
else if ( (have_pending_timers || using_communication) &&
! pseudo_realtime )
{
@ -581,7 +511,6 @@ void net_delete()
set_processing_status("TERMINATING", "net_delete");
delete sessions;
delete packet_sorter;
for ( int i = 0; i < NUM_ADDR_ANONYMIZATION_METHODS; ++i )
delete ip_anonymizer[i];

View file

@ -20,7 +20,7 @@ extern void net_run();
extern void net_get_final_stats();
extern void net_finish(int drain_events);
extern void net_delete(); // Reclaim all memory, etc.
extern void net_packet_arrival(double t, const struct pcap_pkthdr* hdr,
extern void net_packet_dispatch(double t, const struct pcap_pkthdr* hdr,
const u_char* pkt, int hdr_size,
PktSrc* src_ps);
extern int net_packet_match(BPF_Program* fp, const u_char* pkt,

View file

@ -20,6 +20,8 @@ TableType* string_set;
TableType* string_array;
TableType* count_set;
VectorType* string_vec;
VectorType* mime_matches;
RecordType* mime_match;
int watchdog_interval;
@ -47,8 +49,6 @@ int tcp_max_initial_window;
int tcp_max_above_hole_without_any_acks;
int tcp_excessive_data_without_further_acks;
RecordType* x509_type;
RecordType* socks_address;
double non_analyzed_lifetime;
@ -155,8 +155,6 @@ int table_incremental_step;
RecordType* packet_type;
double packet_sort_window;
double connection_status_update_interval;
StringVal* state_dir;
@ -331,6 +329,8 @@ void init_net_var()
string_set = internal_type("string_set")->AsTableType();
string_array = internal_type("string_array")->AsTableType();
string_vec = internal_type("string_vec")->AsVectorType();
mime_match = internal_type("mime_match")->AsRecordType();
mime_matches = internal_type("mime_matches")->AsVectorType();
ignore_checksums = opt_internal_int("ignore_checksums");
partial_connection_ok = opt_internal_int("partial_connection_ok");
@ -355,8 +355,6 @@ void init_net_var()
tcp_excessive_data_without_further_acks =
opt_internal_int("tcp_excessive_data_without_further_acks");
x509_type = internal_type("X509")->AsRecordType();
socks_address = internal_type("SOCKS::Address")->AsRecordType();
non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
@ -479,8 +477,6 @@ void init_net_var()
packet_type = internal_type("packet")->AsRecordType();
packet_sort_window = opt_internal_double("packet_sort_window");
orig_addr_anonymization = opt_internal_int("orig_addr_anonymization");
resp_addr_anonymization = opt_internal_int("resp_addr_anonymization");
other_addr_anonymization = opt_internal_int("other_addr_anonymization");

View file

@ -23,6 +23,8 @@ extern TableType* string_set;
extern TableType* string_array;
extern TableType* count_set;
extern VectorType* string_vec;
extern VectorType* mime_matches;
extern RecordType* mime_match;
extern int watchdog_interval;
@ -50,8 +52,6 @@ extern int tcp_max_initial_window;
extern int tcp_max_above_hole_without_any_acks;
extern int tcp_excessive_data_without_further_acks;
extern RecordType* x509_type;
extern RecordType* socks_address;
extern double non_analyzed_lifetime;
@ -158,8 +158,6 @@ extern int table_incremental_step;
extern RecordType* packet_type;
extern double packet_sort_window;
extern int orig_addr_anonymization, resp_addr_anonymization;
extern int other_addr_anonymization;
extern TableVal* preserve_orig_addr;

View file

@ -1,364 +0,0 @@
#include "IP.h"
#include "PacketSort.h"
const bool DEBUG_packetsort = false;
PacketSortElement::PacketSortElement(PktSrc* arg_src,
double arg_timestamp, const struct pcap_pkthdr* arg_hdr,
const u_char* arg_pkt, int arg_hdr_size)
{
src = arg_src;
timestamp = arg_timestamp;
hdr = *arg_hdr;
hdr_size = arg_hdr_size;
pkt = new u_char[hdr.caplen];
memcpy(pkt, arg_pkt, hdr.caplen);
is_tcp = 0;
ip_hdr = 0;
tcp_flags = 0;
endp = 0;
payload_length = 0;
key = 0;
// Now check if it is a "parsable" TCP packet.
uint32 caplen = hdr.caplen;
uint32 tcp_offset;
if ( caplen >= sizeof(struct ip) + hdr_size )
{
const struct ip* ip = (const struct ip*) (pkt + hdr_size);
if ( ip->ip_v == 4 )
ip_hdr = new IP_Hdr(ip, false);
else if ( ip->ip_v == 6 && (caplen >= sizeof(struct ip6_hdr) + hdr_size) )
ip_hdr = new IP_Hdr((const struct ip6_hdr*) ip, false, caplen - hdr_size);
else
// Weird will be generated later in NetSessions::NextPacket.
return;
if ( ip_hdr->NextProto() == IPPROTO_TCP &&
// Note: can't sort fragmented packets
( ! ip_hdr->IsFragment() ) )
{
tcp_offset = hdr_size + ip_hdr->HdrLen();
if ( caplen >= tcp_offset + sizeof(struct tcphdr) )
{
const struct tcphdr* tp = (const struct tcphdr*)
(pkt + tcp_offset);
id.src_addr = ip_hdr->SrcAddr();
id.dst_addr = ip_hdr->DstAddr();
id.src_port = tp->th_sport;
id.dst_port = tp->th_dport;
id.is_one_way = 0;
endp = addr_port_canon_lt(id.src_addr,
id.src_port,
id.dst_addr,
id.dst_port) ? 0 : 1;
seq[endp] = ntohl(tp->th_seq);
if ( tp->th_flags & TH_ACK )
seq[1-endp] = ntohl(tp->th_ack);
else
seq[1-endp] = 0;
tcp_flags = tp->th_flags;
// DEBUG_MSG("%.6f: %u, %u\n", timestamp, seq[0], seq[1]);
payload_length = ip_hdr->PayloadLen() - tp->th_off * 4;
key = BuildConnIDHashKey(id);
is_tcp = 1;
}
}
}
if ( DEBUG_packetsort && ! is_tcp )
DEBUG_MSG("%.6f non-TCP packet\n", timestamp);
}
PacketSortElement::~PacketSortElement()
{
delete [] pkt;
delete ip_hdr;
delete key;
}
int PacketSortPQ::Timestamp_Cmp(PacketSortElement* a, PacketSortElement* b)
{
double d = a->timestamp - b->timestamp;
if ( d > 0 ) return 1;
else if ( d < 0 ) return -1;
else return 0;
}
int PacketSortPQ::UpdatePQ(PacketSortElement* prev_e, PacketSortElement* new_e)
{
int index = prev_e->pq_index[pq_level];
new_e->pq_index[pq_level] = index;
pq[index] = new_e;
if ( Cmp(prev_e, new_e) > 0 )
return FixUp(new_e, index);
else
{
FixDown(new_e, index);
return index == 0;
}
}
int PacketSortPQ::AddToPQ(PacketSortElement* new_e)
{
int index = pq.size();
new_e->pq_index[pq_level] = index;
pq.push_back(new_e);
return FixUp(new_e, index);
}
int PacketSortPQ::RemoveFromPQ(PacketSortElement* prev_e)
{
if ( pq.size() > 1 )
{
PacketSortElement* new_e = pq[pq.size() - 1];
pq.pop_back();
return UpdatePQ(prev_e, new_e);
}
else
{
pq.pop_back();
return 1;
}
}
void PacketSortPQ::Assign(int k, PacketSortElement* e)
{
pq[k] = e;
e->pq_index[pq_level] = k;
}
PacketSortConnPQ::~PacketSortConnPQ()
{
// Delete elements only in ConnPQ (not in GlobalPQ) to avoid
// double delete.
for ( int i = 0; i < (int) pq.size(); ++i )
{
delete pq[i];
pq[i] = 0;
}
}
int PacketSortConnPQ::Cmp(PacketSortElement* a, PacketSortElement* b)
{
// Note: here we do not distinguish between packets without
// an ACK and packets with seq/ack of 0. The later will sorted
// only by their timestamps.
if ( a->seq[0] && b->seq[0] && a->seq[0] != b->seq[0] )
return (a->seq[0] > b->seq[0]) ? 1 : -1;
else if ( a->seq[1] && b->seq[1] && a->seq[1] != b->seq[1] )
return (a->seq[1] > b->seq[1]) ? 1 : -1;
else
return Timestamp_Cmp(a, b);
}
int PacketSortPQ::FixUp(PacketSortElement* e, int k)
{
if ( k == 0 )
{
Assign(0, e);
return 1;
}
int parent = (k-1) / 2;
if ( Cmp(pq[parent], e) > 0 )
{
Assign(k, pq[parent]);
return FixUp(e, parent);
}
else
{
Assign(k, e);
return 0;
}
}
void PacketSortPQ::FixDown(PacketSortElement* e, int k)
{
uint32 kid = k * 2 + 1;
if ( kid >= pq.size() )
{
Assign(k, e);
return;
}
if ( kid + 1 < pq.size() && Cmp(pq[kid], pq[kid+1]) > 0 )
++kid;
if ( Cmp(e, pq[kid]) > 0 )
{
Assign(k, pq[kid]);
FixDown(e, kid);
}
else
Assign(k, e);
}
int PacketSortConnPQ::Add(PacketSortElement* e)
{
#if 0
int endp = e->endp;
uint32 end_seq = e->seq[endp] + e->payload_length;
int p = 1 - endp;
if ( (e->tcp_flags & TH_RST) && ! (e->tcp_flags & TH_ACK) )
{
DEBUG_MSG("%.6f %c: %u -> %u\n",
e->TimeStamp(), (p == endp) ? 'S' : 'A',
e->seq[p], next_seq[p]);
e->seq[p] = next_seq[p];
}
if ( end_seq > next_seq[endp] )
next_seq[endp] = end_seq;
#endif
return AddToPQ(e);
}
void PacketSortConnPQ::UpdateDeliveredSeq(int endp, int seq, int len, int ack)
{
if ( delivered_seq[endp] == 0 || delivered_seq[endp] == seq )
delivered_seq[endp] = seq + len;
if ( ack > delivered_seq[1 - endp] )
delivered_seq[endp] = ack;
}
bool PacketSortConnPQ::IsContentGapSafe(PacketSortElement* e)
{
int ack = e->seq[1 - e->endp];
return ack <= delivered_seq[1 - e->endp];
}
int PacketSortConnPQ::Remove(PacketSortElement* e)
{
int ret = RemoveFromPQ(e);
UpdateDeliveredSeq(e->endp, e->seq[e->endp], e->payload_length,
e->seq[1 - e->endp]);
return ret;
}
static void DeleteConnPQ(void* p)
{
delete (PacketSortConnPQ*) p;
}
PacketSortGlobalPQ::PacketSortGlobalPQ()
{
pq_level = GLOBAL_PQ;
conn_pq_table.SetDeleteFunc(DeleteConnPQ);
}
PacketSortGlobalPQ::~PacketSortGlobalPQ()
{
// Destruction of PacketSortConnPQ will delete all conn_pq's.
}
int PacketSortGlobalPQ::Add(PacketSortElement* e)
{
if ( e->is_tcp )
{
// TCP packets are sorted by sequence numbers
PacketSortConnPQ* conn_pq = FindConnPQ(e);
PacketSortElement* prev_min = conn_pq->Min();
if ( conn_pq->Add(e) )
{
ASSERT(conn_pq->Min() != prev_min);
if ( prev_min )
return UpdatePQ(prev_min, e);
else
return AddToPQ(e);
}
else
{
ASSERT(conn_pq->Min() == prev_min);
return 0;
}
}
else
return AddToPQ(e);
}
PacketSortElement* PacketSortGlobalPQ::RemoveMin(double timestamp)
{
PacketSortElement* e = Min();
if ( ! e )
return 0;
if ( e->is_tcp )
{
PacketSortConnPQ* conn_pq = FindConnPQ(e);
#if 0
// Note: the content gap safety check does not work
// because we remove the state for a connection once
// it has no packet in the priority queue.
// Do not deliver e if it arrives later than timestamp,
// and is not content-gap-safe.
if ( e->timestamp > timestamp &&
! conn_pq->IsContentGapSafe(e) )
return 0;
#else
if ( e->timestamp > timestamp )
return 0;
#endif
conn_pq->Remove(e);
PacketSortElement* new_e = conn_pq->Min();
if ( new_e )
UpdatePQ(e, new_e);
else
{
RemoveFromPQ(e);
conn_pq_table.Remove(e->key);
delete conn_pq;
}
}
else
RemoveFromPQ(e);
return e;
}
PacketSortConnPQ* PacketSortGlobalPQ::FindConnPQ(PacketSortElement* e)
{
if ( ! e->is_tcp )
reporter->InternalError("cannot find a connection for an invalid id");
PacketSortConnPQ* pq = (PacketSortConnPQ*) conn_pq_table.Lookup(e->key);
if ( ! pq )
{
pq = new PacketSortConnPQ();
conn_pq_table.Insert(e->key, pq);
}
return pq;
}

View file

@ -1,132 +0,0 @@
#ifndef packetsort_h
#define packetsort_h
// Timestamps can be imprecise and even inconsistent among packets
// from different sources. This class tries to guess a "correct"
// order by looking at TCP sequence numbers.
//
// In particular, it tries to eliminate "false" content gaps.
#include "Dict.h"
#include "Conn.h"
enum {
CONN_PQ,
GLOBAL_PQ,
NUM_OF_PQ_LEVEL,
};
class PktSrc;
class PacketSortElement {
public:
PacketSortElement(PktSrc* src, double timestamp,
const struct pcap_pkthdr* hdr,
const u_char* pkt, int hdr_size);
~PacketSortElement();
PktSrc* Src() const { return src; }
double TimeStamp() const { return timestamp; }
const struct pcap_pkthdr* Hdr() const { return &hdr; }
const u_char* Pkt() const { return pkt; }
int HdrSize() const { return hdr_size; }
const IP_Hdr* IPHdr() const { return ip_hdr; }
protected:
PktSrc* src;
double timestamp;
struct pcap_pkthdr hdr;
u_char* pkt;
int hdr_size;
IP_Hdr* ip_hdr;
int is_tcp;
ConnID id;
uint32 seq[2]; // indexed by endpoint
int tcp_flags;
int endp; // 0 or 1
int payload_length;
HashKey* key;
int pq_index[NUM_OF_PQ_LEVEL];
friend class PacketSortPQ;
friend class PacketSortConnPQ;
friend class PacketSortGlobalPQ;
};
class PacketSortPQ {
public:
PacketSortPQ()
{ pq_level = -1; }
virtual ~PacketSortPQ() {}
PacketSortElement* Min() const { return (pq.size() > 0) ? pq[0] : 0; }
protected:
virtual int Cmp(PacketSortElement* a, PacketSortElement* b) = 0;
int Timestamp_Cmp(PacketSortElement* a, PacketSortElement* b);
int UpdatePQ(PacketSortElement* prev_e, PacketSortElement* new_e);
int AddToPQ(PacketSortElement* e);
int RemoveFromPQ(PacketSortElement* e);
void Assign(int k, PacketSortElement* e);
int FixUp(PacketSortElement* e, int k);
void FixDown(PacketSortElement* e, int k);
vector<PacketSortElement*> pq;
int pq_level;
};
// Sort by sequence numbers within a connection
class PacketSortConnPQ : public PacketSortPQ {
public:
PacketSortConnPQ()
{
pq_level = CONN_PQ;
delivered_seq[0] = delivered_seq[1] = 0;
}
~PacketSortConnPQ();
int Add(PacketSortElement* e);
int Remove(PacketSortElement* e);
bool IsContentGapSafe(PacketSortElement* e);
protected:
int Cmp(PacketSortElement* a, PacketSortElement* b);
void UpdateDeliveredSeq(int endp, int seq, int len, int ack);
int delivered_seq[2];
};
declare(PDict, PacketSortConnPQ);
// Sort by timestamps.
class PacketSortGlobalPQ : public PacketSortPQ {
public:
PacketSortGlobalPQ();
~PacketSortGlobalPQ();
int Add(PacketSortElement* e);
int Empty() const { return conn_pq_table.Length() == 0; }
// Returns the next packet to dispatch if it arrives earlier than the
// given timestamp, otherwise returns 0.
// The packet, if to be returned, is also removed from the
// priority queue.
PacketSortElement* RemoveMin(double timestamp);
protected:
int Cmp(PacketSortElement* a, PacketSortElement* b)
{ return Timestamp_Cmp(a, b); }
PacketSortConnPQ* FindConnPQ(PacketSortElement* e);
PDict(PacketSortConnPQ) conn_pq_table;
};
#endif

View file

@ -229,12 +229,21 @@ void PktSrc::Process()
{
// MPLS carried over the ethernet frame.
case 0x8847:
// Remove the data link layer and denote a
// header size of zero before the IP header.
have_mpls = true;
data += get_link_header_size(datalink);
pkt_hdr_size = 0;
break;
// VLAN carried over the ethernet frame.
case 0x8100:
data += get_link_header_size(datalink);
// Check for MPLS in VLAN.
if ( ((data[2] << 8) + data[3]) == 0x8847 )
have_mpls = true;
data += 4; // Skip the vlan header
pkt_hdr_size = 0;
@ -274,8 +283,13 @@ void PktSrc::Process()
protocol = (data[2] << 8) + data[3];
if ( protocol == 0x0281 )
// MPLS Unicast
{
// MPLS Unicast. Remove the data link layer and
// denote a header size of zero before the IP header.
have_mpls = true;
data += get_link_header_size(datalink);
pkt_hdr_size = 0;
}
else if ( protocol != 0x0021 && protocol != 0x0057 )
{
@ -290,12 +304,6 @@ void PktSrc::Process()
if ( have_mpls )
{
// Remove the data link layer
data += get_link_header_size(datalink);
// Denote a header size of zero before the IP header
pkt_hdr_size = 0;
// Skip the MPLS label stack.
bool end_of_stack = false;
@ -309,13 +317,13 @@ void PktSrc::Process()
if ( pseudo_realtime )
{
current_pseudo = CheckPseudoTime();
net_packet_arrival(current_pseudo, &hdr, data, pkt_hdr_size, this);
net_packet_dispatch(current_pseudo, &hdr, data, pkt_hdr_size, this);
if ( ! first_wallclock )
first_wallclock = current_time(true);
}
else
net_packet_arrival(current_timestamp, &hdr, data, pkt_hdr_size, this);
net_packet_dispatch(current_timestamp, &hdr, data, pkt_hdr_size, this);
data = 0;
}
@ -661,7 +669,7 @@ PktDumper::PktDumper(const char* arg_filename, bool arg_append)
if ( linktype < 0 )
linktype = DLT_EN10MB;
pd = pcap_open_dead(linktype, 8192);
pd = pcap_open_dead(linktype, snaplen);
if ( ! pd )
{
Error("error for pcap_open_dead");

View file

@ -3,6 +3,7 @@
#include "config.h"
#include <stdlib.h>
#include <utility>
#include "RE.h"
#include "DFA.h"
@ -266,6 +267,15 @@ void Specific_RE_Matcher::Dump(FILE* f)
dfa->Dump(f);
}
inline void RE_Match_State::AddMatches(const AcceptingSet& as,
MatchPos position)
{
typedef std::pair<AcceptIdx, MatchPos> am_idx;
for ( AcceptingSet::const_iterator it = as.begin(); it != as.end(); ++it )
accepted_matches.insert(am_idx(*it, position));
}
bool RE_Match_State::Match(const u_char* bv, int n,
bool bol, bool eol, bool clear)
{
@ -283,14 +293,9 @@ bool RE_Match_State::Match(const u_char* bv, int n,
current_state = dfa->StartState();
const AcceptingSet* ac = current_state->Accept();
if ( ac )
{
loop_over_list(*ac, i)
{
accepted.append((*ac)[i]);
match_pos.append(0);
}
}
AddMatches(*ac, 0);
}
else if ( clear )
@ -301,7 +306,7 @@ bool RE_Match_State::Match(const u_char* bv, int n,
current_pos = 0;
int old_matches = accepted.length();
size_t old_matches = accepted_matches.size();
int ec;
int m = bol ? n + 1 : n;
@ -324,25 +329,17 @@ bool RE_Match_State::Match(const u_char* bv, int n,
break;
}
if ( next_state->Accept() )
{
const AcceptingSet* ac = next_state->Accept();
loop_over_list(*ac, i)
{
if ( ! accepted.is_member((*ac)[i]) )
{
accepted.append((*ac)[i]);
match_pos.append(current_pos);
}
}
}
const AcceptingSet* ac = next_state->Accept();
if ( ac )
AddMatches(*ac, current_pos);
++current_pos;
current_state = next_state;
}
return accepted.length() != old_matches;
return accepted_matches.size() != old_matches;
}
int Specific_RE_Matcher::LongestMatch(const u_char* bv, int n)
@ -399,7 +396,8 @@ unsigned int Specific_RE_Matcher::MemoryAllocation() const
+ equiv_class.Size() - padded_sizeof(EquivClass)
+ (dfa ? dfa->MemoryAllocation() : 0) // this is ref counted; consider the bytes here?
+ padded_sizeof(*any_ccl)
+ accepted->MemoryAllocation();
+ padded_sizeof(*accepted)
+ accepted->size() * padded_sizeof(AcceptingSet::key_type);
}
RE_Matcher::RE_Matcher()

View file

@ -9,6 +9,9 @@
#include "CCL.h"
#include "EquivClass.h"
#include <set>
#include <map>
#include <ctype.h>
typedef int (*cce_func)(int);
@ -33,7 +36,10 @@ extern int re_lex(void);
extern int clower(int);
extern void synerr(const char str[]);
typedef int_list AcceptingSet;
typedef int AcceptIdx;
typedef std::set<AcceptIdx> AcceptingSet;
typedef uint64 MatchPos;
typedef std::map<AcceptIdx, MatchPos> AcceptingMatchSet;
typedef name_list string_list;
typedef enum { MATCH_ANYWHERE, MATCH_EXACTLY, } match_type;
@ -135,8 +141,8 @@ public:
current_state = 0;
}
const AcceptingSet* Accepted() const { return &accepted; }
const int_list* MatchPositions() const { return &match_pos; }
const AcceptingMatchSet& AcceptedMatches() const
{ return accepted_matches; }
// Returns the number of bytes feeded into the matcher so far
int Length() { return current_pos; }
@ -149,16 +155,16 @@ public:
{
current_pos = -1;
current_state = 0;
accepted.clear();
match_pos.clear();
accepted_matches.clear();
}
void AddMatches(const AcceptingSet& as, MatchPos position);
protected:
DFA_Machine* dfa;
int* ecs;
AcceptingSet accepted;
int_list match_pos;
AcceptingMatchSet accepted_matches;
DFA_State* current_state;
int current_pos;
};

View file

@ -7,14 +7,9 @@
#include "Reassem.h"
#include "Serializer.h"
const bool DEBUG_reassem = false;
static const bool DEBUG_reassem = false;
#ifdef DEBUG
int reassem_seen_bytes = 0;
int reassem_copied_bytes = 0;
#endif
DataBlock::DataBlock(const u_char* data, int size, int arg_seq,
DataBlock::DataBlock(const u_char* data, uint64 size, uint64 arg_seq,
DataBlock* arg_prev, DataBlock* arg_next)
{
seq = arg_seq;
@ -23,10 +18,6 @@ DataBlock::DataBlock(const u_char* data, int size, int arg_seq,
memcpy((void*) block, (const void*) data, size);
#ifdef DEBUG
reassem_copied_bytes += size;
#endif
prev = arg_prev;
next = arg_next;
@ -38,9 +29,9 @@ DataBlock::DataBlock(const u_char* data, int size, int arg_seq,
Reassembler::total_size += pad_size(size) + padded_sizeof(DataBlock);
}
unsigned int Reassembler::total_size = 0;
uint64 Reassembler::total_size = 0;
Reassembler::Reassembler(int init_seq, ReassemblerType arg_type)
Reassembler::Reassembler(uint64 init_seq, ReassemblerType arg_type)
{
blocks = last_block = 0;
trim_seq = last_reassem_seq = init_seq;
@ -51,24 +42,20 @@ Reassembler::~Reassembler()
ClearBlocks();
}
void Reassembler::NewBlock(double t, int seq, int len, const u_char* data)
void Reassembler::NewBlock(double t, uint64 seq, uint64 len, const u_char* data)
{
if ( len == 0 )
return;
#ifdef DEBUG
reassem_seen_bytes += len;
#endif
uint64 upper_seq = seq + len;
int upper_seq = seq + len;
if ( seq_delta(upper_seq, trim_seq) <= 0 )
if ( upper_seq <= trim_seq )
// Old data, don't do any work for it.
return;
if ( seq_delta(seq, trim_seq) < 0 )
if ( seq < trim_seq )
{ // Partially old data, just keep the good stuff.
int amount_old = seq_delta(trim_seq, seq);
uint64 amount_old = trim_seq - seq;
data += amount_old;
seq += amount_old;
@ -86,42 +73,42 @@ void Reassembler::NewBlock(double t, int seq, int len, const u_char* data)
BlockInserted(start_block);
}
int Reassembler::TrimToSeq(int seq)
uint64 Reassembler::TrimToSeq(uint64 seq)
{
int num_missing = 0;
uint64 num_missing = 0;
// Do this accounting before looking for Undelivered data,
// since that will alter last_reassem_seq.
if ( blocks )
{
if ( seq_delta(blocks->seq, last_reassem_seq) > 0 )
if ( blocks->seq > last_reassem_seq )
// An initial hole.
num_missing += seq_delta(blocks->seq, last_reassem_seq);
num_missing += blocks->seq - last_reassem_seq;
}
else if ( seq_delta(seq, last_reassem_seq) > 0 )
else if ( seq > last_reassem_seq )
{ // Trimming data we never delivered.
if ( ! blocks )
// We won't have any accounting based on blocks
// for this hole.
num_missing += seq_delta(seq, last_reassem_seq);
num_missing += seq - last_reassem_seq;
}
if ( seq_delta(seq, last_reassem_seq) > 0 )
if ( seq > last_reassem_seq )
{
// We're trimming data we never delivered.
Undelivered(seq);
}
while ( blocks && seq_delta(blocks->upper, seq) <= 0 )
while ( blocks && blocks->upper <= seq )
{
DataBlock* b = blocks->next;
if ( b && seq_delta(b->seq, seq) <= 0 )
if ( b && b->seq <= seq )
{
if ( blocks->upper != b->seq )
num_missing += seq_delta(b->seq, blocks->upper);
num_missing += b->seq - blocks->upper;
}
else
{
@ -129,7 +116,7 @@ int Reassembler::TrimToSeq(int seq)
// Second half of test is for acks of FINs, which
// don't get entered into the sequence space.
if ( blocks->upper != seq && blocks->upper != seq - 1 )
num_missing += seq_delta(seq, blocks->upper);
num_missing += seq - blocks->upper;
}
delete blocks;
@ -150,7 +137,7 @@ int Reassembler::TrimToSeq(int seq)
else
last_block = 0;
if ( seq_delta(seq, trim_seq) > 0 )
if ( seq > trim_seq )
// seq is further ahead in the sequence space.
trim_seq = seq;
@ -169,9 +156,9 @@ void Reassembler::ClearBlocks()
last_block = 0;
}
int Reassembler::TotalSize() const
uint64 Reassembler::TotalSize() const
{
int size = 0;
uint64 size = 0;
for ( DataBlock* b = blocks; b; b = b->next )
size += b->Size();
@ -184,18 +171,18 @@ void Reassembler::Describe(ODesc* d) const
d->Add("reassembler");
}
void Reassembler::Undelivered(int up_to_seq)
void Reassembler::Undelivered(uint64 up_to_seq)
{
// TrimToSeq() expects this.
last_reassem_seq = up_to_seq;
}
DataBlock* Reassembler::AddAndCheck(DataBlock* b, int seq, int upper,
DataBlock* Reassembler::AddAndCheck(DataBlock* b, uint64 seq, uint64 upper,
const u_char* data)
{
if ( DEBUG_reassem )
{
DEBUG_MSG("%.6f Reassembler::AddAndCheck seq=%d, upper=%d\n",
DEBUG_MSG("%.6f Reassembler::AddAndCheck seq=%"PRIu64", upper=%"PRIu64"\n",
network_time, seq, upper);
}
@ -209,10 +196,10 @@ DataBlock* Reassembler::AddAndCheck(DataBlock* b, int seq, int upper,
// Find the first block that doesn't come completely before the
// new data.
while ( b->next && seq_delta(b->upper, seq) <= 0 )
while ( b->next && b->upper <= seq )
b = b->next;
if ( seq_delta(b->upper, seq) <= 0 )
if ( b->upper <= seq )
{
// b is the last block, and it comes completely before
// the new block.
@ -222,21 +209,20 @@ DataBlock* Reassembler::AddAndCheck(DataBlock* b, int seq, int upper,
DataBlock* new_b = 0;
if ( seq_delta(upper, b->seq) <= 0 )
if ( upper <= b->seq )
{
// The new block comes completely before b.
new_b = new DataBlock(data, seq_delta(upper, seq), seq,
b->prev, b);
new_b = new DataBlock(data, upper - seq, seq, b->prev, b);
if ( b == blocks )
blocks = new_b;
return new_b;
}
// The blocks overlap, complain.
if ( seq_delta(seq, b->seq) < 0 )
if ( seq < b->seq )
{
// The new block has a prefix that comes before b.
int prefix_len = seq_delta(b->seq, seq);
uint64 prefix_len = b->seq - seq;
new_b = new DataBlock(data, prefix_len, seq, b->prev, b);
if ( b == blocks )
blocks = new_b;
@ -247,11 +233,11 @@ DataBlock* Reassembler::AddAndCheck(DataBlock* b, int seq, int upper,
else
new_b = b;
int overlap_start = seq;
int overlap_offset = seq_delta(overlap_start, b->seq);
int new_b_len = seq_delta(upper, seq);
int b_len = seq_delta(b->upper, overlap_start);
int overlap_len = min(new_b_len, b_len);
uint64 overlap_start = seq;
uint64 overlap_offset = overlap_start - b->seq;
uint64 new_b_len = upper - seq;
uint64 b_len = b->upper - overlap_start;
uint64 overlap_len = min(new_b_len, b_len);
Overlap(&b->block[overlap_offset], data, overlap_len);

View file

@ -8,16 +8,16 @@
class DataBlock {
public:
DataBlock(const u_char* data, int size, int seq,
DataBlock(const u_char* data, uint64 size, uint64 seq,
DataBlock* prev, DataBlock* next);
~DataBlock();
int Size() const { return upper - seq; }
uint64 Size() const { return upper - seq; }
DataBlock* next; // next block with higher seq #
DataBlock* prev; // previous block with lower seq #
int seq, upper;
uint64 seq, upper;
u_char* block;
};
@ -26,22 +26,22 @@ enum ReassemblerType { REASSEM_IP, REASSEM_TCP };
class Reassembler : public BroObj {
public:
Reassembler(int init_seq, ReassemblerType arg_type);
Reassembler(uint64 init_seq, ReassemblerType arg_type);
virtual ~Reassembler();
void NewBlock(double t, int seq, int len, const u_char* data);
void NewBlock(double t, uint64 seq, uint64 len, const u_char* data);
// Throws away all blocks up to seq. Returns number of bytes
// if not all in-sequence, 0 if they were.
int TrimToSeq(int seq);
uint64 TrimToSeq(uint64 seq);
// Delete all held blocks.
void ClearBlocks();
int HasBlocks() const { return blocks != 0; }
int LastReassemSeq() const { return last_reassem_seq; }
uint64 LastReassemSeq() const { return last_reassem_seq; }
int TotalSize() const; // number of bytes buffered up
uint64 TotalSize() const; // number of bytes buffered up
void Describe(ODesc* d) const;
@ -49,7 +49,7 @@ public:
static Reassembler* Unserialize(UnserialInfo* info);
// Sum over all data buffered in some reassembler.
static unsigned int TotalMemoryAllocation() { return total_size; }
static uint64 TotalMemoryAllocation() { return total_size; }
protected:
Reassembler() { }
@ -58,20 +58,20 @@ protected:
friend class DataBlock;
virtual void Undelivered(int up_to_seq);
virtual void Undelivered(uint64 up_to_seq);
virtual void BlockInserted(DataBlock* b) = 0;
virtual void Overlap(const u_char* b1, const u_char* b2, int n) = 0;
virtual void Overlap(const u_char* b1, const u_char* b2, uint64 n) = 0;
DataBlock* AddAndCheck(DataBlock* b, int seq,
int upper, const u_char* data);
DataBlock* AddAndCheck(DataBlock* b, uint64 seq,
uint64 upper, const u_char* data);
DataBlock* blocks;
DataBlock* last_block;
int last_reassem_seq;
int trim_seq; // how far we've trimmed
uint64 last_reassem_seq;
uint64 trim_seq; // how far we've trimmed
static unsigned int total_size;
static uint64 total_size;
};
inline DataBlock::~DataBlock()

View file

@ -372,10 +372,7 @@ static bool sendCMsg(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id)
CMsg* msg = (CMsg*) new char[sizeof(CMsg)];
new (msg) CMsg(msg_type, id);
ChunkedIO::Chunk* c = new ChunkedIO::Chunk;
c->len = sizeof(CMsg);
c->data = (char*) msg;
ChunkedIO::Chunk* c = new ChunkedIO::Chunk((char*)msg, sizeof(CMsg));
return io->Write(c);
}
@ -386,10 +383,7 @@ static ChunkedIO::Chunk* makeSerialMsg(RemoteSerializer::PeerID id)
CMsg* msg = (CMsg*) new char[sizeof(CMsg)];
new (msg) CMsg(MSG_SERIAL, id);
ChunkedIO::Chunk* c = new ChunkedIO::Chunk;
c->len = sizeof(CMsg);
c->data = (char*) msg;
ChunkedIO::Chunk* c = new ChunkedIO::Chunk((char*)msg, sizeof(CMsg));
return c;
}
@ -424,7 +418,7 @@ static bool sendToIO(ChunkedIO* io, ChunkedIO::Chunk* c)
}
static bool sendToIO(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id,
const char* str, int len = -1)
const char* str, int len = -1, bool delete_with_free = false)
{
if ( ! sendCMsg(io, msg_type, id) )
{
@ -432,9 +426,14 @@ static bool sendToIO(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id,
return false;
}
ChunkedIO::Chunk* c = new ChunkedIO::Chunk;
c->len = len >= 0 ? len : strlen(str) + 1;
c->data = const_cast<char*>(str);
uint32 sz = len >= 0 ? len : strlen(str) + 1;
ChunkedIO::Chunk* c = new ChunkedIO::Chunk(const_cast<char*>(str), sz);
if ( delete_with_free )
c->free_func = ChunkedIO::Chunk::free_func_free;
else
c->free_func = ChunkedIO::Chunk::free_func_delete;
return sendToIO(io, c);
}
@ -455,10 +454,8 @@ static bool sendToIO(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id,
for ( int i = 0; i < nargs; i++ )
args[i] = htonl(va_arg(ap, uint32));
ChunkedIO::Chunk* c = new ChunkedIO::Chunk;
c->len = sizeof(uint32) * nargs;
c->data = (char*) args;
ChunkedIO::Chunk* c = new ChunkedIO::Chunk((char*)args,
sizeof(uint32) * nargs);
return sendToIO(io, c);
}
@ -1466,7 +1463,7 @@ void RemoteSerializer::Process()
current_pkt = p->pkt;
current_pktsrc = 0;
current_iosrc = this;
sessions->NextPacket(p->time, p->hdr, p->pkt, p->hdr_size, 0);
sessions->NextPacket(p->time, p->hdr, p->pkt, p->hdr_size);
mgr.Drain();
current_hdr = 0; // done with these
@ -1529,7 +1526,6 @@ bool RemoteSerializer::Poll(bool may_block)
current_msgtype = msg->Type();
current_args = 0;
delete [] c->data;
delete c;
switch ( current_msgtype ) {
@ -1592,7 +1588,6 @@ bool RemoteSerializer::Poll(bool may_block)
msgstate = TYPE;
bool result = DoMessage();
delete [] current_args->data;
delete current_args;
current_args = 0;
@ -1787,9 +1782,7 @@ void RemoteSerializer::PeerConnected(Peer* peer)
*args++ = htonl(peer->our_runtime);
strcpy((char*) args, peer->our_class.c_str());
ChunkedIO::Chunk* c = new ChunkedIO::Chunk;
c->len = len;
c->data = data;
ChunkedIO::Chunk* c = new ChunkedIO::Chunk(data, len);
if ( peer->our_class.size() )
Log(LogInfo, fmt("sending class \"%s\"", peer->our_class.c_str()), peer);
@ -2568,8 +2561,8 @@ bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal*
goto error;
c = new ChunkedIO::Chunk;
c->data = 0;
c->len = fmt.EndWrite(&c->data);
c->free_func = ChunkedIO::Chunk::free_func_free;
if ( ! SendToChild(c) )
goto error;
@ -2577,11 +2570,7 @@ bool RemoteSerializer::SendLogCreateWriter(PeerID peer_id, EnumVal* id, EnumVal*
return true;
error:
if ( c )
{
delete [] c->data;
delete c;
}
delete c;
FatalError(io->Error());
return false;
@ -2643,21 +2632,21 @@ bool RemoteSerializer::SendLogWrite(Peer* peer, EnumVal* id, EnumVal* writer, st
{
if ( ! FlushLogBuffer(peer) )
{
delete [] data;
free(data);
return false;
}
}
// If the data is actually larger than our complete buffer, just send it out.
if ( len > LOG_BUFFER_SIZE )
return SendToChild(MSG_LOG_WRITE, peer, data, len);
return SendToChild(MSG_LOG_WRITE, peer, data, len, true);
// Now we have space in the buffer, copy it into there.
memcpy(peer->log_buffer + peer->log_buffer_used, data, len);
peer->log_buffer_used += len;
assert(peer->log_buffer_used <= LOG_BUFFER_SIZE);
delete [] data;
free(data);
return true;
@ -3112,14 +3101,19 @@ bool RemoteSerializer::SendCMsgToChild(char msg_type, Peer* peer)
return true;
}
bool RemoteSerializer::SendToChild(char type, Peer* peer, char* str, int len)
bool RemoteSerializer::SendToChild(char type, Peer* peer, char* str, int len,
bool delete_with_free)
{
DEBUG_COMM(fmt("parent: (->child) %s (#%" PRI_SOURCE_ID ", %s)", msgToStr(type), peer ? peer->id : PEER_NONE, str));
if ( child_pid && sendToIO(io, type, peer ? peer->id : PEER_NONE, str, len) )
if ( child_pid && sendToIO(io, type, peer ? peer->id : PEER_NONE, str, len,
delete_with_free) )
return true;
delete [] str;
if ( delete_with_free )
free(str);
else
delete [] str;
if ( ! child_pid )
return false;
@ -3169,7 +3163,7 @@ bool RemoteSerializer::SendToChild(ChunkedIO::Chunk* c)
if ( child_pid && sendToIO(io, c) )
return true;
delete [] c->data;
c->free_func(c->data);
c->data = 0;
if ( ! child_pid )
@ -3545,7 +3539,6 @@ bool SocketComm::ProcessParentMessage()
parent_msgtype = msg->Type();
parent_args = 0;
delete [] c->data;
delete c;
switch ( parent_msgtype ) {
@ -3600,7 +3593,6 @@ bool SocketComm::ProcessParentMessage()
if ( parent_args )
{
delete [] parent_args->data;
delete parent_args;
parent_args = 0;
}
@ -3900,7 +3892,6 @@ bool SocketComm::ProcessRemoteMessage(SocketComm::Peer* peer)
peer->state = msg->Type();
}
delete [] c->data;
delete c;
break;

View file

@ -317,7 +317,8 @@ protected:
// Communication helpers
bool SendCMsgToChild(char msg_type, Peer* peer);
bool SendToChild(char type, Peer* peer, char* str, int len = -1);
bool SendToChild(char type, Peer* peer, char* str, int len = -1,
bool delete_with_free = false);
bool SendToChild(char type, Peer* peer, int nargs, ...); // can send uints32 only
bool SendToChild(ChunkedIO::Chunk* c);

View file

@ -38,7 +38,7 @@ Rule::~Rule()
const char* Rule::TypeToString(Rule::PatternType type)
{
static const char* labels[] = {
"Payload", "HTTP-REQUEST", "HTTP-REQUEST-BODY",
"File Magic", "Payload", "HTTP-REQUEST", "HTTP-REQUEST-BODY",
"HTTP-REQUEST-HEADER", "HTTP-REPLY-BODY",
"HTTP-REPLY-HEADER", "FTP", "Finger",
};

View file

@ -37,7 +37,7 @@ public:
unsigned int Index() const { return idx; }
enum PatternType {
PAYLOAD, HTTP_REQUEST, HTTP_REQUEST_BODY, HTTP_REQUEST_HEADER,
FILE_MAGIC, PAYLOAD, HTTP_REQUEST, HTTP_REQUEST_BODY, HTTP_REQUEST_HEADER,
HTTP_REPLY_BODY, HTTP_REPLY_HEADER, FTP, FINGER, TYPES,
};

View file

@ -35,6 +35,11 @@ void RuleActionEvent::PrintDebug()
fprintf(stderr, " RuleActionEvent: |%s|\n", msg);
}
void RuleActionMIME::PrintDebug()
{
fprintf(stderr, " RuleActionMIME: |%s|\n", mime);
}
RuleActionAnalyzer::RuleActionAnalyzer(const char* arg_analyzer)
{
string str(arg_analyzer);

View file

@ -36,6 +36,31 @@ private:
const char* msg;
};
class RuleActionMIME : public RuleAction {
public:
RuleActionMIME(const char* arg_mime, int arg_strength = 0)
{ mime = copy_string(arg_mime); strength = arg_strength; }
virtual ~RuleActionMIME()
{ delete [] mime; }
virtual void DoAction(const Rule* parent, RuleEndpointState* state,
const u_char* data, int len)
{ }
virtual void PrintDebug();
string GetMIME() const
{ return mime; }
int GetStrength() const
{ return strength; }
private:
const char* mime;
int strength;
};
// Base class for enable/disable actions.
class RuleActionAnalyzer : public RuleAction {
public:

View file

@ -186,6 +186,15 @@ RuleEndpointState::~RuleEndpointState()
delete matched_text[j];
}
RuleFileMagicState::~RuleFileMagicState()
{
loop_over_list(matchers, i)
{
delete matchers[i]->state;
delete matchers[i];
}
}
RuleMatcher::RuleMatcher(int arg_RE_level)
{
root = new RuleHdrTest(RuleHdrTest::NOPROT, 0, 0, RuleHdrTest::EQ,
@ -564,6 +573,137 @@ static inline bool compare(const vector<IPPrefix>& prefixes, const IPAddr& a,
return false;
}
RuleFileMagicState* RuleMatcher::InitFileMagic() const
{
RuleFileMagicState* state = new RuleFileMagicState();
if ( rule_bench == 3 )
return state;
loop_over_list(root->psets[Rule::FILE_MAGIC], i)
{
RuleHdrTest::PatternSet* set = root->psets[Rule::FILE_MAGIC][i];
assert(set->re);
RuleFileMagicState::Matcher* m = new RuleFileMagicState::Matcher;
m->state = new RE_Match_State(set->re);
state->matchers.append(m);
}
// Save some memory.
state->matchers.resize(0);
return state;
}
bool RuleMatcher::AllRulePatternsMatched(const Rule* r, MatchPos matchpos,
const AcceptingMatchSet& ams)
{
DBG_LOG(DBG_RULES, "Checking rule: %s", r->id);
// Check whether all patterns of the rule have matched.
loop_over_list(r->patterns, j)
{
if ( ams.find(r->patterns[j]->id) == ams.end() )
return false;
// See if depth is satisfied.
if ( matchpos > r->patterns[j]->offset + r->patterns[j]->depth )
return false;
// FIXME: How to check for offset ??? ###
}
DBG_LOG(DBG_RULES, "All patterns of rule satisfied");
return true;
}
RuleMatcher::MIME_Matches* RuleMatcher::Match(RuleFileMagicState* state,
const u_char* data, uint64 len,
MIME_Matches* rval) const
{
if ( ! rval )
rval = new MIME_Matches();
if ( ! state )
{
reporter->Warning("RuleFileMagicState not initialized yet.");
return rval;
}
if ( rule_bench >= 2 )
return rval;
#ifdef DEBUG
if ( debug_logger.IsEnabled(DBG_RULES) )
{
const char* s = fmt_bytes(reinterpret_cast<const char*>(data),
min(40, static_cast<int>(len)));
DBG_LOG(DBG_RULES, "Matching %s rules on |%s%s|",
Rule::TypeToString(Rule::FILE_MAGIC), s,
len > 40 ? "..." : "");
}
#endif
bool newmatch = false;
loop_over_list(state->matchers, x)
{
RuleFileMagicState::Matcher* m = state->matchers[x];
if ( m->state->Match(data, len, true, false, true) )
newmatch = true;
}
if ( ! newmatch )
return rval;
DBG_LOG(DBG_RULES, "New pattern match found");
AcceptingMatchSet accepted_matches;
loop_over_list(state->matchers, y)
{
RuleFileMagicState::Matcher* m = state->matchers[y];
const AcceptingMatchSet& ams = m->state->AcceptedMatches();
accepted_matches.insert(ams.begin(), ams.end());
}
// Find rules for which patterns have matched.
set<Rule*> rule_matches;
for ( AcceptingMatchSet::const_iterator it = accepted_matches.begin();
it != accepted_matches.end(); ++it )
{
AcceptIdx aidx = it->first;
MatchPos mpos = it->second;
Rule* r = Rule::rule_table[aidx - 1];
if ( AllRulePatternsMatched(r, mpos, accepted_matches) )
rule_matches.insert(r);
}
for ( set<Rule*>::const_iterator it = rule_matches.begin();
it != rule_matches.end(); ++it )
{
Rule* r = *it;
loop_over_list(r->actions, rai)
{
const RuleActionMIME* ram =
dynamic_cast<const RuleActionMIME*>(r->actions[rai]);
if ( ! ram )
continue;
set<string>& ss = (*rval)[ram->GetStrength()];
ss.insert(ram->GetMIME());
}
}
return rval;
}
RuleEndpointState* RuleMatcher::InitEndpoint(analyzer::Analyzer* analyzer,
const IP_Hdr* ip, int caplen,
RuleEndpointState* opposite,
@ -742,66 +882,40 @@ void RuleMatcher::Match(RuleEndpointState* state, Rule::PatternType type,
DBG_LOG(DBG_RULES, "New pattern match found");
// Build a joined AcceptingSet.
AcceptingSet accepted;
int_list matchpos;
AcceptingMatchSet accepted_matches;
loop_over_list(state->matchers, y)
loop_over_list(state->matchers, y )
{
RuleEndpointState::Matcher* m = state->matchers[y];
const AcceptingSet* ac = m->state->Accepted();
loop_over_list(*ac, k)
{
if ( ! accepted.is_member((*ac)[k]) )
{
accepted.append((*ac)[k]);
matchpos.append((*m->state->MatchPositions())[k]);
}
}
const AcceptingMatchSet& ams = m->state->AcceptedMatches();
accepted_matches.insert(ams.begin(), ams.end());
}
// Determine the rules for which all patterns have matched.
// This code should be fast enough as long as there are only very few
// matched patterns per connection (which is a plausible assumption).
rule_list matched;
// Find rules for which patterns have matched.
set<Rule*> rule_matches;
loop_over_list(accepted, i)
for ( AcceptingMatchSet::const_iterator it = accepted_matches.begin();
it != accepted_matches.end(); ++it )
{
Rule* r = Rule::rule_table[accepted[i] - 1];
AcceptIdx aidx = it->first;
MatchPos mpos = it->second;
DBG_LOG(DBG_RULES, "Checking rule: %s", r->id);
Rule* r = Rule::rule_table[aidx - 1];
// Check whether all patterns of the rule have matched.
loop_over_list(r->patterns, j)
{
if ( ! accepted.is_member(r->patterns[j]->id) )
goto next_pattern;
// See if depth is satisfied.
if ( (unsigned int) matchpos[i] >
r->patterns[j]->offset + r->patterns[j]->depth )
goto next_pattern;
DBG_LOG(DBG_RULES, "All patterns of rule satisfied");
// FIXME: How to check for offset ??? ###
}
// If not already in the list of matching rules, add it.
if ( ! matched.is_member(r) )
matched.append(r);
next_pattern:
continue;
if ( AllRulePatternsMatched(r, mpos, accepted_matches) )
rule_matches.insert(r);
}
// Check which of the matching rules really belong to any of our nodes.
loop_over_list(matched, j)
for ( set<Rule*>::const_iterator it = rule_matches.begin();
it != rule_matches.end(); ++it )
{
Rule* r = matched[j];
Rule* r = *it;
DBG_LOG(DBG_RULES, "Accepted rule: %s", r->id);
@ -1010,6 +1124,15 @@ void RuleMatcher::ClearEndpointState(RuleEndpointState* state)
state->matchers[j]->state->Clear();
}
void RuleMatcher::ClearFileMagicState(RuleFileMagicState* state) const
{
if ( rule_bench == 3 )
return;
loop_over_list(state->matchers, j)
state->matchers[j]->state->Clear();
}
void RuleMatcher::PrintDebug()
{
loop_over_list(rules, i)
@ -1163,7 +1286,10 @@ static Val* get_bro_val(const char* label)
return 0;
}
return id->ID_Val();
Val* rval = id->ID_Val();
Unref(id);
return rval;
}

View file

@ -3,6 +3,10 @@
#include <limits.h>
#include <vector>
#include <map>
#include <functional>
#include <set>
#include <string>
#include "IPAddr.h"
#include "BroString.h"
@ -191,6 +195,30 @@ private:
int_list matched_rules; // Rules for which all conditions have matched
};
/**
* A state object used for matching file magic signatures.
*/
class RuleFileMagicState {
friend class RuleMatcher;
public:
~RuleFileMagicState();
private:
// Ctor is private; use RuleMatcher::InitFileMagic() for
// instantiation.
RuleFileMagicState()
{ }
struct Matcher {
RE_Match_State* state;
};
declare(PList, Matcher);
typedef PList(Matcher) matcher_list;
matcher_list matchers;
};
// RuleMatcher is the main class which builds up the data structures
// and performs the actual matching.
@ -205,6 +233,42 @@ public:
// Parse the given files and built up data structures.
bool ReadFiles(const name_list& files);
/**
* Inititialize a state object for matching file magic signatures.
* @return A state object that can be used for file magic mime type
* identification.
*/
RuleFileMagicState* InitFileMagic() const;
/**
* Data structure containing a set of matching file magic signatures.
* Ordered from greatest to least strength. Matches of the same strength
* will be in the set in lexicographic order of the MIME type string.
*/
typedef map<int, set<string>, std::greater<int> > MIME_Matches;
/**
* Matches a chunk of data against file magic signatures.
* @param state A state object previously returned from
* RuleMatcher::InitFileMagic()
* @param data Chunk of data to match signatures against.
* @param len Length of \a data in bytes.
* @param matches An optional pre-existing match result object to
* modify with additional matches. If it's a null
* pointer, one will be instantiated and returned from
* this method.
* @return The results of the signature matching.
*/
MIME_Matches* Match(RuleFileMagicState* state, const u_char* data,
uint64 len, MIME_Matches* matches = 0) const;
/**
* Resets a state object used with matching file magic signatures.
* @param state The state object to reset to an initial condition.
*/
void ClearFileMagicState(RuleFileMagicState* state) const;
// Initialize the matching state for a endpoind of a connection based on
// the given packet (which should be the first packet encountered for
// this endpoint). If the matching is triggered by an PIA, a pointer to
@ -297,6 +361,9 @@ private:
void DumpStateStats(BroFile* f, RuleHdrTest* hdr_test);
static bool AllRulePatternsMatched(const Rule* r, MatchPos matchpos,
const AcceptingMatchSet& ams);
int RE_level;
bool parse_error;
RuleHdrTest* root;

View file

@ -62,6 +62,7 @@ protected:
extern bool in_debug;
// If no_global is true, don't search in the default "global" namespace.
// This passed ownership of a ref'ed ID to the caller.
extern ID* lookup_ID(const char* name, const char* module,
bool no_global = false, bool same_module_only=false);
extern ID* install_ID(const char* name, const char* module_name,

View file

@ -111,6 +111,7 @@ SERIAL_VAL(ENTROPY_VAL, 19)
SERIAL_VAL(TOPK_VAL, 20)
SERIAL_VAL(BLOOMFILTER_VAL, 21)
SERIAL_VAL(CARDINALITY_VAL, 22)
SERIAL_VAL(X509_VAL, 23)
#define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR)
SERIAL_EXPR(EXPR, 1)

View file

@ -5,6 +5,8 @@
#include "Serializer.h"
#include "Reporter.h"
const float SerializationFormat::GROWTH_FACTOR = 2.5;
SerializationFormat::SerializationFormat()
: output(), output_size(), output_pos(), input(), input_len(), input_pos(),
bytes_written(), bytes_read()
@ -13,7 +15,7 @@ SerializationFormat::SerializationFormat()
SerializationFormat::~SerializationFormat()
{
delete [] output;
free(output);
}
void SerializationFormat::StartRead(char* data, uint32 arg_len)
@ -33,13 +35,13 @@ void SerializationFormat::StartWrite()
{
if ( output && output_size > INITIAL_SIZE )
{
delete [] output;
free(output);
output = 0;
}
if ( ! output )
{
output = new char[INITIAL_SIZE];
output = (char*)safe_malloc(INITIAL_SIZE);
output_size = INITIAL_SIZE;
}
@ -49,9 +51,12 @@ void SerializationFormat::StartWrite()
uint32 SerializationFormat::EndWrite(char** data)
{
*data = new char[output_pos];
memcpy(*data, output, output_pos);
return output_pos;
uint32 rval = output_pos;
*data = output;
output = 0;
output_size = 0;
output_pos = 0;
return rval;
}
bool SerializationFormat::ReadData(void* b, size_t count)
@ -75,11 +80,8 @@ bool SerializationFormat::WriteData(const void* b, size_t count)
// Increase buffer if necessary.
while ( output_pos + count > output_size )
{
output_size = output_pos + count + INITIAL_SIZE;
char* tmp = new char[output_size];
memcpy(tmp, output, output_pos);
delete [] output;
output = tmp;
output_size *= GROWTH_FACTOR;
output = (char*)safe_realloc(output, output_size);
}
memcpy(output + output_pos, b, count);

View file

@ -44,7 +44,15 @@ public:
// Serialization.
virtual void StartWrite();
virtual uint32 EndWrite(char** data); // passes ownership
/**
* Retrieves serialized data.
* @param data A pointer that will be assigned to point at the internal
* buffer containing serialized data. The memory should
* be reclaimed using "free()".
* @return The number of bytes in the buffer object assigned to \a data.
*/
virtual uint32 EndWrite(char** data);
virtual bool Write(int v, const char* tag) = 0;
virtual bool Write(uint16 v, const char* tag) = 0;
@ -74,6 +82,7 @@ protected:
bool WriteData(const void* buf, size_t count);
static const uint32 INITIAL_SIZE = 65536;
static const float GROWTH_FACTOR;
char* output;
uint32 output_size;
uint32 output_pos;

View file

@ -81,6 +81,7 @@ bool Serializer::EndSerialization(SerialInfo* info)
ChunkedIO::Chunk* chunk = new ChunkedIO::Chunk;
chunk->len = format->EndWrite(&chunk->data);
chunk->free_func = ChunkedIO::Chunk::free_func_free;
if ( ! io->Write(chunk) )
{
@ -282,7 +283,6 @@ int Serializer::Unserialize(UnserialInfo* info, bool block)
if ( ! info->chunk )
{ // only delete if we allocated it ourselves
delete [] chunk->data;
delete chunk;
}

View file

@ -125,7 +125,7 @@ protected:
// This will be increased whenever there is an incompatible change
// in the data format.
static const uint32 DATA_FORMAT_VERSION = 24;
static const uint32 DATA_FORMAT_VERSION = 25;
ChunkedIO* io;

View file

@ -30,7 +30,6 @@
#include "Discard.h"
#include "RuleMatcher.h"
#include "PacketSort.h"
#include "TunnelEncapsulation.h"
#include "analyzer/Manager.h"
@ -168,7 +167,7 @@ void NetSessions::Done()
void NetSessions::DispatchPacket(double t, const struct pcap_pkthdr* hdr,
const u_char* pkt, int hdr_size,
PktSrc* src_ps, PacketSortElement* pkt_elem)
PktSrc* src_ps)
{
const struct ip* ip_hdr = 0;
const u_char* ip_data = 0;
@ -186,14 +185,13 @@ void NetSessions::DispatchPacket(double t, const struct pcap_pkthdr* hdr,
hdr_size += encap_hdr_size;
if ( src_ps->FilterType() == TYPE_FILTER_NORMAL )
NextPacket(t, hdr, pkt, hdr_size, pkt_elem);
NextPacket(t, hdr, pkt, hdr_size);
else
NextPacketSecondary(t, hdr, pkt, hdr_size, src_ps);
}
void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
const u_char* const pkt, int hdr_size,
PacketSortElement* pkt_elem)
const u_char* const pkt, int hdr_size)
{
SegmentProfiler(segment_logger, "processing-packet");
if ( pkt_profiler )
@ -206,70 +204,58 @@ void NetSessions::NextPacket(double t, const struct pcap_pkthdr* hdr,
if ( record_all_packets )
DumpPacket(hdr, pkt);
if ( pkt_elem && pkt_elem->IPHdr() )
// Fast path for "normal" IP packets if an IP_Hdr is
// already extracted when doing PacketSort. Otherwise
// the code below tries to extract the IP header, the
// difference here is that header extraction in
// PacketSort does not generate Weird events.
// ### The following isn't really correct. What we *should*
// do is understanding the different link layers in order to
// find the network-layer protocol ID. That's a big
// portability pain, though, unless we just assume everything's
// Ethernet .... not great, given the potential need to deal
// with PPP or FDDI (for some older traces). So instead
// we look to see if what we have is consistent with an
// IPv4 packet. If not, it's either ARP or IPv6 or weird.
DoNextPacket(t, hdr, pkt_elem->IPHdr(), pkt, hdr_size, 0);
else
if ( hdr_size > static_cast<int>(hdr->caplen) )
{
// ### The following isn't really correct. What we *should*
// do is understanding the different link layers in order to
// find the network-layer protocol ID. That's a big
// portability pain, though, unless we just assume everything's
// Ethernet .... not great, given the potential need to deal
// with PPP or FDDI (for some older traces). So instead
// we look to see if what we have is consistent with an
// IPv4 packet. If not, it's either ARP or IPv6 or weird.
Weird("truncated_link_frame", hdr, pkt);
return;
}
if ( hdr_size > static_cast<int>(hdr->caplen) )
{
Weird("truncated_link_frame", hdr, pkt);
return;
}
uint32 caplen = hdr->caplen - hdr_size;
if ( caplen < sizeof(struct ip) )
{
Weird("truncated_IP", hdr, pkt);
return;
}
uint32 caplen = hdr->caplen - hdr_size;
if ( caplen < sizeof(struct ip) )
const struct ip* ip = (const struct ip*) (pkt + hdr_size);
if ( ip->ip_v == 4 )
{
IP_Hdr ip_hdr(ip, false);
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0);
}
else if ( ip->ip_v == 6 )
{
if ( caplen < sizeof(struct ip6_hdr) )
{
Weird("truncated_IP", hdr, pkt);
return;
}
const struct ip* ip = (const struct ip*) (pkt + hdr_size);
IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size), false, caplen);
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0);
}
if ( ip->ip_v == 4 )
{
IP_Hdr ip_hdr(ip, false);
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0);
}
else if ( analyzer::arp::ARP_Analyzer::IsARP(pkt, hdr_size) )
{
if ( arp_analyzer )
arp_analyzer->NextPacket(t, hdr, pkt, hdr_size);
}
else if ( ip->ip_v == 6 )
{
if ( caplen < sizeof(struct ip6_hdr) )
{
Weird("truncated_IP", hdr, pkt);
return;
}
IP_Hdr ip_hdr((const struct ip6_hdr*) (pkt + hdr_size), false, caplen);
DoNextPacket(t, hdr, &ip_hdr, pkt, hdr_size, 0);
}
else if ( analyzer::arp::ARP_Analyzer::IsARP(pkt, hdr_size) )
{
if ( arp_analyzer )
arp_analyzer->NextPacket(t, hdr, pkt, hdr_size);
}
else
{
Weird("unknown_packet_type", hdr, pkt);
return;
}
else
{
Weird("unknown_packet_type", hdr, pkt);
return;
}
if ( dump_this_packet && ! record_all_packets )
@ -376,6 +362,31 @@ int NetSessions::CheckConnectionTag(Connection* conn)
return 1;
}
static unsigned int gre_header_len(uint16 flags)
{
unsigned int len = 4; // Always has 2 byte flags and 2 byte protocol type.
if ( flags & 0x8000 )
// Checksum/Reserved1 present.
len += 4;
// Not considering routing presence bit since it's deprecated ...
if ( flags & 0x2000 )
// Key present.
len += 4;
if ( flags & 0x1000 )
// Sequence present.
len += 4;
if ( flags & 0x0080 )
// Acknowledgement present.
len += 4;
return len;
}
void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const IP_Hdr* ip_hdr, const u_char* const pkt,
int hdr_size, const EncapsulationStack* encapsulation)
@ -384,6 +395,15 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
const struct ip* ip4 = ip_hdr->IP4_Hdr();
uint32 len = ip_hdr->TotalLen();
if ( len == 0 )
{
// TCP segmentation offloading can zero out the ip_len field.
Weird("ip_hdr_len_zero", hdr, pkt, encapsulation);
// Cope with the zero'd out ip_len field by using the caplen.
len = hdr->caplen - hdr_size;
}
if ( hdr->len < len + hdr_size )
{
Weird("truncated_IP", hdr, pkt, encapsulation);
@ -437,6 +457,8 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
}
}
FragReassemblerTracker frt(this, f);
len -= ip_hdr_len; // remove IP header
caplen -= ip_hdr_len;
@ -451,7 +473,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
vl->append(ip_hdr->BuildPktHdrVal());
mgr.QueueEvent(esp_packet, vl);
}
Remove(f);
// Can't do more since upper-layer payloads are going to be encrypted.
return;
}
@ -466,7 +488,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( ! ignore_checksums && mobility_header_checksum(ip_hdr) != 0xffff )
{
Weird("bad_MH_checksum", hdr, pkt, encapsulation);
Remove(f);
return;
}
@ -480,7 +501,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( ip_hdr->NextProto() != IPPROTO_NONE )
Weird("mobility_piggyback", hdr, pkt, encapsulation);
Remove(f);
return;
}
#endif
@ -488,10 +508,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
int proto = ip_hdr->NextProto();
if ( CheckHeaderTrunc(proto, len, caplen, hdr, pkt, encapsulation) )
{
Remove(f);
return;
}
const u_char* data = ip_hdr->Payload();
@ -553,13 +570,100 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
break;
}
case IPPROTO_GRE:
{
if ( ! BifConst::Tunnel::enable_gre )
{
Weird("GRE_tunnel", ip_hdr, encapsulation);
return;
}
uint16 flags_ver = ntohs(*((uint16*)(data + 0)));
uint16 proto_typ = ntohs(*((uint16*)(data + 2)));
int gre_version = flags_ver & 0x0007;
if ( gre_version != 0 && gre_version != 1 )
{
Weird(fmt("unknown_gre_version_%d", gre_version), ip_hdr,
encapsulation);
return;
}
if ( gre_version == 0 )
{
if ( proto_typ != 0x0800 && proto_typ != 0x86dd )
{
// Not IPv4/IPv6 payload.
Weird(fmt("unknown_gre_protocol_%"PRIu16, proto_typ), ip_hdr,
encapsulation);
return;
}
proto = (proto_typ == 0x0800) ? IPPROTO_IPV4 : IPPROTO_IPV6;
}
else // gre_version == 1
{
if ( proto_typ != 0x880b )
{
// Enhanced GRE payload must be PPP.
Weird("egre_protocol_type", ip_hdr, encapsulation);
return;
}
}
if ( flags_ver & 0x4000 )
{
// RFC 2784 deprecates the variable length routing field
// specified by RFC 1701. It could be parsed here, but easiest
// to just skip for now.
Weird("gre_routing", ip_hdr, encapsulation);
return;
}
if ( flags_ver & 0x0078 )
{
// Expect last 4 bits of flags are reserved, undefined.
Weird("unknown_gre_flags", ip_hdr, encapsulation);
return;
}
unsigned int gre_len = gre_header_len(flags_ver);
unsigned int ppp_len = gre_version == 1 ? 1 : 0;
if ( len < gre_len + ppp_len || caplen < gre_len + ppp_len )
{
Weird("truncated_GRE", ip_hdr, encapsulation);
return;
}
if ( gre_version == 1 )
{
int ppp_proto = *((uint8*)(data + gre_len));
if ( ppp_proto != 0x0021 && ppp_proto != 0x0057 )
{
Weird("non_ip_packet_in_egre", ip_hdr, encapsulation);
return;
}
proto = (ppp_proto == 0x0021) ? IPPROTO_IPV4 : IPPROTO_IPV6;
}
data += gre_len + ppp_len;
len -= gre_len + ppp_len;
caplen -= gre_len + ppp_len;
// Treat GRE tunnel like IP tunnels, fallthrough to logic below now
// that GRE header is stripped and only payload packet remains.
}
case IPPROTO_IPV4:
case IPPROTO_IPV6:
{
if ( ! BifConst::Tunnel::enable_ip )
{
Weird("IP_tunnel", ip_hdr, encapsulation);
Remove(f);
return;
}
@ -567,7 +671,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
encapsulation->Depth() >= BifConst::Tunnel::max_depth )
{
Weird("exceeded_tunnel_max_depth", ip_hdr, encapsulation);
Remove(f);
return;
}
@ -584,7 +687,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( result != 0 )
{
delete inner;
Remove(f);
return;
}
@ -611,7 +713,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
DoNextInnerPacket(t, hdr, inner, encapsulation,
ip_tunnels[tunnel_idx].first);
Remove(f);
return;
}
@ -624,13 +725,11 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
encapsulation->LastType() == BifEnum::Tunnel::TEREDO ) )
Weird("ipv6_no_next", hdr, pkt);
Remove(f);
return;
}
default:
Weird(fmt("unknown_protocol_%d", proto), hdr, pkt, encapsulation);
Remove(f);
return;
}
@ -656,7 +755,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( consistent < 0 )
{
delete h;
Remove(f);
return;
}
@ -680,7 +778,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
if ( ! conn )
{
delete h;
Remove(f);
return;
}
@ -712,7 +809,6 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr,
{
// Above we already recorded the fragment in its entirety.
f->DeleteTimer();
Remove(f);
}
else if ( record_packet )
@ -813,6 +909,9 @@ bool NetSessions::CheckHeaderTrunc(int proto, uint32 len, uint32 caplen,
case IPPROTO_NONE:
min_hdr_len = 0;
break;
case IPPROTO_GRE:
min_hdr_len = 4;
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
default:

View file

@ -28,7 +28,6 @@ declare(PDict,FragReassembler);
class Discarder;
class PacketFilter;
class PacketSortElement;
namespace analyzer { namespace stepping_stone { class SteppingStoneManager; } }
namespace analyzer { namespace arp { class ARP_Analyzer; } }
@ -74,7 +73,7 @@ public:
// employing the packet sorter first.
void DispatchPacket(double t, const struct pcap_pkthdr* hdr,
const u_char* const pkt, int hdr_size,
PktSrc* src_ps, PacketSortElement* pkt_elem);
PktSrc* src_ps);
void Done(); // call to drain events before destructing
@ -220,8 +219,7 @@ protected:
uint8 tcp_flags, bool& flip_roles);
void NextPacket(double t, const struct pcap_pkthdr* hdr,
const u_char* const pkt, int hdr_size,
PacketSortElement* pkt_elem);
const u_char* const pkt, int hdr_size);
void NextPacketSecondary(double t, const struct pcap_pkthdr* hdr,
const u_char* const pkt, int hdr_size,
@ -286,6 +284,21 @@ protected:
NetSessions::IPPair tunnel_idx;
};
class FragReassemblerTracker {
public:
FragReassemblerTracker(NetSessions* s, FragReassembler* f)
: net_sessions(s), frag_reassembler(f)
{ }
~FragReassemblerTracker()
{ net_sessions->Remove(frag_reassembler); }
private:
NetSessions* net_sessions;
FragReassembler* frag_reassembler;
};
// Manager for the currently active sessions.
extern NetSessions* sessions;

View file

@ -160,7 +160,7 @@ void ProfileLogger::Log()
file->Write(fmt("%.06f Connections expired due to inactivity: %d\n",
network_time, killed_by_inactivity));
file->Write(fmt("%.06f Total reassembler data: %dK\n", network_time,
file->Write(fmt("%.06f Total reassembler data: %"PRIu64"K\n", network_time,
Reassembler::TotalMemoryAllocation() / 1024));
// Signature engine.

View file

@ -131,7 +131,7 @@ BroType* BroType::Clone() const
sinfo.cache = false;
this->Serialize(&sinfo);
char* data = 0;
char* data;
uint32 len = form->EndWrite(&data);
form->StartRead(data, len);
@ -141,7 +141,7 @@ BroType* BroType::Clone() const
BroType* rval = this->Unserialize(&uinfo, false);
assert(rval != this);
delete [] data;
free(data);
return rval;
}
@ -1449,6 +1449,7 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name,
}
else
{
Unref(id);
reporter->Error("identifier or enumerator value in enumerated type definition already exists");
SetError();
return;
@ -1626,6 +1627,23 @@ VectorType::~VectorType()
Unref(yield_type);
}
BroType* VectorType::YieldType()
{
// Work around the fact that we use void internally to mark a vector
// as being unspecified. When looking at its yield type, we need to
// return any as that's what other code historically expects for type
// comparisions.
if ( IsUnspecifiedVector() )
{
BroType* ret = ::base_type(TYPE_ANY);
Unref(ret); // unref, because this won't be held by anyone.
assert(ret);
return ret;
}
return yield_type;
}
int VectorType::MatchesIndex(ListExpr*& index) const
{
expr_list& el = index->Exprs();
@ -1645,7 +1663,7 @@ int VectorType::MatchesIndex(ListExpr*& index) const
bool VectorType::IsUnspecifiedVector() const
{
return yield_type->Tag() == TYPE_ANY;
return yield_type->Tag() == TYPE_VOID;
}
IMPLEMENT_SERIAL(VectorType, SER_VECTOR_TYPE);

View file

@ -73,6 +73,7 @@ class EnumType;
class Serializer;
class VectorType;
class TypeType;
class OpaqueType;
const int DOES_NOT_MATCH_INDEX = 0;
const int MATCHES_INDEX_SCALAR = 1;
@ -204,6 +205,18 @@ public:
return (VectorType*) this;
}
OpaqueType* AsOpaqueType()
{
CHECK_TYPE_TAG(TYPE_OPAQUE, "BroType::AsOpaqueType");
return (OpaqueType*) this;
}
const OpaqueType* AsOpaqueType() const
{
CHECK_TYPE_TAG(TYPE_OPAQUE, "BroType::AsOpaqueType");
return (OpaqueType*) this;
}
VectorType* AsVectorType()
{
CHECK_TYPE_TAG(TYPE_VECTOR, "BroType::AsVectorType");
@ -572,7 +585,7 @@ class VectorType : public BroType {
public:
VectorType(BroType* t);
virtual ~VectorType();
BroType* YieldType() { return yield_type; }
BroType* YieldType();
int MatchesIndex(ListExpr*& index) const;
@ -597,6 +610,7 @@ extern OpaqueType* entropy_type;
extern OpaqueType* cardinality_type;
extern OpaqueType* topk_type;
extern OpaqueType* bloomfilter_type;
extern OpaqueType* x509_opaque_type;
// Returns the BRO basic (non-parameterized) type with the given type.
extern BroType* base_type(TypeTag tag);

View file

@ -32,7 +32,6 @@ Val::Val(Func* f)
val.func_val = f;
::Ref(val.func_val);
type = f->FType()->Ref();
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -49,7 +48,6 @@ Val::Val(BroFile* f)
assert(f->FType()->Tag() == TYPE_STRING);
type = string_file_type->Ref();
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -80,6 +78,7 @@ Val* Val::Clone() const
CloneSerializer ss(form);
SerialInfo sinfo(&ss);
sinfo.cache = false;
sinfo.include_locations = false;
if ( ! this->Serialize(&sinfo) )
return 0;
@ -92,8 +91,7 @@ Val* Val::Clone() const
uinfo.cache = false;
Val* clone = Unserialize(&uinfo, type);
delete [] data;
free(data);
return clone;
}
@ -190,8 +188,6 @@ bool Val::DoSerialize(SerialInfo* info) const
if ( ! type->Serialize(info) )
return false;
SERIALIZE_OPTIONAL(attribs);
switch ( type->InternalType() ) {
case TYPE_INTERNAL_VOID:
info->s->Error("type is void");
@ -251,9 +247,6 @@ bool Val::DoUnserialize(UnserialInfo* info)
if ( ! (type = BroType::Unserialize(info)) )
return false;
UNSERIALIZE_OPTIONAL(attribs,
(RecordVal*) Val::Unserialize(info, TYPE_RECORD));
switch ( type->InternalType() ) {
case TYPE_INTERNAL_VOID:
info->s->Error("type is void");
@ -1171,23 +1164,6 @@ ListVal::~ListVal()
Unref(type);
}
const char* ListVal::IncludedInString(const char* str) const
{
if ( tag != TYPE_STRING )
Internal("non-string list in ListVal::IncludedInString");
loop_over_list(vals, i)
{
const char* vs = (const char*) (vals[i]->AsString()->Bytes());
const char* embedded = strstr(str, vs);
if ( embedded )
return embedded;
}
return 0;
}
RE_Matcher* ListVal::BuildRE() const
{
if ( tag != TYPE_STRING )
@ -3139,7 +3115,7 @@ bool VectorVal::DoUnserialize(UnserialInfo* info)
for ( int i = 0; i < len; ++i )
{
Val* v;
UNSERIALIZE_OPTIONAL(v, Val::Unserialize(info, TYPE_ANY));
UNSERIALIZE_OPTIONAL(v, Val::Unserialize(info, TYPE_ANY)); // accept any type
Assign(i, v);
}

View file

@ -80,7 +80,6 @@ public:
{
val.int_val = b;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -90,7 +89,6 @@ public:
{
val.int_val = bro_int_t(i);
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -100,7 +98,6 @@ public:
{
val.uint_val = bro_uint_t(u);
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -110,7 +107,6 @@ public:
{
val.int_val = i;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -120,7 +116,6 @@ public:
{
val.uint_val = u;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -130,7 +125,6 @@ public:
{
val.double_val = d;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -145,7 +139,6 @@ public:
Val(BroType* t, bool type_type) // Extra arg to differentiate from protected version.
{
type = new TypeType(t->Ref());
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -155,7 +148,6 @@ public:
{
val.int_val = 0;
type = base_type(TYPE_ERROR);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -364,7 +356,6 @@ protected:
{
val.string_val = s;
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -376,7 +367,6 @@ protected:
Val(TypeTag t)
{
type = base_type(t);
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -385,7 +375,6 @@ protected:
Val(BroType* t)
{
type = t->Ref();
attribs = 0;
#ifdef DEBUG
bound_id = 0;
#endif
@ -400,7 +389,6 @@ protected:
BroValUnion val;
BroType* type;
RecordVal* attribs;
#ifdef DEBUG
// For debugging, we keep the name of the ID to which a Val is bound.
@ -656,6 +644,8 @@ protected:
DECLARE_SERIAL(PatternVal);
};
// ListVals are mainly used to index tables that have more than one
// element in their index.
class ListVal : public Val {
public:
ListVal(TypeTag t);
@ -669,13 +659,6 @@ public:
Val* Index(const int n) { return vals[n]; }
const Val* Index(const int n) const { return vals[n]; }
// Returns offset of where str includes one of the strings in this
// ListVal (which had better be a list of strings), nil if none.
//
// Assumes that all of the strings in the list are NUL-terminated
// and do not have any embedded NULs.
const char* IncludedInString(const char* str) const;
// Returns an RE_Matcher() that will match any string that
// includes embedded within it one of the patterns listed
// (as a string, e.g., "foo|bar") in this ListVal.
@ -949,7 +932,6 @@ public:
{
val.int_val = i;
type = t;
attribs = 0;
}
Val* SizeVal() const { return new Val(val.int_val, TYPE_INT); }

View file

@ -169,8 +169,14 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
{
Val* aggr;
if ( t->Tag() == TYPE_RECORD )
{
aggr = new RecordVal(t->AsRecordType());
if ( init && t )
// Have an initialization and type is not deduced.
init = new RecordCoerceExpr(init, t->AsRecordType());
}
else if ( t->Tag() == TYPE_TABLE )
aggr = new TableVal(t->AsTableType(), id->Attrs());
@ -379,6 +385,8 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
if ( arg_id && ! arg_id->IsGlobal() )
arg_id->Error("argument name used twice");
Unref(arg_id);
arg_id = install_ID(arg_i->id, module_name, false, false);
arg_id->SetType(arg_i->type->Ref());
}
@ -436,10 +444,13 @@ void end_func(Stmt* body, attr_list* attrs)
Val* internal_val(const char* name)
{
ID* id = lookup_ID(name, GLOBAL_MODULE_NAME);
if ( ! id )
reporter->InternalError("internal variable %s missing", name);
return id->ID_Val();
Val* rval = id->ID_Val();
Unref(id);
return rval;
}
Val* internal_const_val(const char* name)
@ -451,13 +462,17 @@ Val* internal_const_val(const char* name)
if ( ! id->IsConst() )
reporter->InternalError("internal variable %s is not constant", name);
return id->ID_Val();
Val* rval = id->ID_Val();
Unref(id);
return rval;
}
Val* opt_internal_val(const char* name)
{
ID* id = lookup_ID(name, GLOBAL_MODULE_NAME);
return id ? id->ID_Val() : 0;
Val* rval = id ? id->ID_Val() : 0;
Unref(id);
return rval;
}
double opt_internal_double(const char* name)
@ -497,6 +512,8 @@ ListVal* internal_list_val(const char* name)
return 0;
Val* v = id->ID_Val();
Unref(id);
if ( v )
{
if ( v->Type()->Tag() == TYPE_LIST )
@ -522,7 +539,9 @@ BroType* internal_type(const char* name)
if ( ! id )
reporter->InternalError("internal type %s missing", name);
return id->Type();
BroType* rval = id->Type();
Unref(id);
return rval;
}
Func* internal_func(const char* name)

View file

@ -203,17 +203,17 @@ void Analyzer::Done()
finished = true;
}
void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, int seq,
void Analyzer::NextPacket(int len, const u_char* data, bool is_orig, uint64 seq,
const IP_Hdr* ip, int caplen)
{
if ( skip )
return;
// If we have support analyzers, we pass it to them.
if ( is_orig && orig_supporters )
orig_supporters->NextPacket(len, data, is_orig, seq, ip, caplen);
else if ( ! is_orig && resp_supporters )
resp_supporters->NextPacket(len, data, is_orig, seq, ip, caplen);
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( next_sibling )
next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
else
{
try
@ -232,11 +232,11 @@ void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
if ( skip )
return;
// If we have support analyzers, we pass it to them.
if ( is_orig && orig_supporters )
orig_supporters->NextStream(len, data, is_orig);
else if ( ! is_orig && resp_supporters )
resp_supporters->NextStream(len, data, is_orig);
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( next_sibling )
next_sibling->NextStream(len, data, is_orig);
else
{
try
@ -250,16 +250,16 @@ void Analyzer::NextStream(int len, const u_char* data, bool is_orig)
}
}
void Analyzer::NextUndelivered(int seq, int len, bool is_orig)
void Analyzer::NextUndelivered(uint64 seq, int len, bool is_orig)
{
if ( skip )
return;
// If we have support analyzers, we pass it to them.
if ( is_orig && orig_supporters )
orig_supporters->NextUndelivered(seq, len, is_orig);
else if ( ! is_orig && resp_supporters )
resp_supporters->NextUndelivered(seq, len, is_orig);
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( next_sibling )
next_sibling->NextUndelivered(seq, len, is_orig);
else
{
try
@ -278,17 +278,16 @@ void Analyzer::NextEndOfData(bool is_orig)
if ( skip )
return;
// If we have support analyzers, we pass it to them.
if ( is_orig && orig_supporters )
orig_supporters->NextEndOfData(is_orig);
else if ( ! is_orig && resp_supporters )
resp_supporters->NextEndOfData(is_orig);
SupportAnalyzer* next_sibling = FirstSupportAnalyzer(is_orig);
if ( next_sibling )
next_sibling->NextEndOfData(is_orig);
else
EndOfData(is_orig);
}
void Analyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
uint64 seq, const IP_Hdr* ip, int caplen)
{
if ( output_handler )
output_handler->DeliverPacket(len, data, is_orig, seq,
@ -336,7 +335,7 @@ void Analyzer::ForwardStream(int len, const u_char* data, bool is_orig)
AppendNewChildren();
}
void Analyzer::ForwardUndelivered(int seq, int len, bool is_orig)
void Analyzer::ForwardUndelivered(uint64 seq, int len, bool is_orig)
{
if ( output_handler )
output_handler->Undelivered(seq, len, is_orig);
@ -558,31 +557,17 @@ void Analyzer::AddSupportAnalyzer(SupportAnalyzer* analyzer)
void Analyzer::RemoveSupportAnalyzer(SupportAnalyzer* analyzer)
{
SupportAnalyzer** head =
analyzer->IsOrig() ? &orig_supporters : &resp_supporters;
SupportAnalyzer* prev = 0;
SupportAnalyzer* s;
for ( s = *head; s && s != analyzer; prev = s, s = s->sibling )
;
if ( ! s )
return;
if ( prev )
prev->sibling = s->sibling;
else
*head = s->sibling;
DBG_LOG(DBG_ANALYZER, "%s removed support %s",
DBG_LOG(DBG_ANALYZER, "%s disabled %s support analyzer %s",
fmt_analyzer(this).c_str(),
analyzer->IsOrig() ? "originator" : "responder",
fmt_analyzer(analyzer).c_str());
if ( ! analyzer->finished )
analyzer->Done();
delete analyzer;
// We mark the analyzer as being removed here, which will prevent it
// from being used further. However, we don't actually delete it
// before the parent gets destroyed. While we woulc do that, it's a
// bit tricky to do at the right time and it doesn't seem worth the
// trouble.
analyzer->removing = true;
return;
}
@ -596,10 +581,23 @@ bool Analyzer::HasSupportAnalyzer(Tag tag, bool orig)
return false;
}
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
SupportAnalyzer* Analyzer::FirstSupportAnalyzer(bool orig)
{
DBG_LOG(DBG_ANALYZER, "%s DeliverPacket(%d, %s, %d, %p, %d) [%s%s]",
SupportAnalyzer* sa = orig ? orig_supporters : resp_supporters;
if ( ! sa )
return 0;
if ( ! sa->Removing() )
return sa;
return sa->Sibling(true);
}
void Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
uint64 seq, const IP_Hdr* ip, int caplen)
{
DBG_LOG(DBG_ANALYZER, "%s DeliverPacket(%d, %s, %"PRIu64", %p, %d) [%s%s]",
fmt_analyzer(this).c_str(), len, is_orig ? "T" : "F", seq, ip, caplen,
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
}
@ -611,9 +609,9 @@ void Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
fmt_bytes((const char*) data, min(40, len)), len > 40 ? "..." : "");
}
void Analyzer::Undelivered(int seq, int len, bool is_orig)
void Analyzer::Undelivered(uint64 seq, int len, bool is_orig)
{
DBG_LOG(DBG_ANALYZER, "%s Undelivered(%d, %d, %s)",
DBG_LOG(DBG_ANALYZER, "%s Undelivered(%"PRIu64", %d, %s)",
fmt_analyzer(this).c_str(), seq, len, is_orig ? "T" : "F");
}
@ -782,16 +780,35 @@ void Analyzer::Weird(const char* name, const char* addl)
conn->Weird(name, addl);
}
SupportAnalyzer* SupportAnalyzer::Sibling(bool only_active) const
{
if ( ! only_active )
return sibling;
SupportAnalyzer* next = sibling;
while ( next && next->Removing() )
next = next->sibling;
return next;
}
void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
uint64 seq, const IP_Hdr* ip, int caplen)
{
// We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() )
{
GetOutputHandler()->DeliverPacket(len, data, is_orig, seq,
ip, caplen);
else if ( sibling )
return;
}
SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain.
sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
next_sibling->NextPacket(len, data, is_orig, seq, ip, caplen);
else
// Finished with preprocessing - now it's the parent's turn.
Parent()->DeliverPacket(len, data, is_orig, seq, ip, caplen);
@ -800,26 +817,38 @@ void SupportAnalyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
void SupportAnalyzer::ForwardStream(int len, const u_char* data, bool is_orig)
{
// We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() )
GetOutputHandler()->DeliverStream(len, data, is_orig);
else if ( sibling )
if ( GetOutputHandler() )
{
GetOutputHandler()->DeliverStream(len, data, is_orig);
return;
}
SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain.
sibling->NextStream(len, data, is_orig);
next_sibling->NextStream(len, data, is_orig);
else
// Finished with preprocessing - now it's the parent's turn.
Parent()->DeliverStream(len, data, is_orig);
}
void SupportAnalyzer::ForwardUndelivered(int seq, int len, bool is_orig)
void SupportAnalyzer::ForwardUndelivered(uint64 seq, int len, bool is_orig)
{
// We do not call parent's method, as we're replacing the functionality.
if ( GetOutputHandler() )
GetOutputHandler()->Undelivered(seq, len, is_orig);
else if ( sibling )
if ( GetOutputHandler() )
{
GetOutputHandler()->Undelivered(seq, len, is_orig);
return;
}
SupportAnalyzer* next_sibling = Sibling(true);
if ( next_sibling )
// Pass to next in chain.
sibling->NextUndelivered(seq, len, is_orig);
next_sibling->NextUndelivered(seq, len, is_orig);
else
// Finished with preprocessing - now it's the parent's turn.
Parent()->Undelivered(seq, len, is_orig);

View file

@ -44,7 +44,7 @@ public:
* Analyzer::DeliverPacket().
*/
virtual void DeliverPacket(int len, const u_char* data,
bool orig, int seq,
bool orig, uint64 seq,
const IP_Hdr* ip, int caplen)
{ }
@ -59,7 +59,7 @@ public:
* Hook for receiving notification of stream gaps. Parameters are the
* same as for Analyzer::Undelivered().
*/
virtual void Undelivered(int seq, int len, bool orig) { }
virtual void Undelivered(uint64 seq, int len, bool orig) { }
};
/**
@ -143,7 +143,7 @@ public:
* @param caplen The packet's capture length, if available.
*/
void NextPacket(int len, const u_char* data, bool is_orig,
int seq = -1, const IP_Hdr* ip = 0, int caplen = 0);
uint64 seq = -1, const IP_Hdr* ip = 0, int caplen = 0);
/**
* Passes stream input to the analyzer for processing. The analyzer
@ -173,7 +173,7 @@ public:
*
* @param is_orig True if this is about originator-side input.
*/
void NextUndelivered(int seq, int len, bool is_orig);
void NextUndelivered(uint64 seq, int len, bool is_orig);
/**
* Reports a message boundary. This is a generic method that can be
@ -195,7 +195,7 @@ public:
* Parameters are the same as for NextPacket().
*/
virtual void ForwardPacket(int len, const u_char* data,
bool orig, int seq,
bool orig, uint64 seq,
const IP_Hdr* ip, int caplen);
/**
@ -212,7 +212,7 @@ public:
*
* Parameters are the same as for NextUndelivered().
*/
virtual void ForwardUndelivered(int seq, int len, bool orig);
virtual void ForwardUndelivered(uint64 seq, int len, bool orig);
/**
* Forwards an end-of-data notification on to all child analyzers.
@ -227,7 +227,7 @@ public:
* Parameters are the same.
*/
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
/**
* Hook for accessing stream input for parsing. This is called by
@ -241,7 +241,7 @@ public:
* NextUndelivered() and can be overridden by derived classes.
* Parameters are the same.
*/
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
/**
* Hook for accessing end-of-data notifications. This is called by
@ -587,7 +587,7 @@ protected:
void RemoveTimer(Timer* t);
/**
* Returnsn true if the analyzer has associated an SupportAnalyzer of a given type.
* Returns true if the analyzer has associated an SupportAnalyzer of a given type.
*
* @param tag The type to check for.
*
@ -595,6 +595,14 @@ protected:
*/
bool HasSupportAnalyzer(Tag tag, bool orig);
/**
* Returns the first still active support analyzer for the given
* direction, or null if none.
*
* @param orig True if asking about the originator side.
*/
SupportAnalyzer* FirstSupportAnalyzer(bool orig);
/**
* Adds a a new child analyzer with the option whether to intialize
* it. This is an internal method.
@ -616,6 +624,12 @@ protected:
*/
void AppendNewChildren();
/**
* Returns true if the analyzer has been flagged for removal and
* shouldn't be used otherwise anymore.
*/
bool Removing() const { return removing; }
private:
// Internal method to eventually delete a child analyzer that's
// already Done().
@ -718,6 +732,14 @@ public:
*/
bool IsOrig() const { return orig; }
/**
* Returns the analyzer's next sibling, or null if none.
*
* only_active: If true, this will skip siblings that are still link
* but flagged for removal.
*/
SupportAnalyzer* Sibling(bool only_active = false) const;
/**
* Passes packet input to the next sibling SupportAnalyzer if any, or
* on to the associated main analyzer if none. If however there's an
@ -727,7 +749,7 @@ public:
* Parameters same as for Analyzer::ForwardPacket.
*/
virtual void ForwardPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
/**
* Passes stream input to the next sibling SupportAnalyzer if any, or
@ -747,12 +769,7 @@ public:
*
* Parameters same as for Analyzer::ForwardPacket.
*/
virtual void ForwardUndelivered(int seq, int len, bool orig);
/**
* Returns the analyzer next sibling, or null if none.
*/
SupportAnalyzer* Sibling() const { return sibling; }
virtual void ForwardUndelivered(uint64 seq, int len, bool orig);
protected:
friend class Analyzer;

View file

@ -358,7 +358,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
udp::UDP_Analyzer* udp = 0;
icmp::ICMP_Analyzer* icmp = 0;
TransportLayerAnalyzer* root = 0;
tag_set expected;
pia::PIA* pia = 0;
bool analyzed = false;
bool check_port = false;
@ -368,7 +367,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
case TRANSPORT_TCP:
root = tcp = new tcp::TCP_Analyzer(conn);
pia = new pia::PIA_TCP(conn);
expected = GetScheduled(conn);
check_port = true;
DBG_ANALYZER(conn, "activated TCP analyzer");
break;
@ -376,7 +374,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
case TRANSPORT_UDP:
root = udp = new udp::UDP_Analyzer(conn);
pia = new pia::PIA_UDP(conn);
expected = GetScheduled(conn);
check_port = true;
DBG_ANALYZER(conn, "activated UDP analyzer");
break;
@ -393,25 +390,12 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
return false;
}
// Any scheduled analyzer?
for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
{
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*i, conn);
if ( analyzer )
{
root->AddChildAnalyzer(analyzer, false);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
analyzer_mgr->GetComponentName(*i));
}
}
bool scheduled = ApplyScheduledAnalyzers(conn, false, root);
// Hmm... Do we want *just* the expected analyzer, or all
// other potential analyzers as well? For now we only take
// the scheduled ones.
if ( expected.size() == 0 )
if ( ! scheduled )
{ // Let's see if it's a port we know.
if ( check_port && ! dpd_ignore_ports )
{
@ -519,13 +503,6 @@ bool Manager::BuildInitialAnalyzerTree(Connection* conn)
if ( ! analyzed )
conn->SetLifetime(non_analyzed_lifetime);
for ( tag_set::iterator i = expected.begin(); i != expected.end(); i++ )
{
EnumVal* tag = i->AsEnumVal();
Ref(tag);
conn->Event(scheduled_analyzer_applied, 0, tag);
}
return true;
}
@ -636,3 +613,33 @@ Manager::tag_set Manager::GetScheduled(const Connection* conn)
// eventually.
return result;
}
bool Manager::ApplyScheduledAnalyzers(Connection* conn, bool init, TransportLayerAnalyzer* parent)
{
if ( ! parent )
parent = conn->GetRootAnalyzer();
if ( ! parent )
return false;
tag_set expected = GetScheduled(conn);
for ( tag_set::iterator it = expected.begin(); it != expected.end(); ++it )
{
Analyzer* analyzer = analyzer_mgr->InstantiateAnalyzer(*it, conn);
if ( ! analyzer )
continue;
parent->AddChildAnalyzer(analyzer, init);
EnumVal* tag = it->AsEnumVal();
Ref(tag);
conn->Event(scheduled_analyzer_applied, 0, tag);
DBG_ANALYZER_ARGS(conn, "activated %s analyzer as scheduled",
analyzer_mgr->GetComponentName(*it));
}
return expected.size();
}

View file

@ -292,6 +292,23 @@ public:
TransportProto proto, const char* analyzer,
double timeout);
/**
* Searched for analyzers scheduled to be attached to a given connection
* and then attaches them.
*
* @param conn The connection to which scheduled analyzers are attached.
*
* @param init True if the newly added analyzers should be
* immediately initialized.
*
* @param root If given, the scheduled analyzers will become childs
* of this; if not given the connection's root analyzer is used
* instead.
*
* @return True if at least one scheduled analyzer was found.
*/
bool ApplyScheduledAnalyzers(Connection* conn, bool init_and_event = true, TransportLayerAnalyzer* parent = 0);
/**
* Schedules a particular analyzer for an upcoming connection. Once
* the connection is seen, BuildInitAnalyzerTree() will add the

View file

@ -29,6 +29,7 @@ add_subdirectory(pia)
add_subdirectory(pop3)
add_subdirectory(radius)
add_subdirectory(rpc)
add_subdirectory(snmp)
add_subdirectory(smb)
add_subdirectory(smtp)
add_subdirectory(socks)

View file

@ -24,7 +24,10 @@
#endif
#include "NetVar.h"
#include "PacketSort.h"
extern "C" {
#include <pcap.h>
}
namespace analyzer { namespace arp {

View file

@ -22,7 +22,7 @@ void AYIYA_Analyzer::Done()
Event(udp_session_done);
}
void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen)
void AYIYA_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);

View file

@ -12,7 +12,7 @@ public:
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new AYIYA_Analyzer(conn); }

View file

@ -46,7 +46,7 @@ void BackDoorEndpoint::FinalCheckForRlogin()
}
}
int BackDoorEndpoint::DataSent(double /* t */, int seq,
int BackDoorEndpoint::DataSent(double /* t */, uint64 seq,
int len, int caplen, const u_char* data,
const IP_Hdr* /* ip */,
const struct tcphdr* /* tp */)
@ -60,8 +60,8 @@ int BackDoorEndpoint::DataSent(double /* t */, int seq,
if ( endp->state == tcp::TCP_ENDPOINT_PARTIAL )
is_partial = 1;
int ack = endp->AckSeq() - endp->StartSeq();
int top_seq = seq + len;
uint64 ack = endp->ToRelativeSeqSpace(endp->AckSeq(), endp->AckWraps());
uint64 top_seq = seq + len;
if ( top_seq <= ack || top_seq <= max_top_seq )
// There is no new data in this packet.
@ -124,7 +124,7 @@ RecordVal* BackDoorEndpoint::BuildStats()
return stats;
}
void BackDoorEndpoint::CheckForRlogin(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForRlogin(uint64 seq, int len, const u_char* data)
{
if ( rlogin_checking_done )
return;
@ -177,7 +177,7 @@ void BackDoorEndpoint::CheckForRlogin(int seq, int len, const u_char* data)
if ( seq < max_top_seq )
{ // trim to just the new data
int delta = max_top_seq - seq;
int64 delta = max_top_seq - seq;
seq += delta;
data += delta;
len -= delta;
@ -255,7 +255,7 @@ void BackDoorEndpoint::RloginSignatureFound(int len)
endp->TCP()->ConnectionEvent(rlogin_signature_found, vl);
}
void BackDoorEndpoint::CheckForTelnet(int /* seq */, int len, const u_char* data)
void BackDoorEndpoint::CheckForTelnet(uint64 /* seq */, int len, const u_char* data)
{
if ( len >= 3 &&
data[0] == TELNET_IAC && IS_TELNET_NEGOTIATION_CMD(data[1]) )
@ -346,7 +346,7 @@ void BackDoorEndpoint::TelnetSignatureFound(int len)
endp->TCP()->ConnectionEvent(telnet_signature_found, vl);
}
void BackDoorEndpoint::CheckForSSH(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForSSH(uint64 seq, int len, const u_char* data)
{
if ( seq == 1 && CheckForString("SSH-", data, len) && len > 4 &&
(data[4] == '1' || data[4] == '2') )
@ -363,8 +363,9 @@ void BackDoorEndpoint::CheckForSSH(int seq, int len, const u_char* data)
if ( seq > max_top_seq )
{ // Estimate number of packets in the sequence gap
int gap = seq - max_top_seq;
num_pkts += int((gap + DEFAULT_MTU - 1) / DEFAULT_MTU);
int64 gap = seq - max_top_seq;
if ( gap > 0 )
num_pkts += uint64((gap + DEFAULT_MTU - 1) / DEFAULT_MTU);
}
++num_pkts;
@ -388,7 +389,7 @@ void BackDoorEndpoint::CheckForSSH(int seq, int len, const u_char* data)
}
}
void BackDoorEndpoint::CheckForRootBackdoor(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForRootBackdoor(uint64 seq, int len, const u_char* data)
{
// Check for root backdoor signature: an initial payload of
// exactly "# ".
@ -397,7 +398,7 @@ void BackDoorEndpoint::CheckForRootBackdoor(int seq, int len, const u_char* data
SignatureFound(root_backdoor_signature_found);
}
void BackDoorEndpoint::CheckForFTP(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForFTP(uint64 seq, int len, const u_char* data)
{
// Check for FTP signature
//
@ -429,7 +430,7 @@ void BackDoorEndpoint::CheckForFTP(int seq, int len, const u_char* data)
SignatureFound(ftp_signature_found);
}
void BackDoorEndpoint::CheckForNapster(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForNapster(uint64 seq, int len, const u_char* data)
{
// Check for Napster signature "GETfoobar" or "SENDfoobar" where
// "foobar" is the Napster handle associated with the request
@ -449,7 +450,7 @@ void BackDoorEndpoint::CheckForNapster(int seq, int len, const u_char* data)
SignatureFound(napster_signature_found);
}
void BackDoorEndpoint::CheckForSMTP(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForSMTP(uint64 seq, int len, const u_char* data)
{
const char* smtp_handshake[] = { "HELO", "EHLO", 0 };
@ -460,7 +461,7 @@ void BackDoorEndpoint::CheckForSMTP(int seq, int len, const u_char* data)
SignatureFound(smtp_signature_found);
}
void BackDoorEndpoint::CheckForIRC(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForIRC(uint64 seq, int len, const u_char* data)
{
if ( seq != 1 || is_partial )
return;
@ -475,7 +476,7 @@ void BackDoorEndpoint::CheckForIRC(int seq, int len, const u_char* data)
SignatureFound(irc_signature_found);
}
void BackDoorEndpoint::CheckForGnutella(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForGnutella(uint64 seq, int len, const u_char* data)
{
// After connecting to the server, the connecting client says:
//
@ -492,13 +493,13 @@ void BackDoorEndpoint::CheckForGnutella(int seq, int len, const u_char* data)
SignatureFound(gnutella_signature_found);
}
void BackDoorEndpoint::CheckForGaoBot(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForGaoBot(uint64 seq, int len, const u_char* data)
{
if ( seq == 1 && CheckForString("220 Bot Server (Win32)", data, len) )
SignatureFound(gaobot_signature_found);
}
void BackDoorEndpoint::CheckForKazaa(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForKazaa(uint64 seq, int len, const u_char* data)
{
// *Some*, though not all, KaZaa connections begin with:
//
@ -565,7 +566,7 @@ int is_absolute_url(const u_char* data, int len)
return *abs_url_sig_pos == '\0';
}
void BackDoorEndpoint::CheckForHTTP(int seq, int len, const u_char* data)
void BackDoorEndpoint::CheckForHTTP(uint64 seq, int len, const u_char* data)
{
// According to the RFC, we should look for
// '<method> SP <url> SP HTTP/<version> CR LF'
@ -629,7 +630,7 @@ void BackDoorEndpoint::CheckForHTTP(int seq, int len, const u_char* data)
}
}
void BackDoorEndpoint::CheckForHTTPProxy(int /* seq */, int len,
void BackDoorEndpoint::CheckForHTTPProxy(uint64 /* seq */, int len,
const u_char* data)
{
// Proxy ONLY accepts absolute URI's: "The absoluteURI form is
@ -713,7 +714,7 @@ void BackDoor_Analyzer::Init()
}
void BackDoor_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen)
uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);

View file

@ -14,7 +14,7 @@ class BackDoorEndpoint {
public:
BackDoorEndpoint(tcp::TCP_Endpoint* e);
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);
RecordVal* BuildStats();
@ -22,23 +22,23 @@ public:
void FinalCheckForRlogin();
protected:
void CheckForRlogin(int seq, int len, const u_char* data);
void CheckForRlogin(uint64 seq, int len, const u_char* data);
void RloginSignatureFound(int len);
void CheckForTelnet(int seq, int len, const u_char* data);
void CheckForTelnet(uint64 seq, int len, const u_char* data);
void TelnetSignatureFound(int len);
void CheckForSSH(int seq, int len, const u_char* data);
void CheckForFTP(int seq, int len, const u_char* data);
void CheckForRootBackdoor(int seq, int len, const u_char* data);
void CheckForNapster(int seq, int len, const u_char* data);
void CheckForGnutella(int seq, int len, const u_char* data);
void CheckForKazaa(int seq, int len, const u_char* data);
void CheckForHTTP(int seq, int len, const u_char* data);
void CheckForHTTPProxy(int seq, int len, const u_char* data);
void CheckForSMTP(int seq, int len, const u_char* data);
void CheckForIRC(int seq, int len, const u_char* data);
void CheckForGaoBot(int seq, int len, const u_char* data);
void CheckForSSH(uint64 seq, int len, const u_char* data);
void CheckForFTP(uint64 seq, int len, const u_char* data);
void CheckForRootBackdoor(uint64 seq, int len, const u_char* data);
void CheckForNapster(uint64 seq, int len, const u_char* data);
void CheckForGnutella(uint64 seq, int len, const u_char* data);
void CheckForKazaa(uint64 seq, int len, const u_char* data);
void CheckForHTTP(uint64 seq, int len, const u_char* data);
void CheckForHTTPProxy(uint64 seq, int len, const u_char* data);
void CheckForSMTP(uint64 seq, int len, const u_char* data);
void CheckForIRC(uint64 seq, int len, const u_char* data);
void CheckForGaoBot(uint64 seq, int len, const u_char* data);
void SignatureFound(EventHandlerPtr e, int do_orig = 0);
@ -48,11 +48,11 @@ protected:
tcp::TCP_Endpoint* endp;
int is_partial;
int max_top_seq;
uint64 max_top_seq;
int rlogin_checking_done;
int rlogin_num_null;
int rlogin_string_separator_pos;
uint64 rlogin_string_separator_pos;
int rlogin_slash_seen;
uint32 num_pkts;
@ -80,7 +80,7 @@ protected:
// We support both packet and stream input, and can be instantiated
// even if the TCP analyzer is not yet reassembling.
virtual void DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
virtual void DeliverStream(int len, const u_char* data, bool is_orig);
void StatEvent();

View file

@ -68,7 +68,7 @@ void BitTorrent_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
}
}
void BitTorrent_Analyzer::Undelivered(int seq, int len, bool orig)
void BitTorrent_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);

View file

@ -16,7 +16,7 @@ public:
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)

View file

@ -207,7 +207,7 @@ void BitTorrentTracker_Analyzer::ServerReply(int len, const u_char* data)
}
}
void BitTorrentTracker_Analyzer::Undelivered(int seq, int len, bool orig)
void BitTorrentTracker_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);

View file

@ -49,7 +49,7 @@ public:
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)

View file

@ -36,7 +36,7 @@ void ConnSize_Analyzer::Done()
Analyzer::Done();
}
void ConnSize_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen)
void ConnSize_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);

View file

@ -26,7 +26,7 @@ public:
protected:
virtual void DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
uint64_t orig_bytes;

View file

@ -21,7 +21,7 @@ void DHCP_Analyzer::Done()
}
void DHCP_Analyzer::DeliverPacket(int len, const u_char* data,
bool orig, int seq, const IP_Hdr* ip, int caplen)
bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
interp->NewData(orig, data, data + len);

View file

@ -14,7 +14,7 @@ public:
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new DHCP_Analyzer(conn); }

View file

@ -153,7 +153,7 @@ void DNP3_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
}
}
void DNP3_Analyzer::Undelivered(int seq, int len, bool orig)
void DNP3_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
interp->NewGap(orig, len);

View file

@ -14,7 +14,7 @@ public:
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static Analyzer* InstantiateAnalyzer(Connection* conn)

View file

@ -32,6 +32,8 @@ event dnp3_application_response_header%(c: connection, is_orig: bool, fc: count,
##
## qua_field: qualifier field.
##
## number: TODO.
##
## rf_low: the structure of the range field depends on the qualified field.
## In some cases, the range field contains only one logic part, e.g.,
## number of objects, so only *rf_low* contains useful values.

View file

@ -137,18 +137,6 @@ int DNS_Interpreter::ParseQuestions(DNS_MsgInfo* msg,
{
int n = msg->qdcount;
if ( n == 0 )
{
// Generate event here because we won't go into ParseQuestion.
EventHandlerPtr dns_event =
msg->rcode == DNS_CODE_OK ?
dns_query_reply : dns_rejected;
BroString* question_name = new BroString("<no query>");
SendReplyOrRejectEvent(msg, dns_event, data, len, question_name);
return 1;
}
while ( n > 0 && ParseQuestion(msg, data, len, msg_start) )
--n;
return n == 0;
@ -220,6 +208,7 @@ int DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg,
int name_len = sizeof(name) - 1;
u_char* name_end = ExtractName(data, len, name, name_len, msg_start);
if ( ! name_end )
return 0;
@ -287,7 +276,17 @@ int DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg,
break;
case TYPE_SRV:
status = ParseRR_SRV(msg, data, len, rdlength, msg_start);
if ( ntohs(analyzer->Conn()->RespPort()) == 137 )
{
// This is an NBSTAT (NetBIOS NODE STATUS) record.
// The SRV RFC reused the value that was already being
// used for this.
// We aren't parsing this yet.
status = 1;
}
else
status = ParseRR_SRV(msg, data, len, rdlength, msg_start);
break;
case TYPE_EDNS:
@ -299,6 +298,16 @@ int DNS_Interpreter::ParseAnswer(DNS_MsgInfo* msg,
break;
default:
if ( dns_unknown_reply && ! msg->skip_event )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
analyzer->ConnectionEvent(dns_unknown_reply, vl);
}
analyzer->Weird("DNS_RR_unknown_type");
data += rdlength;
len -= rdlength;
@ -402,7 +411,9 @@ int DNS_Interpreter::ExtractLabel(const u_char*& data, int& len,
return 0;
}
if ( label_len > 63 )
if ( label_len > 63 &&
// NetBIOS name service look ups can use longer labels.
ntohs(analyzer->Conn()->RespPort()) != 137 )
{
analyzer->Weird("DNS_label_too_long");
return 0;
@ -635,15 +646,24 @@ int DNS_Interpreter::ParseRR_SRV(DNS_MsgInfo* msg,
u_char* name_end = ExtractName(data, len, name, name_len, msg_start);
if ( ! name_end )
return 0;
*name_end = 0; // terminate name so we can use it in snprintf()
if ( data - data_start != rdlength )
analyzer->Weird("DNS_RR_length_mismatch");
// The following is just a placeholder.
char buf[2048];
safe_snprintf(buf, sizeof(buf), "SRV %s priority=%d weight=%d port=%d",
name, priority, weight, port);
if ( dns_SRV_reply && ! msg->skip_event )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(new StringVal(new BroString(name, name_end - name, 1)));
vl->append(new Val(priority, TYPE_COUNT));
vl->append(new Val(weight, TYPE_COUNT));
vl->append(new Val(port, TYPE_COUNT));
analyzer->ConnectionEvent(dns_SRV_reply, vl);
}
return 1;
}
@ -815,34 +835,61 @@ int DNS_Interpreter::ParseRR_HINFO(DNS_MsgInfo* msg,
return 1;
}
static StringVal* extract_char_string(analyzer::Analyzer* analyzer,
const u_char*& data, int& len, int& rdlen)
{
if ( rdlen <= 0 )
return 0;
uint8 str_size = data[0];
--rdlen;
--len;
++data;
if ( str_size > rdlen )
{
analyzer->Weird("DNS_TXT_char_str_past_rdlen");
return 0;
}
StringVal* rval = new StringVal(str_size,
reinterpret_cast<const char*>(data));
rdlen -= str_size;
len -= str_size;
data += str_size;
return rval;
}
int DNS_Interpreter::ParseRR_TXT(DNS_MsgInfo* msg,
const u_char*& data, int& len, int rdlength,
const u_char* msg_start)
{
int name_len = data[0];
char* name = new char[name_len];
memcpy(name, data+1, name_len);
data += rdlength;
len -= rdlength;
if ( dns_TXT_reply && ! msg->skip_event )
if ( ! dns_TXT_reply || msg->skip_event )
{
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(new StringVal(name_len, name));
analyzer->ConnectionEvent(dns_TXT_reply, vl);
data += rdlength;
len -= rdlength;
return 1;
}
delete [] name;
VectorVal* char_strings = new VectorVal(string_vec);
StringVal* char_string;
return 1;
while ( (char_string = extract_char_string(analyzer, data, len, rdlength)) )
char_strings->Assign(char_strings->Size(), char_string);
val_list* vl = new val_list;
vl->append(analyzer->BuildConnVal());
vl->append(msg->BuildHdrVal());
vl->append(msg->BuildAnswerVal());
vl->append(char_strings);
analyzer->ConnectionEvent(dns_TXT_reply, vl);
return rdlength == 0;
}
void DNS_Interpreter::SendReplyOrRejectEvent(DNS_MsgInfo* msg,
@ -1126,7 +1173,7 @@ void DNS_Analyzer::Done()
}
void DNS_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen)
uint64 seq, const IP_Hdr* ip, int caplen)
{
tcp::TCP_ApplicationAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen);

View file

@ -258,7 +258,7 @@ public:
~DNS_Analyzer();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
virtual void Init();
virtual void Done();

View file

@ -50,7 +50,7 @@ event dns_message%(c: connection, is_orig: bool, msg: dns_msg, len: count%);
event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%);
## Generated for DNS replies that reject a query. This event is raised if a DNS
## reply either indicates failure via its status code or does not pass on any
## reply indicates failure because it does not pass on any
## answers to a query. Note that all of the event's parameters are parsed out of
## the reply; there's no stateful correlation with the query.
##
@ -78,7 +78,7 @@ event dns_request%(c: connection, msg: dns_msg, query: string, qtype: count, qcl
## dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_rejected%(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count%);
## Generated for DNS replies with an *ok* status code but no question section.
## Generated for each entry in the Question section of a DNS reply.
##
## See `Wikipedia <http://en.wikipedia.org/wiki/Domain_Name_System>`__ for more
## information about the DNS protocol. Bro analyzes both UDP and TCP DNS
@ -376,7 +376,7 @@ event dns_MX_reply%(c: connection, msg: dns_msg, ans: dns_answer, name: string,
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request dns_max_queries dns_session_timeout
## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_TXT_reply%(c: connection, msg: dns_msg, ans: dns_answer, str: string%);
event dns_TXT_reply%(c: connection, msg: dns_msg, ans: dns_answer, strs: string_vec%);
## Generated for DNS replies of type *SRV*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.
@ -392,6 +392,12 @@ event dns_TXT_reply%(c: connection, msg: dns_msg, ans: dns_answer, str: string%)
##
## ans: The type-independent part of the parsed answer record.
##
## priority: Priority of the SRV response.
##
## weight: Weight of the SRV response.
##
## p: Port of the SRV response.
##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_end dns_full_request
@ -399,7 +405,23 @@ event dns_TXT_reply%(c: connection, msg: dns_msg, ans: dns_answer, str: string%)
## dns_mapping_unverified dns_mapping_valid dns_message dns_query_reply
## dns_rejected dns_request non_dns_request dns_max_queries dns_session_timeout
## dns_skip_addl dns_skip_all_addl dns_skip_all_auth dns_skip_auth
event dns_SRV_reply%(c: connection, msg: dns_msg, ans: dns_answer%);
event dns_SRV_reply%(c: connection, msg: dns_msg, ans: dns_answer, target: string, priority: count, weight: count, p: count%);
## Generated on DNS reply resource records when the type of record is not one
## that Bro knows how to parse and generate another more specific specific
## event.
##
## c: The connection, which may be UDP or TCP depending on the type of the
## transport-layer session being analyzed.
##
## msg: The parsed DNS message header.
##
## ans: The type-independent part of the parsed answer record.
##
## .. bro:see:: dns_AAAA_reply dns_A_reply dns_CNAME_reply dns_EDNS_addl
## dns_HINFO_reply dns_MX_reply dns_NS_reply dns_PTR_reply dns_SOA_reply
## dns_TSIG_addl dns_TXT_reply dns_WKS_reply dns_SRV_reply dns_end
event dns_unknown_reply%(c: connection, msg: dns_msg, ans: dns_answer%);
## Generated for DNS replies of type *EDNS*. For replies with multiple answers,
## an individual event of the corresponding type is raised for each.

View file

@ -3,6 +3,7 @@
#include "File.h"
#include "file_analysis/Manager.h"
#include "RuleMatcher.h"
#include "Reporter.h"
#include "util.h"
@ -30,12 +31,25 @@ void File_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
if ( buffer_len == BUFFER_SIZE )
Identify();
}
return;
if ( orig )
file_id_orig = file_mgr->DataIn(data, len, GetAnalyzerTag(), Conn(),
orig, file_id_orig);
else
file_id_resp = file_mgr->DataIn(data, len, GetAnalyzerTag(), Conn(),
orig, file_id_resp);
}
void File_Analyzer::Undelivered(int seq, int len, bool orig)
void File_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
if ( orig )
file_id_orig = file_mgr->Gap(seq, len, GetAnalyzerTag(), Conn(), orig,
file_id_orig);
else
file_id_resp = file_mgr->Gap(seq, len, GetAnalyzerTag(), Conn(), orig,
file_id_resp);
}
void File_Analyzer::Done()
@ -44,63 +58,29 @@ void File_Analyzer::Done()
if ( buffer_len && buffer_len != BUFFER_SIZE )
Identify();
if ( ! file_id_orig.empty() )
file_mgr->EndOfFile(file_id_orig);
else
file_mgr->EndOfFile(GetAnalyzerTag(), Conn(), true);
if ( ! file_id_resp.empty() )
file_mgr->EndOfFile(file_id_resp);
else
file_mgr->EndOfFile(GetAnalyzerTag(), Conn(), false);
}
void File_Analyzer::Identify()
{
const char* desc = bro_magic_buffer(magic_desc_cookie, buffer, buffer_len);
const char* mime = bro_magic_buffer(magic_mime_cookie, buffer, buffer_len);
RuleMatcher::MIME_Matches matches;
file_mgr->DetectMIME(reinterpret_cast<const u_char*>(buffer), buffer_len,
&matches);
string match = matches.empty() ? "<unknown>"
: *(matches.begin()->second.begin());
val_list* vl = new val_list;
vl->append(BuildConnVal());
vl->append(new StringVal(buffer_len, buffer));
vl->append(new StringVal(desc ? desc : "<unknown>"));
vl->append(new StringVal(mime ? mime : "<unknown>"));
vl->append(new StringVal("<unknown>"));
vl->append(new StringVal(match));
ConnectionEvent(file_transferred, vl);
}
IRC_Data::IRC_Data(Connection* conn)
: File_Analyzer("IRC_Data", conn)
{
}
void IRC_Data::Done()
{
File_Analyzer::Done();
file_mgr->EndOfFile(GetAnalyzerTag(), Conn());
}
void IRC_Data::DeliverStream(int len, const u_char* data, bool orig)
{
File_Analyzer::DeliverStream(len, data, orig);
file_mgr->DataIn(data, len, GetAnalyzerTag(), Conn(), orig);
}
void IRC_Data::Undelivered(int seq, int len, bool orig)
{
File_Analyzer::Undelivered(seq, len, orig);
file_mgr->Gap(seq, len, GetAnalyzerTag(), Conn(), orig);
}
FTP_Data::FTP_Data(Connection* conn)
: File_Analyzer("FTP_Data", conn)
{
}
void FTP_Data::Done()
{
File_Analyzer::Done();
file_mgr->EndOfFile(GetAnalyzerTag(), Conn());
}
void FTP_Data::DeliverStream(int len, const u_char* data, bool orig)
{
File_Analyzer::DeliverStream(len, data, orig);
file_mgr->DataIn(data, len, GetAnalyzerTag(), Conn(), orig);
}
void FTP_Data::Undelivered(int seq, int len, bool orig)
{
File_Analyzer::Undelivered(seq, len, orig);
file_mgr->Gap(seq, len, GetAnalyzerTag(), Conn(), orig);
}

View file

@ -17,7 +17,7 @@ public:
virtual void DeliverStream(int len, const u_char* data, bool orig);
void Undelivered(int seq, int len, bool orig);
void Undelivered(uint64 seq, int len, bool orig);
// static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
// { return new File_Analyzer(conn); }
@ -28,17 +28,15 @@ protected:
static const int BUFFER_SIZE = 1024;
char buffer[BUFFER_SIZE];
int buffer_len;
string file_id_orig;
string file_id_resp;
};
class IRC_Data : public File_Analyzer {
public:
IRC_Data(Connection* conn);
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
IRC_Data(Connection* conn)
: File_Analyzer("IRC_Data", conn)
{ }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new IRC_Data(conn); }
@ -46,13 +44,9 @@ public:
class FTP_Data : public File_Analyzer {
public:
FTP_Data(Connection* conn);
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
FTP_Data(Connection* conn)
: File_Analyzer("FTP_Data", conn)
{ }
static Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new FTP_Data(conn); }

View file

@ -1,3 +1,12 @@
## TODO.
## Generated when a TCP connection associated w/ file data transfer is seen
## (e.g. as happens w/ FTP or IRC).
##
## c: The connection over which file data is transferred.
##
## prefix: Up to 1024 bytes of the file data.
##
## descr: Deprecated/unused argument.
##
## mime_type: MIME type of the file or "<unknown>" if no file magic signatures
## matched.
event file_transferred%(c: connection, prefix: string, descr: string, mime_type: string%);

View file

@ -23,7 +23,7 @@ void GTPv1_Analyzer::Done()
Event(udp_session_done);
}
void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, int seq, const IP_Hdr* ip, int caplen)
void GTPv1_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
try

View file

@ -12,7 +12,7 @@ public:
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new GTPv1_Analyzer(conn); }

View file

@ -242,10 +242,17 @@ int HTTP_Entity::Undelivered(int64_t len)
if ( end_of_data && in_header )
return 0;
file_mgr->Gap(body_length, len,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig());
if ( is_partial_content )
precomputed_file_id = file_mgr->Gap(body_length, len,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig(), precomputed_file_id);
else
precomputed_file_id = file_mgr->Gap(body_length, len,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig(),
precomputed_file_id);
if ( chunked_transfer_state != NON_CHUNKED_TRANSFER )
{
@ -299,30 +306,33 @@ void HTTP_Entity::SubmitData(int len, const char* buf)
if ( is_partial_content )
{
if ( send_size && instance_length > 0 )
file_mgr->SetSize(instance_length,
precomputed_file_id = file_mgr->SetSize(instance_length,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig());
http_message->IsOrig(), precomputed_file_id);
file_mgr->DataIn(reinterpret_cast<const u_char*>(buf), len, offset,
precomputed_file_id = file_mgr->DataIn(reinterpret_cast<const u_char*>(buf), len, offset,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig());
http_message->IsOrig(), precomputed_file_id);
offset += len;
}
else
{
if ( send_size && content_length > 0 )
file_mgr->SetSize(content_length,
precomputed_file_id = file_mgr->SetSize(content_length,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig());
http_message->IsOrig(),
precomputed_file_id);
file_mgr->DataIn(reinterpret_cast<const u_char*>(buf), len,
precomputed_file_id = file_mgr->DataIn(reinterpret_cast<const u_char*>(buf),
len,
http_message->MyHTTP_Analyzer()->GetAnalyzerTag(),
http_message->MyHTTP_Analyzer()->Conn(),
http_message->IsOrig());
http_message->IsOrig(),
precomputed_file_id);
}
send_size = false;
@ -573,9 +583,16 @@ void HTTP_Message::Done(const int interrupted, const char* detail)
top_level->EndOfData();
if ( is_orig || MyHTTP_Analyzer()->HTTP_ReplyCode() != 206 )
// multipart/byteranges may span multiple connections
file_mgr->EndOfFile(MyHTTP_Analyzer()->GetAnalyzerTag(),
MyHTTP_Analyzer()->Conn(), is_orig);
{
// multipart/byteranges may span multiple connections, so don't EOF.
HTTP_Entity* he = dynamic_cast<HTTP_Entity*>(top_level);
if ( he && ! he->FileID().empty() )
file_mgr->EndOfFile(he->FileID());
else
file_mgr->EndOfFile(MyHTTP_Analyzer()->GetAnalyzerTag(),
MyHTTP_Analyzer()->Conn(), is_orig);
}
if ( http_message_done )
{
@ -653,8 +670,15 @@ void HTTP_Message::EndEntity(mime::MIME_Entity* entity)
Done();
else if ( is_orig || MyHTTP_Analyzer()->HTTP_ReplyCode() != 206 )
file_mgr->EndOfFile(MyHTTP_Analyzer()->GetAnalyzerTag(),
MyHTTP_Analyzer()->Conn(), is_orig);
{
HTTP_Entity* he = dynamic_cast<HTTP_Entity*>(entity);
if ( he && ! he->FileID().empty() )
file_mgr->EndOfFile(he->FileID());
else
file_mgr->EndOfFile(MyHTTP_Analyzer()->GetAnalyzerTag(),
MyHTTP_Analyzer()->Conn(), is_orig);
}
}
void HTTP_Message::SubmitHeader(mime::MIME_Header* h)
@ -879,6 +903,9 @@ HTTP_Analyzer::HTTP_Analyzer(Connection* conn)
reply_code = 0;
reply_reason_phrase = 0;
connect_request = false;
pia = 0;
content_line_orig = new tcp::ContentLine_Analyzer(conn, true);
AddSupportAnalyzer(content_line_orig);
@ -935,6 +962,14 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
if ( TCP() && TCP()->IsPartial() )
return;
if ( pia )
{
// There will be a PIA instance if this connection has been identified
// as a connect proxy.
ForwardStream(len, data, is_orig);
return;
}
const char* line = reinterpret_cast<const char*>(data);
const char* end_of_line = line + len;
@ -1045,6 +1080,29 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
HTTP_Reply();
if ( connect_request && reply_code == 200 )
{
pia = new pia::PIA_TCP(Conn());
if ( AddChildAnalyzer(pia) )
{
pia->FirstPacket(true, 0);
pia->FirstPacket(false, 0);
// This connection has transitioned to no longer
// being http and the content line support analyzers
// need to be removed.
RemoveSupportAnalyzer(content_line_orig);
RemoveSupportAnalyzer(content_line_resp);
return;
}
else
// AddChildAnalyzer() will have deleted PIA.
pia = 0;
}
InitHTTPMessage(content_line,
reply_message, is_orig,
ExpectReplyMessageBody(),
@ -1071,11 +1129,11 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
}
}
void HTTP_Analyzer::Undelivered(int seq, int len, bool is_orig)
void HTTP_Analyzer::Undelivered(uint64 seq, int len, bool is_orig)
{
tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, is_orig);
// DEBUG_MSG("Undelivered from %d: %d bytes\n", seq, length);
// DEBUG_MSG("Undelivered from %"PRIu64": %d bytes\n", seq, length);
HTTP_Message* msg =
is_orig ? request_message : reply_message;
@ -1087,7 +1145,7 @@ void HTTP_Analyzer::Undelivered(int seq, int len, bool is_orig)
{
if ( msg )
msg->SubmitEvent(mime::MIME_EVENT_CONTENT_GAP,
fmt("seq=%d, len=%d", seq, len));
fmt("seq=%"PRIu64", len=%d", seq, len));
}
// Check if the content gap falls completely within a message body
@ -1380,6 +1438,12 @@ void HTTP_Analyzer::HTTP_Request()
{
ProtocolConfirmation();
const char* method = (const char*) request_method->AsString()->Bytes();
int method_len = request_method->AsString()->Len();
if ( strcasecmp_n(method_len, method, "CONNECT") == 0 )
connect_request = true;
if ( http_request )
{
val_list* vl = new val_list;

View file

@ -5,6 +5,7 @@
#include "analyzer/protocol/tcp/TCP.h"
#include "analyzer/protocol/tcp/ContentLine.h"
#include "analyzer/protocol/pia/PIA.h"
#include "analyzer/protocol/zip/ZIP.h"
#include "analyzer/protocol/mime/MIME.h"
#include "binpac_bro.h"
@ -45,6 +46,7 @@ public:
int64_t BodyLength() const { return body_length; }
int64_t HeaderLength() const { return header_length; }
void SkipBody() { deliver_body = 0; }
const string& FileID() const { return precomputed_file_id; }
protected:
class UncompressedOutput;
@ -64,6 +66,7 @@ protected:
uint64_t offset;
int64_t instance_length; // total length indicated by content-range
bool send_size; // whether to send size indication to FAF
std::string precomputed_file_id;
MIME_Entity* NewChildEntity() { return new HTTP_Entity(http_message, this, 1); }
@ -159,7 +162,7 @@ public:
HTTP_Analyzer(Connection* conn);
~HTTP_Analyzer();
void Undelivered(tcp::TCP_Endpoint* sender, int seq, int len);
void Undelivered(tcp::TCP_Endpoint* sender, uint64 seq, int len);
void HTTP_Header(int is_orig, mime::MIME_Header* h);
void HTTP_EntityData(int is_orig, const BroString* entity_data);
@ -175,7 +178,7 @@ public:
// Overriden from Analyzer.
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
// Overriden from tcp::TCP_ApplicationAnalyzer
virtual void EndpointEOF(bool is_orig);
@ -236,6 +239,9 @@ protected:
int connection_close;
int request_ongoing, reply_ongoing;
bool connect_request;
pia::PIA_TCP *pia;
Val* request_method;
// request_URI is in the original form (may contain '%<hex><hex>'

View file

@ -31,7 +31,7 @@ void ICMP_Analyzer::Done()
}
void ICMP_Analyzer::DeliverPacket(int len, const u_char* data,
bool is_orig, int seq, const IP_Hdr* ip, int caplen)
bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
assert(ip);

View file

@ -29,7 +29,7 @@ protected:
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
virtual bool IsReuse(double t, const u_char* pkt);
virtual unsigned int MemoryAllocation() const;

View file

@ -24,7 +24,7 @@ InterConnEndpoint::InterConnEndpoint(tcp::TCP_Endpoint* e)
#define NORMAL_LINE_LENGTH 80
int InterConnEndpoint::DataSent(double t, int seq, int len, int caplen,
int InterConnEndpoint::DataSent(double t, uint64 seq, int len, int caplen,
const u_char* data, const IP_Hdr* /* ip */,
const struct tcphdr* /* tp */)
{
@ -37,8 +37,8 @@ int InterConnEndpoint::DataSent(double t, int seq, int len, int caplen,
if ( endp->state == tcp::TCP_ENDPOINT_PARTIAL )
is_partial = 1;
int ack = endp->AckSeq() - endp->StartSeq();
int top_seq = seq + len;
uint64 ack = endp->ToRelativeSeqSpace(endp->AckSeq(), endp->AckWraps());
uint64 top_seq = seq + len;
if ( top_seq <= ack || top_seq <= max_top_seq )
// There is no new data in this packet
@ -46,7 +46,7 @@ int InterConnEndpoint::DataSent(double t, int seq, int len, int caplen,
if ( seq < max_top_seq )
{ // Only consider new data
int amount_seen = max_top_seq - seq;
int64 amount_seen = max_top_seq - seq;
seq += amount_seen;
data += amount_seen;
len -= amount_seen;
@ -184,7 +184,7 @@ void InterConn_Analyzer::Init()
}
void InterConn_Analyzer::DeliverPacket(int len, const u_char* data,
bool is_orig, int seq, const IP_Hdr* ip, int caplen)
bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
tcp::TCP_ApplicationAnalyzer::DeliverPacket(len, data, is_orig,
seq, ip, caplen);

View file

@ -13,7 +13,7 @@ class InterConnEndpoint : public BroObj {
public:
InterConnEndpoint(tcp::TCP_Endpoint* e);
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);
RecordVal* BuildStats();
@ -25,7 +25,7 @@ protected:
tcp::TCP_Endpoint* endp;
double last_keystroke_time;
int max_top_seq;
uint64 max_top_seq;
uint32 num_pkts;
uint32 num_keystrokes_two_in_a_row;
uint32 num_normal_interarrivals;
@ -56,7 +56,7 @@ protected:
// We support both packet and stream input and can be put in place even
// if the TCP analyzer is not yet reassembling.
virtual void DeliverPacket(int len, const u_char* data, bool is_orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
virtual void DeliverStream(int len, const u_char* data, bool is_orig);
void StatEvent();

View file

@ -1044,6 +1044,7 @@ void MIME_Entity::DecodeQuotedPrintable(int len, const char* data)
{
DataOctet((a << 4) + b);
legal = 1;
i += 2;
}
}

View file

@ -31,7 +31,7 @@ void ModbusTCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
interp->NewData(orig, data, data + len);
}
void ModbusTCP_Analyzer::Undelivered(int seq, int len, bool orig)
void ModbusTCP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
interp->NewGap(orig, len);

View file

@ -14,7 +14,7 @@ public:
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)

View file

@ -149,7 +149,7 @@ event modbus_write_single_register_response%(c: connection, headers: ModbusHeade
##
## start_address: The memory address of the first coil to be written.
##
## value: The values to be written to the coils.
## coils: The values to be written to the coils.
event modbus_write_multiple_coils_request%(c: connection, headers: ModbusHeaders, start_address: count, coils: ModbusCoils%);
## Generated for a Modbus write multiple coils response.

View file

@ -10,6 +10,7 @@
%header{
VectorVal* bytestring_to_coils(bytestring coils, uint quantity);
RecordVal* HeaderToBro(ModbusTCP_TransportHeader *header);
VectorVal* create_vector_of_count();
%}
%code{
@ -30,6 +31,14 @@
return modbus_header;
}
VectorVal* create_vector_of_count()
{
VectorType* vt = new VectorType(base_type(TYPE_COUNT));
VectorVal* vv = new VectorVal(vt);
Unref(vt);
return vv;
}
%}
refine flow ModbusTCP_Flow += {
@ -367,7 +376,7 @@ refine flow ModbusTCP_Flow += {
if ( ::modbus_read_file_record_request )
{
//TODO: this need to be a vector of some Reference Request record type
//VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
//VectorVal *t = create_vector_of_count();
//for ( unsigned int i = 0; i < (${message.references}->size()); ++i )
// {
// Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT);
@ -393,7 +402,7 @@ refine flow ModbusTCP_Flow += {
%{
if ( ::modbus_read_file_record_response )
{
//VectorVal *t = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
//VectorVal *t = create_vector_of_count();
//for ( unsigned int i = 0; i < ${message.references}->size(); ++i )
// {
// //TODO: work the reference type in here somewhere
@ -414,7 +423,7 @@ refine flow ModbusTCP_Flow += {
%{
if ( ::modbus_write_file_record_request )
{
//VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
//VectorVal* t = create_vector_of_count();
//for ( unsigned int i = 0; i < (${message.references}->size()); ++i )
// {
// Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT);
@ -447,7 +456,7 @@ refine flow ModbusTCP_Flow += {
%{
if ( ::modbus_write_file_record_response )
{
//VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
//VectorVal* t = create_vector_of_count();
//for ( unsigned int i = 0; i < (${messages.references}->size()); ++i )
// {
// Val* r = new Val((${message.references[i].ref_type}), TYPE_COUNT);
@ -589,7 +598,7 @@ refine flow ModbusTCP_Flow += {
if ( ::modbus_read_fifo_queue_response )
{
VectorVal* t = new VectorVal(new VectorType(base_type(TYPE_COUNT)));
VectorVal* t = create_vector_of_count();
for ( unsigned int i = 0; i < (${message.register_data})->size(); ++i )
{
Val* r = new Val(${message.register_data[i]}, TYPE_COUNT);

View file

@ -211,7 +211,7 @@ void Contents_NCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig
}
}
void Contents_NCP_Analyzer::Undelivered(int seq, int len, bool orig)
void Contents_NCP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
tcp::TCP_SupportAnalyzer::Undelivered(seq, len, orig);

View file

@ -90,7 +90,7 @@ public:
protected:
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(int seq, int len, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
NCP_FrameBuffer buffer;
NCP_Session* session;

View file

@ -513,7 +513,7 @@ void NetbiosSSN_Analyzer::ConnectionClosed(tcp::TCP_Endpoint* endpoint,
}
void NetbiosSSN_Analyzer::DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen)
uint64 seq, const IP_Hdr* ip, int caplen)
{
tcp::TCP_ApplicationAnalyzer::DeliverPacket(len, data, orig, seq, ip, caplen);

View file

@ -146,7 +146,7 @@ public:
virtual void Done();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
int seq, const IP_Hdr* ip, int caplen);
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* InstantiateAnalyzer(Connection* conn)
{ return new NetbiosSSN_Analyzer(conn); }

View file

@ -25,7 +25,7 @@ void NTP_Analyzer::Done()
Event(udp_session_done);
}
void NTP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, int seq, const IP_Hdr* ip, int caplen)
void NTP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, is_orig, seq, ip, caplen);

Some files were not shown because too many files have changed in this diff Show more