systemd-service zum Zählen von Zugriffen nach ASN
Ich will es wissen: Woher kommen die Zugriffe auf meinen Rootserver? Und stellt das ein Problem dar?
Die letzte Frage kann ich klar mit "nein" beantworten. Der Server langweilt sich die meiste Zeit. Aber neben meinem Rootserver habe ich noch einen virtuellen Server (VPS, virtual private server), der ein bisschen mehr zu tun hat und bei dem es ein Problem sein könnte, wenn da zu viel Mist aufläuft. Der Rootserver ist aber ein gutes Versuchskaninchen.
Anarcat hat letztes Jahr das Python-Programm asncounter veröffentlicht, das Logs aus verschiedenen Quellen nehmen kann, um sie zu analysieren und eine ASN-Statistik auszugeben. Im (englischsprachigen, aber gut verständlichen) Blogbeitrag befinden sich Erklärungen zu AS, ASN und BGP.
Der Server läuft derzeit noch mit Debian 12. Anarcat stellt in Aussicht, dass asncounter in Debian 14 in den offiziellen Repositorys enthalten seien könnte. Bis dahin ist die beste Installationsmethode wohl mittels pip bzw. pipx. Ich habe mich für letzteres entschieden. Der Einfachheit halber installiere ich gleich die Pakete mit, die bei der Installation von asncounter benötigt werden:
apt install pipx build-essential python3-dev
Ich mag es nicht, wenn pipx die virtuellen Environments und so in /root erstellt. Deswegen setze ich in der /root/.bashrc ein paar Variablen für pipx:
export PIPX_BIN_DIR=/usr/local/bin export PIPX_HOME=/usr/local/share/pipx eval "$(register-python-argcomplete pipx)"
Die letzte Zeile dient der Tabvervollständigung von pipx-Befehlen. Einmal kurz ausgeloggt und wieder eingeloggt, geht es weiter:
pipx install --include-deps asncounter
Das installiert den asncounter inklusive seiner Abhängigkeiten. Der Blogbeitrag erwähnt im tl;dr am Anfang eine Befehlszeile folgenden Formats:
tcpdump -q -i enp0s31f6 -n -Q in "tcp and tcp[tcpflags] & tcp-syn != 0 and (port 80 or port 443)" | asncounter --input-format=tcpdump --repl
Ich lese "tcpdump" jetzt nicht so wahnsinnig flüssig, aber ich erkenne eine Filterung nach TCP-Zugriffen auf Ports 80 und 443. Das soll mir für den Anfang reichen. Dummerweise hänge ich dann im REPL fest und muss die dazugehörige man-Page erstmal ein wenig gründlicher lesen, wo ich auf recorder.display_results() stoße:
>>> recorder.display_results() count percent ASN AS 7248 85.27 265269 MEGA TELE INFORMATICA, BR 1132 13.32 270606 R3 TELECOM, BR 25 0.29 54801 ZILLION-NETWORK, US 25 0.29 45102 ALIBABA-CN-NET Alibaba US Technology Co., Ltd., CN 15 0.18 209334 MODAT-01, NL 11 0.13 197540 NETCUP-AS netcup GmbH, DE 6 0.07 16276 OVH, FR 4 0.05 213438 COLOCATEL-INC Colocatel Network - High Bandwidth Dedicated Servers, SC 4 0.05 14061 DIGITALOCEAN-ASN, US 3 0.04 211607 RECORDEDFUTURE, US unique ASN: 26 count percent prefix ASN AS 1826 21.48 168.90.91.0/24 265269 MEGA TELE INFORMATICA, BR 1823 21.45 168.90.89.0/24 265269 MEGA TELE INFORMATICA, BR 1806 21.25 168.90.88.0/23 265269 MEGA TELE INFORMATICA, BR 1793 21.09 168.90.90.0/24 265269 MEGA TELE INFORMATICA, BR 310 3.65 177.37.19.0/24 270606 R3 TELECOM, BR 282 3.32 177.37.17.0/24 270606 R3 TELECOM, BR 273 3.21 177.37.18.0/24 270606 R3 TELECOM, BR 267 3.14 177.37.16.0/24 270606 R3 TELECOM, BR 25 0.29 148.178.64.0/20 54801 ZILLION-NETWORK, US 25 0.29 47.83.0.0/17 45102 ALIBABA-CN-NET Alibaba US Technology Co., Ltd., CN unique prefixes: 34 total lookups: 8500 total skipped: 0 total failed: 0
asncounter gibt also im Falle des Durchpipens von tcpdump nur auf explizite Anfrage Werte aus. Damit kann man sicher arbeiten, aber mir wird beim Gedanken, irgendwelche Sockets regelmäßig abzufragen, ein wenig flau im Magen. Langlaufende Prozesse, die ich verbrochen habe? Nein, danke :-).
Aber tcpdump minütlich Dinge erfassen lassen, die ich asncounter dann zum Analysieren vorwerfen kann? Klar, das sicher. Und so lernte ich heute von timeout, das genau das tut, was ich will:
timeout -sHUP 1m tcpdump -q -i enp0s31f6 -n -Q in "tcp and tcp[tcpflags] & tcp-syn != 0 and (port 80 or port 443)" > tcpdump4asncounter.log
Jetzt brauche ich nur ein Bash-Skript, das mir jede Minute eine Datei mit diesen Daten erstellt.
#!/usr/bin/env bash
CACHE_DIR=/var/cache/count_asn
IF="${INTERFACE:-any}"
DIR="${CACHE_DIRECTORY:-${CACHE_DIR}}"
printf "Interface set to %s.\n" "${IF}"
printf "Cache directory set to %s.\n" "${DIR}"
cleanup () {
#kill -s SIGTERM $!
exit 0
}
trap cleanup SIGINT SIGTERM
if [ ! -d "${DIR}" ]
then
install -d "${DIR}"
fi
printf "Starting logging loop …\n"
while true
do
CURRENT=$(date +%s)
timeout -sHUP 10s tcpdump -q -i "${IF}" -n -Q in "tcp and tcp[tcpflags] & tcp-syn != 0 and (port 80 or port 443)" > "/tmp/count_asn_${CURRENT}.log" 2> /dev/null
find "${DIR}" -type f -mtime +1 -delete
mv "/tmp/count_asn_${CURRENT}.log" "${DIR}/"
cat "${DIR}/"count_asn_*.log | /usr/local/bin/asncounter --input-format tcpdump --no-prefixes --output /etc/motd.d/01-asncounter.txt 2> /dev/null
done
Am Anfang werden ein paar Variablen initialisiert, die ich entweder per systemd übergebe oder eben auch nicht. Dann braucht es aber sinnvolle Defaults.
Ich habe feststellen dürfen, dass sich so eine while-true-Schleife nicht mit Strg+c abbrechen lässt. Vielleicht liegt es auch an timeout. Deswegen werden die Signale SIGINT und SIGTERM explizit abgefangen und in der cleanup()-Funktion behandelt. Das aktuelle tcpdump läuft aber noch bis zum Ende durch. Damit kann ich leben.
Der Dump wird erstmal nur nach /tmp geschrieben. Dann werden die Dateien entfernt, die älter als 1 Tag sind, bevor die neue Datei in den Cache geschoben wird. Der Cache-Inhalt wird dann asncounter zur Analyse übergeben, das Ergebnis wird nach /etc/motd.d geschrieben (Verzeichnis muss manuell erstellt werden). Und auf diese Weise lernte ich, dass pam_login auch die Dateien dieses Verzeichnisses ausgibt statt nur /etc/motd.
Natürlich muss das Skript ausführbar gemacht werden:
chmod +x /usr/local/bin/count_asn
Jetzt muss das Skript nur noch dauerhaft laufen. Ich benutze dafür gerne systemd. Schnell mal eine Vorlage im Web herausgesucht und an meine Bedürfnisse angepasst. Ich bin leider immer noch nicht so weit, dass ich das aus dem Ärmel schütteln kann:
# /etc/systemd/system/count_asn.service [Unit] Description=Count ASNs using asncounter and update motd After=network.target [Service] Type=simple Environment=INTERFACE=enp0s31f6 ExecStart=/usr/local/bin/count_asn Restart=always RestartSec=5 CacheDirectory=count_asn IgnoreSIGPIPE=no [Install] WantedBy=multi-user.target
Der Install-Abschnitt gibt wie immer an, an welcher Stelle beim Booten der Dienst gestartet werden soll, wenn er enabled wird. Im Unit-Abschnitt sagen wir an, dass der Dienst erst nach dem Erreichen des network.target gestartet werden soll. Verfügbarkeit von Netzwerk ist eine Wissenschaft für sich, aber hier sollte das passen.
Der wichtigste Teil ist hier IgnoreSIGPIPE=no, ansonsten klappt das Pipen der Daten an asncounter nicht. Das Skript kriegt mit der Umgebungsvariable INTERFACE noch die richtige Schnittstelle mitgeteilt.
Lohn der Mühe:
$ ssh root@hades Linux hades.fluchtkapsel.de 6.1.0-41-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.158-1 (2025-11-09) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. count percent ASN AS 21811 78.65 265269 MEGA TELE INFORMATICA, BR 5486 19.78 265410 JL INFORMATICA E TELECOM LTDA - ME, BR 108 0.39 14618 AMAZON-AES, US 71 0.26 197540 NETCUP-AS netcup GmbH, DE 43 0.16 8075 MICROSOFT-CORP-MSN-AS-BLOCK, US 40 0.14 202306 HOSTGLOBALPLUS-AS, GB 31 0.11 51852 PLI-AS, PA 17 0.06 206264 AMARUTU-TECHNOLOGY, SC 14 0.05 398705 CENSYS-ARIN-02, US 10 0.04 62068 SPECTRAIP SpectraIP B.V., NL unique ASN: 40 total lookups: 27730 total skipped: 152 total failed: 0 Last login: Fri Jan 9 18:05:35 2026 from 79.248.89.181
Ich werde beim Login mit der Statistik begrüßt. Das sieht mir jetzt robust genug aus, dass ich das auch auf meinem VPS einrichten kann. Dort läuft Arch Linux. Als erstes installiere ich pipx:
pacman -Sy python-pipx python-pip base-devel
python-pip ist nur dafür dabei, falls ich mal manuell in die venv schauen muss, und base-devel ist das Arch-Äquivalent zu Debians build-essential. Als nächstes kommen die Einträge in die .bashrc von oben gefolgt von einem Logout und erneuten Login.
Ich übertrage das Skript und den Service, passe die Schnittstelle an, erstelle das Verzeichnis /etc/motd.d und starte den Service. Nach ein paar Minuten gibt es dann auch hier Statistiken:
$ ssh root@persephone count percent ASN AS 651 58.97 265269 MEGA TELE INFORMATICA, BR 151 13.68 265410 JL INFORMATICA E TELECOM LTDA - ME, BR 113 10.24 24940 HETZNER-AS, DE 61 5.53 14618 AMAZON-AES, US 22 1.99 16276 OVH, FR 12 1.09 197540 NETCUP-AS netcup GmbH, DE 8 0.72 3320 DTAG Internet service provider operations, DE 8 0.72 63949 AKAMAI-LINODE-AP Akamai Connected Cloud, SG 8 0.72 15169 GOOGLE, US 7 0.63 14061 DIGITALOCEAN-ASN, US unique ASN: 52 total lookups: 1104 total skipped: 7 total failed: 9462
Deutlich weniger Betrieb. Das überrascht. Im nächsten Schritt muss ich dann mal schauen, ob ich aus diesen Daten sinnvolle Regeln für die Firewall ableiten kann. Auf beiden Systemen läuft nftables – das macht es mir ein wenig einfacher. Aber das ist eine Aufgabe für einen Folge-Eintrag ins Blog.
Dieser Blog-Eintrag wurde ohne Unterstützung generativer KI erstellt.
Comments
With an account on the Fediverse or Mastodon, you can respond to this post. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.