目次

NetBSD and pf

あとで整理して書き直す。

# 溜まってきているのが辛い。

NetBSD pfでさんざんハマったので、メモ書き。

NATとPacket Filter

NetBSD 6系に載っているpfの挙動で少しハマったので、メモ。

つまり、Packet filterは「NAT処理された後」に適用される。Packet filter rule書く時に大ハマりするポイントなので注意。 (なお、当然、Packet filterを書けるI/Fも注意が必要)

---------------| pf |---------------|server|
         ext_if      int_if

この構成の時に、以下の1 NATルール、4パケットフィルタールールを使って実験

rdr pass on $if_ext proto { tcp,udp } from any    to $ext_if -> $server
block drop quick on $if_ext proto {tcp,udp} from any to $ext_if		# Rule 1
block drop quick on $if_int proto {tcp,udp} from any to $ext_if		# Rule 2
block drop quick on $if_ext proto {tcp,udp} from any to $server		# Rule 3
block drop quick on $if_int proto {tcp,udp} from any to $server		# Rule 4

それぞれのFilterルールをコメントアウトしたりしながら調べると、Rule 4のみが反映される。

Hair-Pin NAT

----------| pf |----------+----------|server-A|
    ext_if      int_if    |
                          +----------|server-B|

rdr pass on $if_ext proto { tcp,udp } from any    to $ext_if -> $server
<code>

この構成において、Server-Bからpfの$ext_ifのアドレス(いわゆるGlobal Address)に対してQueryを投げるとうまく動作しない。
これは、Server-Bからpfのext_ifにパケットを投げると、pfはint_ifから受け取ったパケットなので、NAT処理をしないから。

この状況は、いわゆるLoad Balancer構成を組んでいて、Multi tenantのサービスをしている時に困る場合がある。

このような時に、Server-B → int_if → Server-A に通信が出来れば良いと考えて、以下のruleを突っ込む
<code>
rdr pass on $if_int proto { tcp,udp } from $serverB to $ext_if -> $serverA

これで一見動きそうに見えるが、実はそうは問屋が卸さない。

何が起こるかを表にすると、こんな感じ。

node Src Addr Dest Addr 備考
ServerB ServerB if_ext
pf ServerB if_ext → ServerA に変換 NAT処理
ServerA ServerB ServerA
ServerAで内部処理
ServerA ServerA ServerB
pf ServerA/Bは同一セグメントなので、pfにパケットがこない
ServerB ServerA ServerB

これでは、TCPでもUDPでも「正しく」通信出来ているとは云えない。通常は、このようなパケットは破棄され、通信出来ない。

本来は、こうなって欲しい

node Src Addr Dest Addr 備考
ServerB ServerB if_ext
pf ServerB → if_int if_ext → ServerA に変換 NAT処理
ServerA if_int ServerA
ServerAで内部処理
ServerA ServerA if_int
pf ServerA → if_ext if_int → ServerB NAT処理
ServerB if_ext ServerB

というわけで、突っ込むべきRuleはこうなる

rdr pass on $if_int proto { tcp,udp } from $serverB to $ext_if -> $serverA
nat      on $if_int proto { tcp,udp } from $serverB to $serverA -> $if_int

全ポートを処理すれば良いのなら、binatでいいのだが、port 53だけ、このような処理をしたい場合には、nat(Src-NAT)とrdr(Dest-NAT)を組み合わせて二重変換を行わなければならない。

ちょいと特殊な設定なので、まぁ、普通は必要ないよね。