mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
Checkpoint for logging framework
This commit is contained in:
parent
aa0691ba21
commit
f3b148b019
5 changed files with 139 additions and 1 deletions
93
policy/logging.bro
Normal file
93
policy/logging.bro
Normal file
|
@ -0,0 +1,93 @@
|
|||
module Logging;
|
||||
|
||||
export {
|
||||
# The set of writers Bro provides.
|
||||
type Writer: enum {
|
||||
WRITER_DEFAULT, # See default_writer below.
|
||||
WRITER_CSV,
|
||||
WRITER_DATA_SERIES,
|
||||
WRITER_SYSLOG
|
||||
};
|
||||
|
||||
# Each stream gets a unique ID. This type will be extended by
|
||||
# other scripts.
|
||||
type ID: enum {
|
||||
Unknown
|
||||
};
|
||||
|
||||
# The default writer to use if a filter does not specify
|
||||
# anything else.
|
||||
const default_writer = WRITER_CSV &redef;
|
||||
|
||||
# Type defining a stream.
|
||||
type Stream: record {
|
||||
id : ID; # The ID of the stream.
|
||||
columns : any; # A record type defining the stream's output columns.
|
||||
};
|
||||
|
||||
# A filter defining what to record.
|
||||
type Filter: record {
|
||||
# A name to reference this filter.
|
||||
name: string;
|
||||
|
||||
# A predicate returning True if the filter wants a log entry
|
||||
# to be recorded. If not given, an implicit True is assumed
|
||||
# for all entries. The predicate receives one parameter:
|
||||
# an instance of the log's record type with the fields to be
|
||||
# logged.
|
||||
pred: function(log: any) &optional;
|
||||
|
||||
# A path for outputting everything matching this
|
||||
# filter. The path is either a string, or a function
|
||||
# called with a single ``ID`` argument and returning a string.
|
||||
#
|
||||
# The specific interpretation of the string is left to the
|
||||
# Writer, but if it's refering to a file, it's assumed that no
|
||||
# extension is given; the writer will add whatever is
|
||||
# appropiate.
|
||||
path: any &optional;
|
||||
|
||||
# A subset of column names to record. If not given, all
|
||||
# columns are recorded.
|
||||
select: set[string] &optional;
|
||||
|
||||
# An event that is raised whenever the filter is applied
|
||||
# to an entry. The event receives the same parameter
|
||||
# as the predicate. It will always be generated,
|
||||
# independent of what the predicate returns.
|
||||
ev: event(c: connection, log: any) &optional;
|
||||
|
||||
# The writer to use.
|
||||
writer: Writer &default=default_writer;
|
||||
};
|
||||
|
||||
global filters: table[ID] of set[Filter];
|
||||
|
||||
# Logs the record "rec" to the stream "id". The type of
|
||||
# "rec" must match the stream's "columns" field.
|
||||
global log: function(id: ID, rec: any);
|
||||
|
||||
# Returns an existing filter previously installed for stream
|
||||
# "id" under the given "name". If no such filter exists,
|
||||
# the record "NoSuchFilter" is returned.
|
||||
global get_filter: function(id: ID, name: string) : Filter;
|
||||
|
||||
global create: function(stream: Stream);
|
||||
global add_filter: function(id: ID, filter: Filter);
|
||||
}
|
||||
|
||||
# Sentinel representing an unknown filter.
|
||||
const NoSuchFilter: Filter = [$name="<unknown filter>"];
|
||||
|
||||
function add_filter(id: ID, filter: Filter)
|
||||
{
|
||||
if ( id !in filters )
|
||||
filters[id] = set();
|
||||
|
||||
add filters[id][filter];
|
||||
}
|
||||
|
||||
function log(id: ID, rec: any)
|
||||
{
|
||||
logging_log(id, rec);
|
||||
}
|
27
policy/test-logging.bro
Normal file
27
policy/test-logging.bro
Normal file
|
@ -0,0 +1,27 @@
|
|||
module SSH;
|
||||
|
||||
@load logging
|
||||
|
||||
# Create a new ID for our log stream
|
||||
redef enum Logging::ID += { SSH };
|
||||
|
||||
# Define a record with all the columns the log file can have.
|
||||
# (I'm using a subset of fields from ssh-ext for demonstration.)
|
||||
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()
|
||||
{
|
||||
# Create the stream.
|
||||
Logging::create([$id=SSH, $columns=Log]);
|
||||
|
||||
# Add a default filter that simply logs everything to "ssh.log" using the default writer.
|
||||
#Logging::add_filter(SSH, [$name="default", $path="ssh"]);
|
||||
}
|
||||
|
||||
# Log something.
|
||||
Logging::log(SSH, [$t=network_time(), $status="ok"]);
|
|
@ -1336,7 +1336,9 @@ static int is_init_compat(const BroType* t1, const BroType* t2)
|
|||
|
||||
int same_type(const BroType* t1, const BroType* t2, int is_init)
|
||||
{
|
||||
if ( t1 == t2 )
|
||||
if ( t1 == t2 ||
|
||||
t1->Tag() == TYPE_ANY ||
|
||||
t2->Tag() == TYPE_ANY )
|
||||
return 1;
|
||||
|
||||
t1 = flatten_type(t1);
|
||||
|
|
|
@ -3301,6 +3301,10 @@ Val* check_and_promote(Val* v, const BroType* t, int is_init)
|
|||
TypeTag t_tag = t->Tag();
|
||||
TypeTag v_tag = vt->Tag();
|
||||
|
||||
// More thought definitely needs to go into this.
|
||||
if ( t_tag == TYPE_ANY || v_tag == TYPE_ANY )
|
||||
return v;
|
||||
|
||||
if ( ! EitherArithmetic(t_tag, v_tag) ||
|
||||
/* allow sets as initializers */
|
||||
(is_init && v_tag == TYPE_TABLE) )
|
||||
|
|
12
src/bro.bif
12
src/bro.bif
|
@ -360,6 +360,18 @@ function cat%(...%): string
|
|||
return new StringVal(s);
|
||||
%}
|
||||
|
||||
function logging_log%(id: Logging_ID, rec: any%): bool
|
||||
%{
|
||||
// Generate the log line event
|
||||
// Lookup the log file
|
||||
TableVal *f = opt_internal_table("Logging::filters");
|
||||
TableVal *s = f->Lookup(id, 0)->AsTableVal();
|
||||
|
||||
// For each filter on 'id'
|
||||
// Format the output
|
||||
// Print the line
|
||||
%}
|
||||
|
||||
function cat_sep%(sep: string, def: string, ...%): string
|
||||
%{
|
||||
ODesc d;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue