Next Previous Contents

3. CONFIGURATION

3.1 iptables ULOG target

Quick Setup

Just add rules using the ULOG target to your firewalling chain. A very basic example:

iptables -A FORWARD -j ULOG --ulog-nlgroup 32 --ulog-prefix foo

To increase logging performance, try to use the

--ulog-qthreshold N
option (where 1 < N <= 50). The number you specify is the amout of packets batched together in one multipart netlink message. If you set this to 20, the kernel schedules specter only once every 20 packets. All 20 packets are then processed by specter. This reduces the number of context switches between kernel and userspace.

Of course you can combine the ULOG target with the different netfilter match modules. For a more detailed description, have a look at the netfilter HOWTO's, available on the netfilter homepage.

ULOG target reference

--ulog-nlgroup N

The number of the netlink multicast group to which ULOG'ed packets are sent. In specter, you can specify different task for different netlink groups, see specter configfile syntax reference section for more details.

--ulog-cprange N

Copyrange. This works like the 'snaplen' paramter of tcpdump. You can specify a number of bytes up to which the packet is copied. If you say '40', you will receive the first fourty bytes of every packet. Leave it to '0' if you want whole packet to be copied to userspace. For most tcp packets about 50 is mostly enough, but parsing higher level protocols (like in HTTP plugin) require more.

--ulog-qthreshold N

Queue threshold. If a packet is matched by the iptables rule, and already N packets are in the queue, the queue is flushed to userspace. You can use this to implement a policy like: Use a big queue in order to gain high performance, but still have certain packets logged immediately to userspace.

--ulog-prefix STRING

A string that is associated with every packet logged by this rule. You can use this option to later tell from which rule the packet was logged.

ipt_ULOG module parameters

The ipt_ULOG kernel module has a couple of module loadtime parameters which can (and should) be tuned to accomodate the needs of the application:

nlbufsiz N

Netlink buffer size. A buffer of the specified size N is allocated for every netlink group that is used. Please note that due to restrictions of the kernel memory allocator, we cannot have a buffer size > 128kBytes. Larger buffer sizes increase the performance, since less kernel/userspace context switches are needed for the same amount of packets. The backside of this performance gain is a potentially larger delay. The default value is 4096 bytes, which is quite small.

flushtimeout N

The flushtimeout determines, after how many clock ticks (on alpha: 1ms, on x86 and most other platforms: 10ms time units) the buffer/queue is to be flushed, even if it is not full. This can be used to have the advantage of a large buffer, but still a finite maximum delay introduced. The default value is set to 10 seconds.

Example:
modprobe ipt_ULOG nlbufsiz=65535 flushtimeout=100
This would use a buffer size of 64k and a flushtimeout of 100 clockticks (1 second on x86).

3.2 specter

If you were using ulogd before and want to keep your configuration, check the ulogd2specter.pl script in contrib/, which will convert your configfile. But it's still good to learn the new syntax, as it gives you much more possibilities.

specter configfile syntax reference

