IPF(5)

名称
ipf, ipf.conf - IP パケットフィルタのルール文法

解説

ipf のルールファイルは、どんな名前でも良く、標準入力でもかまいません。 カーネル内部のフィルタリストを表示するとき、 ipfstat は解釈可能なルールを出力しますので、 この出力を ipf への入力としてフィードバックするのに使えます。 よって、入力パケットに対する全フィルタを除去するためには、次のようにします:
# ipfstat -i | ipf -rf -

文法

ipf がフィルタルール構築に使用するフォーマットは、 BNF を使った文法で次のように示すことができます:
filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
	      [ proto ] [ ip ] [ group ].
insert	= "@" decnumber .
action	= block | "pass" | log | "count" | skip | auth | call .
in-out	= "in" | "out" .
options	= [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] .
tos	= "tos" decnumber | "tos" hexnumber .
ttl	= "ttl" decnumber .
proto	= "proto" protocol .
ip	= srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
group	= [ "head" decnumber ] [ "group" decnumber ] .
block	= "block" [ return-icmp[return-code] | "return-rst" ] .
auth    = "auth" | "preauth" .
log	= "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] .
call	= "call" [ "now" ] function-name .
skip	= "skip" decnumber .
dup	= "dup-to" interface-name[":"ipaddr] .
froute	= "fastroute" | "to" interface-name .
protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
srcdst	= "all" | fromto .
fromto	= "from" [ "!" ] object "to" [ "!" ] object .

return-icmp = "return-icmp" | "return-icmp-as-dest" .
object	= addr [ port-comp | port-range ] .
addr	= "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
port-comp = "port" compare port-num .
port-range = "port" port-num range port-num .
flags	= "flags" flag { flag } [ "/" flag { flag } ] .
with	= "with" | "and" .
icmp	= "icmp-type" icmp-type [ "code" decnumber ] .
return-code = "("icmp-code")" .
keep	= "keep" "state" | "keep" "frags" .
loglevel = facility"."priority | priority .
nummask	= host-name [ "/" decnumber ] .
host-name = ipaddr | hostname | "any" .
ipaddr	= host-num "." host-num "." host-num "." host-num .
host-num = digit [ digit [ digit ] ] .
port-num = service-name | decnumber .
withopt = [ "not" | "no" ] opttype [ withopt ] .
opttype = "ipopts" | "short" | "frag" | "opt" optname .
optname	= ipopts [ "," optname ] .
ipopts  = optlist | "sec-class" [ secname ] .
secname	= seclvl [ "," secname ] .
seclvl  = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
	  "reserv-4" | "secret" | "topsecret" .
icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
	    "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
	    "inforep" | "maskreq" | "maskrep"  | decnumber .
icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
	    "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
	    "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
	    "filter-prohib" | "host-preced" | "cutoff-preced" .
optlist	= "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" |
	  "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" |
	  "addext" | "visa" | "imitd" | "eip" | "finn" .
facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" |
	   "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" |
	   "audit" | "logalert" | "local0" | "local1" | "local2" |
	   "local3" | "local4" | "local5" | "local6" | "local7" .
priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" |
	   "info" | "debug" .
hexnumber = "0" "x" hexstring .
hexstring = hexdigit [ hexstring ] .
decnumber = digit [ decnumber ] .
compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" |
	  "gt" | "le" | "ge" .
range	= "<>" | "><" .
hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" .
digit	= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
flag	= "F" | "S" | "R" | "P" | "A" | "U" .

この文法は、可読性のためにいくぶん簡略化しています。 この文法にマッチする組み合わせであっても、 意味をなさないためにソフトウェアが許可しないものがあります (非 TCP パケットに対する tcp flags など)。

フィルタルール

「最短」かつ有効なルールは (現在のところ) 無動作と次の形式です:
       block in all
       pass in all
       log out all
       count in all

フィルタルールは順番通りにチェックされ、 最後にマッチしたルールがパケットの運命を決めます (例外: 後述 quick オプションを参照)。

デフォルトでは、 フィルタはカーネルのフィルタリストの最後にインストールされます。 ルールの前に @n を付けると、 現在のリストの n 番目のエントリとして挿入するようになります。 これは、現在有効なフィルタのルールセットを修正したりテストする場合に有用です。 更なる情報は ipf(1) を参照してください。

