先分清网络不通还是被拦
端口不通时第一个要回答的问题不是「哪条规则拦的」,而是「有没有被拦」。两个判据最有效:对端是否回 RST —— 回 RST(Connection refused)说明包到达了主机但没有监听者或被本地规则显式拒绝;纯超时则大概率是被 DROP 静默丢弃,或者包根本没到。再配合本机抓包看 SYN 是否到达网卡,就能把责任层从云平台一路收到主机内部。
基本信息
| 适用平台 | Linux 主机(iptables/nftables/firewalld/ufw)+ 云平台安全组/网络 ACL |
|---|---|
| 判据 | RST 快拒 = 到达后被拒;超时无响应 = 疑似 DROP 或未到达 |
| 检查顺序 | 云安全组/NACL → 主机 nftables → 主机 iptables → firewalld/ufw → SELinux/AppArmor → 服务监听 |
| 抓包落锤 | tcpdump 看 SYN 是否到达网卡,判断拦截点在主机外还是主机内 |
| 权限 | 查看规则与抓包均需 root |
典型使用场景
- 云主机开放端口后外网仍不通:确认是安全组未放行还是主机防火墙拦截
- 同一台机器上既有 nftables 又有遗留 iptables 规则,需要判断谁在生效
- 变更防火墙后业务中断:快速定位是哪一层规则被改动
- 内网互通但外部不通:区分主机防火墙与云网络 ACL 的拦截
- 确认 SELinux 或 AppArmor 是否在应用层阻断了端口绑定或访问
逐层核对
逐层核对
iptables -L -nv --line-numbers | head -40 # 遗留 iptables 规则(含命中计数)
nft list ruleset | head -60 # nftables 规则全集
firewall-cmd --list-all 2>/dev/null || ufw status verbose # 上层封装的状态
ss -tlnp | grep ':8080' # 服务是否真的在监听
# 本机抓包:外部来访的 SYN 是否到达网卡(判断拦截点在内还是在外)
tcpdump -ni any 'tcp port 8080 and tcp[tcpflags] & tcp-syn != 0' -c 5
# 从外部主动探测,观察是 RST 还是超时
timeout 3 bash -c 'cat < /dev/null > /dev/tcp/10.0.0.5/8080' && echo open || echo blocked症状与拦截层对照
| 外部现象 | 主机抓包 | 指向的拦截层 |
|---|---|---|
| 连接超时 | 看不到 SYN | 云安全组、网络 ACL 或中间设备 DROP |
| 连接超时 | 看到 SYN 无响应 | 主机防火墙 DROP 规则或服务未监听但被丢弃 |
| Connection refused(RST) | 看到 SYN 与 RST | 服务未监听,或规则使用 REJECT |
| 时通时断 | SYN 到达但无规律 | 规则命中顺序或连接跟踪表接近上限 |
| 仅内网可访问 | SYN 只来自内网 | 安全组仅放行内网网段,或监听绑定了内网地址 |
同一台机器可以同时存在 nftables 与遗留 iptables 两套规则(nft 后端兼容层),firewalld 又是它们的上层封装;排查时必须两边都看,否则会漏掉真正的拦截点。