Neulich war das unvermeidliche mal wieder zu beobachten: Einige meiner Adressen und auch ein paar Kundenwebseiten waren mal wieder in einer Datenbank für Kommentarspammer gelandet und die Spamkommentare häuften sich. Was tun?

 

Am besten wäre es doch, die Spammer hätten überhaupt keine Möglichkeit mehr, sich mit dem Server zu verbinden – also muss die Firewall herhalten und die Spammer abhalten. Aber nun von Hand alle IP-Adressen auf allen meinen Servern in iptables eintragen würde dann doch einen nicht ganz unerheblichen Aufwand bedeuten. Eine Lösung, die sich über alle meine Server synchronisiert muss also her.

Auf Xela’s Linux Blog las ich dazu einen interessanten Artikel.

Die Spamhausliste dürfte wohl eher Mailspammer enthalten. Aber da Mailspam genau wie Kommentarspam sehr häufig von gehackten Servern seinen Ursprung hat, ist das doch schon mal ein exzellenter Anfang!

Ausgangspunkt für meine Lösung sollten also die beiden Skripte von Xelas Blog werden, das einzige was ich noch ergänzen musste war ein zweiter Aufruf für eine eigene Block-Liste, die ich einfach auf einem meiner Webserver hoste und mit IP-Adressen füttern kann, die in beliebigen meiner Seiten oder meiner Kundenseiten negativ als Spam-Ursprung aufgefallen sind. Die Skripte werden auf allen meinen Servern installiert, egal ob Mailserver oder Webserver und somit werden täglich alle Server mit einer aktuellen Liste gepflegt. Da ich vermutlich nicht täglich neue IP-Adressen einpflegen werde, habe ich es mir einfach gemacht und das Expiredatum meiner eigenen Liste einfach mal auf Ende 2030 gelegt.

So – nun aber mal konkret an die Arbeit:

Als erstes legen wir uns einen Ordner für die gespeicherten ipset Regeln an:

mkdir /var/lib/ipset/

Der zweite Schritt ist eine angepasste Version des droplist Download-Programms.

Dazu legen wir mit dem Editor unserer Wahl folgende Datei an:

/usr/local/bin/update-ipset.sh:

 

 

#!/bin/bash

# author: xela
# Addendum by mbitcon

# Updates ipset with fresh drop (dont root or peer) list from spamhaus. And fetches central mbitcon droplist

 

ipset_bin=’/sbin/ipset’

savefile=’/var/lib/ipset/blacklist-drop.save’

url=’https://www.spamhaus.org/drop/drop.txt’

tempfile=$(mktemp /tmp/spamhaus.drop.XXXXX)

 

wget -q -O – “$url” > $tempfile

if [ ! -f $tempfile ]

then

  logger -t ‘UpdateIpset’ “Fatal: file $tempfile not found”

  exit 1

else

  linecnt=$(cat $tempfile | wc -l)

  if [ $linecnt -lt 100 ]

  then

    logger -t ‘UpdateIpset’ “Fatal: file $tempfile is way too short to contain the actual block list”

    exit 1

  else

    expires=$(grep Expires $tempfile | awk -F ‘: ‘ ‘{print $2}’ | date +”%s” -f -)

    yesterday=$(date +”%s” -d yesterday)

    if [ $expires -lt $yesterday ]

    then

      logger -t ‘UpdateIpset’ “Warning: block list fetched from spamhaus seems outdated!”

    fi

  fi

fi

 

set_exists=$($ipset_bin -n list | grep -c blacklist-drop)

if [ $set_exists -eq 0 ]

then

  $ipset_bin create blacklist-drop hash:net family inet

else

  $ipset_bin flush blacklist-drop

fi

 

 

tempfile2=$(mktemp /tmp/spamhaus-drop-tmp.XXXXX)

 

grep -v ‘^;’ $tempfile | cut -d ‘ ‘ -f 1 > $tempfile2

 

cat $tempfile2 | while read line

do

  $ipset_bin add blacklist-drop “$line”

done

 

$ipset_bin save blacklist-drop > $savefile

 

records=$(grep -c ‘^add’ $savefile)

expdate=$(grep Expires $tempfile | cut -d ‘:’ -f 2,3,4)

 

logger -t ‘UpdateIpset’ “Updated blacklist-drop ipset with $records entries, expiredate$expdate”

rm $tempfile

rm $tempfile2

 

# Do the same thing with my own blocklist

 

mbitconsavefile=’/var/lib/ipset/blacklist-mbitcon.save’

url=’https://www.wp-webseite.de/drop/drop.txt’

tempfile=$(mktemp /tmp/mbitcon.drop.XXXXX)

 

wget -q -O – “$url” > $tempfile

if [ ! -f $tempfile ]

then

  logger -t ‘UpdateIpset’ “Fatal: file $tempfile not found”

  exit 1

else

  linecnt=$(cat $tempfile | wc -l)

  if [ $linecnt -lt 5 ]

  then

    logger -t ‘UpdateIpset’ “Fatal: file $tempfile is way too short to contain the actual block list”

    exit 1

  else

    expires=$(grep Expires $tempfile | awk -F ‘: ‘ ‘{print $2}’ | date +”%s” -f -)

    yesterday=$(date +”%s” -d yesterday)

    if [ $expires -lt $yesterday ]

    then

      logger -t ‘UpdateIpset’ “Warning: block list fetched from mbitcon seems outdated!”

    fi

  fi

fi

 

set_exists=$($ipset_bin -n list | grep -c blacklist-mbitcon)

