魔術師見習いのノート

プロフィール

魔術師見習い
Author魔術師見習い-_-.
Twitter魔術師見習い

コンピュータ関係のメモを主に書きます.

MENU

PF メモ

投稿日:
編集日:
タグ:

本稿はBSD系OSのパケットフィルタリングツールPFのメモ。参考にしたのはmanと以下のページである。

実行環境
OSFreeBSD
バージョン10.0
アーキテクチャi386

はじめに

PFを利用するには以下の4つの要素がある。

カーネルの設定
PFやPFのログ機能などを利用するにはカーネルの設定が必要である。私の実行環境では標準でPFやログ機能は利用可能だが、ALTQといわれるキューイング制御のためのフレームワークは利用不能であった。
設定ファイル
PF関連の起動スクリプトの設定(/etc/rc.conf)
pf_enable="YES"	# pfを実行可能に
pflog_enable="YES"		# PF用のログインタフェース
pflog_logfile="/var/log/pflog"	# PF用のログファイルのパスを指定
pf_rules="/etc/pf.conf"		# pfの設定ファイルを指定
/etc/sysctl.conf
net.inet.ip.forwarding=1
PFでパケット転送機能を使用するには前述の設定が必要である。OS起動後にこの値を変更するには、次のような処理を行えば良い。
user% sysctl net.inet.ip.forwarding=1
また、現在の値については以下のようにして取得できる。
user% sysctl net.inet.ip.forwarding
PFの設定(/etc/pf.conf)
以下に例を示す。
# Tables
table <private> const { 127.0.0.1 192.168/16 }
table <hosts1> persist

# Options
set block-policy drop

# Filtering
block in all
pass in from any to <private>
起動スクリプトの実行
PF関連のスクリプトにはpfやpflog、pfsyncなどがある。
  • user% /etc/rc.d/pf start
/dev/pf制御用コマンド(pfctl)
PFはpfctlコマンドを利用して制御できる。以下にいくつか例を示す。
ルールテキストのロード
user% pfctl -f /etc/pf.conf
テーブル操作
user% pfctl -t hosts1 -T add 192.168.1.3
ルールの確認
user% pfctl -s rules
本稿では特にこの3つを重視する。


カーネルの設定

PFやログ機能を利用するには、カーネルがそれに対応していなければならない。

pf
device pf
pflog
device pflog
ALTQ
ALTQ(ALTernate Queueing of network packets)というBSD系OSのネットワークインタフェースでのキューイング制御のためのフレームワークのこと。ALTQには以下に記すようないくつかのオプションがあるが、その全てが必要な訳ではない。各オプションの機能はmanを参照されたし。
options ALTQ
options ALTQ_CBQ
options ALTQ_RED
options ALTQ_RIO
options ALTQ_HFSC
options ALTQ_CDNR
options ALTQ_PRIQ
options ALTQ_NOPCC
options ALTQ_DEBUG
私の実行環境では標準でPFやpflogは利用可能だが、ALTQは利用不能だった。


pf.conf

PFの設定はpf_rulesで設定したファイル、または/etc/pf.confに記述する。pf.confはいくつかの種類の文からなり、それらは次の2種類に分類できる。

  • 変数やアドレスリストの定義
    • Macros
    • Tables
  • ルール行
    1. Options
    2. Normalization
    3. Queueing
    4. Translation
    5. Filtering

pf.confのサンプルを以下に示す。

