跳到正文

以太网、ARP 与交换机

环境:Windows 11 x64,GCC 13.1.0(MinGW-w64),自写的 mini-tcpdump 直连 Npcap(datalink=1 的真以太网口,pcap_open_live 的 promisc 参数给 1)。抓包对象是本机”以太网”(Realtek PCIe GbE,MTU 9000,1 Gbps)所在的那段局域网。所有帧字段都是从字节流里解出来的;ARP 欺骗、广播风暴这类要污染邻居表或打扰别人的实验,本节没做,理由写在最后。

一、MAC 帧与 MTU:本机三个数字

Get-NetAdapter 的实物清单(节选):

ifIndex Name                          MacAddress        LinkSpeed Status
     20 以太网                        9C-2D-CD-A8-AB-7D 1 Gbps    Up
     24  VMware Network Adapter VMnet1 00-50-56-C0-00-01 100 Mbps  Up
     26  VMware Network Adapter VMnet8 00-50-56-C0-00-08 100 Mbps  Up
     22  cfw-tap                       00-FF-BF-79-14-14 1 Gbps    Disconnected
      8  cherry                        (无 MAC)          100 Gbps  Up

两个值得记住的结论:

  • 虚拟网卡自己不发二层。cherry 那条隧道口没有 MAC、报 100 Gbps,因为它根本没有链路层,帧由 ifIndex 20 那张真网卡承担。看 ipconfig /all 找不到某张卡的物理地址时,别当成驱动坏了。
  • MAC 前 3 字节是厂商,但能不能信它取决于设备。VMware 的 00-50-56-C0-00-xx 一眼就是 VMnet1/VMnet8(OUI 属于 VMware)。本机 ARP 表里那批 10-20-30-40-xx-xx 就更直白——10-20-30-40-50-29、10-20-30-40-60-01 是明显手工填的地址,见第三节。

MTU 用 DF 标志卡边界(ping -f -l <载荷> 192.168.103.254,目标就是本机网关,一共发了 4 个包):

--- size=1472   来自 192.168.103.254 的回复: 字节=1472 时间=1ms TTL=255
--- size=8972   (通过,8972 + 20 IP + 8 ICMP = 9000,正好占满)
--- size=8973   需要拆分数据包但是设置 DF。

“需要拆分数据包但是设置 DF”这条错误是本机协议栈生成的,一个包都没上网——它是查路由表和接口 MTU 之后直接拒绝。用这个办法可以逐接口把 MTU 量出来,比看配置可靠。回环侧的对应上限是 UDP 载荷 65507(65535−28),超一个字节就返回 10040 WSAEMSGSIZE。

帧长实测分布(同一批抓包):ARP 请求 frame=42(14 头 + 28 ARP),别的机器发来的 ARP frame=60。差的 18 字节是以太网最小帧填充——42 字节不够 64(含 FCS),网卡发出去前会补零。Npcap 抓到的是本机网卡补帧之前的长度,所以自己发的短帧看起来”不合规”。看到 42 字节的以太网帧别急着怀疑抓包工具。

二、ARP 缓存:把状态机看成一个一个的真实状态

网关已解析时:

IPAddress        : 192.168.103.254
InterfaceAlias   : 以太网
LinkLayerAddress : 58-8D-09-60-97-BF
State            : Reachable

对一个不存在的地址(.99)发起一次访问,邻居表里立刻长出这条:

IPAddress        : 192.168.103.99
LinkLayerAddress : 00-00-00-00-00-00
State            : Unreachable

全零 MAC 加上 Unreachable,就是”ARP 没解析成功”的标准形状——不是路由问题,是二层就没找到人。抓包同时记录了失败过程:

[  1043318] ARP who-has ethdst=ff:ff:ff:ff:ff:ff sender 192.168.103.24 [9c:2d:cd:a8:ab:7d] target 192.168.103.77 [00:00:00:00:00:00] frame=42 wire=42
[  1043335] ARP who-has ethdst=ff:ff:ff:ff:ff:ff sender 192.168.103.24 [9c:2d:cd:a8:ab:7d] target 192.168.103.77 [00:00:00:00:00:00] frame=42 wire=42

