← 网络基础学习第 30 / 55 章进阶45 分钟

模块四 · 网络层:控制平面

路由与最长前缀匹配

你见过 route print 那一大坨输出,但看不出头绪。而你的机器上有两条默认路由,凭什么其中一条赢?

本章要解决的问题:你见过 route print 那一大坨输出,但看不出头绪。
而你的机器上有两条默认路由,凭什么其中一条赢?

本章的证据来源:captures/lab_route_lookup_output.txt
(我自己的实现 vs Windows 的判定,逐条对照)和本机快照。

先从一个例子理解概念

电脑既连Wi-Fi又有虚拟接口时,同一个目标可能有多个出口。路由表是在这些条件下选择下一步的依据。

目的地与下一步:路由

路由回答“去这个地址范围,从哪个接口交给谁”。路由表是这些规则的记录,不是已经走过的路线日志。

写得更具体的范围:前缀

10.0.0.0/8和10.1.0.0/16是不同大小的地址范围。对同时匹配的普通路由,优先更长、更具体的前缀,叫最长前缀匹配。

同等候选再比较:度量

度量(metric)是比较某些同等候选路由的数值,具体组合由实现规定。它不是带宽单位,也不能跨前缀直接比较大小。

没有更具体规则时:默认路由

默认路由匹配剩余未被更具体规则选中的目的;IPv4常写0.0.0.0/0。它可以把包交给默认网关,但本地、绑定和其他策略仍要区分。

下面再用这些概念看原理、命令和结果。规范与官方资料列在本章末尾,类比只帮助理解,不代替协议规则。

路由表在说什么

一条路由就是一句话:「要去这个网段,从哪个接口、交给谁」。

本机 IPv4 路由表共 36 条(实测)。字段含义:

字段含义
DestinationPrefix目的网段,如 192.168.31.0/24
NextHop下一跳交给谁。0.0.0.0 表示「直连,不用经过路由器」
InterfaceAlias从哪个网卡出去
RouteMetric这条路由自己的度量
Protocol来源:Local(系统自动加的)/ NetMgmt(网络管理配置的)

看到 36 条不用慌。真正决策的规则只有两条。

全部规则只有两条

规则 1:在所有「目标地址落在其网段内」的路由里,选前缀最长的(最具体的)
规则 2:前缀长度相同时,选有效度量最小的
        有效度量 = 路由度量 + 接口度量

顺序绝对不能颠倒。这是本章最重要的一句话, 4.4 节有一个绝妙的实测证据来证明它。

实测:15 个目标,逐条对照

我写了个脚本(labs/lab_route_lookup.py), 用 Python 自己实现一遍上面两条规则,再调用 Windows 的 Find-NetRoute 问同一个问题,然后对照。结果:

目标地址我算出的命中路由接口Windows 判定一致?
192.168.31.1192.168.31.0/24WLANWLAN✔
192.168.31.51192.168.31.0/24WLANWLAN✔
192.168.31.215192.168.31.215/32WLANWLAN✔
192.168.31.255192.168.31.255/32WLANWLAN✔
198.18.0.2198.18.0.0/30FlClashFlClash✔
198.18.0.1198.18.0.1/32FlClashFlClash✔
198.18.0.3198.18.0.3/32FlClashFlClash✔
198.18.0.2050.0.0.0/0FlClashFlClash✔
1.1.1.10.0.0.0/0FlClashFlClash✔
8.8.8.80.0.0.0/0FlClashFlClash✔
127.0.0.1127.0.0.1/32LoopbackLoopback✔
127.0.0.2127.0.0.0/8LoopbackLoopback✔
172.30.14.213172.30.0.0/20WSLWSL✔
224.0.0.251224.0.0.0/4FlClash*查询失败*—
255.255.255.255255.255.255.255/32FlClashFlClash✔

14/15 完全一致,剩下一个是多播地址 —— Find-NetRoute 对多播查不了, 这是它自身的局限(多播要按接口分别处理,见 4.8 节),不是规则算错了。

逐个看几个典型

去局域网里的另一台设备:

