Firewall logging is very important, both to detect break-in attempts and to ensure that firewall rules are working properly. Unfortunately, it’s often difficult to predict in advance which rules and what information should be logged. Consequently, it’s common practice to err on the side of verbosity. Given the amount of traffic that any machine connected to the Internet is exposed to, it’s critical that firewall logs be separated from normal logs in order to ease monitoring. What follows are two methods to accomplish this using iptables on Linux. The first method uses traditional syslog facility/priority filtering. The second, more robust method filters based on message content with rsyslog.
The Old Way: Use a Fixed Priority for iptables
The traditional UNIX syslog service only has two ways to categorize, and consequently route, messages: facility and priority. Facilities include kernel, mail, daemon, etc. Priorities include emergency, alert, warning, debug, etc. The Linux iptables firewall runs in the kernel and therefore always has the facility set to kern. Using traditional syslog software, the only way you can separate iptables messages from other kernel messages is to set the priority on all iptables messages to something specific that hopefully isn’t used for other kernel logging.
For example, you could add something like the following to /etc/syslog.conf
:
kern.=debug -/var/log/iptables.log
and specifically remove the kernel debugging messages from all other logs like so:
kern.*;kern.!=debug -/var/log/kern.log
and in each iptables logging rule use the command line option --log-level debug
.
There are two distinct disadvantages to this approach. First, there’s no guarantee that other kernel components won’t use the priority you’ve set iptables to log at. There’s a real possibility that useful messages will be lost in the deluge of firewall logging. Second, this approach prevents you from actually setting meaningful priorities in your firewall logs. You might not care about random machines hammering Windows networking ports, but you definitely want to know about malformed packets reaching your server.
The New Way: Filter Based on Message Content with rsyslog
rsyslog is mostly a drop-in replacement for a tradtional syslog daemon–on Linux, klogd and sysklogd. In fact, on Debian and Ubuntu, you can simply:
$ sudo apt-get install rsyslog
and if you haven’t customized /etc/syslog.conf
, logging should continue to work in precisely the same way. rsyslog has been the default syslog on Red Hat/Fedora based systems for a number of versions now, but if it’s not installed:
$ sudo yum install rsyslog
Configure iptables to Use a Unique Prefix
We’ll setup rsyslog to filter based on the beginning of a message from iptables. So, for each logging rule in your firewall script, add --log-prefix "iptables: "
. Most firewall builder applications can be easily configured to add a prefix to every logging rule. For example, if you’re using firehol as I am, you could add:
FIREHOL_LOG_PREFIX="firehol: "
to /etc/firehol/firehol.conf
.
Configure rsyslog to Filter Based on Prefix
Create /etc/rsyslog.d/iptables.conf
with the following contents:
:msg, startswith, "iptables: " -/var/log/iptables.log & ~
The first line means send all messages that start with “iptables: ” to /var/log/iptables.log
. The second line means discard the messages that were matched in the previous line. The second line is of course optional, but it saves the trouble of explicitly filtering out firewall logs from subsequent syslog rules.
When I configured this on my own machines, I did notice one issue that may be a peculiarity of firehol, but it’s probably worth mentioning anyway. It seems that firehol adds an extra single quote at the beginning of log messages that needs to be matched in the rsyslog rule. For example, here’s a log message from firehol:
Apr 17 12:41:07 tick kernel: 'firehol: 'IN-internet':'IN=eth0 OUT= MAC=fe:fd:cf:c0:47:b5:00:0e:39:6f:48:00:08:00 SRC=189.137.225.191 DST=207.192.75.74 LEN=64 TOS=0x00 PREC=0x00 TTL=32 ID=5671 DF PROTO=TCP SPT=3549 DPT=5555 WINDOW=65535 RES=0x00 SYN URGP=0
Notice the extra quote after “kernel: ” and before “firehol: “. So, on my machine I configured the rsyslog filter like so:
:msg, startswith, "'firehol: " -/var/log/iptables.log & ~
Configure iptables Log Rotation
Finally, since we’re logging to a new file, it’s useful to create a log rotation rule. Create a file /etc/logrotate.d/iptables with the following contents:
/var/log/iptables.log { rotate 7 daily missingok notifempty delaycompress compress postrotate invoke-rc.d rsyslog rotate > /dev/null endscript }
The preceding script tells logrotate to rotate the firewall log daily and keep logs from the past seven days.
30 replies on “Log iptables Messages to a Separate File with rsyslog”
Thanks for the tip, but I couldn’t actually get it to work verbatim. The log messages for me look like this:
Jul 1 10:34:57 somehost kernel: [40863.468270] ‘firehol: ‘IN-world’:…
The timestamp in brackets is part of the message and needs to be matched as well.
I got it to work using “contains” instead of “startswith”.
Another useful tip is to add
kernel.printk = 4 4 1 7
to /etc/sysctl.conf to stop the iptables messages from going to the console.
Perhaps this will be helpful for some readers.
This help file is for rsyslog not sysctl
Or you could skip rsyslog all together, and use ULOGD and the ULOG target. More flexibility this way – send the logs to a file, or a database. No issues with filtering, and you can use as many prefixes as you want without having to reconfigure rsyslog.
The advantage of rsyslog is that you’re probably already using it and you can’t really run a linux system with out some sort of syslog daemon. ulogd might make sense on a dedicated firewall, but it’s sort of ridiculous to have to run a completely separate daemon just to log iptables on a workstation.
ULOG does not work with ip6 on debian wheezy and later, so i was happy to find this advice for doing without…
Thanks for this nice tip. I also had the timestamp problem, so now I have added a regex rule:
:msg, startswith, “ipt: ” -/var/log/iptables.log
& ~
:msg, regex, “^\[ *[0-9]*\.[0-9]*\] ipt: ” -/var/log/iptables.log
& ~
However, the messages still also go to dmesg (the command). Would like to remove them from there as well.
Try “dmesg -n5”
The regexp caused rsyslogd to refuse to start. I found using ‘contains: ‘ instead of ‘startswith’ to work for me.
The reason the regex didn’t work is probably because the double quotes here are not regular double quotes. Just spent 15mins trying to find why it was not working…
Copy-paste, I hate you :).
Shouldn’t the regex like this?
:msg, regex, “^ *\[[0-9]*\.[0-9]*\] iptables: ” -/var/log/iptables.log
& ~
That is begin with any number of spaces followed by open bracket: ^ *\[
Rather than begin with open bracket followed by any number of spaces: ^\[ *
Would the timestamp ever include a space?
did you find how to disabled the timestamp messages?, by default in centos 6 show the timestamp then ‘startswith’ not work, just with ‘contains’
thanks
You might want to add a number to the conf file in rsyslog.d and have it load before the other rules.
in example /etc/rsyslog.d/30-iptables.conf is a safe guess for basic ubuntu systems.
Hi,
Thanks for a good and helpful tutorial.
I’ve got one question I was hoping you might be able to answer. I keep getting error messages when i use filters, and I am wondering wether it can be due to a module not being loaded.
Did you load specific modules before implementing the filtering?
What’s the error?
All of this works for getting iptables logging into a separate log file…that’s great…but it’s still, also, logging into /var/log/messages, which is what I’m trying to get cleared out.
As I’m still not horribly good with rsyslog, does anyone have an incantation for the /var/log/messages line that will clean that part up?
The & ~ part will prevent rsyslog from logging matching lines to other files.
Note than with newer versions of rsyslog you need to use “invoke-rc.d rsyslog rotate” instead of “invoke-rc.d rsyslog reload”.
Updated, thanks.
Hello,
Thanks for explanation here.
Just a remark, in case you want to redirect just IPTables to iptables.log:
# Log IPTables.
:msg, startswith, “IPTABLES_” -/var/log/iptables.log
& ~
Is all you need, without the Prefix bit :)
Be good!
hi, i’ve used iptables to create a firewall type of application that can block certain addresses in android. i use logging to keep track of rejected packets. How can i clear the contents of the log programatically.
I think you should just be able to delete the log file and reload rsyslog unless I’m missing something.
Thank you for such a nice tutorial.
I just wrote a different kind of tutorial on how to set up Arno IPTABLES firewall.
May be it may help someone to setup his own firewall based on IPTABLES.
You can find some examples for a mail server and for a Proxy server using SNAT and port forwarding.
The location of my tutorial is here:
http://cosmolinux.no-ip.org/raconetlinux2/arno_iptables_firewall.html
I wish it is useful to someone.
The config
:msg, startswith, “‘firehol: ” -/var/log/iptables.log
& ~
is wrong because in many cases it triggers an all discard action (for example in ubuntu 10.04LTS) it would be better to use the & for all the actions of the multiple actions filter:
:msg, starts with, “‘firehol: ”
& -/var/log/iptables.log
& ~
This behaves correctly, putting the firehol: lines in the iptables.log and discarding only the matched line.
Please correct the guide because many people could silently discard log lines :-D
Hmm. It worked correctly for me. Are you putting these lines in separate file in /etc/rsyslog.d? I just checked the default rsyslog for UFW and it doesn’t split out of the action lines.
Very useful. Like you said, rsylog is best solution, although there are better alternatives. ULOGD is better on dedicated firewall, but for rsylog is more universal approach if you ask me. Saw similar tutorial on http://www.droid.hr, but this is much better. Thanks
Very helpful, thanks!
hi, how to log all iptables rules to one file and lets say “ACK RST URGP” to another, after & ~ – its discarding iptables from futher apperance and matching. And please tellme how to anchor speciefic ACK RST smth from iptables itself not clear how to use this –tcp-flags. thanks
ok, that manuals was written for zombies sure, or.. by zombies, after trying by myself variations, there is a solution: –tcp-flags ACK,FIN,URG ACK,FIN if required to log only disconnections ACK FIN URGP=0 and if need to store logs in a separate files, just add all rules before you put & ~ for stop passing them futher. peace!
please note, that bloody cheapy crap wordpress blog supress double “-” “-” into single “-“.
be careful.
one of my mentees sent me to this ancient posting because it still ranks high in searches. most of what is said still applies to rsyslog’s current versions (hopefully everyone is using ‘8’ or later). certainly everyone should also visit the doc’s and bone up on recent filtering innovations.
what does not still apply is the use of ‘& ~’ which has been replaced with ‘& stop’.
also, putting custom config’s in a file in /etc/rsyslog.d was a practice to prevent losing those settings when an update would over-write the main /etc/rsyslog.conf file. this no longer happens since update scripts leave the original extant and copies in a new “default”.
thus, it it is far more transparent and less prone to mistakes when one puts all config setting into just one (1) file: ‘/etc/rsyslog.conf’. moreover, it would be a wise maintenance project to consolidate settings from any files in the rsyslog.d directory into the main rsyslog.conf (and, of course, remove the files from the rsyslog.d directory). this makes formats, sequencing, rule-effects, sources, and destinations highly visible and this is exactly what any sysadmin would wish for.