Ubuntu下如何彻底终止攻击IP的所有TCP连接(含ESTABLISHED、RELATED)并实现有效拦截?
最近我碰到个一模一样的头疼事儿:有几个恶意IP疯狂刷我的NGINX服务器,想用iptables+ipset拦,但发现只对新连接有用——那些已经建立的ESTABLISHED/RELATED连接完全不受影响,原来我的防火墙规则顺序搞反了!先给你理清楚问题,再一步步解决。
我的现状(和你一模一样)
当前iptables INPUT链规则顺序是先接受所有已建立/关联的连接,再检查黑名单,这就导致黑名单对已有的恶意连接完全无效:
# iptables -nL Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED DROP all -- 0.0.0.0/0 0.0.0.0/0 match-set Blacklist src ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 DROP all -- 0.0.0.0/0 0.0.0.0/0
黑名单ipset已经包含了攻击IP:
# ipset list Blacklist | grep <attacking-server-ip> <attacking-server-ip>
我试过的方法全踩坑了:
- 重启NGINX等30秒:没用,已建立的连接还挂着
conntrack --flush/conntrack -F:完全没效果- tcpkill:开着的时候能拦,但一关就立刻恢复连接
conntrack -D --orig-src <attacking-server-ip>:删完连接立刻又重建
终极解决方案(分三步)
第一步:调整iptables规则顺序(核心!)
iptables是按从上到下的顺序匹配规则的,必须把黑名单DROP放到ESTABLISHED/RELATED ACCEPT前面,这样不管连接是什么状态,只要是黑名单IP就直接拦截:
# 先查看INPUT链的规则序号,方便删除旧规则 iptables -nL INPUT --line-numbers # 假设ACCEPT是序号1,DROP是序号2,先删后面的DROP,再删前面的ACCEPT iptables -D INPUT 2 iptables -D INPUT 1 # 重新添加规则,顺序至关重要! # 1. 先拦黑名单IP iptables -A INPUT -m set --match-set Blacklist src -j DROP # 2. 再接受合法的已建立/关联连接 iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 3. 允许80/443的正常请求 iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT # 4. 最后拒绝所有其他请求 iptables -A INPUT -j DROP
调整后的规则,任何来自黑名单IP的数据包(不管是新连接还是已有的连接)都会被第一时间DROP,不会再绕过。
第二步:彻底清除现有恶意连接
现在规则改好了,接下来要把已经建立的恶意连接彻底干掉,防止它们继续传输数据:
方法一:用conntrack删除连接跟踪条目
# 删除攻击IP发起的所有连接 conntrack -D --orig-src <attacking-server-ip> # 同时删除服务器到攻击IP的反向连接(确保彻底清除) conntrack -D --orig-dst <attacking-server-ip>
因为已经调整了iptables规则,删完后攻击IP无法重建连接。
方法二:用ss命令强制关闭套接字(更直接)
# 强制关闭所有到攻击IP的连接 ss -K dst <attacking-server-ip> # 或者精确针对443端口的连接 ss -K dst <attacking-server-ip> dport = 443
ss -K会直接在内核层面关闭套接字,比tcpkill更高效,不需要一直运行进程。
方法三:发送TCP RST包主动断开(对付顽固连接)
如果上面的方法还不行,可以先给攻击IP发RST包,让双方主动断开连接,再改回DROP:
# 临时添加REJECT规则,发送TCP RST包 iptables -I INPUT 1 -s <attacking-server-ip> -j REJECT --reject-with tcp-reset # 等5秒,让所有连接都收到RST包断开 sleep 5 # 删除临时REJECT规则,换回黑名单DROP iptables -D INPUT 1
TCP RST包会让攻击方的系统直接关闭连接,不会一直重试重建。
第三步:持久化规则,防止重启失效
把ipset和iptables规则保存下来,服务器重启后自动生效:
# 保存ipset规则 ipset save > /etc/ipset.conf # 安装iptables持久化工具(Ubuntu下) apt install -y iptables-persistent # 保存iptables规则 iptables-save > /etc/iptables/rules.v4
为什么之前的方法没用?
- 规则顺序错误:原来的规则先接受已建立连接,黑名单规则根本不会被匹配到
- conntrack删连接后,攻击方只要发一个数据包,因为原来的规则允许ESTABLISHED/RELATED,连接跟踪会立刻重建
- tcpkill是用户层拦截,内核依然会处理连接,进程一停就失效
备注:内容来源于stack exchange,提问作者Dr. Gianluigi Zane Zanettini
相关产品推荐
相关产品推荐

