DHCP Relay Agent+Filterで既存のDHCPサーバーがある環境でPXEを使う
DHCPサーバーが既にあるネットワークでPXEを使おうとすると、通常は既存のDHCPサーバーを一度落としてから、新たにPXE用のDHCPサーバーを立てないといけません。
これがVIVERでは非常に大きな問題で、1つのサブネット内で2つ目のDHCPを立てるときは、1つ目のDHCPサーバーの設定を知っていないと、ネットワークを混乱させてしまいます。VIVERでは「できるだけ」ネットワークを混乱させないようにPXE用のDHCPサーバーを自動的に構築するのですが、既存のDHCPサーバーのアドレスプールの範囲が分からないので、やっぱり混乱させてしまう可能性があります。
そこで!DHCP Relay Agentの実装をハックして、リレー時にDHCPパケットを改変する機能を追加してみました。既存のDHCPサーバーが発行するDHCPOFFERをフックして、それにPXE用のオプションを載せた上で(+ごにょごにょして)再度DHCPOFFERを発行すれば、クライアントは見事にだまされます。
というわけで、↓これがそのパッチです。
dhcprelay-0.3.2b-filter.patch
dhcprelay-0.3.2b.tar.gzに当ててください…と、これを当てるとautoconf/automakeのバージョンの関係で何やらコンパイルできない?ので、configure無しで直にmakeしました(Linux)。そのパッケージは→dhcprelay-0.3.2b-filter-sourceonly.tar.gz
※追記:PXEの仕様自体に既存のDHCPサーバーの設定を変更せずにネットワークブートする規格が存在したので、こちらの実装の方が確実です:Proxy DHCPを使ってネットワークブートサーバーを構築する
使い方は、
$ # ./dhcprelay-filter <device to client> <device to server> -- <tftp server address> <boot file name> $ sudo ./dhcprelay-filter eth0 eth0 -- 192.168.0.2 "/pxelinux.0"
です。元々はDHCP Relay Agentなので中継もできるハズですが、むしろそちらは試していません。(DHCPDISCOVERを中継しないようにしているのでたぶん動きません)
67/udp(dhcps)と68/udp(dhcpc)を待ち受けるので、DHCPクライアントやDHCPサーバーが起動している場合は終了してださい。(DHCPクライアントも終了しないといけません)
さて、その仕組みを。以下
クライアントがPXEでブートしようとすると、まずDHCPDISCOVERをブロードキャストしてきます。これを受信して、その「トランザクションID」(DHCPヘッダのxidフィールド)を記録しておきます。トランザクションIDは、DHCPクライアントがDHCPDISCOVERを送るときにランダムに作成する数値らしいです。
続いて、既存のDHCPサーバーがDHCPOFFERをブロードキャストしてくれます。これを受信します。ただし記録しておいたトランザクションIDとは別のトランザクションIDが付いていたら捨てます。そしてこのパケットを以下のように書き換えます。ここがキモです。
- DHCPヘッダのnext boot server (siadddr)フィールドにTFTPサーバーのIPアドレスをセット
- セット!
- DHCPヘッダのClient boot file name (file)フィールドにブートローダのパスをセット
- ブートローダのパスは、起動時の引数で渡された
です。TFTPサーバーの/からの相対パス。 - Server Identifier (option 54)を自分のアドレスに書き換える
- クライアントからは./dhcprelay-filterが既存のDHCPサーバーとは別のDHCPサーバーに見えるようになります。
- Server Identifier (option 54)以外のoptionを削除する
- Option Overload (option 52)などが残っていたりするとうまく動いてくれません。
- Address Lease Time (option 51)を1分にセット
- ブートローダをダウンロードするためだけにしか使われないので、短くしておきます。どうせ後でまたすぐDHCPDISCOVERが飛ぶことになります。
この書き換えたパケットをブロードキャストします。そうすると、クライアントは見事にDHCPREQUESTを返してくるハズです(ブロードキャスト)。このDHCPREQUESTは、既存のDHCPサーバーが発行したIPアドレスを使うようにセットされているので(Requested IP Address, option 50)、既存のDHCPサーバーはDHCPACKを返してきます。…たぶん。ここのところは微妙で、Server Identifierなどが書き換わっているので、DHCPサーバーの実装によっては無視されるかもしれません。
このDHCPACKも、DHCPOFFERと同じように書き換えてブロードキャストします。…ここのところはDHCPREQUESTを受信した時点でDHCPACKを返せばいいのですが、単純に手抜きです(^_^;)
ちなみにPXEの仕様はここにありますが、仕様上は上記のオプションではブートしないハズなのです。DHCPOFFERにClass Identifier (option 60)をセットしないといけないように書かれているのですが、セットしなくてもブートします(逆にセットするとブートしないカードもあったような…3com?)。それからUDPの4011ポートも不要です。
仕様上の方法も少し試してみたところ、Client IdentifierにPXEClient + PXE Server (udp/4011)(実装はこれを利用)でもブートできました。カードはIntel/PRO 1000です。
…ということで仕様と現状の違いが良く分かりません。どなたか詳しい方、調べてしまった方、ぜひレポートを!