Monday, September 22, 2014

Bro Plugins

A new paradigm has been floating around the development branches of Bro: plugins. Not broctl plugins but compiled plugins dynamically available to the Bro binary at run time. These plugins are similar to Apache modules. I fully support Bro plugins. They will hopefully reduce the size of the core. They will hopefully make creating a Bro package management solution much easier. That would make extending and customizing Bro much simpler.

I had at one point wanted a Levenshtein distance function available to me from scriptland. I ended up writing it into the core by extending the strings.bif file before compiling Bro. This provided me what I wanted, but was rather difficult to do. The new plugin architecture will allow me to remove this functionality from the core (I honestly think I'm the only person that has used this function) and distribute it as a plugin, similar to a Python module.

Gilbert Clark has a practical example of a plugin he wrote here. His plugin
measures overhead around plugin hooks within Bro's core. The code itself is quite confusing if you've never looked at all the custom C++ things Bro does. Luckily, the Bro team has posted a walk through for plugin development here. Let's walk through the steps together, making a few adjustments to the original documentation.

First, let's clone Bro from git (I like to do a clone each time I want to try something new with Bro to ensure I have the freshest of code) and compile Bro.

git clone --recursive
cd bro/

If something fails, try searching the Bro project page for guidance. Documentation is a little haphazard, so use some google foo. Next, change into the auxiliary plugins directory in the bro repository, make a new directory for your plugin and initialize the directory with the init-plugin helper script provided. You'll need to pick a C++ namespace and plugin name before initializing the directory.

cd aux/bro-aux/plugin-support
../init-plugin   # this prints usage


Next, code up the plugin's functionality. Again, if you're not familiar with C++ and the custom things Bro does in it, you'll need to read some of the *.cc and *.h files used to create Bro's core. The following is a modified version of what is shown here and goes in the my_plugin_name.bif file.

module CaesarCipher;

function rot13%(s: string%) : string
    char* rot13 = copy_string(s->CheckString());

    for ( char* p = rot13; *p; p++ )
        char b = islower(*p) ? 'a' : 'A';
        *p  = (*p - b + 13) % 26 + b;

    return new StringVal(new BroString(1, byte_vec(rot13), strlen(rot13)));

You should also provide a description for your plugin (not required) in the file.

nano src/my_plugin_name.bif
nano src/

Once you have your plugin call coded up nicely (you should still be in %BRO_DIR%/bro/aux/bro-aux/plugin-support/MY_PLUGIN_NAME) run configure with the bro directory. Then run make.

./configure --bro-dist=%BRO_DIR%

Bro's use of cmake should take care of all the details for you quite nicely. If you've copy+pasta'd my code (or written your own) correctly, then all should compile just fine. We need to now tell Bro where to find the plugin we just compiled and check that Bro can find and use the plugin.

export BRO_PLUGIN_PATH=$BRO_PLUGIN_PATH:%BRO_DIR%/bro/aux/bro-aux/plugin-support/MY_PLUGIN_NAME
%BRO_DIR%/build/src/bro -N
%BRO_DIR%/bro -e 'print CaesarCipher::rot13("Hello")'

At this point Bro is compiled and our plugin is compiled, but neither are installed. This can be done with:

sudo make install

Unset the environment variable we named BRO_PLUGIN_PATH and make sure we can still use our plugin.

%BRO_DIR%/bro -e 'print CaesarCipher::rot13("Hello")'

Hurray! To see where our plugin was installed to run:

ls /usr/local/bro/lib/bro/plugins/

And to distribute the plugin via source, from the %BRO_DIR%/bro/aux/bro-aux/plugin-support/MY_PLUGIN_NAME directory run:

make sdist
ls ./build/sdist

bro -NN lists all available plugins Bro knows about and their
namespaces. I'm not sure what the difference between plugins and bifs
are, but it seems they are different given that bifs are not listed in
bro -NN.

At some point, it might be wise if someone grep'd through Bro's source
and found all the functions NOT used within base and policy, removed
them from Bro's core, and placed them into plugins.

1 comment:

  1. Agreed. If you're interested, you could split the GeoIP code out into a plugin (although that being broken out into a plugin has been debated some). I know some extensions and fixes I'd like to see applied to the GeoIP code too. :)