两条一模一样的广播请求,间隔 17 微秒(Windows 的 ARP 探测是背靠背发的,不是每秒一条),之后没有任何 is-reply。同一个抓包窗口里也能看到”解析成功”的那一半:

[   24886] ARP who-has ethdst=ff:ff:ff:ff:ff:ff sender 192.168.103.18 [10:ff:e0:59:48:7e] target 192.168.103.189 [00:00:00:00:00:00] frame=60 wire=60
[ 1596975] ARP is-reply ... (同一窗口里抓到 2 条应答、6 条请求)

缓存的规模与上限:arp -a -N 192.168.103.24 在这张卡上有 69 条邻居;netsh int ipv4 show global 给的上限是”邻居缓存限制:每接口 256 项”。也就是说这张 /24 才用了容量的 27%,但一个 /16 段里乱扫是能把缓存顶到上限并开始淘汰的。

还有两条静态项值得注意:

192.168.103.255   ff-ff-ff-ff-ff-ff   静态
255.255.255.255   ff-ff-ff-ff-ff-ff   静态

Windows 自己给子网广播地址留了一条静态 ARP(不会老化)。排查广播相关问题时,这两条是正常项,不是被人种了静态表。

三、ARP 欺骗能怎么”查”,而不是怎么”演”

构造 ARP 欺骗要把假映射推进本机的邻居表、还会影响同段其他机器——这属于本专栏统一划的红线之外的事,所以本节没有做攻击实验,只给在本机能落地的检查方法:

检查项本机实测值异常判据
网关 MAC58-8D-09-60-97-BF(Get-NetNeighbor,State=Reachable)同一个 IP 的 MAC 变了;或同时出现两个候选
OUI 是否合理网关 MAC 前 3 字节 58-8D-0910-20-30-40-xx-xx 这类明显手工序列
是否广播流量异常放大12 秒抓包:ARP 8 条、255.255.255.255 4 条每秒成千条 who-has、ARP 应答比请求多
静态条目来源只有两条广播地址是静态出现别人种下的网关静态项
arp -a 条目数69(上限 256/接口)短时间内条目数暴涨

上表第二行不是假设:本机 ARP 表里确实有 4 条 10-20-30-40-* 形态的动态条目(.8 / .106 / .150 / .250)。这可能是实验室设备的静态配置,也可能是伪造源,光看 ARP 表区分不了,必须去交换机侧看 MAC 表端口、或者对比这台主机其他时间的 MAC。这正是”ARP 没有认证机制”这件事在运维层的代价。

四、交换机学习与广播域:这台机器看到了什么

标准说法是”交换机按源 MAC 学习端口,单播只发给目标端口,广播/未知单播才泛洪”。本机的实测情况有点不一样,而且这个差异本身就是有价值的信息:

12 秒、不加过滤条件、混杂模式抓到的帧分布:

总帧数 4714,其中 ARP 8 条、TCP/UDP/ICMP 4665 条
源 IP 计数:
  2726 192.168.103.24     ← 本机
  1537 120.24.46.217      ← 公网对端
   223 120.76.131.237      ← 公网对端
    38 192.168.103.200     ← 别人的机器
    17 192.168.103.18      ← 别人的机器

192.168.103.200 -> 1.12.12.12、192.168.103.18 -> ... 这类源和目的都不是本机的单播帧,本机网卡收到了。理想交换环境下这不该发生。三种解释:上联设备是共享介质(集线器/无线/AP 桥接)、端口做了镜像、或者对方流量目的地是本机所在广播域的组播/广播。结合 192.168.103.24 那张卡实际是”板载千兆但经由无线网桥”的常见形态,第一种可能性最大。结论:不要假设”我抓不到别人的单播”,先自己验一遍再下判断。

同一批帧里还看到广播域的真实尺寸:

目的为组播/广播的帧计数:
    24  -> 224.0.0.22      (VRRP)
    13  -> 239.255.255.250 (SSDP/WS-Discovery)
    11  -> 224.0.0.251     (mDNS)
     8  -> 224.0.0.252     (LLMNR)
     4  -> 255.255.255.255 (受限广播)

其中 SSDP 那些包的 IP 头是 ttl=1(本机 netsh int ipv4 show global 里”多播转发 : disabled”,MLD 版本 : version3)。TTL=1 就是组播的”只走一跳”围栏:路由器不转发,所以它出不了这个广播域,但域内每台主机都得收一遍——这就是”组播比广播省,但省在路由器和全网范围,不省在你这一段”。

另一个反直觉观察:这段线路上同时跑着 192.168.103.x 和 192.168.3.x 两个网段的主机(抓到的 ARP 里有 192.168.3.1 [ba:54:9d:84:8f:7c] who-has 192.168.3.163)。二层广播域和三层子网不是一一对应的——交换机只认 MAC,把两个子网接进同一个 VLAN 完全可能,而且这时候两边的机器彼此能收到 who-has,只是 IP 层不会互访。路由表里 192.168.103.255 On-link、224.0.0.0/4 On-link 这些条目也只按接口划分,不区分子网。

五、VLAN 与 trunk:本节明确未实测

本机无法实测 VLAN/trunk,原因:手上没有可配的交换机来做打标签/剥离对照,Npcap 在 access 端口上也看不到”标签被剥掉之后”的样子。能给的只有一条否定证据:12 秒、4714 帧里 0 个 EtherType=0x8100(802.1Q)帧,出现的是 7 个 0x86dd(IPv6)和若干个 EtherType 值小于 0x0600 的 802.3 长度字段帧。也就是说本机这张卡接的是 access 端口、untagged 链路。

概念上按标准可以记这几点(都是协议规定,非本机实测):

  • trunk 就是一条物理链路承载多个 VLAN,靠打 802.1Q 标签(在源 MAC 后插 4 字节:0x8100 + 3 位 priority + 1 位 CFI + 12 位 VID,VID 0–4094)区分。
  • 打了标签帧就多了 4 字节,最大帧长从 1518 变 1522;如果同时开 jumbo,MTU 与 MSS 都要相应调整——本机 9000 MTU 对应抓到的 MSS=8960,就是”MTU−40”;换成 trunk 承载时实际可用载荷还会再少 4 字节。
  • PVID/ native VLAN 决定未打标帧归属哪个 VLAN;VLAN 之间互通必须走三层(交换机三层模块或路由器),这也是”广播域被 VLAN 切小”的意义所在:上面第四节那种”一个口能听见 69 个邻居 + 别人家单播”的场面,划 VLAN 后会显著缩小。

六、小结

  • MTU 是可以当场量的:ping -f -l 8972 过、8973 报”需要拆分数据包但是设置 DF”(9000 MTU);回环上 UDP 载荷上限 65507,超了就是 10040。MSS = MTU − 40 在本机 9000 链路上验证为 8960。
  • ARP 的失败形状很实用:LinkLayerAddress=00-00-00-00-00-00 + State=Unreachable;who-has 会背靠背发两条(实测间隔 17µs);缓存上限本机是每接口 256 项,当前 /24 用了 69 项。
  • 192.168.103.255 和 255.255.255.255 在 ARP 表里是系统自带的静态条目,不是人为篡改。
  • 交换机学习只能验证一半:本机能收到别人的单播帧(38+17 帧来自 .200/.18),说明这段链路上”单播只发给目标端口”并不成立。默认别人家流量可见,是安全审计该有的起点,而不是相反。
  • 广播域 ≠ 子网:同一线路上同时出现 192.168.103.x 与 192.168.3.x;VRRP/mDNS/LLMNR/SSDP 这些组播 + 4 个受限广播帧是”这段链路每秒都在交广播税”的直接证据,TTL=1 把它们关在域内。
  • 未实测项:ARP 欺骗(要污染邻居表并影响同段其他机器)、VLAN/trunk 打标签(没有可配交换机,只给出”本端口无 0x8100 帧”的否定证据)。