I want to provide a flexible, almost universal logging daemon for netfilter ULOG target. Although it provides wide range of functions I'm trying to keep it as simple as possible. These are my thoughts about how the architecture which is most capable of doing that:
It should be possible to add plugins / runtime modules for new protocols, etc. For example the standard logging daemon provides source-ip, dest-ip, source-port, dest-port, etc. Logging for variuos other protocols (GRE, IPsec, ...) may be implemented as modules.
... describe how and where to put the information gained by input plugins. The easiest way is to build a line per packet and fprint it to a file. Some people might want to log into a SQL database or want an output conforming to the intrusion detection systems communication draft from the IETF.
The major clue is providing a framework which is as flexible as possible. Nobody knows what strange network protocols are out there :) Flexibility depends on the communication between the output of the input plugins and input of the output plugins.
Harald, following Rusty's advise, implemented type-key-value triples,
which work quite well for that purpose. Structure used for exchanging
data between input and output plugins is defined in specter.h, and
is called specter_iret_t. Most of time, output plugins precisely know what
data they need, so there must exist good querying system, as input
keys are dynamically defined and stored. Up to ulogd 0.3 this was done
by several linked list iterations, which weren't obviously very fast.
In 0.9 Harald implemented usage of hash tables initialized during
init. The idea was good, but deep levels of data structures one
had to dig into to get simple value and somewhat obscure style
(like accessing ulogd_keyh[] from the inside of plugin) forced
me (Michal) to rewrite this again. That's when fork from ulogd happened.
Abandoning hash tables, specter implementation use only pointers
accessed by general function find_iret(). To simplify usage of
that pointers, simple data structure specter_local_ret_t and
few macros defined in plugins/lret.h were also created.
Note they're not the obligatory extension; one can create his own
implementation based on single find_iret() definition.
Important part of specter is dynamic division into execution groups.
Each group have its own set of plugins, which are invoked independently.
That also means they have separate sets of configure options and data.
This model allows you to set various iptables rules and bind different
actions for them. Currently there are two methods of grouping implemented
- one based on netlink groups, other on the netfilter marks. See the
grouping option description
for details. This functionality allows you to adjust specter strictly
to your needs - it can be small and simple substitute to netfilter LOG
target or universal utility to distribute large portions of logs.