我的所有服务器都在非标准端口(987)上运行 SSH,并且我想永久阻止所有尝试连接到端口 22 的 IP。
我现在有规则,iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j DROP
但是该规则不会将 IP 添加到 iptables 中作为阻止,只有当前连接被丢弃。
第一次尝试连接端口 22 后,iptables 是否可以将 IP 添加为全局阻止(禁用任何其他端口上的连接)?
完整规则如下:
iptables -N SSH
iptables -A SSH -p tcp -m tcp --dport 22 -m state --state NEW -j DROP
iptables -A SSH -p tcp -m tcp --dport 987 -m state --state NEW -m recent --rcheck --set --rsource
iptables -A SSH -p tcp -m tcp --dport 987 -m state --state NEW -m recent --rcheck --update --seconds 300 --hitcount 4 --rsource -j DROP
谢谢!
(我正在使用 iptables v1.8.4(旧版))
更新 1:感谢@AB
端口 22 上的连接由 ipset 管理,IP 阻止时间为 86400 秒(1 天)。
iptables 管理的端口 987 上的连接在 300 秒内尝试连接 4 次(失败或成功)后将被阻止 300 秒。
ipset create ssh22 hash:ip timeout 86400
iptables -N SSH22
iptables -A SSH22 -p tcp -m tcp --dport 22 -m state --state NEW -j SET --add-set ssh22 src
iptables -A SSH22 -m set --match-set ssh22 src -j DROP
iptables -N SSH
iptables -A SSH -p tcp -m tcp --dport 987 -m state --state NEW -m recent --name ssh --set --rsource
iptables -A SSH -m recent --name ssh --update --seconds 300 --reap --hitcount 4 --rsource -j DROP
更新2:最终iptables
工作版本:
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -s XXX.XXX.XXX.XXX/32 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 987 -m state --state NEW -m recent --set --name ssh --rsource
-A INPUT -m recent --update --seconds 300 --reap --hitcount 4 --name ssh --rsource -j DROP
-A INPUT -p tcp -m tcp --dport 22 -j SET --add-set ssh22 src
-A INPUT -m set --match-set ssh22 src -j LOG --log-prefix "[SSH 22] " --log-level 4
-A INPUT -m set --match-set ssh22 src -j DROP
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp --icmp-type echo-request -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 987 -j ACCEPT
-A INPUT -i lo -p all -j ACCEPT
COMMIT
答案1
使用最近的
最近的是异常匹配:它不只是过滤,还会进行更改(通常在目标而不是匹配中完成):更改列表中的条目。它必须像您在其他地方所做的那样使用两次:一次用于设置列表,一次用于检查列表。第二次不应检查任何其他内容,因此从 IP 到任何内容的任何连接都将匹配并被丢弃,而不仅仅是到端口 22。
您的用户链 SSH 应该从输入(或者向前-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
) 在使用任何通用状态规则之前。
因此,请替换链的开头:
iptables -N SSH
iptables -A SSH -p tcp -m tcp --dport 22 -m state --state NEW -m recent --name banip --rsource --set -j DROP # -j DROP could be left: the next rule would do it.
iptables -A SSH -m recent --name banip --rsource --update -j DROP
然后,您可以为端口 987 添加附加规则。由于他们没有说明列表名称,因此他们将使用DEFAULT
不会干扰的规则banip
。
--seconds 12345 --reap
如果你希望这些 IP 地址在一段时间后过期(例如 12345 秒),你还可以在--update
在参数记录。
默认情况下最近的列表可以接受 100 个条目,因此使用最近的作为禁令名单,xt_最近应该加载内核模块,加载 iptables 规则之前,带有类似选项,ip_list_tot=65535
因为只能包含 100 个条目的列表可能不足以实现禁止列表。此参数适用于所有列表大小。
您还应该考虑使用ipset相反,如下所述,因为它通常更灵活。
使用ipset
在达到一定复杂程度后,最好使用配套ipset框架。ipset可以处理各种网络相关类型(IP 地址、(TCP 和/或 UDP)端口……)的任意大型散列列表。
你可以这样做iptables的set
匹配和SET
目标 +ipset
。ipset将作为记忆。
使用配套工具创建集合ipset
:
ipset create banip hash:ip
这将创建一个默认包含 65536 个条目的散列集,这比 100 或 255 要好得多。请参阅手册以了解如何在需要时创建更大的集合(集合的大小一旦确定就不能从数据包路径增加,只能通过进一步使用该ipset
命令来增加)。您可以使用适当的命令预填充、保存、恢复、列出此集合的内容等ipset
。
上述规则可以替换为:
iptables -N SSH
iptables -A SSH -p tcp -m tcp --dport 22 -m state --state NEW -j SET --add-set banip src
iptables -A SSH -m set --match-set banip src -j DROP
如果您希望条目过期,最简单的方法是创建带有超时参数的集合。
其中一种方法是失败2ban是使用ipset(但触发器来自日志文件而不是数据包路径)。
答案2
IPtables 本身无法管理这种动态分析。从您的描述来看,您实际上需要一种可以为您管理此类规则的工具。总的来说,我可以针对该特定情况推荐fail2ban
,denyhosts
但可能还有其他。
我成功地尝试了这两种方法,但用例相似。您可以为不同的端口和协议、规则到期时间、最大重试次数和许多其他选项设置不同的规则。
官方链接:
答案3
我同意@J A 的回答。
不过,我确实想分享我的开源 XDP 防火墙项目这里应该能够实现这一点。该工具利用 XDP,如果您的 NIC 支持 XDP-native,应该能够比 IPTables 更快地阻止流量。否则,它应该如果您使用 XDP-generic/SKB 模式,则速度与 IPTables 相同(大多数 NIC/现代内核都应该支持此功能)。
使用该程序的唯一缺点是:
它使用配置文件来指定过滤规则。目前没有添加/删除过滤规则的命令。
程序重新启动后,IP黑名单将被清除。
我希望实现能够添加过滤规则并在将来自动保存它们的命令,同时还能够永久阻止支持重启的 IP。
对于您的情况,以下配置应该可以做到:
interface = "changeme";
updatetime = 15;
filters = (
{
enabled = true,
action = 0,
tcpopts = (
{
enabled = true,
dport = 22,
blocktime = 9999999999
}
)
}
);
这将阻止通过 TCP 针对目标端口 22 的数据包9999999999
数秒(如果需要,您可以增加这个时间,因为blocktime
配置选项是一种uint64_t
类型)。
我希望这对你有帮助!