How nftables log to external file

How nftables log to external file

Logging traffic blocked by the nftables or iptables firewall rules is necessary for debugging the firewall rules and to be alerted to local software problems. Any packet matching a rule can be logged by using -j LOG target for iptables or log statement for nftables. Logging packet has no effect on the packet’s disposition, however. The packet must match an accept or drop rule.

What is ulogd


ulogd is a userspace logging daemon for nftables/iptables related logging. This includes per-packet logging of security violations, per-packet logging for accounting, per-flow logging and flexible user-defined accounting. ulogd-1.x has been around since 2000. Since 2012, 1.x series have entered end-of-life. All production systems should migrate to the stable series ulogd-2.x as soon as possible as we do not plan to make more 1.x releases.

Main Features:

  • Packet based logging (via libnetfilter_log or ULOG target)

  • Flow based logging (via libnetfilter_conntrack)

  • Flexible user-defined traffic accounting via nfacct infrastructure

  • SQL database back-end support: SQLite3, MySQL and PostgreSQL

  • Text-based output formats: CSV, XML, Netfilter’s LOG, Netfilter’s conntrack

To use libnetfilter_log and libnetfilter_conntrack, a kernel superior to 2.6.14 is needed.

ulogd2 concept


ulogd2 wants to provide a flexible, almost universal logging daemon for netfilter logging. This encompasses both packet-based logging (logging of policy violations) and flow-based logging, e.g. for accounting purpose.

ulogd consists of a small core and a number of plugins. All the real power lies in the plugins, and in the user who configures the interactions between those plugins.

Input Plugins

  • Input plugins acts data source. They get data from somewhere outside of ulogd, and convert it into a list of ulogd keys.

Filter Plugins

  • Filter plugins interpret and/or filter data that was received from the Input Plugin. A good example is parsing a raw packet into IPv4 / TCP / … header information.

Output Plugins

  • Output plugins describe how and where to put the information gained by the Input Plugin and processed by one or more Filter Plugins. The easiest way is to build a line per packet and fprint it to a file. Some people might want to log into a SQL database or want an output conforming to the IETF IPFIX language.

By means of the configuration file, the administrator can build any number of Plugin Stacks. A plugin stack is a seris of plugins, starting with an Input plugin, none, one or multiple filter plugins, and one output plugin on top.

example

# this is a stack for packet-based logging via LOGEMU with filtering on MARK
stack=log2:NFLOG,mark1:MARK,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

ulogd2 in debian


Install ulogd2:

~] apt-get install ulogd2

The Netfilter logging framework is a generic way of logging used in Netfilter components. This framework is implemented in two different kernel modules:

  • xt_LOG: printk based logging, outputting everything to syslog (same module as the one used for iptables LOG target). It can only log packets for IPv4 and IPv6

  • nfnetlink_log: netlink based logging requiring to setup ulogd2 to get the events (same module as the one used for iptables NFLOG target). It can log packet for any family.

To use one of the two modules, you need to load them with modprobe. It is possible to have both modules loaded and in this case, you can then setup logging on a per-protocol basis. The active configuration is available for reading in /proc:

~] cat /proc/net/netfilter/nf_log
 0 NONE (nfnetlink_log)
 1 NONE (nfnetlink_log)
 2 nfnetlink_log (nfnetlink_log)
 3 NONE (nfnetlink_log)
 4 NONE (nfnetlink_log)
 5 NONE (nfnetlink_log)
 6 NONE (nfnetlink_log)
 7 nfnetlink_log (nfnetlink_log)
 8 NONE (nfnetlink_log)
 9 NONE (nfnetlink_log)
10 nfnetlink_log (nfnetlink_log)
11 NONE (nfnetlink_log)
12 NONE (nfnetlink_log)

The syntax is the following FAMILY ACTIVE_MODULE (AVAILABLE_MODULES).

Protocol family numbers can look a bit strange. It is in fact mapped on the socket family name that is used in underlying code.
The list is the following:

