Alan Orth
d7c34a30a3
This configures the recommended DROP, EDROP, and DROPv6 lists from Spamhaus as ipsets in firewalld. First we copy an empty placeholder ipset to seed firewalld, then we use a shell script to download the real lists and activate them. The same shell script is run daily as a service (update-spamhaus-lists.service) by a systemd timer. I am strictly avoiding any direct ipset commands here because I want to make sure that this works on older hosts where ipsets is used as well as newer hosts that have moved to nftables such as Ubuntu 20.04. So far I have tested this on Ubuntu 16.04, 18.04, and 20.04, but ev- entually I need to abstract the tasks and run them on CentOS 7+ as well. See: https://www.spamhaus.org/drop/
108 lines
3.5 KiB
Bash
Executable File
108 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# update-spamhaus-lists.sh v0.0.5
|
|
#
|
|
# Download Spamhaus DROP lists and load them into firewalld ipsets. Should work
|
|
# with both the iptables and nftables backends.
|
|
#
|
|
# See: https://www.spamhaus.org/drop/
|
|
#
|
|
# Copyright (C) 2021 Alan Orth
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
# Exit on first error
|
|
set -o errexit
|
|
|
|
firewalld_ipsets=$(firewall-cmd --get-ipsets)
|
|
xml_temp=$(mktemp)
|
|
spamhaus_ipv4_ipset_path=/etc/firewalld/ipsets/spamhaus-ipv4.xml
|
|
spamhaus_ipv6_ipset_path=/etc/firewalld/ipsets/spamhaus-ipv6.xml
|
|
|
|
function download() {
|
|
echo "Downloading $1"
|
|
wget -q -O - "https://www.spamhaus.org/drop/$1" > "$1"
|
|
}
|
|
|
|
download drop.txt
|
|
download edrop.txt
|
|
download dropv6.txt
|
|
|
|
if [[ -f "drop.txt" && -f "edrop.txt" ]]; then
|
|
echo "Processing IPv4 DROP lists"
|
|
|
|
# Extract all networks from drop.txt and edrop.txt, skipping blank lines and
|
|
# comments.
|
|
networks=$(cat drop.txt edrop.txt | sed -e '/^$/d' -e '/^;.*/d' -e 's/[[:space:]];[[:space:]].*//')
|
|
|
|
# If firewalld already has this ipset we should delete it first to emulate
|
|
# `ipset flush` (but I don't want to use that because newer hosts might be
|
|
# using nftables and firewalld will handle that for us).
|
|
if [[ "$firewalld_ipsets" =~ spamhaus-ipv4 ]]; then
|
|
echo "Deleting existing spamhaus-ipv4 ipset"
|
|
# This deletes the firewalld ipset XML file as well as the ipset itself
|
|
firewall-cmd --permanent --delete-ipset=spamhaus-ipv4
|
|
else
|
|
echo "Creating placeholder spamhaus-ipv4 ipset"
|
|
# Create a placeholder ipset so firewalld doesn't complain when we try
|
|
# to reload the ipset later after having added a new XML definition. I
|
|
# don't know why, but depending on the system state there may not be a
|
|
# ipset defined and firewalld errors on INVALID_IPSET.
|
|
firewall-cmd --permanent --new-ipset=spamhaus-ipv4 --type=hash:net --option=family=inet
|
|
fi
|
|
|
|
# I'm not proud of this, but writing the XML directly is WAY faster than
|
|
# using firewall-cmd to add each entry one by one (and we can't add from
|
|
# a file because many of our hosts are using old firewalld).
|
|
cat << XML_HEAD > "$xml_temp"
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<ipset type="hash:net">
|
|
<option name="family" value="inet" />
|
|
<short>spamhaus-ipv4</short>
|
|
<description>Spamhaus DROP and EDROP lists (IPv4).</description>
|
|
XML_HEAD
|
|
|
|
for network in $networks; do
|
|
echo " <entry>$network</entry>" >> "$xml_temp"
|
|
done
|
|
|
|
echo "</ipset>" >> "$xml_temp"
|
|
|
|
install -m 0600 "$xml_temp" "$spamhaus_ipv4_ipset_path"
|
|
fi
|
|
|
|
if [[ -f "dropv6.txt" ]]; then
|
|
echo "Processing IPv6 DROP list"
|
|
|
|
networks=$(sed -e '/^$/d' -e '/^;.*/d' -e 's/[[:space:]];[[:space:]].*//' dropv6.txt)
|
|
|
|
if [[ "$firewalld_ipsets" =~ spamhaus-ipv6 ]]; then
|
|
echo "Deleting existing spamhaus-ipv6 ipset"
|
|
firewall-cmd --permanent --delete-ipset=spamhaus-ipv6
|
|
else
|
|
echo "Creating placeholder spamhaus-ipv6 ipset"
|
|
firewall-cmd --permanent --new-ipset=spamhaus-ipv6 --type=hash:net --option=family=inet6
|
|
fi
|
|
|
|
cat << XML_HEAD > "$xml_temp"
|
|
<?xml version="1.0" encoding="utf-8"?>
|
|
<ipset type="hash:net">
|
|
<option name="family" value="inet6" />
|
|
<short>spamhaus-ipv6</short>
|
|
<description>Spamhaus DROP lists (IPv6).</description>
|
|
XML_HEAD
|
|
|
|
for network in $networks; do
|
|
echo " <entry>$network</entry>" >> "$xml_temp"
|
|
done
|
|
|
|
echo "</ipset>" >> "$xml_temp"
|
|
|
|
install -m 0600 "$xml_temp" "$spamhaus_ipv6_ipset_path"
|
|
fi
|
|
|
|
echo "Reloading firewalld"
|
|
firewall-cmd --reload
|
|
|
|
rm -v drop.txt edrop.txt dropv6.txt "$xml_temp"
|