以太网帧与ARP:帧结构、ARP协议原理与源码解析

核心原理:以太网帧的封装与寻址基础

在TCP/IP协议栈中,网络接口层(即链路层)负责将IP数据报封装为能够在物理链路上传输的帧。以太网帧是最常见的链路层帧格式,其标准结构(IEEE 802.3 / Ethernet II)由前导码、帧起始定界符(SFD)、目的MAC地址、源MAC地址、类型/长度字段、数据载荷和帧校验序列(FCS)组成。其中,前导码与SFD属于物理层同步信息,真正被驱动与协议栈处理的帧体从目的MAC地址开始。

MAC地址是链路层寻址的核心,长度为48位(6字节),通常以十六进制冒号分隔表示,例如 00:1a:2b:3c:4d:5e。以太网帧中的类型字段(EtherType)用于标识上层协议:0x0800表示IPv4,0x0806表示ARP,0x86DD表示IPv6。当帧携带ARP报文时,数据载荷部分不再是IP数据报,而是完整的ARP协议消息。

理解帧结构的关键在于:MAC地址解决“同一广播域内下一跳是谁”的问题,而IP地址解决“端到端目标在哪里”的问题。这两种地址的映射关系,正是ARP协议存在的根本原因。

Ethernet II 帧结构速览(不含前导码与SFD)

字段长度(字节)说明
目的MAC地址6接收方网卡地址,可为单播、多播或广播
源MAC地址6发送方网卡地址
类型(EtherType)20x0806表示ARP,0x0800表示IPv4
数据载荷46~1500ARP报文或IP数据报,不足46字节需填充
FCS(帧校验序列)4CRC32校验,覆盖从目的MAC到载荷末尾
Ethernet II 帧结构(不含前导码) 目的MAC 6字节 源MAC 6字节 类型 2字节 数据载荷(ARP报文 / IP数据报) 46 ~ 1500 字节 FCS 4字节 0x0806 → ARP 0x0800 → IPv4 ARP 报文结构(封装在以太网帧的数据载荷中) 硬件类型 1: 以太网 协议类型 0x0800: IPv4 HLEN 6 PLEN 4 操作码 1请求/2应答 发送方MAC 6字节 发送方IP 4字节 目标MAC 6字节 目标IP 4字节 操作码:1 = ARP请求(广播),2 = ARP应答(单播) 请求时目标MAC填 00:00:00:00:00:00,目的MAC地址为广播 FF:FF:FF:FF:FF:FF 帧类型 = 0x0806 → 数据载荷为ARP报文 帧类型 = 0x0800 → 数据载荷为IP数据报

ARP协议原理:地址解析的工作机制

ARP(Address Resolution Protocol)用于在IPv4环境下,根据目标IP地址获取同一链路(广播域)上对应网卡的MAC地址。其核心流程可概括为请求广播、应答单播。当主机A需要向主机B发送IP数据报时,A首先检查自身的ARP缓存表;若未找到B的IP对应的MAC条目,则构造一个ARP请求报文,将发送方MAC与IP填入对应字段,目标IP填B的IP,目标MAC填全零,然后封装在以太网帧中,目的MAC地址设为广播地址 FF:FF:FF:FF:FF:FF,在本地网络中广播。

网段内所有主机都会收到该广播帧,但只有IP地址与请求中目标IP一致的主机B会处理此请求。B收到后,先将A的IP与MAC映射写入自己的ARP缓存(因为B后续大概率需要回包给A),然后构造ARP应答报文,将自己的MAC填入发送方MAC字段,目标MAC填A的MAC,单播发送给A。A收到应答后,将B的IP-MAC映射写入缓存,随后即可正常封装并发送IP数据报。

ARP缓存表项通常具有老化时间(Linux默认约60秒,Windows约120秒),超时后条目被删除,再次通信需重新解析。此外,ARP协议仅适用于IPv4;IPv6使用ICMPv6的邻居发现协议(NDP)完成类似功能。

方法流程:ARP请求与应答的完整交互

以下以一个具体场景说明:主机A(IP: 192.168.1.10,MAC: AA:AA:AA:AA:AA:AA)首次向主机B(IP: 192.168.1.20,MAC: BB:BB:BB:BB:BB:BB)发送数据。A的ARP缓存为空。

  1. 构造ARP请求:A填充发送方MAC=AA:AA:AA:AA:AA:AA,发送方IP=192.168.1.10,目标IP=192.168.1.20,目标MAC=00:00:00:00:00:00,操作码=1。
  2. 封装并广播:以太网帧目的MAC=FF:FF:FF:FF:FF:FF,源MAC=AA:AA:AA:AA:AA:AA,类型=0x0806,帧载荷为上述ARP报文。
  3. B接收并处理:B检查目标IP与自己匹配,将A的IP-MAC映射写入缓存,然后构造ARP应答(操作码=2),发送方MAC=BB:BB:BB:BB:BB:BB,目标MAC=AA:AA:AA:AA:AA:AA。
  4. A接收应答:A将B的IP-MAC映射写入缓存,随后用B的MAC作为目的MAC封装IP数据报并发送。

