私は、Linux カーネル用のIPv4-IPv6 トランスレーター ( RFC 6146 )のコーディングを任されています。簡単に言えば、IPv4 ネットワークと IPv6 ネットワークの間に立ち、パケット ヘッダーを切り替えてアドレスをマスキングすることで透過的な通信を可能にするゲートウェイです。
カーネルがパケットを変更するためのフレームワークである Netfilter を持っているのを見て、最初は Netfilter モジュールを書いてそこから変換できると思っていました。すべてのパケットをインターセプトし、通常の skb_pull/skb_push 操作を使用してそれらのサイズを変更し、一部のバイトをオーバーライドして、最終的に問題なくカーネルに返すことができました。
判明したように、プロトコルの切り替えは Netfilter にとって極端すぎます。IPv4 パケットを処理するコードは IPv6 パケットを処理するコードから完全に独立しているため、Netfilter モジュールの前後のコードは、ネットワーク プロトコルのヘッダーが存続することを前提としています。したがって、IPv4 ヘッダーを IPv6 ヘッダーに変更すると、IPv4 ヘッダーであるかのようにヘッダーを読み続けるため、カーネルは異常になります。
(または、少なくとも、net/ipv4/ip_input.c を読んだ後に私が信じていることです。カーネルが NF_HOOK の呼び出し後に最初に行うことは、ip_rcv_finish() で IPv4 ヘッダーを抽出することです)。
2 番目のオプションがあります。新しい sk_buff を最初から推定し、Netfilter に元のパケットを NF_DROP するように依頼してから、何らかの方法で新しいパケットを送信します。
ここで、カーネルの原理とスタイルに関する私の限られた知識が私を停滞させます: 私は自分の解決策に眉をひそめることを最小限にしたいのですが、ヘッダーを変更する代わりにパケット全体を置き換えることは、不自然で非効率的であり、Netfilter の設計を冒涜することさえあります. でも、一概には言えませんので、経験者の方のアドバイスをお願いします。また、他に選択肢がありません。
質問: 他のオプションはありますか? 最も自然なアプローチは何でしょうか?
2.6 以降のすべてのカーネル バージョンをサポートしたいと考えています。それが無理なら新しい方がいい。