diff --git a/TODO.logging b/TODO.logging index 3e612eab5a..5ddca90ec7 100644 --- a/TODO.logging +++ b/TODO.logging @@ -10,10 +10,6 @@ List of the things not implemented yet: - "redef LogAscii::separator = '\t'" - "redef LogAscii::headers = T" - - Extended filter manipualtion interface on the script level: - - Disalbe stream altogether. - - Change individual options of an existing filter. - Notes about remote logging: - The receiver must create the stream locally via diff --git a/policy/logging.bro b/policy/logging.bro index e362435cf4..07baa98902 100644 --- a/policy/logging.bro +++ b/policy/logging.bro @@ -98,6 +98,8 @@ export { const no_filter: Filter = [$name=""]; # Sentinel. global create_stream: function(id: ID, stream: Stream) : bool; + global enable_stream: function(id: ID) : bool; + global disable_stream: function(id: ID) : bool; global add_filter: function(id: ID, filter: Filter) : bool; global remove_filter: function(id: ID, name: string) : bool; global get_filter: function(id: ID, name: string) : Filter; # Returns no_filter if not found. @@ -128,6 +130,12 @@ function create_stream(id: ID, stream: Stream) : bool return add_default_filter(id); } + +function disable_stream(id: ID) : bool + { + if ( ! __disable_stream(id) ) + return F; + } function add_filter(id: ID, filter: Filter) : bool { diff --git a/src/LogMgr.cc b/src/LogMgr.cc index 76feb0e0ea..0873ca991e 100644 --- a/src/LogMgr.cc +++ b/src/LogMgr.cc @@ -48,6 +48,7 @@ struct LogMgr::WriterInfo { struct LogMgr::Stream { EnumVal* id; + bool enabled; string name; RecordType* columns; EventHandlerPtr event; @@ -335,6 +336,7 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) // Create new stream. streams[idx] = new Stream; streams[idx]->id = id->Ref()->AsEnumVal(); + streams[idx]->enabled = true; streams[idx]->name = id->Type()->AsEnumType()->Lookup(idx); streams[idx]->event = event ? event_registry->Lookup(event->GetID()->Name()) : 0; streams[idx]->columns = columns->Ref()->AsRecordType(); @@ -344,6 +346,36 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) return true; } +bool LogMgr::EnableStream(EnumVal* id) + { + Stream* stream = FindStream(id); + if ( ! stream ) + return false; + + if ( stream->enabled ) + return true; + + stream->enabled = true; + + DBG_LOG(DBG_LOGGING, "Reenabled logging stream '%s'", stream->name.c_str()); + return true; + } + +bool LogMgr::DisableStream(EnumVal* id) + { + Stream* stream = FindStream(id); + if ( ! stream ) + return false; + + if ( ! stream->enabled ) + return true; + + stream->enabled = false; + + DBG_LOG(DBG_LOGGING, "Disabled logging stream '%s'", stream->name.c_str()); + return true; + } + // Helper for recursive record field unrolling. bool LogMgr::TraverseRecord(Filter* filter, RecordType* rt, TableVal* include, TableVal* exclude, string path, list indices) { @@ -554,6 +586,9 @@ bool LogMgr::Write(EnumVal* id, RecordVal* columns) if ( ! stream ) return false; + if ( ! stream->enabled ) + return true; + columns = columns->CoerceTo(stream->columns); if ( ! columns ) @@ -833,6 +868,9 @@ bool LogMgr::Write(EnumVal* id, EnumVal* writer, string path, int num_fields, Lo return false; } + if ( ! stream->enabled ) + return true; + Stream::WriterMap::iterator w = stream->writers.find(Stream::WriterPathPair(writer->AsEnum(), path)); if ( w == stream->writers.end() ) @@ -891,6 +929,9 @@ bool LogMgr::Flush(EnumVal* id) if ( ! stream ) return false; + if ( ! stream->enabled ) + return true; + for ( Stream::WriterMap::iterator i = stream->writers.begin(); i != stream->writers.end(); i++ ) i->second->writer->Flush(); diff --git a/src/LogMgr.h b/src/LogMgr.h index 3a356b4e88..8f8d991c00 100644 --- a/src/LogMgr.h +++ b/src/LogMgr.h @@ -67,6 +67,8 @@ public: // These correspond to the BiFs visible on the scripting layer. The // actual BiFs just forward here. bool CreateStream(EnumVal* id, RecordVal* stream); + bool EnableStream(EnumVal* id); + bool DisableStream(EnumVal* id); bool AddFilter(EnumVal* id, RecordVal* filter); bool RemoveFilter(EnumVal* id, StringVal* name); bool RemoveFilter(EnumVal* id, string name); diff --git a/src/logging.bif b/src/logging.bif index 0babf75a06..a4b56bb8d3 100644 --- a/src/logging.bif +++ b/src/logging.bif @@ -19,6 +19,18 @@ function Log::__create_stream%(id: Log::ID, stream: Log::Stream%) : bool return new Val(result, TYPE_BOOL); %} +function Log::__enable_stream%(id: Log::ID%) : bool + %{ + bool result = log_mgr->EnableStream(id->AsEnumVal()); + return new Val(result, TYPE_BOOL); + %} + +function Log::__disable_stream%(id: Log::ID%) : bool + %{ + bool result = log_mgr->DisableStream(id->AsEnumVal()); + return new Val(result, TYPE_BOOL); + %} + function Log::__add_filter%(id: Log::ID, filter: Log::Filter%) : bool %{ bool result = log_mgr->AddFilter(id->AsEnumVal(), filter->AsRecordVal()); diff --git a/testing/btest/logging/disable-stream.bro b/testing/btest/logging/disable-stream.bro new file mode 100644 index 0000000000..97b47298e9 --- /dev/null +++ b/testing/btest/logging/disable-stream.bro @@ -0,0 +1,33 @@ +# +# @TEST-EXEC: bro %INPUT +# @TEST-EXEC: test '!' -e ssh.log + +module SSH; + +export { + redef enum Log::ID += { SSH }; + + type Log: record { + t: time; + id: conn_id; # Will be rolled out into individual columns. + status: string &optional; + country: string &default="unknown"; + }; +} + +event bro_init() +{ + Log::create_stream(SSH, [$columns=Log]); + + Log::disable_stream(SSH); + + local cid = [$orig_h=1.2.3.4, $orig_p=1234/tcp, $resp_h=2.3.4.5, $resp_p=80/tcp]; + + Log::write(SSH, [$t=network_time(), $id=cid, $status="success"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="US"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="UK"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="success", $country="BR"]); + Log::write(SSH, [$t=network_time(), $id=cid, $status="failure", $country="MX"]); + +} +