Skip to main contentSkip to footer

Blocken mit dem Linux-Agenten

Der Community-Feed im Kernel und die Adressen, die dieser Host selbst sperrt: die zwei Arten von Set und ihre Lebensdauern, wie eine lokale Sperre entsteht und endet, die Eskalation mit echten Zahlen, die Kette im Kernel, die zwei Schalter mode und ban.enabled, und wie eine Sperre oder alles aufgehoben wird.

Der Community-Feed

Das ist der Teil, den die Seite Blockierung auf Netzwerkebene als Shell-Skript beschreibt. Der Agent macht dasselbe, und die Teile, die man beim Selberschreiben leicht falsch macht, sind schon erledigt: ein bedingter Abruf pro Liste, damit eine unveränderte Liste nichts kostet, eine Größenprüfung, bevor etwas live geht, ein atomarer Tausch, damit es nie ein Zeitfenster mit leerem Set gibt, und portgebundene Regeln, damit ein Web-Angreifer niemanden von SSH aussperrt.

ListeKernel-SetPorts, auf die die Regel greift
sshrip-ssh, rip-ssh-v6aus lists.ssh.ports
mailrip-mail, rip-mail-v625, 465, 587, 110, 995, 143, 993
webrip-web, rip-web-v680, 443
ftprip-ftp, rip-ftp-v621
edgerip-edge, rip-edge-v6jeden Port, mit Absicht
grouprip-group, rip-group-v6jeden Port, siehe unten

Wie oft der Feed geholt wird, hängt von Ihrem Tarif ab, und das entscheidet der Server, nicht der Agent. Auf einem lizenzierten Server ist das Intervall ab Professional alle 15 Minuten bei einer Mindest-Confidence von 75, auf Contributor stündlich bei 90. Business und Enterprise verhalten sich wie Professional. Der Agent fragt, welche Werte für diesen Host gelten, und folgt der Antwort. Ein Upgrade wirkt also, ohne dass jemand eine Datei bearbeitet. Die Antwort wird bis zu 24 Stunden zwischengespeichert, nur ein offener Zustand api_key, license oder reputation lässt ihn bei jedem Durchlauf neu fragen. Ein Tarifwechsel kommt also spätestens nach einem Tag auf dem Host an. Es gibt keinen Konfigurationsschlüssel für das Intervall, und ein Schlüssel, den Sie dafür erfinden, beendet den Agenten mit Exit 2.

Darüber liegen zwei weitere Regeln. Eine Liste, die vor weniger als 15 Minuten geholt wurde, wird nicht erneut geholt, denn so lange hält der Server sie im Cache. sync von Hand zu starten ist damit immer erlaubt und nie schädlich. Und jeder Abruf ist bedingt: eine unveränderte Liste antwortet mit 304 und kostet eine Anfrage und keine Übertragung, und deshalb ist ein kurzes Intervall für beide Seiten günstig.

Die Gruppenliste

Ein Key in einer Gruppe erhält eine sechste Liste, als json mit dem Community-Feed abgerufen. Jede Adresse wird auf jedem Port in den Sets rip-group und rip-group-v6 verworfen, unabhängig davon, welchen Dienst dieser Host anbietet. Ein Key in keiner Gruppe ändert nichts: das Set bleibt leer, und status zeigt group=none.

Die Whitelist der Gruppe, sofern sie eine trägt, wird in derselben Anfrage gelesen und nach /var/lib/reportedip-agent/group-whitelist geschrieben, im Format von whitelist.conf mit jeder Notiz als Kommentar. Bearbeiten Sie diese Datei nicht von Hand, der nächste Sync schreibt sie neu. Sie wird im selben Sync-Lauf an allen drei Stellen angewendet, an denen eine Whitelist wirkt: im Kernel-Whitelist-Set, im Filter jeder Liste und im Report-Gate des Watchers, eine weitere Ebene neben der eigenen whitelist.conf dieses Hosts und seiner Auto-Whitelist. Ein Key, der seine Gruppe verlässt, verliert die Datei mit dem nächsten Sync.

whitelist list und status zeigen die Einträge der Gruppe auf Zeilen, die mit group: markiert sind, samt Notiz. status nennt außerdem die Gruppe und ihre Größe neben der Kontozeile und zeigt die Anzahl der Einträge der Gruppenliste unter den Listen wie bei jeder anderen. Siehe Gruppen für das, was eine Gruppe ist, die Tarifgrenzen, die Whitelist und den Webhook auf der Portalseite.

