diff --git a/CHANGES b/CHANGES index 9f158041f0..f976ec6f47 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +1.6-dev-1505 | 2011-10-26 14:43:58 -0700 + + * A new base script that pretty-prints alarms in the regular + summary. (Robin Sommer) + + * Adding a dummy log writer WRITER_NONE that just discards + everything. (Robin Sommer) + 1.6-dev-1498 | 2011-10-26 14:30:15 -0700 * Adding instructions to local.bro how to do ACTION_ALARM by diff --git a/VERSION b/VERSION index 429661cfeb..629da350b7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.6-dev-1498 +1.6-dev-1505 diff --git a/scripts/base/frameworks/notice/__load__.bro b/scripts/base/frameworks/notice/__load__.bro index 08a99c5a5b..4548e98dc2 100644 --- a/scripts/base/frameworks/notice/__load__.bro +++ b/scripts/base/frameworks/notice/__load__.bro @@ -18,3 +18,6 @@ @if ( Cluster::is_enabled() ) @load ./cluster @endif + +# Load here so that it can check whether clustering is enabled. +@load ./actions/pp-alarms diff --git a/scripts/base/frameworks/notice/actions/pp-alarms.bro b/scripts/base/frameworks/notice/actions/pp-alarms.bro new file mode 100644 index 0000000000..f3a4fac9fd --- /dev/null +++ b/scripts/base/frameworks/notice/actions/pp-alarms.bro @@ -0,0 +1,179 @@ +#! Notice extension that mails out a pretty-printed version of alarm.log +#! in regular intervals, formatted for better human readability. If activated, +#! that replaces the default summary mail having the raw log output. + +module Notice; + +export { + ## Activate pretty-printed alarm summaries. + const pretty_print_alarms = T &redef; + + ## Address to send the pretty-printed reports to. Default if not set is + ## :bro:id:`Notice::mail_dest`. + const mail_dest_pretty_printed = "" &redef; + + ## If an address from one of these networks is reported, we mark + ## the entry with an addition quote symbol (i.e., ">"). Many MUAs + ## then highlight such lines differently. + global flag_nets: set[subnet] &redef; + + ## Function that renders a single alarm. Can be overidden. + global pretty_print_alarm: function(out: file, n: Info) &redef; +} + +# We maintain an old-style file recording the pretty-printed alarms. +const pp_alarms_name = "alarm-mail.txt"; +global pp_alarms: file; +global pp_alarms_open: bool = F; + +# Returns True if pretty-printed alarm summaries are activated. +function want_pp() : bool + { + return (pretty_print_alarms && ! reading_traces() + && (mail_dest != "" || mail_dest_pretty_printed != "")); + } + +# Opens and intializes the output file. +function pp_open() + { + if ( pp_alarms_open ) + return; + + pp_alarms_open = T; + pp_alarms = open(pp_alarms_name); + + local dest = mail_dest_pretty_printed != "" ? mail_dest_pretty_printed + : mail_dest; + + local headers = email_headers("Alarm summary", dest); + write_file(pp_alarms, headers + "\n"); + } + +# Closes and mails out the current output file. +function pp_send() + { + if ( ! pp_alarms_open ) + return; + + write_file(pp_alarms, "\n\n--\n[Automatically generated]\n\n"); + close(pp_alarms); + + system(fmt("/bin/cat %s | %s -t -oi && /bin/rm %s", + pp_alarms_name, sendmail, pp_alarms_name)); + + pp_alarms_open = F; + } + +# Postprocessor function that triggers the email. +function pp_postprocessor(info: Log::RotationInfo): bool + { + if ( want_pp() ) + pp_send(); + + return T; + } + +event bro_init() + { + if ( ! want_pp() ) + return; + + # This replaces the standard non-pretty-printing filter. + Log::add_filter(Notice::ALARM_LOG, + [$name="alarm-mail", $writer=Log::WRITER_NONE, + $interv=Log::default_rotation_interval, + $postprocessor=pp_postprocessor]); + } + +event notice(n: Notice::Info) &priority=-5 + { + if ( ! want_pp() ) + return; + + if ( ACTION_LOG !in n$actions ) + return; + + if ( ! pp_alarms_open ) + pp_open(); + + pretty_print_alarm(pp_alarms, n); + } + +function do_msg(out: file, n: Info, line1: string, line2: string, line3: string, host: addr, name: string) + { + if ( host != 0.0.0.0 ) + { + local country = ""; + if ( n?$remote_location && n$remote_location?$country_code ) + country = fmt(" (%s)", n$remote_location$country_code); + + name = fmt(" %s = %s%s", host, name, country); + } + + + line1 = cat(line1, name); + + print out, line1; + print out, line2; + if ( line3 != "" ) + print out, line3; + } + +# Default pretty-printer. +function pretty_print_alarm(out: file, n: Info) + { + local pdescr = ""; + +@if ( Cluster::is_enabled() ) + pdescr = "local"; + + if ( n?$src_peer ) + pdescr = n$src_peer?$descr ? n$src_peer$descr : fmt("%s", n$src_peer$host); + + pdescr = fmt("<%s> ", pdescr); +@endif + + local msg = fmt( "%s%s%s", pdescr, n$msg, n?$sub ? cat(" ", n$sub) : ""); + + local orig = 0.0.0.0; + local resp = 0.0.0.0; + local host = 0.0.0.0; + + if ( n?$src ) + orig = host = n$src; + + if ( n?$id ) + { + orig = n$id$orig_h; + resp = n$id$resp_h; + } + + if ( host == 0.0.0.0 ) + host = orig; + + local flag = (orig in flag_nets || resp in flag_nets); + + local location = ""; + + if ( host != 0.0.0.0 ) + location = Site::is_local_addr(host) ? "(L)" : "(R)"; + + local line1 = fmt(">%s %D %s %s", (flag ? ">" : " "), network_time(), n$note, location); + local line2 = fmt(" %s", msg); + local line3 = ""; # Could use later. + + if ( host == 0.0.0.0 ) + { + do_msg(out, n, line1, line2, line3, 0.0.0.0, ""); + return; + } + + when ( local name = lookup_addr(host) ) + { + do_msg(out, n, line1, line2, line3, host, name); + } + timeout 5secs + { + do_msg(out, n, line1, line2, line3, host, "(dns timeout)"); + } + } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c785bddc8..b4779e1557 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -335,6 +335,7 @@ set(bro_SRCS LogMgr.cc LogWriter.cc LogWriterAscii.cc + LogWriterNone.cc Login.cc MIME.cc NCP.cc diff --git a/src/LogMgr.cc b/src/LogMgr.cc index 4fde5d3189..9e320f8810 100644 --- a/src/LogMgr.cc +++ b/src/LogMgr.cc @@ -9,6 +9,7 @@ #include "Net.h" #include "LogWriterAscii.h" +#include "LogWriterNone.h" // Structure describing a log writer type. struct LogWriterDefinition { @@ -20,6 +21,7 @@ struct LogWriterDefinition { // Static table defining all availabel log writers. LogWriterDefinition log_writers[] = { + { BifEnum::Log::WRITER_NONE, "None", 0, LogWriterNone::Instantiate }, { BifEnum::Log::WRITER_ASCII, "Ascii", 0, LogWriterAscii::Instantiate }, // End marker, don't touch. diff --git a/src/LogWriterNone.cc b/src/LogWriterNone.cc new file mode 100644 index 0000000000..592772afdb --- /dev/null +++ b/src/LogWriterNone.cc @@ -0,0 +1,16 @@ + +#include "LogWriterNone.h" + +bool LogWriterNone::DoRotate(string rotated_path, double open, + double close, bool terminating) + { + if ( ! FinishedRotation(string("/dev/null"), Path(), open, close, terminating)) + { + Error(Fmt("error rotating %s", Path().c_str())); + return false; + } + + return true; + } + + diff --git a/src/LogWriterNone.h b/src/LogWriterNone.h new file mode 100644 index 0000000000..3811a19469 --- /dev/null +++ b/src/LogWriterNone.h @@ -0,0 +1,30 @@ +// See the file "COPYING" in the main distribution directory for copyright. +// +// Dummy log writer that just discards everything (but still pretends to rotate). + +#ifndef LOGWRITERNONE_H +#define LOGWRITERNONE_H + +#include "LogWriter.h" + +class LogWriterNone : public LogWriter { +public: + LogWriterNone() {} + ~LogWriterNone() {}; + + static LogWriter* Instantiate() { return new LogWriterNone; } + +protected: + virtual bool DoInit(string path, int num_fields, + const LogField* const * fields) { return true; } + + virtual bool DoWrite(int num_fields, const LogField* const * fields, + LogVal** vals) { return true; } + virtual bool DoSetBuf(bool enabled) { return true; } + virtual bool DoRotate(string rotated_path, double open, double close, + bool terminating); + virtual bool DoFlush() { return true; } + virtual void DoFinish() {} +}; + +#endif diff --git a/src/types.bif b/src/types.bif index 8bc5ab8510..da6bd6e031 100644 --- a/src/types.bif +++ b/src/types.bif @@ -159,6 +159,7 @@ module Log; enum Writer %{ WRITER_DEFAULT, + WRITER_NONE, WRITER_ASCII, %}