BroFabric 0.1


Overview
The BroFabric is a framework for multiple bro instances (nodes) to share event and notice information with one another.  In the current form, the notion of a central analyzer node and remote sensor nodes is built in to the design, but this is not a limitation of the underlying (bro intercommunication) software.

There are three basic components to the fabric:

BroShell: as described elsewhere, this will be used to query the state of the various nodes interactively, and do simple debugging.  The policy side changes to the shell will be added to the individual policy files (ie the fabric based components will be in brofabric.bro), while the shell software will be modified for the additional functionality.  See below for more details.

BroFabric
: The fabric layer is designed to contain static information about members of the current operational fabric.  Information (such as local IP ranges) are also held in this layer.  The basic idea is to separate the dynamic event data from what might be thought of as a naming or service data layer.

MetaEventLayer
: This layer contains all of the policy that is designed to operate on dynamic data provided by the individual node hosts.  Examples of this might be distributed NOTICE analysis.  Again, see below and attached policy for more details.


BroFabric
With the fabric we will assume that any host making a remote connection to the node described as the sensors interested in joining the fabric.  Adding additional registration (etc.) is trivial and can be implemented if the need arises. 

Fabric members are indexed by their event_peer id number, which should be unique per host.  As a strawman data structure, it currently looks like:

type fabric_member: record {
        EP: event_peer;         # information about the individual event peer
        domain: set[subnet];    # the addresses associated with the new fabric member
};

As data is determined to be useful per fabric entity, it can be added to this structure and functions created to extract it (see return_node_address() later as an example).  When a remote host (dis)connects, we use remote_connection_established and remote_connection_closed to load and unload hosts from the list of fabric members.  Ie:

event remote_connection_established(p: event_peer)
        {
        print("remote_connection_established");
        local FM: fabric_member;

        if ( p$id !in fabric_member_container && fabric_center )
                { # we need to add this
                FM$EP = p;
                fabric_member_container[p$id] = FM;
                # further information will be loaded in via events
               
                NOTICE([$note=FabricMemberAdd,
                        $msg=fmt("%0.6f Added id=%s, name=%s",
                        network_time(), p$id, p$descr)]);

                }
        }

Here 'fabric_center' is just a boolean which tells the current bro instance if it ought to keep track of connections and disconnects from itself.  Information can then be added to the fabric via additional events which touch structures within the fabric_member record.  For example, the local subnets of the remote bro instance can be added via register_local_address:

event register_local_address(p: event_peer, loc_sub: set[subnet])
        {
        local s: subnet;
        local FM: fabric_member;

        if ( p$id in fabric_member_container && fabric_center)
                {
                FM = fabric_member_container[p$id];

                for ( s in loc_sub )
                        {
                        add FM$domain[s];
                        }
                }
        }

Information can be extracted from the fabric via regular functions such as return_node_address :

function return_node_address(id:count) : addr
        {
        # here we are given one of the node id's and we return it's
        # IP address
        local tmpFM: fabric_member;
        local retAddr: addr;

        if ( id in fabric_member_container )
                {
                tmpFM = fabric_member_container[id];
                retAddr = tmpFM$EP$host;
                }
        else
                {
                # error condition
                retAddr = 0.0.0.0;
                }

        return retAddr;
        }


MetaEventLayer
The metaevent layer (which will be renamed when I come up with something better) is the component that actually does most of the work.  The initial proof of concept for this layer is explored in distribute.bro and has been fleshed out more in eventwrapper.bro.  The general idea for this is to look at collections of events from different sources and to identify when the same IP address has been seen by multiple sources.

In eventwrapper.bro, Notices are looked at rather than discrete events in order to minimize the overhead brought on by the communication layer.  In addition, most of the things that are interesting are not event driven, but are the byproduct of local function analysis.  In order to access these notices (such as AddressScan), the notice_action event is used to transfer all notices that the sensor bros are processing rather than events.  This is orders of magnitude less communication than would otherwise be required.  If the notice is part of a defined list, then it is further processed.  The default list of 'interesting' notices is:

global interestingNotices = {
        "TRWAddressScan",
        "AddressScan",
        "AddressDropped",
        "PortScan",
        "SensitivePortmapperAccess",
        "LowPortTrolling",
        "OutboundCallback",
        "SensitiveConnection",
        "LandMineDetect",
} &redef;

With analysis notices happening when a given notice has been seen by more than source_sensor_pairs_exceeded sensors, or if the IP has been seen more than source_IP_threshold times.  See the code for more details.


BroShell
Several changes have been made in the broshell code to support this functionality.  Broshell infrastructure is broken up into the c++ code in the shell itself, and the event driven code on the bro side.  Event code relating to shell functionality has been added into the individual component side code, so that fabric related events for broshell are located in brofabric.bro rather than broshell.bro.  This is designed to simplify the broshell code.

The new commands in broshell include 'show fabric' and 'show notice <>' which look like:

--> show fabric
{
        [1] = host:131.243.64.97 id: 1 port: 44332/tcp islocal: F descr: ,
        [3] = host:127.0.0.1 id: 10000 port: 4477/tcp islocal: F descr: ,
        [2] = host:128.55.14.206 id: 2 port: 44332/tcp islocal: F descr:
}
-->
and
--> show notice TRWAddressScan
{
        [1] = 222.186.68.211 seen 3 times for TRWAddressScan 1: 131.243.64.97 2: 128.55.14.206 local:127.0.0.1,
        [2] = 219.153.32.12 seen 3 times for TRWAddressScan 1: 131.243.64.97 2: 128.55.14.206 local:127.0.0.1
}
-->

Currently the data formatting is rather crude, and indicates the need for additional functionality in the broshell itself.  For more details on the basic operation and command set of the broshell, see: http://www.nersc.gov/~scottc/software/bro/broshell.html  



Download
[NOTE: all of this is alpha quality - there is a great deal of debugging code here since this is still proof of concept]

Broshell Source Code : shell.cc
Broshell Policy : broshell.bro

Additional Policy:
brofabric.bro
eventwrapper.bro