The logging systems now supports fields of type set[<atomic_type>].

This commit is contained in:
Robin Sommer 2011-03-09 18:01:41 -08:00
parent 52c54859b6
commit c6e3174bc8
7 changed files with 364 additions and 109 deletions

View file

@ -63,6 +63,21 @@ struct LogMgr::Stream {
~Stream(); ~Stream();
}; };
LogVal::~LogVal()
{
if ( type == TYPE_STRING && present )
delete val.string_val;
if ( type == TYPE_TABLE && present )
{
for ( int i = 0; i < val.set_val.size; i++ )
delete val.set_val.vals[i];
delete [] val.set_val.vals;
}
}
bool LogVal::Read(SerializationFormat* fmt) bool LogVal::Read(SerializationFormat* fmt)
{ {
int ty; int ty;
@ -139,6 +154,23 @@ bool LogVal::Read(SerializationFormat* fmt)
return fmt->Read(val.string_val, "string"); return fmt->Read(val.string_val, "string");
} }
case TYPE_TABLE:
{
if ( ! fmt->Read(&val.set_val.size, "set_size") )
return false;
val.set_val.vals = new LogVal* [val.set_val.size];
for ( int i = 0; i < val.set_val.size; ++i )
{
val.set_val.vals[i] = new LogVal;
if ( ! val.set_val.vals[i]->Read(fmt) )
return false;
}
return true;
}
default: default:
internal_error(::fmt("unsupported type %s in LogVal::Write", type_name(type))); internal_error(::fmt("unsupported type %s in LogVal::Write", type_name(type)));
} }
@ -205,6 +237,20 @@ bool LogVal::Write(SerializationFormat* fmt) const
case TYPE_STRING: case TYPE_STRING:
return fmt->Write(*val.string_val, "string"); return fmt->Write(*val.string_val, "string");
case TYPE_TABLE:
{
if ( ! fmt->Write(val.set_val.size, "set_size") )
return false;
for ( int i = 0; i < val.set_val.size; ++i )
{
if ( ! val.set_val.vals[i]->Write(fmt) )
return false;
}
return true;
}
default: default:
internal_error(::fmt("unsupported type %s in LogVal::REad", type_name(type))); internal_error(::fmt("unsupported type %s in LogVal::REad", type_name(type)));
} }
@ -402,14 +448,18 @@ bool LogMgr::TraverseRecord(Filter* filter, RecordType* rt, TableVal* include, T
// Recurse. // Recurse.
if ( ! TraverseRecord(filter, t->AsRecordType(), include, exclude, new_path, new_indices) ) if ( ! TraverseRecord(filter, t->AsRecordType(), include, exclude, new_path, new_indices) )
return false; return false;
continue;
} }
else else if ( t->Tag() == TYPE_TABLE && t->AsTableType()->IsSet() )
{ {
// That's ok, handle it with all the other types below.
}
else {
run_time("unsupported field type for log column"); run_time("unsupported field type for log column");
return false; return false;
} }
continue;
} }
// If include fields are specified, only include if explicitly listed. // If include fields are specified, only include if explicitly listed.
@ -701,6 +751,70 @@ bool LogMgr::Write(EnumVal* id, RecordVal* columns)
return true; return true;
} }
LogVal* LogMgr::ValToLogVal(Val* val)
{
LogVal* lval = new LogVal(val->Type()->Tag());
switch ( lval->type ) {
case TYPE_BOOL:
case TYPE_INT:
case TYPE_ENUM:
lval->val.int_val = val->InternalInt();
break;
case TYPE_COUNT:
case TYPE_COUNTER:
lval->val.uint_val = val->InternalUnsigned();
break;
case TYPE_PORT:
lval->val.uint_val = val->AsPortVal()->Port();
break;
case TYPE_SUBNET:
lval->val.subnet_val = *val->AsSubNet();
break;
case TYPE_NET:
case TYPE_ADDR:
{
addr_type t = val->AsAddr();
copy_addr(&t, &lval->val.addr_val);
break;
}
case TYPE_DOUBLE:
case TYPE_TIME:
case TYPE_INTERVAL:
lval->val.double_val = val->InternalDouble();
break;
case TYPE_STRING:
{
const BroString* s = val->AsString();
lval->val.string_val = new string((const char*) s->Bytes(), s->Len());
break;
}
case TYPE_TABLE:
{
ListVal* set = val->AsTableVal()->ConvertToPureList();
lval->val.set_val.size = set->Length();
lval->val.set_val.vals = new LogVal* [lval->val.set_val.size];
for ( int i = 0; i < lval->val.set_val.size; i++ )
lval->val.set_val.vals[i] = ValToLogVal(set->Index(i));
break;
}
default:
internal_error("unsupported type for log_write");
}
return lval;
}
LogVal** LogMgr::RecordToFilterVals(Filter* filter, RecordVal* columns) LogVal** LogMgr::RecordToFilterVals(Filter* filter, RecordVal* columns)
{ {
LogVal** vals = new LogVal*[filter->num_fields]; LogVal** vals = new LogVal*[filter->num_fields];
@ -727,55 +841,8 @@ LogVal** LogMgr::RecordToFilterVals(Filter* filter, RecordVal* columns)
} }
} }
if ( ! val ) if ( val )
continue; vals[i] = ValToLogVal(val);
vals[i] = new LogVal(type);
switch ( val->Type()->Tag() ) {
case TYPE_BOOL:
case TYPE_INT:
case TYPE_ENUM:
vals[i]->val.int_val = val->InternalInt();
break;
case TYPE_COUNT:
case TYPE_COUNTER:
vals[i]->val.uint_val = val->InternalUnsigned();
break;
case TYPE_PORT:
vals[i]->val.uint_val = val->AsPortVal()->Port();
break;
case TYPE_SUBNET:
vals[i]->val.subnet_val = *val->AsSubNet();
break;
case TYPE_NET:
case TYPE_ADDR:
{
addr_type t = val->AsAddr();
copy_addr(&t, &vals[i]->val.addr_val);
break;
}
case TYPE_DOUBLE:
case TYPE_TIME:
case TYPE_INTERVAL:
vals[i]->val.double_val = val->InternalDouble();
break;
case TYPE_STRING:
{
const BroString* s = val->AsString();
vals[i]->val.string_val = new string((const char*) s->Bytes(), s->Len());
break;
}
default:
internal_error("unsupported type for log_write");
}
} }
return vals; return vals;

