EN JA
DIVERT(4)
DIVERT(4) FreeBSD Kernel Interfaces Manual DIVERT(4)

名称

divertカーネルパケット迂回メカニズム

書式

#include < sys/types.h>
#include < sys/socket.h>
#include < netinet/in.h>

int
socket( PF_INET, SOCK_RAW, IPPROTO_DIVERT);

divert ソケットサポートを有効にするためには、次の行をカーネル設定ファイルに置きます:

options IPFIREWALL
options IPDIVERT

もう一つの方法として、ブート時にモジュールとしてドライバをロードするためには、次の行を loader.conf(5) に置きます:

ipfw_load="YES" 
ipdivert_load="YES"

解説

迂回ソケットは bind(2) システムコールによって指定された divert (迂回) ポートをバインドすることができることを除いて、生の IP ソケットと同様です。 bind での IP アドレスは無視され、ポート番号だけが意味があります。迂回ポートにバインドされた迂回ソケットは、何らかの (ここでは特定されません) カーネルメカニズムによってそのポートを迂回するすべてのパケットを受信します。パケットは迂回ポートに書き込むこともできます。その場合はカーネル IP パケット処理に再び入力されます。

迂回ソケットは通常、 FreeBSD のパケットフィルタリングの実装と ipfw(8) プログラムと連動して使用されます。迂回ソケットからの読み込みと書き込みよって、一致するパケットはホストマシンを経由するような任意の ``フィルタ'' をパススルー (通過) できたり、特別なルーティングトリックなどを行なうことができます。

パケット読み込み

パケットは ``着信'' か ``発信'' のいずれでも迂回されます。着信パケットは IP インタフェースで受信の後に迂回されますが、発信パケットは次のホップに転送する前に迂回されます。

迂回パケットは read(2), recv(2) または recvfrom(2) によって変更されずに読み込むことができます。後者の場合では、返されたアドレスはパケット迂回者によってポートを供給されたあるタグに設定し、 (通常 ipfw ルール番号) IP アドレスは (パケットが着信であったなら) パケットが受信されたインタフェースの (最初の) アドレスを (パケットが発信であったなら) INADDR_ANY を設定します。 (パケットのために定義されるなら) インタフェース名は (それに収まるなら) アドレスに続く 8 バイトの中におかれます。

パケット書き込み

迂回ソケットの書き込みは生の IP ソケットに書き込むのと似ています。パケットは ``そのまま'' の形で sendto(2) を使用して通常のカーネル IP パケット処理に入れられ、最小のエラーチェックが行なわれます。パケットは着信または発信のいずれかとして区別されます。 sendto(2) が INADDR の送付先 IP アドレスと共に _ 少しも使用されるなら、まるでそれが外向的で、すなわち、非ローカルアドレスのために運命づけられるかのようにパケットは扱われます。 sendto(2)INADDR_ANY の宛先 IP アドレスと共に使用される場合、パケットはまるで発信であるかのように扱われます。すなわち、ローカルでないアドレスに行くことになっています。そうでなければ、パケットは着信であると想定され、完全なパケットルーティングが行われます。

後者の場合では、指定された IP アドレスはいくつかのローカルインタフェースのアドレスに一致しなければならないか、インタフェース名は IP アドレスの後に見つからなければなりません。インタフェース名が見つけられれば、そのインタフェースは使用され、 (それが INADDR_ANY でないという事実を除いて) IP アドレスの値は無視されます。これは、パケットがどのインタフェースで“到着したか”を示すためです。

通常、着信として読み込まれるパケットは着信として書き込まれるべきです。発信パケットも同様です。パケットを読み込んで次に書き戻すとき、 recvfrom(2) によって供給された同じソケットアドレスを修正せずに sendto(2) に渡すことはものを単純化します(下記参照)。

sendto(2) に渡されたソケットアドレスのポート部分は迂回モジュールにとって重要になるべきであるタグを含んでいます。 ipfw(8) の場合には、タグはルール処理が再開するべきである 後の ルール番号として解釈されます。

ループの回避

( sendto(2) を使用して) 迂回ソケットに書き込まれたパケットはソケットアドレスのポート部分に与えられたタグに続くルール番号でパケットフィルタに再入されます。通常、ソケットアドレスは迂回を引き起こしたルール番号で既に設定されています (同じ番号がいくつかあるなら、次のルールではありません)。´タグ' が別の再入点を示すために変更されるなら、同じパケットは同じルールで 2 回以上迂回されるループを避けるために注意を要します。

詳細

パケットが迂回されるが、ソケットがポートにバインドされていない場合、または IPDIVERT がカーネルで有効になっていない、またはロードされていないなら、パケットは落されます。

迂回される着信パケットのフラグメントは配送の前に完全に再構築されます。フラグメントが 1 つでも迂回されると、すべてのパケットは迂回されます。異なったフラグメントが異なったポートに迂回されるなら、結局どのポートが選ばれるかは予測できません。

ipfw(8) tee 動作によって迂回ソケットで到着したパケットはそのまま配信され、この場合、パケットフラグメント (断片) は再組み立てされないことに注意してください。

発信として読み込まれたパケットが不正な IP ヘッダチェックサムを持っていて、発信として書き込まれるパケットが正しい値でそれらの IP ヘッダチェックサムを上書きすることを除いて、パケットは受信され変更せずに送信されます。着信として書き込まれ不正なチェックサムを持っているパケットは落されます。そうでなければ、すべてのヘッダフィールドは変更されません (そしてその結果、ネットワーク順序で)。

タイプ SOCK_RAW のソケットを作成するように、 1024 未満のポート番号へのバインドはスーパユーザのアクセスを必要とします。

エラー

生のパケットを書き込むとき、起こり得る普通のエラーと共に迂回ソケットへの書き込みは次のエラーを返すかもしれません。
[ EINVAL]
パケットに不正なヘッダがあるか、またはパケットの IP オプションと設定されたソケットオプションは不適合です。
[ EADDRNOTAVAIL]
宛先アドレスはどんなインタフェースにも関連づけらなかった INADDR_ANY と等しくない IP アドレスを含んでいます。

作者

Archie Cobbs <archie@FreeBSD.org>, Whistle Communications Corp.

バグ

これはアドレス変換のような様々な IP トリックを実装するためにユーザモードのプロセスにきれいな方法を提供する試みです。しかし、きれいになるかもしれませんが、それは ipfw(8) に依存しすぎています。

迂回される前に着信フラグメントが再構築されるべきでかどうかには疑問の余地があります。例えば、別のマシンに向けられたパケットのいくつかのフラグメントだけがローカルマシンを介してルーティングされないなら、パケットは失われます。これはたぶんどんな場合でも設定可能なソケットオプションであるべきです。

December 17, 2004 FreeBSD