iptables学習メモ

## はじめに
iptablesがよくわかっていないので勉強した時のメモ
学習教材:
https://straypenguin.winfield-net.com/iptables.html

## 構造
### テーブル(filter,nat,mangle)
組み込まれているチェーンは、テーブルの種類によって異なる。

### チェーン(PREROUTING, INPUT, OUTPUT, FORWARD, POSTROUTINGおよびユーザ定義チェーン)
ルールのまとまりによるフィルタリングアルゴリズム。

### ルール(ACCEPT, DROP, REJECT, LOG, RETURN, TOS, TTL, MARK, DNAT, SNAT, MASQUERADE, QUEUE, REDIRECTなど)
「パケットがこれこれだったら、そいつをこう操作せよ」 という指示。設定できるルールはチェーンによって異なる。例えばDNATは、natテーブルPREROUTINGチェーンなどに登録する

## 主なコマンド
### ルール操作
-t table: テーブルを指定。デフォルトではfilterテーブル
-A chain rule: chainにruleをappend
-D chain rule: chainのruleをdelete。numberでも指定可能
-I chain rule_number rule: chainにruleをnumber位置にinsert。rule_numberのデフォルト値は0。
-R chain rule_number new_rule: rule_numberの位置のruleをnew_ruleでreplace

### チェーン操作
-N new_chain_name: New。チェーンを作成(ex. `ip6tables -t filter -N new_chain_name`)
-P chain policy: chainの基本Policyをセット。ルールでドロップして残りは受け入れる (ACCEPT) か、ルールでアクセプトして残りを拒否する (DROP) かのいずれか。ユーザ定義チェーンには使えない
[-t table] -X [chain]: 指定したchain（ユーザ定義に限る）を削除
[-t table] -L [chain] [options]: chainにあるruleをリスト出力

## 実験
ip6tables -t filter -L などで、確かにChainが出てきた。
ip6tables -t filter -N my_new_chain で、chainを追加できた
ip6tables -t filter -A my_new_chain で、ruleを追加できた(こんなに空っぽでも追加できるのか)

また、Ubuntuで、
`iptables -t filter -A INPUT -p tcp --dport 8080 -j DROP` を実行したら、ちゃんとLANの別のマシンから8080へアクセスしようとしたら、アクセスできなかった。
さらに、`iptables -t filter -L -v` で、パケット数を見てみたら、LANの別のマシンからアクセスするたびに増えていっていた。

なお、変更は基本的にすべて、再起動で消えるらしい。また、SSH先のUbuntuで作業している場合（私の場合はそう）、うっかり閉め出されるといけないので、作業している時は、
(sleep 300 && iptables -F) & などをしておくと安全らしい（SSH先のUbuntuは私の場合は、別室にあるので、マシンのある部屋まで行って直接再起動すればよいので不要そう）

`sudo iptables -A OUTPUT -p udp --dport 53 -j DROP` したら、ちゃんとDNS解決ができなくなった。

```sh
sudo ip6tables -t filter -L | grep Chain
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy DROP)
Chain OUTPUT (policy ACCEPT)
Chain DOCKER (1 references)
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
Chain DOCKER-ISOLATION-STAGE-2 (1 references)
Chain DOCKER-USER (1 references)

sudo ip6tables -t nat -L | grep Chain
Chain PREROUTING (policy ACCEPT)
Chain INPUT (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)
Chain POSTROUTING (policy ACCEPT)
Chain DOCKER (2 references)

sudo ip6tables -t mangle -L | grep Chain
Chain PREROUTING (policy ACCEPT)
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)
Chain POSTROUTING (policy ACCEPT)
```

Dockerと名前の入ったもの以外はデフォルトの模様。

## ルール操作
条件 -j 動作または他のユーザ定義チェーン[オプション]

```
"!" を挟むと意味を反転 (否定) できる。
-p [!] protocol	tcp, udp, icmp, all のいずれか。all は「ありとあらゆるプロトコル」ではなく、tcp, udp, icmp を指す。指定無しは all と同じ
-s [!] address[/mask]	送信元アドレス。ネットマスクは4オクテット書式、CIDR書式とも可
-d [!] address[/mask]	宛先アドレス
-i [!] interface[+]	入ってくるインターフェイス。eth+ などとすると eth0, eth1.. .にマッチ
-o [!] interface[+]	出て行くインターフェイス
```

## 動作（ジャンプターゲット）の主なもの
```
ACCEPT: 受け入れる
DROP: 黙って捨てる
```

## テーブルとチェーンの仕様
### filterテーブル
INPUT, FORWARDチェーン

どちらもPCに到達してくるパケットが該当。
INPUTは、そのPCが終端のパケット。
FORWARDは、つぎのデバイスへ転送する必要があるパケット。

OUTPUTチェーン
そのPCで発生して、外へ出ていくパケット。なお、FORWARDの結果、次のマシンへ転送することになった場合、一見そのPCから出ていっているようにも見えるが、この場合はOUTPUTチェーンは利用されない（あくまでOUTPUTは、そのPCが作成したパケットのみに対応する）。


## コラム(静的ルーティングCRUD)
どのIPアドレスは、どの
### create
ip route add <IPアドレス>/<サブネットマスク> [dev <デバイス名>] via <デフォルトゲートウェイ>
例: ip route add 172.17.0.0/16 dev eth0 via 192.168.1.70

### read
ip route

### update
不可能。消して作るしかないらしい

### delete
ip route delete 172.17.0.0/16 dev eth0 via 192.168.1.70
delete 以外については、条件文となるもよう。
ただ、viaは無視されているかも。

## NATテーブル
PREROUTING、OUTPUT、POSTROUTINGチェーン

### PREROUTING、POSTROUTINGは、外から来たパケットに関するチェーン。
PREROUTINGはルーティングの前、POSTROUTINGはルーティングの後。
すなわち、PREROUTING、ルーティング、POSTROUTINGの順番。
具体的な用途としては、
* PREROUTING
宛先NAT(DNAT)
* POSTROUTING
送信元NAT(SNAT)、マスカレード

### OUTPUTは、自分のマシンが生成したパケットに関するチェーン。
具体的な用途としては、
* OUTPUT
ローカルでの宛先NAT(DNAT)
例:ルーターに設定して、内部のネットワークからのパケットのL3ヘッダのソースIPアドレスを、ルーターが送信する送信元インターフェースのIPアドレスに変換する(NATゲートウェイ)。
```sh
# 内部ネットワーク (192.168.1.0/24) を外部ネットワークにNATする
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
```
例:外部からの特定のサービスへのリクエストを内部サーバへ転送する(ポートフォワード)
```sh
# 外部ポート80のリクエストを内部サーバ192.168.1.100:80に転送
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80
```