パケットの息遣いを聞け!DHCPのDORAプロセスとオプションフィールドの深層
ネットワークエンジニアとして現場を渡り歩いていると、「IPアドレスが取れない」「名前解決ができない」といったトラブルに幾度となく直面します。クラウド全盛の現代であっても、コンテナが立ち上がるとき、オフィスのデスクに新しいPCをつないだとき、その背後では必ず「DHCP(Dynamic Host Configuration Protocol)」の静かなるハンドシェイクが行われています。
Web APIの設計やモダンなインフラ運用に携わるエンジニアにとって、HTTPの上下動やJSONの構造に目が行きがちですが、その土台を支えるレイヤー2/レイヤー3の泥臭い挙動――特にOSI参照モデルの各階層がどのように連携してパケットを送り出しているかを知ることは、障害切り分けの強力な武器になります。
今回は、DHCPの基本であるDORAプロセスのパケットの動きを解き明かし、実務でトラブルシューティングの鍵となるオプションフィールドの深い部分まで徹底解説します。
—
1. 境界防御の要とIPアドレスのライフサイクル
企業ネットワークやクラウドのVPCにおいて、デバイスがネットワークに参加する最初の瞬間、何が起きているでしょうか。デバイスは自分のIPアドレスすら持っていません。そのため、通信の宛先も送信元も決まっていない状態からスタートします。
ここで登場するのが、UDPのブロードキャスト(あるいはレイヤー2のブロードキャスト)です。「俺の名前はまだない、誰かIPをくれ!」という叫びから、DHCPのドラマが始まります。
OSI参照モデルとTCP/IP階層モデルの対応において、DHCPはアプリケーション層(TCP/IPではアプリケーション層)に位置しますが、下位層のトランスポート層ではUDP(ポート番号:クライアント 68、サーバー 67)を利用し、最終的にデータリンク層のMACアドレスを頼りに宛先を特定するという、非常にユニークな生態系を持っています。
—
2. DORAプロセスの4ステップとパケットのリアルな挙動
DHCPの代名詞であるDORAプロセスは、以下の4つのフェーズで構成されています。
1. Discover(発見)
2. Offer(提案)
3. Request(要求)
4. Acknowledge(確認・承諾)
それぞれのフェーズで、パケットがネットワーク上をどのように駆け巡っているのか、その実態を見ていきましょう。
① DHCP Discover(クライアント → ネットワーク全体)
新米のクライアントがネットワークに繋がった瞬間、自身のIPアドレス(0.0.0.0)とMACアドレスを頼りに、宛先IPアドレス 255.255.255.255(ブロードキャスト)、宛先MACアドレス FF:FF:FF:FF:FF:FF でパケットをブロードキャストします。
このパケットを受け取ったルーターやDHCPリレーエージェントは、同じセグメント内(またはリレー経由)にあるDHCPサーバーへこの叫びを転送します。
② DHCP Offer(DHCPサーバー → クライアント)
Discoverを受信したDHCPサーバーは、プールから空いているIPアドレスを選び、「このIPを使ってもいいよ」という提案を返します。
この時点ではまだクライアントにIPが正式に割り当てられていないため、サーバー側もブロードキャスト(またはユニキャスト)で返答します。パケットの中には、割り当て予定のIPアドレス、サブネットマスク、デフォルトゲートウェイ、そして後述するオプションフィールドが含まれています。
③ DHCP Request(クライアント → ネットワーク全体)
Offerを受け取ったクライアントは、複数のDHCPサーバーが存在する場合を考慮し、「〇〇サーバーから提案されたIPアドレスを正式に要求します!」という宣言を再びブロードキャストします。
このブロードキャストにより、他のDHCPサーバーは「あ、別のサーバーの提案が採用されたんだな」と認識し、保留していたIPアドレスのプールを解放します。
④ DHCP Acknowledge(DHCPサーバー → クライアント)
最後に、DHCPサーバーが「よし、そのIPの利用を正式に許可する。リース期間は〇日間だ」と最終承認(ACK)を返します。
これを受信したクライアントは、自分のインターフェースにIPアドレスをバインドし、晴れてネットワークの正式な一員となるのです。
—
3. パケットの深部:DHCPオプションフィールドの正体
DHCPパケットの本体(UDPペイロード)の中身をWiresharkなどで覗いたことがありますか? 固定長ヘッダーの後に続くオプションフィールド(Option Field)こそが、モダンなネットワーク運用の肝です。
マジッククッキー(0x63538263)の後に続く可変長のタグ構造になっており、[Code (1byte)][Length (1byte)][Value (Nbytes)] という形式で様々な設定値が詰め込まれています。
実務で頻繁に目にする主要なオプションコードを見てみましょう。
| オプションコード | パラメータ名 | 概要・実務上の重要性 |
| :— | :— | :— |
| Option 1 | サブネットマスク (Subnet Mask) | クライアントが所属するネットワーク範囲を決定する |
| Option 3 | ルーター (Router / Gateway) | 外部ネットワークへ出るためのデフォルトゲートウェイのIP |
| Option 6 | ネームサーバー (DNS Server) | ドメイン名解決のためのDNSサーバーIP。ここが間違えると名前引きができなくなる |
| Option 12 | ホスト名 (Host Name) | クライアントのホスト名 |
| Option 15 | ドメイン名 (Domain Name) | 所属するDNSドメイン(例: internal.example.com) |
| Option 51 | IPアドレスリース時間 (IP Address Lease Time) | IPを占有できる期間(秒単位)。短いとトラフィックが増え、長いとアドレスプールが枯渇する |
| Option 121 | クラスレス静的ルート (Classless Static Routes) | 特定のサブネットへのルーティングを動的に追加する。複雑な社内網で多用される |
—
4. 実務で役立つ!Pythonを用いたDHCPパケットシミュレーション・解析の断片
インフラエンジニアやセキュリティエンジニアが、自前でカスタムスクリプトを書いてネットワークの挙動をテストしたり、パケットのモックを作ったりする際の参考として、Pythonの scapy ライブラリを用いた簡単なDHCP Discoverパケット構築のコードスニペットを紹介します。
実務の現場では、セキュアな環境検証や、ローカルのDHCPサーバーの応答速度測定などにこういったコードが役立ちます。
from scapy.all import *
from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.inet import IP, UDP
from scapy.layers.l2 import Ether
def create_dhcp_discover():
"""
DHCP Discoverパケットを構築するサンプルコード
レイヤー2のブロードキャストからUDPの67/68番ポートまでを緻密に組み立てます。
"""
# 1. イーサネットフレーム層(宛先はMACブロードキャスト)
eth_layer = Ether(dst="ff:ff:ff:ff:ff:ff", src="12:34:56:78:9a:bc", type=0x0800)
# 2. IP層(送信元は未定なので 0.0.0.0、宛先はIPブロードキャスト)
ip_layer = IP(src="0.0.0.0", dst="255.255.255.255")
# 3. トランスポート層(UDP: クライアント68番 -> サーバー67番)
udp_layer = UDP(sport=68, dport=67)
# 4. BOOTP層(初期化リクエストを示すためにchaddrに自身のMACを設定)
bootp_layer = BOOTP(op=1, chaddr=b"\x12\x34\x56\x78\x9a\bc", xid=0x12345678)
# 5. DHCP層(オプションとして Discover を指定、要求するパラメータも追加)
dhcp_layer = DHCP(options=[
("message-type", "discover"),
("param_request_list", [1, 3, 6, 15, 119]), # サブネット, ゲートウェイ, DNS, ドメイン名などを要求
("end")
])
# パケットの結合
packet = eth_layer / ip_layer / udp_layer / bootp_layer / dhcp_layer
print("[*] DHCP Discover パケットを構築しました。")
return packet
# 実際の送信テストやダンプを行う場合は以下のように実行(要root権限)
# if __name__ == "__main__":
# pkt = create_dhcp_discover()
# sendp(pkt, iface="eth0", verbose=False)
このコードを実行すると、OSI参照モデルの物理層からアプリケーション層(DHCPオプション)に至るまで、すべてのデータ構造が正確にパッケージングされ、ネットワーク空間へと飛び出していきます。
—
5. 現場の教訓:DHCPトラブルシューティングの作法
最後に、現場で数々の障害を潜り抜けてきたシニアからの実践的なTipsをいくつか伝授します。
1. リレーエージェント(IPヘルパーアドレス)の存在を忘れるな
DHCPはブロードキャスト通信であるため、ルーターをまたいだ別セグメントには届きません。もし「IPが取れない」というチケットが起票されたら、大元の上流ルーターに ip helper-address (Ciscoの場合)が正しく設定されているか、あるいはL3スイッチのルーティング設定が死んでいないかを真っ先に疑ってください。
2. スコープ枯渇とリース時間のジレンマ
オフィスの無線LANや開発用の検証環境で、急にIPが取れなくなる現象の8割は「DHCPプールの枯渇」です。Option 51(リース時間)を無駄に長く設定していると、退社したデバイスのIPが解放されず、翌朝に出社したエンジニアたちが一斉に弾かれます。環境の特性に合わせてリース時間を最適化(例: 2時間〜8時間など)する勇気を持ちましょう。
3. Wiresharkのフィルタはシンプルに
パケットキャプチャを取る際は、情報量が多すぎると目を回します。bootp や dhcp というフィルターをかけ、DORAの4つのフェーズ(Message Type: Discover / Offer / Request / ACK)が綺麗に流れているかを時系列で追うのが、最短のデバッグ手法です。
ネットワークの裏側で静かに、しかし確実に動いているDHCPとオプションの世界。この仕組みの解像度を上げておくことが、いざという時の素早いインシデント解決への一番の近道です。さあ、次はあなたのターミナルとパケットアナライザーで、その息遣いを確かめてみてください。
コメント