Ich muss iptables eine Regel hinzufügen, um Verbindungen zu einem TCP-Port aus dem Internet zu blockieren.
Da mein Skript möglicherweise mehrmals aufgerufen wird und es kein Skript zum Löschen der Regel gibt, möchte ich vor dem Einfügen prüfen, ob bereits eine iptables-Regel vorhanden ist. Andernfalls enthält die INPUT-Kette viele Dup-Regeln.
Wie kann ich überprüfen, ob bereits eine iptables-Regel existiert?
In den letzten iptables-Versionen gibt es eine neue -C --check
-Option.
# iptables -C INPUT -p tcp --dport 8080 --jump ACCEPT
iptables: Bad rule (does a matching rule exist in that chain?).
# echo $?
1
# iptables -A INPUT -p tcp --dport 8080 --jump ACCEPT
# iptables -C INPUT -p tcp --dport 8080 --jump ACCEPT
# echo $?
0
Für ältere iptables-Versionen würde ich den Garrett-Vorschlag verwenden:
# iptables-save | grep -- "-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT"
Die neue Option -C
ist nicht zufriedenstellend, da sie für eine TOCTTOU-Rennbedingung (Time-of-Check-to-Time-of-Use) offen ist. Wenn zwei Prozesse versuchen, dieselbe Regel ungefähr zur selben Zeit hinzuzufügen, schützt -C
sie nicht davor, sie zweimal hinzuzufügen.
Es ist also wirklich nicht besser als die grep
Lösung. Ein genauer Textverarbeitungsjob über die Ausgabe von iptables-save
kann genauso zuverlässig arbeiten wie -C
, da diese Ausgabe eine zuverlässige Momentaufnahme des Status der Tabellen ist.
Was benötigt wird, ist eine --ensure
-Option, die eine Regel atomar prüft und nur hinzufügt, wenn sie noch nicht existiert. Außerdem wäre es schön, wenn die Regel an die richtige Position verschoben würde, an der eine neue Regel eingefügt würde, wenn sie noch nicht vorhanden wäre (--ensure-move
). Wenn beispielsweise iptables -I 1
zum Erstellen einer Regel am Anfang einer Kette verwendet wird, diese Regel jedoch bereits an der siebten Position vorhanden ist, sollte die vorhandene Regel an die erste Position verschoben werden.
Ohne diese Funktionen ist es meiner Meinung nach eine praktikable Lösung, eine Shell-Skriptschleife zu schreiben, die auf diesem Pseudocode basiert:
while true ; do
# delete all copies of the rule first
while copies_of_rule_exist ; do
iptables -D $RULE
done
# now try to add the rule
iptables -A $RULE # or -I
# At this point there may be duplicates due to races.
# Bail out of loop if there is exactly one, otherwise
# start again.
if exactly_one_copy_of_rule_exists ; then
break;
fi
done
Dieser Code könnte sich drehen; Dies garantiert nicht, dass zwei oder mehr Fahrer innerhalb einer festgelegten Anzahl von Iterationen ausfallen. Einige randomisierte exponentielle Backoff-Schlafzustände könnten hinzugefügt werden, um dies zu unterstützen.
Dies mag ein bisschen rückwärts scheinen, aber es funktioniert bei mir. Versuchen Sie zuerst, die Regel zu löschen.
iptables -D INPUT -s xxx.xxx.xxx.xxx -j DROP;
Sie sollten eine Nachricht erhalten, die der folgenden ähnelt:
iptables: Bad rule (Gibt es in dieser Kette eine passende Regel?)
Dann fügen Sie einfach Ihre Regel wie gewohnt hinzu:
iptables -A INPUT -s xxx.xxx.xxx.xxx -j DROP;
Einfach auflisten und danach suchen?
iptables --list | grep $ip
... oder aber Sie haben die Regel angegeben. Wenn Sie grep -q
verwenden, wird nichts ausgegeben, und Sie können den Rückgabewert einfach mit $?
überprüfen.