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.
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.
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.
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.
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.
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:
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.
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.
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).
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 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.
Available global options are:
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.
Path to a file you want specter messages to get logged to. Can be set to
stdout or stderr.
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.
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).
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'.
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.
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 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.
Apart from the config file, there are a couple of commandline options to specter:
Print a help message about the commandline options.
Print version information about specter.
Fork off into daemon mode. Unless you are debugging, you will want to use this most of the time.
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.
This option tells specter to drop its privileges and run as given user.
This option tells specter to drop its privileges and run as given group.
For description of plugins and their options, see plugins section.
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
}
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
}
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
}
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.