Ubuntu 19.10 Eoan Ermine で iptables を使ったパケットフィルタリング設定とその永続化

## 概要

- iptables-save / iptables-restore コマンドで設定を保存・反映する
- IPv4 と IPv6 の両方を設定する
- netfilter-persistent コマンドで設定を永続化する (OS再起動しても設定が消えないようにする)
- nmap でポートスキャンを実行して iptables の設定が反映されているか確認する

## iptables-save / iptables-restore コマンドで設定を保存・反映

### 初期設定を確認する (IPv4)

iptables コマンドと iptables-save コマンドで確認する。

```
$ 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
```

```
$ sudo iptables-save
# Generated by iptables-save v1.8.3 on Sun Jan 12 23:15:35 2020
*filter
:INPUT ACCEPT [1796:190499]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1400:212762]
COMMIT
# Completed on Sun Jan 12 23:15:35 2020
```

### ルールを書く (IPv4)

今回はパケットフィルタリングのルールを rules.v4 というファイルに保存した。

```
*filter
:INPUT   DROP   [0:0]
:FORWARD DROP   [0:0]
:OUTPUT  ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP
-A INPUT -p tcp ! --syn -m state --state NEW -j DROP
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP
-A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-name t_icmp --hashlimit 1/m --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-htable-expire 120000 -j ACCEPT
-A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m state --syn --state NEW --dport 22 -m hashlimit --hashlimit-name t_sshd --hashlimit 1/m --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-htable-expire 120000 -j ACCEPT
-A INPUT -p tcp --dport 80   -j ACCEPT
-A INPUT -p tcp --dport 443  -j ACCEPT
COMMIT
```

