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


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

  3. モジュールの読み込み
  4. ng_ipfw と ng_nat が必要になるので、 /boot/loader.conf に以下の設定を追加する。 もちろん ipfw の設定も必要だけど、ここでは省略。

    ng_ipfw_load="YES" ng_nat_load="YES"

  5. NAT node の作成
  6. /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

  7. ipfw へのルールの追加
  8. 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" とするのがお奨め。

  9. ipfw の設定変更
  10. /etc/sysctl.conf に以下の行を追加する。

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

  11. rc.conf の確認
  12. すでに ppp(8) や natd(8) で NAT を行っていた場合は、 これらを無効にする。

    natd_enable="NO" ppp_nat="NO"

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


にゃん <nyan@furiru.org>