iptablesの基本的な使い方

# はじめに

去年iptablesでFWサーバを構築したときの知識まとめ。
今回の記事はチェインについて書いています。
設定ファイル全体としてこう書くのが理想！みたいな内容ではありません。
各チェインがどのように作用するのかをまとめてみました。
最後に番外編として使っていて気付いたことなどを書いています。

# パケットフィルタリングを考えるときに気にすること

iptablesに入る前にパケットフィルタリングをする際に意識することを書きます。
通信制御をする際に考えることは4つ。
**どこに**
**どこから**
**どうやって**
**どうする**

5W2Hのような文言になりましたが詳しく書きます。

**どこに**
これはPortの場合もあれば、IPの場合もあります。
またPortとIPを両方使って決める場合もあるでしょう。
要するに送信先ですね。

**どこから**
これは送信元です。
どのIPからを許可するのかを把握します。

**どうやって**
これはプロトコルの意味です。
TCPなのかICMPなのかなどどのプロトコルの通信を許可するのかを決めます。

**どうする**
これがフィルタリングをするところで一番大切。
許可するのか拒否するのか。
iptablesとしては許可、拒否以外にも設定できるものはありますが、
基本パケットフィルタリングという観点では許可か拒否でしょう。

# iptablesとは

iptablesはファイアウォールとルータとしての機能を兼ね備えたパケットフィルタです。
Linuxには基本的に搭載されています。
ここからiptablesについての話になります。
ファイアウォールとして使うパケットフィルタリングと、
ルータとして使うルーティングについて書いていきます。

## iptablesの設定について

iptablesはコマンドラインから設定することも可能ではありますが、
私は設定ファイルを編集する方法でやっていたので設定ファイルに書くことを前提とします。
設定ファイルはデフォルトでは`/etc/sysconfig/iptables`にあります。

基本的な書き方がこんな感じ

```
-A チェイン -s どこから -d どこに(IP) -p どうやって --dport どこに(Port) -j どうする

例
-A INPUT -s 10.20.30.40/32 -d 192.168.100.200/32 -m tcp -p tcp --dport 12345 -j ACCEPT
```

チェインについては後で説明します。
まずはこんな感じでフィルタのルールを書いていきます。
例のルールは「10.20.30.40/32 のIPから192.168.100.200/32のポート12345へのTCP通信は許可」ということ。
`-m tcp`は送られてきたパケットの中で`tcp`にマッチしているものを見つけるオプションです。
この型で基本的な設定はできます。

`-s どこから`などは書かない場合は全部許可という設定になるので必ず書くものではありません。
ですが運用を考えると書かずに全許可はおすすめしません。
明記しておくことをおすすめします。

## パケットフィルタリングで使う3つのチェインと概念

さてでは先ほどでたチェインについて、まずは以下の三つを覚える。
チェインというのは経路だと考えてください。

* `INPUT`
* `OUTPUT`
* `FORWARD`

