nft によるMSQUERADE(iptables MASQUERADEからの移行)
iptablesでマスカレード(またはSNAT)は古くから行われている枯れた手法。これをnft(nftables)に書き換える場合のメモ
次のような、マスカレード(NAT)をiptablesで追記しているとする。
iptables -I FORWARD -o ${interface} -j ACCEPT iptables -t nat -A POSTROUTING -o ${interface} -j MASQUERADE
たとえば、このように。ルーティングと組み合わせて使ってる。
DEST_NET=10.1.1.0/24 interface=vpn0 router=10.1.1.1.1 ip route add ${DEST_NET} via ${router} dev ${interface} ## iptables -I FORWARD -o ${interface} -j ACCEPT iptables -t nat -A POSTROUTING -o ${interface} -j MASQUERADE
これをnft(nftables)に書き換えてみると。
nft コマンドでは次のようになる。 テーブル追加とチェインの追加、そして、ルールの追加である。
interface=vpn0 router=10.1.1.1.1 TABLE=my_vpn_nat nft add table ip ${TABLE}; # 冗長じゃない? nft add chain ${TABLE} prerouting { type nat hook postrouting priority srcnat \; } nft add chain ${TABLE} postrouting type nat hook postrouting priority srcnat accept; nft add rule ${TABLE} postrouting oifname ${interface} masquerade nft add rule ${TABLE} postrouting oifname ${interface} masquerade
テーブルの追加
nft add table ip ${TABLE};
一般形式は次のようになっていて。
nft add table <?family> <name>
<?family>
にはip, ip6, inet ,arp, bridge
が使える。省略時は ip
である。ipはv4 アドレスを意味する。inet はinet = ip + ip6
であり、v6/v4に無関係(双方)を指す。
テーブルを削除する場合 add を delete にかえるだけである。(2023-08-29 現在 del ではエラーになる)
nft delete table <?family> <name>
サンプル
nft add table my_sample nft list tables # チェック nft delete table my_sample nft list tables # チェック
チェインの追加
チェインは、テーブル内部に作られる。チェインの中にはパケットのルールが入る。ルールをグループにして一括りにする。
nft add chain <?family> <table> <chain_name> { \ type <type> hook <hook> priority <priority> \; \ policy <policy> \; }
hook はチェインが実行されるタイミング。type は何をするか。
{ ... }
で括られた部分が、チェインに入るrule
である。
ip/ip6/inetにおいては、
hook={prerouting, input, forward, output, postrouting}
から一つ.type={filter,nat,route}
から一つを選ぶ。policy ={accept,drop}
から一つを選ぶ。priority
は、他のチェイン・ルールとの優先度±1 を書く。基本は0を書いておく。
ベースチェインの候補は、テーブル名やチェイン名と混同するような類似キーワードが多く初見殺しである。
以下をよく覚えておく。
type <type_name> hook <hook_name> priority <num|name>
例えばよくあるサンプルでは次のようになっている
nft add chain vpn_nat postrouting { type nat hook postrouting priority srcnat; policy accept; }
この場合、ベースチェインの名前=postrouting
となり、hook = postrouting
であり、type=nat
であり、priority=srcnat
である。postroutingとnatが、名前にもキーワードにも登場し、ややこしくなる。これが初見殺しである。
ベースチェインとはiptablesでも使っていた、mangle や nat のような特定パケットに一致する機能である。
ベースチェインのタイプ未指定にしたら、単なる関数になる。独立したチェインとして登録され、他チェインから呼び出されるために存在できる。
## ベースチェイン(タイプあり)の例 nft add chain ip MyMangle prerouting { type filter hook prerouting priority mangle \;} ## 単純チェイン(ベースタイプなし)の例 nft add chain ip MyMangle my_chain
詳しくは、公式wikiを参考にする。
ベースチェインは「パケットが条件一致したら呼び出される手順」、関数は「他チェインのルールから使われる手順」という違いがある。
マスカレード対象のフォワードをAcceptする。
iptable の場合は次のように先頭に書けば良い。
iptables -I FORWARD -o $TARGET_IF -i br0 -j ACCEPT
nftables の場合は次のように、対象のチェインに追記すると良い
nft insert rule inet fw4 forward iifname br0 oifname $TARGET_IF accept;
nftablesの場合は、同じチェイン内でaccept したら打ち止めになるが、ほかテーブルを参照している場合、他テーブルでDROPされる可能性もあるので注意する。デフォルトがDROP
などであれば、add
は使わずに、insert
でチェイン先頭にacceptを追記するようにする。