オルタナティブ・ブログ > プログラマー社長のブログ >

プログラミングでメシが食えるか!?

DHCP:トランザクションIDゼロ問題

»

DHCPサーバ製品のProDHCPを長年、開発販売している中で、数々の運用現場で様々な問題に対応してきました。プログラムの不具合もゼロとは言いませんが、多くの問題は「RFCに準拠していない」「RFC記述が曖昧で解釈が異なる」という問題でした。

不特定多数のクライアント・ネットワーク機器にサービスをする製品では、標準規格と異なる動きをするクライアント・ネットワーク機器であっても基本的には対応することを求められます。特にクライアントは一般ユーザ側ということが多いため、クライアント側にアップデートを依頼しても、そもそもやり方すらわからないということもありますし、アップデートしてくれないことも多いものです。

DHCPの基本的な標準仕様となっているのがRFC2131ですが、この資料も実に曖昧な記述が多く、クライアントやネットワーク機器の実装も様々なバリエーションが存在してしまうことにつながっています。

先日ある構築現場で発生した問題は、サーバ側としては実に困ったものでした。

DHCPでは、クライアントがリクエストを送信する際にブロードキャストフラグというものを設定します。クライアントがユニキャストを受信できない可能性がある場合は、ブロードキャストフラグを設定してリクエストすると、応答がブロードキャストで届けられます。ここでいうブロードキャスト・ユニキャストというのはIPレベルではなく、イーサフレームレベルで、ユニキャストは宛先MACアドレスに送信先MACアドレスが、ブロードキャストはFF:FF:FF:FF:FF:FFが使われます。

クライアントが自分宛のMACアドレスが指定された応答を受け取れないというのは、普通に考えるとないのですが、古い時代にIPアドレスが設定されるまではブロードキャストしか受信しないというデバイスが存在したようです。

WindowsXPまではブロードキャストフラグをオフでDHCPリクエストを送信していたのですが、ネットワークデバイスによってはユニキャストを受信できないものが存在したり、あるいは、DHCPを仲介するリレーエージェントがユニキャストで正しく送信できないものがあったりしたため、DHCPサーバ側でリクエストのブロードキャストフラグを無視し、応答は全てブロードキャストフラグをオンにして返答するという設定がよく行われました。ProDHCPでは「ignore-broadcast-flag」という設定で、ISC-DHCPでは「always-broadcast」という設定でそのような動きになります。

その後、WindowsVistaが登場した際に、ブロードキャストフラグはオンでDHCPリクエストを送信するようになりました。ところが、今度はブロードキャストフラグがオンだとうまく動かないケースもあったようで、この場合はWindowsVistaのレジストリを変更してブロードキャストフラグをオフにしてDHCPリクエストを送信するという対処も行われたようです。

いずれにしても、WindowsでDHCPでのIPアドレス付与ができないという問題のため、ProDHCPは初期の案件で、「応答は全てブロードキャストフラグをオンにする」という機能の実装を要求され、さらに、問題が大きかったこともあり、「デフォルトでオンにするように!」と言われ、現在にいたるまでこの機能はデフォルトで有効になっています。

ところが、今度は一部の家庭用ルーターがDHCPリクエストを送信する際にトランザクションIDをゼロで送信してしまうという問題が発生しました。DHCPではRFCでも「クライアントはトランザクションIDで自分への応答かどうかを判断すること、トランザクションIDは他の端末と重複しないように乱数などを使用すること」と定められているのですが、これに準拠していないというか、ファームウェアの問題でそのような動きのルーターが存在するのです。このルーターはブロードキャストフラグはオフでリクエストしますので、本来はユニキャストで応答が届けられます。しかし、前述のWindowsでの問題などもあり、DHCPサーバ側で全ての応答はブロードキャストフラグをオンにして返す、となっていると問題が発生します。

