In some scenarios it is helpful to use custom C/C++ functions (e.g., external libraries) from the Bro policy layer. Builtin Functions (BiFs) can help in such situations, and Bro’s bifcl tool makes it easy to build the necessary stubs.
Contents
BiFs provide a convenient way of interaction between the C/C++ event engine and the script policy layer by making C/C++ functions easily available to the policy layer and making policy types, consts, and variables available to the C/C++ layer. (The same principles of C/C++ <—> policy interaction also apply for writing new analyzers. )
There is an example putting everything together, that might also give additional insight: example.html
BiFs are in .bif files in Bro’s source distribution, they are then compiled into C/C++ and Bro policy code using the custom bifcl tool. The C/C++ is included (by #include) in the approriate C/C++ files and then compiled into the core. I.e., Bro must be recompiled if BiFs are changed. You can find the generated bifcl output files in the build/src directory.
While every BiF-file in general supports the full BiF language, the way the generated files are included in C/C++ files limits the places consts, events, functions, etc. should be defined. However, you could add a new BiF-file and add the appropriate includes to the C/C++ files.
Bro variables and constants are represented in the C/C++ layer as pointers to class Val objects. Actually, it is a class hierarchy, with class Val being the ancestor of all derived Val classes. E.g., a count is represented by a Val*, while an enum is represented as an EnumVal. See also Val.h and Val.cc in the Bro distribution for more information.
Complex, user defined types (enums, records, sets, etc.) are represented in the C/C++ layer as pointers to class BroType. Again, a class hierarchy is used with BroType as the base class. E.g., user defined records are represented instances of class RecordType.
Bro event handlers are represented as class EventHandlerPtr. The boolean value of an EventHandlerPtr (e.g., in an if) is true if there is at least one event handler defined for this event.
BiF supports namespaces for the policy layer (modules) as well as the C/C++ layer (namespaces). To use a namespace in a BiF file, use the module <MODULENAME> syntax we know from Bro policy scripts. In addition, you can use fully qualified identifiers, i.e., <MODULENAME>::<IDENTIFIER>.
You can use the special module name GLOBAL to switch back to the global default namespace.
We first describe the BiF syntax. There is also a full example at the end demonstrating (almost all) of the BiF features and how to use them.
By convention (see above), constants that you want to have easily accessible in the C/C++ layer are declared in const.bif. You still need to define these constants in bro.init. Adding them to the BiF files merely makes them easily available in C/C++. If a const is declared in a BiF but not defined, it will result in a runtime error.
Syntax:
const <IDENTIFIER> : <BROTYPE>;
<IDENTIFIER> can include a module/namespace specification and must match a define const (e.g., in bro.init).
<BROTYPE> can be any Bro type, either basic types (count, interval, etc.) or user defined types (records).
Examples:
const XYZ::the_time_diff : interval; const constdummy: string;
Some Bro types are converted into basic C/C++ types while others are available as Val*. See bif_type.def in the source directory for a list of these mappings.
Constants are available in the BifConst namespace in C/C++. If a const is part of a Bro module, it is available in BifConst::<MODULENAME> namespace. For the above examples:
double BifConst::XYZ::the_time_diff StringVal* BifConst::constdummy
By convention user-defined types (enum, record, vector, table, and set) that should be easily accessible in C/C++ are declared, but not defined, in type.bif. You still need to define these types in bro.init. However, there is one exception: enums can be defined in a BiF as well.
Enums are supported in .bif and .bro scripts. An enum in a BiF will become available in the event engine and the policy layer.
Example:
module FOO;
enum status %{
s1 = 1,
s2 = 2,
s3 = 3,
%}
Enums are available in C/C++ in the BifTypePtr::Enum namespace as an EnumType*. If the enum is in a Bro module, the C/C++ namespace will be BifTypePtr::Enum::<MODULENAME>. In addition, you have access to a C/C++ enum:
namespace BifEnum { namespace FOO {
enum status {
s1 = 1,
s2 = 2,
s3 = 3,
};
}}
namespace BifTypePtr {
namespace Enum { namespace FOO {
extern EnumType * status;
}}}
You can declare record, set, table, and vector user-defined Bro types in a BiF.
Syntax:
type <IDENTIFIER> : <TYPE_CATEGORY> ;
Where <TYPE_CATEGORY> is one of record, set, table, or vector. <IDENTIFIER> is the name of the type you used when defining the type in bro.init:
| type category | namespace | C type |
|---|---|---|
| record | BifTypePtr::Record | RecordType* |
| set | BifTypePtr::Set | SetType* |
| table | BifTypePtr::Table | TableType* |
| vector | BifTypePtr::Vector | VectorType* |
If a type is in a Bro module, the module name is used as an additional C/C++ namespace, e.g., BifTypePtr::Set::<MODULENAME>.
TODO
TODO
There is an example putting everything together: example.html
© 2011 The Bro Project. Logo design by DigiP.
