zeek/aux/broccoli/docs/html/c84.html
Robin Sommer 2b6ad76bd5 Creating a branch release/1.5 with the current 1.5.3 release code.
This is so that people working from the current stable version can
still start using git.
2011-03-09 15:26:01 -08:00

4044 lines
No EOL
81 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Using Broccoli</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="Broccoli: The Bro Client Communications Library"
HREF="index.html"><LINK
REL="PREVIOUS"
TITLE="Installing Broccoli"
HREF="c54.html"><LINK
REL="NEXT"
TITLE="Broccoli API Reference"
HREF="api.html"><LINK
REL="STYLESHEET"
TYPE="text/css"
HREF="stylesheet.css"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Broccoli: The Bro Client Communications Library</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c54.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="api.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="AEN84"
></A
>Chapter 3. Using Broccoli</H1
><DIV
CLASS="TOC"
><DL
><DT
><B
>Table of Contents</B
></DT
><DT
>3.1. <A
HREF="c84.html#AEN87"
>Obtaining information about your build using <TT
CLASS="FILENAME"
>broccoli-config</TT
></A
></DT
><DT
>3.2. <A
HREF="c84.html#AEN121"
>Suggestions for instrumenting applications</A
></DT
><DT
>3.3. <A
HREF="c84.html#AEN134"
>The Broccoli API</A
></DT
><DT
>3.4. <A
HREF="c84.html#AEN738"
>Configuring encrypted communication</A
></DT
><DT
>3.5. <A
HREF="c84.html#AEN785"
>Configuring event reception in Bro policies</A
></DT
><DT
>3.6. <A
HREF="c84.html#AEN819"
>Configuring debugging output</A
></DT
><DT
>3.7. <A
HREF="c84.html#AEN843"
>Test programs</A
></DT
></DL
></DIV
><P
> </P
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN87"
>3.1. Obtaining information about your build using <TT
CLASS="FILENAME"
>broccoli-config</TT
></A
></H1
><P
> Similarly to many other software packages, the Broccoli distribution
provides a script that you can use to obtain details about your
Broccoli setup. The script currently provides the following flags:
<P
></P
><UL
><LI
><P
><B
CLASS="COMMAND"
>--build</B
> prints the name of the machine the build was
made on, when, and whether debugging support was enabled or not.</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>--prefix</B
> prints the directory in the filesystem
below which Broccoli was installed.</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>--version</B
> prints the version of the distribution
you have installed.</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>--libs</B
> prints the flags to pass to the
linker in order to link in the Broccoli library.</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>--cflags</B
> prints the flags to pass to the
compiler in order to properly include Broccoli's header file.</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>--config</B
> prints the location of the system-wide
config file your installation will use.</P
></LI
></UL
>
</P
><P
> The <TT
CLASS="FILENAME"
>--cflags</TT
> and <TT
CLASS="FILENAME"
>--libs</TT
> flags
are the suggested way of obtaining the necessary information for integrating
Broccoli into your build environment. It is generally recommended to use
<TT
CLASS="FILENAME"
>broccoli-config</TT
> for this purpose, rather than, say,
develop new <B
CLASS="COMMAND"
>autoconf </B
> tests.
If you use the <B
CLASS="COMMAND"
>autoconf</B
>/<B
CLASS="COMMAND"
>automake</B
>
tools, we recommend something along the following lines for your
<TT
CLASS="FILENAME"
>configure</TT
> script:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>dnl ##################################################
dnl # Check for Broccoli
dnl ##################################################
AC_ARG_WITH(broccoli-config,
AC_HELP_STRING([--with-broccoli-config=FILE], [Use given broccoli-config]),
[ brocfg="$withval" ],
[ AC_PATH_GENERIC(broccoli,,
brocfg="broccoli-config",
AC_MSG_ERROR(Cannot find Broccoli: Is broccoli-config in path? Use more fertilizer?)) ])
broccoli_libs=`$brocfg --libs`
broccoli_cflags=`$brocfg --cflags`
AC_SUBST(broccoli_libs)
AC_SUBST(broccoli_cflags)
</PRE
></TD
></TR
></TABLE
><P
> You can then use the compiler/linker flags in your Makefile.in/ams by
substituting in the values accordingly, which might look as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>CFLAGS = -W -Wall -g -DFOOBAR @broccoli_cflags@
LDFLAGS = -L/usr/lib/foobar @broccoli_libs@
</PRE
></TD
></TR
></TABLE
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN121"
>3.2. Suggestions for instrumenting applications</A
></H1
><P
> Often you will want to make existing applications Bro-aware,
that is, <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>instrument</B
></SPAN
> them so that they can send and
receive Bro events at appropriate moments in the execution flow.
This will involve modifying an existing code tree, so care needs to
be taken to avoid unwanted side effects. By protecting the instrumented
code with
<CODE
CLASS="FUNCTION"
>#ifdef</CODE
>/<CODE
CLASS="FUNCTION"
>#endif</CODE
>
statements you can still build the original application, using the
instrumented source tree. The <TT
CLASS="FILENAME"
>broccoli-config</TT
> script helps you in doing so because
it already adds <CODE
CLASS="FUNCTION"
>-DBROCCOLI</CODE
> to the compiler flags
reported when run with the <TT
CLASS="FILENAME"
>--cflags</TT
> option:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>cpk25@localhost:/home/cpk25 &#62; broccoli-config --cflags
-I/usr/local/include -I/usr/local/include -DBROCCOLI
</PRE
></TD
></TR
></TABLE
><P
> So simply surround all inserted code with a preprocessor check
for <CODE
CLASS="FUNCTION"
>BROCCOLI</CODE
> and you will be able to
build the original application as soon as <CODE
CLASS="FUNCTION"
>BROCCOLI</CODE
>
is not defined.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN134"
>3.3. The Broccoli API</A
></H1
><P
> Time for some code. In the code snippets below we will introduce variables
whenever context requires them and not necessarily when C requires them.
The library does not require calling a global initialization function.
In order to make the API known, include <TT
CLASS="FILENAME"
>broccoli.h</TT
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>#ifdef BROCCOLI
#include &#60;broccoli.h&#62;
#endif
</PRE
></TD
></TR
></TABLE
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>A note on Broccoli's memory management philosophy:</B
></SPAN
></P
><P
>Broccoli generally does not release objects you allocate.
The approach taken is "you clean up what you allocate."
</P
></TD
></TR
></TABLE
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN143"
>3.3.1. Initialization</A
></H2
><P
> Broccoli requires global initialization before most of its
other other functions can be used. Generally, the way to
initialize Broccoli is as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>bro_init(NULL);
</PRE
></TD
></TR
></TABLE
><P
> The argument to
<CODE
CLASS="FUNCTION"
>bro_init()</CODE
>
provides optional initialization context, and may be kept
<CODE
CLASS="CONSTANT"
>NULL</CODE
> for normal use. If required, you may
allocate a <TT
CLASS="FILENAME"
>BroCtx</TT
> structure locally,
initialize it using
<CODE
CLASS="FUNCTION"
>bro_ctx_init()</CODE
>,
fill in additional values as required and and subsequently pass it to
<CODE
CLASS="FUNCTION"
>bro_init()</CODE
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>BroCtx ctx;
bro_ctx_init(&#38;ctx);
/* Make adjustments to the context structure as required... */
bro_init(&#38;ctx);
</PRE
></TD
></TR
></TABLE
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
> The <TT
CLASS="FILENAME"
>BroCtx</TT
> structure currently contains
a set of five different callback function pointers. These
are <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>required</B
></SPAN
> for thread-safe operation
of OpenSSL (Broccoli itself is thread-safe). If you intend
to use Broccoli in a multithreaded environment, you need to
implement functions and register them via the
<TT
CLASS="FILENAME"
>BroCtx</TT
> structure. The O'Reilly book
"Network Security with OpenSSL" by Viega et al. shows how to
implement these callbacks.
</P
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>You <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>must</B
></SPAN
> call
<CODE
CLASS="FUNCTION"
>bro_init()</CODE
>
at the start of your application. Undefined behavior may result
if you don't.
</P
></TD
></TR
></TABLE
></DIV
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN167"
>3.3.2. Data types in Broccoli</A
></H2
><P
> Broccoli declares a number of data types in <TT
CLASS="FILENAME"
>broccoli.h</TT
> that
you should know about. The more complex ones are kept opaque, while you do get
access to the fields in the simpler ones. The full list is as follows:
<P
></P
><UL
><LI
><P
>Simple signed and unsigned types: <SPAN
CLASS="TYPE"
>int</SPAN
>, <SPAN
CLASS="TYPE"
>uint</SPAN
>,
<SPAN
CLASS="TYPE"
>uint32</SPAN
>, <SPAN
CLASS="TYPE"
>uint16</SPAN
> and <SPAN
CLASS="TYPE"
>uchar</SPAN
>.</P
></LI
><LI
><P
>Connection handles: <SPAN
CLASS="TYPE"
>BroConn</SPAN
>, kept opaque.</P
></LI
><LI
><P
>Bro events: <SPAN
CLASS="TYPE"
>BroEvent</SPAN
>, kept opaque.</P
></LI
><LI
><P
>Buffer objects: <SPAN
CLASS="TYPE"
>BroBuf</SPAN
>, kept opaque. See the separate
<A
HREF="c84.html#AEN696"
>section on buffer management</A
> for details.</P
></LI
><LI
><P
>Ports: <SPAN
CLASS="TYPE"
>BroPort</SPAN
> for network ports, defined as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>typedef struct bro_port {
uint16 port_num; /* port number in host byte order */
int port_proto; /* IPPROTO_xxx */
} BroPort;
</PRE
></TD
></TR
></TABLE
></LI
><LI
><P
>Records: <SPAN
CLASS="TYPE"
>BroRecord</SPAN
>, kept opaque. See the separate
<A
HREF="c84.html#AEN554"
>section on record handling</A
> for details.</P
></LI
><LI
><P
>Strings (character and binary): <SPAN
CLASS="TYPE"
>BroString</SPAN
>, defined as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>typedef struct bro_string {
int str_len;
char *str_val;
} BroString;
</PRE
></TD
></TR
></TABLE
><P
> BroStrings are mostly kept transparent for convenience; please have a look at the
string API:
<A
HREF="broccoli-broccoli.html#BRO-STRING-INIT"
><CODE
CLASS="FUNCTION"
>bro_string_init()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-STRING-SET"
><CODE
CLASS="FUNCTION"
>bro_string_set()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-STRING-SET-DATA"
><CODE
CLASS="FUNCTION"
>bro_string_set_data()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-STRING-COPY"
><CODE
CLASS="FUNCTION"
>bro_string_copy()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-STRING-CLEANUP"
><CODE
CLASS="FUNCTION"
>bro_string_cleanup()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-STRING-FREE"
><CODE
CLASS="FUNCTION"
>bro_string_free()</CODE
></A
>.
</P
></LI
><LI
><P
>Tables: <SPAN
CLASS="TYPE"
>BroTable</SPAN
>, kept opaque. See the separate
<A
HREF="c84.html#AEN599"
>section on table handling</A
> for details.</P
></LI
><LI
><P
>Sets: <SPAN
CLASS="TYPE"
>BroSet</SPAN
>, kept opaque. See the separate
<A
HREF="c84.html#AEN636"
>section on table handling</A
> for details.</P
></LI
><LI
><P
>Subnets: <SPAN
CLASS="TYPE"
>BroSubnet</SPAN
>, defined as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>typedef struct bro_subnet
{
uint32 sn_net; /* IP address in network byte order */
uint32 sn_width; /* Length of prefix to consider. */
} BroSubnet;
</PRE
></TD
></TR
></TABLE
></LI
></UL
>
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN226"
>3.3.3. Managing connections</A
></H2
><P
> You can use Broccoli to establish a connection to a remote Bro, or to create a
Broccoli-enabled server application that other Bros will connect to. (This
means that in principle, you can also use Broccoli purely as middleware and
have multiple Broccoli applications communicate directly.)
</P
><P
>
In order to establish a connection to a remote Bro, you first obtain a connection
handle. You then use this connection handle to request events, connect to the
remote Bro, send events, etc. Connection handles are pointers to <CODE
CLASS="FUNCTION"
>BroConn</CODE
>
structures, which are kept opaque. Use
<A
HREF="broccoli-broccoli.html#BRO-CONN-NEW"
><CODE
CLASS="FUNCTION"
>bro_conn_new()</CODE
></A
> or
<A
HREF="broccoli-broccoli.html#BRO-CONN-NEW-STR"
><CODE
CLASS="FUNCTION"
>bro_conn_new_str()</CODE
></A
>
to obtain a handle, depending on what parameters are more convenient for
you: the former accepts the IP address and port number as separate numerical
arguments, the latter uses a single string to encode both, in "hostname:port"
format.
</P
><P
> To write a Broccoli-enabled server, you first need to implement the usual
<CODE
CLASS="FUNCTION"
>socket()</CODE
> / <CODE
CLASS="FUNCTION"
>bind()</CODE
> /
<CODE
CLASS="FUNCTION"
>listen()</CODE
> / <CODE
CLASS="FUNCTION"
>accept()</CODE
> routine.
Once you have obtained a file descriptor for the new connection from <CODE
CLASS="FUNCTION"
>accept()</CODE
>,
you pass it to the third function that returns a <CODE
CLASS="FUNCTION"
>BroConn</CODE
>
handle,
<A
HREF="broccoli-broccoli.html#BRO-CONN-NEW-SOCKET"
><CODE
CLASS="FUNCTION"
>bro_conn_new_socket()</CODE
></A
>.
The rest of the connection handling then proceeds as in the client scenario.
</P
><P
>
All three calls accept additional flags for fine-tuning connection behaviour.
These flags are:
<P
></P
><UL
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_NONE</CODE
>: no functionality. Use when
no flags are desired.
</P
></LI
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_RECONNECT</CODE
>:
When using this option, Broccoli will attempt to reconnect to the peer
after lost connectivity transparently. Essentially whenever you try to
read from or write to the peer and its connection broke down, a
full reconnect including complete handshaking is attempted. You can check
whether the connection to a peer is alive at any time using
<A
HREF="broccoli-broccoli.html#BRO-CONN-ALIVE"
><CODE
CLASS="FUNCTION"
>bro_conn_alive()</CODE
></A
>.
</P
></LI
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_ALWAYS_QUEUE</CODE
>:
When using this option, Broccoli will queue any events you send for
later transmission when a connection is currently down. Without using this
flag, any events you attempt to send while a connection is down get dropped
on the floor. Note that Broccoli maintains a maximum queue size per connection
so if you attempt to send lots of events while the connection is down, the
oldest events may start to get dropped nonetheless. Again, you can check
whether the connection is currently okay by using
<A
HREF="broccoli-broccoli.html#BRO-CONN-ALIVE"
><CODE
CLASS="FUNCTION"
>bro_conn_alive()</CODE
></A
>.
</P
></LI
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_DONTCACHE</CODE
>:
When using this option, Broccoli will ask the peer not to use caching on
the objects it sends to us. This is the default, and the flag need not
normally be used. It is kept to maintain backward compatibility.
</P
></LI
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_CACHE</CODE
>:
When using this option, Broccoli will ask the peer to use caching on
the objects it sends to us. Caching is normally disabled.
</P
></LI
><LI
><P
><CODE
CLASS="CONSTANT"
>BRO_CFLAG_YIELD</CODE
>: When
using this option,
<CODE
CLASS="FUNCTION"
>bro_conn_process_input()</CODE
>
processes at most one event at a time and then
returns.
</P
></LI
></UL
>
</P
><P
> By obtaining a connection handle, you do not also establish a connection right
away. This is done using
<A
HREF="broccoli-broccoli.html#BRO-CONN-CONNECT"
><CODE
CLASS="FUNCTION"
>bro_conn_connect()</CODE
></A
>.
The main reason for this is to allow you to subscribe to events
(using
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add()</CODE
></A
>,
see <A
HREF="c84.html#AEN461"
>below</A
>)
before establishing the connection. Upon returning from
<A
HREF="broccoli-broccoli.html#BRO-CONN-CONNECT"
><CODE
CLASS="FUNCTION"
>bro_conn_connect()</CODE
></A
>
you are guaranteed to receive all instances of the event types you have
requested, while later on during the connection some time may elapse between
the issuing of a request for events and the processing of that request at the
remote end.
Connections are established via TCP, optionally using SSL encryption. See
<A
HREF="c84.html#AEN738"
>"Configuring encrypted communication"</A
> below for more
information on setting up enncryption.
The port numbers Bro agents and Broccoli applications listen on can vary from peer
to peer.
</P
><P
> Finally, <A
HREF="broccoli-broccoli.html#BRO-CONN-DELETE"
><CODE
CLASS="FUNCTION"
>bro_conn_delete()</CODE
></A
>
terminates a connection and releases all resources associated with it.
You can create as many connections as you like, to one or more peers.
You can obtain the file descriptor of a connection using
<A
HREF="broccoli-broccoli.html#BRO-CONN-GET-FD"
><CODE
CLASS="FUNCTION"
>bro_conn_get_fd()</CODE
></A
>.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>char host_str = "bro.yourorganization.com";
int port = 1234;
struct hostent *host;
BroConn *bc;
if (! (host = gethostbyname(host_str)) ||
! (host-&#62;h_addr_list[0])) {
/* Error handling -- could not resolve host */
}
/* In this example, we obtain a connection handle, then register event handlers,
* and finally connect to the remote Bro.
*
* First obtain a connection handle:
*/
if (! (bc = bro_conn_new((struct in_addr*) host-&#62;h_addr_list[0], htons(port), BRO_CFLAG_NONE))) {
/* Error handling - could not get connection handle */
}
/* Register event handlers:
*/
bro_event_registry_add(bc, "foo", bro_foo_handler, NULL);
/* ... */
/* Now connect to the peer:
*/
if (! bro_conn_connect(bc)) {
/* Error handling - could not connect to remote Bro. */
}
/* Send and receive events ... */
/* Disconnect from Bro and clean up connection */
bro_conn_delete(bc);
</PRE
></TD
></TR
></TABLE
><P
> Or simply use the string-based version:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>char host_str = "bro.yourcompany.com:1234";
BroConn *bc;
/* In this example we don't request any events from the peer, but
* we ask it not to use the serialization cache.
*
* Again, first obtain a connection handle:
*/
if (! (bc = bro_conn_new_str(host_str, BRO_CFLAG_DONTCACHE))) {
/* Error handling - could not get connection handle */
}
/* Now connect to the peer:
*/
if (! bro_conn_connect(bc)) {
/* Error handling - could not connect to remote Bro. */
}
/* ... */
</PRE
></TD
></TR
></TABLE
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN286"
>3.3.4. Connection classes</A
></H2
><P
> When you want to establish connections from multiple Broccoli applications
with different purposes, the peer needs a means to understand what kind of
application each connection belongs to. The real meaning of "kind of application"
here is "sets of event types to request", because depending on the class of
an application, the peer will likey want to receive different types of events.
</P
><P
> Broccoli lets you set the class of a connection using
<A
HREF="broccoli-broccoli.html#BRO-CONN-SET-CLASS"
><CODE
CLASS="FUNCTION"
>bro_conn_set_class()</CODE
></A
>.
When using this feature, you need to call that function before issuing a
<A
HREF="broccoli-broccoli.html#BRO-CONN-CONNECT"
><CODE
CLASS="FUNCTION"
>bro_conn_connect()</CODE
></A
>,
since the class of a connection is determined at connection startup.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>if (! (bc = bro_conn_new_str(host_str, BRO_CFLAG_DONTCACHE))) {
/* Error handling - could not get connection handle */
}
/* Set class of this connection: */
bro_conn_set_class(bc, "syslog");
if (! bro_conn_connect(bc)) {
/* Error handling - could not connect to remote Bro. */
}
</PRE
></TD
></TR
></TABLE
><P
> If your peer is a Bro node, you need to match the chosen connection class in
the remote Bro's <CODE
CLASS="FUNCTION"
>Remote::destinations</CODE
> configuration.
See <A
HREF="c84.html#AEN785"
>below</A
> for how to do this.
Finally, in order to obtain the class of a connection as indicated by the remote side, use
<A
HREF="broccoli-broccoli.html#BRO-CONN-GET-PEER-CLASS"
><CODE
CLASS="FUNCTION"
>bro_conn_get_peer_class()</CODE
></A
>.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN300"
>3.3.5. Composing and sending events</A
></H2
><P
> In order to send an event to the remote Bro agent, you first create
an empty event structure with the name of the event, then add parameters
to pass to the event handler at the remote agent, and then send off the
event.
</P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
> <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Bro peers ignore unrequested events.</B
></SPAN
>
</P
><P
> You need to make sure that the remote Bro agent is interested in receiving
the events you send. This interest is expressed in policy configuration.
We'll explain this in more detail <A
HREF="c84.html#AEN785"
>below</A
>
and for now assume that our remote peer is configured to receive the
events we send.
</P
></TD
></TR
></TABLE
></DIV
><P
> Let's assume we want to request a report of all connections a remote
Bro currently keeps state for that match a given destination port and
host name and that have amassed more than a certain number of bytes.
The idea is to send an event to the remote Bro that contains the
query, identifiable through a request ID, and have the remote Bro
answer us with <CODE
CLASS="FUNCTION"
>remote_conn</CODE
> events
containing the information we asked for. The definition of our
requesting event could look as follows in the Bro policy:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>event report_conns(req_id: int, dest_host: string, dest_port: port, min_size: count);
</PRE
></TD
></TR
></TABLE
><P
> First, create a new event:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>BroEvent *ev;
if (! (ev = bro_event_new("report_conns"))) {
/* Error handling - could not allocate new event. */
}
</PRE
></TD
></TR
></TABLE
><P
> Now we need to add parameters to the event. The sequence and types must
match the event handler declaration &mdash; check the Bro policy to make
sure they match. The function to use for adding parameter values is
<A
HREF="broccoli-broccoli.html#BRO-EVENT-ADD-VAL"
><CODE
CLASS="FUNCTION"
>bro_event_add_val()</CODE
></A
>
All values are passed as <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>pointer arguments</B
></SPAN
> and are copied internally,
so the object you're pointing to stays unmodified at all times. You clean
up what you allocate. In order to indicate the type of the value passed into the
function, you need to pass a numerical type identifier along as well.
<A
HREF="c84.html#TABLE-1"
>Table 1</A
> lists the value types that Broccoli supports along with
the type identifier and data structures to point to.
</P
><DIV
CLASS="TABLE"
><A
NAME="TABLE-1"
></A
><P
><B
>Table 3-1. Types, type tags, and data structures for event parameters in Broccoli</B
></P
><TABLE
BORDER="1"
FRAME="vsides"
RULES="all"
CLASS="CALSTABLE"
><COL><COL><COL><THEAD
><TR
><TH
ALIGN="CENTER"
>Type</TH
><TH
ALIGN="CENTER"
>Type tag</TH
><TH
ALIGN="CENTER"
>Data type pointed to</TH
></TR
></THEAD
><TBODY
><TR
><TD
>Boolean</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_BOOL</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>int</CODE
></TD
></TR
><TR
><TD
>Integer value</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_INT</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>int</CODE
></TD
></TR
><TR
><TD
>Counter (nonnegative integers)</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_COUNT</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>uint32</CODE
></TD
></TR
><TR
><TD
>Enums (enumerated values)</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_ENUM</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>int</CODE
> (see also the description of
<A
HREF="broccoli-broccoli.html#BRO-EVENT-ADD-VAL"
><CODE
CLASS="FUNCTION"
>bro_event_add_val()</CODE
></A
>'s
<CODE
CLASS="FUNCTION"
>type_name</CODE
> argument below)</TD
></TR
><TR
><TD
>Floating-point number</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_DOUBLE</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>double</CODE
></TD
></TR
><TR
><TD
>Timestamp</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_TIME</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>double</CODE
> (see also
<A
HREF="broccoli-broccoli.html#BRO-UTIL-TIMEVAL-TO-DOUBLE"
><CODE
CLASS="FUNCTION"
>bro_util_timeval_to_double()</CODE
></A
> and
<A
HREF="broccoli-broccoli.html#BRO-UTIL-CURRENT-TIME"
><CODE
CLASS="FUNCTION"
>bro_util_current_time()</CODE
></A
>)</TD
></TR
><TR
><TD
>Time interval</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_INTERVAL</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>double</CODE
></TD
></TR
><TR
><TD
>Strings (text and binary)</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_STRING</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroString</CODE
> (see also the family of <CODE
CLASS="FUNCTION"
>bro_string_xxx()</CODE
> functions)</TD
></TR
><TR
><TD
>Network ports</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_PORT</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroPort</CODE
>, with the port number in host byte order</TD
></TR
><TR
><TD
>IPv4 address</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_IPADDR</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>uint32</CODE
>, in network byte order</TD
></TR
><TR
><TD
>IPv4 network</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_NET</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>uint32</CODE
>, in network byte order</TD
></TR
><TR
><TD
>IPv4 subnet</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_SUBNET</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroSubnet</CODE
>, with the sn_net member in network byte order</TD
></TR
><TR
><TD
>Record</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_RECORD</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroRecord</CODE
> (see also the family of
<CODE
CLASS="FUNCTION"
>bro_record_xxx()</CODE
> functions and their
explanation below)</TD
></TR
><TR
><TD
>Table</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_TABLE</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroTable</CODE
> (see also the family of
<CODE
CLASS="FUNCTION"
>bro_table_xxx()</CODE
> functions and their
explanation below)</TD
></TR
><TR
><TD
>Record</TD
><TD
><CODE
CLASS="CONSTANT"
>BRO_TYPE_SET</CODE
></TD
><TD
><CODE
CLASS="FUNCTION"
>BroSet</CODE
> (see also the family of
<CODE
CLASS="FUNCTION"
>bro_set_xxx()</CODE
> functions and their
explanation below)</TD
></TR
></TBODY
></TABLE
></DIV
><P
> Knowing these, we can now compose a
<CODE
CLASS="FUNCTION"
>request_connections</CODE
> event:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>BroString dest_host;
BroPort dest_port;
uint32 min_size;
int req_id = 0;
bro_event_add_val(ev, BRO_TYPE_INT, NULL, &#38;req_id);
req_id++;
bro_string_set(&#38;dest_host, "desthost.destdomain.com");
bro_event_add_val(ev, BRO_TYPE_STRING, NULL, &#38;dest_host);
bro_string_cleanup(&#38;dest_host);
dest_port.dst_port = 80;
dest_port.dst_proto = IPPROTO_TCP;
bro_event_add_val(ev, BRO_TYPE_PORT, NULL, &#38;dest_port);
min_size = 1000;
bro_event_add_val(ev, BRO_TYPE_COUNT, NULL, &#38;min_size);
</PRE
></TD
></TR
></TABLE
><P
> The third argument to
<A
HREF="broccoli-broccoli.html#BRO-EVENT-ADD-VAL"
><CODE
CLASS="FUNCTION"
>bro_event_add_val()</CODE
></A
>
lets you specify a specialization of the types listed in
<A
HREF="c84.html#TABLE-1"
>Table 1</A
>. This is generally not necessary
except for one situationn: When using <CODE
CLASS="CONSTANT"
>BRO_TYPE_ENUM</CODE
>. You currently
cannot define
a Bro-level enum type in Broccoli, and thus when sending an enum value, you
have to specify the type of the enum along with the value. For example, in order
to add an instance of enum <CODE
CLASS="FUNCTION"
>transport_type</CODE
> defined in
Bro's <TT
CLASS="FILENAME"
>bro.init</TT
>, you would use
<TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>int transport_proto = 2;
/* ... */
bro_event_add_val(ev, BRO_TYPE_ENUM, "transport_proto", &#38;transport_proto);
</PRE
></TD
></TR
></TABLE
>
to get the equivalent of "udp" on the remote side. The same system is used
to point out type names when calling
<A
HREF="broccoli-broccoli.html#BRO-EVENT-SET-VAL"
><CODE
CLASS="FUNCTION"
>bro_event_set_val()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-RECORD-ADD-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_add_val()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-RECORD-SET-NTH-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_set_nth_val()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-RECORD-SET-NAMED-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_set_named_val()</CODE
></A
>.
</P
><P
> All that's left to do now is to send off the event. For this, use
<A
HREF="broccoli-broccoli.html#BRO-EVENT-SEND"
><CODE
CLASS="FUNCTION"
>bro_event_send()</CODE
></A
>
and pass it the connection handle and the event. The function returns
<CODE
CLASS="CONSTANT"
>TRUE</CODE
> when the event could be sent right away or if
it was queued for later delivery. <CODE
CLASS="CONSTANT"
>FALSE</CODE
> is returned
on error. If the event get queued, this does not indicate an error &mdash;
likely the connection was just not
ready to send the event at this point. Whenever you call
<A
HREF="broccoli-broccoli.html#BRO-EVENT-SEND"
><CODE
CLASS="FUNCTION"
>bro_event_send()</CODE
></A
>,
Broccoli attempts to send as much of an existing event queue as possible.
Again, the event is copied internally to make it easier for you to
send the same event repeatedly. You clean up what you allocate.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>bro_event_send(bc, ev);
bro_event_free(ev);
</PRE
></TD
></TR
></TABLE
><P
> Two other functions may be useful to you:
<A
HREF="broccoli-broccoli.html#BRO-EVENT-QUEUE-LENGTH"
><CODE
CLASS="FUNCTION"
>bro_event_queue_length()</CODE
></A
>
tells you how many events are currently queued, and
<A
HREF="broccoli-broccoli.html#BRO-EVENT-QUEUE-FLUSH"
><CODE
CLASS="FUNCTION"
>bro_event_queue_flush()</CODE
></A
>
attempts to flush the current event queue and returns the number of events that do remain
in the queue after the flush. <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Note:</B
></SPAN
> you do not normally need
to call this function, queue flushing is attempted every time you send an event.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN461"
>3.3.6. Receiving events</A
></H2
><P
> Receiving events is a little more work because you need to
</P
><P
></P
><OL
TYPE="1"
><LI
><P
>tell Broccoli what to do when requested events arrive,</P
></LI
><LI
><P
>let the remote Bro agent know that you would like to receive those events,</P
></LI
><LI
><P
>find a spot in the code path suitable for extracting and processing arriving events.</P
></LI
></OL
><P
> Each of these steps is explained in the following sections.
</P
><BR
CLEAR="all"><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN472"
>3.3.6.1. Implementing event callbacks</A
></H3
><P
> When Broccoli receives an event, it tries to dispatch the event to callbacks
registered for that event type. The place where callbacks get registered is
called the callback registry. Any callbacks registered for the arriving
event's name are invoked with the parameters shipped with the event. There
are two styles of argument passing to the event callbacks.
Which one is better suited depends on your application.
<P
></P
><UL
><LI
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Expanded argument passing.</B
></SPAN
> Each event argument
is passed via a pointer to the callback. This makes best sense when you
know the type of the event and of its arguments, because it provides you
immediate access to arguments as when using a normal C function.
</P
><P
> In order to register a callback with expanded argument passing, use
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add()</CODE
></A
>
and pass it the connection handle, the name of the event for which you
register the callback, the callback itself that matches the signature
of the <TT
CLASS="FILENAME"
>BroEventFunc</TT
> type, and any user data (or
<CODE
CLASS="CONSTANT"
>NULL</CODE
>) you want to see passed to the callback on
each invocation. The callback's type is defined rather generically as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>typedef void (*BroEventFunc) (BroConn *bc, void *user_data, ...);
</PRE
></TD
></TR
></TABLE
><P
> It requires a connection handle as its first argument
and a pointer to user-provided callback data as the second argument.
Broccoli will pass the connection handle of the connection on which the event
arrived through to the callback. <CODE
CLASS="FUNCTION"
>BroEventFunc</CODE
>s
are variadic, because each callback you provide is directly invoked with
pointers to the parameters of the event, in a format directly usable in C.
All you need to know is what type to point to in order to receive the
parameters in the right layout. Refer to <A
HREF="c84.html#TABLE-1"
>Table 1</A
>
again for a summary of those types. Record types are more involved and are
addressed in more detail <A
HREF="c84.html#AEN554"
>below</A
>.
</P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>Note that <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>all</B
></SPAN
> parameters are passed to the
callback as pointers, even elementary types such as <CODE
CLASS="CONSTANT"
>int</CODE
>s
that would normally be passed directly.
Also note that Broccoli manages the lifecycle of event parameters
and therefore you do <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>not</B
></SPAN
> have to clean them up inside
the event handler.
</P
></TD
></TR
></TABLE
></DIV
><P
> Continuing our example, we will want to process the connection reports
that contain the responses to our <CODE
CLASS="FUNCTION"
>report_conns</CODE
>
event. Let's assume those look as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>event remote_conn(req_id: int, conn: connection);
</PRE
></TD
></TR
></TABLE
><P
> The reply events contain the request ID so we can associate requests
with replies, and a connection record (defined in <TT
CLASS="FILENAME"
>bro.init</TT
>
in Bro. (It'd be nicer to report all replies in a single event but we'll
ignore that for now.) For this event, our callback would look like this:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>void remote_conn_cb(BroConn *bc, void *user_data, int *req_id, BroRecord *conn);
</PRE
></TD
></TR
></TABLE
><P
> Once more, you clean up what you allocate, and since you never allocated the
space these arguments point to, you also don't clean them up. Finally, we register
the callback using
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add()</CODE
></A
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>bro_event_registry_add(bc, "remote_conn", remote_conn_cb, NULL);
</PRE
></TD
></TR
></TABLE
><P
> In this case we have no additional data to be passed into the
callback, so we use <CODE
CLASS="CONSTANT"
>NULL</CODE
> for the last argument.
If you have multiple events you are interested in, register
each one in this fashion.
</P
></LI
><LI
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Compact argument passing.</B
></SPAN
> This is designed for
situations when you have to determine how to handle different types of
events at runtime, for example when writing language bindings or when
implementing generic event handlers for multiple event types.
The callback is passed a connection handle and the
user data as above but is only passed one additional pointer, to a
<SPAN
CLASS="TYPE"
>BroEvMeta</SPAN
> structure. This structure contains all metadata
about the event, including its name, timestamp (in UTC) of creation,
number of arguments, the arguments'
types (via type tags as listed in <A
HREF="c84.html#TABLE-1"
>Table 1</A
>),
and the arguments themselves.
</P
><P
> In order to register a callback with compact argument passing, use
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD-COMPACT"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add_compact()</CODE
></A
>
and pass it similar arguments as you'd use with
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add()</CODE
></A
>.
The callback's type is defined as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>typedef void (*BroCompactEventFunc) (BroConn *bc, void *user_data, BroEvMeta *meta);
</PRE
></TD
></TR
></TABLE
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>As before, Broccoli manages the lifecycle of event parameters.
You do not have to clean up the <SPAN
CLASS="TYPE"
>BroEvMeta</SPAN
>
structure or any of its contents.
</P
></TD
></TR
></TABLE
></DIV
><P
> Below is sample code for extracting the arguments form the <SPAN
CLASS="TYPE"
>BroEvMeta</SPAN
>
structure, using our running example. This is still written with the assumption
that we know the types of the arguments, but note that this is not a requirement
for this style of callback.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>void remote_conn_cb(BroConn *bc, void *user_data, BroEvMeta *meta)
{
int *req_id;
BroRecord *rec;
/* For demonstration, print out the event's name: */
printf("Handling a %s event.\n", meta-&#62;ev_name);
/* Sanity-check the number of arguments: */
if (meta-&#62;ev_numargs != 2)
{ /* error */ }
/* Sanity-check the argument types: */
if (meta-&#62;ev_args[0].arg_type != BRO_TYPE_INT)
{ /* error */ }
if (meta-&#62;ev_args[1].arg_type != BRO_TYPE_RECORD)
{ /* error */ }
req_id = (int *) meta-&#62;ev_args[0].arg_data;
rec = (BroRecord *) meta-&#62;ev_args[1].arg_data;
/* ... */
}
</PRE
></TD
></TR
></TABLE
><P
> Finally, register the callback using
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-ADD-COMPACT"
><CODE
CLASS="FUNCTION"
>bro_event_registry_add_compact()</CODE
></A
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>bro_event_registry_add_compact(bc, "remote_conn", remote_conn_cb, NULL);
</PRE
></TD
></TR
></TABLE
></LI
></UL
>
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN527"
>3.3.6.2. Requesting event delivery</A
></H3
><P
> At this point, Broccoli knows what to do with the requested events upon
arrival. What's left to do is to let the remote Bro know that you
would like to receive the events for which you registered. If you haven't
yet called <A
HREF="broccoli-broccoli.html#BRO-CONN-CONNECT"
><CODE
CLASS="FUNCTION"
>bro_conn_connect()</CODE
></A
>,
then there is nothing to do, since that function will request the registered
events anyway. Once connected, you can still request events. To do so, call
<A
HREF="broccoli-broccoli.html#BRO-EVENT-REGISTRY-REQUEST"
><CODE
CLASS="FUNCTION"
>bro_event_registry_request()</CODE
></A
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>bro_event_registry_request(bc);
</PRE
></TD
></TR
></TABLE
><P
> This mechanism also implies that no unrequested events will be delivered
to us (and if that happened for whatever reason, the event would simply
be dropped on the floor).
</P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Note that at the moment you cannot unrequest events, nor
can you request events based on predicates on the values of the
events' arguments.</B
></SPAN
></P
></TD
></TR
></TABLE
></DIV
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="AEN539"
>3.3.6.3. Reading events from the connection handle</A
></H3
><P
> At this point the remote Bro will start sending you the requested events
once they are triggered. What is left to do is to read the arriving events
from the connection and trigger dispatching them to the registered callbacks.
</P
><P
> If you are writing a new Bro-enabled application, this is easy, and you can
choose among two approaches: polling explicitly via Broccoli's API, or using
<CODE
CLASS="FUNCTION"
>select()</CODE
> on the file handle associated with a <SPAN
CLASS="TYPE"
>BroConn</SPAN
>.
The former case is particularly straightforward; all you need to do is
call
<A
HREF="broccoli-broccoli.html#BRO-CONN-PROCESS-INPUT"
><CODE
CLASS="FUNCTION"
>bro_conn_process_input()</CODE
></A
>,
which will go off and check if any events have arrived and if so, dispatch
them accordingly. This function does not block &mdash; if no events have
arrived, then the call will return immediately. For more fine-grained control
over your I/O handling, you will probably want to use
<A
HREF="broccoli-broccoli.html#BRO-CONN-GET-FD"
><CODE
CLASS="FUNCTION"
>bro_conn_get_fd()</CODE
></A
>
to obtain the file descriptor of your connection and then incorporate that
in your standard <CODE
CLASS="FUNCTION"
>FD_SET</CODE
>/<CODE
CLASS="FUNCTION"
>select()</CODE
>
code. Once you have determined that data in fact are ready to be read from
the obtained file descriptor, you can then try another
<A
HREF="broccoli-broccoli.html#BRO-CONN-PROCESS-INPUT"
><CODE
CLASS="FUNCTION"
>bro_conn_process_input()</CODE
></A
>,
this time knowing that it'll find something to dispatch.
</P
><P
> As a side note, if you don't process arriving events frequently enough,
then TCP's flow control will start to slow down the sender until eventually
events will queue up and be dropped at the sending end.
</P
></DIV
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN554"
>3.3.7. Handling records</A
></H2
><P
> Broccoli supports record structures, i.e., types that pack a set of values
together, placing each value into its own field. In Broccoli, the way you handle
records is somewhat similar to events:
after creating an empty record (of opaque type <SPAN
CLASS="TYPE"
>BroRecord</SPAN
>, you can
iteratively add fields and values to it. The main difference is that you must specify a
field name with the value; each value in a record can be identified both by position
(a numerical index starting from zero), and by field name. You can retrieve vals
in a record by field index or field name. You can also reassign values.
There is no explicit, IDL-style definition of record types. You define the type of
a record implicitly by the sequence of field names and the sequence of the types
of the values you put into the record.
</P
><P
> Note that all fields in a record must be assigned before it can be shipped.
</P
><P
> The API for record composition consists of
<A
HREF="broccoli-broccoli.html#BRO-RECORD-NEW"
><CODE
CLASS="FUNCTION"
>bro_record_new()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-RECORD-FREE"
><CODE
CLASS="FUNCTION"
>bro_record_free()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-RECORD-ADD-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_add_val()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-RECORD-SET-NTH-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_set_nth_val()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-RECORD-SET-NAMED-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_set_named_val()</CODE
></A
>.
</P
><P
> On records that use field names, the names of individual fields can be extracted using
<A
HREF="broccoli-broccoli.html#BRO-RECORD-GET-NTH-NAME"
><CODE
CLASS="FUNCTION"
>bro_record_get_nth_name()</CODE
></A
>.
Extracting values from a record is done using
<A
HREF="broccoli-broccoli.html#BRO-RECORD-GET-NTH-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_get_nth_val()</CODE
></A
> and
<A
HREF="broccoli-broccoli.html#BRO-RECORD-GET-NAMED-VAL"
><CODE
CLASS="FUNCTION"
>bro_record_get_named_val()</CODE
></A
>.
The former allows numerical indexing of the fields in the record, the latter provides
name-based lookups. Both need to be passed the record you want to extract a value from,
the index or name of the field, and either a pointer to an <SPAN
CLASS="TYPE"
>int</SPAN
> holding a
<SPAN
CLASS="TYPE"
>BRO_TYPE_xxx</SPAN
> value (see again <A
HREF="c84.html#TABLE-1"
>Table 1</A
> for a
summary of those types) or <CODE
CLASS="CONSTANT"
>NULL</CODE
>. The pointer, if not
<CODE
CLASS="CONSTANT"
>NULL</CODE
>, serves two purposes: type checking and type retrieval.
Type checking is performed if the value of the <SPAN
CLASS="TYPE"
>int</SPAN
> upon calling the
functions is not <SPAN
CLASS="TYPE"
>BRO_TYPE_UNKNOWN</SPAN
>. The type tag of the requested record
field then has to match the type tag stored in the <SPAN
CLASS="TYPE"
>int</SPAN
>, otherwise
<CODE
CLASS="CONSTANT"
>NULL</CODE
> is returned. If the <SPAN
CLASS="TYPE"
>int</SPAN
> stores <SPAN
CLASS="TYPE"
>BRO_TYPE_UNKNOWN</SPAN
>
upon calling, no type-checking is performed. In <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>both</B
></SPAN
> cases,
the <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>actual</B
></SPAN
> type of the
requested record field is returned in the <SPAN
CLASS="TYPE"
>int</SPAN
> pointed to upon
return from the function. Since you have no guarantees of the type of the value
upon return if you pass <CODE
CLASS="CONSTANT"
>NULL</CODE
> as the <SPAN
CLASS="TYPE"
>int</SPAN
> pointer,
this is a bad idea and either <SPAN
CLASS="TYPE"
>BRO_TYPE_UNKNOWN</SPAN
> or another type value
should always be used.
</P
><P
> For example, you could extract the value of the record field "label", which
we assume should be a string, in the following ways:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>BroRecord *rec = /* obtained somehow */
BroString *string;
int type;
/* --- Example 1 --- */
type = BRO_TYPE_STRING; /* Use type-checking, will not accept other type */
if (! (string = bro_record_get_named_val(rec, "label", &#38;type))) {
/* Error handling, either there's no field of that value,
* or the value is not of BRO_TYPE_STRING. The actual
* type is now stored in "type".
*/
}
/* --- Example 2 --- */
type = BRO_TYPE_UNKNOWN; /* No type checking, just report the existant type */
if (! (string = bro_record_get_named_val(rec, "label", &#38;type))) {
/* Error handling, no field of that name exists. */
}
printf("The type of the value in field 'label' is %i\n", type);
/* --- Example 3 --- */
if (! (string = bro_record_get_named_val(rec, "label", NULL))) {
/* Error handling, no field of that name exists. */
}
/* We now have a value, but we can't really be sure of its type */
</PRE
></TD
></TR
></TABLE
><P
> Record fields can be records, for example in the case of Bro's standard
connection record type. In this case, in order to get to a nested record, you
use <CODE
CLASS="CONSTANT"
>BRO_TYPE_RECORD</CODE
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>void remote_conn_cb(BroConn *bc, int *req_id, BroRecord *conn) {
BroRecord *conn_id;
int type = BRO_TYPE_RECORD;
if (! (conn_id = bro_record_get_named_val(conn, "id", &#38;type))) {
/* Error handling */
}
}
</PRE
></TD
></TR
></TABLE
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN599"
>3.3.8. Handling tables</A
></H2
><P
> Broccoli supports Bro-style tables, i.e., associative containers that map
instances of a key type to an instance of a value type. A given key
can only ever point to a single value. The key type can be
<SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>composite</B
></SPAN
>, i.e., it may consist of an ordered
sequence ofdifferent types, or it can be <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>direct</B
></SPAN
>,
i.e., consisting of a single type (such as an integer, a string, or
a record).
</P
><P
> The API for table manipulation consists of
<A
HREF="broccoli-broccoli.html#BRO-TABLE-NEW"
><CODE
CLASS="FUNCTION"
>bro_table_new()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-FREE"
><CODE
CLASS="FUNCTION"
>bro_table_free()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-INSERT"
><CODE
CLASS="FUNCTION"
>bro_table_insert()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-FIND"
><CODE
CLASS="FUNCTION"
>bro_table_find()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-GET-SIZE"
><CODE
CLASS="FUNCTION"
>bro_table_get_size()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-GET-TYPES"
><CODE
CLASS="FUNCTION"
>bro_table_get_types()</CODE
></A
>,
and
<A
HREF="broccoli-broccoli.html#BRO-TABLE-FOREACH"
><CODE
CLASS="FUNCTION"
>bro_table_foreach()</CODE
></A
>.
</P
><P
> Tables are handled similarly to records in that typing is determined
dynamically by the initial key/value pair inserted. The resulting types
can be obtained via
<A
HREF="broccoli-broccoli.html#BRO-TABLE-GET-TYPES"
><CODE
CLASS="FUNCTION"
>bro_table_get_types()</CODE
></A
>.
Should the types not have been determined yet, <CODE
CLASS="CONSTANT"
>BRO_TYPE_UNKNOWN</CODE
>
will result. Also, as with records,
values inserted into the table are copied internally, and the ones passed
to the insertion functions remain unaffected.
</P
><P
> In contrast to records, table entries can be iterated. By passing a function
of signature
<A
HREF="broccoli-broccoli.html#BROTABLECALLBACK"
><CODE
CLASS="FUNCTION"
>BroTableCallback()</CODE
></A
>
and a pointer to data of your choosing,
<A
HREF="broccoli-broccoli.html#BRO-TABLE-FOREACH"
><CODE
CLASS="FUNCTION"
>bro_table_foreach()</CODE
></A
>
will invoke the given function for each key/value pair stored in the table.
Return <CODE
CLASS="CONSTANT"
>TRUE</CODE
> to keep the iteration going, or <CODE
CLASS="CONSTANT"
>FALSE</CODE
>
to stop it.
</P
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
> The main thing to know about Broccoli's tables is how to use composite key
types. To avoid additional API calls, you may treat composite key types
exactly as records, though you do not need to use field names when assigning
elements to individual fields. So in order to insert a key/value pair, you
create a record with the needed items assigned to its slots, and use this
record as the key object. In order to differentiate composite index types
from direct ones consisting of a single record, use <CODE
CLASS="CONSTANT"
>BRO_TYPE_LIST</CODE
>
as the type of the record, as opposed to <CODE
CLASS="CONSTANT"
>BRO_TYPE_RECORD</CODE
>.
Broccoli will then know to interpret the record
as an ordered sequence of items making up a composite element, not a regular
record.
</P
></TD
></TR
></TABLE
></DIV
><P
> <TT
CLASS="FILENAME"
>brotable.c</TT
> in the test subdirectory of the Broccoli tree
contains an extensive example of using tables with composite as well as direct
indexing types.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN636"
>3.3.9. Handling sets</A
></H2
><P
> Sets are essentially tables with void value types.
The API for set manipulation consists of
<A
HREF="broccoli-broccoli.html#BRO-SET-NEW"
><CODE
CLASS="FUNCTION"
>bro_set_new()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-SET-FREE"
><CODE
CLASS="FUNCTION"
>bro_set_free()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-SET-INSERT"
><CODE
CLASS="FUNCTION"
>bro_set_insert()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-SET-FIND"
><CODE
CLASS="FUNCTION"
>bro_set_find()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-SET-GET-SIZE"
><CODE
CLASS="FUNCTION"
>bro_set_get_size()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-SET-GET-TYPE"
><CODE
CLASS="FUNCTION"
>bro_set_get_type()</CODE
></A
>,
and
<A
HREF="broccoli-broccoli.html#BRO-SET-FOREACH"
><CODE
CLASS="FUNCTION"
>bro_set_foreach()</CODE
></A
>.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN653"
>3.3.10. Associating data with connections</A
></H2
><P
> You will often find that you would like to connect data with
a <TT
CLASS="FILENAME"
>BroConn</TT
>. Broccoli provides an API that
lets you associate data items with a connection handle through
a string-based key&ndash;value registry. The functions of interest
are
<A
HREF="broccoli-broccoli.html#BRO-CONN-DATA-SET"
><CODE
CLASS="FUNCTION"
>bro_conn_data_set()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-CONN-DATA-GET"
><CODE
CLASS="FUNCTION"
>bro_conn_data_get()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-CONN-DATA-DEL"
><CODE
CLASS="FUNCTION"
>bro_conn_data_del()</CODE
></A
>.
You need to provide a string identifier for a data item and can then use
that string to register, look up, and remove the associated data item.
Note that there is currently no mechanism to trigger a destructor
function for registered data items when the Bro connection is terminated.
You therefore need to make sure that all data items that you do
not have pointers to via some other means are properly released before
calling
<CODE
CLASS="FUNCTION"
>bro_disconnect()</CODE
>.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN665"
>3.3.11. Configuration files</A
></H2
><P
>
Imagine you have instrumented the mother of all server applications.
Building it takes forever, and every now and then you need to change
some of the parameters that your Broccoli code uses, such as the host names
of the Bro agents to talk to.
To allow you to do this quickly, Broccoli comes with support for
configuration files. All you need to do is change the settings in the
file and restart the application (we're considering adding support
for volatile configuration items that are read from the file every
time they are requested).
</P
><P
> A configuration is read from a single configuration file.
This file can be read from two different locations:
<P
></P
><UL
><LI
><P
>The system-wide configuration file. You can obtain the location
of this config file by running <TT
CLASS="FILENAME"
>broccoli-config --config</TT
>.
</P
></LI
><LI
><P
>Alternatively, a per-user configuration file stored in <TT
CLASS="FILENAME"
>~/.broccoli.conf</TT
>
can be used.
</P
></LI
></UL
>
If a user has a configuration file in <TT
CLASS="FILENAME"
>~/.broccoli.conf</TT
>,
it is used exclusively, otherwise the global one is used.
</P
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
><TT
CLASS="FILENAME"
>~/.broccoli.conf</TT
> will only be used if
it is a regular file, not executable, and neither group nor others have
any permissions on the file. That is, the file's permissions must look
like <CODE
CLASS="FUNCTION"
>-rw-------</CODE
> or <CODE
CLASS="FUNCTION"
>-r--------</CODE
>.
</B
></SPAN
></P
></TD
></TR
></TABLE
></DIV
><P
> In the configuration file, a "#" anywhere starts a comment that runs
to the end of the line. Configuration items are specified as key-value
pairs:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
># This is the Broccoli system-wide configuration file.
#
# Entries are of the form &#60;identifier&#62; &#60;value&#62;, where the identifier
# is a sequence of letters, and value can be a string (including
# whitespace), and floating point or integer numbers. Comments start
# with a "#" and go to the end of the line. For boolean values, you
# may also use "yes", "on", "true", "no", "off", or "false".
# Strings may contain whitespace, but need to be surrounded by
# double quotes '"'.
#
# Examples:
#
Foo/PeerName mybro.securesite.com
Foo/PortNum 123
Bar/SomeFloat 1.23443543
Bar/SomeLongStr "Hello World"
</PRE
></TD
></TR
></TABLE
><P
> You can also have multiple sections in your configuration. Your application can
select a section as the current one, and queries for configuration settings will
then only be answered with values specified in that section. A section is started
by putting its name (no whitespace please) between square brackets. Configuration
items positioned before the first section title are in the default domain and
will be used by default.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
># This section contains all settings for myapp.
[ myapp ]
</PRE
></TD
></TR
></TABLE
><P
> You can name identifiers any way you like, but to keep things
organized it is recommended to keep a namespace hierarchy similar
to the file system. In the code, you can query configuration
items using
<A
HREF="broccoli-broccoli.html#BRO-CONF-GET-STR"
><CODE
CLASS="FUNCTION"
>bro_conf_get_str()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-CONF-GET-INT"
><CODE
CLASS="FUNCTION"
>bro_conf_get_int()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-CONF-GET-DBL"
><CODE
CLASS="FUNCTION"
>bro_conf_get_dbl()</CODE
></A
>.
You can switch between sections using
<A
HREF="broccoli-broccoli.html#BRO-CONF-SET-DOMAIN"
><CODE
CLASS="FUNCTION"
>bro_conf_set_domain()</CODE
></A
>.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN696"
>3.3.12. Using dynamic buffers</A
></H2
><P
> Broccoli provides an API for dynamically allocatable, growable, shrinkable,
and consumable buffers with <CODE
CLASS="FUNCTION"
>BroBuf</CODE
>s. You may or may
not find this useful &mdash; Broccoli mainly provides this feature in
<TT
CLASS="FILENAME"
>broccoli.h</TT
> because these buffers are used internally
anyway and because they are typical case of something that people implement
themselves over and over again, for example to collect a set of data before
sending it through a file descriptor, etc.
</P
><P
> The buffers work as follows. The structure implementing a buffer is
called BroBuf. BroBufs are initialized to a default size when created via
<A
HREF="broccoli-broccoli.html#BRO-BUF-NEW"
><CODE
CLASS="FUNCTION"
>bro_buf_new()</CODE
></A
>,
and released using
<A
HREF="broccoli-broccoli.html#BRO-BUF-FREE"
><CODE
CLASS="FUNCTION"
>bro_buf_free()</CODE
></A
>.
Each BroBuf has a content
pointer that points to an arbitrary location between the start of the
buffer and the first byte after the last byte currently
used in the buffer (see buf_off in the illustration below). The content
pointer can seek to arbitrary locations, and data can be copied from and
into the buffer, adjusting the content pointer accordingly.
You can repeatedly append data to end of the buffer's used contents using
<A
HREF="broccoli-broccoli.html#BRO-BUF-APPEND"
><CODE
CLASS="FUNCTION"
>bro_buf_append()</CODE
></A
>.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13; &#60;---------------- allocated buffer space ------------&#62;
&#60;======== used buffer space ========&#62;
^ ^ ^ ^
| | | |
`buf `buf_ptr `buf_off `buf_len
</PRE
></TD
></TR
></TABLE
><P
> Have a look at the following functions for the details:
<A
HREF="broccoli-broccoli.html#BRO-BUF-NEW"
><CODE
CLASS="FUNCTION"
>bro_buf_new()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-FREE"
><CODE
CLASS="FUNCTION"
>bro_buf_free()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-APPEND"
><CODE
CLASS="FUNCTION"
>bro_buf_append()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-CONSUME"
><CODE
CLASS="FUNCTION"
>bro_buf_consume()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-RESET"
><CODE
CLASS="FUNCTION"
>bro_buf_reset()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-GET"
><CODE
CLASS="FUNCTION"
>bro_buf_get()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-GET-END"
><CODE
CLASS="FUNCTION"
>bro_buf_get_end()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-GET-SIZE"
><CODE
CLASS="FUNCTION"
>bro_buf_get_size()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-GET-USED-SIZE"
><CODE
CLASS="FUNCTION"
>bro_buf_get_used_size()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-PTR-GET"
><CODE
CLASS="FUNCTION"
>bro_buf_ptr_get()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-PTR-TELL"
><CODE
CLASS="FUNCTION"
>bro_buf_ptr_tell()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-PTR-SEEK"
><CODE
CLASS="FUNCTION"
>bro_buf_ptr_seek()</CODE
></A
>,
<A
HREF="broccoli-broccoli.html#BRO-BUF-PTR-CHECK"
><CODE
CLASS="FUNCTION"
>bro_buf_ptr_check()</CODE
></A
>, and
<A
HREF="broccoli-broccoli.html#BRO-BUF-PTR-READ"
><CODE
CLASS="FUNCTION"
>bro_buf_ptr_read()</CODE
></A
>.
</P
></DIV
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN738"
>3.4. Configuring encrypted communication</A
></H1
><P
> Encrypted communication between Bro peers takes place over an SSL connection in
which both endpoints of the connection are authenticated. This requires at least
some PKI in the form of a certificate authority (CA) which you use to issue and sign
certificates for your Bro peers. To facilitate the SSL setup, each peer requires
three documents: a certificate signed by the CA and containing the public key, the
corresponding private key, and a copy of the CA's certificate.
</P
><P
> The OpenSSL command line tool <B
CLASS="COMMAND"
>openssl</B
> can be used to create all
files neccessary, but its unstructured arguments and poor documentation make it
a pain to use and waste lots of people a lot of time<A
NAME="AEN743"
HREF="#FTN.AEN743"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
>. Therefore, the Bro distribution comes with two scripts,
<B
CLASS="COMMAND"
>ca-create</B
> and <B
CLASS="COMMAND"
>ca-issue</B
>. You use the former
once to set up your CA, and the latter to create a certificate for each of the Bro
peers in your infrastructure.
<P
></P
><UL
><LI
><P
><B
CLASS="COMMAND"
>ca-create</B
> lets you choose a directory in which the
CA maintains its files. If you set <CODE
CLASS="VARNAME"
>BRO_CA_DIR</CODE
> in your
environment, it will be used for this purpose. After entering a passphrase
for the private key of your CA, you can find the self-signed certificate
of your CA in <TT
CLASS="FILENAME"
>$BRO_CA_DIR/ca_cert.pem</TT
>.
</P
></LI
><LI
><P
><B
CLASS="COMMAND"
>ca-issue</B
> first requires the directory of the CA,
offering <TT
CLASS="FILENAME"
>$BRO_CA_DIR</TT
> if that is found. It asks you for
a prefix for the certificate to be generated, for the passphrase of the
private key of the CA so the new certificate can be signed, for the
passphrase for the new private key, and for a few parameters that make up
the "distinguished name" of the certificate. This name (i.e., the combination
of all the fields you enter a value for) must be unique among all your Bro
peers. Once that is done, you find a new certificate named
<TT
CLASS="FILENAME"
>&lt;prefix&gt;.pem</TT
> in your current
directory. This file actually consists of two of the three cryptographic
documents mentioned above, namely the new certificate and the private key.
We refer to it as "certificate" for simplicity.
</P
></LI
></UL
>
In order to enable encrypted communication for your Broccoli application, you
need to put the CA certificate and the peer certificate in the
<CODE
CLASS="VARNAME"
>/broccoli/ca_cert</CODE
> and
<CODE
CLASS="VARNAME"
>/broccoli/host_cert</CODE
> keys, respectively, in the configuration file.
Optionally, you can store the private key in a separate file specified by
<CODE
CLASS="VARNAME"
>/broccoli/host_key</CODE
>.
To quickly enable/disable a certificate configuration, the
<CODE
CLASS="VARNAME"
>/broccoli/use_ssl</CODE
> key can be used.
<DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>This is where you configure whether to use encrypted or unencrypted
connections.</B
></SPAN
></P
><P
>If the <CODE
CLASS="VARNAME"
>/broccoli/use_ssl</CODE
> key is present and set to one of
"yes", "true", "on", or 1, then SSL will be used and an incorrect or
missing certificate configuration will cause connection attempts to fail.
If the key's value is one of "no", "false", "off", or 0, then in no case
will SSL be used and connections will always be cleartext.
</P
><P
>If the <CODE
CLASS="VARNAME"
>/broccoli/use_ssl</CODE
> key is <SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>not</B
></SPAN
>
present, then SSL will be used if a certificate configuration is
found, and invalid certificates will cause the connection to fail.
If no certificates are configured, cleartext connections will be used.
</P
><P
>In no case does an SSL-enabled setup ever fall back to a cleartext one.</P
></TD
></TR
></TABLE
></DIV
>
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>/broccoli/use_ssl yes
/broccoli/ca_cert &#60;path&#62;/ca_cert.pem
/broccoli/host_cert &#60;path&#62;/bro_cert.pem
/broccoli/host_key &#60;path&#62;/bro_cert.key
</PRE
></TD
></TR
></TABLE
><P
> In a Bro policy, you need to load the <TT
CLASS="FILENAME"
>listen-ssl.bro</TT
> policy and
redef <CODE
CLASS="VARNAME"
>ssl_ca_certificate</CODE
> and <CODE
CLASS="VARNAME"
>ssl_private_key</CODE
>,
defined in <TT
CLASS="FILENAME"
>bro.init</TT
>:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>@load listen-ssl
redef ssl_ca_certificate = "&#60;path&#62;/ca_cert.pem";
redef ssl_private_key = "&#60;path&#62;/bro.pem";
</PRE
></TD
></TR
></TABLE
><P
> By default, you will be prompted for the passphrase for the private key matching
the public key in your agent's certificate. Depending on your application's user
interface and deployment, this may be inappropriate. You can store the passphrase
in the config file as well, using the following identifier:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>/broccoli/host_pass foobar
</PRE
></TD
></TR
></TABLE
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
><SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>Make sure that access to your configuration is restricted.</B
></SPAN
></P
><P
> If you provide the passphrase this way, it is obviously essential to have
restrictive permissions on the configuration file. Broccoli partially enforces
this. Please refer to the section on
<A
HREF="c84.html#AEN665"
>configuration files</A
> for details.
</P
></TD
></TR
></TABLE
></DIV
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN785"
>3.5. Configuring event reception in Bro policies</A
></H1
><P
> Before a remote Bro will accept your connection and your events, it needs to have its
policy configured accordingly:
<P
></P
><OL
TYPE="1"
><LI
><P
>Load either <TT
CLASS="FILENAME"
>listen-ssl</TT
> or <TT
CLASS="FILENAME"
>listen-clear</TT
>,
depending on whether you want to have encrypted or cleartext communication. Obviously,
encrypting the event exchange is recommended and cleartext should only be used for
early experimental setups. See below for details on how to set up encrypted
communication via SSL.
</P
></LI
><LI
><P
> You need to find a port to use for the Bros and Broccoli applications that will
listen for connections. Every such agent can use a different port, though default
ports are provided in the Bro policies.
To change the port the Bro agent will be listening on from its default
redefine the <CODE
CLASS="VARNAME"
>listen_port_ssl</CODE
> or
<CODE
CLASS="VARNAME"
>listen_port_clear</CODE
> variables from <TT
CLASS="FILENAME"
>listen-clear.bro</TT
>
or <TT
CLASS="FILENAME"
>listen-ssl.bro</TT
>, respectively. Have a look at these policies as well
as <TT
CLASS="FILENAME"
>remote.bro</TT
> for the default values. Here is the policy
for the unencrypted case:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>@load listen-clear
redef listen_port_clear = 12345/tcp;
</PRE
></TD
></TR
></TABLE
><P
> Including the settings for the cryptographic files introduced in the previous section,
here is the encrypted one:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>@load listen-ssl
redef listen_port_ssl = 12345/tcp;
redef ssl_ca_certificate = "&#60;path&#62;/ca_cert.pem";
redef ssl_private_key = "&#60;path&#62;/bro.pem";
</PRE
></TD
></TR
></TABLE
></LI
><LI
><P
> The policy controlling which peers a Bro agent will communicate with and how this
communication will happen are defined in the <CODE
CLASS="VARNAME"
>destinations</CODE
> table
defined in <TT
CLASS="FILENAME"
>remote.bro</TT
>. This table contains entries of type
<SPAN
CLASS="TYPE"
>Destination</SPAN
>, whose members mostly provide default values so you do not
need to define everything. You need to come up with a tag for the connection
under which it can be found in the table (a creative one would be "broccoli"),
the IP address of the peer, the pattern of names of the events the Bro will accept
from you, whether you want Bro to connect to your
machine on startup or not, if so, a port to connect to (defaults are
<CODE
CLASS="VARNAME"
>default_port_ssl</CODE
> and <CODE
CLASS="VARNAME"
>default_port_clear</CODE
>, also
defined in <TT
CLASS="FILENAME"
>remote.bro</TT
>), a retry timeout, whether to use SSL,
and the class of a connection as set on the Broccoli side via
<A
HREF="broccoli-broccoli.html#BRO-CONN-SET-CLASS"
><CODE
CLASS="FUNCTION"
>bro_conn_set_class()</CODE
></A
>.
</P
><P
> An example could look as follows:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>&#13;redef Remote::destinations += {
["broping"] = [$host = 127.0.0.1, $class="broping", $events = /ping/, $connect=F, $ssl=F]
};
</PRE
></TD
></TR
></TABLE
><P
> This example is taken from <TT
CLASS="FILENAME"
>broping.bro</TT
>, the policy the
remote Bro must run when you want to use the <B
CLASS="COMMAND"
>broping</B
> tool
explained in the <A
HREF="c84.html#AEN843"
>section on testing</A
> below.
It will allow an agent on the local host to connect and send "ping" events.
Our Bro will not attempt to connect, and incoming connections will be expected
in cleartext.
</P
></LI
></OL
>
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN819"
>3.6. Configuring debugging output</A
></H1
><P
> If your Broccoli installation was configured with <B
CLASS="COMMAND"
>--enable-debug</B
>,
Broccoli will report two kinds of debugging information: (<SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>i</B
></SPAN
>)
function call traces and
(<SPAN
CLASS="emphasis"
><B
CLASS="EMPHASIS"
>ii</B
></SPAN
>) individual debugging messages. Both are enabled by default, but can be adjusted
in two ways.
<P
></P
><UL
><LI
><P
>In the configuration file: in the appropriate section of the configuration
file, you can set the keys <CODE
CLASS="FUNCTION"
>/broccoli/debug_messages</CODE
> and
<CODE
CLASS="FUNCTION"
>/broccoli/debug_calltrace</CODE
> to <CODE
CLASS="FUNCTION"
>on</CODE
>/<CODE
CLASS="FUNCTION"
>off</CODE
>
to enable/disable the corresponding output.
</P
></LI
><LI
><P
>In code: you can set the variables
<A
HREF="broccoli-broccoli.html#BRO-DEBUG-CALLTRACE"
><CODE
CLASS="FUNCTION"
>bro_debug_calltrace</CODE
></A
> and
<A
HREF="broccoli-broccoli.html#BRO-DEBUG-MESSAGES"
><CODE
CLASS="FUNCTION"
>bro_debug_messages</CODE
></A
>
to 1/0 at any time to enable/disable the corresponding output.
</P
></LI
></UL
>
</P
><P
> By default, debugging output is inactive (even with debuggin support compiled in).
You need to enable it explicitly either in your code by assigning 1 to
<A
HREF="broccoli-broccoli.html#BRO-DEBUG-CALLTRACE"
><CODE
CLASS="FUNCTION"
>bro_debug_calltrace</CODE
></A
> and
<A
HREF="broccoli-broccoli.html#BRO-DEBUG-MESSAGES"
><CODE
CLASS="FUNCTION"
>bro_debug_messages</CODE
></A
>,
or by enabling it in the configuration file.
</P
></DIV
><BR
CLEAR="all"><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN843"
>3.7. Test programs</A
></H1
><P
> The Broccoli distribution comes with a few small test programs,
located in the <TT
CLASS="FILENAME"
>test/</TT
> directory of the tree.
The most notable one is <CODE
CLASS="FUNCTION"
>broping</CODE
>
<A
NAME="AEN848"
HREF="#FTN.AEN848"
><SPAN
CLASS="footnote"
>[2]</SPAN
></A
>, a mini-version of ping.
It sends "ping" events to a remote Bro agent, expecting "pong" events
in return. It operates in two flavours: one uses atomic types for sending
information across, and the other one uses records. The Bro agent you want
to ping needs to run either the <TT
CLASS="FILENAME"
>broping.bro</TT
> or
<TT
CLASS="FILENAME"
>broping-record.bro</TT
> policies. You can find these
in the <TT
CLASS="FILENAME"
>test/</TT
> directory of the source tree, and
in <TT
CLASS="FILENAME"
>&lt;prefix&gt;/share/broccoli</TT
> in the installed
version. <TT
CLASS="FILENAME"
>broping.bro</TT
> is shown below. By default,
pinging a Bro on the same machine is configured. If you want your Bro
to be pinged from another machine, you need to update the
<CODE
CLASS="VARNAME"
>destinations</CODE
> variable accordingly.
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>@load listen-clear;
global ping_log = open_log_file("ping");
redef Remote::destinations += {
["broping"] = [$host = 127.0.0.1, $events = /ping/, $connect=F, $retry = 60 secs, $ssl=F]
};
event ping(src_time: time, seq: count)
{
event pong(src_time, current_time(), seq);
}
event pong(src_time: time, dst_time: time, seq: count)
{
print ping_log, fmt("ping received, seq %d, %f at src, %f at dest, one-way: %f",
seq, src_time, dst_time, dst_time-src_time);
}
</PRE
></TD
></TR
></TABLE
><P
> <CODE
CLASS="FUNCTION"
>broping</CODE
> sends ping events to Bro. Bro accepts those because they are configured
accordingly in the destinations table. As shown in the policy, ping events
trigger pong events, and <CODE
CLASS="FUNCTION"
>broccoli</CODE
> requests delivery of all pong events back to it.
When running <CODE
CLASS="FUNCTION"
>broping</CODE
>, you'll see something like this:
</P
><TABLE
WIDTH="100%"
BORDER="0"
BGCOLOR="#eaeaf0"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>cpk25@localhost:/home/cpk25/devel/broccoli &#62; ./test/broping
pong event from 127.0.0.1: seq=1, time=0.004700/1.010303 s
pong event from 127.0.0.1: seq=2, time=0.053777/1.010266 s
pong event from 127.0.0.1: seq=3, time=0.006435/1.010284 s
pong event from 127.0.0.1: seq=4, time=0.020278/1.010319 s
pong event from 127.0.0.1: seq=5, time=0.004563/1.010187 s
pong event from 127.0.0.1: seq=6, time=0.005685/1.010393 s
</PRE
></TD
></TR
></TABLE
></DIV
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN743"
HREF="c84.html#AEN743"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>In other
documents and books on OpenSSL you will find this expressed more politely, using
terms such as "daunting to the uninitiated", "challenging", "complex", "intimidating".
</P
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN848"
HREF="c84.html#AEN848"
><SPAN
CLASS="footnote"
>[2]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>Pronunciation is said to be somewhere on the continuum between
"brooping" and "burping".</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c54.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="api.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Installing Broccoli</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Broccoli API Reference</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>