Feed fail2ban from sipnab - NormB/sipnab GitHub Wiki

fail2ban bans the addresses that a log names. sipnab can write that log. Its scanner detector and its registration-flood detector each find attackers in the SIP traffic sipnab captures, and with --fail2ban sipnab writes one line for each detection. The filter and jail in sipnab's contrib/fail2ban turn those lines into bans. sipnab writes the lines, and fail2ban decides and bans.

sipnab's lines come from the traffic it captures, not from your SIP server's log.

This guide starts where Ban SIP scanners with fail2ban ends, before its uninstall: OpenSIPS, fail2ban and the two test addresses in place.

What sipnab writes

Two kinds of line, one per detection:

2026-10-01 03:49:45 sipnab[17157]: scanner_detected src=198.51.100.60 ua="friendly-scanner" method="OPTIONS"
2026-10-01 03:51:13 sipnab[17540]: reg_flood src=198.51.100.60 count=51
  • scanner_detected comes from the scanner detector, --kill-scanner. sipnab quotes ua and method.
  • reg_flood comes from the registration-flood detector, --reg-flood. count is how many REGISTERs with credentials the registrar refused from that address within one second. Out of the box the threshold is 50, and sipnab writes a line for each refusal past it, so 80 refusals in a burst write 30 lines, count=51 to count=80.

--fail2ban itself detects nothing: it only chooses the format. Without a detector beside it, sipnab warns when it starts that no detector is running, so this run will emit nothing.

Know what --kill-scanner sends. On a live capture, the scanner detector also answers the scanner requests it detects, from a separate process. The answer is a 200 OK, sent with your SIP server's address and port as its source. Watching the scanner's side, the request OpenSIPS ignored on purpose got an answer within milliseconds:

03:50:04.370537 IP 198.51.100.60.54184 > 192.0.2.10.5060: SIP: OPTIONS sip:192.0.2.10 SIP/2.0
03:50:04.383978 IP 192.0.2.10.5060 > 198.51.100.60.54184: SIP: SIP/2.0 200 OK

So with sipnab running this way, a scanner learns that something answers on your SIP port, even when your SIP server answers nothing.

Tested on

Every block on this page, and every command in step 7's table, ran as written, in order, on 2026-10-01, with sipnab 0.5.199 from its release package and the contrib/fail2ban files as this version of the page describes them, on the machines the fail2ban guide ran on: clean x86_64 virtual machines with 2 cores and 3 GB of memory, Debian 13 (kernel 6.12.111) and Ubuntu 24.04 (kernel 6.8.0), right after that guide's step 8. Step 6 ran on both: Debian 13's iptables package is 1.8.11 and reports (nf_tables). A capture on both showed the answer --kill-scanner sends.

1. Install sipnab