#define AF_UNSPEC	0
#define AF_UNIX		1	/* Unix domain sockets 		*/
#define AF_INET		2	/* Internet IP Protocol 	*/
#define AF_AX25		3	/* Amateur Radio AX.25 		*/
#define AF_IPX		4	/* Novell IPX 			*/
#define AF_APPLETALK	5	/* Appletalk DDP 		*/
#define	AF_NETROM	6	/* Amateur radio NetROM 	*/
#define AF_BRIDGE	7	/* Multiprotocol bridge 	*/
#define AF_AAL5		8	/* Reserved for Werner's ATM 	*/
#define AF_X25		9	/* Reserved for X.25 project 	*/
#define AF_INET6	10	/* IP version 6			*/
#define AF_MAX		12	/* For now.. */

configure ulogd2


Open file /etc/ulogd.conf and edit:

Edit stack statement:


# this is a stack for logging packet send by system via LOGEMU
stack=log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu2:LOGEMU
stack=log3:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu3:LOGEMU

Don’t touch first stack and add two another stacks with log2 and log2 NFLOG input plugin and emu2 and emu3 LOGEMU output plugin

Edit NFLOG and LOGEMU


Group O is used by the kernel to log connection tracking invalid message. So statement for [log1] and [emu1] is untouched.

# Logging of system packet through NFLOG
[log1]
# netlink multicast group (the same as the iptables --nflog-group param)
# Group O is used by the kernel to log connection tracking invalid message
group=0
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
# set number of packet to queue inside kernel
#netlink_qthreshold=1
# set the delay before flushing packet in the queue inside kernel (in 10ms)
#netlink_qtimeout=100

[emu1]
file="/var/log/ulog/syslogemu.log"
sync=1

And add two another statement for [log2] and [log3] in the end of config file. The same is for [emu2] and [emu3]

[log2]
group=2
[emu2]
file="/var/log/ulog/group2-icmp.log"
sync=1

[log3]
group=3
[emu3]
file="/var/log/ulog/group3-ssh.log"
sync=1

Reload ulogd2 configuration


~] /etc/init.d/ulogd2 restart

or

~] systemctl restart ulogd2

nftables configuration


Add testing nftables rules like this:

table inet my_icmp {
        chain input {
                type filter hook input priority 0; policy accept;
                ip protocol icmp log prefix "icmp-accept " group 2 accept
        }

        chain output {
                type filter hook output priority 0; policy accept;
                ip protocol icmp log prefix "icmp-accept " group 2 accept
        }
}

ping to our firewall:

C:\Windows\system32>ping 192.168.221.206

Pinging 192.168.221.206 with 32 bytes of data:
Reply from 192.168.221.206: bytes=32 time<1ms TTL=64
Reply from 192.168.221.206: bytes=32 time<1ms TTL=64
Reply from 192.168.221.206: bytes=32 time<1ms TTL=64
Reply from 192.168.221.206: bytes=32 time<1ms TTL=64

Ping statistics for 192.168.221.206:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

And open your [log2] logfile for log control:

