OS Xを含むBSD系OSで使われている Firewall の pf の設定メモ.普段は Linux の iptables しか書いていない人なので間違っているところもあるかも.できるだけ iptables と対比させながら書いて見る.pfのテスト環境は10.0-RELEASE-p12
.iptablesの方は検証せずに書いているので参考程度に.
参考資料
原則
pf はルールが上から順番に評価されるが,マッチするルールがあってもそこで評価は停止しない.最後にマッチしたルールが適用される.ただし,quick
をつけた場合にはそこで評価が終了し,そのルールが適用される.
Rule Syntax
フィルタの文法は以下の通り.詳しくはOpenBSDのドキュメントを参照のこと
action [direction] [log] [quick] [on interface] [af] [proto protocol] \
[from src_addr [port src_port]] [to dst_addr [port dst_port]] \
[flags tcp_flags] [state]
FreeBSDでのpfの有効化方法
/etc/rc.conf
に以下の行を追加する.
pf_enable="YES"
pf_flags=""
pflog_enable="YES"
gateway_enable="YES"
とりあえず有効化するだけであればservice pf start
でできる.ログは別のサービスで取るのでservice pflog start
も必要.gateway_enable
はNATを使いたければ必要.
基本形
ローカルループバックは許可し,入ってくるパケットはログを取った上ですべて拒否する.ただし,出て行くパケットに関連付けられていたパケットは許可する.
# Allow Local Loop back
set skip on lo0
# packet is silently dropped
set block-policy drop
# Block and log add packets from outside
block in log all
# Allow all packets to go out, and keep state of them
pass out all keep state
pass out all keep state
で出て行くパケットの状態を記録し,これに関連する内向き通信を許可することを示している.関連すると判定された場合にはそもそもフィルタのチェック対象にはならない.iptablesの-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
に相当するが,in/outが逆なので一瞬戸惑う.
相当するiptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -j LOG --log-prefix "iptables-INPUT-drop:" --log-level 5
ログを確認する
ログは標準では/var/log/pflog
に出力されている.ただ,このログはバイナリなので直接は読めない.そこでtcpdump
を使う.
$ tcpdump -n -e -ttt -r /var/log/pflog
iptablesのようにログにヘッダーはつけられないけど,何番目のルールにマッチし,結果としてblockされたのかpassされたのかも一緒に記録されるのでそれほど問題にはならないはず.
もし,ログをリアルタイムに確認したければtcpdump -n -e -ttt -i pflog0
でできる.
特定のサービスのIncomingを許可
SSHを許可してみる.サービスの名前は/etc/services
にあるものが使える.数字でも良い.
set skip on lo0
set block-policy drop
block in log all
pass in proto tcp to any port ssh
pass out all keep state
相当するiptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j LOG --log-prefix "iptables-INPUT-drop:" --log-level 5
特定のアクセス元のみIncomingを許可
IPアドレスを指定して接続を許可する.この例では192.168.67.0/24
からのSSHアクセスを許可している.
set skip on lo0
set block-policy drop
block in log all
pass in proto tcp from 192.168.67.0/24 to any port ssh
pass out all keep state
相当するiptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -m state --state NEW -m tcp --dport 22 -s 192.168.67.0/24 -j ACCEPT
-A INPUT -j LOG --log-prefix "iptables-INPUT-drop:" --log-level 5
複数のポート,IPをまとめて指定する.
{}
で囲うことで複数のサービス/IPをまとめて指定できる.
set skip on lo0
set block-policy drop
block in quick proto udp to any port 17500
block in log all
pass in log proto tcp from {192.168.67.0/24, 192.168.68.0/24} to any port {ssh, http}
pass out all keep state
変数を使う
変数のようなものが使える.
set skip on lo0
tcp_services="{ ssh, http }"
acceptables_ip="{ 172.16.0.0/12, 192.168.0.0/16 }"
block in quick proto udp to any port 17500
block in log all
pass in log proto tcp from $acceptables_ip to any port $tcp_services
pass out all keep state