Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 協議棧 ARP 數據包接收處理流程:arp_rcv 到 arp_process

編輯:Linux 教學

ARP 協議負責 IPv4 地址到 MAC 地址的解析。內核通過 packet_type 掛鉤在網絡設備接收路徑,入口函數 arp_rcv() 完成基本校驗後交由 arp_process() 進行核心邏輯處理(請求回應、緩存更新、代理 ARP 等)。本文基於 Linux 2.6.21 源碼完整追蹤接收流程。

一、 註冊入口


static struct packet_type arp_packet_type = {
    .type = __constant_htons(ETH_P_ARP),  // 0x0806
    .func = arp_rcv,
};
dev_add_pack(&arp_packet_type);  // arp_init() 中調用

二、 arp_rcv() 基本校驗


int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) {
    struct arphdr *arp;

    // 1. 線性化並檢查長度:ARP頭 + 2*硬件地址 + 2*協議地址
    if (!pskb_may_pull(skb, sizeof(struct arphdr) + 2*dev->addr_len + 2*sizeof(u32)))
        goto freeskb;

    arp = skb->nh.arph;

    // 2. 基本字段校驗
    if (arp->ar_hln != dev->addr_len ||        // 硬件地址長度匹配
        dev->flags & IFF_NOARP ||              // 設備禁用 ARP
        skb->pkt_type == PACKET_OTHERHOST ||   // 非本機單播/廣播
        skb->pkt_type == PACKET_LOOPBACK ||    // 回環
        arp->ar_pln != 4)                      // 協議地址長度必須 4 (IPv4)
        goto freeskb;

    // 3. 共享檢查(Copy-on-Write)
    if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
        goto out_of_mem;

    // 4. Netfilter 掛鉤 -> arp_process
    return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);

freeskb:
    kfree_skb(skb);
out_of_mem:
    return 0;
}

三、 arp_process() 核心處理


int arp_process(struct sk_buff *skb) {
    struct net_device *dev = skb->dev;
    struct in_device *in_dev = in_dev_get(dev);  // 獲取 IPv4 設備配置
    struct arphdr *arp = skb->nh.arph;
    unsigned char *arp_ptr = (unsigned char *)(arp + 1);
    struct neighbour *n;
    u32 sip, tip;  // 發送端 IP、目標 IP
    unsigned char *sha, *tha;  // 發送端 MAC、目標 MAC

    if (!in_dev) goto out;  // 設備無 IPv4 配置

    // 1. 硬件類型/協議類型校驗(以太網/令牌環/FDDI 等)
    switch (dev->type) {
        case ARPHRD_ETHER:
        case ARPHRD_IEEE802_TR:
        case ARPHRD_FDDI:
        case ARPHRD_IEEE802:
            if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
                 arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
                arp->ar_pro != htons(ETH_P_IP))
                goto out;
            break;
        // ... AX25, NETROM 等其他類型
    }

    // 2. 僅處理 REQUEST/REPLY
    if (arp->ar_op != htons(ARPOP_REPLY) &&
        arp->ar_op != htons(ARPOP_REQUEST))
        goto out;

    // 3. 解析地址字段
    sha = arp_ptr; arp_ptr += dev->addr_len;
    memcpy(&sip, arp_ptr, 4); arp_ptr += 4;
    tha = arp_ptr; arp_ptr += dev->addr_len;
    memcpy(&tip, arp_ptr, 4);

    // 4. 過濾回環/多播目標 IP
    if (LOOPBACK(tip) || MULTICAST(tip))
        goto out;

    // 5. 確定目標 IP 類型
    int addr_type = inet_addr_type(tip);

    // 6. 處理 ARP REQUEST
    if (arp->ar_op == htons(ARPOP_REQUEST)) {
        // 目標 IP 是本機
        if (addr_type == RTN_LOCAL) {
            // 構造並發送 REPLY
            arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, tha);
            goto out;
        }
        // 目標 IP 是本機代理(代理 ARP)
        if (arp_fwd_proxy(in_dev, sip, tip) ||
            (arp->ar_hrd == htons(ARPHRD_ETHER) && arp_proxy(in_dev, sip, tip))) {
            arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, tha);
            goto out;
        }
    }

    // 7. 處理 ARP REPLY / 通用緩存更新
    // 查找或創建鄰居條目
    n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
    if (n) {
        // 更新鄰居條目:狀態→REACHABLE,MAC→sha
        neigh_update(n, sha, NUD_REACHABLE,
                     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
        neigh_release(n);
    }

out:
    kfree_skb(skb);
    return 0;
}

四、 關鍵分支邏輯

1. 本機回應 REQUEST

  • 條件:tip == 本機接口 IP (addr_type == RTN_LOCAL)。
  • 動作:構造 ARP REPLY,源 MAC = 設備 MAC,目標 MAC = 請求者 MAC (sha),直接發送(arp_send)。

2. 代理 ARP

  • arp_proxy:/proc/sys/net/ipv4/conf/*/proxy_arp 啟用,且 sip 可通過該設備路由到達。
  • arp_fwd_proxy:proxy_arp_pvlan (Private VLAN) 場景,隔離同 VLAN 端口間通信。

3. 緩存更新(REPLY 或 REQUEST 學習)

  • 調用 __neigh_lookup(&arp_tbl, &sip, dev, 1) 查找/創建鄰居。
  • neigh_update(..., NUD_REACHABLE, OVERRIDE) 強制設置為可達、更新 MAC。
  • 若鄰居有排隊 skb (arp_queue),立即發送。

五、 發送路徑 arp_send()


void arp_send(int op, int type, u32 dest_ip, struct net_device *dev,
              u32 src_ip, const unsigned char *dest_hw, const unsigned char *src_hw,
              const unsigned char *target_hw) {
    struct sk_buff *skb = alloc_skb(ARP_PACKET_SIZE, GFP_ATOMIC);
    // 填充以太網頭 + ARP 頭 + 地址字段
    // dev_queue_xmit(skb) 發送
}

六、 Netfilter 掛鉤點

  • NF_ARP_IN:arp_rcv → arp_process 之間,可修改/丟棄 ARP 包。
  • NF_ARP_OUT:arp_send 發送前。
  • NF_ARP_FORWARD:轉發 ARP 包(罕見)。
Copyright © Windows教程網 All Rights Reserved