Blocken

Der Agent schreibt zwei sehr verschiedene Dinge in den Kernel, und wer von fail2ban kommt, verwechselt sie in der ersten Woche meistens. Sie haben verschiedene Quellen, verschiedene Lebensdauern und verschiedene Schalter, es lohnt sich also, das einmal richtig zu trennen.

Zwei Arten von Set, zwei Lebensdauern

Community-BlacklistLokale Funde
Setsrip-ssh, rip-mail, rip-web, rip-ftp, rip-edge, rip-group, und je ein -v6-Set dazurip-local und rip-local-v6
Woher die Adressen kommenVon jedem Melder der Community, gefiltert über Ihr confidenceNur aus den eigenen Logs dieses Hosts
Wie ein Eintrag hineinkommtDas ganze Set wird bei jedem Feed-Durchlauf ersetztJeweils eine Adresse, wenn ein Schwellwert erreicht ist
Wie ein Eintrag verschwindetMit dem nächsten Tausch, wenn der Feed sie nicht mehr führtDer Kernel lässt ihn ablaufen, wenn sein eigenes Timeout um ist
Timeout pro Eintragkeinesja, das ist das ganze Konzept
Schaltermodeban.enabled, und mode darüber
Braucht eine Lizenzja, das ist der bezahlte Teilnein

Wie eine lokale Sperre entsteht und wie sie endet

Eine Sperre entsteht, wenn der Zähler eines Detektors für eine Adresse den Schwellwert ihrer Ereignisquelle überschreitet. Was dann passiert, in dieser Reihenfolge:

  1. Die Whitelist wird zuerst geprüft, bevor überhaupt etwas anderes gefragt wird. Eine Adresse auf der Whitelist hinterlässt gar keine Spur, Sie finden also Ihren eigenen Management-Bereich nie in reportedip-agent ban list und fragen sich, ob er geblockt war. Die Prüfung sagt, welche Schicht gegriffen hat: ein eingebauter reservierter Bereich, eine der eigenen Adressen dieses Hosts, oder Ihre Datei.
  2. Der Bann-Speicher, /var/lib/reportedip-agent/bans.json, wird nach der Sperrzeit gefragt. Er hält die Adresse, wann die Sperre abläuft, wie viele Sperren ins Gedächtnisfenster fielen, wann die letzte begann, die Quelle und die Kategorien. Die Datei wird vor dem Kernel-Eintrag geschrieben, ein Absturz direkt nach dem Kernel-Schreiben kann also nicht den Datensatz verlieren, der die Sperre wieder aufhebt.
  3. Die Adresse kommt mit dieser Zeit als Timeout pro Eintrag in rip-local. Der Kernel lässt sie ablaufen. Es gibt keinen Aufräum-Timer, keinen Cronjob und keine Entsperr-Warteschlange, und genau deshalb hinterlässt ein abgestürzter oder entfernter Agent keine dauerhafte Sperre.
  4. Eine Zeile geht ins Log, mit der Adresse, der Sperrzeit, der Quelle, der Zahl der Sperren dieser Adresse im Fenster, dem Abstand zwischen Logzeile und Kernel-Eintrag und den zwei Befehlen, mit denen man das rückgängig macht.

Eine laufende Sperre wird nie verkürzt. Kommt ein neuer Treffer für eine Adresse, die schon gesperrt ist, passiert nichts: es ist auch keine Eskalation, denn die Eskalation zählt Sperren und nicht Treffer, genau wie das Recidive-Jail, das sie ersetzt. Eine Adresse, die schon geblockt ist, kann nicht noch einmal geblockt werden. Diese Regel hält auch die Übergangszeit sauber, in der der Agent einen Angriff zweimal sieht, einmal als rohe Zeile aus auth.log und einmal als Bann-Zeile aus fail2ban.log.

Eine nachgespielte Logzeile erzeugt ebenfalls keine Sperre. Ein Treffer, dessen Zeitstempel nicht neuer ist als die letzte Sperre dieser Adresse, ist ein Replay nach einem harten Stopp und kein neues Vergehen, und der Meldepfad hat denselben Schutz in seiner Dedup-Datei.