この三つのイメージがこんな感じ
![iptables](https://github.com/dtanimoto00/qiita/blob/master/iptables1.jpg?raw=true)

### INPUTについて

`INPUT`を使うと**FWサーバに入ってくるパケットの制御**ができます。
FWサーバ自体が外部と通信をしたりする場合は`INPUT`を使って通信を制御します。
つまり`INPUT`は**FWサーバ**に入ってくる通信の設定なので**どこに**については記述しなくてOKなのです。
基本的な書き方の話で言うと`-d どこに(IP)`の部分です。
ポートに関しては制御する必要がある場合は指定できるので`-dport どこに(Port)`の部分は適宜記述します。
`yum`とか使いたい場合はちゃんと`INPUT`で許可をしておかないと外から受信できなくなるので注意が必要です。

### OUTPUTについて

`OUTPUT`は**FWサーバから出るパケットの制御**ができます。
こちらも外部との通信の制御に使います。
`OUTPUT`の場合は**どこから**については記述しなくてOKです。
基本的な書き方の`-s どこから`の部分にあたります。

### FORWARDについて

`FORWARD`は**FWサーバを経由するパケットの制御**ができます。
`FORWARD`はFWサーバを通過してバックエンドサーバと通信をするパケットを制御できます。
このときFWサーバは経由するだけなので`INPUT`や`OUTPUT`を書く必要はありません。
`INPUT`と`OUTPUT`は**FWサーバ自身**の通信を制御しているので経由するときは関係ありません。

チェインについてはここまでです。

## ルーティングについて

さきほどのチェインの話はパケットフィルタリングで使用するものでした。
最初に軽く書きましたが、iptablesはファイアウォールとルータの機能もあります。
ここからルーティングの設定について書きます。

## ルーティングで使う2つのチェインと概念

以下の2つがルーティングで使うチェインです。

* `PREROUTING（DNAT）`
* `POSTROUTING（SNAT）`

カッコ書きで付け足しましたが要はDNATとSNATです。
イメージはこんな感じ
![NAT](https://raw.githubusercontent.com/dtanimoto00/qiita/master/nat.jpg)

### PREROUTING（DNAT）について

`PREROUTING`はようはDNATです。
入ってくるパケットのIPを変換して対象サーバへルーティングします。
書き方としてはこんな感じ

```
-A PREROUTING -m tcp -p tcp --dst 10.20.30.40 --dport 1111 -j DNAT --to-destination 192.168.10.20:1111
```

これで「IPが10.20.30.40のポート1111にきたパケットはIPを192.168.10.20に変換してポートはそのまま」というルーティングが完成。
DNATは**宛先アドレス**を変換します。

### POSTROUTING(SNAT)

`POSTROUTING`はようはSNATです。
出ていくパケットのIPを変換してルーティングします。
書き方としてはこんな感じ

```
-A POSTROUTING -s 192.168.10.20 -j SNAT --to 10.20.30.40
```

こちらはシンプルですね。
「192.168.10.20が送信するパケットはIPを10.20.30.40にする」というルーティングになります。
シンプルではありますがSNATは重要です。
どのIPから送信されているかは受信側にとって重要です。
SNATの書き忘れで私も何度かひっかかりました...

## パケットフィルタリングとルーティングの関係

ルーティングのところでアドレスが変換される話をしました。
ではアドレス変換が行われるということはパケットフィルタリングはどのように書くのか。
ずばり、
**ルーティングが行われた後、パケットフィルタリングが行われます!**

どうゆうことか。
ルーティングの説明の際に載せたイメージで説明します。
このイメージのオレンジの矢印は以下の流れになります。

1. 10.20.30.40のアドレスのポート1111へのアクセスがきます
2. FWサーバは`PREROUTING`に従い、宛先アドレスを192.168.10.20に変換します
3. FWサーバはアドレスを変換した後に192.168.10.20にパケットをルーティングします

この3の項目の際にパケットフィルタリングはどのように設定するべきなのかがポイントです。
もとは10.20.30.40に送信していたので、**どこに＝10.20.30.40**でした。
設定でいうと`-d 10.20.30.40`です。

ですが、iptablesの設定は`-d 10.20.30.40`**ではありません！！**
設定する必要があるのは**IPアドレスが変換された後のアドレスでの設定**です。

つまり、この場合はFWサーバを経由しているので`FORWARD`チェインで以下のように設定します。

```
-A FORWARD -s XXX.XXX.XXX.XXX -d 192.168.10.20/32 -p tcp -m tcp --dport 1111 -j ACCEPT
```

これで正しくルーティングとパケットフィルタリングができます。

**ルーティングが行われた後のIPでパケットフィルタリングの設定をする！*

以上で、基本的な使い方は終了です。


# 番外編

## IPのCider指定時の注意

ここまでいくつか設定のコードを載せましたが、例では指定するIPを`/32`で書いています。
ここはもちろん変更可能です。
ネットワークに合わせて書くことも可能です。

ただし、注意点が一点あります。
iptablesの設定ファイルは一行目から順にチェックし、マッチする条件があるとそこでチェックが終了します。
つまりCiderで指定すると条件にマッチする確率は高くなります。
実際に私がひっかかった例を出します。

```
-A POSTROUTING -s 192.168.10.0/24 -j SNAT --to 10.20.30.40
-A POSTROUTING -s 192.168.10.20 -j SNAT --to 10.20.30.100
```

この設定では2行目の`192.168.10.20`だけ`10.20.30.100`というIPに変換したかったのですが、
`192.168.10.20`は1行目に設定している`192.168.10.0/24`の条件にマッチするため`10.20.30.40`に変換されます。

後から見れば気づくのですが、この事象にかかったときもあとから特定のIPに対する設定を追記しました。
どうしても追記する際は今ある設定の下に書くことが多いと思います。（意識せず下に書くことがほとんどでしょう）
こうゆうことも起こりうるのでぜひ、
**Cider指定するときはできるだけ最後のほうに設定をいれる！！**
ということを覚えておいてください。

## 設定反映コマンドの恐怖

これは恐怖です。
まずは設定反映のコマンドがこちら

```
[正]iptables-restore < /etc/sysconfig/iptables

[誤]iptables-restore > /etc/sysconfig/iptables
```

このコマンドで**`<`**の記号の向きを逆に書くと設定がクリアされます。
空っぽになります。
本当に怖いのでこの向きはしっかり覚えてください。
リダイレクトの感覚で書くと失敗するので気を付けましょう。
本当に...

# おわりに

iptablesのパケットフィルタリングで使うチェインとルーティングに使うチェインについて色々書いてみました。
今回書いたチェインだけでもFWサーバとして機能するものを作ることは可能です。
ほかにもiptablesでは色々設定ができるので興味のあるかたは実際に使ってみてください。
ここまで読んでくださった方、ありがとうございました。

# 2020/07/16 追記
######（久しぶりに触って忘れてることが多かった...）

## コマンドで追加したルールのエクスポート
職場で質問されて理解してなかったので追記しておきます。
iptablesのコマンドで追加したルールはメモリ上に保存されるので、このままでは再起動時にルールが全てなくなってしまうのでiptablesファイルに書き込む必要があります。
メモリ上にあるルールをファイルに書き出すには以下のコマンドで実行できます。

```
/sbin/iptables-save > 設定ファイル
```

このコマンドでファイルにルールを書き出しておかないと復元に時間がかかってしまいます。

## iptables -L とhostsについて

iptables -Lのコマンドで現在の設定のリストを出力することが可能です。
このとき出力されるリストのなかにhostsに記載があるものはhostsに記載された名前で出力される。
なのでリストでみた場合IPが出力されずiptablesファイルの中からルールを探すのが面倒です...