if [ $set_exists -eq 0 ]

then

  $ipset_bin create blacklist-mbitcon hash:net family inet

else

  $ipset_bin flush blacklist-mbitcon

fi

 

tempfile2=$(mktemp /tmp/spamhaus-drop-tmp.XXXXX)

 

grep -v ‘^;’ $tempfile | cut -d ‘ ‘ -f 1 > $tempfile2

 

cat $tempfile2 | while read line

do

  $ipset_bin add blacklist-mbitcon “$line”

done

 

$ipset_bin save blacklist-mbitcon > $mbitconsavefile

 

records=$(grep -c ‘^add’ $mbitconsavefile)

expdate=$(grep Expires $tempfile | cut -d ‘:’ -f 2,3,4)

 

logger -t ‘UpdateIpset’ “Updated blacklist-mbitcon ipset with $records entries, expiredate$expdate”

rm $tempfile

rm $tempfile2

 

exit 0

 

 

Die Datei machen wir noch ausführbar:

chmod 755 /usr/local/bin/update-ipset.sh

Als nächstes bearbeiten wir die Datei /etc/ufw/after.init , oder falls es sie noch nicht gibt, legen wir sie an. Hier ist ein bisschen Fingerspitzengefühl gefragt, denn man sollte schon einen Blick in die Datei werfen, ob hier leere Standarddeklarationen für start, stop, status vorhanden sind, oder ob hier schon mal jemand Arbeit reingesteckt hat und schon “echte” andere Funktionalität vorhanden ist.

Wir nehmen an, dass wie in meinem Fall die Datei keine Zusatzfunktionen enthält und wir den Inhalt einfach überschreiben können.

/etc/ufw/after.init:

 

#!/bin/bash

# by xela, inspired by https://bugs.launchpad.net/ufw/+bug/1571579
# Addendum by mbitcon

 

savefile=”/var/lib/ipset/blacklist-drop.save”

if [ ! -f “$savefile” ]; then

  echo “Could not find ‘$savefile'” >&2

  return

fi

 

mbitconsavefile=”/var/lib/ipset/blacklist-mbitcon.save”

if [ ! -f “$mbitconsavefile” ]; then

  echo “Could not find ‘$mbitconsavefile'” >&2

  return

fi

 

#check whether ipset is installed

if [ ! -x “/sbin/ipset” ]; then

  echo ‘Ipset binary not found’

  return

fi

 

IPSET_BIN=”/sbin/ipset”

 

case “$1” in

start)

    exists=$($IPSET_BIN -n list | grep -c blacklist-drop)

    if [ $exists -eq 0 ]; then

      # Loading ipset

      $IPSET_BIN restore < “$savefile”

    fi

    # Setting firewall rules

    iptables -I INPUT -m set –match-set blacklist-drop src -j DROP

    iptables -I INPUT -m set –match-set blacklist-drop src -j LOG –log-prefix “[UFW BLOCK bl-drop] “

 

    exists=$($IPSET_BIN -n list | grep -c blacklist-mbitcon)

    if [ $exists -eq 0 ]; then

      # Loading ipset

      $IPSET_BIN restore < “$mbitconsavefile”

    fi

    # Setting firewall rules

    iptables -I INPUT -m set –match-set blacklist-mbitcon src -j DROP

    iptables -I INPUT -m set –match-set blacklist-mbitcon src -j LOG –log-prefix “[UFW BLOCK bl-mbitcon] “

    ;;

stop)

    # Unset firewall rules

    iptables -D INPUT -m set –match-set blacklist-drop src -j DROP || true

    iptables -D INPUT -m set –match-set blacklist-drop src -j LOG –log-prefix “[UFW BLOCK bl-drop] ” || true

    # Backup ipset list and destroy ipset

    $IPSET_BIN save > “$savefile”

    $IPSET_BIN destroy blacklist-drop || true

   

    # Unset firewall rules

    iptables -D INPUT -m set –match-set blacklist-mbitcon src -j DROP || true

    iptables -D INPUT -m set –match-set blacklist-mbitcon src -j LOG –log-prefix “[UFW BLOCK bl-mbitcon] ” || true

    # Backup ipset list and destroy ipset

    $IPSET_BIN save > “$mbitconsavefile”

    $IPSET_BIN destroy blacklist-mbitcon || true

    ;;

status)

    echo “= after.init =”

    $IPSET_BIN -t list

    echo “”

    ;;

*)

    echo “‘$1’ not supported”

    echo “Usage: after.init {start|stop|status}”

    ;;

esac

 

Auch diese Datei machen wir mit

chmod 755 /etc/ufw/after.init

ausführbar und nun können wir alles schon mal aktivieren:

/usr/local/bin/update-ipset.sh; /etc/ufw/after.init

Und eine Kontrolle mittels

ipset list

sollte uns nun einen ganzen Schwung geblockte Adressen und Netze auswerfen.

Jetzt bleibt uns noch eines, nämlich für eine regelmäßige Ausführung des Droplist-Downloaders zu sorgen:

Dazu legen wir uns einen cronjob an, indem wir folgende Datei anlegen:

/etc/cron.d/update-ipset

mit folgendem Inhalt:

21 7 * * * root /usr/local/bin/update-ipset.sh

Die Uhrzeit ist natürlich willkürlich, ich habe sie einfach übernommen, man kann hier natürlich eintragen, was man möchte.

Und natürlich nicht vergessen, eine eigene Liste auf dem Webserver anzulegen. Das Format habe ich einfach von der Spamhaus Liste übernommen.