View file

@ -36,17 +36,20 @@ struct LogVal {
// The following union is a subset of BroValUnion, including only the // The following union is a subset of BroValUnion, including only the
// atomic types. // atomic types.
union { struct set_t { bro_int_t size; LogVal** vals; };
union _val {
bro_int_t int_val; bro_int_t int_val;
bro_uint_t uint_val; bro_uint_t uint_val;
addr_type addr_val; addr_type addr_val;
subnet_type subnet_val; subnet_type subnet_val;
double double_val; double double_val;
string* string_val; string* string_val;
set_t set_val;
} val; } val;
LogVal(TypeTag arg_type = TYPE_ERROR, bool arg_present = true) : type(arg_type), present(arg_present) {} LogVal(TypeTag arg_type = TYPE_ERROR, bool arg_present = true) : type(arg_type), present(arg_present) {}
~LogVal() { if ( type == TYPE_STRING && present ) delete val.string_val; } ~LogVal();
bool Read(SerializationFormat* fmt); bool Read(SerializationFormat* fmt);
bool Write(SerializationFormat* fmt) const; bool Write(SerializationFormat* fmt) const;
@ -97,6 +100,7 @@ private:
struct WriterInfo; struct WriterInfo;
bool TraverseRecord(Filter* filter, RecordType* rt, TableVal* include, TableVal* exclude, string path, list<int> indices); bool TraverseRecord(Filter* filter, RecordType* rt, TableVal* include, TableVal* exclude, string path, list<int> indices);
LogVal* ValToLogVal(Val* val);
LogVal** RecordToFilterVals(Filter* filter, RecordVal* columns); LogVal** RecordToFilterVals(Filter* filter, RecordVal* columns);
Stream* FindStream(EnumVal* id); Stream* FindStream(EnumVal* id);
void RemoveDisabledWriters(Stream* stream); void RemoveDisabledWriters(Stream* stream);

View file

@ -16,6 +16,10 @@ LogWriterAscii::LogWriterAscii()
separator = new char[separator_len]; separator = new char[separator_len];
memcpy(separator, BifConst::LogAscii::separator->Bytes(), separator_len); memcpy(separator, BifConst::LogAscii::separator->Bytes(), separator_len);
set_separator_len = BifConst::LogAscii::set_separator->Len();
set_separator = new char[set_separator_len];
memcpy(set_separator, BifConst::LogAscii::set_separator->Bytes(), set_separator_len);
empty_field_len = BifConst::LogAscii::empty_field->Len(); empty_field_len = BifConst::LogAscii::empty_field->Len();
empty_field = new char[empty_field_len]; empty_field = new char[empty_field_len];
memcpy(empty_field, BifConst::LogAscii::empty_field->Bytes(), empty_field_len); memcpy(empty_field, BifConst::LogAscii::empty_field->Bytes(), empty_field_len);
@ -27,6 +31,7 @@ LogWriterAscii::LogWriterAscii()
header_prefix_len = BifConst::LogAscii::header_prefix->Len(); header_prefix_len = BifConst::LogAscii::header_prefix->Len();
header_prefix = new char[header_prefix_len]; header_prefix = new char[header_prefix_len];
memcpy(header_prefix, BifConst::LogAscii::header_prefix->Bytes(), header_prefix_len); memcpy(header_prefix, BifConst::LogAscii::header_prefix->Bytes(), header_prefix_len);
} }
LogWriterAscii::~LogWriterAscii() LogWriterAscii::~LogWriterAscii()
@ -35,6 +40,7 @@ LogWriterAscii::~LogWriterAscii()
fclose(file); fclose(file);
delete [] separator; delete [] separator;
delete [] set_separator;
delete [] empty_field; delete [] empty_field;
delete [] unset_field; delete [] unset_field;
delete [] header_prefix; delete [] header_prefix;
@ -89,6 +95,86 @@ void LogWriterAscii::DoFinish()
{ {
} }
bool LogWriterAscii::DoWriteOne(ODesc* desc, LogVal* val, const LogField* field)
{
if ( ! val->present )
{
desc->AddN(unset_field, unset_field_len);
return true;
}
switch ( val->type ) {
case TYPE_BOOL:
desc->Add(val->val.int_val ? "T" : "F");
break;
case TYPE_INT:
case TYPE_ENUM:
desc->Add(val->val.int_val);
break;
case TYPE_COUNT:
case TYPE_COUNTER:
case TYPE_PORT:
desc->Add(val->val.uint_val);
break;
case TYPE_SUBNET:
desc->Add(dotted_addr(val->val.subnet_val.net));
desc->Add("/");
desc->Add(val->val.subnet_val.width);
break;
case TYPE_NET:
case TYPE_ADDR:
desc->Add(dotted_addr(val->val.addr_val));
break;
case TYPE_DOUBLE:
case TYPE_TIME:
case TYPE_INTERVAL:
desc->Add(val->val.double_val);
break;
case TYPE_STRING:
{
int size = val->val.string_val->size();
if ( size )
desc->AddN(val->val.string_val->data(), val->val.string_val->size());
else
desc->AddN(empty_field, empty_field_len);
break;
}
case TYPE_TABLE:
{
if ( ! val->val.set_val.size )
{
desc->AddN(empty_field, empty_field_len);
break;
}
for ( int j = 0; j < val->val.set_val.size; j++ )
{
if ( j > 0 )
desc->AddN(set_separator, set_separator_len);
if ( ! DoWriteOne(desc, val->val.set_val.vals[j], field) )
return false;
}
break;
}
default:
Error(Fmt("unsupported field format %d for %s", val->type, field->name.c_str()));
return false;
}
return true;
}
bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, LogVal** vals) bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, LogVal** vals)
{ {
ODesc desc(DESC_READABLE); ODesc desc(DESC_READABLE);
@ -99,63 +185,9 @@ bool LogWriterAscii::DoWrite(int num_fields, const LogField* const * fields, Log
if ( i > 0 ) if ( i > 0 )
desc.AddRaw(separator, separator_len); desc.AddRaw(separator, separator_len);
LogVal* val = vals[i]; if ( ! DoWriteOne(&desc, vals[i], fields[i]) )
const LogField* field = fields[i];
if ( ! val->present )
{
desc.AddN(unset_field, unset_field_len);
continue;
}
switch ( field->type ) {
case TYPE_BOOL:
desc.Add(val->val.int_val ? "T" : "F");
break;
case TYPE_INT:
case TYPE_ENUM:
desc.Add(val->val.int_val);
break;
case TYPE_COUNT:
case TYPE_COUNTER:
case TYPE_PORT:
desc.Add(val->val.uint_val);
break;
case TYPE_SUBNET:
desc.Add(dotted_addr(val->val.subnet_val.net));
desc.Add("/");
desc.Add(val->val.subnet_val.width);
break;
case TYPE_NET:
case TYPE_ADDR:
desc.Add(dotted_addr(val->val.addr_val));
break;
case TYPE_DOUBLE:
case TYPE_TIME:
case TYPE_INTERVAL:
desc.Add(val->val.double_val);
break;
case TYPE_STRING:
{
int size = val->val.string_val->size();
if ( size )
desc.AddN(val->val.string_val->data(), val->val.string_val->size());
else
desc.AddN(empty_field, empty_field_len);
break;
}
default:
Error(Fmt("unsupported field format %d for %s", field->type, field->name.c_str()));
return false; return false;
} }
}
desc.Add("\n"); desc.Add("\n");

View file

@ -24,6 +24,7 @@ protected:
private: private:
bool IsSpecial(string path) { return path.find("/dev/") == 0; } bool IsSpecial(string path) { return path.find("/dev/") == 0; }
bool DoWriteOne(ODesc* desc, LogVal* val, const LogField* field);
FILE* file; FILE* file;
string fname; string fname;
@ -35,6 +36,9 @@ private:
char* separator; char* separator;
int separator_len; int separator_len;
char* set_separator;
int set_separator_len;
char* empty_field; char* empty_field;
int empty_field_len; int empty_field_len;

View file

@ -69,6 +69,7 @@ const output_to_stdout: bool;
const include_header: bool; const include_header: bool;
const header_prefix: string; const header_prefix: string;
const separator: string; const separator: string;
const set_separator: string;
const empty_field: string; const empty_field: string;
const unset_field: string; const unset_field: string;

View file

@ -0,0 +1,90 @@
#
# @TEST-EXEC: btest-bg-run sender bro --pseudo-realtime %INPUT ../sender.bro
# @TEST-EXEC: sleep 1
# @TEST-EXEC: btest-bg-run receiver bro --pseudo-realtime %INPUT ../receiver.bro
# @TEST-EXEC: sleep 1
# @TEST-EXEC: btest-bg-wait -k 1
# @TEST-EXEC: btest-diff receiver/ssh.log
# @TEST-EXEC: cmp receiver/ssh.log sender/ssh.log
# Remote version testing all types.
# This is the common part loaded by both sender and receiver.
redef LogAscii::empty_field = "EMPTY";
module SSH;
export {
# Create a new ID for our log stream
redef enum Log::ID += { SSH };
type Log: record {
b: bool;
i: int;
e: Log::ID;
c: count;
p: port;
sn: subnet;
n: net;
a: addr;
d: double;
t: time;
iv: interval;
s: string;
sc: set[count];
ss: set[string];
se: set[string];
};
}
global log_ssh: event(rec: Log);
event bro_init()
{
Log::create_stream(SSH, [$columns=Log, $ev=log_ssh]);
}
#####
@TEST-START-FILE sender.bro
module SSH;
@load listen-clear
event remote_connection_handshake_done(p: event_peer)
{
local empty_set: set[string];
Log::write(SSH, [
$b=T,
$i=-42,
$e=SSH,
$c=21,
$p=123/tcp,
$sn=10.0.0.1/24,
$n=10.0.,
$a=1.2.3.4,
$d=3.14,
$t=network_time(),
$iv=100secs,
$s="hurz",
$sc=set(1,2,3,4),
$ss=set("AA", "BB", "CC"),
$se=empty_set
]);
}
@TEST-END-FILE
@TEST-START-FILE receiver.bro
#####
@load remote
redef Remote::destinations += {
["foo"] = [$host = 127.0.0.1, $connect=T, $request_logs=T]
};
@TEST-END-FILE

View file

@ -0,0 +1,57 @@
#
# @TEST-EXEC: bro %INPUT
# @TEST-EXEC: btest-diff ssh.log
#
# Testing all possible types.
redef LogAscii::empty_field = "EMPTY";
module SSH;
export {
redef enum Log::ID += { SSH };
type Log: record {
b: bool;
i: int;
e: Log::ID;
c: count;
p: port;
sn: subnet;
n: net;
a: addr;
d: double;
t: time;
iv: interval;
s: string;
sc: set[count];
ss: set[string];
se: set[string];
};
}
event bro_init()
{
Log::create_stream(SSH, [$columns=Log]);
local empty_set: set[string];
Log::write(SSH, [
$b=T,
$i=-42,
$e=SSH,
$c=21,
$p=123/tcp,
$sn=10.0.0.1/24,
$n=10.0.,
$a=1.2.3.4,
$d=3.14,
$t=network_time(),
$iv=100secs,
$s="hurz",
$sc=set(1,2,3,4),
$ss=set("AA", "BB", "CC"),
$se=empty_set
]);
}