I believe in my old blog I’ve shown how to block bogons with iptables and later with nftables. Here’s how to do it with Suricata.
First of all, what are Bogons? Basically, these are networks which should not appear on Internet. It might also be networks which are reserved or not assigned. If you want to know more about this (as well as other ways to implement them) check out: https://www.team-cymru.com/bogon-networks. I’m always using their lists. They provide an IPv4 and IPv6 list.
You should carefully review the IPs which are in this lists. Because if you use them (wrongly, e.g. in your LAN) you may block your whole internal network. For IPv6 you may want to review the rules also, because currently they do block link-local addresses. That is because fe80::/10 and ff02::/16 are in 8000::/1 and 8000::/1 is listed. So you may want to exclude this.
In regard to IPv6 you may want to take a look at RFC 4890. In Section 4.3 it gives Recommendations for ICMPv6 Transit Traffic. Especially take a look at Section 4.3.3 because if you run Suricata like I do, it is a firewall/bridge and not a firewall/router.
The following Suricata rule would pass any IPv6-ICMP Traffic (ip_proto:58):
pass ip any any -> any any (msg:"Pass ICMPv6"; ip_proto:58; sid:10; rev:1;)
Instead you might just specify fe80::/10 and ff02::/16 like this:
pass ip [fe80::/10,ff02::/16] any -> any any (msg:"Pass some ICMPv6"; ip_proto:58; sid:10; rev:1;)
Let’s add some sort of reference to this message so that we remember where to look for more useful information. Add “rfc” to reference.config:
~# grep rfc /etc/suricata/reference.config
config reference: rfc https://datatracker.ietf.org/doc/html/
That will allow you to use reference:rfc,rfcXXXX in Suricata rules. Now you can change the above rule to:
pass ip [fe80::/10,ff02::/16] any -> any any (msg:"Pass some ICMPv6"; ip_proto:58; reference:rfc,rfc4890; sid:10; rev:1;)
Suricata has xbits/datasets. But I did not see a way to use CIDR / IP ranges with it. However, the ip reputation part in Suricata can do this! Uncomment the IP Reputation configuration in suricata.yaml and add two list files.
# IP Reputation
reputation-categories-file: /etc/suricata/iprep/categories.txt
default-reputation-path: /etc/suricata/iprep
reputation-files:
- bogons-v4.list
- bogons-v6.list
Then edit the categories file. I add a category for bogons. So open /etc/suricata/iprep/categories.txt in your favorite text editor and add:
1,Bogons,fullbogons list
IPv4
Now you need a small bash script which fetches the bogons lists and transforms it into an iprep list:
#!/bin/bash
#
# see: https://blog.jeanbruenn.info/2023/12/08/block-bogons-with-suricata/
# where to store the ruleset?
IPREPFILE="/etc/suricata/iprep/bogons-v4.list"
# where to temp store the bogons
TMPIPREPFILE="/tmp/fullbogons-ipv4.txt"
# where to obtain the bogons from
SRCURL="http://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt"
if [ -f "$TMPIPREPFILE" ]; then
mv "$TMPIPREPFILE" "$TMPIPREPFILE.old"
fi
wget -q -O "$TMPIPREPFILE" "$SRCURL"
if [ "$?" != 0 ]; then
echo "Failed to wget $SRCURL. Exiting..."
fi
# if the list did not change, just exit.
if [ -f "$TMPIPREPFILE.old" ]; then
diff "$TMPIPREPFILE" "$TMPIPREPFILE.old" &>/dev/null
if [ "$?" == 0 ]; then
exit 0
fi
fi
if [ -s "$TMPIPREPFILE" ]; then
# temporary bogons file exists and size > 0
if [ -f $IPREPFILE ]; then
# current iprep file exists; remove
rm $IPREPFILE
fi
while read -r NETWORK; do
echo "$NETWORK,1,10" >> $IPREPFILE
done< <(grep -v "^#" $TMPIPREPFILE)
fi
IPv6
Same script; just fetching the ipv6 list and storing as v6 list.
#!/bin/bash
#
# see: https://blog.jeanbruenn.info/2023/12/08/block-bogons-with-suricata/
# where to store the ruleset?
IPREPFILE="/etc/suricata/iprep/bogons-v6.list"
# where to temp store the bogons
TMPIPREPFILE="/tmp/fullbogons-ipv6.txt"
# where to obtain the bogons from
SRCURL="http://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt"
if [ -f "$TMPIPREPFILE" ]; then
mv "$TMPIPREPFILE" "$TMPIPREPFILE.old"
fi
wget -q -O "$TMPIPREPFILE" "$SRCURL"
if [ "$?" != 0 ]; then
echo "Failed to wget $SRCURL. Exiting..."
fi
# if the list did not change, just exit.
if [ -f "$TMPIPREPFILE.old" ]; then
diff "$TMPIPREPFILE" "$TMPIPREPFILE.old" &>/dev/null
if [ "$?" == 0 ]; then
exit 0
fi
fi
if [ -s "$TMPIPREPFILE" ]; then
# temporary bogons file exists and size > 0
if [ -f $IPREPFILE ]; then
# current iprep file exists; remove
rm $IPREPFILE
fi
while read -r NETWORK; do
echo "$NETWORK,1,10" >> $IPREPFILE
done< <(grep -v "^#" $TMPIPREPFILE)
fi
The final rule
Lastly a rule which uses the reputation list is required:
# use this first to see what it would drop.
alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"DROP FullBogons listed."; iprep:src,Bogons,>,1; sid:11; rev:1;)
So my two rules (the ipv6 whitelist icmpv6 plus the drop rule) look like this:
pass ip [fe80::/10,ff02::/16] any -> any any (msg:"Pass some ICMPv6"; ip_proto:58; reference:rfc,rfc4890; sid:10; rev:1;)
# use previous alert rule first. satisfied? Then switch to this one.
drop ip $EXTERNAL_NET any -> $HOME_NET any (msg:"DROP FullBogons listed."; iprep:src,Bogons,>,1; sid:11; rev:1;)
You should be sure you know what you’re doing if you use this to drop traffic in an IPS. I strongly suggest to use alert instead of drop first. Verify that everything is setup correctly:
You should see many entries in bogons-v4.list and bogons-v6.list:
root@fw2:/etc/suricata/iprep# wc -l *
674 bogons-v4.list
142054 bogons-v6.list
1 categories.txt
142729 total
The suricata log should tell you that it loaded that reputation files:
[1347 - Suricata-Main] 2023-12-07 23:41:27 Info: reputation: Loading reputation file: /etc/suricata/iprep/bogons-v4.list
[1347 - Suricata-Main] 2023-12-07 23:41:27 Info: reputation: Loading reputation file: /etc/suricata/iprep/bogons-v6.list
If you don’t use the IPv6 pass rule you’ll probably see entries similar to this in your fast.log:
[Drop] [**] [1:1:2] IPREP [**] [Classification: (null)] [Priority: 3] {IPv6-ICMP} fe80:0000:0000:0000:0xxx:xxxx:xxxx:xxxx:135 -> xxxx:xxxx:xxxx:xxxx:0000:0000:0000:0001:0
I used IPREP first for testing as message; However. This shows that it works for me.