应使用ipset替代iptables海量规则,hash:ip用于单ip、hash:net用于网段,需显式设置hashsize和maxelem,通过restore批量导入,并确保内核模块加载、iptables正确引用及开机自动恢复。

直接用 iptables 加成千上万条规则来管黑白名单,性能会断崖式下跌——匹配是线性扫描,10 万条规则平均要比对 5 万次,CPU 拉满、延迟飙升、防火墙卡死。真正高效的做法,是用 ipset 把 IP 归入哈希集合,iptables 只需一条规则查一次哈希表,查找复杂度接近 O(1),十万级也稳如毫秒级响应。
选对类型和容量,避免运行时报错
ipset 类型选错,内存和速度差十倍;容量不设够,加到第 65537 条就报 “Set is full”:
- 纯单 IP 黑/白名单:用 hash:ip,内存低、查询快
示例:ipset create whitelist hash:ip hashsize 65536 maxelem 500000 - 含网段(如 192.168.1.0/24)或混合使用:必须用 hash:net
示例:ipset create blacklist hash:net hashsize 32768 maxelem 200000 - hashsize 建议设为预期元素数的 2–4 倍,默认 1024 容易哈希冲突;maxelem 必须显式指定,不能依赖默认值
批量导入导出,别用循环 add
逐行执行 ipset add 是最慢方式——每条都 fork 新进程,十万次调用可能耗时几分钟且易超时:
- 准备标准 restore 文件(如
whitelist.restore),格式如下:create whitelist hash:ip hashsize 65536 maxelem 500000add whitelist 192.168.1.10add whitelist 10.0.5.0/24 - 过滤原始列表(去空行、注释)再生成:
grep -v '^#|^$' ips.txt | sed 's/^/add whitelist /' > adds.txt
拼入 restore 文件头部即可 - 一次性加载:
ipset restore -f whitelist.restore
验证:ipset list whitelist | grep "Number of entries"
iptables 正确关联,确保规则生效
集合建好了,iptables 引用错一点,整套机制就失效:
- 必须加载内核模块:
modprobe ip_set_hash_ip(单 IP)或ip_set_hash_net(网段),并写入/etc/modules持久化 - iptables 规则必须带 -m set 和 --match-set,例如:
iptables -I INPUT -m set --match-set whitelist src -j ACCEPTiptables -I INPUT -m set --match-set blacklist src -j DROP - 规则位置很关键:-I 插入链首,确保在 -j ACCEPT 或 -j DROP 之前匹配;若已有放行规则在前,黑名单将被跳过
重启后自动恢复,避免配置丢失
ipset 运行在内存中,重启即清空。必须绑定系统启动流程:
- 导出当前状态:
ipset save whitelist > /etc/ipset-whitelist.conf - 写恢复脚本
/usr/local/bin/load-ipset.sh:#!/bin/bashipset restore /etc/ipset-whitelist.conf 2>/dev/null || trueiptables -I INPUT -m set --match-set whitelist src -j ACCEPT - 创建 systemd 服务,
After=network.target,启用开机自启 - 检查四点:模块是否加载、集合名是否三处一致(restore 文件 / iptables / 脚本)、规则是否插在链首、restore 前集合未被引用











