【実務・中級編】 Gratuitous ARP(GARP)のパケット構造、IPアドレス重複検出、およびフェイルオーバー検知 – インフラ・物理&L2/L3ネットワーク基礎実践ガイド

ネットワークの「静かなる主張」:Gratuitous ARPがインフラを救う理由

エンジニア諸君、今日もパケットの海を泳いでいるか?
ネットワークの世界には、派手なルーティングプロトコルや高度なロードバランシングの裏側で、極めてシンプルだが「これがないと何も始まらない」という地味なヒーローが存在する。

その筆頭が Gratuitous ARP (GARP) だ。直訳すれば「不必要なARP」だが、現場の感覚で言えば「自己主張の激しいARP」と呼ぶべきだろう。今日は、この一見地味なパケットが、なぜフェイルオーバーやIP競合検知というシビアな現場で不可欠なのか、その深淵を紐解いていこう。

—

1. GARPの正体:パケット構造に隠された「自己紹介」

まず、RFC 826で定義されたARPの基本を思い出してほしい。通常のARPは「誰か192.168.1.1のMACアドレスを知らないか?」と問いかけるものだ。

しかし、GARPは違う。GARPのパケットを覗くと、以下のようになっている。

  • Sender Protocol Address (送信元IP): 自身のIPアドレス
  • Target Protocol Address (宛先IP): 自身のIPアドレス
  • Sender Hardware Address (送信元MAC): 自身のMACアドレス
  • Target Hardware Address (宛先MAC): 00:00:00:00:00:00 (通常は無視される)

これを見て違和感を覚えないだろうか?「宛先IPが自分自身」なのだ。つまり、誰かを探しているわけではなく、「ネットワーク上の全員に向かって、自分のIPとMACの紐付けを強制的にアナウンスしている」のである。

なぜこれが重要なのか?

GARPを受信したスイッチやルーター、あるいは他のホストは、自身のARPキャッシュテーブルを強制的に更新する。これが「無言の命令」として機能し、ネットワーク全体のMAC学習テーブルを瞬時に書き換えるわけだ。

—

2. 現場の現実:フェイルオーバーとMACの即時更新

Web APIのバックエンドサーバーをクラスタリング(VRRPやHSRP)している時、マスター機がダウンしたらどうなる? 待機系がIPを引き継いだ瞬間、上位のスイッチや周辺機器のARPテーブルは「旧マスター」のMACアドレスを指したままになっている。

ここでGARPの出番だ。切り替わった瞬間に待機系がGARPを送信することで、L2スイッチのCAMテーブルと、周囲の機器のARPテーブルが「あ、IPは同じだけどMACが新しい奴になったんだな」と瞬時に認識する。これがないと、数分間の通信断(ARPタイムアウト待ち)が発生し、APIのレスポンスが壊滅的なことになる。

VRRP設定例 (Keepalived)

実際の現場でよく使う keepalived.conf の設定を例に挙げよう。

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    # 仮想IPの定義
    virtual_ipaddress {
        192.168.1.100
    }
    # 状態変化時にGARPを送信する回数を制御
    garp_master_refresh 5
    garp_master_refresh_repeat 1
}

この garp_master_refresh こそが、インフラ屋の命綱だ。

—

3. IP競合検知:ネットワークの「密告者」

開発環境で「IPアドレスが重複してますよ」という警告を見たことはないだろうか? あれもGARPの仕業だ。

OSが起動してIPを割り当てた瞬間、自身のIPに対してGARPを投げる(これを ARP Probe とも呼ぶ)。もし、そのGARPに対して「それは俺のIPだ!」と返事(ARP Reply)が返ってきたら、OSは「IP競合」としてエラーを出す。

これをプログラムから確認したい場合、Pythonの scapy を使うとパケットレベルでシミュレーションが可能だ。

from scapy.all import Ether, ARP, sendp

# 自身のIPとMACを偽装してGARPを送信するコード
# 注意:本番環境でこれを実行するとネットワークが混乱するので実験環境でやること
def send_garp(interface, ip_address, mac_address):
    # ARPパケットの構築 (op=2はARP Reply)
    pkt = Ether(src=mac_address, dst="ff:ff:ff:ff:ff:ff") / \
          ARP(hwsrc=mac_address, psrc=ip_address, hwdst=mac_address, pdst=ip_address, op=2)
    
    sendp(pkt, iface=interface, count=3)
    print(f"GARPを送信しました: {ip_address} -> {mac_address}")

# 実行例
# send_garp("eth0", "192.168.1.100", "aa:bb:cc:dd:ee:ff")

—

4. トラブルシューティングの極意

現場で「なぜか通信が時々ブラックホールに吸い込まれる」という謎の現象に遭遇したら、以下の手順でGARPを疑え。

1. tcpdump でパケットをキャプチャする:
tcpdump -i eth0 arp を実行し、異常な頻度でGARPが飛んでいないか確認せよ。
2. スイッチのCAMテーブルを確認:
show mac address-table (Ciscoの場合) で、IPの紐付けが頻繁に入れ替わっていないか?
3. Gratuitous ARPの抑制設定を確認:
一部の高度なL2スイッチには、セキュリティ機能(ARP Inspection等)によりGARPをドロップするものがある。フェイルオーバー時に通信が切れる場合、この設定が犯人の可能性が高い。

まとめ:地に足の着いた設計を

GARPは、現代の複雑なクラウドネイティブな環境でも、依然としてL2レベルの信頼性の要だ。APIの負荷分散設定や、仮想化基盤のネットワーク設計を行う際、「IPアドレスが移動したとき、周囲はどうやってそれを知るのか?」という問いを常に持ってほしい。

教科書通りの仕様を知ることは大事だが、そのパケットがネットワーク機器のASICをどう叩き、テーブルをどう書き換えるか。その「現場の景色」を想像できる人間こそが、真のインフラエンジニアだ。

それでは、また次回のパケット解析でお会いしよう。諸君のネットワークに障害が起きないことを祈る。

コメント

タイトルとURLをコピーしました