Der Zustand überlebt mehr als einen Neustart. Mit ban.enabled: true vergleicht jeder Sync-Lauf bans.json mit dem, was der Kernel wirklich hält, und stellt das Fehlende mit der Restzeit wieder her:

  • Nach einem Reboot sind das alle, denn weder ein ipset-Timeout noch das Set selbst überlebt einen Reboot. Deshalb ist der Sync-Dienst für multi-user.target aktiviert und läuft nach jedem Firewall-Dienst.
  • Im normalen Betrieb sind es die Einträge, die etwas aus dem Set entfernt hat: ein firewall-cmd --reload, ein csf -r, ein ipset flush. Einträge, die der Kernel noch hat, bleiben unangetastet, die Lücke ist also ein Teil eines Sync-Intervalls und nicht der Rest der Sperre. Das Log sagt ausdrücklich, wenn Einträge unter laufenden Sperren fehlten, denn das heißt, dass etwas das Set unter dem Agenten bearbeitet hat.
  • Ein abgelaufener Datensatz kommt nie zurück. Der Angreifer von gestern ist kein Grund, heute jemanden abzuschneiden.
  • Die Whitelist wird bei jeder Wiederherstellung neu geprüft. Sie kann gewachsen sein, während der Host außer Betrieb war, und eine Adresse, die Sie gestern auf die Whitelist gesetzt haben, darf nicht durch einen Datensatz vom Vortag wieder geblockt werden.

Eskalation, mit echten Zahlen

Die erste Sperre dauert time_minutes. Jede Wiederholung innerhalb des Gedächtnisfensters multipliziert sie mit escalate, und max_time_minutes deckelt sie. Mit den Standardwerten (30 Minuten, Multiplikator 4, Obergrenze eine Woche) geht eine Adresse, die immer wiederkommt, so:

SperreRechnungDauer
1.time_minutes30 Minuten
2.30 × 42 Stunden
3.120 × 48 Stunden
4.480 × 432 Stunden
5.1920 × 4128 Stunden, fünf Tage und acht Stunden
6. und weiterwären 512 Stunden, gedeckelt7 Tage, der Wert von max_time_minutes

Die Kette im Kernel

Mit dem ipset-Backend besitzt der Agent genau eine Kette, rip-blacklist, und einen Sprung dorthin. Ein Sync baut die Kette neu, sobald ihr Fingerabdruck (Config und Kette, wie der Kernel sie ausgibt) abweicht, ihr Inhalt ist also immer das, was die Config sagt. Sonst lässt er die Kette stehen, damit die Paketzähler weiterzählen. Der Sprung wird nur an Position 1 von INPUT eingefügt, wenn er nicht schon da ist.

bash
# What a sync builds, in this order:
iptables -N rip-blacklist
iptables -F rip-blacklist
iptables -A rip-blacklist -m set --match-set rip-whitelist src -j RETURN
iptables -A rip-blacklist -m set --match-set rip-local src -j DROP
iptables -A rip-blacklist -p tcp --dport 22 \
         -m set --match-set rip-ssh src -j DROP
iptables -A rip-blacklist -p tcp -m multiport --dports 25,465,587,110,995,143,993 \
         -m set --match-set rip-mail src -j DROP
iptables -A rip-blacklist -p tcp -m multiport --dports 80,443 \
         -m set --match-set rip-web src -j DROP
iptables -A rip-blacklist -m set --match-set rip-edge src -j DROP
iptables -A rip-blacklist -m set --match-set rip-group src -j DROP

# Only with a scan source in the config: a SYN to a port this host
# does not listen on is logged, at most ten a minute. Listening ports
# and the passive range of a running FTP server return first, then any
# port a socket listens on at this very moment.
iptables -N rip-blacklist-scan
iptables -A rip-blacklist-scan -p tcp -m multiport --dports 21,22,25,80,443,40110:40210 -j RETURN
iptables -A rip-blacklist-scan -p tcp -m socket --nowildcard -j RETURN
iptables -A rip-blacklist-scan -m limit --limit 10/min --limit-burst 20 \
         -j LOG --log-prefix "rip-scan: "
iptables -A rip-blacklist -p tcp --syn -j rip-blacklist-scan

iptables -I INPUT 1 -j rip-blacklist

Die Whitelist ist die erste Regel und springt zurück, sie ist nicht die letzte Regel. Ein RETURN vor allem anderen heißt, dass eine Adresse auf der Whitelist die Kette verlässt, bevor irgendein Set befragt wird, sie steht also über jeder Sperre, auch über einer, die schon in rip-local liegt. Das macht whitelist add zu einem funktionierenden Weg aus einer Aussperrung, ohne Sync und ohne Neustart. Eine Whitelist am Ende wäre eine Liste von Ausnahmen, die zu spät kommen, und auf einem Host, auf dem Sie sich ausgesperrt haben, ist „zu spät“ das ganze Problem.