ルールの内容は [ファイアウォールiptablesを簡単解説～初心者でもよくわかる！VPSによるWebサーバー運用講座\(4\) \| さくらのナレッジ](https://knowledge.sakura.ad.jp/4048/) を参考にした。

### ルールを反映する (IPv4)

iptables-restore コマンドでルールを反映する。

```
$ sudo iptables-restore < rules.v4
```

設定が反映されていることを確認する。

```
$ sudo iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
DROP       tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,PSH,ACK,URG/NONE
DROP       tcp  --  anywhere             anywhere             tcp flags:!FIN,SYN,RST,ACK/SYN state NEW
DROP       tcp  --  anywhere             anywhere             tcp flags:FIN,SYN,RST,PSH,ACK,URG/FIN,SYN,RST,PSH,ACK,URG
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request limit: up to 1/min burst 10 mode srcip htable-expire 120000
ACCEPT     tcp  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     udp  --  anywhere             anywhere             udp spt:domain
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh flags:FIN,SYN,RST,ACK/SYN limit: up to 1/min burst 10 mode srcip htable-expire 120000
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https

Chain FORWARD (policy DROP)
target     prot opt source               destination         

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

```
$ sudo iptables-save
# Generated by iptables-save v1.8.3 on Sun Jan 12 23:16:24 2020
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [50:6132]
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m state --state NEW -j DROP
-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m hashlimit --hashlimit-upto 1/min --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-name t_icmp --hashlimit-htable-expire 120000 -j ACCEPT
-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 --tcp-flags FIN,SYN,RST,ACK SYN -m hashlimit --hashlimit-upto 1/min --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-name t_sshd --hashlimit-htable-expire 120000 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
COMMIT
# Completed on Sun Jan 12 23:16:24 2020
```

### 初期設定を確認する (IPv6)

ip6tables コマンドと ip6tables-save コマンドで確認する。

```
$ sudo ip6tables -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
```

```
$ sudo ip6tables-save
# Generated by ip6tables-save v1.8.3 on Sun Jan 12 20:37:47 2020
*filter
:INPUT ACCEPT [328:22552]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [448:31496]
COMMIT
# Completed on Sun Jan 12 20:37:47 2020
```

### ルールを書く (IPv6)

今回はパケットフィルタリングのルールを rules.v6 というファイルに保存した。

```
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
COMMIT
```

### ルールを反映する (IPv6)

ip6tables-restore コマンドでルールを反映する。

```
$ sudo ip6tables-restore < rules.v6
```

設定が反映されていることを確認する。

```
$ sudo ip6tables -L
Chain INPUT (policy DROP)
target     prot opt source               destination

Chain FORWARD (policy DROP)
target     prot opt source               destination

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

```
$ sudo ip6tables-save
# Generated by ip6tables-save v1.8.3 on Mon Jan 13 00:10:54 2020
*filter
:INPUT DROP [18:1296]
:FORWARD DROP [0:0]
:OUTPUT DROP [74:5328]
COMMIT
# Completed on Mon Jan 13 00:10:54 2020
```

## netfilter-persistent コマンドで設定を永続化

### 永続化する意味

iptables の設定は OS 再起動時に初期状態に戻ってしまう。
netfilter-persistent コマンドで設定を永続化しておくと、OS 起動時に設定内容を再反映してくれる。

### iptables-persistent パッケージをインストール

netfilter-persistent コマンドの iptables 用プラグインである iptables-persistent パッケージをインストールする。

```
$ sudo apt install iptables-persistent
```

依存で netfilter-persistent パッケージもインストールされる。
永続化用の netfilter-persistent コマンドは netfilter-persistent パッケージに含まれている。

### netfilter-persistent save で設定を永続化

netfilter-persistent save で現在の設定を永続化する。

```
$ sudo netfilter-persistent save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
```

永続化される設定は /etc/iptables/ 以下にあるファイル rules.v4 と rules.v6 に保存される。

```
$ tree /etc/iptables/
/etc/iptables/
├── rules.v4
└── rules.v6

0 directories, 2 files
```

sudo reboot などで OS を再起動した後、設定を確認するとちゃんと復元されている。

### iptables-persistent と netfilter-persistent の資料

README ファイルとマニュアルが用意されている。

```
$ cat /usr/share/doc/iptables-persistent/README
netfilter-persistent and its plugins
------------------------------------

netfilter-persistent does no work on its own. You need the accompanying
plugins (for example, iptables-persistent) to load and save filter rules.

However, commands are run from netfilter-persistent. For example, to save
all filter rules:

   netfilter-persistent save

or to load them:

   netfilter-persistent start

For more details, see `man netfilter-persistent`.

The system service will try to load rules at startup if enabled, but by
default it will not flush rules at shutdown. This behaviour can be changed
by editing /etc/default/netfilter-persistent.
```

[Ubuntu Manpage: netfilter\-persistent \- load, flush and save netfilter rule sets](http://manpages.ubuntu.com/manpages/eoan/man8/netfilter-persistent.8.html)

## nmap でポートスキャン

他のマシンから nmap コマンドでポートスキャンして、iptables の設定が効いているか確認する。

いくつかのパターンでポートスキャンする。

XXX.XXX.XXX.XXX はターゲットのIPアドレス (IPv4)。

```
$ sudo nmap -Pn XXX.XXX.XXX.XXX
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-12 23:38 JST
Nmap scan report for www.example.com (XXX.XXX.XXX.XXX)
Host is up (0.020s latency).
Not shown: 997 filtered ports
PORT    STATE  SERVICE
22/tcp  open   ssh
80/tcp  closed http
443/tcp closed https

Nmap done: 1 IP address (1 host up) scanned in 4.59 seconds
```

ステルススキャン。

```
$ sudo nmap -sS -sU -Pn XXX.XXX.XXX.XXX
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-12 23:38 JST
Nmap scan report for www.example.com (XXX.XXX.XXX.XXX)
Host is up (0.023s latency).
Not shown: 1000 open|filtered ports, 997 filtered ports
PORT    STATE  SERVICE
22/tcp  open   ssh
80/tcp  closed http
443/tcp closed https

Nmap done: 1 IP address (1 host up) scanned in 10.63 seconds
```

XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX はターゲットのIPアドレス (IPv6)。

```
$ nmap -6 -Pn XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-12 23:46 JST
Nmap scan report for wwww.v6.example.com (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX)
Host is up.
All 1000 scanned ports on wwww.v6.example.com (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX) are filtered

Nmap done: 1 IP address (1 host up) scanned in 201.70 seconds
```

ステルススキャン。

```
$ sudo nmap -6 -sS -sU -Pn XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
Starting Nmap 7.80 ( https://nmap.org ) at 2020-01-12 23:52 JST
Nmap scan report for wwww.v6.example.com (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX)
Host is up.
All 2000 scanned ports on wwww.v6.example.com (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX) are filtered (1000) or open|filtered (1000)

Nmap done: 1 IP address (1 host up) scanned in 404.36 seconds
```

## 参考資料

- [IptablesHowTo \- Community Help Wiki](https://help.ubuntu.com/community/IptablesHowTo)
- [Ubuntu Manpage: iptables/ip6tables — IPv4/IPv6 のパケットフィルタと NAT の管理ツール](http://manpages.ubuntu.com/manpages/eoan/ja/man8/iptables.8.html)
- [Ubuntu Manpage: iptables\-save — iptables ルールを標準出力にダンプする](http://manpages.ubuntu.com/manpages/eoan/ja/man8/iptables-save.8.html)
- [Ubuntu Manpage: iptables\-restore — IP テーブルを復元する](http://manpages.ubuntu.com/manpages/eoan/ja/man8/iptables-restore.8.html)
- [Ubuntu – eoan の iptables\-persistent パッケージに関する詳細](https://packages.ubuntu.com/ja/eoan/iptables-persistent)
- [Ubuntu Manpage: netfilter\-persistent \- load, flush and save netfilter rule sets](http://manpages.ubuntu.com/manpages/eoan/man8/netfilter-persistent.8.html)
- [iptables\-persistent / netfilter\-persistent を理解する \- j3iiifn’s blog](https://j3iiifn.hatenablog.com/entry/2019/05/04/193428)