パケットフィルタリング Netfilterの動作と設定

# Netfilterとは
CentOSで使用することができるパケットフィルタリングのパッケージ。
ネットワークドライバとカーネルの間でパケットの内容を精査し、設定に応じてパケットを破棄することで不正なパケットの排除を行う。
IPv4, IPv6の両方に対応している。

# パケットフィルタリングの流れ
パケットフィルタリングの処理はいくつかの順序があり、段階に応じてフィルタリングが行われる

1. Checksum and sanity
パケットのチェックサムをチェックし、不正な構造を持ったパケットはここで破棄される。

2. PreRouting
パケットのリダイレクトなど、ネットワークインターフェースから送られてきたパケットのアドレス変換などを行う。

3. Routing（一般的なネットワークのルーティング処理）
パケットのルーティング（宛先に向けて転送）を行う。

4. Forward（他のマシンに転送する）
ネットワークインターフェースから送られてきたパケットを転送する。

5. INPUT（自サーバのプロセスに配送して処理を行う）
ローカルプロセスにパケットを配送する。

6. OUTPUT（自サーバで処理したパケットを外に返す）
ローカルプロセスからネットワークインターフェースにパケットを配送する。

7. PostRouting
ネットワークに出力されるパケットに対して、アドレス変換などの処理を行う。

※ルーティングから先は状況に応じて処理順が異なる。

# Firewalld（Dynamic Firewall Manager）

## Firewalldとは
Netfilterの設定を管理するための使用するプログラム。
ファイアウォールの設定を行っても、通信を遮断せずに設定反映を行うことができる（サービス再起動が不要）。

## Firewalldの起動、停止、リロード

```bash:Command
# リロード
firewal-cmd --reload
# systemctlを使用してのreloadも可能
systemctl start|stop|reload|status firewalld.service
```

リロードは、永続的な設定（--permanentオプションを付けた設定）を行う場合に必要となる。
--permanentオプションを付けない設定は、一時的な設定となり、即時反映される。

## ゾーンの設定
Firewalldではインターフェースに特定のゾーンを割り当てて管理する。
割り当てたゾーンに対して、フィルタリング設定を行うことで特定の通信を許可、拒否することができる。

予め用意されているゾーン一覧

| ゾーン    | 用途 |
|:---------|:----|
| public   | デフォルトで適用されるゾーン。<br>公共領域での利用を想定したゾーン。<br>社内向けサーバなどが繋がる想定。 |
| work     | 業務での利用を想定したゾーン。<br>社内の業務PCが接続される想定。 |
| home     | 家庭内ネットワークを想定したゾーン。<br>家庭内のPCが接続される想定。 |
| internal | ファイアウォールにおける内部ネットワークを想定したゾーン。 |
| external | ファイアウォールにおける外部ネットワークを想定したゾーン |
| dmz      | ファイアウォールにおけるDMZネットワークを想定したゾーン。 |
| block    | 内部から外部への通信とその戻りパケットだけを許可するゾーン。<br>外部から内部への通信は拒否される。 |
| drop     | blockと同様だが受信パケットを拒否するのではなく破棄する。 |
| trusted  | すべてのネットワークコネクションを許可するゾーン。 |


## zoneの確認、設定
firewall-cmdコマンドを使用することで設定の確認や変更を行うことができる。

### ゾーン一覧を表示

```bash:Command
firewall-cmd --get-zones
```

### デフォルトゾーンの確認

```bash:Command
firewall-cmd --get-default-zone
```

### デフォルトゾーンの変更
デフォルトゾーンを変更すると今までデフォルトゾーンになっていたインターフェースやコネクションも設定するゾーンに変更される。

```bash:Command
firewall-cmd --set-default-zone=<zone>
```

### アクティブなゾーンを表示
ゾーンとインターフェースの対応を確認するコマンド。

```bash:Command
firewall-cmd --get-active-zone
```

### インターフェースのゾーン変更
--zoneでzoneを指定しない場合はデフォルトゾーンが設定される。

```bash:Command
firewall-cmd [--zone=<zone>] --change-interface=<interface>
```

