Linux服务器禁ping不能只靠icmp_echo_ignore_all=1,因其仅屏蔽响应而不拦截ICMP包,无法缓解ICMP洪水攻击造成的软中断、带宽和CPU压力;真正有效防护需分层:网卡层分流、raw表快速丢弃、hashlimit限速,并合理配置iptables/firewalld规则优先级。

Linux服务器禁ping不能只靠关一个开关,ICMP洪水攻击(如ping flood)本质是利用大量ICMP Echo Request耗尽带宽或CPU资源,单纯设置 net.ipv4.icmp_echo_ignore_all = 1 能屏蔽响应,但无法阻止ICMP包到达内核、排队、触发中断——这本身就会造成负载。真正有效的防护需要分层:先过滤无效流量,再限制合法ICMP速率,最后才考虑是否彻底禁用响应。
为什么 icmp_echo_ignore_all = 1 不等于防攻击
这个内核参数只是让内核在协议栈上层“不生成Echo Reply”,但它不拦截原始ICMP包。攻击者发10万pps的 echo-request,网卡照样收、软中断照样处理、conntrack表照样可能被填满(如果启用了连接跟踪)、日志照样刷屏(如果开了log_martians)。实测中,即使设为1,单核CPU在50k+ pps ICMP洪水中仍可能软中断占满90%。
所以它适合「降低暴露面」,而非「抗洪」。
- 仅对本机响应生效,不影响转发路径上的ICMP(比如你做网关时)
- 不减少网络接口接收压力,也不影响iptables规则匹配顺序
- 若同时启用
iptables -A INPUT -p icmp --icmp-type 8 -j DROP,规则会早于该参数起作用,此时参数实际不生效
iptables 拦截ICMP前必须确认链和表位置
很多运维直接加 iptables -A INPUT -p icmp --icmp-type 8 -j DROP 就以为完事,但漏了两个关键点:一是没指定-i接口(比如只封外网eth0,放行内网bond0),二是没考虑raw表优先级。ICMP包进入netfilter后,会先过raw表(常用于NOTRACK),再进mangle,最后到filter的INPUT链。如果你在raw里写了-j NOTRACK,而ICMP又恰好匹配,那后续filter规则根本不会执行。
更稳妥的做法是:在raw表显式丢弃,避免绕过:
iptables -t raw -A PREROUTING -p icmp --icmp-type 8 -j DROP
或者限定接口+状态,兼顾管理需求:
- 只封公网接口:
iptables -A INPUT -i eth0 -p icmp --icmp-type 8 -j DROP - 允许已建立连接的ICMP(比如traceroute用的time-exceeded):
iptables -A INPUT -p icmp --icmp-type 3 -m state --state ESTABLISHED,RELATED -j ACCEPT - 禁止所有ICMP但留出必要类型(如type 3 destination-unreachable)可配合
ipset做白名单
用 iptables + hashlimit 限速比全禁更实用
完全禁ping会阻碍运维排障(比如监控系统用ping探测存活),也影响部分依赖ICMP的工具(如mtr、某些SDN健康检查)。更合理的做法是限速:允许少量探测,但拒绝突发流量。
例如,限制每个源IP每分钟最多5个echo-request:
iptables -A INPUT -p icmp --icmp-type 8 -m hashlimit \ --hashlimit-above 5/minute \ --hashlimit-burst 5 \ --hashlimit-mode srcip \ --hashlimit-name icmp_limit \ -j DROP
注意几个易错点:
-
--hashlimit-burst不是“首次允许多少”,而是令牌桶初始容量;超过后按速率限制放行 -
--hashlimit-name必须全局唯一,重复会导致规则加载失败 - 该模块依赖
xt_hashlimit内核模块,CentOS 7默认已加载,但Alpine等精简系统需手动modprobe xt_hashlimit - 不要和
limit模块混用——limit无源IP区分能力,容易误伤
firewalld用户别跳过rich rule的priority字段
用firewall-cmd配禁ping时,很多人只写:
firewall-cmd --permanent --add-rich-rule='rule protocol value="icmp" drop'
但这会在filter表末尾追加规则,而firewalld默认的public区域规则里已有ACCEPT相关ICMP的规则(比如允许echo-reply)。结果就是drop规则永远不命中。
正确做法是提高优先级,确保它早于其他ICMP规则:
firewall-cmd --permanent --add-rich-rule='rule priority="100" protocol value="icmp" drop'
数值越小优先级越高(0最高),建议设为100以下避开firewalld自动生成规则的范围(通常从200开始)。改完必须firewall-cmd --reload,且--permanent不可省略,否则重启失效。
另外,firewalld的rich rule不支持hashlimit,要限速只能切回iptables或改用nftables。
真正抗ICMP洪水的关键不在“禁”而在“筛”:优先在网卡驱动层(如启用rps、调大net.core.netdev_max_backlog)分流压力,再用iptables raw表快速丢弃,最后用hashlimit兜底限速。把icmp_echo_ignore_all当成最后一道门禁,而不是整面墙。


















