
DHCP リクエストを傍受して、送信者に気付かれずにいくつかの DHCP オプションを追加したいと思ったことはありますか? おそらくないでしょう。しかし、もしその必要性が生じた場合、dhcpoptinj が役に立つでしょう(おそらく)。
DHCP リクエストを改変する理由はたくさん考えられますが、おそらく問題を解決するためにはもっと良い方法を探すべきでしょう。DHCP サーバー/クライアントにアクセスできず、その DHCP オプションを変更する必要がある場合、DHCP ソフトウェアの設定が難しい(またはやりたいことをサポートしていない)場合、非常に複雑または変わった設定をしている場合、あるいは単に特殊な形式や不正なオプションを送信してみたい場合などです。dhcoptinj が実際に役立つ可能性はわずかながらあります。
dhcpoptinj は netfilter キューに到着するパケットを待ち受けます。パケットが実際に BOOTP/DHCP パケットであることを確認し、そうであればオプションを注入します。IPv4 ヘッダーのチェックサムを再計算し、UDP チェックサムを無効にして(実装を簡略化するため)、パケットを netfilter に戻します。
パケットを傍受して dhcpoptinj に送るためには、iptables ルールが必要です。例えば、eth0 と eth1 の 2 つのインターフェイスをブリッジしているとします。eth0 からのすべての BOOTP リクエストを傍受し、リレーエージェント情報オプション(82/0x52)を注入したいとします。適当なペイロードを作りましょう。エージェント回線 ID サブオプションの値を"Fjas"とします。
iptables の mangle テーブルにルールを追加します:
sudo iptables -t mangle -A PREROUTING -m physdev --physdev-in eth0 -p udp --dport 67 -j NFQUEUE --queue-num 42
次に dhcpoptinj を実行します(フォアグラウンドでデバッグ出力を追加):
sudo dhcpoptinj -d -f -q 42 -o'52 01 04 46 6A 61 73'
dhcpoptinj は CAP_NET_ADMIN ケイパビリティを持つユーザーで実行する必要があります。root で実行する必要はなく、実際には実行すべきではありません。代わりに、例えばバイナリに CAP_NET_ADMIN ケイパビリティを付与し(setcap を使用)、実行権限を特定のユーザーまたはグループに制限することができます。これは wireshark を非 root で実行するために使用される方法なので、これを達成するためのガイドがいくつか見つかるでしょう。
次に、eth0 インターフェイスに DHCP パケットを送信し、ブリッジインターフェイスに到達したときに変更されているのを(wireshark などのツールを使用して)確認します。オプションリストの最後に注入されたオプションが追加されているはずです。Wireshark で受信 DHCP パケットをキャプチャすると、変更されていないように見えますが、実際には改変されています。
-o オプションの引数の形式に注意してください:DHCP オプションコードで始まり、その後にオプションペイロードが続く 16 進数文字列です。オプション長(通常オプションコードの後に続くバイト)は自動的に計算されるため、指定してはいけません。16 進数文字列は読みやすさのために非 16 進文字で区切ることができます。すべてのオプションにはペイロードが必要ですが、特別な パッドオプション(コード 0)は例外です。
この例で使用した無意味なオプションのレイアウト(まず DHCP オプションのレイアウト、次に特定の リレーエージェント情報オプションのサブオプションレイアウト)は次のとおりです:
| コード | 長さ | データ |
|---|---|---|
| 52 | (自動) | 01 04 46 6A 61 73 ("Fjas") |
| サブオプション | 長さ | データ |
|---|---|---|
| 01 | 4 | 46 6A 61 73 ("Fjas") |
dhcpoptinj はオプションペイロードに何を書くかは気にせず、オプションコードが存在するかもチェックしません。ただし、オプションコード 255(終端のエンドオプション)の使用は禁止されています。dhcpoptinj はこのオプションを最後のオプションとして自動的に挿入します。
dhcpoptinj -f -d -q42 -r -o'0C 66 6A 61 73 65 68 6F 73 74' -o'52 01 04 46 6A 61 73' -o 320A141E28
3 つの DHCP オプションを注入(合計 25 バイト):12 (0x0C) (ホスト名)、82 (0x52) (リレーエージェント情報)、50 (0x32) (アドレス要求)
既存のオプションは削除されます
netfilter キューを初期化
シグナルハンドラを初期化
初期化完了。キュー 42 で改変するパケットを待機中
416 バイトを受信
B6:40:FE:41:30:DC → 255.255.255.255:67 の 328 バイトの DHCP パケットを検査
パケットを改変
オプション 53 (0x35) (DHCP メッセージタイプ) DHCPREQUEST (コピー)
オプション 54 (0x36) (DHCP サーバー ID) 4 バイトペイロード 0A 14 1E 01 (コピー)
オプション 50 (0x32) (アドレス要求) 4 バイトペイロード 0A 14 1E 28 (削除)
オプション 12 (0x0C) (ホスト名) 12 バイトペイロード 33 31 36 64 65 39 31 34 64 61 62 34 (削除)
オプション 55 (0x37) (パラメータリスト) 13 バイトペイロード 01 1C 02 03 0F 06 77 0C 2C 2F 1A 79 2A (コピー)
END オプション (削除)
オプション 12 (0x0C) (ホスト名) 9 バイトペイロード 66 6A 61 73 65 68 6F 73 74 を注入
オプション 82 (0x52) (リレーエージェント情報) 6 バイトペイロード 01 04 46 6A 61 73 を注入
オプション 50 (0x32) (アドレス要求) 4 バイトペイロード 0A 14 1E 28 を注入
END オプションを挿入
最小 BOOTP ペイロードサイズに達するために 10 バイトでパディング
改変されたパケットを送信
dhcpoptinj は Debian/Ubuntu に含まれています。deb パッケージは salsa でソース管理されています。dhcpoptinj を deb パッケージからインストールすることを推奨します。マニュアルページ、bash 補完ルール、サンプルファイルなども含まれているためです。
cmake と libnetfilter_queue が必要です(C99 をサポートする C コンパイラも必要です)。Debian 系のシステムをお使いの場合、以下のコマンドでインストールできます:sudo apt-get install cmake libnetfilter-queue-dev
git clone git://github.com/misje/dhcpoptinjcd dhcpoptinjmkdir build && cd buildcmake .. (デバッグビルドが必要な場合は cmake -DCMAKE_BUILD_TYPE=Debug ..)make -j4sudo make installsudo make uninstall を実行ビルドディレクトリとその内容は安全に削除できます。ビルドディレクトリを使用しなかった場合は、git clean -dfx を実行して cmake 関連のファイルを全て削除できます。ただし、これによりプロジェクトディレクトリ内のソース管理されていないすべてが削除されることに注意してください。
dhcptopinj は /etc/dhcpoptinj.conf または -c/--conf-file で指定されたファイルを解析しようとします。設定ファイルの構文は次の通りです:
空白は任意です。文字 # 以降はコメントと見なされます。DHCP オプションは option=01:02:03 のように 1 つずつ列挙します。オプションの 16 進数文字列を囲む引用符は任意で、バイトは任意の数の非 16 進文字で区切ることができます。
オプション version、help、conf-file は設定ファイル内では受け付けられません。
例:
# フォアグラウンドで実行:
foreground
# デバッグ出力を有効にする:
debug
# ホスト名を "fjasehost" に上書き:
option = '0C 66 6A 61 73 65 68 6F 73 74'
# エージェント ID "Fjas" を送信:
option = "52:01:04:46:6A:61:73"
# アドレス要求を 10.20.30.40 に上書き:
option=320A141E28
# キュー 12 を使用:
queue = 12
remove-existing-opt # オプションを挿入する前に削除
この README で始められるはずです。マニュアルページ(deb パッケージ内)とヘルプ出力(dhcpoptinj -h)もご覧ください。これらでユーティリティの全機能を網羅しています。
バグや提案は Issue を作成してください。
dhcpoptinj はシンプルであり、そのままであることを願っています。それでも、以下の機能は将来追加されることを期待しています:
Failed to bind queue handler to AF_INET: Operation not permitted
おそらく CAP_NET_ADMIN ケイパビリティがないか、同じ netfilter キュー番号に別のプロセス(別の dhcpoptinj インスタンスなど)がバインドされています。
正常でない終了時のメモリリーク
これはリークとは見なされません。ただし、通常の終了(SIGTERM、SIGINT、SIGHUP をキャッチ)ではメモリリークは発生しません。
dhcpoptinj で使用する iptables ルールを作成する際、以下のオプションが役立ちます:
--queue-bypassdhcpoptinj が実行されていない(または正しいキュー番号でリッスンしていない)場合、パケットをドロップせずに通過させます。
提案があれば Issue を残してください。ご連絡します。コントリビューションは歓迎します。プルリクエストも大歓迎です。
dhcpoptinj が役立つと思われたら、どのような用途で使用しているかをぜひお聞かせください。Wiki ページを更新して、使用例を説明してください。
このプロジェクトには GPL を選択しました。これが適さない場合はご連絡ください。別のライセンスについて合意できます。