Die Regel für lokale Sperren hat keine Portbindung, denn ein Host, der Ihren Mailserver angegriffen hat, hat auf Port 22 auch nichts zu suchen. Die Regeln für ssh, mail, web und ftp sind portgebunden, eine Adresse auf der Web-Liste wird also auf 80 und 443 verworfen und erreicht SSH weiterhin. Das ist Absicht: eine geteilte Adresse, ein Carrier-NAT oder ein übernommener Proxy auf der Web-Liste darf keinen Administrator von der Maschine aussperren. Nur edge und group greifen auf jeden Port: bei edge ist das die Bedeutung der Kategorie dahinter, bei group der Sinn einer geteilten Sperre.

Mit dem nftables-Backend ist die Form dieselbe, nur nativ: eine Tabelle inet reportedip, eine Kette, die mit Priorität -10 und Policy accept in input hängt, zuerst die zwei return-Regeln der Whitelist, dann rip-local, dann die Feed-Listen mit ihren Portbindungen. Die Whitelist-Sets sind Intervall-Sets, damit sie CIDR-Bereiche halten können; die lokalen Sets tragen das Timeout-Flag, das beide Werkzeuge am Set verlangen, bevor ein Element überhaupt ein Timeout tragen darf.

In mode: log werden dieselben Regeln gebaut, und das Urteil ist eine ratenbegrenzte Logzeile (sechs pro Minute, mit dem Präfix rip-<list>:) statt DROP. Alles andere ist gleich, und deshalb ist der Log-Modus eine echte Probe und keine Simulation.

mode und ban.enabled sind zwei Schalter

Das ist das häufigste Missverständnis, es bekommt also seinen eigenen Absatz. mode entscheidet, was die Regeln tun. ban.enabled entscheidet, ob Ihre eigenen Funde überhaupt je ein Eintrag werden. Ab Werk sind beide an (mode: drop, ban.enabled: true). Wer ban.enabled: false setzt, hat mit mode: drop die Community-Liste durchgesetzt und von seinen eigenen Funden nichts.

modeban.enabledCommunity-ListeIhre eigenen Funde
logfalseGreift und loggt, nichts wird verworfenWerden an die Community gemeldet, lokal nicht geblockt
logtrueGreift und loggtWerden in rip-local erfasst und sind in ban list sichtbar, geloggt statt verworfen
dropfalseWird verworfenNur gemeldet. Das ist ein völlig sinnvoller Dauerzustand.
droptrueWird verworfenWird ebenfalls verworfen, mit Eskalation. Die vollständige Konfiguration.
offegalNichts im Paketpfad: der Sprung wird entfernt; bei ipset bleibt die Kette mit ihren Regeln, bei nftables wird die Kette gelöschtIm Speicher erfasst, ohne Wirkung

off ist der Notschalter und ist darin ehrlich. Es entfernt, was die Kette in den Paketpfad hängt, bis zu fünfmal, um doppelte Sprünge zu erwischen, und bricht laut ab, wenn ein Sprung überlebt, denn „off“ zu sagen und weiter zu verwerfen ist schlimmer als ein Fehler. Bei nftables wird die Kette selbst gelöscht. Die Sets behalten in beiden Backends ihre Einträge, ein Zurückschalten braucht also keinen vollen Download.

Eine Sperre von Hand ignoriert beide Schalter mit Absicht: reportedip-agent ban add funktioniert auch bei ban.enabled: false, denn das ist eine bewusste Handlung eines Operators, so wie fail2ban-client set banip es war. Die Whitelist gilt weiterhin, und auf einem Host ohne Firewall-Backend verweigert der Befehl den Dienst.

Von log auf drop wechseln

bash
# 1. What would have been dropped? The rules already match in
#    log mode, so ask the kernel log.
journalctl -k --since "24 hours ago" | grep -c "rip-"
journalctl -k --since "24 hours ago" | grep -o "rip-[a-z]*:" | sort | uniq -c

# 2. Is anything of yours in there? Check every source address
#    against your whitelist before you switch.
reportedip-agent whitelist list