アクション

アクションは、 フィルタルールの残りの部分にパケットがマッチする場合に、 そのパケットをどのように扱うのかを示します。 各ルールは、アクションを 1 つ持つことが「必要です」。 次のアクションが認識されます:

block
    このパケットを、ドロップするように印を付けることを示します。 パケットをブロックすることに対し、 ICMP パケット (return-icmp) か、 元のパケット送信宛先起源を装う ICMP パケット (return-icmp-as-dest) か、 TCP 「リセット」 (return-rst) の、いずれかの返答パケットを返すよう、 フィルタに指示できます。 ICMP パケットは、任意の IP パケットの応答として生成でき、 そのタイプを指定することもできます。 TCP リセットは、TCP パケットに対して適用されるルールにおいてのみ使用できます。 return-icmp または return-icmp-as-dest を使うとき、 到達不可の 'タイプ' を指定可能です。 このタイプとは、 ネットワーク到達不可、ポート到達不可、権限による禁止のいずれかです。 指定方法は、 return-icmp または return-icmp-as-dest の直後に、 タイプに関連する ICMP コードを括弧で括るというものです。 例えば
            block return-icmp(11) ...

とすると、Type-Of-Service (TOS) ICMP 到達不可エラーを返します。

pass
    このパケットを、そのままフィルタを通過させるように印を付けます。

log このパケットのログを取ります (後述のロギング節参照)。 パケットがフィルタを通過可能か否かには、影響を与えません。

count
    このパケットを、フィルタのアカウンティング統計に含めます。 パケットがフィルタを通過可能か否かには、影響を与えません。 統計は ipfstat(8) にて閲覧可能です。

call
    このアクションは指定されたカーネル内関数を呼び出すために使用されます。 カーネル内関数は、特定の呼び出しインタフェースを満す必要があります。 カスタマイズしたアクションとセマンティクスを実装し、 利用可能なアクションを補うことができます。 知識があるハッカーが使用する機能であり、現在のところ文書化されていません。

skip <n>
    フィルタに、次の n フィルタルールをスキップさせます。 スキップされる範囲のルールに挿入または除去があった場合、 n の値は適切に調整されます。

auth
    これにより、 ユーザ空間プログラムを実行して正当性を確認するパケット情報を待つことにより、 認証できます。 プログラムがカーネルに対してパケット通過を許すか否かの 実際の フラグを返すまでの間、パケットは内部バッファに保持されます。 パケット通過を許す前または 認識されない送信元からのパケットをカーネルに落すよう指示する前に、 このようなプログラムは、 送信元アドレスを見るかもしれませんし、 ユーザからの (パスワード等の) ある種の認証を求めるかもしれません。

preauth
    このクラスのパケットに対しては、 更なる明確化のために既に認証されたリストを見るべきであると、 フィルタに指示します。 更にマッチするルールが見付からないと、パケットは落とされます (FR_PREAUTH は FR_PASS と同じではありません)。 更にマッチするルールが見付かると、その結果が使用されます。 これが使用される状況は、 ユーザがファイアウォールにログインし、 このユーザに関する一時的なルールを設定するような場合です。

次の語は in か out のいずれかである必要があります。 カーネル内部を通過するパケットは、内向き (インタフェースにて受信された ばかりで、 カーネルのプロトコル処理部に向って移動している) か、 外向き (プロトコルスタックにより送出または転送され、 インタフェースに向かっている) かのいずれかです。 各フィルタルールが入出力のどちら側に適用されるのかを、 明示的に示す必要があります。

オプション

オプションの一覧は短く、事実すべて省略可能です。 オプションが使用されるところでは、ここに示す順序で置かれる必要があります。 次のオプションが現在サポートされています:

log 最後にマッチするルールの場合、 パケットヘッダが ipl ログに書き込まれます (後述のロギング節参照)。

quick
    フィルタを高速化したり後続のルールよりも優先させるために、 ルールの「ショートカット」を許します。 パケットが quick の印が付いたフィルタルールにマッチする場合、 このルールが最後にチェックされるルールになり、 「短絡 (short-circuit)」パスにより後続のルールが このパケットに対して処理されなくなります。 (現在のルールが適用された後に) パケットの現在の状態が、 パケットが通過されるかブロックされるかを決定します。

    このオプションが指定されないと、 ルールは「継続(fall-through)」ルールとされます。 つまり、マッチの結果 (ブロック/通過) が保存され、 更なるマッチがあるかをみるため処理が継続されます。

