Detecting port scans from nftables and iptables log files


Every device with public IP does get a constant stream of port scans every day. If one just wants to inspect these port scans with a simple and fast program that follows Unix philosophy, you are out of options. Or that was the case when I first wanted to do something like this, so I had to write this program myself, but more on that later. The program introduced in this article should work with nftables, iptables and firewalld or any firewall which uses “ipt_LOG” kernel module for logging.

Building and installing LPSD

Before doing anything you should enable logging in to your firewall if you have not done so yet. If you are using nftables refer to their wiki (nft add rule filter input log) if you don’t know how to do that (it’s very trivial). If you are using iptables it can be enabled with “iptables -A INPUT -j LOG” or something like that. Ideally, you may want to only log the blocked traffic to keep the log file sizes down. After enabling logging, entries should start appearing in the syslog or kern.log file.

The source code is available in Gitlab and Github, just use the one you prefer.

After cloning the repository the program can be installed with “install” target or just built with “all” target (if you don’t want to make an installation).

# make install
gcc -Wall -std=gnu17 -O2 -pthread  lpsd.c -o lpsd
install lpsd /usr/bin/
gzip man/lpsd.1 -c > man/lpsd.1.gz
install -m 644 man/lpsd.1.gz /usr/share/man/man1/lpsd.1.gz

The install target also installs a man page “lpsd(1)”, so refer to that if the information provided in the help isn’t enough.

First a short introduction to LPSD’s features:

So nothing too fancy but that’s the point. Do one thing and do it well (not sure about that last point:)).

The usage is fairly simple but there are some examples to give some idea (real IPs on the output so I censored them):

$ lpsd -i kern.log --date 03-22
2022-03-22 04:05:58 23 ports
2022-03-22 06:55:53 8 ports
2022-03-22 10:53:44 31 ports
2022-03-22 11:57:13 27 ports
2022-03-22 13:59:06 26 ports
2022-03-22 17:05:53 5 ports

Works also with IPv6:

$ lpsd -i kern.log
2022-04-08 17:20:59 2002:c000:0203:0000:0000:0000:0000:0002 1000 ports
2022-04-08 17:23:40 2002:c000:0203:0000:0000:0000:0000:0003 1000 ports
2022-04-08 17:24:16 2002:c000:0203:0000:0000:0000:0000:0004 1000 ports
2022-04-08 17:24:36 2002:c000:0203:0000:0000:0000:0000:0005 1000 ports
2022-04-08 17:25:00 2002:c000:0203:0000:0000:0000:0000:0006 1000 ports

Reporting port scanners to abuseipdb

You may want to report these IP addresses to abuseipdb or some equivalent. I have written a script for this purpose, so you may want to check it out. It parses the CSV output of LPSD and prepares it for a bulk report.

Gitlab and Github.

Why C? Why not Python, Rust etc.?

Short answer: because C is fast and I’m familiar with it.

I want this to be able to run with low power devices with the smallest overhead possible, so Python is ruled out. Rust could be another option, but C is generally more performant and has lower memory usage (I don’t say this as an absolute), and C and its ecosystem are more mature. Overall Rust is an overhyped language.