このページの目次

ARP と NDP

IPアドレスからMACアドレスへの変換——IPv4ではARP(ブロードキャスト要求+ユニキャスト応答+キャッシュ老化)、IPv6ではNDP(マルチキャスト近接ノード発見+SLAAC自動設定)を使用します。レイヤー2とレイヤー3の間のこの架橋は、ローカルネットワーク通信の第一歩です。

概要

ARP がなければ、IP パケットはイーサネット上で転送できません——ARP は IP アドレスを MAC アドレスに変換する接着剤プロトコルです。ARP リクエスト(「192.168.1.1 は誰?」)はブロードキャストフレームとして送信され、宛先ホストが自身の MAC を返信します。IPv6 では NDP が ARP に代わり、ICMPv6 を基盤としており、アドレス解決に加え、ルーター発見(RS/RA)とアドレス自動設定(SLAAC)も提供します。ARP は 1982 年に設計されましたが、「LAN 内の全員を信頼する」というセキュリティモデルは現代では非常に脆弱です。しかし、低オーバーヘッドと単純さゆえに、閉鎖型ネットワークでは依然として効率的です。

ARP プロトコル (RFC 826)

フレーム形式

ARP は Ethernet フレーム内に直接カプセル化されます (EtherType=0x0806)。IP レヤーは存在しません:

Hardware Type:        2 bytes — 1 = Ethernet
Protocol Type:        2 bytes — 0x0800 = IPv4
HW Addr Len:          1 byte  — 6 (MAC)
Protocol Addr Len:    1 byte  — 4 (IPv4)

Operation:            2 bytes — 1=Request, 2=Reply, (RARP は 3/4、ほとんど使われない)

Sender HW Addr:       6 bytes (MAC)
Sender Protocol Addr: 4 bytes (IPv4)
Target HW Addr:       6 bytes (Request では 0 パディング)
Target Protocol Addr: 4 bytes (IPv4)

Request はブロードキャスト MAC (ff:ff:ff:ff:ff:ff) 宛てに送信され、Reply はユニキャストです。ARP メッセージの総長は 28 bytes + イーサネットヘッダー 18 bytes = 46 bytes です——これはイーサネットの最小ペイロード長にちょうど一致し、パディングは不要です。

カーネル ARP 状態機械

各 neighbor entry には以下の状態があります (include/net/neighbour.h):

NUD_NONE:      新規作成、状態なし
NUD_INCOMPLETE: ARP リクエストを送信済み、応答を待機中 — タイムアウト後に再試行
NUD_REACHABLE:  直近で到達可能を確認(通常状態)
NUD_STALE:      期限切れだがクリーンアップされていない — 次回使用時に DELAY に移行
NUD_DELAY:      TCP 確認応答を待機中(5秒間)
NUD_PROBE:      ARP プロブを送信(最大3回、1秒間隔)
NUD_FAILED:     プロブが3回失敗 — entry を削除

状態遷移:

カーネル ARP 状態機械: NUD 近接ノード表項のライフサイクル NUD_NONE 新規作成・状態なし NUD_INCOMPLETE ARP request 送信済み・reply 待機中 NUD_REACHABLE 直近で到達可能確認(通常) NUD_FAILED entry 削除(再作成が必要) NUD_STALE 期限切れだが未クリーンアップ NUD_DELAY TCP 確認応答を待機中(5秒) NUD_PROBE ARP probe 送信(最大3回、1秒間隔) ARP request 送信 タイムアウト(1秒) ARP reply 受信 30秒で期限切れ データパケットがこの entry 宛てに送信 5秒以内に TCP 確認応答 → ARP 不要! 5秒経過しても確認応答なし ARP reply 3回失敗 重要: NUD_STALE では能動的に ARP を送信しない——カーネルは、 実際にその近接ノード宛てにデータパケットを送信する際にのみ、

重要: base_reachable_time(デフォルト 30秒)経過後の NUD_STALE 状態では、⁠能動的に ARP を送信しません⁠。カーネルは、実際にその近接ノード宛てにデータパケットを送信する際にのみ、DELAY → PROBE のチェーンを通じて到達可能性を確認します。これにより、ネットワークがアイドル状態のときに意味のない ARP トラフィックが大量に発生するのを防ぎます。

/proc によるチューニング

