nftables set 管理恶意 ip 的关键是启用 interval 标志以支持单 ip 与 cidr 网段混合存储,避免拆分导致性能下降;配合 timeout 实现自动清理,通过一次规则引用实现 o(1) 查询,动态增删不中断服务。

用 nftables 的 Set 管理海量恶意 IP 黑名单,关键不在“加得多”,而在“查得快、删得稳、混得准”。核心是把上万条 IP 变成内核级哈希表,一条规则完成全部匹配,避免规则膨胀和 flush 中断。
必须启用 interval 标志才能真正支持网段混合
恶意 IP 数据往往既有单 IP(如 203.0.113.42),又有 CIDR 网段(如 198.51.100.0/24)。若不启用 interval,nftables 会把每个 /24 拆成 256 个独立地址存入集合,内存暴涨、查询变慢,完全失去优势。
- 错误写法:
nft add set inet firewall blacklist { type ipv4_addr }—— 不识别网段,纯地址列表 - 正确写法:
nft add set inet firewall blacklist { type ipv4_addr \ flags interval \ timeout 1h }—— 支持单 IP + 网段共存,自动合并相邻地址区间 - 验证是否生效:添加
192.168.1.0/24后,再查nft list set inet firewall blacklist,应显示为一条网段条目,而非 256 行
规则链里只写一次引用,不堆重复规则
Set 的价值体现在链中“一次引用、全局生效”。只要链已存在,后续增删集合元素,无需重载规则或重启防火墙。
- 先建基础链(默认 drop):
nft add chain inet firewall input { type filter hook input priority 0 \; policy drop \; } - 再加唯一拦截规则:
nft add rule inet firewall input ip saddr @blacklist drop - 这条规则生效后,每个入包仅需一次哈希查表,命中即丢弃;哪怕集合含 10 万个条目,性能仍接近 O(1)
动态更新不中断服务,慎用 flush
黑名单需对接威胁情报或自动封禁脚本,运行时增删是刚需。但 nft flush set 会导致集合瞬间清空,出现短暂放行窗口,极其危险。
- 安全添加:
nft add element inet firewall blacklist { 203.0.113.42 }或{ 198.51.100.0/24 } - 批量导入(推荐):
while read ip; do nft add element inet firewall blacklist { $ip }; done - 删除指定条目:
nft delete element inet firewall blacklist { 203.0.113.42 }(比 flush 更精准) - 依赖 timeout 自动清理:设
timeout 1h后,过期条目由内核自动回收,无需人工干预
超 10 万条时考虑 Map 实现分级响应
当不同 IP 需不同处置(如扫描器封 10 分钟、撞库源永久拉黑),纯 Set 无法区分动作。此时改用 Map,把 IP 映射到 verdict(drop / reject / jump)。
- 建 Map:
nft add map inet firewall ip_action { type ipv4_addr : verdict } - 设策略:
nft add element inet firewall ip_action { 192.0.2.100 : drop, 192.0.2.101 : reject with icmp type host-unreachable } - 在链中调用:
nft add rule inet firewall input @ip_action ip saddr - 注意:Map 不支持 per-entry timeout,需配合用户态脚本维护时间戳或使用 conntrack 超时联动