抓包验证技巧:使用Wireshark捕获ARP流量时,可设置过滤表达式 arp 或 ether proto 0x0806。观察请求帧的目的MAC是否为广播地址,应答帧的目的MAC是否为请求方的单播地址。通过对比操作码字段(1=请求,2=应答)可快速判断报文类型。

源码解析:Linux内核ARP核心处理逻辑

Linux内核中,ARP协议的核心实现位于 net/ipv4/arp.c。关键函数包括 arp_process()(处理收到的ARP报文)和 arp_send()(构造并发送ARP报文)。以下为 arp_process() 中处理ARP请求的核心逻辑片段(简化版):

// 内核源码示意:arp_process() 处理ARP请求
static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    struct arphdr *arp = arp_hdr(skb);
    unsigned char *arp_ptr = (unsigned char *)(arp + 1);
    struct net_device *dev = skb->dev;
    // 提取发送方MAC、发送方IP、目标MAC、目标IP
    unsigned char *sha = arp_ptr;
    arp_ptr += dev->addr_len;              // 跳过发送方MAC
    __be32 sip = *(__be32 *)arp_ptr;       // 发送方IP
    arp_ptr += 4;
    unsigned char *tha = arp_ptr;          // 目标MAC
    arp_ptr += dev->addr_len;
    __be32 tip = *(__be32 *)arp_ptr;       // 目标IP

    // 判断是否为ARP请求(操作码=1)
    if (arp->ar_op == htons(ARPOP_REQUEST)) {
        // 检查目标IP是否为本机地址
        if (tip == inet_addr(dev->dev_addr)) {
            // 更新ARP缓存:记录发送方的IP-MAC映射
            __neigh_lookup(&arp_tbl, &sip, dev, 1);
            // 构造ARP应答并发送
            arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, sha,
                     sha, sip, tha, tip);
        }
    }
    return 0;
}

上述代码展示了三个关键点:地址提取顺序严格遵循ARP报文格式;目标IP匹配决定是否应答;缓存更新在应答前完成,确保后续通信可直接使用。实际内核代码还包含代理ARP、 gratuitous ARP(免费ARP)、冲突检测等复杂逻辑,但核心流程与此一致。

案例与场景:真实网络中的ARP行为

场景一:同一交换机下的两台主机首次通信。主机A ping 主机B,A广播ARP请求,B应答,随后A发送ICMP Echo Request。整个过程可通过抓包看到4个报文:ARP请求(广播)、ARP应答(单播)、ICMP请求、ICMP应答。

场景二:ARP缓存老化后的重解析。若A与B在缓存老化时间内未通信,再次通信时A会重新发起ARP请求。这解释了为何长时间静默后首次ping延迟较高。

场景三:ARP欺骗攻击。攻击者C向A发送伪造的ARP应答,声称自己是B(即发送方IP=192.168.1.20,MAC=C的MAC)。A更新缓存后,发往B的数据实际被C截获。防御措施包括静态ARP表、DAI(动态ARP检测)等。

常见误区与排障要点:

  • 误区1:认为ARP请求是单播。实际上ARP请求必须广播,因为目标MAC未知。
  • 误区2:混淆ARP应答与免费ARP。免费ARP(Gratuitous ARP)是主机主动广播自己的IP-MAC映射,用于地址冲突检测或网关冗余切换,并非对请求的应答。
  • 排障提示:若ping不通但ARP缓存中已有目标条目,可执行 arp -d(Linux)或 arp -d *(Windows)删除缓存后重试,排除缓存脏数据问题。

误区与复盘:ARP协议理解中的常见偏差

学习ARP时,一个典型误区是认为“ARP请求会跨路由器传播”。实际上,ARP请求永远只在同一广播域内传播,路由器不会转发ARP广播帧。当主机访问不同网段的目标时,它先将数据报发送给默认网关(路由器接口),由网关负责下一跳的ARP解析。因此,ARP解析的是下一跳设备的MAC地址,而非最终目的主机的MAC地址(除非目标就在同一网段)。

另一个易混淆点是ARP报文长度。ARP报文固定为28字节(以太网+IPv4场景),但以太网帧最小载荷为46字节,因此ARP报文封装后需填充至46字节。抓包时看到的ARP帧总长度为42字节(14字节帧头+28字节ARP),但实际线上传输会补齐到64字节(含前导码与FCS)。理解这一点有助于正确解读抓包文件中的帧长度字段。

复盘实际排障案例:某次网络中断,主机无法访问网关。抓包发现主机持续发送ARP请求但无应答。排查发现网关接口所在VLAN配置错误,导致广播帧未到达网关。这提醒我们:ARP请求无应答时,问题往往不在主机本身,而在链路、VLAN或网关接口状态。此时应检查交换机端口VLAN划分、网关接口是否up、以及是否存在ACL阻断广播。