rfc826 An Ethernet Address Resolution Protocol (ARP) を読んだ。

rfc826 An Ethernet Address Resolution Protocol (ARP)

リンクは以下から

datatracker.ietf.org

                            Abstract

The implementation of protocol P on a sending host S decides,
through protocol P's routing mechanism, that it wants to transmit
to a target host T located some place on a connected piece of
10Mbit Ethernet cable.  To actually transmit the Ethernet packet
a 48.bit Ethernet address must be generated.  The addresses of
hosts within protocol P are not always compatible with the
corresponding Ethernet address (being different lengths or
values).  Presented here is a protocol that allows dynamic
distribution of the information needed to build tables to
translate an address A in protocol P's address space into a
48.bit Ethernet address.
The Problem:
------------

The world is a jungle in general, and the networking game
contributes many animals.  At nearly every layer of a network
architecture there are several potential protocols that could be
used.  For example, at a high level, there is TELNET and SUPDUP
for remote login.  Somewhere below that there is a reliable byte
stream protocol, which might be CHAOS protocol, DOD TCP, Xerox
BSP or DECnet.  Even closer to the hardware is the logical
transport layer, which might be CHAOS, DOD Internet, Xerox PUP,
or DECnet.  The 10Mbit Ethernet allows all of these protocols
(and more) to coexist on a single cable by means of a type field
in the Ethernet packet header.  However, the 10Mbit Ethernet
requires 48.bit addresses on the physical cable, yet most
protocol addresses are not 48.bits long, nor do they necessarily
have any relationship to the 48.bit Ethernet address of the
hardware.  For example, CHAOS addresses are 16.bits, DOD Internet
addresses are 32.bits, and Xerox PUP addresses are 8.bits.  A
protocol is needed to dynamically distribute the correspondences
between a <protocol, address> pair and a 48.bit Ethernet address.

上位層のプロトコルの多くがイーサネットを使用しています。 しかし、10Mbit Ethernetは物理ケーブル上に48.bitのアドレスを必要としますが、ほとんどのプロトコルアドレスは48.bit長ではなく、またハードウェアの48.bit Ethernetアドレスと必ずしも関係があるわけでもない。 TCP/IP を使用するためにはIPアドレスを使うが、MACアドレスIPアドレスのアドレス解決をできる必要がある。

Packet format:
--------------

To communicate mappings from <protocol, address> pairs to 48.bit
Ethernet addresses, a packet format that embodies the Address
Resolution protocol is needed.  The format of the packet follows.

    Ethernet transmission layer (not necessarily accessible to
         the user):
        48.bit: Ethernet address of destination
        48.bit: Ethernet address of sender
        16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION
    Ethernet packet data:
        16.bit: (ar$hrd) Hardware address space (e.g., Ethernet,
                         Packet Radio Net.)
        16.bit: (ar$pro) Protocol address space.  For Ethernet
                         hardware, this is from the set of type
                         fields ether_typ$<protocol>.
         8.bit: (ar$hln) byte length of each hardware address
         8.bit: (ar$pln) byte length of each protocol address
        16.bit: (ar$op)  opcode (ares_op$REQUEST | ares_op$REPLY)
        nbytes: (ar$sha) Hardware address of sender of this
                         packet, n from the ar$hln field.
        mbytes: (ar$spa) Protocol address of sender of this
                         packet, m from the ar$pln field.
        nbytes: (ar$tha) Hardware address of target of this
                         packet (if known).
        mbytes: (ar$tpa) Protocol address of target.

まず、Ethernet headerの情報がある。

    Ethernet transmission layer (not necessarily accessible to
         the user):
        48.bit: Ethernet address of destination
        48.bit: Ethernet address of sender
        16.bit: Protocol type = ether_type$ADDRESS_RESOLUTION

16.bit: Protocol type はこの場合ARPを示す0x0806を使用する。

Ethertype   Ethertype       Description              Reference
(decimal)    (hex)        

  2054        0806     Address Resolution Protocol    [RFC7042]

from: https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.txt

他のEthertypesとしてIETFが定めたものとして以下のものがある

B.1.  Some Ethertypes Specified by the IETF

   0x0800  Internet Protocol Version 4 (IPv4)
   0x0806  Address Resolution Protocol (ARP)
   0x0808  Frame Relay ARP
   0x22F3  TRILL
   0x22F4  L2-IS-IS
   0x8035  Reverse Address Resolution Protocol (RARP)
   0x86DD  Internet Protocol Version 6 (IPv6)
   0x880B  Point-to-Point Protocol (PPP)
   0x880C  General Switch Management Protocol (GSMP)
   0x8847  MPLS
   0x8848  MPLS with upstream-assigned label
   0x8861  Multicast Channel Allocation Protocol (MCAP)
   0x8863  PPP over Ethernet (PPPoE) Discovery Stage
   0x8864  PPP over Ethernet (PPPoE) Session Stage
   0x893B  TRILL Fine Grained Labeling (FGL)
   0x8946  TRILL RBridge Channel

from: https://datatracker.ietf.org/doc/html/rfc7042#appendix-B

