クイックスタート(5分):Ubuntu/Debianでdhcrelayを稼働させる
マルチVLAN環境では、DHCP検出用のブロードキャストはレイヤー3の境界で完全にブロックされます。ルーターがこれらを意図的に破棄するためです。しかし、20ものVLANそれぞれで独立したDHCPデーモンを運用するのは管理の悪夢ですし、すべての場所にヘルパーアドレス内蔵のL3スイッチを導入するのはコストが跳ね上がります。Linuxルーターなら、この課題を簡単に解決できます。クライアントからのブロードキャストを傍受し、中央のDHCPサーバーへユニキャストとして直接転送します。
ここでは、2つのVLANサブインターフェース(eth1.10およびeth1.20)からのリクエストを、192.168.10.50にある中央のKeaまたはISCサーバーへ転送する最小限のリレーを構築します。
# 1. ISC DHCPリレーのインストール
sudo apt update && sudo apt install -y isc-dhcp-relay
# 2. カーネルのIPv4パケットフォワーディングを有効化
sudo sysctl -w net.ipv4.ip_forward=1
# 3. 疎通テスト用に手動でdhcrelayを起動
sudo dhcrelay -d -4 -i eth1.10 -i eth1.20 192.168.10.50
ターミナルでこのコマンドを実行したままにしておきます。これで、VLAN 10または20でブロードキャストしている任意のワークステーションからのリクエストが、ユニキャストUDPパケットとして192.168.10.50:67へ転送されるようになります。クライアントマシンでIPリースをテストしてください。正常に動作したらCtrl+Cを押し、次回の再起動後もサービスが維持されるようsystemdの設定に進みます。
詳細解説:VLANインターフェース間でのdhcrelayの動作メカニズム
リレーのトラブルシューティングを的確に行うには、バイトレベルでパケットの挙動を追跡する必要があります。クライアントは未設定のネットワークスタックから処理を開始し、送信元IP 0.0.0.0:68から宛先255.255.255.255:67に向けてDHCPDISCOVERをブロードキャストします。通常の環境では、ブロードキャストストームを防ぐため、Linuxはインターフェースの境界でこのブロードキャストを破棄します。
リレーメカニズムとGIADDRフィールド
dhcrelayがサブインターフェースをリッスンしていると、カーネルがパケットを破棄する前に受信UDPポート67のフレームをキャプチャします。単にパケットをミラーリングするのではなく、次の2つの重要な変更を加えてペイロードを書き換えます。
- DHCPペイロード内のgiaddr(ゲートウェイIPアドレス)フィールドに、該当のVLANインターフェースにバインドされたIP(例:
eth1.10なら10.0.10.1)を格納します。 - リクエストを標準のユニキャストUDPデータグラムにカプセル化します。送信元IPはリレーのローカルインターフェースIPとなり、宛先は中央のDHCPサーバー(
192.168.10.50)になります。
アップストリームサーバーは完全にgiaddrを頼りに動作します。これがないと、サーバーはクライアントがどのサブネットに属しているかを特定できません。10.0.10.1を読み取ったサーバーは、一致する10.0.10.0/24プールから利用可能なリースを払い出します。そして、10.0.10.1:67宛てにDHCPOFFERをユニキャストで返送します。最後に、dhcrelayがこのオファーを展開し、VLAN 10上のクライアントのハードウェアMACアドレスへ配信します。
Systemdによる永続設定
DebianおよびUbuntuでは、/etc/default/isc-dhcp-relayを介して永続的なリレーパラメータを管理します。クライアント側のVLANと、アップストリームサーバー側のインターフェースの両方を指定する必要がある点に注意してください。
# /etc/default/isc-dhcp-relay
# アップストリームDHCPサーバー
SERVERS="192.168.10.50"
# リッスン対象インターフェース(クライアント側のサブインターフェース + アップストリーム側の送信インターフェース)
INTERFACES="eth1.10 eth1.20 eth0"
# デーモンの起動フラグ
OPTIONS=""
ファイルを保存したら、systemdユニットを再起動してステータスを確認します。
sudo systemctl restart isc-dhcp-relay
sudo systemctl status isc-dhcp-relay
高度な運用:Option 82と冗長DHCPクラスタ
基本的なgiaddrルーティングは、サーバーにどのサブネットを使用すべきかを伝えます。しかし、リクエストの背後にある特定のスイッチポート、ラック、またはテナントインターフェースまでは識別できません。高密度なデプロイ環境では、DHCP Option 82とサーバーのクラスタ化によってこの課題を解決します。
Option 82(Circuit IDおよびRemote ID)の有効化
Option 82は、DHCPパケットをアップストリームへルーティングする前に、ベンダー固有のトラッキングデータをパケットに追加します。このデータには、物理インターフェース名やカスタムのサーキット識別子が含まれます。-aフラグを使用することで有効化できます。
# /etc/default/isc-dhcp-relay 内の設定
OPTIONS="-a -m replace"
-m replaceパラメータは極めて重要な保護機能です。万が一侵害されたマシンが偽装されたOption 82タグを挿入してきた場合でも、リレーはそれを除去し、検証済みのローカルインターフェースメタデータに置き換えます。ISC KeaやFreeRADIUSでは、これらのCircuit IDと照合して厳格な固定IPポリシーや動的なファイアウォールアクセスコントロールリスト(ACL)を適用できます。
複数のDHCPサーバーへのリレー
本番環境において、単一のDHCPデーモンに依存すべきではありません。朝のリース更新ラッシュ時にクラッシュが発生すると、数百台のデバイスに影響が及びます。dhcrelayは、ディスカバリパケットを複数のアップストリームターゲットに複製することでフェイルオーバーを実現します。
SERVERS="192.168.10.50 192.168.20.50"
リレーは、まったく同一のユニキャストパケットを両方のサーバーに同時に送信します。先に応答したサーバーの処理が優先されます。クライアントは最初のDHCPOFFERを受け入れ、DHCPREQUESTを送信して確定させ、遅れて届いた応答は無視します。これにより、カーネルパッチ適用のために片方のサーバーが再起動している間でも、IPプロビジョニングは停止しません。
本番環境向けの強化とトラブルシューティング
以下は、40以上のVLANと数千の同時DHCPリースを処理するコアLinuxルーターを安定して稼働させ続けるための実践的なプラクティスです。
1. tcpdumpによるパケットパスの追跡
クライアントがリースを取得できない場合、やみくもに設定ファイルを変更してはいけません。リレーマシン上でtcpdumpを実行し、ハンドシェイクの各段階を確実に検証します。
# 詳細出力付きですべてのインターフェースのDHCPトラフィックを監視
sudo tcpdump -env -n -i any port 67 or port 68
正常なハンドシェイクでは、次のような整然としたシーケンスが確認できます。まずeth1.10でブロードキャストのDHCPDISCOVERを受信し、即座に192.168.10.50へのユニキャストが送信され、続いてeth0でDHCPOFFERを受信します。
2. ファイアウォールの注意点(iptablesとnftables)
導入失敗の原因として最も多いのが、ホストのファイアウォールによってブロードキャストUDPフレームがサイレントにドロップされることです。包括的なドロップルールを処理する前に、INPUTチェーンでDHCPを明示的に許可する必要があります。
# ローカルリレーソケットでのDHCPトラフィックを許可
sudo iptables -A INPUT -p udp -m multiport --dports 67,68 -j ACCEPT
# アクティブな接続に対するカーネルルーティングを維持
sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
3. ARPキャッシュの枯渇防止
クライアントの出入りが激しい環境では、ARPキャッシュの入れ替わりが頻繁になります。DHCP応答が完了する前にカーネルが期限切れのMACエントリを破棄してしまうと、リレーはオファーを届けることができなくなります。リースが滞った際は、近隣探索テーブルを確認してください。
ip neighbor show dev eth1.10
短時間のみ接続されるデバイスが数百台存在するネットワーク(公衆Wi-Fiや動的な検証ラボなど)では、/etc/sysctl.d/99-arp.confでカーネルの近隣探索しきい値を引き上げ、net.ipv4.neigh.default.gc_thresh1 = 1024およびgc_thresh2 = 2048に設定します。これにより、トラフィックのピーク時におけるサイレントなパケットドロップを防ぐことができます。

