IPTables 或替代解决方案阻止第一次连接尝试,然后允许来自同一 IP 的进一步尝试

IPTables 或替代解决方案阻止第一次连接尝试,然后允许来自同一 IP 的进一步尝试

我遇到了一种独特的情况,某个游戏的 DDOS 攻击正在发送真实的玩家连接数据包,这些数据包似乎完美地模仿了真实玩家的连接数据包。

这些通常会循环遍历数千个 IP,发送一个请求并填满服务器上的连接槽,从而阻止任何真实玩家连接。

一旦连接,真正的玩家就会开始以高频率发送多个 UDP 数据包,但这些虚假数据包每个 IP 只发送一次。

有没有办法我可以丢弃从 IP 接收到的第一个数据包,但然后允许所有后续数据包?

服务器在 Debian Linux 9.x 上运行。

答案1

iptables +ipset

您可以使用recent匹配扩展,但对于您的使用情况来说,它可能太有限,至少有两个原因:默认模块设置只允许 100 个条目,如果不进行更多调整,将限制为 < 100 个玩家,并且陈旧条目的过期不是自动的(它必须从数据包路径完成,这在性能方面并不好,或者从某些外部批处理作业完成)。

您还可以使用ipset,旨在与 iptables 一起使用,iptables 的功能是 的超集recent,并且效果更好。它会自动处理超时条目的删除。

例如,如果将其应用于端口 27960/udp...

ipset create firstseenpacket hash:ip timeout 60

iptables -N dropfirstseenpacket

iptables -I INPUT -p udp -m udp --dport 27960 -m set ! --match-set firstseenpacket src -j dropfirstseenpacket
iptables -I INPUT 2 -p udp -m udp --dport 27960 -j SET --exist --add-set firstseenpacket src
iptables -A dropfirstseenpacket -j SET --add-set firstseenpacket src
iptables -A dropfirstseenpacket -j DROP

第一次看到源时,测试将找不到条目,​​并且反转后将跳转到dropfirstseenpacket,这将添加条目并丢弃数据包。来自同一源的进一步出现将找到条目,刷新其计时器(--exist)并且不会执行任何其他操作。规则可以通过一个链进一步分解,例如,如果第一个测试比仅检查 27960/udp 更昂贵。

你可以使用以下命令查看 ipset 的内容:

ipset save firstseenpacket

请注意,我使用了-I(insert) 语句来确保此操作不受干扰地进行处理。将其放在条目之后-A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT应该可以保持兼容性,甚至可以提高性能和资源(通过将活动条目的责任从 ipset 移交给 conntrack),因为 conntrack 维护着自己的一组全部活动流在激活时始终有效。这将产生类似于以下内容的结果:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp -m udp --dport 27960 -m set ! --match-set firstseenpacket src -j dropfirstseenpacket
iptables -A dropfirstseenpacket -j SET --add-set firstseenpacket src
iptables -A dropfirstseenpacket -j DROP
iptables -A INPUT -p udp -m udp --dport 27960 -m conntrack --ctstate NEW -j ACCEPT

第二个数据包后的活动超时现在转移到 conntrack 的处理如果发送答复,根据各种情况,超时时间为 30 秒或 180 秒(最新内核为 120 秒)。

您应该验证它是否符合您的特定规则。

nftables

由于它可能会成为 iptables 的继任者,因此下面是与第一个版本相当的内容nft命令(并用于处理 IPv4 和 IPv6)。Nftables 原生处理设置。必须使用足够新的 nftables(>= 0.8.4 ?)才能使用set 语句允许从数据包路径添加的功能,因此在 Debian 9 上需要来自 stretch-backports 的 nftables

样板:

nft add table inet filter
nft add chain inet filter input '{ type filter hook input priority 0; }'

设置语句

set 语句用于从数据包路径动态添加或更新集合中的元素。set 集合名称必须已存在于给定表中。此外,任何将从 nftables 规则集动态更新的集合都必须同时指定最大集合大小(以防止内存耗尽)和一个暂停(这样集合中的条目数就不会无限增长)。set 语句可用于创建动态黑名单。

命名集与 ipset 等效的功能:

nft add set inet filter ipv4firstseenpacket '{ type ipv4_addr; timeout 60s; size 5000; }'
nft add set inet filter ipv6firstseenpacket '{ type ipv6_addr; timeout 60s; size 5000; }'

过滤规则:

nft add rule inet filter input udp dport 27960 ip  saddr != @ipv4firstseenpacket add @ipv4firstseenpacket '{ ip  saddr }' drop
nft add rule inet filter input udp dport 27960 update @ipv4firstseenpacket '{ ip  saddr }'

nft add rule inet filter input udp dport 27960 ip6 saddr != @ipv6firstseenpacket add @ipv6firstseenpacket '{ ip6 saddr }' drop
nft add rule inet filter input udp dport 27960 update @ipv6firstseenpacket '{ ip6 saddr }' drop

这里一次性检查条目,如果没有发现则添加并丢弃数据包。还必须执行其他操作来刷新计时器。ipv6 版本的工作原理相同。

例如,你可以使用以下命令查看设置内容:

nft list set inet filter ipv4firstseenpacket

更详细地说,使用 conntrack 将会是这样(也可以用附加链来分解):

nft add rule inet filter input ct state established accept
nft add rule inet filter input udp dport 27960 ip  saddr != @ipv4firstseenpacket add @ipv4firstseenpacket '{ ip  saddr }' drop
nft add rule inet filter input udp dport 27960 ip6 saddr != @ipv6firstseenpacket add @ipv6firstseenpacket '{ ip6 saddr }' drop
nft add rule inet filter input udp dport 27960 ct state new accept

相关内容