on  マッチ手続きにインタフェース名を組み込みます。 インタフェース名は "netstat -i" で表示できます。 このオプションを使用すると、 指定した方向 (入出力) にこのインタフェースを通過するパケットに対してのみ、 このルールがマッチします。 このオプションが指定されないと、 ルールはこのパケットが置かれたインタフェースに依存せずに (すなわち全インタフェースに) 適用されます。 フィルタルールセットは全インタフェースに共通であり、 各インタフェースに対してフィルタリストを持つのではありません。

    このオプションは特に、単純な IP 詐称 (IP spoofing) に対する防御として有用です: 指定したインタフェース上で、 指定した送信元アドレスであるとされる入力パケットのみを通し、 他のパケットをログしたりドロップすることができます。

dup-to
    パケットをコピーし、 複写したパケットを指定したインタフェースに対して外向きに送ります。 また、宛先 IP アドレスを指定して、変更することができます。 ネットワークスニファを使用して、ホスト外でログするために有用です。

to  指定したインタフェースにおいて、パケットを外向きキューに移動させます。 カーネルのルーティングを回避するために使用でき、 パケットに対する残りのカーネル処理をバイパスするためにも使用できます (内向きルールに適用された場合)。 よって、ルータではなく、フィルタリングハブやスイッチのように、 透過的に動作するファイアウォールを構築することができます。 fastroute キーワードは、このオプションの同義語です。

マッチングパラメータ

この節に記載されているキーワードは、ルールがマッチするか否かを決定するときに、 パケットのどの属性を使用するのかを記述するために使用されます。 以下の汎用属性がマッチングに使用でき、この順序で使用する必要があります:

tos 異なるサービス型 (Type-Of-Service) 値を持つパケットをフィルタできます。 この上、個々のサービスレベルや組み合わせでフィルタできます。 TOS マスクに対する値は、16 進数または 10 進数の整数で表現されます。

ttl パケットを生存時間 (Time-To-Live) 値で選択することもできます。 フィルタルールで与えられる値は、 マッチが行われるパケットの値と厳密にマッチする必要があります。 この値は、10 進数の整数でのみ与えることができます。

proto
    特定のプロトコルに対してマッチすることができます。 /etc/protocols 中の全プロトコル名が認識されますし、使用可能です。 また、プロトコルを 10 進数で指定することもできます。 これにより、あなた独自のプロトコルや 新しいプロトコルであるためリストが古くて掲載されていないものに対し、 マッチするルールを作成できます。

    TCP または UDP パケットにマッチする、 特殊なプロトコルキーワード tcp/udp を使用することができます。 このキーワードは、 同じルールをいくつも書かなくてもよいようにするため、追加されました。

from と to のキーワードは、 IP アドレス (および省略可能なポート番号) とマッチさせるために使用されます。 送信元と送信先の「両方の」パラメータを指定する必要があります。

IP アドレスの指定方法は、次の 2 つのうちのいずれかです: 数値によるアドレス/マスクまたは、ホスト名 mask ネットマスク。 ホスト名は、hosts ファイルまたは DNS 中 (設定やライブラリに依存します) の有効なホスト名か、ドット付き数値形式です。 ネットワーク指定として特別な記法はありませんが、ネットワーク名は認識されます。 フィルタルールを DNS に依存させると攻撃の余地を導入してしまうので、 勧められません。

ホスト名には特殊な any が許され、0.0.0.0/0 と認識されます (後述のマスク書式参照)。これは全 IP アドレスにマッチします。 "any" だけがマスクを暗黙的に指定しますので、 他の状況では、ホスト名はマスクとともに指定する必要があります。 ホストとマスクに対して "any" を指定できるものの、 この言語においては、意味を持たなくなります。

数値フォーマット "x/y" は、 1 のビットが MSB から開始して y 個連続するマスクの生成を示します。 よって、y の値が 16 である場合には、0xffff0000 になります。 シンボリックな "x mask y" は、 マスク y がドット付き IP 表現、 または 0x12345678 の形式の 16 進数であることを示します。 ビットマスクが示す IP アドレスの全ビットと、 パケットのアドレスとが、厳密にマッチする必要があります; 現在、マッチの意味を反転する方法はありませんし、 ビットマスクにて容易に表現可能ではない IP アドレス範囲にマッチさせる方法もありません (たとえるなら、ここまで実現すると、もはや朝食とは言えないですね)。

