Linux Network Namespace（その４：NAT）

# Network NamespaceにてNAT
今回のNetwork NamespaceではNATを実現。ネットワーク環境は下記である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/0fc6298c-c45f-0d56-8c89-f86008955a8d.png)

中央のルーターがNAT機能を持ち、左側ネットワークがNAT内側、右側ネットワークがNAT外側である。

## 構築
### NG1
まずはトライアンドエラー1回目。NG例の紹介。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/881412ac-5feb-7a48-e45f-024cd264d2d1.png)

- Namespaceを一つだけ作成し（ns1）、仮想ネットワークインターフェースペアを２つ作成（veth1とns1-veth、veth00とveth01）
- veth1とveth00とがNATルーター（後述するiptableコマンドにてNATの設定）
    - veth1の左側がNAT内側、veth00の右側がNAT外側
- それぞれの仮想ネットワークインターフェースにIPアドレスをアサイン

が、1st space（ログイン後のシェルが起動している空間）から、ns1-vethへのpingが通ってしまう。

### NG2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/e5db2a5d-ba72-6775-a827-98a913979783.png)

- Namespaceを二つ作成し（ns1およびns2）、Namespace内に仮想ネットワークインターフェースペアを作成（ns1-veth0とns1-veth、ns2-veth0とns2-veth）
- ns1にてns2側ネットワークへのルートの宛先をns1-veth0、ns2にてns1側ネットワークへのルートの宛先をns2-veth0

が、ns1-veth0とns2-veth0とをつなげられず（ブリッジ化できず）、これもNG。

### OKだが複雑
下記は機能したが複雑。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/571c96c5-d8ac-453e-94df-9f634814ad5d.png)

- Namespaceを二つ作成（ns1およびns2）し、仮想ネットワークインターフェースペアを作成（veth1とns1-veth、veth2とns2-veth、ns1-veth10とns1-veth11、ns2-veth20とns1-veth22）
- ns1-vethとns1-veth10、ns2-vethとns2-veth20をブリッジ化
- veth1、veth2、ns1-veth11、ns2-veth22にIPアドレスをアサイン
- 1st spaceにて、IP Forwardにより、veth1とveth2との間の転送を有効化後、NAT化
 
コマンド多数必要、複雑。

### OK：これがEasy
トライを続け、下記構成が最も簡単であると判断。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/a68d73af-5213-d9c9-6d37-6b15b1c47620.png", width=70%>

以降、コマンド解説。

```shell
sudo ip netns add ns1
sudo ip link add name veth1 type veth peer name ns1-veth
sudo ip link set ns1-veth netns ns1
sudo ip link set veth1 up
sudo ip addr add 172.16.1.1/24 dev veth1
sudo ip netns exec ns1 ip link set lo up
sudo ip netns exec ns1 ip link set ns1-veth up
sudo ip netns exec ns1 ip addr add 172.16.1.11/24 dev ns1-veth
```

- Namespace ns1作成
- 仮想ネットワークインターフェースPairであるveth1およびns1-veth作成
- ns1-vethをns1に配置
- veth1をUpし、IPアドレスアサイン
- ns1のループバックおよびns1-vethをUp
- ns1のns1-vethにIPアドレスアサイン

```shell
sudo ip netns add ns2
sudo ip link add name veth2 type veth peer name ns2-veth
sudo ip link set ns2-veth netns ns2
sudo ip link set veth2 up
sudo ip addr add 10.1.1.1/24 dev veth2
sudo ip netns exec ns2 ip link set lo up
sudo ip netns exec ns2 ip link set ns2-veth up
sudo ip netns exec ns2 ip addr add 10.1.1.22/24 dev ns2-veth
```

- 上記ns1設定内容を、ns2にて実施

```shell
sudo sysctl -w net.ipv4.ip_forward=1

sudo ip netns exec ns1 ip route add 10.1.1.0/24 via 172.16.1.1
#sudo ip netns exec ns2 ip route add 172.16.1.0/24 via 10.1.1.1
```

- 1st space（ログイン時のシェルが起動している空間）のIP Forward（転送）を有効化
- ns1にてns2ネットワークへのスタティックルート設定
- （コメント化、未実行、後述）ns2にてns1ネットワークへのスタティックルート設定

## 検証
### NAT構築前
まず、NAT（後述iptablesコマンド）構築前に、上述したコメント文を外し、

```shell
sudo ip netns exec ns2 ip route add 172.16.1.0/24 via 10.1.1.1
```

を実施時（スタティックルート）の結果を記す。左側PCから右側PCへのping時のns2でのtcpdumpの結果である。

```
$ sudo ip netns exec ns1 ping 10.1.1.22 -c 1
PING 10.1.1.22 (10.1.1.22) 56(84) bytes of data.
64 bytes from 10.1.1.22: icmp_seq=1 ttl=63 time=0.083 ms

$ sudo tcpdump -nel -i veth2

18:07:18.447930 76:a5:94:32:bb:bf > 32:c7:9a:bf:0a:62, ethertype IPv4 (0x0800), length 98: 172.16.1.11 > 10.1.1.22: ICMP echo request, id 2532, seq 1, length 64
18:07:18.447941 32:c7:9a:bf:0a:62 > 76:a5:94:32:bb:bf, ethertype IPv4 (0x0800), length 98: 10.1.1.22 > 172.16.1.11: ICMP echo reply, id 2532, seq 1, length 64
```

Echo Requestを送出しているパケットのIPアドレスが、左側PCの172.16.1.11であることがわかる（NAT適用前なので当然）。

### NAT構築
下記iptablesコマンドにより、1st space内でNATを構築する。

```shell
sudo iptables -t nat -A POSTROUTING -o veth2 -j MASQUERADE
sudo iptables -P FORWARD DROP
sudo iptables -A FORWARD -i veth1 -o veth2 -j ACCEPT
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
```

この時の左側PCから右側PCへのping時のns2でのtcpdumpの結果は下記となる。（NAT構築前のコメント文はそのまま（未実行）。）

```
$ sudo ip netns exec ns1 ping 10.1.1.22 -c 1
PING 10.1.1.22 (10.1.1.22) 56(84) bytes of data.
64 bytes from 10.1.1.22: icmp_seq=1 ttl=63 time=0.089 ms

$ sudo tcpdump -nel -i veth2

18:03:43.935497 76:a5:94:32:bb:bf > 32:c7:9a:bf:0a:62, ethertype IPv4 (0x0800), length 98: 10.1.1.1 > 10.1.1.22: ICMP echo request, id 2730, seq 1, length 64
18:03:43.935518 32:c7:9a:bf:0a:62 > 76:a5:94:32:bb:bf, ethertype IPv4 (0x0800), length 98: 10.1.1.22 > 10.1.1.1: ICMP echo reply, id 2730, seq 1, length 64
```

Echo Requestを送出しているパケットのIPアドレスが、左側PCの172.16.1.11ではなく、NATにて変換された、10.1.1.1であることがわかる。OK。

EOF