目标 192.168.31.51 (局域网内另一台设备)
  命中的路由 3 条,按优先级排列:
    ← 选中 192.168.31.0/24    接口=WLAN     下一跳=0.0.0.0       路由度量=256  接口度量=30   有效=286
           0.0.0.0/0         接口=FlClash  下一跳=198.18.0.2    路由度量=0    接口度量=0    有效=0
           0.0.0.0/0         接口=WLAN     下一跳=192.168.31.1  路由度量=0    接口度量=30   有效=30

下一跳是 0.0.0.0 → 直连,不经过任何路由器, 自己用 ARP 找到对方的 MAC 直接发帧(4.6 节详述)。

去本机自己的地址:

目标 192.168.31.215 (本机 WLAN 地址)
  命中的路由 4 条
    ← 选中 192.168.31.215/32   接口=WLAN   下一跳=0.0.0.0   有效=286
           192.168.31.0/24     接口=WLAN   下一跳=0.0.0.0   有效=286

命中的是 /32,不是 /24。两个路由的度量完全一样(都是 286), 区别只在前缀长度。/32 更具体,所以赢 —— 这就是规则 1 的体现。

去 fake-IP(《DNS 与 Fake-IP》里的那个地址):

目标 198.18.0.205 (fake-IP)
  命中的路由 2 条
    ← 选中 0.0.0.0/0   接口=FlClash   下一跳=198.18.0.2   有效=0
           0.0.0.0/0   接口=WLAN      下一跳=192.168.31.1 有效=30

只命中默认路由。为什么不是 198.18.0.0/30? 因为 /30 的范围是 198.18.0.0 ~ 198.18.0.3,装不下 .205。 所以假地址是靠默认路由进 TUN 的。

绝妙证据:度量小 ≠ 赢

看这个对比,这是证明「前缀长度优先」最有力的数据:

去 192.168.31.1(局域网网关):

  192.168.31.0/24    接口=WLAN     有效度量 = 286     ← Windows 选了这个
  0.0.0.0/0          接口=WLAN     有效度量 = 30

/24 的有效度量是 286,默认路由只有 30。

如果规则是「度量小者赢」,那么在自己家里的局域网里访问网关, 就应该走默认路由 —— 也就是把包发给网关,好让网关再转回给自己。 这显然是荒谬的。

实测结果:Windows 选了 /24。 这就证明了:前缀长度先比,度量只在同前缀长度之间才参与比较。

两条默认路由的竞争

Windows普通IP路由选择在匹配前缀中优先更具体的路由,同等前缀通常再比较路由与接口度量组合。还需考虑地址族、源地址约束、接口状态、socket绑定及其他策略;不能说所有系统全部只有两条规则。

历史Find-NetRoute记录选择FlClash;WLAN接口度量记录为30,而FlClash接口度量字段为空。字段为空不等于数值0,也不证明代理手工设为0。 实际选择是观察,具体度量成因仍需完整输出/对象值与配置。

示例powershell
Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0'
Get-NetIPInterface -AddressFamily IPv4 | Select-Object InterfaceIndex,InterfaceAlias,InterfaceMetric,AutomaticMetric,ConnectionState
Find-NetRoute -RemoteIPAddress 1.1.1.1

低度量默认路由是一种接管流量的方式,但代理也可能通过更具体路由或过滤框架处理流量;不能断言所有代理必须赢默认路由。Microsoft 自动度量

下一跳 0.0.0.0 = 直连 + ARP

路由表里在Windows路由输出中,下一跳0.0.0.0表示on-link类处理;对普通单播邻居可以解释为 「目标就在我所连的网段里,不需要路由器,我自己找它」。

普通以太网IPv4单播邻居通常靠ARP;本机回环、广播、多播与TUN需要分别处理,不是全部靠ARP:把 IP 地址换成 MAC 地址。

为什么需要这一步:以太网帧的头部只有 MAC 地址,没有 IP 地址。 你知道对方的 IP,但要在二层把帧发出去,必须知道它的 MAC。

本机 ARP 表(实测):

