🛠️

忙しい人向けのつまみ食いDHCP

2022/08/01に公開

はじめに

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:初めて借りる場合

  1. クライアントはサブネット内にDHCPDISCOVERをブロードキャストで送信します。
    ※クライアント目線では、サーバがいるかどうかはこの時点ではわかっていません。
    ※リレーエージェントがいれば別のサブネットにも拡散してくれると思います。
  2. サーバはクライアントのDHCPDISCOVERに対してDHCPOFFERで応答します。
    ※ブロードキャストで送信するパターンとユニキャストで送信するパターンがあります。
    ※クライアントがflagsフィールドのブロードキャストビットを1にしていたらブロードキャスト
  3. クライアントはDHCPOFFERを受信したらサーバに対して
    DHCPREQUESTをブロードキャストで送信します。
  4. サーバはクライアントのDHCPREQUESTに対して、
    貸し出すアドレスが他で使われていなかったらDHCPACKで応答します。
    使われていたらDHCPNAKで応答します。
    ※使用中かどうかの確認には例えばICMP Echo(いわゆるping)などが使われます。
  5. クライアントはDHCPACKに含まれるIPアドレスやサブネットマスクで設定を行います。
    ※このとき、アドレスが使用中でないことを確認するためにARPリクエストを送信します。
  6. アドレスが使用中でないならばクライアントは通信を開始することができます。
    不幸にも使用中であった場合、サーバにDHCPDECLINEを送信して手順1からやり直します。
  7. クライアントは借用期限が近くなって延長したい場合、
    サーバに対してDHCPREQUESTをユニキャストで送信します。
  8. サーバはクライアントに対してDHCPACKをユニキャストで送信します。
    ※許可しない場合はあまりイメージないので、許可されると思います。
    ※許可された場合は手順7と8の繰り返しになります。
    ※許可してもしなくてもサーバはDHCPACKを送信すべきとなっています。
  9. クライアントはユニキャストのDHCPREQUESTに対するサーバのDHCPACKが届かず、
    借用期限がさらに迫ってきた場合はDHCPREQUESTをブロードキャストで送信します。
  10. それでもDHCPACKを受け取れずに借用期限が切れてしまった場合、手順1に戻ります。
  11. クライアントは借用しているIPアドレスが不要になった場合、
    サーバにDHCPRELEASEを送信してアドレスを返却します。
    ※サーバはDHCPRELEASEの有無に関係なく動作するように実装しなくてはなりません。
    ※だからぶっちゃけDHCPRELEASEは送信しなくても問題にはならないはずです。

パターンB:以前借りたことがある場合

  1. クライアントが以前借りたアドレスを覚えていて、再度同じアドレスを借りたい場合は
    DHCPREQUESTをブロードキャストで送信するところから始まります。
    ※このとき、以前借りた(と思っている)アドレスをDHCPREQUESTに含めます。
    ※DHCPDISCOVERは省略されるのでパケットキャプチャ等で見つかりません。
  2. サーバは問題なければユニキャストの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