前言
上一篇文章停在了这里:
HTTP Request
↓
TCP Segment
↓
IP Datagram
此时 IP Header 中已经写入了目标地址:
203.0.113.20
但问题并没有结束。
本机可能只有一张网卡:
192.168.1.10/24
目标服务器却远在另一个网络。
于是新的问题出现了:
操作系统怎样判断目标是否与本机处于同一网络?
子网掩码究竟算出了什么?
路由表中的
default、via和dev分别代表什么?
多条路由都能匹配时,应该选择哪一条?
最终目标是服务器,为什么数据先发给网关?
已经知道下一跳 IP,为什么还需要 MAC 地址?
ARP 为什么不能查询远端服务器的 MAC?
数据每经过一台路由器,哪些 Header 会变化?
源 IP 和源端口会不会永远保持不变?
traceroute 为什么能够看到路径中的路由器?
原资料从 IP、掩码、路由表一路讲到下一跳、ARP 和分层封装,这部分本身就构成了一条完整主线。
整个过程可以先概括为:
目标 IP
↓
路由规则
↓
出口网卡
↓
下一跳 IP
↓
邻居表 / ARP
↓
下一跳 MAC
↓
链路层发送
一、地址包含前缀
假设本机地址是:
192.168.1.10/24
其中:
192.168.1.10
IP 地址
/24
网络前缀长度
/24 表示前 24 位用于描述网络前缀。
对应掩码:
255.255.255.0
二进制:
11111111.11111111.11111111.00000000
可以粗略理解为:
前 24 位
网络部分
后 8 位
当前网络内的地址部分
原资料将掩码描述为通过按位与计算网络号,这个理解适合入门。
二、判断是否直连
假设本机为:
192.168.1.10/24
目标一
192.168.1.20
按掩码计算:
192.168.1.10
AND
255.255.255.0
=
192.168.1.0
目标地址:
192.168.1.20
AND
255.255.255.0
=
192.168.1.0
前缀相同,可以通过直连网络到达。
目标二
203.0.113.20
计算得到:
203.0.113.0
与本地:
192.168.1.0
不同,因此不能直接在本地链路中交付。
RFC 1122 对主机出站路由的描述是:如果目标位于直连网络,就直接发送给目标;否则应发送给当前连接网络上的网关。
不过,现代 Linux 的实际决策不只是做一次掩码比较。
它还可能考虑:
多个路由表
策略路由
源地址
流量标记
VRF
接口状态
路由优先级
所以最终结果应以路由查询为准。
三、读取路由表
Linux 可以执行:
ip route show
示例:
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0
10.10.0.0/16 via 192.168.1.254 dev eth0
直连路由
192.168.1.0/24 dev eth0
表示:
目标属于 192.168.1.0/24
↓
从 eth0 发出
↓
目标自身位于当前链路
指定网关
10.10.0.0/16 via 192.168.1.254 dev eth0
表示:
目标属于 10.10.0.0/16
↓
从 eth0 发出
↓
先交给 192.168.1.254
默认路由
default via 192.168.1.1 dev eth0
default 等价于 IPv4 的:
0.0.0.0/0
表示没有更具体规则时,使用这条路径。Linux ip route 文档也把 default 定义为 IPv4 的 0/0 或 IPv6 的 ::/0。
四、不是从上往下找
假设同时存在:
10.0.0.0/8
10.10.0.0/16
10.10.20.0/24
目标地址:
10.10.20.8
三条规则都能匹配。
系统应该选:
10.10.20.0/24
因为它的前缀最长、范围最具体。
这叫:
Longest Prefix Match
最长前缀匹配
RFC 1812 对最长匹配给出的典型示例也是:当 /24、/16 和 /8 同时匹配时,保留最长的 /24 路由。
所以不能简单理解为:
路由表从第一行向下扫描
找到一条能匹配的就结束
实际路由查找还会综合:
前缀长度
metric
策略规则
表优先级
下一跳状态
五、查询实际结果
比起只看整张路由表,更直接的命令是:
ip route get 203.0.113.20
示例输出:
203.0.113.20 via 192.168.1.1 dev eth0
src 192.168.1.10
可以读成:
最终目标:
203.0.113.20
下一跳:
192.168.1.1
出口接口:
eth0
本次源地址:
192.168.1.10
ip route get 会执行一次实际的路由解析,并按照内核看到的方式返回结果;它不同于单纯列出已有路由条目的 ip route show。
对于复杂环境,还可以查询:
ip route get 203.0.113.20 \
from 192.168.1.10
甚至加入:
源端口
目标端口
协议
fwmark
VRF
六、目标不是网关
这是整篇文章最重要的区别。
假设:
客户端:
192.168.1.10
网关:
192.168.1.1
服务器:
203.0.113.20
IP Header 中写入的目标地址仍然是:
203.0.113.20
不是:
192.168.1.1
网关只是:
当前这一跳的接收者
而服务器才是:
IP 数据报的最终目标
因此:
最终目标 IP:
203.0.113.20
当前下一跳 IP:
192.168.1.1
路由器收到数据后,会读取最终目标 IP,再查询自己的路由表:
客户端
↓
家庭网关
↓
运营商接入路由器
↓
城域网路由器
↓
骨干网路由器
↓
目标机房
每台设备只需要知道:
下一步交给谁
这就是逐跳转发。
七、为什么还要 MAC?
路由查询已经得到:
下一跳 IP = 192.168.1.1
但在常见 Ethernet 局域网中,网卡发送 Frame 时需要链路层地址。
因此主机还要完成:
下一跳 IPv4 地址
↓
ARP
↓
下一跳 MAC 地址
ARP 的目的就是把协议地址映射为 Ethernet 等链路所需的硬件地址。
先查看邻居表:
ip neigh show
示例:
192.168.1.1 dev eth0
lladdr 00:11:22:33:44:55
REACHABLE
Linux ip neighbour 管理协议地址和链路层地址之间的绑定;IPv4 的邻居表也就是通常所说的 ARP 表。
八、ARP 怎样工作?
如果邻居表中没有下一跳 MAC,主机会在本地链路广播 ARP Request:
谁拥有 192.168.1.1?
请告诉 192.168.1.10。
网关返回:
192.168.1.1
对应
00:11:22:33:44:55
主机缓存这条映射,然后构造链路层 Frame。
同一网络
目标:
192.168.1.20
查询:
192.168.1.20 的 MAC
远端网络
目标:
203.0.113.20
查询:
192.168.1.1 网关的 MAC
不会查询:
203.0.113.20 的 MAC
因为远端服务器不在当前广播域内,普通 ARP 请求不会穿越路由器传播到整个互联网。
九、Frame 怎样构造?
客户端第一次发向网关时,可以抽象为:
┌──────────────────────────────────────┐
│ Ethernet Header │
│ 源 MAC:客户端 │
│ 目标 MAC:网关 │
├──────────────────────────────────────┤
│ IP Header │
│ 源 IP:客户端 │
│ 目标 IP:最终服务器 │
├──────────────────────────────────────┤
│ TCP Header │
│ 源端口:客户端临时端口 │
│ 目标端口:80 │
├──────────────────────────────────────┤
│ HTTP Request │
└──────────────────────────────────────┘
注意两组地址的职责:
MAC
描述当前这一跳
IP
描述端到端目标
因此第一跳中:
目标 MAC
是网关
目标 IP
是远端服务器
十、每跳都重新封装
假设路径为:
客户端
↓
路由器 A
↓
路由器 B
↓
服务器
路由器 A 收到 Frame 后:
移除当前链路层 Header
↓
读取目标 IP
↓
查询自己的路由表
↓
找到下一跳
↓
构造新的链路层 Header
因此 MAC 地址通常逐跳变化:
第一跳
源 MAC:客户端
目标 MAC:路由器 A
第二跳
源 MAC:路由器 A 的出口
目标 MAC:路由器 B
第三跳
源 MAC:路由器 B 的出口
目标 MAC:服务器
在普通、无地址转换的 IP 路由中:
源 IP
目标 IP
TCP 源端口
TCP 目标端口
通常保持端到端不变。
但链路层 Header 会适应当前链路重新构造。
十一、TTL 防止死循环
IP Header 中还有一个重要字段:
TTL
Time To Live
IPv4 路由器转发数据报时会递减 TTL。TTL 归零时,数据报会被丢弃,并通常返回 ICMP Time Exceeded。
例如:
客户端发出:
TTL = 64
经过路由器 A:
TTL = 63
经过路由器 B:
TTL = 62
TTL 的作用之一是防止错误路由形成无限循环:
路由器 A → B → C → A → B → C……
如果没有 TTL,这类数据包可能长期占用网络资源。
十二、traceroute 怎么看路径?
传统 traceroute 的思路是逐步增加 TTL:
第一次:
TTL = 1
第二次:
TTL = 2
第三次:
TTL = 3
当 TTL 在某一跳归零时,该设备可能返回 ICMP Time Exceeded。
于是客户端逐步记录:
第 1 跳是谁
第 2 跳是谁
第 3 跳是谁
传统 traceroute 正是利用 TTL 到期和 ICMP Time Exceeded 来推测路径中的节点。
不过 traceroute 展示的不是一条永远固定的完整路线。
现实中可能存在:
负载均衡路由
异步路径
ICMP 被过滤
MPLS
隧道
设备不响应探测
因此某些跳可能显示:
*
*
*
并不一定代表实际没有经过设备。
十三、IP 也可能变化
很多入门图会写:
IP 和端口全程不变
MAC 每跳变化
这只适用于没有地址转换的普通路由场景。
经过 NAT 或 NAPT 时,中间设备可以改写:
源 IP
目标 IP
源端口
目标端口
传统 NAT 可以转换 IP 地址,NAPT 还会转换 TCP 或 UDP 端口。
例如家庭网络:
内网请求:
192.168.1.10:51000
→
203.0.113.20:80
经过路由器后可能变成:
公网请求:
198.51.100.8:62001
→
203.0.113.20:80
因此更准确的说法是:
普通路由主要保持端点 IP 和端口;NAT、代理、隧道和负载均衡设备可能改写地址或重新封装数据。
十四、默认网关不唯一
原资料把默认网关描述为唯一条目,这适合最简单的单网卡主机,但并不是通用规则。
一台 Linux 主机可以拥有:
多张网卡
多个默认路由
不同 metric
多个路由表
策略路由
等价多路径
例如:
default via 192.168.1.1
dev eth0
metric 100
default via 10.0.0.1
dev eth1
metric 200
通常较低 metric 的路由优先,但实际决策还可能受到策略规则影响。Linux 也支持多个路由表,策略路由会让不同流量进入不同表。
十五、动手实验
查看地址
ip addr show
查看路由表
ip route show
查询目标路径
ip route get 8.8.8.8
查看邻居表
ip neigh show
清除某个邻居项
sudo ip neigh del \
192.168.1.1 \
dev eth0
抓取 ARP
sudo tcpdump -ni eth0 arp
随后访问外网:
ping -c 1 8.8.8.8
如果网关映射尚未缓存,就可能先看到 ARP:
Who has 192.168.1.1?
Tell 192.168.1.10
然后才看到 IP 数据包发出。
十六、(扩展)换成 5G,请求路径变了吗?
传统有线网络:
电脑
↓
网线或 Wi-Fi
↓
家庭路由器
↓
运营商网络
↓
互联网
5G 网络:
手机
↓
5G 无线链路
↓
基站
↓
运营商承载网与核心网
↓
互联网
重点说明四件事:
第一,5G 主要改变接入段。
它改变的是终端连接运营商网络的方式:
网线 / Wi-Fi
变成:
无线空口
↓
5G 基站
但进入运营商网络后,请求仍然要经过:
IP 路由
下一跳选择
骨干网络
目标机房
第二,5G 不会让路由消失。
即使接入速度更快,数据仍然需要:
终端
↓
基站
↓
运营商核心网
↓
多个路由节点
↓
目标服务器
所以 5G 提升的是部分链路的带宽、接入能力和时延表现,不是让数据“直接飞到服务器”。
第三,5G 接入不适合继续套用简单 ARP 图。
第二篇前半部分主要使用:
IPv4 + Ethernet + ARP
解释家庭或局域网环境。
而蜂窝网络内部使用的无线接入、隧道和运营商承载机制更加复杂,不能简单理解为:
手机通过 ARP 查询基站 MAC
因此扩展段应强调:
ARP 示例适用于常见 IPv4 Ethernet 局域网;进入 5G 蜂窝接入后,链路层与接入网机制会发生变化,但 IP 数据仍需要经过运营商网络继续路由。
第四,5G 不等于端到端低延迟。
完整延迟来自:
无线接入延迟
+
运营商网络延迟
+
公网路由延迟
+
服务器排队与处理延迟
+
数据库和下游服务延迟
即使无线接入部分变快,如果服务器部署得很远:
中国终端
↓
跨洋网络
↓
美国服务器
物理距离和中间网络仍然会产生延迟。
十七、常见误区
1. 掩码只用于计算本机网络
不完整。
网络前缀是路由匹配和地址规划的核心信息。
2. 路由表按显示顺序匹配
错误。
路由选择首先强调最长前缀匹配。
3. 网关就是最终目标
错误。
网关是当前下一跳,目标 IP 仍然是最终服务器。
4. 远端服务器的 MAC 会写入客户端 Frame
错误。
客户端通常只需要获得当前下一跳的链路层地址。
5. ARP 可以查询全网 MAC
错误。
ARP 面向当前 IPv4 链路,不会作为普通广播跨越整个互联网。
6. MAC 地址从客户端一直保持到服务器
错误。
路由器转发时通常重新封装链路层 Header。
7. IP 地址和端口永远不变
错误。
NAT、NAPT、代理或某些负载均衡器可能改写它们。
8. 只要有默认路由就一定能通信
错误。
仍可能遇到:
邻居解析失败
网关不可达
防火墙拦截
上游没有路由
目标未监听
9. traceroute 是服务器返回的完整路径
错误。
它是通过 TTL 和可能返回的 ICMP 消息逐步推测路径。
总结
目标 IP 已知后,主机首先进行路由决策:
目标 IP
↓
路由表
↓
最长前缀匹配
路由结果会给出:
出口网卡
源地址
下一跳
目标位于直连网络时:
下一跳
=
最终目标
目标位于远端网络时:
下一跳
=
网关
在 IPv4 Ethernet 环境中,还要解析下一跳的 MAC:
下一跳 IP
↓
邻居表
↓
ARP
↓
下一跳 MAC
链路层 Frame 中:
目标 MAC
当前下一跳
目标 IP
最终服务器
数据每经过一台路由器:
旧链路层 Header 被移除
↓
查询新的下一跳
↓
构造新的链路层 Header
MAC 地址通常逐跳变化,TTL 逐跳递减;普通路由中端点 IP 通常保持不变,但 NAT、代理等设备可能改写地址或端口。
最后,可以用一句话概括本文:
路由表决定当前应该把数据交给谁,ARP 负责找到这个下一跳在本地链路上的地址,而最终目标 IP 会继续留在数据包中,指导后续路由器完成一跳又一跳的转发。
评论区