インターネットへの疎通を行うためにファイアウォールでSNAT設定を行うことがあると思います。
インターネットへの疎通であるため宛先は指定せず、 0.0.0.0/0
や Interfaceを通過するすべての通信を対象にSNAT設定を行いますが、例えばVPNを利用していると特定のセグメントのみ、SNATルールを適用させたくない場合などがあると思います。(特にVPNルータでのNAT設定)
今回FreeBSDのipfwとLinuxのiptablesでNATの除外設定を行ったのでメモとして残しておきます。
FreeBSDの場合
まずFreeBSDでnat設定をする場合、 natdが紹介されている事が多いのですが、ipfwでもNAT設定が可能です。私は基本ipfwでファイアウォールを使っているため、今回はipfwでNAT設定を行いました。
用途としてはjailで作成したインスタンスの通信を、SNATでインターネットへ疎通出来るようにしています。今回LANを 192.0.2.0/25
、 VPN接続先を 192.0.2.128/25
を例にipfwのnatルール設定を記載します。
ipfwのNAT有効化
sysrc firewall_nat_enable="YES"
ipfwの設定ファイル
nat 1 config ip {SNAT後IPアドレス}
# SNAT除外設定
add allow all from 192.0.2.0/24 to 192.0.2.0/24
add 2000 nat 1 ip from 192.0.2.0/25 to any
add 2001 nat 1 ip from any to {SNAT後IPアドレス} via {SNAT後IPアドレス}
ポイントなのがallowルールでLAN==VPN接続先のセグメント間を許可している点です。
ipfwはルールの番号通りルールマッチをしていくため、 NATルールの2000,2001の前にallowルールに合致すれば該当するトラフィックはNATされません。
例ではallowルールで明示的なルール番号を指定していませんが、自動的にルール番号が採番されNATルールより先に適用されています。適用されているルール、ルールの採番の確認は ipfw -a list
で確認出来ます。
また冒頭のNATルールの確認は ipfw nat 1 show config
などのコマンドで確認出来ます。
FreeBSDのkernel NAT良いな。ipfwでjailの通信簡単にNATでまとめられた。
— spg (@spg_games) September 20, 2020
natdよりipfwでnatした方がルール的にも書きやすい。
natのconfig確認、若干分かりづらいけれどhttps://t.co/8QzqZHLwO7
Linuxの場合
Linuxの場合はiptablesで同じくSNATルールに加え、除外ルールを書けば可能です。
今回OpenWrtでルールを書きました。VPNルータとしてSNATとVPNトラフィックを共存させるケースです。
今回も同じくLANを 192.0.2.0/25
、 VPN接続先を 192.0.2.128/25
として記載しています。
iptables -t nat -I POSTROUTING 1 -s 192.0.2.0/25 -d 192.0.2.128/25 -j RETURN
iptables -t nat -I POSTROUTING 2 -s 192.0.2.0/25 -j SNAT --to-source {SNAT後IPアドレス}
ポイントは以下2つです。
OpenWrtの場合、 POSTROUTING
ではなくLAN I/Fでは zone_lan_prerouting
のチェーンになっており、かつLuCIのバージョンが古いせいかRETURNルールはUIから設定出来なかったので Custom Rules で設定しました。(反映させるのに/etc/init.d/firewall restart
とかが必要でした。)
基本的にはFreeBSDと同じく、ルール順に処理されていくのでSNATルールの前にRETURNルールを入れてあげる所が大事ですね。
まとめ
今回FreeBSDのipfw, LinuxのiptablesでNATルールの除外ルール設定方法を紹介しました。
設定としてはシンプルなのですが、私自身結構苦戦しました 😇
VPNルータを構成する場合、この様なNAT除外設定が必要になってくるので参考になれば幸いです。