そしてEthernet header のあとにEthernet Payloadが続く

    Ethernet packet data:
        16.bit: (ar$hrd) Hardware address space (e.g., Ethernet,
                         Packet Radio Net.)
        16.bit: (ar$pro) Protocol address space.  For Ethernet
                         hardware, this is from the set of type
                         fields ether_typ$<protocol>.
         8.bit: (ar$hln) byte length of each hardware address
         8.bit: (ar$pln) byte length of each protocol address
        16.bit: (ar$op)  opcode (ares_op$REQUEST | ares_op$REPLY)
        nbytes: (ar$sha) Hardware address of sender of this
                         packet, n from the ar$hln field.
        mbytes: (ar$spa) Protocol address of sender of this
                         packet, m from the ar$pln field.
        nbytes: (ar$tha) Hardware address of target of this
                         packet (if known).
        mbytes: (ar$tpa) Protocol address of target.

TCP/IP でのARPでは実際に何の値をいれるか。

Hardware address space (ar$hrd) には Ethernet (10Mb) を表す Hardware Types である0x0001を使用。

    Number   Hardware Type (hrd)              Reference
       0     Reserved                         [RFC5494]
       1     Ethernet (10Mb)                  [Jon_Postel]
       2     Experimental Ethernet (3Mb)      [Jon_Postel]
       .
       .

Protocol address space (ar$pro) には IPv4 を表すEthertypes である 0x0800 を使用。

アルゴリズム

RFCより引用

?Do I have the hardware type in ar$hrd?
Yes: (almost definitely)
  [optionally check the hardware length ar$hln]
  ?Do I speak the protocol in ar$pro?
  Yes:
    [optionally check the protocol length ar$pln]
    Merge_flag := false
    If the pair <protocol type, sender protocol address> is
        already in my translation table, update the sender
        hardware address field of the entry with the new
        information in the packet and set Merge_flag to true.
    ?Am I the target protocol address?
    Yes:
      If Merge_flag is false, add the triplet <protocol type,
          sender protocol address, sender hardware address> to
          the translation table.
      ?Is the opcode ares_op$REQUEST?  (NOW look at the opcode!!)
      Yes:
        Swap hardware and protocol fields, putting the local
            hardware and protocol addresses in the sender fields.
        Set the ar$op field to ares_op$REPLY
        Send the packet to the (new) target hardware address on
            the same hardware on which the request was received.

日本語に訳すと以下

?ハードウェアの種類はar$hrdにありますか?
はい:(ほぼ間違いなくEthernet)
  [オプションでハードウェアの長さar$hlnを確認する] 。
  
  ?ar$proで指定されたプロトコル(IPv4)を話しているか? 
  はい: 
    [オプションでプロトコルの長さを確認するar$pln]。
    
    Merge_flag := false
     <protocol type, sender protocol address>のペアが
     すでに変換テーブルにある場合、パケットの新しい情報でエントリ
     の送信者ハードウェアアドレスフィールドを更新し、
     Merge_flagをtrueに設定する。
     
    ?私はターゲットプロトコルアドレスですか?
    はい:
      Merge_flag が false の場合、<protocol type, 
      送信者プロトコルアドレス, 送信者ハードウェアアドレス>
      を変換テーブルに追加する。
      
      ?オペコードはares_op$REQUESTか? (今すぐオペコードを見よ!!)
      はい:
        ハードウェアとプロトコルのフィールドを入れ替え、
        ローカルハードウェアとプロトコルのアドレスを送信者フィールドに入れる。
        
        ar$opフィールドをairs_op$REPLYに設定する。
        
        要求を受けたハードウェアと同じハードウェア上の(新しい)
        ターゲット・ハードウェア・アドレスにパケットを送信する。

上記をコードにすると以下のようである。 コードはmicrops から github.com

static void
arp_input(const uint8_t *data, size_t len, struct net_device *dev)
{
    struct arp_ether_ip *msg;
    ip_addr_t spa, tpa;
    int merge = 0;
    struct net_iface *iface;

    if (len < sizeof(*msg)) {
        errorf("too short");
        return;
    }
    msg = (struct arp_ether_ip *)data;

    // ハードウェアアドレスのチェック
    if (ntoh16(msg->hdr.hrd) != ARP_HRD_ETHER || msg->hdr.hln != ETHER_ADDR_LEN) {
        errorf("unsupported hardware address");
        return;
    }

    // プロトコルアドレスのチェック
    if (ntoh16(msg->hdr.pro) != ARP_PRO_IP || msg->hdr.pln != IP_ADDR_LEN) {
        errorf("unsupported protocol address");
        return;
    }

    memcpy(&spa, msg->spa, sizeof(spa));
    memcpy(&tpa, msg->tpa, sizeof(tpa));

    if (arp_cache_update(spa, msg->sha)) {
        /* updated */
        merge = 1;
    }

    // デバイスに紐づくIPインタフェースを取得する
    iface = net_device_get_iface(dev, NET_IFACE_FAMILY_IP);

    // ARP要求のターゲットプロトコルアドレスと一致するか確認
    if (iface && ((struct ip_iface *)iface)->unicast == tpa) {
        if (!merge) {
            arp_cache_insert(spa, msg->sha);
        }
        if (ntoh16(msg->hdr.op) == ARP_OP_REQUEST) {
            arp_reply(iface, msg->sha, spa, msg->sha);
        }
    }
}

KLab camp の TCP/IP 自作キャンプに参加してARPRFCを読もうと思った時のまとめ。 その時の資料は以下から

drive.google.com