最稳妥方案是 ipset + iptables;因规则顺序匹配导致数百条 iptables drop 规则性能骤降,而 ipset 哈希查找为 o(1),实测吞吐几乎无损,且需配合 geo_filter 链避免误杀本地流量。

直接结论:用 ipset + iptables 是最稳妥、可维护、性能可控的方案;xt_geoip 模块虽省内存,但编译麻烦、兼容性差,不推荐新部署。
为什么不用 iptables 直接加几百条 DROP 规则?
因为规则匹配是顺序执行的 —— 每个进来的包都要从第一条规则开始逐条比对,直到命中 RETURN 或 DROP。当规则数超 200 条,CPU 花在规则遍历上的开销就明显上升,尤其在高并发 SSH 或 HTTP 请求时,会拖慢连接建立速度。
而 ipset 把所有国内网段存成一个哈希表,iptables -m set --match-set cn_ips src 这一条规则就能完成 O(1) 查找,实测在 4 核服务器上吞吐下降几乎为零。
- 别手动写
iptables -A INPUT -s 1.0.1.0/24 -j ACCEPT一百次 - 别用
for ip in $(cat cn.txt); do iptables -A INPUT -s $ip -j ACCEPT; done—— 这等于把规则数拉到几千条 - 务必先建
ipset集合,再让iptables引用它
怎么从 APNIC 获取最新 CN IPv4 段并导入 ipset?
APNIC 的 delegated-apnic-latest 是权威来源,每日更新,但原始格式不是 CIDR,需转换子网掩码。
以下命令可直接跑通(CentOS/RHEL/Ubuntu 均适用):
curl -s http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest \
| awk -F\| '$2=="CN" && $3=="ipv4" { printf "%s/%d\n", $4, 32-log($5)/log(2) }' \
| grep -v "0.0.0.0" > /tmp/cn_cidr.txt
<p>ipset create cn_ips hash:net
while read cidr; do
[ -n "$cidr" ] && ipset add cn_ips "$cidr"
done </p><p>注意点:</p>
-
awk中的log($5)/log(2)是把 IP 数量转成 CIDR 前缀长度,比如 65536 → /16 -
grep -v "0.0.0.0"是过滤掉 APNIC 里偶尔混入的非法段 - 如果提示
ipset: set with the same name already exists,先ipset flush cn_ips或ipset destroy cn_ips
iptables 规则链怎么组织才不误杀本地流量?
错误做法:iptables -A INPUT -m set ! --match-set cn_ips src -j DROP —— 这会直接干掉所有非 CN 流量,包括你本机 curl localhost、内网管理口、Docker bridge 等。
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
正确顺序必须是:
iptables -N GEO_FILTER iptables -A INPUT -j GEO_FILTER <h1>先放行可信源</h1><p>iptables -A GEO_FILTER -s 127.0.0.1 -j RETURN iptables -A GEO_FILTER -s 10.0.0.0/8 -j RETURN iptables -A GEO_FILTER -s 172.16.0.0/12 -j RETURN iptables -A GEO_FILTER -s 192.168.0.0/16 -j RETURN</p><h1>再放行国内</h1><p>iptables -A GEO_FILTER -m set --match-set cn_ips src -j RETURN</p><h1>最后兜底 DROP(上线前建议先用 LOG)</h1><p>iptables -A GEO_FILTER -j LOG --log-prefix "GEO_DROP: " iptables -A GEO_FILTER -j DROP</p>
关键逻辑:
- 自定义链
GEO_FILTER让规则更清晰,也方便后续单独禁用或调试 -
RETURN不是“跳过”,而是跳出当前链、继续走默认策略;所以一定要确保INPUT默认策略是ACCEPT,否则没显式放行的全被 DROP -
LOG行必须放在DROP前,且建议加--log-prefix,方便用dmesg | grep GEO_DROP快速验证是否真在拦截海外 IP
定时更新 IP 段和避免规则失效的细节
APNIC 数据每周有微调,但实际变化不大;建议每周一凌晨更新一次即可,不必每天跑。
写个简单脚本 /root/update-cn-ips.sh,然后加 crontab:
0 3 * * 1 /root/update-cn-ips.sh
脚本内容要点:
- 先
ipset flush cn_ips清空旧数据,再重新add,不要用destroy/create—— 否则正在运行的iptables规则会报错 “set not found” - 下载失败时用
exit 1并发邮件提醒,别静默失败 - 更新后执行
iptables-save > /etc/sysconfig/iptables(CentOS)或iptables-save > /etc/iptables/rules.v4(Debian),否则重启就丢了
最容易被忽略的一点:如果你开了 ufw 或 firewalld,它们会覆盖或干扰 iptables 手动规则。确认它们已停用:systemctl stop ufw firewalld && systemctl disable ufw firewalld。










