You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu下如何彻底终止攻击IP的所有TCP连接(含ESTABLISHED、RELATED)并实现有效拦截?

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 14:53:09