AI支援によるバイナリパッチ:放棄されたルーターのDHCPバグ修正
AIを活用した解析により、EdgeOSルーターのdhcrelay3にあるRFC 2131違反のバグを8バイトのバイナリパッチで修正した事例を詳述。DHCPリレーの仕組み、45台以上のルーターで複製パケットが増幅される現象、およびgiaddrチェックに置き換える正確なパッチ方法を説明。パッチは既存の関数出口を再利用し、MIPSのディレイスロットも適切に処理する。
あるISPネットワークにおいて、集中管理されたDHCPサーバーが毎秒約200件の重複要求パケットを記録していた。原因はEdgeOSのリレーデーモンdhcrelay3が、既にリレーされたパケットを再びリレーするというRFC 2131違反にあった。ネットワークは45台以上のEdgeOSルーターで構成され、リレーパスが数段階にわたっており、単一のクライアント要求がサーバーに殺到する原因となっていた。著者は出荷時のdhcrelay3バイナリに8バイトのパッチを適用し、重複パケットを完全に停止させた。
DHCPリレーの仕組み:IPアドレスを持たないデバイスはブロードキャストでDHCP DISCOVERを送信するが、ブロードキャストはローカルサブネットに留まる。リレーエージェントはローカルルーター上で動作し、ブロードキャストをリッスンして設定されたサーバーへユニキャストで転送する。その際、giaddrフィールド(ゲートウェイIPアドレス)に受信インターフェースのアドレスを設定する。RFC 2131は、既にgiaddrが設定されたパケットは他のリレーが処理すべきでないと明記している。しかしEdgeOSのビルドは、giaddrが自身のアドレスと一致する場合のみパケットを無視し、それ以外は再リレーしていた。
このバグにより、少なくとも2つのリレーが経路に存在するとループが発生する。最初のリレー(R1)は正しくgiaddrを設定して転送する。次のリレー(R2)は本来そのパケットをルーティングするだけだが、バグにより再リレーしてしまう。これが各ホップで繰り返され、コピーが倍増する。BOOTPホップ数(最大16)が上限となるが、これは深さのみを制限し、広がり方は制限しない。さらにEdgeOSの起動スクリプトはすべてのリレーインターフェースを受信と転送の両方に設定するため、ルーターが自身の送信したコピーを再度受信してリレーすることもある。45台以上のルーターが数段階にわたる構成で、中央サーバーに毎秒約200の重複要求が到達する。
dhcrelay3はISC DHCP(オープンソース、現在は終了)のリレーエージェントであり、修正方法自体は単純:do_relay4()関数の先頭でgiaddrが設定されていれば直ちに返却する。しかしEdgeOSは古いISCバージョンをクロスコンパイルしたMIPSバイナリを出荷しており、サポートされた方法でデーモンを再構築して再インストールすることはできない。そのため、既存のバイナリに直接パッチを当てる必要がある。
著者は関数が出力するログメッセージ「Dropping request received on %s」を手がかりに、実際に実行されているインターフェースフラグチェックのコード位置を特定した。アドレス0xCF38にあるbeqz v0, d224(「下流」フラグが未設定なら分岐)を、giaddr(レジスタa2にロード済み)が非ゼロなら関数の既存出口0xCC94へジャンプするbnez a2, cc94に置き換えた。ジャンプ直後の遅延スロットには、lw ra,148(sp)(リターンアドレスを復元)を配置。この命令は出口でも最初に実行されるため、分岐時もフォールスルー時も正しく動作する。
このパッチはMIPSの遅延スロット特性を考慮し、既存のコードを再利用するため新たなコードを追加せず、安全に機能する。Octeon(ビッグエンディアン)およびMediaTek MT7621(リトルエンディアン)ルーターでテストされ、重複要求が完全に停止した。