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_detectedcomes from the scanner detector,--kill-scanner. sipnab quotesuaandmethod.reg_floodcomes from the registration-flood detector,--reg-flood.countis 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=51tocount=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 fail2bansaysHave not found any log file for sipnab-scanner jail./var/log/sipnab.logdoes 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--fail2banhas no detector beside it.