Interface: 192.168.31.215 --- 0x11
  192.168.31.1          a4-39-b3-0b-ab-19     dynamic   ← 网关
  192.168.31.51         e8-51-77-27-5a-9a     dynamic
  192.168.31.248        fa-aa-ff-92-e6-3f     dynamic
  192.168.31.255        ff-ff-ff-ff-ff-ff     static    ← 广播
  224.0.0.22            01-00-5e-00-00-16     static    ← 多播
  224.0.0.251           01-00-5e-00-00-fb     static
  239.255.255.250       01-00-5e-7f-ff-fa     static

MAC 地址第一字节藏着两个开关

第0位I/G区分个体/组地址,第1位U/L区分通用/本地管理格式。FA=11111010是单播、本地管理;01=00000001是组地址、通用管理。

位值不证明地址来自硬件烧录或随机化,也不能确认具体厂商与端点身份。Hyper-V等软件同样可以使用通用管理格式。OUI信息应查IEEE登记,不能用操作系统型号倒推后再称为两个独立证据。IEEE Registration Authority

多播 MAC 的映射规则(用本机数据验证)

IPv4 多播地址映射到 MAC,规则是:01-00-5E + 组播 IP 的低 23 位。

拿本机 ARP 表里的真实条目验证,四条全部吻合:

  224.0.0.22         -> 01-00-5e-00-00-16
  224.0.0.251        -> 01-00-5e-00-00-fb
  224.0.0.252        -> 01-00-5e-00-00-fc
  239.255.255.250    -> 01-00-5e-7f-ff-fa

为什么用 01-00-5E 开头:第一个字节 01 的最低两位是 01, 表示I/G=1(组地址)、U/L=0(通用管理格式),不是本地管理。

为什么只取低 23 位(而不是全部 28 位组播地址位): 因为该映射使用固定25位,其中第四字节最高位为0;余下23位嵌入IPv4多播地址。代价是不同的多播 IP 可能映射到同一个 MAC, 这在二层是可以接受的(收到的帧再按 IP 层过滤即可)。

/32 主机路由是哪来的

路由表里有一堆 /32,看着奇怪:

192.168.31.215/32    WLAN      Local     ← 本机地址
192.168.31.255/32    WLAN      Local     ← 广播地址
198.18.0.1/32        FlClash   Local
198.18.0.3/32        FlClash   Local
127.0.0.1/32         Loopback  Local
127.255.255.255/32   Loopback  Local
255.255.255.255/32   FlClash   Local
172.30.0.1/32        WSL       Local
172.30.15.255/32     WSL       Local

规律很清楚:每个接口的本机地址、广播地址,各加一条 /32 主机路由。 Protocol 都是 Local,说明是系统自动加的。

为什么要加:以本机地址 192.168.31.215 为例, 不加以 /32 的话,去这个地址的包会命中 192.168.31.0/24 这条直连路由, 然后被发到网卡上、发给别人。加了 /32 之后,系统知道 该地址有专门的本地处理;但不能由删除某条显示路由的设想保证报文一定发到别人,实际本地地址处理取决于协议栈。

多播和广播为什么各有 13 条路由

224.0.0.0/4        接口=FlClash / 以太网 / 本地连接* 9 / 本地连接* 10 / ...
255.255.255.255/32 接口=FlClash / 以太网 / 本地连接* 9 / 本地连接* 10 / ...

每个接口一条,本机有 13 个接口,所以各 13 条。

为什么不像单播那样只留一条:多播/广播的语义是「发给一组接收者」, 而每个接口连接的是不同的二层网络。要在哪个网络上发多播, 取决于你的目标多播组有哪些成员在哪个网段 —— 所以系统为每个接口都留一条, 由具体应用指定走哪个接口。

这也解释了为什么 Find-NetRoute 查多播地址会失败: 多播的出口不是唯一确定的,得由应用层来指定,不是一个能"算出来"的答案。

排错命令速查

示例powershell
# 看完整路由表(传统命令,输出较长但通用)
route print