#Comments #から文末までコメント
#Macros 変数の定義 net_if="alc0"
#Tables アドレスリストの定義 table <default> const { 10/8, 172.16/12, 192.168/16 } table <goodhost> persist # pfctlで追加するリスト
#Options パラメータの設定 set block-policy drop set timeout { icmp.first 20 }
#Normalization パケットの正規化(分断化されたパケットを再構築すること)の制御 scrub in all scrub out all random-id max-mss 1414
#Queueing 帯域幅の制御 queue http on parent std bandwidth 100M default
#Translation NATや他のアドレスへのリダイレクトの制御 # nat|rdr|binat on 〜 rdr on $net_if proto tcp from 192.168.1.4 to 192.168.1.2 port 10080 -> 192.168.1.3 port 80
#Filtering ブロックや通過の設定 #block|pass in|out 〜 block in on $net_if all # ファイアウォールから入るのを防ぐ pass in on $net_if from <default> # default内のアドレスの通過を許可 pass in on $net_if from <goodhost> # goodhost内のアドレスの通過を許可
pf.confの作成や修正が終わったならば、起動スクリプトの再実行("/etc/rc.d/pf restart")や設定ファイルの再読み込み("/etc/rc.d/pf reload")を行えば、ルールが適応される。


変数やアドレスリストの定義

Macros
PFではマクロが利用可能である。
代入
var="string"
評価
$var
マクロはインタフェース、IPアドレスやポート番号などを記述するのに便利である。
myaddr="192.168.1.2"
nif="alc0"
mport="{ 25, 110 }"
また、マクロの機能という訳ではないがインタフェースを()で囲うことでそれに割り当てられたIPアドレスを指定できる。
($nif)
Tables
PFではいくつかのアドレスの集合を表す仕組みにテーブルがある。テーブルはアドレスのリストで、これによっていくつかのアドレスに対してまとめてブロックや通過などを指定できる。アドレスはIPアドレスやネットワークアドレスを指定できる。また、テーブルには、タイプがいくつかある。以下にいくつか例を紹介する。
const
不変なアドレスリスト。以下のように設定ファイルに記述できる。
table <private> const { 10/8,  172.16/12, 192.168/16 }
table <local> const { 127.0.0.1, 192.168.1.15 }
persist
可変なアドレスリスト。以下のように設定ファイルに記述し、
table <badhost> persist
pfctlによって次のように制御できる。
追加
user% pfctl -t badhost -T add 192.168.1.3
削除
user% pfctl -t badhost -T delete 192.168.1.3
コマンドの詳細は"man pfctl"を参照されたし。


ルール行(1)

ルール行は標準では次のような設定に従う。

  • PFはフィルタルールセット(/etc/pf.conf)の先頭から末尾へと順に評価される。
  • 最後に一致したルールが採用される。
  • quickキーワードが付いたルールと一致する場合、そのルールを最終的に一致するルールとなる。
  • デフォルトではパケットは通過するように設定されている。

また、ルール行は次の順番で記述しなければならない。

  1. Options
  2. Normalization
  3. Queueing
  4. Translation
  5. Filtering
ただし本稿ではこの順番ではないので注意されたし。また、はじめに以下の3つを、続けて残りの要素を記す。
  • Filtering
  • Translation
  • Options
