An introduction to Ulogd2 hacking

 

Short introduction to Ulogd2

Ulogd2 is a userspace logging daemon for netfilter/iptables related logging. This is the successor of the ulogd daemon which one of the best mean to log packets coming from Netfilter. Ulogd-2.x uses latest Netfilter features to provide:
  • Packet based logging (via libnetfilter_log or ULOG target)
  • Flow based logging (via libnetfilter_conntrack)
Logging can be done to file, syslog, pcap or a database (MySQL, PostgreSQL, …). To use libnetfilter_log and libnetfilter_conntrack, a kernel superior to 2.6.14 is needed. If you want to give a try to Ulogd2, I suggest you to read the User documentation available from software.inl.fr or pollux’s tutorial.

Ulogd2 hacking

Getting the sources

Ulogd2 is work in progress. It smoothly leave the beta area and should reach the release candidate phase in the upcoming month. Thus, to play with Ulogd2 code I recommand to use the latest git:
git clone git://git.netfilter.org/ulogd2.git
I hack a lot on Ulogd2 and my version may contain some interesting features. If you want to hack over it, you may want to use my personnal git tree. You can browse it at: http://git.inl.fr/cgi-bin/gitweb.cgi?p=ulogd2.git;a=summary To use it:
git clone http://git.inl.fr/git/ulogd2.git ulogd2
This a tree obtained with git-svn, master branch should be in sync with subversion repository and INL branch contains my ulogd2 work. Thus to work over my latest modifications, you can do:
git checkout INL

Hacking modules

Current state of Ulogd2 core (in the src directory) seems to be fairly stable and I will then only focus on modules hacking. The behaviour of a module is defined in a structure of type ulogd_plugin :
static struct ulogd_plugin ip2str_pluging = {
        .name = "IP2STR",
        .input = {
                .keys = ip2str_inp,
                .num_keys = ARRAY_SIZE(ip2str_inp),
                .type = ULOGD_DTYPE_PACKET | ULOGD_DTYPE_FLOW,
        },
        .output = {
                .keys = ip2str_keys,
                .num_keys = ARRAY_SIZE(ip2str_keys),
                .type = ULOGD_DTYPE_PACKET | ULOGD_DTYPE_FLOW,
        },
        .interp = &interp_ip2str,
        .version = ULOGD_VERSION,
};
This is the main starting point when you try to understand inner working of a module. The other starting points in a module are:
  • struct config_keyset: this structure contains a definition of module options
  • the input keys defined in a struct ulogd_key, this structure is pointed in the struct ulogd_plugin by .input.keys
  • the output keys defined in a struct ulogd_key,this structure is pointed in the struct ulogd_plugin by .output.keys
In the case of filtering modules, the main function is the function pointed by .interp in the struct ulogd_plugin defining the module. This function is in charge of building the output keys of the module respectively to the already defined input keys.

Key definition

The definition of keys is done in an array of struct ulogd_key structures.
static struct ulogd_key ip2str_inp[] = {
        [KEY_OOB_FAMILY] = {
                           .type = ULOGD_RET_UINT8,
                           .flags = ULOGD_RETF_NONE,
                           .name = "oob.family",
        },
        [KEY_IP_SADDR] = {
                         .type = ULOGD_RET_IPADDR,
                         .flags = ULOGD_RETF_NONE|ULOGD_KEYF_OPTIONAL,
                         .name = "ip.saddr",
        },
The needed items are:
  • .name: this is the identifier of the key
  • .type: this define the type of data contained in the key
  • .flags: the flags change the behaviour of ulogd2 relatively to the key
Available type and flags are defined in the file include/ulogd/ulogd.h. Ulogd2 is in charge of managing the memory allocated to the output keys defined in the modules. To tell ulogd2 a key is using allocated memory, just simply add the ULOGD_RETF_FREE flags to the key definition. For example, in IP2STR module we have:
{
.type = ULOGD_RET_STRING,
.flags = ULOGD_RETF_FREE,
.name = "ip.daddr.str",
},

Doing the stuff

The simplest ulogd2 plugin is the MAC2STR module. This is a good starting point to build other modules. The previous sections details the init section of the plugin but the main work is done in the .interp function. When a message is fetch by the input module, each plugin instance of the stack is called in turn via a call to the function pointed by .interp in the struct ulogd_plugin. In MAC2STR plugin, the function is defined as follow:
static int interp_mac2str(struct ulogd_pluginstance *pi)
{
        struct ulogd_key *ret = pi->output.keys;
        struct ulogd_key *inp = pi->input.keys;
        if (pp_is_valid(inp, KEY_RAW_MAC)) {
                unsigned char *mac = (unsigned char *) GET_VALUE(inp, KEY_RAW_MAC).ptr;
                int len = GET_VALUE(inp, KEY_RAW_MACLEN).ui16;
                char *mac_str = calloc(len/sizeof(char)*3, sizeof(char));
                char *buf_cur = mac_str;
                int i;
                if (mac_str == NULL)
                        return -1;
                for (i = 0; i < len; i++)
                       buf_cur += sprintf(buf_cur, "%02x%c", mac[i],
                                                i == len - 1 ? 0 : ':');
                ret[KEY_MAC_SADDR].u.value.ptr = mac_str;
                ret[KEY_MAC_SADDR].flags |= ULOGD_RETF_VALID;
        }
        return 0;
}
The main idea is to work with input keys (struct ulogd_key *inp = pi->input.keys;) to build output keys (struct ulogd_key *ret = pi->output.keys;). A value is given to a key by changing the .value element in the structure:
ret[KEY_MAC_SADDR].u.value.ptr = mac_str;
An output key needs to be declared as VALID to be used by other modules. Thus ULOGD_RETF_VALID has to be added to the flags of the key:
ret[KEY_MAC_SADDR].flags |= ULOGD_RETF_VALID;
 Posted by at 12:49

  5 Responses to “An introduction to Ulogd2 hacking”

  1. Can this also log to proprietary databases like MSSQL server or Oracle 12g?

  2. The DBI module could be used to do logging into that databases.

  3. UlogD2 has many function. It will be a great tool to have packets faster and will be a useful medium to make your task faster and reliable.

  4. […] any information through SSDP.  My last resort is to look at actual traffic flows. For that we need ulogd2 and ulogd2-sqlite3. Here are installation instructions for Ubuntu […]

  5. […] reads logs generated by dnsmasq and to get the most detailed results, collects data stored by the Ulog2 daemon on Linux. That limits the amount of people that can initially run the software to people […]

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>