PFIL(9) | FreeBSD Kernel Developer's Manual | PFIL(9) |
名称
pfil, pfil_head_register, pfil_head_unregister, pfil_head_get, pfil_add_hook, pfil_remove_hook, pfil_run_hooks, pfil_rlock, pfil_runlock, pfil_wlock, pfil_wunlock — パケットフィルタインタフェース書式
#include < sys/param.h>#include < sys/mbuf.h>
#include < net/if.h>
#include < net/pfil.h>
typedef int (*pfil_func_t)(void *arg, struct mbuf **mp, struct ifnet *, int dir, struct inpcb);
int
pfil_head_register(struct pfil_head *head);int
pfil_head_unregister(struct pfil_head *head);struct pfil_head *
pfil_head_get(int af, u_long dlt);void
pfil_add_hook(pfil_func_t, void *arg, int flags, struct pfil_head *);void
pfil_remove_hook(pfil_func_t, void *arg, int flags, struct pfil_head *);int
pfil_run_hooks(struct pfil_head *head, struct mbuf **mp, struct ifnet *, int dir, struct inpcb *);void
pfil_rlock(struct pfil_head *, struct rm_priotracker *);void
pfil_runlock(struct pfil_head *, struct rm_priotracker *);void
pfil_wlock(struct pfil_head *);void
pfil_wunlock(struct pfil_head *);
解説
pfil フレームワークは、指定された関数が特定のネットワーク I/O ストリームであらゆる着信または発信パケットのために呼び出されることを可能とします。これらのフックは、ファイアウォールを実装するか、またはパケット変換を実行するために使用されます。パケットフィルタリングポイントは、 pfil_head_register() で登録されます。フィルタリングポイントは、 pfil_head 構造体でキー ( void *) とデータリンクタイプ ( int) によって識別されます。パケットフィルタは、それらがそれら自体を登録するフィルタリングポイントを検索するためにキーとデータリンクタイプを使用します。キーは、フィルタリングポイントに特有です。データリンクタイプは、どういう種類のヘッダがフィルタリングポイントでパケットに存在しているかを示す bpf(4) DLT 定数です。各フィルタリングポイントは、デフォルトで共通の VNET ごとの rmlock を使用します。 pfil_head 構造体の flags フィールドとして PFIL_FLAG_PRIVATE_LOCK を指定することによって、これを変更することができます。プライベートロックを指定することは、異なるデータリンクタイプの間で同じルールセットおよび状態を共有するフィルタを壊すことができることに注意してください。フィルタリングポイントは、 pfil_head_unregister() 関数で登録を抹消されます。
パケットフィルタは、それぞれ pfil_add_hook() と pfil_remove_hook() 関数でフィルタリングポイントをそれら自体に登録/登録を抹消します。ヘッドは、パケットフィルタが期待するキーとデータリンクタイプを取る、 pfil_head_get() 関数を使用して検索されます。フィルタは、パケットで呼び出されるとき、フィルタに渡される引数を提供します。
フィルタが呼び出されるとき、パケットは、まるでまさしくそれが“came off the wire” (ワイヤにはじかれたの) ように見えます。すなわち、すべてのプロトコルフィールドは、ネットワークバイト順です。フィルタは、指定された引数、パケットを含む mbuf へのポインタへのポインタ、パケットが横断しているネットワークインタフェースへのポインタ、とパケットが横断している方向 ( PFIL_IN または PFIL_OUT) で呼び出されます。フィルタは、 mbuf ** 引数参照の mbuf を変更するかもしれません。フィルタは、パケット処理が停止するなら、エラー (errno) を返し、処理が継続するなら、0 を返します。パケット処理が停止するなら、パケットを解放するのは、フィルタの責任です。
すべてのフィルタのフックは、 pfil 読み込みロックを保持して呼び出されます。すべてのヘッドは、同じ VNET インスタンス内の同じロックを使用します。パケットフィルタは、性能を改善するために独自のロックモデルの代わりに、このロックを使用することができます。 pfil は、 rmlock(9) pfil_rlock() を使用するので、 pfil_runlock() は、 struct rm_priotracker が引数として渡されることを要求します。フィルタは、 pfil_wlock() と pfil_wunlock() 関数を通して書き込み側ロックを獲得して解放することができます。さらに詳しくは、 rmlock(9) を参照してください。
フィルタリングポイント
現在、フィルタリングポイントは、次のリンクタイプに対して実装されています:
- AF_INET
- IPv4 パケット。
- AF_INET6
- IPv6 パケット。
- AF_LINK
- リンクレイヤ (Link-layer) パケット。
戻り値
成功するなら、 pfil_head_get() は、与えられた key/dlt のための pfil_head 構造体を返します。 pfil_add_hook() と pfil_remove_hook() 関数は、成功するなら、0 を返します。フラグ PFIL_WAITOK で呼び出されるなら、 pfil_remove_hook() は、常に成功すると予想されます。pfil_head_unregister() 関数は、スリープするかもしれません!
歴史
pfil インタフェースは、 NetBSD 1.3 ではじめて登場しました。 pfil 入力と出力リストは、元々、 < sys/queue.h> LIST 構造体として実装されました。しかしながら、これは、 NetBSD 1.4 で TAILQ 構造体に変更されました。この変更は、入出力フィルタが逆順で処理されることを可能にし、カーネルの中と外で同じパスが取られることを可能にします。pfil インタフェースは、プロトコル毎のフィルタリングの能力を導入して、 pfil_add_hook() と pfil_remove_hook() の両方の 3 番目のパラメータを受け付けるために 1.4T で変更されました。これは、主に IPv6 のフィルタリングをサポートするために行われました。
1.5K では、 pfil フレームワークは、少ない IP セントリックと同様に、フィルタリングポイントの任意の数で動作するように変更されました。
きめの細かいロックは、 FreeBSD 5.2 で追加されました。 pfil ロックのエクスポートは、 FreeBSD 10.0 で追加されました。
バグ
pfil_head が変更されているとき、(デッドロックを避けるために) どんなトラフィックも方向転換されません。これは、トラフィックが短期間に無条件で落とされるかもしれないことを意味します。 pfil_run_hooks() は、これを示すために ENOBUFS を返します。August 23, 2013 | FreeBSD |