送信元と送信先のどちらかまたは両者に port マッチを含む場合、 TCP と UDP のパケットに対してのみ適用されます。 proto マッチパラメータが無い場合、 どちらのプロトコルのパケットも比較されます。 これは、"proto tcp/udp" と等価です。 port の比較を行うときには、 サービス名および数値のポート番号のどちらでも使用できます。 ポートの比較を行う際、数値形式を比較演算子とともに使用したり、 ポート範囲を指定したりできます。 ポートが from オブジェクトの一部として登場する場合、 送信元ポート番号にマッチします。 ポートが to オブジェクトの一部として登場する場合、 送信先ポート番号にマッチします。 更なる情報は使用例を参照してください。

all キーワードは、本質的に、 他のマッチパラメータを伴わない "from any to any" の同義語です。

送信元および送信先のマッチパラメータの後に、次の追加のパラメータを使用可能です:

with
    ある種のパケットのみが持つ特殊な属性にマッチする場合に使用します。 一般に、IP オプションが存在する場合にマッチさせるには、with ipopts を使用します。 完全なヘッダを格納するには短かすぎるパケットにマッチさせるには、 with short を使用します。 断片化されたパケットにマッチさせるためには、with frag を使用します。 更に、IP オプション固有のフィルタリングに関しては、 各オプションを列挙可能です。

    with キーワードの後にパラメータを続ける前に、 語 not または no を挿入し、 オプションが存在しない場合にのみフィルタルールがマッチするようにできます。

    with 節を連続して記述することが許されます。 また、キーワード and を、with の代りに使用することができます。 これは、純粋に可読性向上のためです ("with ... and ...")。 複数の節を列挙したとき、すべてがマッチするときに、ルールがマッチします。

flags
    TCP フィルタリングにおいてのみ有効です。 使用可能なレターは、TCP ヘッダにて設定可能なフラグの 1 つを表現します。 関連は次の通りです:

        F - FIN
        S - SYN
        R - RST
        P - PUSH
        A - ACK
        U - URG

    様々なフラグシンボルを組み合わせて使用できますので、 "SA" はパケット中の SYN-ACK の組み合わせを表現します。 "SFR" などの組み合わせの指定を制限するものはありません。 この組み合わせは、規則を守っている TCP 実装では通常生成されません。 しかしながら、異常を避けるために、 どのフラグに対してフィルタリングしているのかを示す必要があります。 このために、どの TCP フラグを比較するのか (すなわち、どのフラグを重要と考えるか) を示すマスクを指定できます。 これは、マッチ対象の TCP フラグ集合の後に、"/<flags>" を付けることで 実現できます。 例えば:

	... flags S
			# "flags S/AUPRFS" になり、SYN フラグ「のみ」
			# が設定されているパケットにマッチします。
	... flags SA
			# "flags SA/AUPRFSC" になり、SYN および ACK のフラグ
			# のみが設定されているパケットにマッチします。
	... flags S/SA
			# SYN-ACK の組のうち、SYN フラグのみが設定されている
			# パケットにのみマッチします。これは共通の「確立」
			# キーワード動作です。"S/SA" は SYN と ACK の組の
			# 「両方」が設定されているものにはマッチ「しません」
			# が、"SFP" にはマッチ「します」。

icmp-type
    proto icmp とともに使用した場合にのみ有効であり、 flags とともに使用しては「なりません」。 多くのタイプがあり、この言語で認識される短縮形や、 これに関連付けられた数値で指定できます。 セキュリティの観点からみて最も重要なものは ICMP リダイレクトです。

履歴保存

フィルタルールに設定可能な、最後から 2 番目のパラメータは、 パケットの履歴情報を記録するか否か、およびどのような履歴を保存するかです。 以下の情報を保存できます:

state
    通信セッションのフロー情報を保存します。 TCP, UDP, ICMP の各パケットに関して状態が保存されます。

frags
    断片化されたパケットの情報を保存します。 この情報は、後に断片化する際に使用します。

これらにマッチするパケットは素通しし、アクセス制御リストを通しません。

