ICMP Type=3 Code=3表示端口不可达,即目标主机传输层无应用监听该端口;其他Type/Code包括:Type 3 Code 0(网络不可达)、Code 1(主机不可达)、Code 2(协议不可达)等。

直接用 tcpdump 捕获并过滤 ICMP Type 3(目的不可达)报文,尤其是 Code 3(端口不可达),是定位内网服务缺失或通信异常源头的高效方式。关键不在于“看到报文”,而在于把报文和发起它的本地进程对应起来。
明确抓取目标:只捕ICMP Type 3 Code 3
ICMP Type 3 是“目的不可达”大类,Code 3 才代表“端口不可达”。必须精准过滤,避免混入网络/主机不可达等干扰项:
-
基础命令:
sudo tcpdump -i any 'icmp and icmp[0] == 3 and icmp[1] == 3' -nn -v -
-i any确保捕获所有接口(含 lo、eth0、docker0 等) -
icmp[0]是 type 字段,icmp[1]是 code 字段,直取字节偏移,最可靠 -
-nn禁用域名和端口名解析,避免延迟;-v显示详细信息,含嵌套的原始 IP 头
从报文中提取关键线索
抓到的每条 Type 3 Code 3 报文都包含被拒绝的原始数据包头(即触发该错误的 UDP/TCP 包)。重点看 orig ip 行:
- 它会显示类似
orig ip 192.168.1.100.54321 > 192.168.1.200.8080 - 前半段(
192.168.1.100.54321)是发起探测的源 IP 和源端口 - 后半段(
192.168.1.200.8080)是目标 IP 和目标端口——这个端口上没有服务在监听 - 如果源 IP 和目标 IP 都是
127.0.0.1,说明是本机程序发给本机未监听端口(如 curl http://localhost:9999 但没服务)
快速定位发起进程(Linux 本地场景)
知道是哪个 IP+端口在发请求后,下一步是找出谁在用那个源端口:
- 查当前所有 UDP/TCP 连接及监听状态:
ss -tulnp | grep ':$'(例如grep ':54321$') - 若无结果,说明该连接已断开,但可结合时间戳回溯日志:
journalctl --since "2 minutes ago" | grep -E "(54321|8080)" - 检查定时任务或脚本:
crontab -l; ls /etc/cron.*; systemctl list-timers --all - 容器环境需额外确认:
docker ps --format "{{.ID}} {{.Names}}" | xargs -I{} docker inspect {} | grep -A5 HostConfig,看端口映射是否遗漏
常见误判与排除要点
不是所有 Type 3 Code 3 都指向配置错误,需结合上下文判断:
- 防火墙拦截:iptables/nftables 的 DROP 规则不会触发 ICMP 不可达;只有 REJECT 规则(且未禁用 icmp-host-prohibited)才会发此报文
-
SELinux 或 AppArmor:可能阻止进程 bind 端口,导致看似“服务未启动”,实为策略拒绝,查
ausearch -m avc -ts recent - 服务监听了 0.0.0.0,但客户端连的是 127.0.0.1:正常;若服务只 bind 了 127.0.0.1,则外部 IP 访问会触发 Type 3 Code 1(主机不可达),不是 Code 3
- UDP 应用无连接状态:UDP 客户端发包后,若服务未运行,内核会在首次收到包时返回一个 ICMP 端口不可达;后续包不再返回——所以抓包可能只出现一次


















