Bro Scripting Question

     I'm new to the world of Bro but I'm attempting to complete a small project for a graduate level class at the University of Illinois. The concept of the project is to define a set of policy files for a few core host services (SMTP, DNS, WEB SERVER). Each service specific policy file would ensure that only allowed hosts are running that service. The policy file would also ensure that each allowed host is only running a specified set of services. With that said, I started writing the policy files but had a few questions.

From what I can gather is seems like the new_connection event would be an obvious place to perform my checks since it is called for inbound and outbound connections. Does this sound like the correct approach? Also, is there a simple way to determine what service(s) a host is running (smtp, ssh, etc)? In other words, if a host is making an outbound connection is there any easy way to tie the traffic to a specific service? Right now I'm just logging connections but I'm wondering if there is an easier way to determine the service other then trying to tie port traffic to a potential service.

I would appreciate any suggestions or advice you could send my way. Thanks in advance - William Seemann

Check out the bro workshop a few years ago. They had you create a
learning policy that would baseline hosts and alarm on deviations.
Same could be done for the other policies I believe.

Seth will have some great insight though.


There is a script in the next release that is a variant on what you are looking to do. I even went back and fixed it recently since it was pretty badly broken.

Clone our git repository[1] and look at the script: scripts/policy/protocols/conn/known-services.bro [2]



Thank you, both of the responses I've received have been extremely helpful. I have another question. I read through snippets from the Bro documentation but I can't seem to find a way to generate an email alert in a script. I've redefined the "mail_dest" as follows:

redef Notice::mail_dest = "";

I can't seem to find a way to actually generate the email notification from within my script, all my attempts produce syntax errors. Can anyone suggest a script to look at? Thanks again, William

I can't seem to find a way to actually generate the email notification
from within my script, all my attempts produce syntax errors. Can anyone
suggest a script to look at? Thanks again, William

base/frameworks/notice/main.bro (from the git repos) might give you some hints at how to do it, but here's a couple examples.

If you'd like to make a certain type of notice (either a predefined or one you created) generate an email, you can augment the Notice::policy like this example:

redef Notice::mail_dest = "";

redef Notice::policy += {
    [$result = Notice::ACTION_EMAIL,
     $pred(n: Notice::Info) =
        { return n$note == PacketFilter::Dropped_Packets; }

Or if you really need a more raw way to generate a mail at any point in a script you could do something like:

event bro_init()
    local msg = Notice::email_headers("Test Email Subject", "");
    local body = "Here's the test email's body content.";
    msg = string_cat(msg, "\n", body);
    piped_exec(fmt("%s -t -oi", Notice::sendmail), msg);

Which would just send a mail once at startup.

- Jon

Ironically I finally started writing this documentation last night (the notice framework has been completely rewritten). If you have a particular notice that you want to send to send to email every time the notice is generated you can add the notice a set that acts like a shorthand for modifying your Notice::policy. Here's an example...

redef Notice::emailed_types += { HTTP::SQL_Injection_Attack_Against };


Can someone tell me if there is an easy way to detect of a connection is being made by a local host rather then an external one? For instance, if I have a cluster of machines and an instance of Bro running is there any easy way to distinguish connections made by these machines vs. external ones? Is maintaining a list of local hosts and performing a check (shown below) the only way to accomplish this?

if (c$id$resp_h !in local_hosts)
     do something...

There is a shorthand function for getting this information: is_local_addr. You give it an address and it returns T or F. In the upcoming release it has moved into the Site:: namespace though so it will be Site::is_local_addr (I don't know if you are working with the git master or 1.5.x). Regardless, you still need to be careful and give it the correct address to check. It sounds like this will work for you...

if ( is_local_addr(c$id$orig) )
  # do something

In order for is_local_addr function to work, you need to also be sure you have populated the local_nets variable (Site::local_nets in the repository). Here's an example:

redef local_nets += {, };