iptablesでNATする

# iptablesでNAPTする
[TRex](https://trex-tgn.cisco.com/)のDUTとしてUbuntu 18.10を選び、いろいろと試そうとしたときのメモ。TRexでNAPTでの戻り通信がどう処理されるのか検証するため、iptablesでのNAPT手法を調査した。
そもそものTRex環境構築は[こちらを参照](https://qiita.com/Shakapon/items/128f8d39cdacb8f1fc0a).

---
#基本的なところ
## Statusを見る
### -L
現行の設定を表示。ただし、tableを指定しないとfilter tableが表示される。natを見たいなら、-t natもつけてあげる必要がある。

```console
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
```

##設定する
### -t/--table
iptablesはTABLEとして4種類を持つ。NATで遊ぶ場合は、natを利用する。

|Tableタイプ|その役割|
|---|---|
|filter|パケットの透過や遮断を制御|
|nat |ネットワークアドレス変換|
|mangle| ToSフィールドの書き換え|
|raw |追跡を除外（特定の通信については、iptableでの制御をしないようにする等）|

rawに関してはちょっと特殊。iptablesを動かしている装置で処理をせず、素通しをさせたい場合に利用するらしい。DNSサーバへのアクセスはDNSサーバ自体に（あるいはその前に設置したLoad Balancerに）処理させるとか。

### -j/--jump

|target|設定可能なtable|その説明|
|---|---|---|
|SNAT|POSTROUTING|出ていくパケットのIPを変換<br />--to-sourceオプションでは、送信元アドレスの変換範囲を指定する。<br />-pオプションでTCP/UDPを指定した場合、:をつけて変換後のPort番号の範囲も指定可能。|
|DNAT|PREROUTING|宛先アドレスを変換する。入ってくるパケットのIPを変換し、サーバへRoutingする|
|MASQUERADE|POSTROUTING|変換後のアドレスを動的に割り当て|

##SNATとMASQUERADE
変換先アドレスが不定な場合（DHCP/PPPなどで割り当てられる）を想定された機能。固定的なIP接続であればSNATを利用するべき。SNATオプションとの違いとして、MASQUERADEでは、変換先IFが閉塞されるとTable情報が削除される（閉塞解除された際にアドレスが変わる可能性が高いため）。SNATではテーブルが維持される（静的な接続だから）

### Static NAT
アドレス空間が被るNWの間でRoutingをするのなら、これでいいのだろうね。

```console
iptables -t nat -A POSTROUTING -o ens39 -j SNAT --to-source 2.2.2.2
iptables -t nat -A PREROUTING  -i ens38 -j DNAT --to-destination 1.1.1.1
```

### Dynamic NAT
Globalアドレスを使いまわすのならこっち。Private:Globalを16:1とか128:1とかの比率で割り当てるようなこともしたいのだけれど、そこまで制御するやり方は見つけられなかった。TCP/UDPにだけ絞れば出来そうだったんだけれど、ICMPが入ってくると、さて。

```console
iptables -t nat -A POSTROUTING -s 1.1.1.0/24 -o ens39 -j MASQUERADE
```

#### ICMPのDynamic NAT
ICMPのNATってどうやるのと調べてみると、ICMPのIdentifierフィールドで制御できるっぽい、ということまでは分かった。じゃあ、iptablesでそれをどうやって実現するの、というと、よく分からない。A10なんかだと、すでにあるセッション情報と同じ接続先と思われるICMPパケットが来ると、その中身を見て処理してくれる。同じような仕組みはiptablesでもあるのではないだろうか？（未調査）

## NAPTのStatus確認
conntrackで確認可能。検索したらnetstat-natでと書いてあるサイトもいくつか見かけたが、少なくとも検証した条件ではnetstat-natではNAPTのステータスは確認できなかった。conntrackはaptで入手する。

```console
sudo apt install conntrack
```
実際の表示は下記のようになる。

```console
conntrack -L
tcp      6 393813 ESTABLISHED src=16.0.0.16 dst=48.0.0.14 sport=23195 dport=80 src=48.0.0.14 dst=2.2.2.3 sport=80 dport=23195 [ASSURED] mark=0 use=1
tcp      6 393813 ESTABLISHED src=16.0.0.12 dst=48.0.0.10 sport=19111 dport=80 src=48.0.0.10 dst=2.2.2.3 sport=80 dport=19111 [ASSURED] mark=0 use=1
```

表示例はこうなんだけれど、それぞれの意味するところはまだ調査が必要

## NAPTのロギング
どのようにNAPTされたのかを調べるために、logを吐かせたい。基本的なアイデアとして
1. 独自Targetを定義する(ここではNATwithLogging)
2. 独自Target内でNAT変換とLoggingを行う
3. 独自TargetをPOSTROUTINGにジャンプさせる
色々と考えたけれど、conntrackで変換Statusが取れるのなら、ここまでは不要かも。/var/log/syslogの溜まり方も凄まじかったし（ちょっと遊んでたら数百MBに達した）

    iptables -t nat -N NAPTwithLogging
    iptables -t nat -A NAPTwithLogging -m state --state NEW -j LOG --log-prefix " [>] New Forward"
    iptables -t nat -A NAPTwithLogging -s 1.1.1.0/24 -o ens39  -j MASQUERADE
    iptables -t nat -A NAPTwithLogging -s 16.0.0.0/24 -o ens39 -j MASQUERADE
    iptables -t nat -I POSTROUTING -o ens39 -j NAPTwithLogging

## iptablesの初期化
-tオプションでTableを指定しないと、デフォルトのfilter　Tableの設定が消される。-t natを指定して、nat Tableの設定を削除する。

    iptables -F
    iptables -t nat -F

---
## iptablesの永続化
iptablesで指定したルールはOSを再起動すると消えてしまう。このため、起動後に再度設定をする必要がある。Ubuntuではiptables-persistentパッケージを使うことでコントロール可能。

    sudo apt install iptables-persistent

iptablesの中身は下記に書き込まれる。
    
    /etc/iptables/rules.v4
 
### 保存と再読み込み
    sudo /etc/init.d/netfilter-persistent save
    sudo /etc/init.d/netfilter-persistent reload