ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux网桥单向ping排查:防火墙、路由与ARP全解析

Linux网桥单向ping排查:防火墙、路由与ARP全解析

最近在整理一套主机加Linux虚拟机的桥接网络,配完桥接到测试时碰到一个特别让人头大的现象:主机能ping通虚拟机里的Linux,反过来Linux却ping不通主机。同一个物理口、同一个网桥、同网段的IP,链路看着全通,结果只有一边能说话。当时第一反应是把桥接配置整个推倒重来,结果还是一样,后来静下心逐步抓包排查,才发现问题根本不在“桥”上面。

这种单向ping问题在网络桥接场景里出现频率不低,而且特别有迷惑性——主机能ping通Linux,等于链路层和桥转发都正常,问题一定出在回程方向的某个环节:主机防火墙、接口IP归属、路由或ARP,四者必居其一。这篇记录我按“先定位、后处理”的顺序完整写出来,遇到同样问题的朋友可以直接照着排查。

先说清楚场景范围:主机和Linux客户机(或另一台Linux)通过网桥(br0)处在同一网段,现象是“主机→Linux通,Linux→主机不通”。如果你现在双向都不通,那多半是桥本身没生效或者客户机防火墙没放行,属于另一类问题,就不在下面展开了。

1. 单向ping的怪现象:先用抓包把问题钉死在某一段

1.1 为什么“主机通、客户机不通”最容易误判

单向通之所以坑人,是因为它看起来既像链路问题,又像防火墙问题,还像配置问题。很多人在这个阶段就开始凭着感觉改配置——重配网桥、换网络模式、重启网络服务,折腾一圈没效果又改回去,时间全浪费了。

我的建议是先别动任何配置。既然主机能ping通虚拟机,说明桥上的MAC地址学习和二层转发是好的,虚拟机的网络栈也能正常收发ICMP。那么剩下的怀疑对象只有三个方向:虚拟机发出去的包有没有真正到主机,主机收到后有没有回包,回包有没有回到虚拟机。这三个问题分别对应防火墙、路由、ARP,而抓包一次就能把它们全区分开。

1.2 双向tcpdump:一分钟看出包丢在哪

先在主机侧抓包。如果主机是Linux,直接在网桥接口上抓:

sudo tcpdump -i br0 -ne 'arp or icmp' and host 192.168.1.20

这里的192.168.1.20是Linux虚拟机(客户机)的IP,br0是主机的网桥接口。加-n只显示数字地址,-e带上MAC地址,方便确认ARP层面的对端是谁。然后在虚拟机里再抓一份:

sudo tcpdump -i eth0 -ne 'arp or icmp' and host 192.168.1.10

192.168.1.10是主机IP,eth0是虚拟机里的网卡接口名,按实际环境改。两边同时开着,虚拟机里执行ping -c 3 192.168.1.10,然后对照抓包结果,基本就是四种情况:

抓包现象结论下一步方向
虚拟机发出request,主机抓不到请求没到主机查桥接转发、虚拟化平台网络模式
主机抓到request,但只有request没有reply主机收到请求但拒绝回包查主机防火墙/iptables
主机发出了reply,虚拟机抓不到回程丢了查主机出方向策略、客户机路由
request和reply都通但ping还是失败二层或地址层面问题查ARP缓存、IP冲突、MTU

这个表基本覆盖了这类问题的所有可能。从我处理过的案例看,第二种情况占了一大半,也就是主机收到请求但死活不回包——把矛头直接指向主机防火墙。

2. 主机防火墙的ICMP策略:单向ping头号元凶

2.1 桌面系统主机的入站回显规则

最常见的场景是主机跑的是桌面系统,虚拟化软件在桥接模式下把虚拟网卡接到了物理网卡上。虚拟机发出的ping请求,其实和局域网里另一台电脑ping主机没有本质区别——数据包从物理网卡进到主机协议栈,然后被入站防火墙规则审视。

桌面系统自带的防火墙默认策略是“拦截入站请求,放行出站”。ICMP回显请求(echo request)属于入站流量,如果防火墙里没有对应的允许规则,主机会默默丢弃。于是单向通的诡异现象就出现了:主机ping虚拟机是出站流量,防火墙不管,所以能通;虚拟机ping主机是入站流量,被防火墙拦截,所以不通。

处理方法:Windows主机的话,到“控制面板 → 系统安全 → Windows防火墙 → 高级设置”,左侧选“入站规则”,右侧找“文件和打印机共享(回显请求 - ICMPv4-In)”这条规则,右键启用。注意如果当前网络类型显示的是“公用”,而规则只勾了“专用”配置文件,仍然会被拦,最好把这条规则在“公用”配置文件下也启用。命令行方式更直接:

netsh advfirewall firewall add rule name="allow icmp in" protocol=icmpv4:8,any dir=in action=allow

这条命令会在所有配置文件下放行ICMPv4回显请求入站。做完之后虚拟机立刻再ping一次,通了就说明判断正确。