~] cat /var/log/ulog/group2-icmp.log 
May 20 13:02:26 openvpn icmp-accept  IN=ens192 OUT= MAC=00:50:56:8f:67:d3:00:04:23:ad:5f:2d:08:00 SRC=192.168.0.208 DST=192.168.221.206 LEN=60 TOS=00 PREC=0x00 TTL=126 ID=5685 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=20 MARK=0 
May 20 13:02:27 openvpn icmp-accept  IN= OUT=ens224 MAC= SRC=192.168.221.206 DST=192.168.0.208 LEN=60 TOS=00 PREC=0x00 TTL=64 ID=54586 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=20 MARK=0 
May 20 13:02:27 openvpn icmp-accept  IN=ens192 OUT= MAC=00:50:56:8f:67:d3:00:04:23:ad:5f:2d:08:00 SRC=192.168.0.208 DST=192.168.221.206 LEN=60 TOS=00 PREC=0x00 TTL=126 ID=5686 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=21 MARK=0 
May 20 13:02:27 openvpn icmp-accept  IN= OUT=ens224 MAC= SRC=192.168.221.206 DST=192.168.0.208 LEN=60 TOS=00 PREC=0x00 TTL=64 ID=54625 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=21 MARK=0 
May 20 13:02:28 openvpn icmp-accept  IN=ens192 OUT= MAC=00:50:56:8f:67:d3:00:04:23:ad:5f:2d:08:00 SRC=192.168.0.208 DST=192.168.221.206 LEN=60 TOS=00 PREC=0x00 TTL=126 ID=5687 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=22 MARK=0 
May 20 13:02:29 openvpn icmp-accept  IN= OUT=ens224 MAC= SRC=192.168.221.206 DST=192.168.0.208 LEN=60 TOS=00 PREC=0x00 TTL=64 ID=54630 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=22 MARK=0 
May 20 13:02:29 openvpn icmp-accept  IN=ens192 OUT= MAC=00:50:56:8f:67:d3:00:04:23:ad:5f:2d:08:00 SRC=192.168.0.208 DST=192.168.221.206 LEN=60 TOS=00 PREC=0x00 TTL=126 ID=5688 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=23 MARK=0 
May 20 13:02:29 openvpn icmp-accept  IN= OUT=ens224 MAC= SRC=192.168.221.206 DST=192.168.0.208 LEN=60 TOS=00 PREC=0x00 TTL=64 ID=54814 PROTO=ICMP TYPE=0 CODE=0 ID=1 SEQ=23 MARK=0 

Woalaaaa, It’s Working :-)

Full content of /etc/ulogd.conf config file


/etc/ulogd.conf
# Example configuration for ulogd
# Adapted to Debian by Achilleas Kotsis <achille@debian.gr>

[global]
######################################################################
# GLOBAL OPTIONS
######################################################################


# logfile for status messages
logfile="syslog"

# loglevel: debug(1), info(3), notice(5), error(7) or fatal(8) (default 5)
loglevel=3

######################################################################
# PLUGIN OPTIONS
######################################################################

# We have to configure and load all the plugins we want to use

# general rules:
#
# 0. don't specify any plugin for ulogd to load them all
# 1. load the plugins _first_ from the global section
# 2. options for each plugin in seperate section below

#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_inppkt_NFLOG.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_inppkt_ULOG.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_inppkt_UNIXSOCK.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_inpflow_NFCT.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_IFINDEX.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_IP2STR.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_IP2BIN.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_IP2HBIN.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_PRINTPKT.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_HWHDR.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_PRINTFLOW.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_filter_MARK.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_LOGEMU.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_SYSLOG.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_XML.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_SQLITE3.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_GPRINT.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_NACCT.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_PCAP.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_PGSQL.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_MYSQL.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_DBI.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_raw2packet_BASE.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_inpflow_NFACCT.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_GRAPHITE.so"
#plugin="/usr/lib/x86_64-linux-gnu/ulogd/ulogd_output_JSON.so"

# this is a stack for logging packet send by system via LOGEMU
stack=log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu2:LOGEMU
stack=log3:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu3:LOGEMU

# this is a stack for packet-based logging via LOGEMU
#stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

# this is a stack for ULOG packet-based logging via LOGEMU
#stack=ulog1:ULOG,base1:BASE,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

# this is a stack for packet-based logging via LOGEMU with filtering on MARK
#stack=log2:NFLOG,base1:BASE,mark1:MARK,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU

# this is a stack for packet-based logging via GPRINT
#stack=log1:NFLOG,gp1:GPRINT

# this is a stack for flow-based logging via LOGEMU
#stack=ct1:NFCT,ip2str1:IP2STR,print1:PRINTFLOW,emu1:LOGEMU

# this is a stack for flow-based logging via GPRINT
#stack=ct1:NFCT,gp1:GPRINT

# this is a stack for flow-based logging via XML
#stack=ct1:NFCT,xml1:XML

# this is a stack for logging in XML
#stack=log1:NFLOG,xml1:XML