### ゾーンの詳細な設定情報を確認する
zoneに属するインターフェース、許可されたservice、ポートへの通信、ポートフォワーディングの設定などを確認することができる。
--permanentを指定した場合は、永続化された設定のみ表示し、指定しなかった場合は現状で有効な設定が表示される。
--zoneを指定した場合は指定したzoneの情報を表示。指定がなければデフォルトゾーンの設定を表示。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --list-all
```

## サービスの公開設定

### 予め登録されているサービスを表示する。
このコマンドで表示されるサービスをゾーンに適用することで、サービスへのアクセスを許可することができる。

```bash:Command
firewall-cmd --get-services
```

### サービス公開設定
ゾーンにサービスを追加して、サービスへのアクセスを許可する。
--permanentを付けないと一時的な設定となり再起動で元の設定に戻る。また--permanentで永続化する場合はfirewalldのreloadが必要。
--zoneでサービス公開するゾーンを指定できる。指定がない場合はデフォルトゾーンが対象となる。
--timeoutを設定すると指定時間だけサービス公開することができる。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --add-services=<service> [--timeout=<seconds>]
```

### サービス公開の停止設定
オプションの意味は公開設定と同じ。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --remove-services=<service>
```

### 公開しているサービスの確認

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --list-services
```

## ポート開放設定
サービスが登録されていない場合は、ポート番号とTCP/UDPの組み合わせを指定してポート開放を行うことで通信を許可する。

### ポート開放設定
オプションはサービスのものと同様の意味。
ポートにはポート番号か、/etc/servicesに登録されているサービス名を指定する。
ポート番号は、10-100といった範囲指定も可能。
protocolにはtcpかudpのいずれかを指定する。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --add-port=<port>/<protocol> [--timeout=<second>]
```

### ポートを閉じる設定

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --remove-port=<port>/<protocol>
```

### ポート開放状態の確認

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --list-ports
```

## ポートフォワーディング
ポートフォワーディングの設定を行うことで、設定したゾーンに来た通信を他のサーバやポートに転送することができる。

### ポートフォワーディングの設定
基本的なオプションはサービスなどと同じ。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --add-foward-port=<expression> [--timeout=<seconds>]
```

ポートフォワーディングのexpressionは以下のように書く。

```
# 頭から順に受信ポート、プロトコル、転送先アドレス、転送先ポート
"port=<port>:proto=<tcp/udp>:toaddr=<dest address>:toport=<port>"
```

### ポートフォワーディングの設定削除
expressionは設定時と同様の書式

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --remove-foward-port=<expression> 
```

### ポートフォワーディングの設定確認

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --list-forward-ports
```

## リッチルールによるパケットフィルタリング
より複雑な条件でフィルタリングやポートフォワーディング、IPマスカレイドなどを行う場合には、リッチルールで実現することができる。
例えばアクセス元のIPアドレスに応じて特定の処理をするといったことができる。
条件にマッチした場合にログに記録するといったこともできる。

### リッチルールの追加
基本的なオプションはサービスなどと同じ。
ruleについては細かく設定可能なので、以下の公式サイトを参照。
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Using_Firewalls.html

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --add-rich-rule=<rule> [--timeout=<seconds>]
```

###　設定されているリッチルールの確認

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --list-rich-rule
```

### リッチルールの削除
削除するruleは、設定時と同じ書式で指定する。
--list-rich-ruleで確認したものをコピペすると間違いがない。

```bash:Command
firewall-cmd [--permanent] [--zone=<zone>] --remove-rich-rule=<rule>
```

## ダイレクトルールによるフィルタリング
ダイレクトルールを使用することでパケットの流れのどこでフィルタリングをかけるかを細かく指定することができる。
例えばINPUTやForward以外にOUTPUT時（パケットを外に送り出す際）に特定のパケットの送信をブロックすることができるので、内部から外部への特定の通信をさせたくない場合などに使用できる。

細かな設定が可能なので、設定値はmanなどを参照。

### ダイレクトルールの追加

```bash:Command
firewall-cmd [--permanent] --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>
```

### ダイレクトルールの確認

```bash:Command
firewall-cmd [--permanent] --direct --get-all-rules
```

### ダイレクトルールの削除

```bash:Command
firewall-cmd [--permanent] --direct --remove-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>
```