cat /proc/sys/net/ipv4/neigh/default/gc_stale_time    # STALE entry の生存時間(デフォルト 60秒)
cat /proc/sys/net/ipv4/neigh/default/base_reachable_time # REACHABLE 状態のタイムアウト(デフォルト 30秒)
cat /proc/sys/net/ipv4/neigh/default/delay_first_probe_time # DELAY 状態の持続時間(デフォルト 5秒)
cat /proc/sys/net/ipv4/neigh/default/mcast_solicit     # マルチキャストプロブ回数(デフォルト 3)

Gratuitous ARP

送信元 IP = 宛先 IP かつ送信元 MAC != 0 の ARP Request のことです。イーサネットブロードキャスト + 宛先 IP が自身の IP という、「自問自答」の特殊な形式です。用途は以下の通りです:

  1. IP の切り替え(VRRP/HSRP/CARP): 仮想 IP が1つの物理ホストから別のホストに移行 → Gratuitous ARP を送信 → スイッチと近接ノードの ARP キャッシュを更新 → 新所有者が即座にトラフィックを受信
  2. 重複 IP の検出: IP を設定直後 → Gratuitous ARP を送信 → 応答があれば → IP 衝突
  3. ARP キャッシュの更新: 「私の MAC は変わっていないが、キャッシュを更新してほしい」と能動的に通知(あまり使われない)

Proxy ARP

ルーターが、同じ物理セグメントにいない宛先の ARP Request に代わって応答します:

Host A: (10.0.1.100 に ping を送信、ただしこれは自分のサブネット外)
  → ARP 「10.0.1.100 は誰?」
Router: (Host A の ARP を確認し、10.0.1.0/24 へのルートを持っている)
  → ARP Reply(自身の MAC で): 「10.0.1.100 は <router_MAC> です」
Host A: → IP パケットをルーターの MAC 宛てに送信
Router: → ルーティングテーブルに従って転送

非推奨——設定ミス(Host A は 10.0.1.100 がローカル到達可能と考えるのではなく、ルーターへのルートを持つべき)を隠蔽してしまいます。Linux のデフォルトは proxy_arp=0 です。


NDP (IPv6 近接ノード発見, RFC 4861)

NDP は ICMPv6 を介して 5 種類のメッセージを伝達し、ARP の全機能を置き換えるとともに、アドレス自動設定を追加しました:

ICMPv6 メッセージ形式

すべての NDP メッセージは、IPv6 Next Header=58 の後に共通の ICMPv6 ヘッダー形式を共有します:

Type (1 byte):  133=RS, 134=RA, 135=NS, 136=NA, 137=Redirect
Code (1 byte):  0 (Redirect を除く)
Checksum:        ICMPv6擬似ヘッダーチェックサム(IPv6 src/dst を含む)
Reserved:        (4 bytes、ゼロ)
Message Body:    タイプ固有のオプション

オプション(TLV 形式):

[Type 1] [Length 1] [Value...]
Length = 8バイト単位(Type+Length 自体を含む)
→ Type=1 Len=1 → 合計 8バイト、Value=6バイト

主要オプション:
  Type 1: ソース/ターゲットリンク層アドレス(MAC)
  Type 2: プレフィックス情報(RA に含まれる: プレフィックス + プレフィックス長 + フラグ)
  Type 3: リダイレクトヘッダー
  Type 5: MTU(RA)

Neighbor Solicitation (NS, type 135)

宛先: 「この IPv6 は誰?MAC を教えて」

宛先 IPv6 の solicited-node マルチキャストアドレス宛てに送信:
  ff02::1:ff<宛先 IPv6 アドレスの下位24ビット>

送信元アドレス: 送信インターフェースの link-local(または、すでに持っている場合はユニキャスト)
オプション: Source Link-Layer Address(自身の MAC)

Neighbor Advertisement (NA, type 136)

宛先: 「この IPv6 私です、私の MAC は X です」

NS の送信元アドレス(ユニキャスト)または全ノード(マルチキャスト、DAD 衝突の場合)宛てに送信
フラグ:
  R (Router): 送信者がルーター(RA の Router Lifetime に基づく)
  S (Solicited): NS への応答である(1 に設定)
  O (Override): 既存の NCE を上書き(0 の場合、受信者は古いエントリを保持可能)
オプション: Target Link-Layer Address

