我需要向 iptables 添加一条规则来阻止来自 Internet 的 tcp 端口的连接。
因为我的脚本可能会被调用多次,并且没有删除规则的脚本,所以我想在插入之前检查 iptables 规则是否已经存在 - 否则 INPUT 链中会有很多重复的规则。
我如何检查 iptables 规则是否已经存在?
答案1
-C --check
最近的 iptables 版本中有一个新的选项。
# 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
对于较旧的 iptables 版本,我会使用 Garrett 建议:
# iptables-save | grep -- "-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT"
答案2
新-C
选项并不令人满意,因为它容易受到检查时间到使用时间 (TOCTTOU) 竞争条件的影响。如果两个进程尝试在大约同一时间添加同一条规则,则-C
无法保护它们不被添加两次。
因此,它实际上并不比grep
解决方案更好。对 输出的精确文本处理作业iptables-save
可以像 一样可靠地工作-C
,因为该输出是表状态的可靠快照。
我们需要的是一个--ensure
选项,它自动检查规则,并且仅在规则尚不存在时才添加规则。此外,如果规则被移动到正确的位置,并且新规则尚不存在,则插入新规则(--ensure-move
),那就太好了。例如,如果iptables -I 1
用于在链的头部创建规则,但该规则已存在于第七个位置,则现有规则应移动到第一个位置。
如果没有这些功能,我认为一个可行的解决方法是基于此伪代码编写一个 shell 脚本循环:
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
此代码可能会旋转;它不能保证两个或更多赛车手会在固定的迭代次数内出局。可以添加一些随机指数退避睡眠来帮助解决这个问题。
答案3
这可能看起来有点倒退,但对我来说却很有效。
请先尝试删除该规则。
iptables -D INPUT -s xxx.xxx.xxx.xxx -j DROP;
您应该收到类似以下内容的消息:
iptables: Bad rule (does a matching rule exist in that chain?)
然后只需像平常一样添加规则:
iptables -A INPUT -s xxx.xxx.xxx.xxx -j DROP;
答案4
为了避免脚本中出现重复的规则,请添加以下行。
iptables -C -INPUT -p tcp --dport 8080 --jump ACCEPT || iptables -A -INPUT -p tcp --dport 8080 --jump ACCEPT
第一次运行上述命令时,我们会看到以下消息
iptables: Bad rule (does a matching rule exist in that chain?).
这仅供参考。但命令的后半部分将确保添加规则。