Log iptables Messages to a Separate File with rsyslog

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

  1. 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: "
  1. /etc/firehol/firehol.conf.
  2. /etc/rsyslog.d/iptables.conf with the following contents:

Configure rsyslog to Filter Based on Prefix

: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 reload > /dev/null
	endscript
}

The preceding script tells logrotate to rotate the firewall log daily and keep logs from the past seven days.


( ! ) Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/vhosts/shan.info/httpdocs/templates/gk_publisher/html/com_k2/templates/default/item.php on line 169
Call Stack
#TimeMemoryFunctionLocation
10.0016414072{main}( ).../index.php:0
20.08774264088Joomla\CMS\Application\SiteApplication->execute( ).../index.php:49
30.08774264088Joomla\CMS\Application\SiteApplication->doExecute( ).../CMSApplication.php:196
40.309611455112Joomla\CMS\Application\SiteApplication->dispatch( ).../SiteApplication.php:233
50.310111479488Joomla\CMS\Component\ComponentHelper::renderComponent( ).../SiteApplication.php:194
60.310811534816Joomla\CMS\Component\ComponentHelper::executeComponent( ).../ComponentHelper.php:377
70.311111562216require_once( '/var/www/vhosts/shan.info/httpdocs/components/com_k2/k2.php' ).../ComponentHelper.php:402
80.320011961848K2ControllerItem->execute( ).../k2.php:64
90.320111961848K2ControllerItem->display( ).../BaseController.php:710
100.331912612552K2ControllerItem->display( ).../item.php:78
110.331912612552K2ControllerItem->display( ).../controller.php:19
120.336612983592Joomla\CMS\Cache\Controller\ViewController->get( ).../BaseController.php:663
130.338913003960K2ViewItem->display( ).../ViewController.php:102
140.417515878928K2ViewItem->display( ).../view.html.php:742
150.417515878928K2ViewItem->loadTemplate( ).../HtmlView.php:230
160.421416051864include( '/var/www/vhosts/shan.info/httpdocs/templates/gk_publisher/html/com_k2/templates/default/item.php' ).../HtmlView.php:701

( ! ) Notice: Only variables should be assigned by reference in /var/www/vhosts/shan.info/httpdocs/templates/gk_publisher/html/com_k2/templates/default/item.php on line 478
Call Stack
#TimeMemoryFunctionLocation
10.0016414072{main}( ).../index.php:0
20.08774264088Joomla\CMS\Application\SiteApplication->execute( ).../index.php:49
30.08774264088Joomla\CMS\Application\SiteApplication->doExecute( ).../CMSApplication.php:196
40.309611455112Joomla\CMS\Application\SiteApplication->dispatch( ).../SiteApplication.php:233
50.310111479488Joomla\CMS\Component\ComponentHelper::renderComponent( ).../SiteApplication.php:194
60.310811534816Joomla\CMS\Component\ComponentHelper::executeComponent( ).../ComponentHelper.php:377
70.311111562216require_once( '/var/www/vhosts/shan.info/httpdocs/components/com_k2/k2.php' ).../ComponentHelper.php:402
80.320011961848K2ControllerItem->execute( ).../k2.php:64
90.320111961848K2ControllerItem->display( ).../BaseController.php:710
100.331912612552K2ControllerItem->display( ).../item.php:78
110.331912612552K2ControllerItem->display( ).../controller.php:19
120.336612983592Joomla\CMS\Cache\Controller\ViewController->get( ).../BaseController.php:663
130.338913003960K2ViewItem->display( ).../ViewController.php:102
140.417515878928K2ViewItem->display( ).../view.html.php:742
150.417515878928K2ViewItem->loadTemplate( ).../HtmlView.php:230
160.421416051864include( '/var/www/vhosts/shan.info/httpdocs/templates/gk_publisher/html/com_k2/templates/default/item.php' ).../HtmlView.php:701
back to top