首次连接到端口后使用 iptables 永久阻止 IP

首次连接到端口后使用 iptables 永久阻止 IP

我的所有服务器都在非标准端口(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)端口……)的任意大型散列列表。

你可以这样做iptablesset匹配和SET目标 +ipsetipset将作为记忆。

使用配套工具创建集合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(但触发器来自日志文件而不是数据包路径)。

还有其他可能的方法,例如使用nftables(及其内置) 代替iptables+ipset。请随意测试一下。

答案2

IPtables 本身无法管理这种动态分析。从您的描述来看,您实际上需要一种可以为您管理此类规则的工具。总的来说,我可以针对该特定情况推荐fail2bandenyhosts但可能还有其他。

我成功地尝试了这两种方法,但用例相似。您可以为不同的端口和协议、规则到期时间、最大重试次数和许多其他选项设置不同的规则。

官方链接:

http://denyhosts.sourceforge.net/

https://www.fail2ban.org/wiki/index.php/Main_Page

答案3

我同意@J A 的回答。

不过,我确实想分享我的开源 XDP 防火墙项目这里应该能够实现这一点。该工具利用 XDP,如果您的 NIC 支持 XDP-native,应该能够比 IPTables 更快地阻止流量。否则,它应该如果您使用 XDP-generic/SKB 模式,则速度与 IPTables 相同(大多数 NIC/现代内核都应该支持此功能)。

使用该程序的唯一缺点是:

  1. 它使用配置文件来指定过滤规则。目前没有添加/删除过滤规则的命令。

  2. 程序重新启动后,IP黑名单将被清除。

我希望实现能够添加过滤规则并在将来自动保存它们的命令,同时还能够永久阻止支持重启的 IP。

对于您的情况,以下配置应该可以做到:

interface = "changeme";
updatetime = 15;

filters = (
    {
        enabled = true,
        action = 0,

        tcpopts = (
            {
                enabled = true,
                dport = 22,
                blocktime = 9999999999
            }
        )
    }
);

这将阻止通过 TCP 针对目标端口 22 的数据包9999999999数秒(如果需要,您可以增加这个时间,因为blocktime配置选项是一种uint64_t类型)。

我希望这对你有帮助!

相关内容