FreeBSD で ng_nat(4) を使用して NAT をする方法


始めに

netgraph の機能を使用して kernel 内に NAT node を作成し、 ipfw のルールで NAT すべきパケットを作成した NAT node へ転送することで、 kernel 内で NAT をすることが可能となる。 設定はそんなに難しくなく、ng_nat(4) に書いてある通りにすれば問題ない。

モジュールの読み込み

ng_ipfw と ng_nat が必要になるので、/boot/loader.conf に以下の設定を追加する。 もちろん ipfw の設定も必要だけど、ここでは省略。

ng_ipfw_load="YES"
ng_nat_load="YES"
    
NAT node の作成

/etc/start_if.fxp0 に以下のように書いて、 起動時に ngctl を実行して NAT node を作成するようにする。 ファイル名のインタフェース部分と、NAT する IP アドレスは環境に応じて変更する。 (本当はこのファイルに書くべき事では無いのかもしれないけど、他にいい場所が見当たらなかったので)

ngctl mkpeer ipfw: nat 60 out
ngctl name ipfw:60 nat
ngctl connect ipfw: nat: 61 in
ngctl msg nat: setaliasaddr AAA.BBB.CCC.DDD
    
ipfw へのルールの追加

ipfw のルールに以下の設定を追加して、NAT したいパケットを ng_nat へ送るようにする。 追加する場所、インタフェース名、設定方法はそれぞれの環境に応じて異なるので注意。

add netgraph 61 ipv4 from any to any in via tun0
add netgraph 60 ipv4 from any to any out via tun0
    

設定は /etc/ipfw.rule といったファイルに ipfw のルールを全部書いておいて、 rc.conf で firewall_type="/etc/ipfw.rule" とするのがお奨め。

ipfw の設定変更

/etc/sysctl.conf に以下の行を追加する。

net.inet.ip.fw.one_pass=0
    

デフォルトだと one_pass が 1 になっているため、 dummynet(4) や ng_ipfw(4) から戻ってきたパケットが再び ipfw を通らずに抜けてしまう。 これを 0 にすることで、戻ってきたパケットを ipfw の次のルールから適用させることができるようになる。 詳しくは ipfw(8) を参照。

rc.conf の確認

すでに ppp(8) や natd(8) で NAT を行っていた場合は、これらを無効にする。

natd_enable="NO"
ppp_nat="NO"
    
パフォーマンス

パフォーマンスの違いがどのくらいあるのか簡単に計ってみたけど、どうもあんまり違いは無いみたい。 FreeBSD で NAT をする方法はいろいろあるけど、パフォーマンス的にはどれもそんなに違いはなさそう。


にゃん <nyan@furiru.org>