pythonでDHCPサーバ作成 ~①DHCPとは~

DHCPサーバ作成,python

最近業務でDHCPに触れる機会があったので、pythonを使用して任意のIPアドレス解決を実施できるDHCPサーバツールを作成してみました。

DHCPとは

DHCP(Dynamic Host Configuration Protocol)は、自分が使うためのIPアドレスをDHCPサーバからもらうためのプロトコルです。

市販のルータにも該当の機能が備わっており、皆さんが普段使っているPCやスマホでも、知らないうちにDHCPを使っていたりします。

DHCP通信の流れは以下の通り。

送信フレーム送信元概要送信データ宛先
① DHCP DiscoverDHCPクライアント利用可能なDHCPサーバーを見つける為の、ブロードキャストメッセージ。ブロードキャスト
② DHCP OfferDHCPサーバサーバーからクライアントへの DHCPDISCOVER に対する応答。任意のクライアント
③ DHCP RequestDHCPクライアントクライアントからサーバーへの、次のいずれかのメッセージ
(a) サーバからのレスポンスに対するリクエスト
(b) リブート時などに、以前使用していたIPアドレスの正当性を確認
(c) IPアドレスの延長要求
ブロードキャスト
④ DHCP ACKDHCPサーバサーバーからクライアントへの要求受け入れメッセージ任意のクライアント
⑤ DHCP ReleaseDHCPクライアント事前に取得していた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)名称意味
op1Message Operation Codeop=1:DHCPクライアントからのメッセージ
op=2:DHCPサーバからのメッセージ
htype1Hardware Address Typehtype=1 : Ethernet 
hops1hopsDHCP サーバの中継回数(今回は0)
xid4Transaction IDDHCP クライアントが割り当てる 4 byte のランダム値
Discover/Offer/Request/ACK 等の流れで一貫して同じ値となる
secs2Seconds elapsed再リースの要求時に残り時間を設定
flags2flagsflags=0x0000 :DHCP クライアントへの応答にユニキャストを指定
flags=0x0001 :DHCP クライアントへの応答にブロードキャストを指定
ciaddr4Client IP AddressDHCP クライアントが再リース要求時、自身へ既に払い出されているIPアドレスを設定
yiaddr4Your IP AddressDHCP サーバが DHCP クライアントへ払い出す IP アドレスを設定
siaddr4Server IP AddressDHCP サーバのIPアドレス
giaddr4Gateway IP AddressDHCPリレーエージェントのIPアドレス
DHCPサーバはGIADDRを見てクライアントの所属するサブネットを識別する
chaddr16Client Hardware Addressクライアントの MAC アドレスを格納する
後ろ10byteは0パディング
sname64Server Nameオプションのサーバ ホスト名(今回は未使用)
file128fileブート ファイルの名前(今回は未使用)
OptionsOptions様々なネットワーク環境情報を載せる

Optionsについて

Optionsについては重要なもののみ抽出したものを以下にまとめます。

なお、オプション領域の最初には Magic Cookie = 0x63 0x82 0x53 0x63 が入ります。この Magic Cookie によって受信データが DHCP であることが分かります。

また、各オプションデータのフォーマットはまず初めにオプションの識別子、データサイズ、実際のデータとなります。
例 (Message TypeがDiscoverのOption):0x35 0x01 0x01

識別子オプション名概要
53Message TypeDiscover/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 (強制再取得)
55Parameter Request ListDiscover において、クライアントがサーバに要求するオプションを示す
サーバは必ずすべての要求にこたえる必要はない
1Subnet Mask払い出し IP (yiaddr)における、サブネットマスク
3Routerデフォルトゲートウェイの IP アドレス
6DNS ServerDNS サーバのIPアドレス
12Hostnameクライアントのホスト名
15Domain Nameクライアントの所属するドメイン
28Broadcast Addressブロードキャスト・アドレス
50Address RequestクライアントがリクエストするIPアドレス
51Address TimeIPアドレス・リース期間
54DHCP Server IdDHCPサーバ・アドレス
255Endオプションの終了位置を示す

IPアドレスのリース期間について

DHCPサーバーから割り当てられるIPアドレスには有効期限が存在します。

この有効期限のことをリース期間といいます。

例えば以下wiresharkによるキャプチャの場合、DHCPクライアントはDHCPサーバよりリース期間7200秒でIPアドレスを取得しています。その後、リース期間の半分である3600秒後にリース期間の延長を要求し、DHCPサーバからのACKを取得しています。

DHCPサーバからの応答がない場合は、延長要求を繰り返し実施しますが、リース期間を満了した場合、事前割り当てIPアドレスを破棄しなければなりません。

コード

最終的なDHCPサーバコードは以下にあります。(詳細については関連記事参照)

関連記事