DHCPによるアドレス割り当てとリース更新
メッセージの欄と時刻から、割当てと更新の状態を確認します。
説明
DHCPはIPアドレスと関連設定を一定期間貸し出します。初めて取得するときと、取得済みのアドレスを更新するときでは、同じメッセージ名でも送信先や欄の内容が違います。
四つの交換をPCAPで確認し、XID、Requested IP、Server Identifier、リース時間をバイト列で照合します。続いてT1・T2・期限と更新の交換を調べ、新しい期限を計算します。
1割当ての四つのメッセージ
端末MAC末尾0aが新たにIPv4アドレスを取得する交換を表示します。
tcpdump -n -tt -vvv種類・送受信先・オプション -r allocation.pcap割当ての交換Discover、Offer、Request、ACKの順です。端末はアドレス未設定のため0.0.0.0から送信し、この例ではbroadcastフラグに合わせて応答もブロードキャストされています。すべての場面で応答が必ずブロードキャストになるわけではありません。
2同じ取引を識別するXID
要求とACKの固定部分からXID、yiaddr、クライアントMACを取り出します。
python3 -c固定部分の対応を確認 'from pathlib import Path; import socket; rows=[Path(n).read_bytes() for n in ("request.bin","ack.bin")]; print([(hex(int.from_bytes(b[4:8],"big")),socket.inet_ntoa(b[16:20]),b[28:34].hex(":")) for b in rows])'XID・割当てIP・MACXID0x3903f326とMACが対応しています。要求のyiaddrは0、ACKのyiaddrは割当てる192.0.2.10です。送信元IPだけでは未設定の端末を特定できないため、取引IDやクライアント識別情報を照合します。
3どの提案を選んだか
Requestのオプション部分を表示します。236バイトの固定部分と4バイトのcookieの後から始まります。
xxd -g 1 -s 236 -l 32固定部分の後の32バイト request.bin選択した提案63 82 53 63がcookieです。35 01 03はoption53・長さ1・DHCPREQUEST、32 04 c0 00 02 0aは要求IP192.0.2.10、36 04 c0 00 02 02は選んだサーバー192.0.2.2です。Offerが複数あっても、選択した相手をRequestで知らせます。
4ACKで受け取る設定
ACKのオプションを表示します。
xxd -g 1 -s 240 -l 60ACKのオプション ack.binリースと配布設定option51の00000e10はリース3600秒、58の00000708はT1=1800秒、59の00000c4eはT2=3150秒です。さらにサブネットマスク、ルーター、DNSのIPが続きます。IPアドレスだけでなく、通信に必要な設定を合わせて受け取ります。
5更新と再結合の時刻
このACKのT1・T2・リース期限を使い、取得後の経過時間で状態を分類します。
python3 -cT1・T2・期限を比較 't1,t2,lease=1800,3150,3600; print([(t,"BOUND" if t<t1 else "RENEWING" if t<t2 else "REBINDING" if t<lease else "EXPIRED") for t in (1700,1800,3200,3600)])'経過秒による状態T1で元のサーバーへ更新を試み、T2まで応答がなければ他のサーバーにも再結合を求めます。期限までACKが得られなければ、そのアドレスの使用を止めます。ここではACKに明示された時刻を使い、毎回同じ秒数が固定で使われるという意味ではありません。
6更新時は既にあるアドレスを使う
renewal.pcapは元のサーバーへのユニキャスト更新要求とACKです。
tcpdump -n -tt -vvv更新時の送受信先とciaddr -r renewal.pcapユニキャスト更新送信元192.0.2.10、宛先192.0.2.2で、ciaddrに現在のアドレスが入ります。最初の選択時と違い、この更新要求にはRequested IPとServer Identifierのオプションを入れません。DHCPREQUESTという種類が同じでも、状態によって欄の使い方が変わります。
7更新後の期限を求める
取得から1800秒で更新が成功し、新たに3600秒のリースを受け取ったとします。
python3 -c更新後の基準時刻を適用 'renewed_at=1800; lease=3600; print(renewed_at+lease); print(renewed_at+1800,renewed_at+3150)'新しい期限と更新開始時刻この例の新しい使用期限は元の時刻基準で5400秒、次のT1は3600秒、T2は4950秒です。最初の期限3600秒のままではなく、更新成功時の条件で管理し直します。
まとめ
同じ取引のXIDと端末情報を照合し、選択したサーバーと割当てIPを確認します。
T1・T2・リース期限と、更新成功後の期限を管理します。
操作履歴と解説を振り返れます。
シェル / PCAPと通信の記録
tcpdump -n -tt -vvv -r allocation.pcapreading from file allocation.pcap, link-type EN10MB (Ethernet)
0.000000 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto UDP (17), length 328)
0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from 02:00:00:00:00:0a, length 300, xid 0x3903f326, Flags [Broadcast] (0x8000)
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: Discover
END (255), length 0
PAD (0), length 0, occurs 56
0.010000 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 328)
192.0.2.2.67 > 255.255.255.255.68: [udp sum ok] BOOTP/DHCP, Reply, length 300, xid 0x3903f326, Flags [Broadcast] (0x8000)
Your-IP 192.0.2.10
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: Offer
Server-ID (54), length 4: 192.0.2.2
Lease-Time (51), length 4: 3600
RN (58), length 4: 1800
RB (59), length 4: 3150
Subnet-Mask (1), length 4: 255.255.255.0
Default-Gateway (3), length 4: 192.0.2.1
Domain-Name-Server (6), length 4: 192.0.2.53
END (255), length 0
PAD (0), length 0, occurs 14
0.020000 IP (tos 0x0, ttl 64, id 2, offset 0, flags [none], proto UDP (17), length 328)
0.0.0.0.68 > 255.255.255.255.67: [udp sum ok] BOOTP/DHCP, Request from 02:00:00:00:00:0a, length 300, xid 0x3903f326, Flags [Broadcast] (0x8000)
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: Request
Requested-IP (50), length 4: 192.0.2.10
Server-ID (54), length 4: 192.0.2.2
END (255), length 0
PAD (0), length 0, occurs 44
0.030000 IP (tos 0x0, ttl 64, id 3, offset 0, flags [none], proto UDP (17), length 328)
192.0.2.2.67 > 255.255.255.255.68: [udp sum ok] BOOTP/DHCP, Reply, length 300, xid 0x3903f326, Flags [Broadcast] (0x8000)
Your-IP 192.0.2.10
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: ACK
Server-ID (54), length 4: 192.0.2.2
Lease-Time (51), length 4: 3600
RN (58), length 4: 1800
RB (59), length 4: 3150
Subnet-Mask (1), length 4: 255.255.255.0
Default-Gateway (3), length 4: 192.0.2.1
Domain-Name-Server (6), length 4: 192.0.2.53
END (255), length 0
PAD (0), length 0, occurs 14python3 -c 'from pathlib import Path; import socket; rows=[Path(n).read_bytes() for n in ("request.bin","ack.bin")]; print([(hex(int.from_bytes(b[4:8],"big")),socket.inet_ntoa(b[16:20]),b[28:34].hex(":")) for b in rows])'[('0x3903f326', '0.0.0.0', '02:00:00:00:00:0a'), ('0x3903f326', '192.0.2.10', '02:00:00:00:00:0a')]xxd -g 1 -s 236 -l 32 request.bin000000ec: 63 82 53 63 35 01 03 32 04 c0 00 02 0a 36 04 c0 c.Sc5..2.....6.. 000000fc: 00 02 02 ff 00 00 00 00 00 00 00 00 00 00 00 00 ................
xxd -g 1 -s 240 -l 60 ack.bin000000f0: 35 01 05 36 04 c0 00 02 02 33 04 00 00 0e 10 3a 5..6.....3.....: 00000100: 04 00 00 07 08 3b 04 00 00 0c 4e 01 04 ff ff ff .....;....N..... 00000110: 00 03 04 c0 00 02 01 06 04 c0 00 02 35 ff 00 00 ............5... 00000120: 00 00 00 00 00 00 00 00 00 00 00 00 ............
python3 -c 't1,t2,lease=1800,3150,3600; print([(t,"BOUND" if t<t1 else "RENEWING" if t<t2 else "REBINDING" if t<lease else "EXPIRED") for t in (1700,1800,3200,3600)])'[(1700, 'BOUND'), (1800, 'RENEWING'), (3200, 'REBINDING'), (3600, 'EXPIRED')]
tcpdump -n -tt -vvv -r renewal.pcapreading from file renewal.pcap, link-type EN10MB (Ethernet)
0.000000 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto UDP (17), length 328)
192.0.2.10.68 > 192.0.2.2.67: [udp sum ok] BOOTP/DHCP, Request from 02:00:00:00:00:0a, length 300, xid 0x3903f326, Flags [none] (0x0000)
Client-IP 192.0.2.10
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: Request
END (255), length 0
PAD (0), length 0, occurs 56
0.010000 IP (tos 0x0, ttl 64, id 1, offset 0, flags [none], proto UDP (17), length 328)
192.0.2.2.67 > 192.0.2.10.68: [udp sum ok] BOOTP/DHCP, Reply, length 300, xid 0x3903f326, Flags [none] (0x0000)
Client-IP 192.0.2.10
Your-IP 192.0.2.10
Client-Ethernet-Address 02:00:00:00:00:0a
Vendor-rfc1048 Extensions
Magic Cookie 0x63825363
DHCP-Message (53), length 1: ACK
Server-ID (54), length 4: 192.0.2.2
Lease-Time (51), length 4: 3600
RN (58), length 4: 1800
RB (59), length 4: 3150
Subnet-Mask (1), length 4: 255.255.255.0
Default-Gateway (3), length 4: 192.0.2.1
Domain-Name-Server (6), length 4: 192.0.2.53
END (255), length 0
PAD (0), length 0, occurs 14python3 -c 'renewed_at=1800; lease=3600; print(renewed_at+lease); print(renewed_at+1800,renewed_at+3150)'5400 3600 4950
演習完了