DHCPリレーエージェントとは
DHCPのDISCOVERは宛先IPアドレスを 255.255.255.255、宛先MACアドレスをブロードキャストとして送信されます。ルータはブロードキャストを転送しないため、クライアントとDHCPサーバーが別のセグメントにいる場合、そのままではDISCOVERがサーバーに届きません。
セグメントごとにDHCPサーバーを設置すれば解決しますが、拠点やVLANの数だけサーバーが必要になり現実的ではありません。そこで、クライアント側のセグメントに接続しているルータがブロードキャストを代理で受け取り、ユニキャストに変換して別セグメントのDHCPサーバーへ転送します。この機能をDHCPリレーエージェントと呼びます。
リレーエージェントの動作はRFC 2131で規定されており、BOOTPリレーとしての詳細な要件はRFC 1542で定義されています。DHCPがBOOTPのメッセージフォーマットを引き継いでいるのと同様に、リレーの仕組みもBOOTPリレーエージェントから引き継いだものです。
giaddrの役割
リレーエージェントの動作を理解する鍵が、DHCPメッセージのgiaddr(Gateway IP Address)フィールドです。
| フィールド | クライアントが送信した時点 | リレーエージェント通過後 |
|---|---|---|
giaddr | 0.0.0.0 | リレーエージェントがクライアント側インターフェースのIPアドレスを書き込む |
hops | 0 | リレーエージェントを経由するたびに1ずつ加算される |
| 宛先IPアドレス | 255.255.255.255 | DHCPサーバーのIPアドレス(ユニキャスト) |
| 送信元IPアドレス | 0.0.0.0 | リレーエージェントのIPアドレス |
giaddrは単なる「経由地の記録」ではなく、サーバーがどのプールからアドレスを払い出すかを決めるための情報です。サーバーは受け取ったメッセージのgiaddrを見て、そのアドレスが含まれるサブネットに対応するプールを選びます。リレーエージェントのクライアント側インターフェースが 192.168.20.1/24 であれば、giaddrにはこの値が入るため、サーバーは 192.168.20.0/24 のプールからアドレスを割り当てます。
また、サーバーからの応答(OFFER・ACK)はgiaddr宛てにユニキャストで返されます。リレーエージェントはそれを受け取り、クライアントへ転送します。サーバーはクライアントの位置を知る必要がなく、giaddrだけを見て応答を返せばよいという設計になっています。
hopsはリレーを経由した回数で、ループ防止のために使われます。RFC 1542はリレーエージェントに対し、hopsが4を超えたメッセージを破棄することを推奨しています。通常の構成でリレーを何段も経由することはないため、この値は1のままであることがほとんどです。リレー経由時のパケットの流れ
クライアント(192.168.20.0/24)、リレーエージェントR1、DHCPサーバー(10.1.2.2)という構成でDORAが行われる場合の流れです。
sequenceDiagram
participant C as クライアント
192.168.20.0/24
participant R as R1(リレー)
Gi1: 192.168.20.1
Gi2: 10.1.2.1
participant S as DHCPサーバー
10.1.2.2
C->>R: ① DISCOVER(ブロードキャスト)
宛先: 255.255.255.255
giaddr = 0.0.0.0、hops = 0
Note over R: giaddrに192.168.20.1を書き込み
hopsを1に加算
ユニキャストへ変換
R->>S: ② DISCOVER(ユニキャスト)
10.1.2.1 → 10.1.2.2
giaddr = 192.168.20.1、hops = 1
Note over S: giaddrが192.168.20.1なので
192.168.20.0/24のプールを選択
S->>R: ③ OFFER(ユニキャスト)
宛先: giaddr = 192.168.20.1
yiaddr = 192.168.20.101
R->>C: ④ OFFER(ブロードキャスト)
クライアント側セグメントへ転送
Note over C,S: REQUEST / ACK も同じ経路をたどる
- クライアントは通常どおりDISCOVERをブロードキャストで送信する。リレーエージェントがいることをクライアントは意識しない。
- R1はGigabitEthernet1でこれを受信し、
giaddrに受信インターフェースのIPアドレス(192.168.20.1)を書き込み、hopsを1に加算したうえで、ip helper-addressで指定されたサーバーへユニキャストで転送する。 - サーバーは
giaddrから要求元のセグメントを判断し、対応するプールからアドレスを選んでOFFERをgiaddr宛てにユニキャストで返す。 - R1はOFFERを受け取り、クライアント側セグメントへ転送する。クライアントはアドレスをまだ持たないため、通常はブロードキャストで転送される。
REQUESTとACKも同じ経路をたどります。クライアントとサーバーのどちらもリレーの存在を特別扱いしておらず、giaddrというフィールド1つで成り立っている点がこの仕組みの要です。
ip helper-address による設定
Cisco IOS / IOS XEでは、クライアント側のインターフェースにip helper-addressを設定してリレーエージェントを有効にします。サーバー側のインターフェースではない点に注意が必要です。
interface GigabitEthernet1
description to client segment
ip address 192.168.20.1 255.255.255.0
ip helper-address 10.1.2.2DHCPサーバーが複数ある環境では、ip helper-addressを複数行書くことですべてのサーバーへ転送できます。
サーバー側には、クライアントのセグメント宛ての戻り経路が必要です。OFFERやACKはgiaddr(192.168.20.1)宛てに返されるため、サーバーがそのアドレスへ到達できなければリレーは成立しません。
ip helper-addressはDHCP以外のUDPブロードキャストも転送します。 Cisco IOSは既定で次の8つのサービスを転送対象としています。
| ポート | サービス |
|---|---|
| 37 | TIME |
| 49 | TACACS |
| 53 | DNS |
| 67 | BOOTP / DHCP サーバー |
| 68 | BOOTP / DHCP クライアント |
| 69 | TFTP |
| 137 | NetBIOS ネームサービス |
| 138 | NetBIOS データグラムサービス |
DHCPだけを転送したい場合は、不要なものをno ip forward-protocol udp <ポート番号>で個別に無効化します。意図せずDNSやNetBIOSのブロードキャストまで別セグメントへ転送してしまうと、不要なトラフィックやセキュリティ上の問題につながります。
Option 82(Relay Agent Information)
Option 82は、リレーエージェントがDHCPメッセージに付加する情報で、RFC 3046で定義されています。「どのリレーエージェントの、どのポート(回線)から来た要求か」をサーバーに伝えるためのもので、内部にサブオプションを持ちます。
| サブオプション | 名称 | 内容 |
|---|---|---|
| 1 | Circuit ID | 要求を受け取った回線の識別子。物理ポート番号やVLAN IDなど |
| 2 | Remote ID | リレーエージェント自身の識別子。MACアドレスやホスト名など |
リレーエージェントはクライアントからのメッセージを転送する際にOption 82を挿入し、サーバーからの応答を受け取るとクライアントへ転送する前にOption 82を取り除きます。そのためクライアントはOption 82の存在を知りません。
サーバー側では、この情報を使って「特定のポートに接続された機器にだけ特定のアドレスを割り当てる」といったポリシーや、アドレス払い出しの監査ログに利用します。またスイッチのDHCP Snoopingと組み合わせることで、バインディングテーブルにポート情報を持たせられます。
Cisco IOS / IOS XEでは次のように設定します。
(リレーエージェント側)
ip dhcp relay information option
(DHCPサーバー側:giaddrが0のOption 82付きパケットも受け入れる場合)
ip dhcp relay information trust-allgiaddrが 0.0.0.0 のままOption 82が付いているメッセージを不正とみなして破棄します。これはリレーエージェントを経由していないのにOption 82が付いている、つまり詐称の可能性があるためです。スイッチのDHCP Snoopingがgiaddrを書き換えずにOption 82だけを挿入する構成では、サーバー側でip dhcp relay information trust-allが必要になります。実機での検証
R3(クライアント)・R1(リレーエージェント)・R2(DHCPサーバー)を別セグメントに分けて接続し、リレー経由でのアドレス取得を実機で確認しました。ルータはいずれもCisco IOS XE 17.03.08a(csr1000v)です。
キャプチャーを2箇所で同時に取得している点がこの検証の要です。同じメッセージがリレーの前後でどう変わるかを突き合わせられます。
R2(サーバー)には次のプールと戻り経路を設定しています。戻り経路が無いとOFFERをgiaddrへ返せず、リレーは成立しません。
ip dhcp excluded-address 192.168.20.1 192.168.20.100
!
ip dhcp pool LAN20
network 192.168.20.0 255.255.255.0
default-router 192.168.20.1
dns-server 10.1.2.2
domain-name kazulog.example
lease 0 0 2
!
ip route 192.168.20.0 255.255.255.0 10.1.2.1R1(リレー)はクライアント側のGigabitEthernet1にip helper-addressを設定しています。
interface GigabitEthernet1
description to R3 Gi1 (client segment / capture A)
ip address 192.168.20.1 255.255.255.0
ip helper-address 10.1.2.2検証の流れとサーバー側カウンタの推移
| STEP | 操作 | R3のGi1 | DISCOVER受信 | OFFER送信 | REQUEST受信 | ACK送信 |
|---|---|---|---|---|---|---|
| 0 | 初期状態(R3のGi1はshutdown) | unassigned | 0 | 0 | 0 | 0 |
| 1 | R3のGi1をno shutdown | 192.168.20.102 | 1 | 1 | 1 | 1 |
| 2 | T1(60秒)の発火を2回待つ | 192.168.20.102 | 1 | 1 | 3 | 3 |
| 3 | R1からip helper-addressを削除しrelease/renew | unassigned | 1 | 1 | 3 | 3 |
| 4 | ip helper-addressを戻してrenew | 192.168.20.103 | 2 | 2 | 5 | 5 |
| 5 | Option 82を有効化してrelease/renew | 192.168.20.104 | 3 | 3 | 7 | 7 |
STEP 3に注目してください。 クライアントはアドレスを取得できずunassignedのままで、サーバー側のDISCOVER受信カウンタも1から動いていません。ip helper-addressを外したことで、DISCOVERがサーバーまで届かなくなったことが数字で確認できます。
同じDISCOVERがリレーの前後でどう変わるか
STEP 1で発生したDORAを、2つのキャプチャーで並べます。まずクライアント側です。
1 0.000000 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x26d1
2 0.021989 52:54:00:86:de:30 → Broadcast ARP 60 Who has 192.168.20.102? Tell 192.168.20.1
3 2.051454 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP Offer - Transaction ID 0x26d1
4 2.057779 0.0.0.0 → 255.255.255.255 DHCP 375 DHCP Request - Transaction ID 0x26d1
5 2.070234 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP ACK - Transaction ID 0x26d1続いてサーバー側です。同じTransaction ID 0x26d1のやり取りですが、すべてユニキャストになっています。
1 0.000000 192.168.20.1 → 10.1.2.2 DHCP 357 DHCP Discover - Transaction ID 0x26d1
2 2.038251 10.1.2.2 → 192.168.20.1 DHCP 372 DHCP Offer - Transaction ID 0x26d1
3 2.053646 192.168.20.1 → 10.1.2.2 DHCP 375 DHCP Request - Transaction ID 0x26d1
4 2.060189 10.1.2.2 → 192.168.20.1 DHCP 372 DHCP ACK - Transaction ID 0x26d1DISCOVERの中身を比較すると、リレーエージェントが書き換えたフィールドがはっきりします。左がクライアント側、右がサーバー側です。
Source Address: 0.0.0.0
Destination Address: 255.255.255.255
Dynamic Host Configuration Protocol (Discover)
Message type: Boot Request (1)
Hops: 0
Transaction ID: 0x000026d1
Bootp flags: 0x8000, Broadcast flag (Broadcast)
Client IP address: 0.0.0.0
Your (client) IP address: 0.0.0.0
Next server IP address: 0.0.0.0
Relay agent IP address: 0.0.0.0
Client MAC address: 52:54:00:49:49:5a (52:54:00:49:49:5a) Source Address: 192.168.20.1
Destination Address: 10.1.2.2
Dynamic Host Configuration Protocol (Discover)
Message type: Boot Request (1)
Hops: 1
Transaction ID: 0x000026d1
Bootp flags: 0x8000, Broadcast flag (Broadcast)
Client IP address: 0.0.0.0
Your (client) IP address: 0.0.0.0
Next server IP address: 0.0.0.0
Relay agent IP address: 192.168.20.1
Client MAC address: 52:54:00:49:49:5a (52:54:00:49:49:5a)| フィールド | クライアント側 | サーバー側 |
|---|---|---|
| 送信元IPアドレス | 0.0.0.0 | 192.168.20.1(リレーのアドレス) |
| 宛先IPアドレス | 255.255.255.255 | 10.1.2.2(サーバーのアドレス) |
Hops | 0 | 1 |
Relay agent IP address(giaddr) | 0.0.0.0 | 192.168.20.1 |
Transaction ID | 0x000026d1 | 0x000026d1(同じ) |
Client MAC address | 52:54:00:49:49:5a | 52:54:00:49:49:5a(同じ) |
前述のとおり、リレーエージェントはIPパケットとしては新しく作り直しつつ、DHCPメッセージの中身はgiaddrとhops以外そのまま引き継いでいます。Transaction IDとClient MAC addressが変わらないため、サーバーはクライアントを正しく識別でき、応答もクライアントに対応付けられます。
クライアント側から見ると、OFFERとACKの送信元は192.168.20.1、つまりリレーエージェントです。クライアントにとってはリレーがDHCPサーバーのように見えている一方、クライアントが受け取ったOption 54(Server Identifier)は実際のサーバーのアドレスになっています。
R3#show dhcp lease
Temp IP addr: 192.168.20.102 for peer on Interface: GigabitEthernet1
Temp sub net mask: 255.255.255.0
DHCP Lease server: 10.1.2.2, state: 5 Bound
DHCP transaction id: 26D1
Lease: 120 secs, Renewal: 60 secs, Rebind: 105 secs
Temp default-gateway addr: 192.168.20.1
Next timer fires after: 00:00:17
Retry count: 0 Client-ID: cisco-5254.0049.495a-Gi1
Hostname: R3DHCP Lease serverが自セグメント外の10.1.2.2、default-gatewayがリレー側の192.168.20.1と、参照先が分かれている点がリレー構成ならではです。
リース更新はリレーを経由しない
T1(60秒)の満了で行われた更新です。添付のクライアント側キャプチャーのNo.10・No.11にあたります。
10 66.279226 192.168.20.102 → 10.1.2.2 DHCP 363 DHCP Request - Transaction ID 0x26d1
11 66.285223 10.1.2.2 → 192.168.20.102 DHCP 372 DHCP ACK - Transaction ID 0x26d1送信元はクライアント自身の192.168.20.102、宛先はサーバーの10.1.2.2です。リレーエージェントのアドレスは現れません。この2パケットはgiaddrも0.0.0.0のままで、hopsも0です。前述のとおり、更新はブロードキャストではなくサーバー宛てのユニキャストなので、リレーの処理を通らず通常のルーティングでR1を通過していることが確認できます。
同じパケットはサーバー側のキャプチャーにも現れます。リレーが転送しているのではなく、R1がルータとして中継しているだけです。
ip helper-address を外すとどうなるか
STEP 3でR1のGigabitEthernet1からip helper-addressを削除し、R3でアドレスを取り直させました。
16 179.110077 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439
17 182.335039 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439
18 186.335474 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439クライアントは同じxidで3回再送し、その後xidを変えてさらに繰り返しています。クライアント側キャプチャーにはこれらのDISCOVERが9パケット記録されている一方、サーバー側キャプチャーには1パケットも現れません。
| キャプチャー | STEP 3のDISCOVER(xid 0x1439 / 0x143a / 0x143b) |
|---|---|
| A(クライアント側) | 9パケット |
| B(サーバー側) | 0パケット |
このときR1ではshow ip helper-addressの一覧が空になっています。
R1#show ip helper-address
Interface Helper-Address VPN VRG Name VRG Stateリンクはupのままなのにアドレスが取得できず、サーバー側のカウンタも動かない。ブロードキャストがルータを越えていないことが、この3点から確認できます。STEP 4でip helper-addressを戻すと、DISCOVER受信カウンタが1から2に増えて復旧しました。
Option 82 の実際
STEP 5でR1にip dhcp relay information option、R2にip dhcp relay information trust-allを設定し、アドレスを取り直しました。サーバー側のキャプチャーではパケットが大きくなっています。
21 387.544996 192.168.20.1 → 10.1.2.2 DHCP 373 DHCP Discover - Transaction ID 0xfb5
22 389.551056 10.1.2.2 → 192.168.20.1 DHCP 388 DHCP Offer - Transaction ID 0xfb5
23 389.561390 192.168.20.1 → 10.1.2.2 DHCP 391 DHCP Request - Transaction ID 0xfb5
24 389.567012 10.1.2.2 → 192.168.20.1 DHCP 388 DHCP ACK - Transaction ID 0xfb5DISCOVERは373バイトで、Option 82が無いSTEP 1のDISCOVER(357バイト)より16バイト大きくなっています。中身は次のとおりです。
Option: (82) Agent Information Option
Length: 14
Option 82 Suboption: (2) Agent Remote ID
Length: 12
Agent Remote ID: 020a0000c0a8140100000000
Option: (255) End020a0000c0a8140100000000のうちc0a81401はリレーエージェントのインターフェースアドレス192.168.20.1です。Option 82に何を入れるかは実装と構成に依存し、スイッチのDHCP Snoopingのようにポートによる区別がある環境ではCircuit IDも挿入されます。ルータ間のリレーでは区別すべき「回線」が無いため、Remote IDのみになったと考えられます。一方、同じやり取りをクライアント側のキャプチャーで見るとOption 82は現れません。
42 387.547323 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0xfb5
43 387.559201 52:54:00:86:de:30 → Broadcast ARP 60 Who has 192.168.20.104? Tell 192.168.20.1
44 389.562682 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP Offer - Transaction ID 0xfb5
45 389.566898 0.0.0.0 → 255.255.255.255 DHCP 375 DHCP Request - Transaction ID 0xfb5
46 389.577910 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP ACK - Transaction ID 0xfb5DISCOVERは357バイトのままで、OFFERとACKも372バイトです。リレーエージェントがクライアントへ転送する前にOption 82を取り除いているため、クライアントはOption 82の存在を知りません。前述の説明どおりの動作が、パケットサイズの差としてそのまま観測できます。
キャプチャーA(クライアント側)の全体をダウンロード
キャプチャーB(サーバー側)の全体をダウンロード
検証Configおよびshow結果
各STEPでR1・R2・R3から、次の3種類をルータごとに分けて取得しています。検証Configはこの..._run.txtです(最終状態はSTEP 5のもの)。
| ファイル | 内容 |
|---|---|
..._show.txt | show version / show interfaces description / show ip interface brief / show ip route / show arp / show ip helper-address / show ip dhcp pool / show ip dhcp binding / show ip dhcp server statistics / show ip dhcp conflict / show ip dhcp relay information trusted-sources / show dhcp lease |
..._log.txt | そのSTEPの範囲だけに絞ったshow logging。各STEPの開始時にsend logでマーカーを入れ、その文字列をshow logging | beginに指定して取得したもの |
..._run.txt | そのSTEP時点のshow running-config(=そのSTEPの検証Config) |
STEP 0:初期状態(R3のGi1はshutdown)
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
STEP 1:R3のGi1をno shutdownし、リレー経由でアドレスを取得した状態
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
STEP 2:T1の満了によりリースが2回更新された状態
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
STEP 3:R1からip helper-addressを削除し、アドレスを取得できなくなった状態
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
STEP 4:ip helper-addressを戻して復旧した状態
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
STEP 5:Option 82を有効化した状態(最終状態)
| ノード | show出力 | syslog | running-config |
|---|---|---|---|
| R1(リレー) | show | log | run |
| R2(サーバー) | show | log | run |
| R3(クライアント) | show | log | run |
参考
| RFC | タイトル | 概要 |
|---|---|---|
| RFC 2131 | Dynamic Host Configuration Protocol | giaddrとhopsの扱い、リレーエージェントの基本動作を定義。 |
| RFC 1542 | Clarifications and Extensions for the Bootstrap Protocol | BOOTPリレーエージェントの詳細な要件。hopsの上限などを規定。 |
| RFC 3046 | DHCP Relay Agent Information Option | Option 82とサブオプション(Circuit ID / Remote ID)を定義。 |