specter reads its configuration parameters from file, which is mostly `/etc/specter.conf'. It is divided into blocks. Each block start with a opening curly bracket { and end with closing curly bracket }. Nesting of blocks (opening new block inside another) is forbidden, and there's no need for that in specter configuration. In order to distinguish between blocks, each has a name. You can use any name for a block, except two special names: global (which is used to specify general daemon parameters) and plugins (that list available add-ons). Numbers in range 1-SPECTER_GROUPS_MAX has also special functional meaning (see grouping option description). You cannot define the same block twice, but don't have to define all of them. In most configurations you'll be fine with three or four blocks.

Each block have to start in a new line, then goes its name and opening bracket. All blocks (except for global and plugins) are divided into logical sections, which define a configuration space for every plugin. You start a section with a colon : followed by its name. Within section you can finally specify your configuration. global and plugins blocks are simpler in that manner that they don't have any sections. Block ends with a closing bracket. So, in general, block definition looks like this:

name {
include other_block
:section_one
some_option value
# comment
other_option "long value that needs spaces"
:section_two
# this section have no options, but it's important to specify it
:section_three
option
option value # another comment
   ...
}

As you can see, not every option needs a value, in that case its presence will override a default (see below for specific options description). A hash # is used as a comment, as it will cause a rest of line to be ignored. Of course you can use comments everywhere, not only inside blocks. If you need to set an option to a string containing spaces or tabs, you can enclose it inside double quotation marks, as shown above. And if you ever manage to write a very long config line, you can cut it by \ and continue your statement in the line below.

Since 1.2 version of specter you can use include statement to attach contents of other block to current block. Length of include chain is unlimited, but no recursion is allowed. Each include command is performed exacly once, what mostly does what you wanted.

global block syntax

Available global options are:

errignore

This options causes specter to continue running despite of errors generated by plugins. That doesn't affect initialization phase, when all errors cause an exit. This option can be useful on heavy-load systems, when you expect some malloc() to fail. It doesn't take any arguments.

logfile

Path to a file you want specter messages to get logged to. Can be set to stdout or stderr.

loglevel

The lower the value, the more information is logged. If you experience any problems, check lowest, debug loglevel=1, so that you can see all messages. The highest loglevel is 8, which cause only fatal errors to be shown. The default is 3.

rmem

Size of the netlink socket receive memory. You should set this to at least the size of the kernel buffer (nlbufsiz parameter of the ipt_ULOG module). Please note that there is a maximum limit in /proc/sys/net/core/rmem_max which you cannot exceed by increasing the rmem parameter. You may need to raise the system-wide maximum limit before. You can define this variable in kilobytes (suffix it by 'K') or in megabytes (use 'M' suffix).

bufsize

Size of the receive buffer. You should set this to at least the size rmem option has. Like rmem can be suffixed by 'M' or 'K'.

grouping

That option sets grouping strategy. Every block which name is a number within range 1 to SPECTER_GROUPS_MAX (default 32, use --with-group-max build option to change it), will be treaten as a separate execution block. Setting grouping to netlink will cause interpreting these blocks as netlink groups (as defined with --ulog-nlgroup iptables ULOG target option). When nfmark value is used, groups will be compared to mark field in netfilter packet (see iptables(8) for more details on MARK module). If you find it a bit complicated, check examples section.

nlgroup

Will set netlink group to listen to. Can't be used with grouping set to netlink, as several nlgroups are used in that case.

plugins block syntax

plugins block structure is very simple. In each line symbolic name and path to plugin binary have to be provided, like in a example:

BASE    /lib/specter/specter_BASE.so
Name can be anything you want, but it's probably the most informative to set it to plugin's name. You should then use this name as sections names.

Please note that setting paths doesn't mean corresponding plugins will be loaded. You have to use them in blocks in order to force their load. That mean you can list all plugins you have compiled and select which to use by configuring execute blocks adequately.

specter commandline option reference

Apart from the config file, there are a couple of commandline options to specter:

-h --help

Print a help message about the commandline options.

-V --version

Print version information about specter.

-d --daemon

Fork off into daemon mode. Unless you are debugging, you will want to use this most of the time.

-c --configfile

Using this commandline option, an alternate config file can be used. This is important if multiple instances of specter are to be run on a single machine.

-u --uid

This option tells specter to drop its privileges and run as given user.

-g --gid

This option tells specter to drop its privileges and run as given group.

Examples

For description of plugins and their options, see plugins section.

Example 1

Say, you just want to log non-related tcp and udp packets in separate files. You must first set up your netfilter:

    # iptables -A INPUT -p tcp -m state --state INVALID -j ULOG --ulog-nlgroup 1
    # iptables -A INPUT -p udp -m state --state INVALID -j ULOG --ulog-nlgroup 2
And now use this specter configuration:
    plugins {
        BASE    /lib/specter/specter_BASE.so
        LOCAL   /lib/specter/specter_LOCAL.so
        LOGEMU  /lib/specter/specter_LOGEMU.so
    }

    1 {
        :BASE
        :LOCAL
        :LOGEMU
        logfile /var/log/specter.tcp
    }

    2 {
        :BASE
        :LOCAL
        :LOGEMU
        logfile /var/log/specter.udp
    }

Example 2

Maybe you want to analyze every packet that passes your HTTP server with a application that uses pcap-style files? Prepare you firewall:

    # iptables -A INPUT -p tcp --dport 80 -j ULOG --ulog-nlgroup 5
    # iptables -A OUTPUT -p tcp --sport 80 -j ULOG --ulog-nlgroup 5
Then use this configuration, so all http traffic will be saved in a /var/log/specter.http. But you expect some attacks and want packets to appear immediately in log, so you use sync option as well.
    plugins {
        BASE    /lib/specter/specter_BASE.so
        PCAP    /lib/specter/specter_PCAP.so
    }

    5 {
        :BASE
        :PCAP
        file /var/log/specter.http
        sync
    }

Example 3

You're very paranoid and want to save all IPs that tried to ping you in a database, yes? Logging tcp requests are also in you concern, right? Moreover, you don't want to occupy more than one netlink group, so you decide to use mark module to divide packets into groups. Try these iptables rules:

    # iptables -t mangle -A INPUT -p icmp --icmp-type echo-request -j MARK --set-mark 13
    # iptables -t mangle -A INPUT -p tcp -m state --state NEW -j MARK --set-mark 15
    # iptables -A INPUT -m mark --mark 13 -j ULOG --ulog-nlgroup 1
    # iptables -A INPUT -m mark --mark 15 -j ULOG --ulog-nlgroup 1
This config will do the rest:
    global {
        grouping nfmark
        nlgroup 1
    }

    plugins {
        BASE    /lib/specter/specter_BASE.so
        MYSQL   /lib/specter/specter_MYSQL.so
    }

    13 {
        :BASE
        :MYSQL
        db mydb
        host localhost
        user username
        pass password
        table pings
    }

    15 {
        :BASE
        :MYSQL
        db mydb
        host localhost
        user username
        pass password
        table tcp_requests
    }

Example 4

You don't like fragmented packets? You can automaticaly block anyone who ever send you fragmented tcp packet. Use this single iptables rule:

    # iptables -A INPUT -p tcp -f -j ULOG --ulog-nlgroup 1
Now use this config to dynamically change your netfilter configuration with the use of EXEC plugin:
    plugins {
        BASE    /lib/specter/specter_BASE.so
        EXEC    /lib/specter/specter_EXEC.so
    }

    1 {
        :BASE
        :EXEC
        command "/usr/sbin/iptables -A INPUT -p tcp -s %S --sport %s -j DROP"
    }
BASE plugin is needed to support recognition of %S and %s tags.


Next Previous Contents