📚 第二章 TCP/IP基础知识
📄 一句话概括

包要交给下一跳,就得把「下一跳的 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 秒实验

  1. 算一下 224.0.0.22 映射到哪个 MAC,然后和表里对一下。
  2. 用 ping 一个本网段的陌生地址,再看 ARP 表有没有多一行。
  3. 想一下:ARP 欺骗为什么能成功?有没有办法防?

常见误区

  1. 以为跨网段时帧头填的是目标机器的 MAC。 填的是网关的 MAC,链路层只管一跳。
  2. 以为 ARP 表是永久的。 它有老化时间,设备换网卡或换 IP 之后旧表项会失效。
  3. 以为组播 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 检测。

最后一节:接收端怎么处理。

相关笔记