それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

IPv6間のMasquerade(NAT)nftablesでLinux v6 GWを作る方法。

ipv6 NATをnftables

v4 の masquerade は次のようになっていた。

nft を使ってv4 を作る単純な例は次のようになる。

# テーブル追加
nft add table my_nat44
# テーブルにフィルタチェーンを追加
nft add chain my_nat44 postrouting { type nat hook postrouting priority 100 \; }
# masquerade する
nft add rule my_nat44 postrouting oifname "eth1" masquerade

これは省略形が含まれる。familyを省略せずに書くと、次のようになっている。

nft add table ip my_nat44
nft add chain ip my_nat44 postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip my_nat44 postrouting oifname "eth1" masquerade

消す場合は

nft delete table ip my_nat44

ip は IPv4 のことで、IPv6 の場合は ip6と書くので ip -> ip6 に変える

nft add table ip6 my_nat66
nft add chain ip6 my_nat66 postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip6 my_nat66 postrouting oifname "eth1" masquerade

nft の一般例で「ipは省略される」を思い出すのが大事。ipはIPv4を表し、IPv6はip6と記述する。これを思い出しておく、neftablesを扱うときは常に省略に注意を払う。

実際にやってみる。

次のような構成を作る。

構成を作る(LXD)

router としてのマシン作る

lxc launch ubuntu: router01

lan 側のnicn をrouter に挿し込む

lxc config device add router01 mytap0 nic nictype=macvlan parent=eth0
lxc exec router01 dhclient -v eth1

クライアントを作成する

lxc launch ubuntu: client01

2台分をアップデートすると時間がもったいないので、apt-cacherを使う。

echo 'Acquire::HTTP::Proxy "http://apt-cacher.lan:3142";' |sudo tee  /etc/apt/apt.conf.d/01proxy
apt update 
apt upgrade -y

メイン ルーター

メインルータにアドレスを追加。

ip addr add fd11:0801::1/64 dev br-lan

router01にアドレスを追加

ip addr add fd11:0801::2/64 dev eth1
ip addr add fc33:3e1f::1/64 dev eth0

client01 にアドレスを追加

ip addr add fc33:3e1f::2/64 dev eth0

疎通チェック

ssh main-router   -- ping fd11:0801::1
lxc exec router01 -- ping fd11:0801::1
lxc exec router01 -- ping fc33:3e1f::2
lxc exec client01 -- ping fc33:3e1f::1

まだこの状態では、NATをしていないので、パケットが通らないこと粉を確認

lxc exec client01 -- ping fd11:0801::1

パケットを転送する

router01 がv6 をForwardするように構成。これで、v6パケットが転送される。

lxc exec router01 -- sysctl -w net.ipv6.conf.all.forwarding=1

eth0 から受けたパケットをeth1へ転送するようにする。

経路を変える。

デフォルトのルートを削除する。

lxc exec client01 -- ip -6 route del default

v6アドレスは、すべてrouter01 へ向けてやる

lxc exec client01 -- ip -6 route add default via fc33:3e1f::1

この状態では、メインルータにICMP6が届くが、アドレス変換が掛かってない。そのため、メインルータは戻りパケットの送信先がわからない。

lxc exec client01 -- ping fd11:0801::1

ルータはにはパケット届いているのがわかる。

root@# ssh main-router -- tcpdump -n  -i br-lan icmp6
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-lan, link-type EN10MB (Ethernet), capture size 262144 bytes
18:20:56.536041 IP6 fc33:3e1f::2 > fd11:801::1: ICMP6, echo request, seq 4, length 64

この状態で通信するためには、選択肢は2つある。1つは戻りパケット経路を入れる、もう一つはNATする。この2つである。今回は、マスカレードを調べているので、NATする。

NAT・Masqueradeする。

router01 でマスカレードを構成すれば、通信できるはず。

lxc shell router01

nft / nftables をする。マスカレードする。

