包要交给下一跳,就得把「下一跳的 IP」翻成「下一跳的 MAC」,这件事靠 ARP。 IP 组播映射到 MAC 组播是固定规则:取低 23 位,前面补 01-00-5e。
2.5.2 讲的是「加头」,这一节讲「头里的地址从哪来」。 这一节会读本机的 ARP 表,那是「IP 到 MAC」映射的真实样本。
一、下一跳是谁
跨网段时,帧头的目的 MAC 填的不是最终目标:
| 情形 | 帧头目的 MAC | 原因 | |---|---| | 同网段 | 目标的 MAC | 直接交付 | | 跨网段 | 网关的 MAC | 链路层只管一跳 |
第二行是很多人第一次抓包时看错的地方: 你要访问 8.8.8.8,帧头的目的 MAC 却是你家路由器—— 因为链路层只负责「把它交给下一个能转发的人」。 至于最终去哪,那是 IP 头里的事。 所以「一次传输里 MAC 换了很多次,IP 只变了一次(NAT)」: MAC 是「这一跳」的地址,IP 是「两端」的地址。 理解这一点,就不会把「帧」和「包」混为一谈。
二、ARP 表长什么样
本机读出来的样本:
| IP 地址 | MAC 地址 | 类型 |
|---|---|---|
| 192.168.3.1 | b0-fe-e5-54-e9-3f |
动态 |
| 192.168.3.74 | 4c-b7-e0-34-60-6c |
动态 |
| 192.168.3.147 | 58-cd-c9-df-80-6e |
动态 |
| 192.168.3.255 | ff-ff-ff-ff-ff-ff |
静态 |
| 224.0.0.251 | 01-00-5e-00-00-fb |
静态 |
第一行那个通常是网关:它既是「本网段第一跳」,也是「广播域边界」。
你的包发给外网时,帧头的目的 MAC 填的就是它。
第四行那个 ff-ff-ff-ff-ff-ff 是广播地址:全 F 表示「本网段所有设备都收」。
它一定是静态的,因为它不是学来的。
第五行那个是组播映射:224.0.0.251 对应 01-00-5e-00-00-fb,
这不是随便给的,是固定规则:取 IP 的低 23 位,前面补 01-00-5e。
所以 239.255.255.250 会映射成 01-00-5e-7f-ff-fa。
这个规则有个副作用:IP 组播地址有 28 位可用,MAC 只有 23 位,
所以 32 个不同的 IP 组播地址会映射到同一个 MAC。
接收端还得再按 IP 过滤一次——这就是「组播接收要两次过滤」的原因。
三、ARP 是怎么工作的
四步,全在本网段内:
| 步骤 | 动作 | 范围 |
|---|---|---|
| 1 | 广播问「谁是 X」 | 全段 |
| 2 | 目标单播回答 | 只有它回 |
| 3 | 写进 ARP 表 | 本机 |
| 4 | 有老化时间 | 几分钟后失效 |
第一行那个「广播问」是 ARP 的本质:它是一问一答的「地址翻译」协议, 没有 ARP,IP 包根本发不出去——因为网卡只认 MAC。 第四行那个「老化」很重要:设备换了网卡、换了 IP,旧表项要能失效。 所以 ARP 表不是永久的,通常几分钟就过期。 ARP 有一个著名的安全问题:它没有认证,谁都可以回答「我是网关」。 这就是「ARP 欺骗」——攻击者冒充网关,把流量引到自己这儿。 防御办法是做静态绑定或启用动态 ARP 检测(DAI)。 这也是「二层没有认证」的又一个例子。
四、动手 Demo:数据链路层的包,看 ARP 表最直接
读本机的 ARP 表,看 IP 与 MAC 的对应关系。 重点看组播那几行:映射规则是固定的。
import subprocess
r = subprocess.run(['arp', '-a'], capture_output=True, timeout=10)
txt = r.stdout.decode('gbk', 'ignore')
for l in txt.split('\n'):
parts = l.split()
if len(parts) >= 3 and parts[0].count('.') == 3:
print('%-16s %-20s %s' % (parts[0], parts[1], parts[2]))
实跑输出:
--------------------------------------------------------------------
数据链路层的包,看 ARP 表最直接
--------------------------------------------------------------------
**IP 包要交给下一跳,就得知道下一跳的 MAC。**下面读本机的 ARP 表,看这个映射长什么样。
IP 地址 MAC 地址 类型
-----------------------------------------------
192.168.3.1 b0-fe-e5-54-e9-3f 动态
192.168.3.74 4c-b7-e0-34-60-6c 动态
192.168.3.147 58-cd-c9-df-80-6e 动态
192.168.3.255 ff-ff-ff-ff-ff-ff 静态
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 静态
**第一行那个通常是网关**:**它既是「本网段第一跳」,也是「广播域边界」。**
**你的包发给外网时,帧头的目的 MAC 填的是它,不是最终目标。**
**注意最后几行是组播与广播地址**:
**224.0.0.251 对应 01-00-5e-00-00-fb**——
**这不是随便给的,是「IP 组播映射到 MAC 组播」的固定规则:取 IP 的低 23 位,前面补 01-00-5e。**
**所以多个 IP 组播地址会映射到同一个 MAC**,**接收端还要再按 IP 过滤一次。**
**「动态」与「静态」的区别也要看清**:
**动态是靠 ARP 学来的(有老化时间),静态是手动配的或系统预置的(广播与组播地址都是静态)。**
第一行一般是网关:192.168.3.1 对应 b0-fe-e5-54-e9-3f,这是你家路由器的 LAN 口 MAC。
你可以拿这个地址去厂商 OUI 库里查,能查出设备品牌。
「动态」是靠 ARP 学来的(有老化时间),
「静态」是手动配的或系统预置的(广播与组播地址都是静态)。
组播那几行的映射要会算:224.0.0.251 → 低 23 位是 0x0000FB → MAC 01-00-5e-00-00-fb;
239.255.255.250 → 低 23 位是 0x7FFFFA → MAC 01-00-5e-7f-ff-fa。
规则就是「取后 23 位、前面补 01-00-5e」。
30 秒实验
- 算一下
224.0.0.22映射到哪个 MAC,然后和表里对一下。 - 用
ping一个本网段的陌生地址,再看 ARP 表有没有多一行。 - 想一下:ARP 欺骗为什么能成功?有没有办法防?
常见误区
- 以为跨网段时帧头填的是目标机器的 MAC。 填的是网关的 MAC,链路层只管一跳。
- 以为 ARP 表是永久的。 它有老化时间,设备换网卡或换 IP 之后旧表项会失效。
- 以为组播 MAC 就是「IP 地址照抄」。 只取低 23 位,所以 32 个 IP 组播会映射到同一个 MAC。
自测三问(点开对答案)
1. 跨网段时,以太网帧的目的 MAC 填谁? —— **网关的 MAC**,不是最终目标的。链路层只负责把它交给下一个能转发的人。 2. IP 组播怎么映射到 MAC 组播? —— **取 IP 的低 23 位,前面补 `01-00-5e`。**因为 IP 组播有 28 位可用、MAC 只有 23 位, 所以会多对一。 3. ARP 欺骗为什么能成功? —— **因为 ARP 没有认证**,谁都能回答「我是网关」。防御靠静态绑定或动态 ARP 检测。最后一节:接收端怎么处理。
- ☐ (本节完,下一节 2.5.4 数据包接收处理)