グループ
パラメータの最後の組はフィルタルールの「グルーピング」を制御します。 他のグループが指定されない限り、 デフォルトでは、全フィルタルールはグループ 0 に置かれます。 非デフォルトのグループにルールを追加するには、 グループの「頭 (head)」を作成するところから、グループを開始します。 パケットがグループの「頭」のルールにマッチする場合、 フィルタ処理はそのグループに切り替わり、 そのルールをそのグループのデフォルトとして使用します。 quick を head ルールとともに使用する場合、 そのグループの処理から戻るまでは、ルール処理は停止しません。

あるルールは、新規グループの頭でありかつ、 非デフォルトグループのメンバであることが可能です (head と group を同一ルール内で同時に使用可能です)。

head <n>
    新規グループ (番号 n) を作成することを示します。

group <n>
    このルールを、グループ 0 ではなく、グループ (番号 n) に置くことを示します。

ロギング

log アクションまたはオプションにて、パケットのログを行うとき、 パケットのヘッダが ipl パケットロギング擬似デバイスに書き込まれます。 log キーワードの直後に、次の修飾語句を (この順序で) 使用できます:

body
    パケットの内容の最初の 128 バイトを、ヘッダの後でログすることを示します。

first
    ログが "keep" オプションと共に使用される場合、 本オプションも指定することを勧めます。 これにより、トリガとなるパケットのみをログして、 この後に状態情報にマッチする全パケットをログしないようになります。

or-block
    なんらかの理由でフィルタがログを取れない場合 (ログ読み取りが非常に遅い場合など)、 このパケットに対するこのルールのアクションが block であったと解釈 させます。

level <loglevel>
    このパケットの情報ログに、 どのログファシリティと優先度を使用するか、 またはデフォルトファシリティでどの優先度を使用するかを指定します。 情報ログには、ipmon の -s オプションを使用します。

このデバイスに書き込まれるレコードのフォーマットについては ipl(4) を参照してください。 このログを読み取って整形するには、ipmon(8) を使用します。

使用例

quick オプションは次のようなルールに対して都合が良いです:
block in quick from any to any with ipopts

これは、 標準的な長さではないヘッダを持つ (IP オプションを持つ) パケットにマッチし、 この先のルール処理を行わずに、 マッチが発生したこととパケットをブロックすべきことを記録します。

次のような「継続」ルールの解釈により:

        block in from any to any port < 6000
        pass in from any to any port >= 6000
        block in from any to any port > 6003

範囲 6000-6003 が許され、他は許さないように設定できます。 最初のルールの効果よりも、後続ルールが優先することに注意してください。 同じことを行う、他の (容易な) 方法は次の通りです:

        block in from any to any port 6000 <> 6003
        pass in from any to any port 5999 >< 6004

効果を持たせるためには、 "block" および "pass" の両方をここに書く必要があります。 なぜなら、"block" アクションにマッチしないことが通過を意味するわけではなく、 ルールが効果を持たないことを意味するだけだからです。 ポートが1024未満のものを許すには、次のようなルールを使用します:

        pass in quick from any to any port < 1024

これは、最初のブロックの前に置く必要があります。 le0/le1/lo0 からのすべての内向きパケットを処理し、 デフォルトでは内向きの全パケットをブロックする 新規グループを作成するには、次のようにします:

       block in all
       block in quick on le0 all head 100
       block in quick on le1 all head 200
       block in quick on lo0 all head 300

そして、le0 で ICMP パケットのみを許すには、次のようにします:

       pass in proto icmp all group 100

le0 からの内向きパケットのみがグループ 100 で処理されますので、 インタフェース名を再度指定する必要がないことに注意してください。 同様に、次のように TCP などの処理を分解できます:

       block in proto tcp all head 110 group 100
       pass in from any to any port = 23 group 110

最終行を、グループを使用せずに記述すると、次のようになります:

       pass in on le0 proto tcp from any to any port = telnet

"port = telnet" と記述したい場合には、"proto tcp" を指定する必要があることに 注意してください。 なぜなら、 パーザは自己に基づいてルールを解釈し、 指定されたプロトコルによって全サービス/ポート名を修飾するからです。

関連ファイル
/dev/ipauth
/dev/ipl
/dev/ipstate
/etc/hosts
/etc/services

関連項目
ipftest(1), iptest(1), mkfilters(1), ipf(4), ipnat(5), ipf(8), ipfstat(8)