[Bro] Converting a Bro Script to A New Stream

Chris Crawford christopher.p.crawford at gmail.com
Mon Aug 20 06:43:15 PDT 2012


I was able to make some progress.  This script does what I want, but
there are still some problems.

module Foo;

export {
    redef enum Log::ID += { LOG };

    type Info: record {
        ts:                      time      &log;
        uid:                     string    &log;
        orig_ip:                 addr      &log;
        query:                   string    &log;
    };

}

event bro_init() &priority=5
    {
    Log::create_stream(Foo::LOG, [$columns=Info]);
    }

event DNS::log_dns(rec: DNS::Info)
    {
        if(rec$qtype_name == "A")
                if( |rec$answers| > 0 )
                        for( i in rec$answers )
                                if( "1.2.3.4" in rec$answers[i] )
                                        Log::write(Foo::LOG, [
$ts=rec$ts, $uid=rec$uid, $orig_ip=rec$id$orig_h, $query=rec$query]);
    }

I get the log I want, with the data I expect.

The problem is, I get thousands of entries in reporter.log that say:

"Reporter::ERROR field value missing [Foo::rec$qtype_name]"

And I get hundreds of entries that say:

"Reporter::ERROR field value missing [Foo::rec$answers]"

I think I'm getting these error messages because log_dns fires, but
rec is empty or doesn't exist.  How can I check my theory?  If that is
truly the case, is there a better way to write the initial logic in
event DNS::log_dns(rec: DNS::Info) that would break out of that
function if rec does not exist?  I thought that checking for DNS
answers and then checking to make sure that there is a positive number
of answers would help to eliminate the errors I see in reporter.log,
but it doesn't.

-Chris

On Thu, Aug 16, 2012 at 5:32 PM, Chris Crawford
<christopher.p.crawford at gmail.com> wrote:
> I have a short bro script that I wrote that hooks the DNS log
> (http://www.bro-ids.org/documentation/logging.html#hooking-into-the-logging).
>  Each time a DNS::log_dns event fires, if a specific IP is in
> rec$answers, the script prints out rec$ts, rec$uid, rec$id$orig_h, and
> rec$query.
>
> I want the entries from the script to go to their own log, though.  I
> am struggling to figure out how to make that work.  Based on the
> documentation for logging, it looks like I'd need to define a new
> Stream to create a new log file.
> (http://www.bro-ids.org/documentation/logging.html#adding-streams)
>
> Here's my original script that hooks the DNS logs:
>
> event DNS::log_dns(rec: DNS::Info)
>     {
>         for( i in rec$answers )
>                 if( "1.2.3.4" in rec$answers[i] )
>                         print fmt("%s %s %s %s", rec$ts, rec$uid,
> rec$id$orig_h, rec$query);
>     }
>
>
> To make this go to its own log, I tried this:
>
>
>
> module Foo;
>
> export {
>     # Create an ID for the our new stream. By convention, this is
>     # called "LOG".
>     redef enum Log::ID += { LOG };
>
>     # Define the fields. By convention, the type is called "Info".
>     type Info: record {
>         ts:                      time      &log;
>         uid:                     string    &log;
>         orig_ip:                 string    &log;
>         query:                   string    &log;
>     };
>
>     # Define a hook event. By convention, this is called
>     # "log_<stream>".
>     global log_foo: event(rec: Info);
>
> }
>
> redef record rec += {
>         foo: Info &optional;
> };
>
> # This event should be handled at a higher priority so that when
> # users modify your stream later and they do it at priority 0,
> # their code runs after this.
> event bro_init() &priority=5
>     {
>     # Create the stream. This also adds a default filter automatically.
>     Log::create_stream(Foo::LOG, [$columns=Info]);
>     }
>
> event DNS::log_dns(rec: DNS::Info)
>     {
>         for( i in rec$answers )
>                 if( "1.2.3.4" in rec$answers[i] )
>                         local rec: Foo::Info = [ $ts=rec$ts,
> $uid=rec$uid, $orig_h=rec$id$orig_h, $query=rec$query];
>                         rec$foo = rec;
>                         Log::write(Foo::LOG, rec);
>     }
>
> I get the errors:
>
> error in ./test.bro, line 22: unknown identifier (Foo::rec)
> error in ./test.bro, line 35 and ./test.bro, line 39: already defined (Foo::rec)
>
>
> I am new to writing Bro scripts.  Any pointers on what I'm doing wrong?
>
>
> -Chris



More information about the Bro mailing list