# 结构化查询(可过滤)
Get-NetRoute -AddressFamily IPv4 | Sort-Object DestinationPrefix

# 【最好用】直接问:去某个地址实际走哪条路?
Find-NetRoute -RemoteIPAddress 1.1.1.1

# 只有默认路由
Get-NetRoute -DestinationPrefix '0.0.0.0/0'

# 接口度量(多网卡优先级问题必查)
Get-NetIPInterface -AddressFamily IPv4 | Sort-Object InterfaceMetric

# 看 ARP 表
arp -a

# 清 ARP 缓存(怀疑 MAC 对不上时)
netsh interface ip delete arpcache

# 测试连通性(比 ping 信息更全,能看到走的哪个源地址)
Test-NetConnection 1.1.1.1 -Port 443 -InformationLevel Detailed

# 看路径(每一跳)
tracert 1.1.1.1

Find-NetRoute 是最好用的一个,它直接告诉你「实际会选哪条路由、 用哪个源地址」,不用你自己在 36 条里找。

本章小结

结论状态
此例的普通IPv4选路以最长前缀和有效度量为主,不能排除绑定/策略等条件教学范围
我自己的实现和 Windows 判定 14/15 一致实测
/24 度量 286 打败 /0 度量 30,证明前缀长度优先于度量实测
两条默认路由靠接口度量分胜负,FlClash 胜出实测
历史选路结果为FlClash,空字段不证明接口度量0或手工设置原因观察与限制
下一跳0.0.0.0需区分普通邻居、本机、广播/多播和TUN,不一律使用ARP实现范围
本机链路层单播要 ARP,多播/广播有固定映射实测
多播 MAC = 01-00-5E + 组播 IP 低 23 位实测(4 条全部吻合)
MAC 第一字节的 U/L 位可识别随机 MAC实测(fa-... 为本地管理)
每个接口的自身地址与广播地址各有一条 /32 主机路由实测
多播/广播每个接口一条路由,出口由应用指定实测 + 原理
00-15-5D 属于 Microsoft/Hyper-V判断(未查 OUI 库)

自测题

5 题 · 先自己答,再展开对照

  1. 路由表里有 10.0.0.0/8(度量 100)和 10.1.0.0/16(度量 5000)两条。去 10.1.2.3 走哪条?为什么?
    走 10.1.0.0/16。因为它的前缀更长(16 > 8),更具体。
    度量 5000 在这里完全不参与比较 —— 度量只在两条路由前缀长度相同时才比。
    这正是 4.4 节实测证明的规则。
  2. 一台机器有两条 0.0.0.0/0 路由,度量完全相同。会发生什么?
    先确认所比较的是路由度量还是有效度量,还需考虑源地址、绑定、接口状态和实现的同等候选选择;不要猜接口序号等固定规则。用实际选路和流量观察确认。
  3. 为什么每个接口的本机地址都需要一条 /32 路由?
    Windows为本地地址提供相应路由与本地交付处理;不能由这条显示记录反推删除后报文必然绕网关,更不能把它当成所有协议栈都需要同样记录的标准。
  4. Find-NetRoute -RemoteIPAddress 224.0.0.251 查不出结果。这算 bug 吗?
    不算 bug。 多播的出口不是唯一确定的:
    224.0.0.0/4 有 13 条路由(每个接口一条),走哪条取决于
    哪个网段上有该多播组的成员,这需要应用层指定接口。
    所以没有一个"算出来"的答案,Find-NetRoute 也就无法给出唯一结果。
  5. ARP 表里出现了一个第一字节是 02 的 MAC。这说明什么?
    02的I/G=0、U/L=1,表示单播且本地管理;可能随机化、人工配置或虚拟接口,不能从位值确定生成方式、厂商或安全性。

参考资料与适用范围

修订核对日期:2026-10-13。规则按所列协议与实现范围理解;文中的原始命令输出是历史观察,不表示本次重新实测。跨版本、代理/隧道及不同捕获位置需要另行核对。

正文源自 m4-01-路由与最长前缀匹配.md · 共 13 节 · 5 道自测题