# Run all of these, in order.
V=$(curl -fsSL https://api.github.com/repos/NormB/sipnab/releases/latest \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["tag_name"].lstrip("v"))')
curl -fsSLO https://github.com/NormB/sipnab/releases/download/v$V/sipnab_${V}_amd64.deb
curl -fsSL https://github.com/NormB/sipnab/releases/download/v$V/SHA256SUMS.txt \
  | grep " sipnab_${V}_amd64.deb$" | sha256sum -c -
sudo apt-get install -y ./sipnab_${V}_amd64.deb

The package installs a service that runs sipnab as the sipnab user, capturing on every interface. It does not start it.

2. Run sipnab with its detectors, writing the log

A drop-in adds the two detectors and --fail2ban to the packaged command, and sends sipnab's standard output, where the lines go, to /var/log/sipnab.log, the file the contrib jail reads. sipnab's own messages, on standard error, stay in the journal:

# Run all of these, in order.
sudo mkdir -p /etc/systemd/system/sipnab.service.d
sudo tee /etc/systemd/system/sipnab.service.d/fail2ban.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/sipnab -N -d any --no-cli-print --syslog --metrics 127.0.0.1:9090 \
  --kill-scanner --reg-flood --fail2ban
StandardOutput=append:/var/log/sipnab.log
StandardError=journal
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now sipnab
sleep 3
systemctl is-active sipnab
sudo ls -l /var/log/sipnab.log

--no-cli-print keeps every SIP message out of the log, but does not hold back the detection lines. systemd creates the log file when the service starts. Start sipnab before the jail: fail2ban refuses to start a jail whose log file does not exist, and stops every other jail with it.

3. Install sipnab's filter and jail

Fetch both files at the tag of the sipnab you installed:

# Run all of these, in order.
V=$(sipnab --version | awk 'NR==1 {print $2}')
sudo curl -fsSL "https://raw.githubusercontent.com/NormB/sipnab/v$V/contrib/fail2ban/sipnab-scanner.conf" \
  -o /etc/fail2ban/filter.d/sipnab-scanner.conf
sudo curl -fsSL "https://raw.githubusercontent.com/NormB/sipnab/v$V/contrib/fail2ban/sipnab-jail.conf" \
  -o /etc/fail2ban/jail.d/sipnab.conf
cat /etc/fail2ban/jail.d/sipnab.conf

The jail, sipnab-scanner, reads /var/log/sipnab.log and bans an address after 5 lines within 60 seconds, for an hour, on every port, UDP and TCP, with nftables. backend = auto makes it read that file even where the distribution's default is the systemd journal, as on Ubuntu 24.04. Load it:

# Run all of these, in order.
sudo systemctl restart fail2ban
sleep 3
sudo fail2ban-client status sipnab-scanner

The status shows File list: /var/log/sipnab.log.

Before you leave this running on real traffic, measure who the detectors would name on a capture of your own, as Detect SIP scanners and auto-block via fail2ban shows. Change the jail in a sipnab.local beside it, never in sipnab.conf, which the next download replaces. For example, never ban the phone's network, and wait for 10 detections rather than 5:

# Run all of these, in order.
sudo tee /etc/fail2ban/jail.d/sipnab.local >/dev/null <<'EOF'
[sipnab-scanner]
ignoreip = 127.0.0.1/8 ::1 203.0.113.0/24
maxretry = 10
EOF
sudo systemctl restart fail2ban
sleep 3
sudo fail2ban-client get sipnab-scanner ignoreip
sudo fail2ban-client get sipnab-scanner maxretry

The jail now prints the three ignored ranges and 10. Take the example out again before step 4, which counts to 5:

# Run all of these, in order.
sudo rm /etc/fail2ban/jail.d/sipnab.local
sudo systemctl restart fail2ban
sleep 3
sudo fail2ban-client get sipnab-scanner maxretry

It prints 5.

4. Watch sipnab's lines become a ban

Start with the scanner unbanned in every jail, in case the fail2ban guide's tests left a ban behind. The OpenSIPS jail would also ban this scanner, after its third request, so have that jail ignore it while you watch sipnab's, until the end of step 5. Then the scanner sends four OPTIONS as friendly-scanner:

# Run all of these, in order.
sudo fail2ban-client unban 198.51.100.60
sudo fail2ban-client set opensips addignoreip 198.51.100.60
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 OPTIONS 4 friendly-scanner
sleep 3
sudo grep -c 'scanner_detected src=198.51.100.60 ' /var/log/sipnab.log
sudo fail2ban-client status sipnab-scanner

The first three print SIP/2.0 200 OK: sipnab's answer, not OpenSIPS's. The fourth prints no answer, because sipnab answers one source at most three times a minute. sipnab wrote a scanner_detected src=198.51.100.60 line for each of the four, and the jail counts them, Total failed: 4, but has banned nobody: Banned IP list: is empty. The fifth inside 60 seconds earns the ban:

# Run all of these, in order.
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 OPTIONS 1 friendly-scanner
sleep 3
sudo fail2ban-client status sipnab-scanner
sudo nft list set inet f2b-table addr-set-sipnab
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 OPTIONS 1

The jail lists 198.51.100.60, nftables holds it in addr-set-sipnab, and the next OPTIONS prints refused.

The phone is not affected, and sipnab wrote nothing about it:

# Run all of these, in order.
sudo ip netns exec phone python3 ~/f2b-test/sipreq.py 192.0.2.10 REGISTER 1 MicroSIP 1001 correct-horse-1001
sudo grep -c 203.0.113.70 /var/log/sipnab.log || true

It prints REGISTER 1001: SIP/2.0 200 OK, then 0.

5. Watch a registration flood become a ban

Lift the scanner's ban first. The OpenSIPS jail still ignores the address, so only sipnab's jail acts. Afterwards, the OpenSIPS jail stops ignoring it:

# Run all of these, in order.
sudo fail2ban-client set sipnab-scanner unbanip 198.51.100.60
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 REGISTER 80 MicroSIP 1001 wrong-password | sort | uniq -c
sleep 3
sudo grep -c 'reg_flood src=198.51.100.60' /var/log/sipnab.log
sudo fail2ban-client status sipnab-scanner
sudo fail2ban-client set opensips delignoreip 198.51.100.60

All 80 guesses print REGISTER 1001: SIP/2.0 401 Unauthorized. sipnab wrote 30 reg_flood lines for them, and the jail lists 198.51.100.60.

6. Ban with iptables instead of nftables

The shipped jail bans with nftables, which worked on both systems this guide ran on. On a host where you manage the firewall with the iptables command, give the jail fail2ban's iptables action, which the shipped file shows in a comment. This installs iptables, switches the jail to it in a sipnab.local, and bans the scanner again with five OPTIONS:

# Run all of these, in order.
sudo apt-get install -y iptables
sudo iptables -V
sudo tee /etc/fail2ban/jail.d/sipnab.local >/dev/null <<'EOF'
[sipnab-scanner]
action = iptables-allports[name=sipnab, protocol=all]
EOF
sudo systemctl restart fail2ban
sleep 3
sudo fail2ban-client unban 198.51.100.60
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 OPTIONS 5 friendly-scanner
sleep 3
sudo fail2ban-client status sipnab-scanner
sudo iptables -S f2b-sipnab
sudo ip netns exec scanner python3 ~/f2b-test/sipreq.py 192.0.2.10 OPTIONS 1

iptables -V names its backend in brackets: (nf_tables) is the iptables command writing nftables rules for you, (legacy) the old kernel tables. The jail lists 198.51.100.60, the f2b-sipnab chain holds a rule rejecting it, and the next OPTIONS prints refused.

To go back to nftables, remove the override:

# Run all of these, in order.
sudo rm /etc/fail2ban/jail.d/sipnab.local
sudo systemctl restart fail2ban
sleep 3
sudo fail2ban-client status sipnab-scanner

7. Operate it

Command What it does
sudo fail2ban-client status sipnab-scanner the jail's failures and its banned addresses
sudo fail2ban-client set sipnab-scanner unbanip 198.51.100.60 lift a ban
sudo fail2ban-regex /var/log/sipnab.log sipnab-scanner count the lines of sipnab's log the filter matches, without banning anything
sudo journalctl -u sipnab -n 20 sipnab's own messages, including an [ALERT] line for each detection

Uninstall. Remove the jail and the drop-in, and put the packaged service back:

# Run all of these, in order.
sudo rm -f /etc/fail2ban/jail.d/sipnab.conf /etc/fail2ban/jail.d/sipnab.local /etc/fail2ban/filter.d/sipnab-scanner.conf
sudo systemctl restart fail2ban
sudo rm /etc/systemd/system/sipnab.service.d/fail2ban.conf
sudo systemctl daemon-reload
sudo systemctl disable --now sipnab
sudo rm -f /var/log/sipnab.log

To remove sipnab too:

sudo apt-get purge -y sipnab

When something does not work

  • fail2ban does not start, and journalctl -u fail2ban says Have not found any log file for sipnab-scanner jail. /var/log/sipnab.log does not exist yet. Start sipnab as in step 2, then restart fail2ban.
  • The log stays empty. Run sudo journalctl -u sipnab -n 20. sipnab warns there when --fail2ban has no detector beside it.