(Packet) Filtering
ファイアウォールの中や外への通信の遮断(block)や通過(pass)などを制御。組合せは以下の4つである。
inout
blockblock inblock out
passpass inpass out
そして、それにネットワークインタフェースの指定や宛先や送信元の指定することで細かな制限が可能である。例えば、ファイアウォールの外部のネットワークの"183.77.202.242"から内部の"192.168.1.2"への通信を遮断するには次のように記述する。
block in from 183.77.202.242 to 192.168.1.2
Filteringの行の書き方は以下のような流れである。
block/pass [quick] [on interface] in/out [log] from 〜 to 〜
指定するIPアドレスは直接記述したりTablesで定義したテーブルを指定したりできる。また、全てのアドレスを指す場合は"any"というキーワードが使用でき、"from any to any"と記述する場合は"all"と書いても良い。
block block-policy
通信を遮断。blockはblock-policyの設定に基づいて動作が変化する。blockのblock-policyを省略した場合の設定はOptionsで設定できる。block-policyには次のいずれかを設定できる。
drop
パケットは黙って破棄。
return
ブロックされたTCPパケットに対してTCP RST パケットが返され、 他のすべてのパケットに対しては ICMP UNREACHABLE パケットが返されます。
block-policyは次のようにして指定する。
block drop on all
また、Optionsでデフォルトを設定する場合、次のように記述する。
set block-policy drop
pass
パケットを通過。
route-to
replay-to
dup-to
fastroute
キーワードには次のようなものがあり、基本的に他のルール行と共通である。
<キーワードの一例>
inファイアウォールの中への通信か外への通信
out
logログを記録(pflogは通常/var/log/pflogにtcpdumpのバイナリ形式で記録される。ログの保存先はrc.confのpflog_logfileで指定可能)
on interfaceネットワークインタフェース
proto protocolプロトコル名。/etc/protocolsに記述されているプロトコル。
inetIPv4/v6
inet6
from送信元
to宛先
any全てのアドレス
allfrom any to anyのこと
portポート番号(TCPやUDP通信などの場合)
quick一致する場合それを最終的に一致するルールとする
以下に実際のFilteringルールの例を紹介する。
<サンプルルール>
re0を通したファイアウォール内の192.168.1.21のTCPの110番(POP3)に対するアクセスをブロック
block in on re0 inet proto tcp from any to 192.168.1.21 port 110
または
block in on re0 inet proto tcp from any to 192.168.1.21 port = 110
ポートの指定には次の記号が利用可能。
port = xxと等しい
port != xxと等しくない
port < xx未満
port <= xx以下
port > xxより大きい
port >= xx以上
port x:yx以上y以下
port x >< yx未満でかつyより大きい
port x <> yx未満かyより大きい
また、IPアドレスと同様にリストが使用できる("{ 22, 80 }")。
re0を通したファイアウォール内の192.168.1.21のTCPかUDPの110番(POP3)に対するアクセスをブロック
block in on re0 inet proto {tcp, udp} from any to 192.168.1.21 port = 110
指定したアドレス(badhost)からファイアウォール内へのアクセスをブロック
table <badhost> persist
block in from <badhost>
テーブル<badhost>へのアドレスの追加は次のように行う。
user% pfctl -t badhost -T add 192.168.1.3
ファイアウォール内への全てのICMPアクセスをブロック
block in inet proto icmp all
ログを記録
block in log inet proto icmp all
ログはpflogによって制御され、通常/var/log/pflogにtcpdumpのバイナリ形式で記録される。icmpであれば、次のようなコマンドでログを取得できる。
user% sudo tcpdump -n -r  /var/log/pflog icmp
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)
00:13:43.605085 IP 192.168.1.4 > 192.168.1.2: ICMP echo request, id 7202, seq 1, length 64
00:13:44.612563 IP 192.168.1.4 > 192.168.1.2: ICMP echo request, id 7202, seq 2, length 64
00:13:45.620305 IP 192.168.1.4 > 192.168.1.2: ICMP echo request, id 7202, seq 3, length 64
また、次のようなpop3をブロックするログがあるとする。
block in log on re0 inet proto tcp from any to 192.168.1.21 port 110
この時、このログは次のようにして取得できる。
user% sudo tcpdump -n -r /var/log/pflog port pop3
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)
00:25:00.624451 IP 192.168.1.4.51868 > 192.168.1.2.110: Flags [S], seq
 1646204942, win 14600, options [mss 1460,sackOK,TS[|tcp]>
00:25:01.622446 IP 192.168.1.4.51868 > 192.168.1.2.110: Flags [S], seq
1646204942, win 14600, options [mss 1460,sackOK,TS[|tcp]>
00:25:03.627292 IP 192.168.1.4.51868 > 192.168.1.2.110: Flags [S], seq
1646204942, win 14600, options [mss 1460,sackOK,TS[|tcp]>
Translation
宛先や送信元のアドレスの変更やポート番号などを制御。
rdr
リダイレクトまたはポートフォワーディング。あるパケットを別のIPアドレスや別のポート番号に転送する。例えば"192.168.1.4"から"192.168.1.2"のポート番号10080へのTCP通信を"192.168.1.3"のポート番号80に転送する場合、次のように記述する。
rdr proto tcp from 192.168.1.4 to 192.168.1.2 port 10080 -> 192.168.1.3 port 80
また、直接IPアドレスを指定せずインタフェースを()で囲えば、そのインタフェースに割り当てられたIPアドレスを指定できる。
rdr proto tcp from any to ($nif) -> 192.168.1.5
nat
NATまたはNAPT。あるパケットのアドレスやポート番号を変更する。例えば"192.168.1.2"からの通信を"192.168.1.100"に変更する場合、次のように記述する。
nat on alc0 from 192.168.1.2 to any -> 192.168.1.100
->の右辺は以下のようにインタフェース名を指定することもできる。
nat on alc0 from 192.168.1.2 to any -> alc1
rdrとは異なり、->の右辺で指定するのは宛先ではなく送信元である。また、宛先ポート番号は指定できないが、送信元ポート番号を指定できる。NAPTは次のように行う。
nat on re0 proto tcp from 192.168.1.2 port 80 to any -> 192.168.1.100
natの状態はpfctlで確認可能である。
user% pfctl -s nat
なお変更後のアドレスには任意のアドレスを利用できるが、通信が成り立つためには相手が経路を確保できることとこちらのインタフェースがそれを取得できることが必要である。例えばローカルネットワーク"192.168.1.0"内で、"192.168.1.2"と"192.168.1.3"のマシンが通信を行い、"192.168.1.2"を"192.168.1.100"に変更する場合、それぞれのマシンで次のような処理が必要である。
192.168.1.2のマシン
pf.confに次の行を追加。
nat on re0 from 192.168.1.2 to any -> 192.168.1.100
インタフェースに"192.168.1.100"をエイリアスし、受信可能にする。
user% ifconfig re0 alias 192.168.1.100
192.168.1.3のマシン
192.168.1.2のMACアドレスが"01:23:45:67:89:ab"の時、192.168.1.100に対応するMACアドレスをそれに対応づける。
user% arp -s 192.168.1.100 01:23:45:67:89:ab -i eth0
binat
双方向マッピング。ある2つのアドレスやポート番号を対応させる。例えば192.168.1.1と192.168.1.5を対応付けるには次のように記述する。
binat on re0 from 192.168.1.1 to any -> 192.168.1.5
Translationの特定の通信だけを一致させないために、"no"というキーワードがある。例えば特定のアドレス("192.168.1.4")への通信の場合にNATを行わない場合、次のように記述する。
no nat on re0 from 192.168.1.2 to 192.168.1.4
nat on re0 from 192.168.1.2 to any -> 192.168.1.100
なおこのような場合最初に一致したルールが最終的な一致となる。
Options
PFや通信に関する基本的な情報を設定。以下にサンプルを示す。
set block-policy drop
set timeout { icmp.first 20 }
詳しくは"man pf.conf"を参照されたし。
timeout
loginterface
limitパケットフィルタで使用するメモリプールの限界値。
ruleset-optimization
optimization
block-policyFilterのblockでblock-policyを省略した場合のblock-policy。
state-policy
hostid
require-order
fingerrpints
skip on
debug


ルール行(2)

編集中

Traffic Normalization
分断化されたパケットを再構築(正規化)する際の制御。詳しくは"man pf.conf"を参照されたし。
scrub in all
scrub out all random-id max-mss 1414
Queueing


pfctl

pfctlの詳細は"man pfctl"で閲覧できる。以下にいくつかpfctlの機能を紹介する。

ルールテキストのロード
user% pfctl -f /etc/pf.conf
テーブル操作
user% pfctl -t hosts1 -T add 192.168.1.3
ルールの確認
user% pfctl -s rules
PFを有効に
user% pfctl -e
PFを無効に
user% pfctl -d


メモ

  • タグ

一覧