# 3. Switch, and rebuild the rules.
sed -i "s/^mode: log/mode: drop/" /etc/reportedip-agent/config.yaml
reportedip-agent sync
reportedip-agent status

# 4. Only now the second switch, if you want it.
#    ban.enabled: true, then restart the daemon.
systemctl restart reportedip-agent.service
reportedip-agent ban list

Nachsehen, was wirklich im Kernel steht

reportedip-agent status ist die Zusammenfassung, und es liest sowohl die State-Dateien als auch den laufenden Kernel, damit man beides vergleichen kann. Wo die zwei sich widersprechen, ist der Kernel die Wahrheit, und status sagt das: ein Datensatz ohne Kernel-Eintrag ist eine Sperre, die nicht wirkt.

bash
# The agent's own view
reportedip-agent status
reportedip-agent ban list

# ipset backend, straight from the kernel
ipset list -t rip-ssh            # header and entry count only
ipset list rip-local             # entries, each with its timeout
iptables -S rip-blacklist
iptables -L INPUT -n --line-numbers | head

# nftables backend
nft list table inet reportedip
nft list set inet reportedip rip-local

In ban list ist die Spalte kernel das, was der Kernel noch auf der Uhr hat, und record das, was bans.json erwartet. Ein Strich unter kernel neben einem laufenden Datensatz heißt, die Sperre wirkt nicht und der nächste Sync stellt sie wieder her. Eine Zeile, deren Datensatz none sagt, existiert nur im Kernel, also hat jemand ipset oder nft von Hand benutzt, oder der Speicher ist verloren gegangen: sie läuft trotzdem ab, aber kein Reboot bringt sie zurück.

Eine Sperre aufheben, und alles zurückbauen

Der Weg aus einer Aussperrung ist ein Befehl. Die Whitelist-Regel steht vor der Blockregel, reportedip-agent whitelist add <address> wirkt also sofort und steht über jeder Sperre, auch über einer, die schon im Set liegt. Der Befehl schreibt die Datei und das laufende Kernel-Set in einem Schritt und braucht weder Sync noch Neustart.
bash
# Lift one ban and forget its history. The next detection starts
# from a first offence rather than escalating on top of a verdict
# you disagreed with.
reportedip-agent unban 203.0.113.45

# Never ban and never report this address or range, from now on.
reportedip-agent whitelist add 203.0.113.0/24 "customer office"

# Ban by hand. Works even with ban.enabled: false. A time given
# here is the time, not the first step of an escalation.
reportedip-agent ban add 203.0.113.45
reportedip-agent ban add 203.0.113.45 1440

# Stop blocking without uninstalling: no jump, the sets keep their entries.
sed -i "s/^mode: .*/mode: off/" /etc/reportedip-agent/config.yaml
reportedip-agent sync

# Remove the agent from the packet path completely (ipset backend).
iptables  -D INPUT -j rip-blacklist; iptables  -F rip-blacklist; iptables  -X rip-blacklist
ip6tables -D INPUT -j rip-blacklist; ip6tables -F rip-blacklist; ip6tables -X rip-blacklist
for s in $(ipset list -n | grep "^rip-"); do ipset destroy "$s"; done

# nftables backend
nft delete table inet reportedip

unban und whitelist add nehmen beide das Sync-Lock, der Wiederherstellungsschritt eines laufenden Syncs kann also nicht zurücklegen, was Sie gerade aufheben. Einen Eintrag aus der Whitelist-Datei zu entfernen ist der eine Vorgang, der nicht sofort wirkt: er greift mit dem nächsten Sync-Neubau, und eine Ausnahme zu entfernen muss nie sofort passieren.

Lassen Sie nie ein gespeichertes Ruleset auf ein rip--Set verweisen. iptables-restore verwirft die ganze Datei, sobald es auf ein unbekanntes Set trifft, eine übrig gebliebene Zeile in /etc/iptables/rules.v4 kann Ihnen also beim nächsten Boot die komplette Firewall nehmen. Der Agent baut seine Kette bei jedem Boot selbst auf und braucht nichts Gespeichertes. status warnt, wenn es rip- in rules.v4, rules.v6, /etc/sysconfig/iptables, ip6tables oder /etc/nftables.conf findet. In /etc/nftables.d sieht es nicht nach.

Zuletzt aktualisiert: · Betreut vom ReportedIP-Team

Security Focused
DSGVO-konform
Made in Germany
Zurück zur Doku