216 条网络命令(二):防火墙、conntrack、抓包、MTU
第二篇。上一篇讲地址、路由、连接与隧道;这一篇是防火墙、conntrack、抓包与 MTU。
五、netfilter(47 条)
iptables -vnL [链]
iptables -vnL
iptables -vnL FORWARD --line-numbers | head -8
关键:计数涨只说明匹配,不说明 hook 选对了。
坑:DNAT 之后目的地址变了,包走 FORWARD 而不是 INPUT。
写在 INPUT 链的规则永远碰不到它——这是最高频的一条死路。
iptables -t nat -vnL [PREROUTING|POSTROUTING]
关键:nat 表一条连接只查一次,所以计数只涨 1 是正常的。
判据:计数涨了 = 改写成功?不一定。要看 conntrack 里有没有成对的会话。
iptables -S
规则的可复现文本形式。
坑:只看 -L 不看 -S,容易漏掉链的默认策略(-P INPUT DROP 这类)。
建立一条能用的基线
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -P INPUT DROP
第一条几乎总是 ctstate。 没有它,回程包会被拦,你会看到「请求出去了、响应回不来」。
IPv6 的默认全通陷阱
ip6tables -S | head -20
坑:ip6tables 的默认策略可能是 -P INPUT ACCEPT(全放行)。
v4 严、v6 裸奔,是极常见的配置失衡。
v6 最小防护基线:
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 1 -j ACCEPT # 目的不可达
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 2 -j ACCEPT # 包太大
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 3 -j ACCEPT # 超时
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type 133:136 -j ACCEPT # RS/RA/NS/NA
ip6tables -A INPUT -p ipv6-icmp -j DROP
ICMP:只禁 Echo,别封 Type 3 与 11
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 2/s -j ACCEPT
iptables -A INPUT -p icmp --icmp-type fragmentation-needed -j ACCEPT
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
反例:iptables -A INPUT -p icmp -j DROP
全禁 ICMP = 制造 PMTUD 黑洞。大包被丢,小包正常,症状极其难查。
nft list ruleset
关键:inet 族一张表同时管 v4/v6。
坑:看到 table inet 就以为都齐了,没确认规则落在哪个 priority。
坑:iptables-nft 兼容表可能同时存在,两套规则并存。
nmap -Pn -p <端口> <公网IP>
从外部验证暴露面。
判据:本机 ss 有监听 + 云侧放行 + 主机规则放行,三者缺一不可。
六、conntrack(3 条)
conntrack -L
conntrack -L | grep 8080
关键:同一会话应该有成对的两行(正向 + 反向)。
坑:查不到就断定「没建连」——可能走了 XDP 旁路,或者被 NOTRACK 跳过。
conntrack -S
conntrack -S
看 insert_failed / drop / early_drop。这是表满的直接证据,即便系统日志里什么都没有。
cat /proc/sys/net/netfilter/nf_conntrack_count / max
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
判据:比值 > 0.9 且失败与并发峰值同步 → 表满。
关键:每条约 300 字节常驻内核内存,且不可交换。
100 万条 ≈ 300 MB。1 GB 内存的网关上,调大上限可能先触发 OOM。
顺序:永远先降产生速率,再评估调大。
七、抓包(9 条)
三档深度,成本递增
| 档 | 命令 | 拿到什么 |
|---|---|---|
| 一 | ip -s link / nstat -az / conntrack -S |
计数器,包在不在 |
| 二 | tcpdump -ni eth0 -c 20 '<filter>' |
头部,谁发给谁 |
| 三 | tcpdump -s0 -w /tmp/cap.pcap |
全长载荷 |
先数计数,再抓包。 抓包成本最高,而且会引入新的怀疑对象。
tcpdump -ni eth0 -c 20 'tcp port 8099'
关键参数:
-n 不做反向 DNS(否则你会等解析超时)
-i 指定接口;隧道场景 wg0 是明文、eth0 是 UDP 密文
-c 限数,防止刷屏
坑:默认只抓包头前若干字节。判「大包是否被丢」时,会以为包不存在。
判读重点:[S] 之后有没有 [S.]、重传间隔、包长是否贴着 MTU。
tcpdump -ni eth0 udp port 51820
确认 WireGuard 外层密文包。
关键:外层看不到内层 IP——它被加密了。
在 eth0 找不到内层地址,不等于没走隧道。
长度:148 / 92 字节是握手包。
tcpdump -s0 -w /tmp/cap.pcap
第三档,抓全长。
坑:加密流量看不到载荷。
坑:Wireshark 标 [TCP Previous segment not captured] 时,
先确认是不是抓包侧自己丢了。
坑:含敏感数据要脱敏。
八、路径与 MTU(21 条)
ping -M do -s <size> <dst> —— 找路径 MTU
-M do 禁止分片(DF 位),-s 是载荷大小。
# 前提:wg0 MTU = 1420
ping -M do -s 1392 10.0.0.5 # 1392 + 8(ICMP) + 20(IP) = 1420 通
ping -M do -s 1393 10.0.0.5 # 1421 > 1420 不通
铁律:不写链路 MTU 直接抄 1392,换环境就错。
1422/1423 那组数字只在路径 MTU = 1450 时成立。
二分法找边界:
for s in 1200 1300 1350 1380 1392 1400; do
ping -c1 -W1 -M do -s $s 8.8.8.8 >/dev/null 2>&1 \
&& echo "$s OK" || { echo "$s FAIL"; break; }
done
ping -c 4 <dst>
坑:默认载荷 56 字节,测不出任何 MTU 问题。
坑:ping 通 ≠ 业务通;ping 不通 ≠ 服务不可用。
traceroute -T -p 443 -n vs traceroute -I -n
TCP 探针穿透力最强,ICMP 探针对比着看。
判据:两种探针在某一跳开始分叉 → 那一跳就是策略设备(防火墙/负载均衡)。
坑:中间的星号不是「不通」,是「这一跳没把 ICMP 送回给我」。
mtr -rwz -c 10 <dst>
持续探测 + 丢包率统计。
关键:要写采样次数。短跑一次噪声极大。
判据:某一跳 100% 丢包但后续跳恢复正常 → 忽略那一跳。
下一篇:《216 条网络命令(三):DNS、TLS、队列、内核参数》