这里提醒一句:排查期间临时关防火墙验证可以,别把它当成最终方案。先确认问题是防火墙,再有针对性地加一条最小规则,这才是工程做法。

2.2 Linux主机的firewalld与iptables处理

如果主机本身也是Linux,嫌疑从“防火墙通用策略”变成具体的firewalld或iptables规则。先看firewalld有没有屏蔽回显请求:

firewall-cmd --zone=public --query-icmp-block=echo-request

返回yes说明这个zone屏蔽了回显请求,移除屏蔽:

firewall-cmd --zone=public --remove-icmp-block=echo-request --permanent firewall-cmd --reload

更直接一点,也可以通过rich rule显式放行ICMP协议:

firewall-cmd --permanent --add-rich-rule='rule protocol value="icmp" accept' firewall-cmd --reload

新版firewalld(在众多企业级Linux发行版上)默认用了nftables后端,这时候看iptables输出不一定准确,用nft list ruleset看全部规则更可靠。如果你看到INPUT链的policy是DROP,或者有一条-p icmp --icmp-type echo-request -j DROP,那就是它了。手动加放行:

iptables -I INPUT -p icmp --icmp-type echo-request -j ACCEPT

临时验证可以先iptables -L INPUT -n --line-numbers看清现有规则编号,再选择插入位置,别把已有安全规则打乱。主机上如果还开着fail2ban这类工具,它也可能在INPUT链前面插入规则,影响要一并考虑。

Linux主机的防火墙重点看INPUT链,因为虚拟机ping主机的包到达主机网桥接口后,是发往本机的流量,走的就是INPUT链。很多人只盯着FORWARD链查,却忽略INPUT,这也是这类问题在Linux主机上排查慢的原因。

3. 网桥IP挂错接口:手工配br0时的经典配置错误

3.1 物理网卡被桥接管后IP必须迁到br0

防火墙查完还是不通,就要回头审视桥接配置本身。手工配置网桥的标准姿势是这样:

ip link set eth0 up ip link add br0 type bridge ip link set eth0 master br0 ip addr add 192.168.1.10/24 dev br0 ip link set br0 up ip route add default via 192.168.1.1 dev br0

核心是第四行:主机IP必须配置在br0上,而不是留在eth0上。很多人配完桥之后图省事,IP还挂在eth0上,或者eth0和br0都配了同网段IP,这时候就会出现各种匪夷所思的单向问题。

原因需要理解一下:eth0一旦被桥接管,它的角色就从“主机的一块网卡”变成了“桥上的一个端口”。主机协议栈收发IP流量的入口应该是br0自身。如果IP还留在eth0上,内核虽然也能通过eth0应答ARP,但这个应答发生在桥端口的上下文里,和桥自身的行为会打架。实际表现为:从主机往虚拟机发包正常,因为桥会学习MAC再转发;反过来虚拟机找主机时,ARP应答和ICMP回包的处理路径可能就拧了,表现为虚拟机发出请求、主机收到也不回,或者回了但没走上正确的桥端口。

处理方式:把残留IP从eth0上清掉,只保留br0上的地址:

ip addr del 192.168.1.10/24 dev eth0 ip addr show eth0 # 确认这个口不再有IP bridge link show # 确认eth0在br0的端口列表里

如果是用NetworkManager管理网桥,应该通过nmcli创建,不要混用手工brctl加上nm托管,两边会互相抢配置,这个坑不少人都踩过。

3.2 br_netfilter、STP和端口状态这些隐藏变量

还有一个Linux特性值得单独说:br_netfilter模块。这个模块加载后,桥接流量会被“复制”一份进iptables处理,这意味着即使流量只是从虚拟机到主机,也可能被FORWARD/INPUT链上的规则过滤。排查时先确认模块状态:

lsmod | grep br_netfilter

如果加载了,并且sysctl里net.bridge.bridge-nf-call-iptables是1,那么桥接流量会受iptables影响。临时验证可以把它关掉:

sudo sysctl net.bridge.bridge-nf-call-iptables=0

立刻再ping,通了就是它在捣鬼。注意这是全局变量,生产环境建议用精确的规则放行而不是直接关,因为容器方案依赖这个行为做网络隔离。

STP(生成树协议)也别忽略。如果网桥开了STP,新接入的端口要经过listening/learning状态才能转发,常见表现是“配置完桥之后前几十秒不通,过一会儿通了”,或者反过来“通了半分钟突然又不通”。实验室环境建议直接关掉:

ip link set br0 type bridge stp_state 0

端口状态同样要检查,ip link show eth0确认master是br0且状态是UP。有的发行版把网卡默认down,桥起来了端口没起来,流量就出不去。

4. 路由和ARP:直连同网段为什么还会走歪

4.1 用ip route get看客户机到底打算怎么走

防火墙和桥配置都没问题还是不通,接着怀疑路由。在虚拟机里执行:

ip route get 192.168.1.10

输出会告诉你内核认为到主机IP该走哪块网卡、源地址用哪个。同网段直连的情况下,正常输出应该类似local 192.168.1.20 dev lo src ...或via 192.168.1.10 dev eth0 src 192.168.1.20。如果它告诉你需要绕道某个网关,那就说明客户机路由表有问题。

再配合一条命令确认默认路由:

ip route show

典型错误是把客户机的默认网关指向了一个不存在或回不来的地址,导致发往主机的包明明在同一个广播域,却先被交给了网关。查ARP邻居表也能看出端倪:

ip neigh show 192.168.1.10

如果这条记录状态是FAILED或STALE,说明二层根本就没建立起邻居关系,问题在ARP层面而不是ICMP层面。这时候给客户机清一遍邻居缓存,有时能立刻恢复:

ip neigh flush all

这类问题在“主机IP是被虚拟化软件自动分配的”场景里特别容易出现,自动分配的地址可能落在另一个网段或另一张虚拟网卡上,客户机根本不在同一广播域。

4.2 IP冲突和ARP缓存:最容易被忽略的二层陷阱

同网段直连且路由正常,还有个隐藏很深的坑:IP冲突。别以为桥接环境就只有主机和虚拟机两台,如果主机挂在真实局域网里,网桥上通常会再接一个物理上行口。这个网络里一旦有别的设备也用着主机IP,虚拟机发ARP请求找主机IP时,可能收到的是那台冲突设备的应答。

这时候抓包的结果很有迷惑性:能看到虚拟机发出request,也能看到“有设备”回了reply,但回包的是错误MAC,虚拟机把所有ICMP包都发给了它,主机自然一个包都收不到。而反向“主机ping虚拟机”却正常,因为虚拟机IP没冲突。这一正一反,就把IP冲突伪装成了“桥配坏了”。

在主机上用arping可以快速验证:

sudo arping -I br0 -c 3 192.168.1.10

如果收到多个MAC的回复,说明这个IP在网络上被多台设备占用,必须先解决冲突,再谈ping通。物理局域网里最常见的冲突来源是路由器DHCP地址池和手动静态IP重叠。

5. 虚拟化平台和NetworkManager的隐藏影响

5.1 桥接模式的网卡选择和多网卡主机的坑

前面都是主机和客户机两侧的通用排查,最后回到配置源头:虚拟化平台或网络管理工具本身。桌面级虚拟化软件在配置桥接网络时,通常有一个“桥接到哪块物理网卡”的选项。很多笔记本自带有线加无线两块网卡,如果虚拟机桥接到了无线网卡,而主机IP实际配置在有线网卡上,就会出现“一半通一半不通”的状况。

判断依据很简单:打开主机的网络连接详情,看哪块物理网卡上配置了和虚拟机同网段的IP,把虚拟机的桥接目标改成那一块,再重启虚拟网络服务。无线网卡做桥接本身还受驱动和漫游影响,能不用就不用;如果一定要用,建议把无线网卡的省电模式关掉,不然流量稍微一大就掉包。

Linux主机上使用常见开源虚拟化方案时,还要分清默认NAT网桥和真正的桥接:默认那个虚拟网桥是NAT模式,虚拟机能上网但不等于桥接到了真实物理网络。要让虚拟机直连物理网段,需要单独创建一个bridge型的网络定义,把物理接口交给br0,这一步容易和默认网桥搞混。

5.2 firewalld区域策略对桥接接口的默认处置

另一个隐蔽位置是NetworkManager和firewalld的配合。用nmcli创建网桥后,新生成的br0接口如果没有显式指定防火墙区域,会被firewalld划分到默认zone(通常是public)。public区域对外部来源的流量默认拒绝,ICMP回显请求自然也被拒之门外。明明客户机就在这个桥上,主机却把它当“外部”处理,于是又出现单向不通。

把网桥接口放入trusted区域就能解决:

firewall-cmd --zone=trusted --add-interface=br0 --permanent firewall-cmd --reload

或者用nmcli把连接的zone属性直接改掉:

nmcli connection modify br0 connection.zone trusted

这个操作对桥接接口影响很大,执行完记得确认zone已生效,永久参数要跟上。这也是我在企业级Linux桌面环境配桥接时几乎每次都会做的一步,省掉了后面大量“为什么不通”的猜测时间。

我自己处理单向ping问题的一般顺序已经固定成:先在客户机和主机两侧同时抓包定位,再查主机入站防火墙,然后回头看网桥IP归属和路由ARP,最后才是怀疑虚拟化平台的桥接选项。按照这个顺序,绝大多数情况都能在半小时内搞定。最忌讳一上来就重配网桥——这种问题的原因几乎从来不在“桥”本身,而在桥之外的某一层。如果你也遇到同样现象,建议就从第一节的双向抓包开始,一步步往下排除,比凭感觉换配置靠谱得多。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进