# this is a stack for accounting-based logging via XML
#stack=acct1:NFACCT,xml1:XML

# this is a stack for accounting-based logging to a Graphite server
#stack=acct1:NFACCT,graphite1:GRAPHITE

# this is a stack for NFLOG packet-based logging to PCAP
#stack=log2:NFLOG,base1:BASE,pcap1:PCAP

# this is a stack for logging packet to MySQL
#stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2bin1:IP2BIN,mac2str1:HWHDR,mysql1:MYSQL

# this is a stack for logging packet to PGsql after a collect via NFLOG
#stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,mac2str1:HWHDR,pgsql1:PGSQL

# this is a stack for logging packet to JSON formatted file after a collect via NFLOG
#stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,mac2str1:HWHDR,json1:JSON

# this is a stack for logging packets to syslog after a collect via NFLOG
#stack=log3:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,sys1:SYSLOG

# this is a stack for logging packets to syslog after a collect via NuFW
#stack=nuauth1:UNIXSOCK,base1:BASE,ip2str1:IP2STR,print1:PRINTPKT,sys1:SYSLOG

# this is a stack for flow-based logging to MySQL
#stack=ct1:NFCT,ip2bin1:IP2BIN,mysql2:MYSQL

# this is a stack for flow-based logging to PGSQL
#stack=ct1:NFCT,ip2str1:IP2STR,pgsql2:PGSQL

# this is a stack for flow-based logging to PGSQL without local hash
#stack=ct1:NFCT,ip2str1:IP2STR,pgsql3:PGSQL

# this is a stack for flow-based logging to SQLITE3
#stack=ct1:NFCT,sqlite3_ct:SQLITE3

# this is a stack for logging packet to SQLITE3
#stack=log1:NFLOG,sqlite3_pkt:SQLITE3

# this is a stack for flow-based logging in NACCT compatible format
#stack=ct1:NFCT,ip2str1:IP2STR,nacct1:NACCT

# this is a stack for accounting-based logging via GPRINT
#stack=acct1:NFACCT,gp1:GPRINT

[ct1]
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
#netlink_resync_timeout=60 # seconds to wait to perform resynchronization
#pollinterval=10 # use poll-based logging instead of event-driven
# If pollinterval is not set, NFCT plugin will work in event mode
# In this case, you can use the following filters on events:
#accept_src_filter=192.168.1.0/24,1:2::/64 # source ip of connection must belong to these networks
#accept_dst_filter=192.168.1.0/24 # destination ip of connection must belong to these networks
#accept_proto_filter=tcp,sctp # layer 4 proto of connections

[ct2]
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
#reliable=1 # enable reliable flow-based logging (may drop packets)
hash_enable=0

# Logging of system packet through NFLOG
[log1]
# netlink multicast group (the same as the iptables --nflog-group param)
# Group O is used by the kernel to log connection tracking invalid message
group=0
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
# set number of packet to queue inside kernel
#netlink_qthreshold=1
# set the delay before flushing packet in the queue inside kernel (in 10ms)
#netlink_qtimeout=100

# packet logging through NFLOG for group 1
#[log2]
# netlink multicast group (the same as the iptables --nflog-group param)
#group=1 # Group has to be different from the one use in log1
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
# If your kernel is older than 2.6.29 and if a NFLOG input plugin with
# group 0 is not used by any stack, you need to have at least one NFLOG
# input plugin with bind set to 1. If you don't do that you may not
# receive any message from the kernel.
#bind=1

# packet logging through NFLOG for group 2, numeric_label is
# set to 1
#[log3]
# netlink multicast group (the same as the iptables --nflog-group param)
#group=2 # Group has to be different from the one use in log1/log2
#numeric_label=1 # you can label the log info based on the packet verdict
#netlink_socket_buffer_size=217088
#netlink_socket_buffer_maxsize=1085440
#bind=1

[ulog1]
# netlink multicast group (the same as the iptables --ulog-nlgroup param)
nlgroup=1
#numeric_label=0 # optional argument

[nuauth1]
socket_path="/tmp/nuauth_ulogd2.sock"

