あとで整理して書き直す。
# 溜まってきているのが辛い。
NetBSD pfでさんざんハマったので、メモ書き。
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のみが反映される。
----------| 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)を組み合わせて二重変換を行わなければならない。
ちょいと特殊な設定なので、まぁ、普通は必要ないよね。