I need to add a rule to iptables to block connections to a tcp port from the Internet.
Since my script may be called multiple times and there is not a script to delete the rule, I want to check if an iptables rule already exists before inserting it - otherwise there will be a lot of dup rules in the INPUT chain.
How can I check if an iptables rule already exists?
16 Answers
There is a new -C --check option in recent iptables versions.
# 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 $?
0For older iptables versions, I would use Garrett suggestion :
# iptables-save | grep -- "-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT" The new -C option is not satisfactory, because it is open to a time-of-check-to-time-of-use (TOCTTOU) race condition. If two processes try to add the same rule at around the same time, -C will not protect them from adding it twice.
So, it is really no better than the grep solution. An accurate text processing job over the output of iptables-save can work as reliably as -C, since that output is a reliable snapshot of the state of the tables.
What is needed is an --ensure option which atomically checks and adds a rule only if it doesn't already exist. Moreover, it would be nice if the rule is moved to the correct position where a new rule would be inserted if it did not exist already (--ensure-move). For instance if iptables -I 1 is used to create a rule at the head of a chain, but that rule exists already in the seventh position, then the existing rule should move to the
first position.
Without these features, I think a feasible workaround is to write a shell script loop based on this pseudo code:
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
doneThis code could spin around; it does not guarantee that two or more racers will be out within a fixed number of iterations. Some randomized exponential backoff sleeps could be added to help with that.
2This may seem a bit backwards, but it works for me - Try deleting the rule first.
iptables -D INPUT -s xxx.xxx.xxx.xxx -j DROP;
You should get a message similiar to:
iptables: Bad rule (does a matching rule exist in that chain?)
Then simply add your rule as normal:
iptables -A INPUT -s xxx.xxx.xxx.xxx -j DROP;
Just list and search for it?
iptables --list | grep $ip... or however you have the rule specified. If you use grep -q it won't output anything, and you can just check the return value with $?
To avoid duplicate rules from your script, add below line.
iptables -C -INPUT -p tcp --dport 8080 --jump ACCEPT || iptables -A -INPUT -p tcp --dport 8080 --jump ACCEPTFirst time when above command is run, we would observe below message
iptables: Bad rule (does a matching rule exist in that chain?).
This is just for information. But second half of the command would ensure to add the rule.
How about first adding and then removing duplicates as described in . Easiest (for adjacent lines) seems to be
iptables-save | uniq | iptables-restore 1