ひとつのリレーエージェント配下に複数のこの問題を持ったルーターが存在し、それらがほぼ同時にDHCPリクエストを送信すると、応答のトランザクションIDはゼロで、それがブロードキャストで配信されてしまうことにより、全てのこの問題を持ったルーターが、どの応答も自分宛だと勘違いして受信してしまうのです。DHCPクライアントの場合、DHCPDISCOVERを送信し、DHCPOFFERを受信し、DHCPOFFERに従ってDHCPREQUESTを送信してDHCPACKを受けて自分のIPアドレスが決まるのですが、他のルーター向けのDHCPOFFERでも受信してしまうので、間違えたDHCPREQUESTを送信し、エラーのDHCPNAKが戻ってきてしまいます。するとDHCPDISCOVERからやり直すのですが、ほぼ全てのルーターがエラーになるのでまたほぼ同時にDHCPDISCOVERからやり直すので、いつまでたってもほとんどのルーターが成功できないのです。

DHCPサーバ側で「全ての応答はブロードキャストする」というのをオフにすれば一応解決しますが、かつてのWindowsでの問題に対応できない可能性があることと(今では基本的に問題ないと思いますが)、それでもまだこのルーターに対しては問題が残ります。RFCで「DHCPNAKはブロードキャストで返すこと」という記述があり、全ての応答はブロードキャストする機能をオフにしても、DHCPNAKはブロードキャストフラグがオンで返るのです。幸いなことに、この問題を持ったルーターでも、DHCPREQUESTはトランザクションIDを乱数にしているようですので、DHCPNAKのトランザクションIDがゼロで戻って混乱することはなさそうですが。

トランザクションIDゼロ問題の他にも、ある家庭用ルーターは、一定時間内に応答がない場合にものすごい勢いでリクエストを投げ続けるという問題を持ったものも存在します。ある1つのルーターによりDHCPサーバの負荷を高め、それによって応答が遅延しやすくなると、同じ問題を持ったルーターがまた暴走しはじめ、という感じでどんどんDHCPサーバに負荷がかかってしまい、サービス不能に陥ることもあるくらいです。ProDHCPではDOS対策機能としてこの問題に可能な限りの対処を自動で行うようになっています。

量販店で販売されている一般家庭用のネットワーク機器にもこのような大きな問題を持ったものは存在するのです。ファームウェアも人間が作るものですから、バグが存在すること自体は仕方ないかも知れませんが、少なくとも、「どのような問題があったか」と、「修正ファームウェアの提供」は行って欲しいものです。ちなみに、トランザクションIDゼロ問題のあったルーターは、以前、あるSIerさんでメーカーに問い合わせを行ったところ、「一時期の製品に問題があったことを認め、新しいファームでは修正されている」と回答があったようですが、メーカーのファームウェア提供ページを確認しても、この問題のことに関しては一切記述はなく、こっそり修正しておいた、という感じのようです。先日、私自身もこの問題でひどい目にあいましたので、MACアドレスのベンダーコードを書いておきます。特に多くて困ったのが「00:1b:8b」「00:3a:9d」です。「00:0f:ea」これも同様でした。探せばベンダーはすぐに分かると思いますが。ちなみに、凄い勢いでリクエストを投げまくる機器は「00:0a:79」がほとんどです。

こういう事象をどれだけ把握しているかも製品ベンダーやSIerの実力のうち、と言われるかも知れませんが、そんなものはノウハウでも何でもなく、誰もが困ったときに知ることができる情報であるべきだと私は思います。もちろん、問題を開示することにより攻撃を受ける心配がある製品もありますので、全てを一般向けに公開すべきとは考えません。ProDHCPも不具合によって攻撃される危険がある問題もかつていくつかりましたので、それらは運用先:ライセンス先への開示情報としています。いずれにしても、対処に困る可能性がある人が、容易に知ることができるようにしておくのが筋というものだと思います。それなりに探してもこの問題の明確な情報見つからないので私が書いておきました。この問題で困った人がこの記事ですぐに気がつき、対処できれば被害が減りますので。

ということで、サーバ製品は仕様に準拠してないクライアントでもうまく対応することが要求され、それが実は一番気を使って苦労するところだったりもします。

Comment(2)