SLAAC (ステートレスアドレス自動設定, RFC 4862)

ホスト:
  1. link-local アドレスを生成: fe80::/64 プレフィックス + IID
  2. RS (Router Solicitation, type 133) を送信
     送信元: ::(未指定アドレス)または link-local
     宛先: ff02::2(all-routers マルチキャスト)

ルーター:
  3. RA (Router Advertisement, type 134) で応答
     送信元: ルーターの link-local
     宛先: RS への応答の場合 → RS の送信元アドレス宛て(ユニキャスト)
           定期的な場合 → ff02::1(all-nodes マルチキャスト)

RA には Prefix Information (Option 2) が含まれる:
  プレフィックス:       (例: 2001:db8:abcd::)
  プレフィックス長:   (例: 64)
  L (on-link):        このプレフィックスは同じリンク上にある → 直接通信可能
  A (autonomous):      このプレフィックスを使用して SLAAC → グローバルアドレスを生成
  Valid Lifetime:      アドレスの有効期間(通常 2592000秒 = 30日)
  Preferred Lifetime:  アドレスの「優先」期間(到達後、deprecated だが削除はされない)

RA には Router Lifetime が含まれる:
  0: このルーターはデフォルトゲートウェイとして使用不可
  >0: デフォルトルートの有効秒数(最大 65535 ≈ 18時間)

SLAAC アドレス生成

EUI-64(非推奨、MAC が露出する):
  MAC: aa:bb:cc:dd:ee:ff
  → IID: aa:bb:cc:ff:fe:dd:ee:ff
         (fffe を挿入、U/L ビットを反転)
  → 完全なアドレス: 2001:db8:abcd:0:a8bb:ccff:fedd:eeff/64

プライバシー拡張 (RFC 8981、Linux デフォルト):
  ランダム IID + 短い有効期間 → 定期的に新しいアドレスを生成
  → 古いアドレスは deprecated だが保持(既存接続は切断されない)
  → 新しいアドレスは preferred → 新しい接続では新しいアドレスを使用
  → ネットワーク間での追跡を防止

DAD (重複アドレス検出)

生成されたすべての IPv6 アドレス(link-local または global)は、使用可能になる前に DAD を実行する必要があります:

  1. NS を送信: target = 検証するアドレス, 送信元 = ::(未指定アドレス)
  2. NA が返信された場合(DAD 衝突)→ そのアドレスは使用不可
  3. DupAddrDetectTransmits 回まで送信(デフォルト 1回)
  4. NA が 0 個受信 → アドレス使用可能 → tentative から preferred へ移行

注意: DAD はアドレス設定時、ネットワーク接続直後に実行する必要があります
      → 2台のデバイスが同時に同じアドレスを生成した場合(衝突確率は極めて低い)→ 2台目が検出 → 無効化

ARP の攻撃面と防御

ARP スプーフィング(Man-in-the-Middle):
  攻撃者: 偽造された ARP Reply を送信 → 宛先の IP を攻撃者の MAC にマッピング
  → トラフィックが攻撃者にリダイレクト

防御:
  1. DAI (Dynamic ARP Inspection): スイッチが ARP の正当性をチェック
     (DHCP snooping DB + 静的バインディング)— 企業ネットワーク向け
  2. 暗号化トンネル: ARP がポイズニングされても → トラフィックは暗号化 → 中間者は閲覧不可
     これが唯一の完全な解決策である——トラフィックが
     WireGuard/Tailscale で暗号化されていれば、ARP スプーフィングは無効
  3. 静的 ARP: `ip neigh add 192.168.1.1 lladdr xx:xx:xx dev eth0 nud permanent`
     最も安全だが、大規模な管理は不可能

参考

  • RFC: 826 (ARP), 4861 (NDP), 4862 (SLAAC), 8981 (Privacy Extensions)
  • ソースコード⁠: net/ipv4/arp.c, net/core/neighbour.c (ARP 状態機械), net/ipv6/ndp.c
  • ツール⁠: ip neigh, arp -a, arping -I eth0 192.168.1.1, tcpdump arp / tcpdump icmp6

キーワード: ARP, NUD 状態機械, gratuitous ARP, proxy ARP, NDP, NS/NA, RS/RA, SLAAC, EUI-64, DAD, solicited-node multicast