スポンサーリンク

DIVERT(4) FreeBSD カーネルインタフェースマニュアル DIVERT(4)

名称

divert − カーネルによるパケット迂回メカニズム

書式

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

int

socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT);

解説

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

通常、迂回ソケットは FreeBSD のパケットフィルタリングの実装や ipfw(8) プ ログラムと共に使われます。迂回ソケットからの読み出しや書き込みによって、 合致するパケットをホストマシンを経由する時に任意の ‘‘フィルタ’’ を通した り、特別なルーティングの細工を行うといったことができます。

パケットを読む

`‘入ってくるパケット’’ であっても ‘‘出ていくパケット’’ であっても迂回させ ることができます。入力パケットは IP インタフェース上で受信された後に迂回 されます。出力パケットは次のホップに転送する前に迂回されます。

迂回パケットは read(2), recv(2), もしくは recvfrom(2) によってそのままの 形で読み出すことができます。後者の場合に得られるアドレスでは、ポート番号 にはパケット迂回者が提供するなんらかのタグ (通常は ipfw のルール番号) が 設定され、 IPアドレス部には入力パケットの場合はパケットが受信された (最初 の) インタフェースアドレス、出力パケットの場合は INADDR_ANY が設定されま す。入力パケットの場合はアドレスに続く 8 バイトの中にインタフェース名も ( そこに収まるものとして) おかれます。

パケットを書く

迂回ソケットへの書き込みは生の IP ソケットへの書き込みと似ています。パ ケットは ‘‘そのままの’’ 形で通常のカーネル IP パケット処理へ送られ、最小 のエラーチェックのみが行われます。パケットは入力としても出力としても書く ことができます。すなわち write(2) もしくは send(2) がパケットの配送に使わ れるか、 sendto(2) が INADDR_ANY の宛先 IP アドレスと共に使われると、パ ケットはそれが出力であるかのように扱われます。つまりローカルでないアドレ スへ差し向けられます。その他の場合は、入力であると想定され、全てのパケッ トルーティングが実行されます。

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

通常、入力として読み出されるパケットは入力として書かれなければなりませ ん。出力パケットについても同様です。パケットを読み出して書き戻す時には、 recvfrom(2) によって与えられたソケットアドレスと同じものを、そのままの形 で sendto(2) に渡すことで物事が単純になります (下記参照)。

sendto(2) へ渡されるソケットアドレスのポート部分には、迂回モジュールに とって意味のあるタグが含まれます。 ipfw(8) の場合には、タグは、 この次の ルール番号からルール処理を再開すべきと解釈されます。

ループの回避

迂回ソケットへ ( sendto(2) を使って) 書き込まれたパケットは、ソケットアド レスのポート部分に与えられたタグに続くルール番号から、パケットフィルタに 再入されます。通常、ソケットアドレスは迂回を発生させる (同じ番号において いくつかのルールがある場合は次のルールではない) ルール番号においてすでに セットされています。もし ’タグ’ が別の再入点を示すために置き換えられてい れば、同じパケットが同じルールで 1 度以上迂回されるようなループを回避する ための考慮がなされるべきです。

詳細

迂回ソケットを有効とするためには、 IPDIVERT オプションを指定してカーネル をコンパイルしなければなりません。

パケットは迂回されるがポートにバインドされるソケットがない場合、もしくは IPDIVERT がカーネルにおいて有効にされていない場合は、パケットは捨てられま す。

迂回される入力パケットフラグメントは配送前に全てリアセンブルされます。フ ラグメントが 1 つでも迂回されると全てのパケットが迂回されることになりま す。もし、フラグメントのいくつかが違うポートに迂回されると、最後にどの ポートが選択されるかは予期できません。

パケットは受信されて、変更されずに送信されますが、出力として書かれたパ ケットの IP ヘッダのチェックサムは正しい値に書き換えられます。入力として 書かれ、誤ったチェックサムを持つパケットは捨てられます。それら以外は、全 てのヘッダフィールドは変更されません (もちろんネットワークに届いた順番 で)。

タイプ SOCK_RAW のソケットの生成と同様に、 1024 より小さいボート番号をバ インドするためにはスーパユーザアクセスが必要となります。

エラー

生のパケットの書き込み時に通常発生するエラーに加え、迂回ソケットへの書き 込みは以下のエラーを返すことがあります。

       [EINVAL]

パケットのヘッダが不正か、パケットの IP オプションと設 定されたソケットのオプションに不整合があります。

[EADDRNOTAVAIL]
宛先アドレスに含まれる IP アドレスは、 INADDR_ANY と等 しくなく、どのインタフェースにも関連づけられていませ ん。

関連項目

bind(2), recvfrom(2), sendto(2), socket(2), ipfw(8)

バグ

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

入力のフラグメントが迂回の前に再構成されるべきかどうかについては疑問の余 地があります。例えば、他のマシン宛のパケットのうち数個のフラグメントが ローカルマシン経由でルーティングされないだけで、パケットが失われます。こ れはおそらく何らかの方法で設定可能なオプションにするべきです。

作者

Archie Cobbs ⟨archie@whistle.com⟩, Whistle Communications Corp.

FreeBSD June 18, 1996 FreeBSD

スポンサーリンク