nft add table ip6 my_nat66
nft add chain ip6 my_nat66 postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip6 my_nat66 postrouting oifname "eth1" masquerade

疎通を確認する

lxc exec client -- ping fd11:0801::1

ちゃんとパケットの応答が出てくる。

PING fd11:0801::1(fd11:801::1) 56 data bytes
64 bytes from fd11:801::1: icmp_seq=1 ttl=63 time=1.71 ms
64 bytes from fd11:801::1: icmp_seq=2 ttl=63 time=1.34 ms
64 bytes from fd11:801::1: icmp_seq=3 ttl=63 time=1.21 ms

念のためにtcpdump で、NATしていることを確認する

メイン・ルータで確認

root# ssh router 'tcpdump -n  -i br-lan icmp6'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br-lan, link-type EN10MB (Ethernet), capture size 262144 bytes
18:27:27.517512 IP6 fd11:801::2 > fd11:801::1: ICMP6, echo request, seq 1, length 64

中間にいる router01で確認

lxc exec router01 -- tcpdump -n -i eth1 icmp6
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
09:28:53.183917 IP6 fd11:801::2 > fd11:801::1: ICMP6, echo request, id 62941, seq 1, length 64
09:28:53.184916 IP6 fd11:801::1 > fd11:801::2: ICMP6, echo reply, id 62941, seq 1, length 64

ちゃんと、NATしていることがわかる。

結論

nftablesでも3行あれば、IPv6 でもNAT変換して 'Unique Local Unicast' をグローバルユニキャストに変換してネットに出ていけることがわかる。

ポエム。nat66 による匿名性とセキュリティ

NATがないと、匿名性の確保が困難になる。また別の経路での通信(VPN)が困難である。すべてのIPv6端末にファイアウォール設定が必要になる。

ユーザ追跡が容易に可能になる。そのため、プライバシー面で問題だと思う。IPv6の使い捨てアドレスを追加で割り当てたとしてもプレフィックスは変わらない。なので、使い捨てアドレスがあってもNATしても、ユーザー追跡性は同じようなものである。NATを否定する理由にならない。

グローバルv6アドレスでグローバル通信を許可すると、機器はNAT制御の中にない。自宅のIP通信機器へ、世界中からアクセスすることが可能になる。このときに、保護はどうしたら良いのでしょうか。ネットに繋がる端末があふれる自宅になりつつあります。Google HomeやNestのような据え置き端末、食洗機や照明と言ったIoT機器がそれぞれが「機器自体でv6フィルタ機能を持つ」というセキュリティ機能が要求される。

しかし通信機器がフィルタ機能を持っていない。サポート面でも貧弱だ。さらに怖いことに、通信機器(IoT家電)のファイアウォール脆弱性を抱えていた場合に非常に面倒になる。アップデートが提供され続ける機器ならいいが、アップデートを怠るメーカやユーザーにより危険性が増す。脆弱性を突かれ、IoT機器は外部から操作されてしまう。そうならないよう、外部からの通信を遮断し、内部から外部への通信を許可し応答パケットだけを許可する必要がある。この設定を機器利用の全家庭に仕込まなくてはいけない。可能だろうか。

家庭用ルータでは機器から外部への通信(と応答パケット)を許可する設定を入れているとしても、その設定がルーターに入っているかどうか。安価なルータの説明書に書いてあるのでしょうか。アップデートは提供されるのでしょうか。そしてそれは一般人にわかるように説明書に記載ができるのでしょうか。

「内と外」という境界型のセキュリティは結局のところ必要になるし、境界型というのは「人間の肌感覚」にマッチしているので、SNATを使えば「アドレスが長くなっただけ」と認識できる。既存の知識の人たちには理解しやすいと思うのです。すべての機器にグローバルアドレスを割り当てる意味、懐疑的に見ています。一般市民にはGWもNATも無いグローバル接続は難しいのではないか。そう考えるとNAT-6-6でGWを作るのは悪くない選択肢だと思うのです。