忙しい人向けのつまみ食いDHCP
はじめに
DHCPのRFCを読んでみたのでDHCPを雑に説明する記事を書きました。
詳細に説明すると結構長くなりそうだったので、まずは要点を書くことを目的にしました。
この記事のターゲット
- まずはDHCPの概要を知りたい人
- DHCPでトラブっているけど、RFCで詳細を確認するのは嫌な人
- 急にDHCPの調査・デバッグをすることになってしかも期限まで時間がない人
制限
- ネットワーク内のDHCPサーバは1台しかいないことにします。
(ややこしくなるから通常は1台だけ立てるようにしている場合も多いはず。知らんけど。) - ルータで複数のサブネットをまたいだりせず、1つのLAN内を想定します。
面倒くさいのでリレーエージェントとやらの存在はなかったことにします。
DHCPとは
Dynamic Host Configuration Protocolの略です。
IPアドレスの設定とかを自動でやってくれます。
それ以外のこともたくさんできるけど、今回はIPアドレスの設定について扱います。
基本的な考え方としては
- DHCPサーバが複数のIPアドレスを管理します。(例:192.168.0.100 ~ 192.168.0.150など)
- IPアドレスを設定したい端末はDHCPサーバにお願いしてIPアドレスを「借用」します。
以降の説明を簡単にするため、この端末を「クライアント」と呼ぶことにします。 - クライアントは借用したIPアドレスを使用して通信をします。
- IPアドレスの借用には期限が存在します。(例:24時間など)
- 借用期限が切れたIPアドレスはDHCPサーバに返す必要があります。
- 借用期限の延長を申請することもできます。
- DHCPサーバ側の受信ポート番号は67で、クライアント側の受信ポート番号は68です。
メッセージフォーマット
フィールド説明
フィールド名 | フィールド長 | 説明 |
---|---|---|
op | 1 octet | 1=BOOTREQUEST(クライアントからサーバ) 2=BOOTREPLY(サーバからクライアント) |
htype | 1 octet | ハードウェアタイプ(Ethernetの場合は1) |
hlen | 1 octet | ハードウェアアドレスの長さ(Ethernetの場合は6) |
hops | 1 octet | 0 (リレーエージェントとやらに関係) |
xid | 4 octets | 通信開始時にクライアントがランダムに設定する番号 同じ値であるか確認することでクライアントとサーバは どの通信に関するメッセージであるかわかる ※例えばxid=1のDHCPDISCOVERに対する応答は xid=1のDHCPOFFERとなるし、 さらに続くDHCPREQUESTもxid=1となる |
secs | 2 octets | 最初のメッセージからの経過時間 |
flags | 2 octets | 最も左のビットがブロードキャストビット 残りはreservedで0 |
ciaddr | 4 octets | クライアントのIPアドレス ※ただしここが使われるのは一度IPアドレスを借用した後 |
yiaddr | 4 octets | サーバが提案するIPアドレス |
siaddr | 4 octets | サーバのIPアドレス |
giaddr | 4 octets | リレーエージェントとやらのIPアドレス ※今回はスルー |
chaddr | 16 octets | クライアントのハードウェアアドレス (Ethernetの場合はMACアドレス) |
sname | 64 octets | サーバのホスト名 ※今回はスルー |
file | 128 octets | ブートファイル名 ※今回はスルー |
option | 可変長 | オプション ※オプションなのに必須の項目もある |
オプション説明
まず、optionsフィールドの最初の4オクテットはそれぞれ順番に
0x63, 0x82, 0x53, 0x63が格納されます。この値をMagic Cookieと呼んだりします。
そして、オプションの種類(Type)、長さ(Length)、値(Value)が続きます。
この順番で並ぶデータ形式を、頭文字の省略でTLV形式なんて呼んだりもします。
必須オプションとしては例えばDHCP Message Typeがあります。
オプション名 ※データには含まれない |
Type | Length | Value |
---|---|---|---|
DHCP Message Type | 53 | 1 | 1~8 |
よく使われるオプションとしては以下のあたりではないでしょうか。
オプション名 ※データには含まれない |
Type | Length | Value | |||
---|---|---|---|---|---|---|
Subnet Mask | 1 | 4 | m1 | m2 | m3 | m4 |
requested IP address | 50 | 4 | a1 | a2 | a3 | a4 |
IP address lease time | 51 | 4 | t1 | t2 | t3 | t4 |
Server Identifier | 54 | 4 | a1 | a2 | a3 | a4 |
Renewal (T1) Time Value | 58 | 4 | t1 | t2 | t3 | t4 |
Renewal (T2) Time Value | 59 | 4 | t1 | t2 | t3 | t4 |
オプション名 ※データには含まれない |
Type | Length | value (addr1) |
(addr2) |
|||||
---|---|---|---|---|---|---|---|---|---|
Router | 3 | 4n (n>=1) |
a1 | a2 | a3 | a4 | a1 | a2 | ... |
Domain Name Server | 6 | 4n (n>=1) |
a1 | a2 | a3 | a4 | a1 | a2 | ... |
Network Time Protocol Servers | 42 | 4n (n>=1) |
a1 | a2 | a3 | a4 | a1 | a2 | ... |
最後には必ずendオプションが入ります。
endオプションともう1つpadオプションは特別で、Typeの部分しか存在しません。
Lengthの部分は存在しませんが、長さは1オクテットとして扱われます。
オプション名 ※データには含まれない |
Type | Length | Value |
---|---|---|---|
pad | 0 | ||
end | 255 |
実際にはもっと多くのオプションで構成されると思いますが、
例えばDHCP Message Type = 1だけをオプションに持つ場合の
optionsフィールドの並びは以下のようになることでしょう。
magic cookie | Message Type | Length | Value | End | Pad... | |||
---|---|---|---|---|---|---|---|---|
0x63 | 0x82 | 0x53 | 0x63 | 0x35 | 0x01 | 0x01 | 0xff | 0x0 |
RFCにはワードの境界まで埋めるとあるので、Padがいくつ続くかはシステム次第だと思います。ちなみに64bitのWindowsで試すとoptionsフィールドの大きさが52オクテットのとき、12オクテットのpaddingが続きました。1ワード8バイトだから4オクテット埋めて56オクテットだと思ったのですが。すみません勉強不足です。
DHCP Message Type
メッセージタイプ | 値 | 方向 | 説明 |
---|---|---|---|
DHCPDISCOVER | 1 | クライアントからサーバ | クライアント「サーバ誰かおらへん?」 |
DHCPOFFER | 2 | サーバからクライアント | サーバ「おるで。このアドレス貸せるで?」 |
DHCPREQUEST | 3 | クライアントからサーバ | クライアント「それ貸してや」 |
DHCPACK | 4 | サーバからクライアント | サーバ「ええで。ほれ。」 ※設定完了! |
DHCPNAK | 5 | サーバからクライアント | サーバ「あかんわ」 ※DHCPDISCOVERからやり直し |
DHCPDECLINE | 6 | クライアントからサーバ | クライアント「すでに使ってるやつおったで」 ※DHCPDISCOVERからやり直し |
DHCPRELEASE | 7 | クライアントからサーバ | クライアント「返すわ。ありがとう。」 |
DHCPINFORM | 8 | クライアントからサーバ | ※ちょっと特殊な用途なので今回はスルー |
DHCP通信手順
パターンA:初めて借りる場合
- クライアントはサブネット内にDHCPDISCOVERをブロードキャストで送信します。
※クライアント目線では、サーバがいるかどうかはこの時点ではわかっていません。
※リレーエージェントがいれば別のサブネットにも拡散してくれると思います。 - サーバはクライアントのDHCPDISCOVERに対してDHCPOFFERで応答します。
※ブロードキャストで送信するパターンとユニキャストで送信するパターンがあります。
※クライアントがflagsフィールドのブロードキャストビットを1にしていたらブロードキャスト - クライアントはDHCPOFFERを受信したらサーバに対して
DHCPREQUESTをブロードキャストで送信します。 - サーバはクライアントのDHCPREQUESTに対して、
貸し出すアドレスが他で使われていなかったらDHCPACKで応答します。
使われていたらDHCPNAKで応答します。
※使用中かどうかの確認には例えばICMP Echo(いわゆるping)などが使われます。 - クライアントはDHCPACKに含まれるIPアドレスやサブネットマスクで設定を行います。
※このとき、アドレスが使用中でないことを確認するためにARPリクエストを送信します。 - アドレスが使用中でないならばクライアントは通信を開始することができます。
不幸にも使用中であった場合、サーバにDHCPDECLINEを送信して手順1からやり直します。 - クライアントは借用期限が近くなって延長したい場合、
サーバに対してDHCPREQUESTをユニキャストで送信します。 - サーバはクライアントに対してDHCPACKをユニキャストで送信します。
※許可しない場合はあまりイメージないので、許可されると思います。
※許可された場合は手順7と8の繰り返しになります。
※許可してもしなくてもサーバはDHCPACKを送信すべきとなっています。 - クライアントはユニキャストのDHCPREQUESTに対するサーバのDHCPACKが届かず、
借用期限がさらに迫ってきた場合はDHCPREQUESTをブロードキャストで送信します。 - それでもDHCPACKを受け取れずに借用期限が切れてしまった場合、手順1に戻ります。
- クライアントは借用しているIPアドレスが不要になった場合、
サーバにDHCPRELEASEを送信してアドレスを返却します。
※サーバはDHCPRELEASEの有無に関係なく動作するように実装しなくてはなりません。
※だからぶっちゃけDHCPRELEASEは送信しなくても問題にはならないはずです。
パターンB:以前借りたことがある場合
- クライアントが以前借りたアドレスを覚えていて、再度同じアドレスを借りたい場合は
DHCPREQUESTをブロードキャストで送信するところから始まります。
※このとき、以前借りた(と思っている)アドレスをDHCPREQUESTに含めます。
※DHCPDISCOVERは省略されるのでパケットキャプチャ等で見つかりません。 - サーバは問題なければユニキャストのDHCPACKで、
問題があればブロードキャストのDHCPNAKで応答します。
以降はパターンAの手順5と同様です。
キャプチャしてみた
WiresharkでDHCPメッセージをキャプチャしてみました。
Transaction IDがxidフィールドのことですね。
この値が同じメッセージは一連のやりとりとして解釈されます。
おおー、Magic Cookieもあるし、DHCP Message Typeもある。ポート番号も67と68だ。
通信もDHCPDISCOVER、DHCPOFFER、DHCPREQUEST、DHCPACKの順になっていますね。
どうやら今回はパターンAのようです。
トラブりそうなところ
※個人の感想です。読んだ限りで起こりそうなトラブルを勝手に考えました。知らんけど。
- クライアントがDHCPDISCOVERを送信してくれません。
パターンBで省略されてるだけちゃうか? - DHCPOFFERは確かに送信されているのですが受信できません。
ブロードキャストビットを試してみ? - DHCPOFFERやDHCPACKが途中で消えます。
サブネットまたいだパターンは面倒くさいから考えとうない言うとるやろ。
どっかにリレーエージェントがおって悪さしてないか?
ブロードキャストビットをセットしたらうまくいくかもしれんで。 - DHCPNAKしか返ってきません。
サーバのIPアドレスとサーバが貸し出すIPアドレスの設定が食い違ってるとかないか?
サーバは192.168.0.1/24なのに貸し出すアドレスが192.168.1.100~192.168.1.150/24とか - なんか変なIPアドレスがついてまったくネットにつながりません。
DHCPサーバちゃんと生きとるか?
それか誰か勝手にDHCPサーバ立ててそいつが変なIP配ったりしとらんか?
DHCPサーバで遊ぶときは絶対に外部から独立したネットワークで遊ぶんやで。
おっちゃんとの約束やで。
RFC
RFC 2131 Dynamic Host Configuration Protocol
RFC 2132 DHCP Options and BOOTP Vendor Extensions
この記事の改版履歴
2022/08/01 初版
Discussion