【実務・中級編】 DHCPリレーエージェントの動作とパケット転送の仕組み – ネットワーク基礎とWebセキュリティ実践ガイド

DHCPリレーエージェントの深淵:なぜブロードキャストは「国境」を越えられるのか

ネットワークエンジニアとして現場に立っていると、ふとした瞬間に「当たり前」の挙動が不思議に見えることがあります。その筆頭が、DHCPによるIPアドレスの自動割り当てです。

「ブロードキャストはルータを越えない」――これはネットワークの鉄則です。しかし、VLANでセグメントを細分化した現代のエンタープライズ環境では、クライアントが異なるサブネットにいるDHCPサーバからIPを受け取る必要があります。ここで登場するのが、DHCPリレーエージェント(RFC 3046)という「翻訳者」です。

今日は、パケットがルータの境界でどう変身し、どう宛先へ届けられるのか。その泥臭い裏側を紐解いていきましょう。

—

DHCPの「境界問題」を解決する仕組み

DHCPの通信(DHCPDISCOVER)は、もともと「自分と同じセグメントにいるはずのサーバを探す」ために、宛先MACアドレス FF:FF:FF:FF:FF:FF、宛先IP 255.255.255.255 というフルブロードキャストで行われます。

ルータは設計上、このブロードキャストを破棄します。つまり、何もしなければクライアントは孤立無援です。ここでルータ(またはL3スイッチ)のインターフェースに ip helper-address(Cisco等のコマンド)を設定することで、ルータは「DHCPの泣き声(ブロードキャスト)」をキャッチし、特定のDHCPサーバへユニキャストで転送してくれるようになります。

通信シーケンスのリアル

1. Client → Relay: DHCPDISCOVER をブロードキャスト。
2. Relay → Server: 受信したパケットをカプセル化し、宛先をDHCPサーバのIPに変更してユニキャスト送信。
3. Server → Relay: DHCPOFFER を受け取り、DHCPサーバはリレーエージェントのIP(giaddrフィールド)を見て、どのサブネットに払い出すべきかを判断。
4. Relay → Client: サーバからの応答を元のクライアントへ転送。

—

設定の現場:Cisco機器での実装例

実務では、DHCPサーバが遠隔地にある場合、L3スイッチのゲートウェイ(SVI)に設定を施します。

! VLAN 10 (クライアント用) のゲートウェイ設定
interface Vlan10
 ip address 192.168.10.1 255.255.255.0
 ! 以下の設定が「リレーエージェント」として機能する魔法のコマンド
 ! DHCPリクエストをこのIPに向けてユニキャスト転送する
 ip helper-address 10.0.50.10

ここで重要なのが、パケット内の giaddr(Gateway IP Address)フィールドです。リレーエージェントは、クライアントからのリクエストを転送する際、自分のインターフェースIPをこのフィールドに書き込みます。DHCPサーバはこれを見て、「ああ、192.168.10.0/24のプールからIPを貸し出せばいいんだな」と理解するわけです。

—

デバッグの流儀:パケットを見抜く

トラブルシューティングの際、Wireshark でパケットをキャプチャすると、転送されたパケットのヘッダーがどう変化しているか確認できます。

確認すべきポイント

  • giaddr の値: 0.0.0.0 になっていないか?(リレーエージェントが機能していない証拠です)
  • UDPポート 67/68: クライアントは 68、サーバは 67 を使います。ファイアウォールのポリシーでこのポートが塞がれていないか確認してください。

Pythonを使って、DHCPのようなUDP通信をシミュレートする簡易的なテストコードを書いてみましょう。

import socket

# DHCPリレーの挙動を確認するための簡易UDPソケット通信例
def simulate_dhcp_request(server_ip):
    # DHCPポート(67)を指定
    port = 67
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    # 実際にはここにDHCPパケットのバイナリデータが入る
    payload = b"\x01\x01\x06\x00..." 
    
    try:
        # リレーエージェントはここをサーバのIPに書き換えて転送する
        sock.sendto(payload, (server_ip, port))
        print(f"Server {server_ip} へDHCPパケットを転送しました。")
    except Exception as e:
        print(f"送信失敗: {e}")
    finally:
        sock.close()

# 運用中のDHCPサーバIP
simulate_dhcp_request("10.0.50.10")

—

エンジニアへのアドバイス:ゼロトラスト時代に向けて

昨今のゼロトラストアーキテクチャでは、単にDHCPでIPを配れば終わり、ではありません。配布されたIPが「誰の、どのデバイスか」を認証基盤(RADIUS/802.1X)と紐付けることが求められます。

リレーエージェントは、単なる転送役から、セキュリティの起点(Option 82によるAgent Circuit IDの付与など)へと役割を拡大しています。Option 82を利用すれば、どのスイッチのどのポートから接続要求が来たかをDHCPサーバ側で識別し、アクセス制御を動的に変えることも可能です。

トラブルシューティングの鉄則:
もし「IPが取れない」という相談を受けたら、まずは show ip interface で helper-address が正しく設定されているかを確認し、次にルータのACLで UDP 67/68 が弾かれていないかを確認してください。そして最後は、DHCPサーバ側のスコープ設定が giaddr のサブネットと一致しているか。

このフローを頭に入れておくだけで、現場での復旧速度は劇的に変わります。ネットワークの境界は、技術でいくらでも書き換えられるのです。

それでは、今日もセキュアで快適なネットワークライフを!

コメント

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