[emu1]
file="/var/log/ulog/syslogemu.log"
sync=1

[op1]
file="/var/log/ulog/oprint.log"
sync=1

[gp1]
file="/var/log/ulog/gprint.log"
sync=1
timestamp=1

[xml1]
directory="/var/log/ulog/"
sync=1

[json1]
sync=1
#file="/var/log/ulog/ulogd.json"
#timestamp=0
# device name to be used in JSON message
#device="My awesome Netfilter firewall"
# If boolean_label is set to 1 then the numeric_label put on packet
# by the input plugin is coding the action on packet: if 0, then
# packet has been blocked and if non null it has been accepted.
#boolean_label=1
# Uncomment the following line to use JSON v1 event format that
# can provide better compatility with some JSON file reader.
#eventv1=1

[pcap1]
#default file is /var/log/ulogd.pcap
#file="/var/log/ulog/ulogd.pcap"
sync=1

[mysql1]
db="nulog"
host="localhost"
user="nupik"
table="ulog"
pass="changeme"
procedure="INSERT_PACKET_FULL"
# backlog configuration:
# set backlog_memcap to the size of memory that will be
# allocated to store events in memory if data is temporary down
# and insert them when the database came back.
#backlog_memcap=1000000
# number of events to insert at once when backlog is not empty
#backlog_oneshot_requests=10

[mysql2]
db="nulog"
host="localhost"
user="nupik"
table="conntrack"
pass="changeme"
procedure="INSERT_CT"

[pgsql1]
db="nulog"
host="localhost"
user="nupik"
table="ulog"
#schema="public"
pass="changeme"
procedure="INSERT_PACKET_FULL"
# connstring can be used to define PostgreSQL connection string which
# contains all parameters of the connection. If set, this value has
# precedence on other variables used to build the connection string.
# See http://www.postgresql.org/docs/9.2/static/libpq-connect.html#LIBPQ-CONNSTRING
# for a complete description of options.
#connstring="host=localhost port=4321 dbname=nulog user=nupik password=changeme"
#backlog_memcap=1000000
#backlog_oneshot_requests=10
# If superior to 1 a thread dedicated to SQL request execution
# is created. The value stores the number of SQL request to keep
# in the ring buffer
#ring_buffer_size=1000

[pgsql2]
db="nulog"
host="localhost"
user="nupik"
table="ulog2_ct"
#schema="public"
pass="changeme"
procedure="INSERT_CT"

[pgsql3]
db="nulog"
host="localhost"
user="nupik"
table="ulog2_ct"
#schema="public"
pass="changeme"
procedure="INSERT_OR_REPLACE_CT"

[pgsql4]
db="nulog"
host="localhost"
user="nupik"
table="nfacct"
#schema="public"
pass="changeme"
procedure="INSERT_NFACCT"

[dbi1]
db="ulog2"
dbtype="pgsql"
host="localhost"
user="ulog2"
table="ulog"
pass="ulog2"
procedure="INSERT_PACKET_FULL"

[sqlite3_ct]
table="ulog_ct"
db="/var/log/ulog/ulogd.sqlite3db"

[sqlite3_pkt]
table="ulog_pkt"
db="/var/log/ulog/ulogd.sqlite3db"

[sys2]
facility=LOG_LOCAL2

[nacct1]
sync = 1
#file = /var/log/ulog/nacct.log

[mark1]
mark = 1

[acct1]
pollinterval = 2
# If set to 0, we don't reset the counters for each polling (default is 1).
#zerocounter = 0
# Set timestamp (default is 0, which means not set). This timestamp can be
# interpreted by the output plugin.
#timestamp = 1

[graphite1]
host="127.0.0.1"
port="2003"
# Prefix of data name sent to graphite server
prefix="netfilter.nfacct"




# Moje Veci
[log2]
group=2
[emu2]
file="/var/log/ulog/group2-icmp.log"
sync=1

[log3]
group=3
[emu3]
file="/var/log/ulog/group3-ssh.log"
sync=1