概要
前回の
の続きで、今回はネットワーク名前空間から外部ネットワークへアクセスできるようにします。
環境
- Ubuntu 18.04
以下の状態からスタートします。
手順
ip_forward
の有効化
デフォルトだとIP FORWARDは無効になっているため、有効にしておきます。
# echo 1 > /proc/sys/net/ipv4/ip_forward
永続化したい場合は/etc/sysctl.conf
に
net.ipv4.ip_forward = 1
を設定します。
ネットワーク名前空間のデフォルトゲートウェイをveth1
に
host1
やhost2
のルーティングテーブルを確認すると、デフォルトゲートウェイが設定されていません。
$ sudo ip netns exec host1 netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 host1
なのでインターネットのアドレスでアクセスしようとするとルーティングテーブルはどこにパケットを投げていいか分からず次のようにunreachable
でコケます。
root@ubuntu-bionic:~# ping 8.8.8.8 connect: Network is unreachable
そこで10.0.0.0/24
サブネット以外の宛先IPの場合、10.0.0.100
へ転送するようにデフォルトゲートウェイを設定します。
$ sudo ip netns exec host1 ip route add default via 10.0.0.100 $ sudo ip netns exec host2 ip route add default via 10.0.0.100
するとルーティングテーブルにデフォルトゲートウェイが設定されます。
$ sudo ip netns exec host1 netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.0.0.100 0.0.0.0 UG 0 0 0 host1 10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 host1 $ $ sudo ip netns exec host2 netstat -rn Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 0.0.0.0 10.0.0.100 0.0.0.0 UG 0 0 0 host2 10.0.0.0 0.0.0.0 255.255.255.0 U 0 0 0 host2
これによって10.0.0.0/24
サブネット以外の宛先IPの場合、パケットは10.0.0.100
へ転送されます。
$ sudo ip netns exec host1 traceroute 8.8.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 10.0.0.100 (10.0.0.100) 0.135 ms 0.006 ms 0.005 ms 2 * * * 3 * * *
このように10.0.0.100
まで到達できるようになりました。
NATテーブルの設定
しかしまだ10.0.0.100
に届いたパケットは外部インターネットへと届きません。
なぜならこの時のパケットは以下の状態なのですが、
パケットのIPヘッダ | 値 |
---|---|
送信元IP | 10.0.0.1 |
宛先IP | 8.8.8.8 |
インターネット側からみたらプライベートIPである10.0.0.1
は見えません。そういった送信元IPと宛先IPがはっきりしないパケットは破棄されてしまいます。
そこでiptablesのNATテーブルを利用します。
送信元アドレスが10.0.0.0/24
サブネットのパケットの送信元IPを、外部ネットワークに繋がっているNICenp0s3
のIP10.0.2.15
へと書き換えます。
※今回ホストLinuxはvagrantなので実際にはこのようなIPアドレス変換が何度か繰り返されます
$ sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o enp0s3 -j MASQUERADE $ sudo iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 10.0.0.0/24 anywhere
これによってパケットのIPヘッダの送信元IPは、外部からでも疎通できるIPになります。
動作確認
では動作確認してみます。
$ sudo ip netns exec host1 traceroute 8.8.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 10.0.0.100 (10.0.0.100) 0.051 ms 0.013 ms 0.010 ms 2 10.0.2.2 (10.0.2.2) 0.408 ms 0.220 ms 0.260 ms 3 * * * ... 10 * 108.170.242.193 (108.170.242.193) 21.429 ms 108.170.242.129 (108.170.242.129) 21.179 ms 11 108.170.233.81 (108.170.233.81) 20.049 ms 8.8.8.8 (8.8.8.8) 8.280 ms 72.14.238.75 (72.14.238.75) 8.350 ms
ネットワーク名前空間から外部インターネットへと疎通することができました。
またveth1
とenp0s3
のパケットキャプチャをするとNATによって送信元IPが上書きされていることが分かります。
Q&A
MASQUERADEはホストLinuxからhost1
へのパケットに影響しないのか
先ほど送信元アドレスが10.0.0.0/24
サブネットのパケットの送信元IPを〜書き換えると述べました。
とするとホストLinux10.0.0.100
からhost110.0.0.1
へのパケットも条件に当てはまるのではないでしょうか?
ホストLinuxからhost1
へpingを打った時のtcpdumpをhost1
側でとってみると特にアドレス変換は入っていません。
root@ubuntu-bionic:~# tcpdump -i host1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on host1, link-type EN10MB (Ethernet), capture size 262144 bytes 18:12:22.574303 IP 10.0.0.100 > 10.0.0.1: ICMP echo request, id 13133, seq 1, length 64 18:12:22.574316 IP 10.0.0.1 > 10.0.0.100: ICMP echo reply, id 13133, seq 1, length 64 18:12:23.591129 IP 10.0.0.100 > 10.0.0.1: ICMP echo request, id 13133, seq 2, length 64 18:12:23.591157 IP 10.0.0.1 > 10.0.0.100: ICMP echo reply, id 13133, seq 2, length 64 18:12:24.610498 IP 10.0.0.100 > 10.0.0.1: ICMP echo request, id 13133, seq 3, length 64
これはホストLinuxとネットワーク名前空間host1
はL2ブリッジで繋がっているためです。
L2でつながっているのでiptablesが扱うIPパケットをカプセル化したEthernetフレームのまま状態でデータが届くのです。
つまり今回ホストLinuxとネットワーク名前空間host1
はL2のブリッジ(水色)で繋がっているためiptablesのフィルタ(黄緑)を通りません。
ref: ebtables/iptables interaction on a Linux-based bridge
その代わりL2=Ethernet層のフィルタが可能なebtables
というコマンドがあるので、それを使うとブリッジでもフィルタすることができます。
まとめ
NATによるアドレス変換を用いて、ネットワーク名前空間から外部ネットワークへアクセスすることができました。