pythonでDHCPサーバ作成 ~①DHCPとは~
最近業務でDHCPに触れる機会があったので、pythonを使用して任意のIPアドレス解決を実施できるDHCPサーバツールを作成してみました。
DHCPとは
DHCP(Dynamic Host Configuration Protocol)は、自分が使うためのIPアドレスをDHCPサーバからもらうためのプロトコルです。
市販のルータにも該当の機能が備わっており、皆さんが普段使っているPCやスマホでも、知らないうちにDHCPを使っていたりします。
DHCP通信の流れは以下の通り。
送信フレーム | 送信元 | 概要 | 送信データ宛先 |
① DHCP Discover | DHCPクライアント | 利用可能なDHCPサーバーを見つける為の、ブロードキャストメッセージ。 | ブロードキャスト |
② DHCP Offer | DHCPサーバ | サーバーからクライアントへの DHCPDISCOVER に対する応答。 | 任意のクライアント |
③ DHCP Request | DHCPクライアント | クライアントからサーバーへの、次のいずれかのメッセージ (a) サーバからのレスポンスに対するリクエスト (b) リブート時などに、以前使用していたIPアドレスの正当性を確認 (c) IPアドレスの延長要求 | ブロードキャスト |
④ DHCP ACK | DHCPサーバ | サーバーからクライアントへの要求受け入れメッセージ | 任意のクライアント |
⑤ DHCP Release | DHCPクライアント | 事前に取得していたIPアドレスの解放をサーバへ通知 | 任意のサーバ |
詳細については RFC2131参照
wiresharkによるキャプチャ
実際の通信内容は以下の通り。重要なことはDHCPクライアントの送信元IPアドレスが0.0.0.0かつ、送信先IPアドレスが255.255.255.255(ブロードキャスト)であることです。
ちなみにwiresharkでDHCPプロトコル使用時のキャプチャを取るため、以下の流れでIPアドレスのリリース、再取得を実施しました。
本コマンドはDHCPサーバの動作確認でも使用するので重要です。
① 管理者としてコマンドプロンプト起動
② コマンド「ipconfig /release」実行しIPアドレスの解放
③ コマンド「ipconfig /renew」実行しIPアドレスの再取得
DHCPのパケットフォーマット
DHCPのパケットフォーマットは以下の通り。(UDPヘッダまでは省略)
各パラメータ詳細については、以下のようになっています。
領域 | サイズ(byte) | 名称 | 意味 |
op | 1 | Message Operation Code | op=1:DHCPクライアントからのメッセージ op=2:DHCPサーバからのメッセージ |
htype | 1 | Hardware Address Type | htype=1 : Ethernet |
hops | 1 | hops | DHCP サーバの中継回数(今回は0) |
xid | 4 | Transaction ID | DHCP クライアントが割り当てる 4 byte のランダム値 Discover/Offer/Request/ACK 等の流れで一貫して同じ値となる |
secs | 2 | Seconds elapsed | 再リースの要求時に残り時間を設定 |
flags | 2 | flags | flags=0x0000 :DHCP クライアントへの応答にユニキャストを指定 flags=0x0001 :DHCP クライアントへの応答にブロードキャストを指定 |
ciaddr | 4 | Client IP Address | DHCP クライアントが再リース要求時、自身へ既に払い出されているIPアドレスを設定 |
yiaddr | 4 | Your IP Address | DHCP サーバが DHCP クライアントへ払い出す IP アドレスを設定 |
siaddr | 4 | Server IP Address | DHCP サーバのIPアドレス |
giaddr | 4 | Gateway IP Address | DHCPリレーエージェントのIPアドレス DHCPサーバはGIADDRを見てクライアントの所属するサブネットを識別する |
chaddr | 16 | Client Hardware Address | クライアントの MAC アドレスを格納する 後ろ10byteは0パディング |
sname | 64 | Server Name | オプションのサーバ ホスト名(今回は未使用) |
file | 128 | file | ブート ファイルの名前(今回は未使用) |
Options | ー | Options | 様々なネットワーク環境情報を載せる |
Optionsについて
Optionsについては重要なもののみ抽出したものを以下にまとめます。
なお、オプション領域の最初には Magic Cookie = 0x63 0x82 0x53 0x63 が入ります。この Magic Cookie によって受信データが DHCP であることが分かります。
また、各オプションデータのフォーマットはまず初めにオプションの識別子、データサイズ、実際のデータとなります。
例 (Message TypeがDiscoverのOption):0x35 0x01 0x01
識別子 | オプション名 | 概要 |
53 | Message Type | Discover/Offer/Request/ACK 等のメッセージタイプ 0x01:DHCP DISCOVER (発見) 0x02:DHCP OFFER (提示) 0x03:DHCP REQUEST (要求) 0x04:DHCP DECLINE (辞退) 0x05:DHCP ACK (承認) 0x06:DHCP NAK (拒否) 0x07:DHCP RELEASE (解放) 0x08:DHCP INFORM (情報) 0x09:DHCP FORCERENEW (強制再取得) |
55 | Parameter Request List | Discover において、クライアントがサーバに要求するオプションを示す サーバは必ずすべての要求にこたえる必要はない |
1 | Subnet Mask | 払い出し IP (yiaddr)における、サブネットマスク |
3 | Router | デフォルトゲートウェイの IP アドレス |
6 | DNS Server | DNS サーバのIPアドレス |
12 | Hostname | クライアントのホスト名 |
15 | Domain Name | クライアントの所属するドメイン |
28 | Broadcast Address | ブロードキャスト・アドレス |
50 | Address Request | クライアントがリクエストするIPアドレス |
51 | Address Time | IPアドレス・リース期間 |
54 | DHCP Server Id | DHCPサーバ・アドレス |
255 | End | オプションの終了位置を示す |
IPアドレスのリース期間について
DHCPサーバーから割り当てられるIPアドレスには有効期限が存在します。
この有効期限のことをリース期間といいます。
例えば以下wiresharkによるキャプチャの場合、DHCPクライアントはDHCPサーバよりリース期間7200秒でIPアドレスを取得しています。その後、リース期間の半分である3600秒後にリース期間の延長を要求し、DHCPサーバからのACKを取得しています。
DHCPサーバからの応答がない場合は、延長要求を繰り返し実施しますが、リース期間を満了した場合、事前割り当てIPアドレスを破棄しなければなりません。
コード
最終的なDHCPサーバコードは以下にあります。(詳細については関連記事参照)