iptables (日本語) - ArchWiki

# iptables (日本語)

関連記事

- ファイアウォール
- Simple stateful firewall
- Sysctl#TCP/IP スタックの防御
- Sshguard
- Fail2ban
- Nftables

Iptables は netfilter プロジェクトの一つとして Linux カーネルに組み込まれている強力なファイアウォールです。直接、または様々なフロントエンドや GUI を使って設定することができます。IPv4 では iptables が、IPv6 では ip6tables が使用されます。

いつかメインの Linux ファイアウォールユーティリティとして iptables を置き換えるものとして、Linux カーネル 3.13 で nftables がリリースされています。

## インストール

標準の Arch Linux カーネルは iptables サポートを有効にしてコンパイルされています。必要なのは、公式リポジトリの iptables に入ってるユーザーランドユーティリティをインストールすることだけです (base グループの iproute2 パッケージが iptables に依存しているため、あなたのシステムにはデフォルトで iptables パッケージがインストールされています)。

## 基本概念

iptables は IPv4 パケットを検査・変更・転送・リダイレクト・拒否するのに使われます。IPv4 パケットをフィルタリングするコードはカーネルに含まれており、特定の目的ごとにテーブルとしてまとめられています。テーブルは定義済みのチェインのセットで出来ており、チェインを通過するルールが順番に含まれています。各ルールはマッチと対応するアクション (ターゲットと呼ばれます) の条件文からなり、条件が真のときに (つまり条件がマッチしたとき) 実行されます。iptables はそれらのチェインやルールを使うためのユーザーユーティリティです。ほとんどの新規ユーザーは linux の IP ルーティングの複雑性をとても難しく感じますが、一般的なユースケース (NAT や基本的なインターネットファイアウォール) では実はあまり複雑ではありません。

iptables の動作を理解するための鍵は このチャート です。上部の小文字の単語がテーブルで下部の大文字の単語がチェインになります。あらゆるネットワークインターフェースから来た IP パケットは全てこのフローチャートの上から下まで通過します。よくある勘違いの元は、内部インターフェースからのパケットがインターネットに接するインターフェースからのパケットと違ったふうに処理されることにあります。全てのインターフェースは同じように処理されます。それを別々に扱うようにルールを定義するのはあなた次第です。もちろんローカルプロセスのためのパケットというものが存在し、チャートの一番上から <Local Process> のところで止まり、一方ローカルプロセスによって生成されたパケットは <Local Process> からスタートしてフローチャートを下っていきます。このフローチャートの働きの詳しい説明は こちら から読めます。

ほとんどの使い方では raw, mangle, security テーブルを使うことは全くありません。従って、iptables をネットワークパケットが通る様子を表すと以下のチャートのようになります:

                                   XXXXXXXXXXXXXXXXXX
                                 XXX     Network    XXX
                                   XXXXXXXXXXXXXXXXXX
                                           +
                                           |
                                           v
     +-------------+              +------------------+
     |table: filter| <---+        | table: nat       |
     |chain: INPUT |     |        | chain: PREROUTING|
     +-----+-------+     |        +--------+---------+
           |             |                 |
           v             |                 v
     [local process]     |           ****************          +--------------+
           |             +---------+ Routing decision +------> |table: filter |
           v                         ****************          |chain: FORWARD|
    ****************                                           +------+-------+
    Routing decision                                                  |
    ****************                                                  |
           |                                                          |
           v                        ****************                  |
    +-------------+       +------>  Routing decision  <---------------+
    |table: nat   |       |         ****************
    |chain: OUTPUT|       |               +
    +-----+-------+       |               |
          |               |               v
          v               |      +-------------------+
    +--------------+      |      | table: nat        |
    |table: filter | +----+      | chain: POSTROUTING|
    |chain: OUTPUT |             +--------+----------+
    +--------------+                      |
                                          v
                                   XXXXXXXXXXXXXXXXXX
                                 XXX    Network     XXX
                                   XXXXXXXXXXXXXXXXXX

### テーブル

iptables には5つのテーブルがあります:

1. `raw` は接続追跡の対象から外れるようパケットを設定するのに使われます。
2. `filter` はデフォルトのテーブルで、主としてファイアウォールが備えるべきアクションは全てここで行われます。
3. `nat` はネットワークアドレス変換に使われます (例: ポートフォワーディング)。
4. `mangle` は特別なパケット変換に使われます (Mangled packet を参照)。
5. `security` は強制アクセス制御のネットワークルールに使われます (例: SELinux -- 詳しくは この記事 を参照)。

ほとんどの場合、使用するテーブルは2つだけです: filter と nat。他のテーブルは複数のルーターやルーティングの判定が関わる複雑な設定のためにあり、どちらにしろ導入の域を超えています。

### チェイン

テーブルはチェインで構成されています。チェインは順番に並べられたルールのリストです。デフォルトのテーブル、`filter` には3つの組み込みチェインが含まれます: `INPUT`, `OUTPUT`, `FORWARD`。フローチャート で示されているように、パケットのフィルタリングプロセスの別々の場所で使われます。nat テーブルには `PREROUTING`, `POSTROUTING`, `OUTPUT` チェインが含まれます。

他のテーブルの組み込みチェインの説明は `man 8 iptables` を見て下さい。

デフォルトでは、チェインにはツールが何も入っていません。使用したいチェインにルールを追加するのはあなたの手に委ねられています。チェインにはデフォルトのポリシーが存在し、基本的には `ACCEPT` に設定されていますが、あなたのルールセットを何も通り抜けられないようにしたい場合は `DROP` に設定しなおすことができます。デフォルトのポリシーは常にチェインの一番最後に適用されます。故に、パケットはデフォルトポリシーの適用の前にチェインに存在するルール全てを通過する必要があります。

ユーザー定義チェインを追加すればルールセットをより効率的に、または簡単に修正できるようにすることができます。ユーザー定義チェインをどうやって使うかの例は Simple stateful firewall を見て下さい。

### ルール

パケットフィルタリングは複数のマッチ (ルールが適用されるパケットの条件) と一つのターゲット (パケットが全ての条件に一致したときのアクション) によって記された、ルールに基づきます。ルールがマッチするものはパケットが入ってくるインターフェース (例: eth0 または eth1) や、パケットのタイプ (ICMP, TCP, UDP)、パケットの送信先ポートなどになります。

ターゲットは `-j` または `--jump` オプションを使って指定します。ターゲットはユーザー定義チェイン (条件に一致した場合、次のユーザー定義チェインにジャンプしてそこから処理が続行される)、特別な組み込みターゲットのどれか、またはターゲットの拡張のいずれかになります。組み込みターゲットは `ACCEPT`, `DROP`, `QUEUE`, `RETURN` で、ターゲットの拡張は `REJECT` や `LOG` などです。ターゲットが組み込みターゲットだった場合、パケットの運命はすぐに決まり、現在のテーブルのパケットの処理は停止します。ターゲットがユーザー定義チェインだった場合で、さらにこの2番目のチェインをパケットが通過した場合、元のチェインの次のルールに移ります。ターゲットの拡張は終了 (組み込みターゲットと同じ) と非終了 (ユーザー定義チェインと同じ) のいずれも可能です。詳しくは `man 8 iptables-extensions` を見て下さい。

### チェインの通過

あらゆるインターフェースで受け取られたネットワークパケットは フローチャート で示されている順番でテーブルのトラフィック制御チェインを通過していきます。最初のルーティングの決定はパケットの最終目的地がローカルマシンなのか (その場合パケットは `INPUT` チェインを通過します) もしくは他のところなのか (その場合パケットは `FORWARD` チェインを通過します) 判断するところからです。次のルーティングの決定は送出パケットにどのインターフェースを割り当てるかの決定を伴います。この経路にあるチェインごとに、全てのルールが順番に評価され、ルールが一致すれば、対応するターゲット・ジャンプのアクションが実行されます。最も一般的に使われるターゲットのビッグスリーは `ACCEPT` と `DROP`、そしてユーザー定義チェインへのジャンプです。組み込みチェインにはデフォルトポリシーを設定できますが、ユーザー定義チェインではできません。ジャンプした先のチェインのルールがどれも完全一致しないときは、パケットは こちら に描かれているように元のチェインに戻ります。`DROP` ターゲットのルールで完全一致があった場合は即座にパケットは拒否され、先の処理は行われません。チェインの中でパケットが `ACCEPT` されると、全ての上位のチェインでパケットが `ACCEPT` され、上位チェインを通過しなくなります。ただし、他のテーブルのチェインは全て通常通りにパケットが通過するので注意してください。

### モジュール

connlimit, conntrack, limit, recent など多数のモジュールを使うことで iptables を拡張することができます。これらのモジュールは新しい機能を追加して複雑なフィルタリングルールを可能にします。

## iptables の設定と実行

iptables は systemd のサービスであり次のように起動できます:

    # systemctl start iptables

ただし、このサービスは `/etc/iptables/iptables.rules` ファイルがないと起動せず、Arch の iptables パッケージにはデフォルトの iptables.rule ファイルは付いていません。したがって初めてサービスを起動する場合:

    # touch /etc/iptables/iptables.rules
    # systemctl start iptables

または:

    # cp /etc/iptables/empty.rules /etc/iptables/iptables.rules
    # systemctl start iptables

他のサービスと同じように、起動時に iptables が自動的にロードされるようにしたいときは、有効化してください:

    # systemctl enable iptables

### コマンドラインから

#### 現在のルールを表示する

次のコマンドを使うことで現在のルールセットとルールごとのヒット数を確認できます:

    # iptables -nvL

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination

    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination

    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
     pkts bytes target     prot opt in     out     source               destination

上のように出力された場合、ルールは存在しません。何もブロックされません。

ルールを表示する際に行番号を表示するには、`--line-numbers` をコマンドに追加してください。個々のルールを削除したり追加するときに便利です。

#### ルールをリセットする

以下のコマンドを使えば iptables をデフォルトに戻すことができます:

    # iptables -F
    # iptables -X
    # iptables -t nat -F
    # iptables -t nat -X
    # iptables -t mangle -F
    # iptables -t mangle -X
    # iptables -t raw -F
    # iptables -t raw -X
    # iptables -t security -F
    # iptables -t security -X
    # iptables -P INPUT ACCEPT
    # iptables -P FORWARD ACCEPT
    # iptables -P OUTPUT ACCEPT

引数を付けない `-F` コマンドは現在のテーブルの全てのチェインを削除します。同じく、`-X` はテーブル内の空の (デフォルトでない) チェインを全て削除します。

`[chain]` 引数を付けて `-F` や `-X` を使うことでチェインを個別に削除することもできます。

#### ルールを編集する

ルールの追加は、チェインにルールを付け足すか、またはチェインの特定の位置にルールを挿入することで行います。ここでは両方の方法を用います。

まず最初に、わたしたちのコンピュータはルーターではありません (もちろん、ルーターなのであれば話は別ですが)。`FORWARD` チェインのデフォルトポリシーを `ACCEPT` から `DROP` に変更します:

    # iptables -P FORWARD DROP

Warning: このセクションは iptables のルールに関する構文と構想を伝えるためにあります。サーバーのセキュリティを確保するための方法を記述しているわけではありません。システムのセキュリティを向上させる方法については、最小限セキュアな iptables の設定について書かれた Simple stateful firewall や、一般的な視点で Arch Linux のセキュリティを上げる方法を説明している Security (日本語) を参照してください。

Dropbox の LAN 同期機能は認識された全てのコンピュータに30秒毎にパケットを送信します。Dropbox クライアントで LAN を使っていてこの機能を利用しない場合、このパケットは拒否すると良いでしょう:

    # iptables -A INPUT -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable

    # iptables -nvL --line-numbers

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1        0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:17500 reject-with icmp-port-unreachable

    Chain FORWARD (policy DROP 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

Note: ここでは `DROP` ではなく `REJECT` を使用していますが、これは RFC 1122 3.3.8 がパケットをドロップする代わりに出来る限り ICMP エラーを返すことをホストに要求しているためです。実際には、サーバーの存在を知るべきホストからのパケットは `REJECT` して、サーバーの存在すら知るべきでない (もしくは何か良からぬことを企んでいる) ホストからのパケットは `DROP` するのがベストです。

そして今度は、Dropbox に関する考えをあらためてコンピュータに Dropbox をインストールすることを決めたとします。LAN 同期も行いますが、ネットワーク上の特定の一つの IP しか使いません。そこで `-R` を使って古いルールを置き換える必要があります。`10.0.0.85` は別の IP です:

    # iptables -R INPUT 1 -p tcp --dport 17500 ! -s 10.0.0.85 -j REJECT --reject-with icmp-port-unreachable

    # iptables -nvL --line-numbers

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1        0     0 REJECT     tcp  --  *      *      !10.0.0.85            0.0.0.0/0            tcp dpt:17500 reject-with icmp-port-unreachable

    Chain FORWARD (policy DROP 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

オリジナルのルールをコンピュータのポート `17500` に `10.0.0.85` がアクセスできるようにルールを置き換えました。しかしながらここで、このルールは扱いづらいということに気づきました。フレンドリーな Dropbox ユーザーがデバイスのポート `17500` にアクセスしようとしたときに、すぐにそのユーザーを許可したいわけで、その後のファイアウォールルールで彼をテストしたくないということです。

信頼されているユーザーはすぐ許可するように、新しいルールを書き込みます。`-I` を使って古いルールの前に新しいルールを挿入:

    # iptables -I INPUT -p tcp --dport 17500 -s 10.0.0.85 -j ACCEPT -m comment --comment "Friendly Dropbox"

    # iptables -nvL --line-numbers

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1        0     0 ACCEPT     tcp  --  *      *       10.0.0.85            0.0.0.0/0            tcp dpt:17500 /* Friendly Dropbox */
    2        0     0 REJECT     tcp  --  *      *      !10.0.0.85            0.0.0.0/0            tcp dpt:17500 reject-with icmp-port-unreachable

    Chain FORWARD (policy DROP 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

そして2番目のルールを、ポート `17500` で全てを拒否するルールに置き換えます:

    # iptables -R INPUT 2 -p tcp --dport 17500 -j REJECT --reject-with icmp-port-unreachable

最終的なルールは以下のようになりました:

    # iptables -nvL --line-numbers

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1        0     0 ACCEPT     tcp  --  *      *       10.0.0.85            0.0.0.0/0            tcp dpt:17500 /* Friendly Dropbox */
    2        0     0 REJECT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:17500 reject-with icmp-port-unreachable

    Chain FORWARD (policy DROP 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

    Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination

### 設定ファイル

Arch Linux のデフォルトでは、iptables のルールは `/etc/iptables/iptables.rules` に保存されます。ただし、ルールは自動でロードされません。代わりに起動時にこのファイルを読み込んでルールをロードする `iptables.service` を有効にすることができます:

    # systemctl enable iptables
    # systemctl start iptables

IPv6 の iptables ルールは、デフォルトで、`/etc/iptables/ip6tables.rules` に保存され、このファイルは `ip6tables.service` によって読み込まれます。このサービスを起動する方法は上と同じです。

Note: iptables 1.4.21-1 パッケージの `iptables.service` と `ip6tables.service` ファイルは古くなっています。systemd 214 からセキュリティ上の理由で、ネットワークが設定される前にファイアウォールが実行するように、ファイアウォールは `network-pre.target` ターゲットの前に起動することが推奨されています。iptables がアップデートされるまで、ドロップインディレクトリ `/etc/systemd/system/iptables.service.d` を作成して、その中に `00-pre-network.conf` ファイルを使って以下のスニペットを記述して下さい:

    [Unit]
    Before=network-pre.target
    [Install]
    RequiredBy=network-pre.target

システムが `ip6tables.service` を使っている場合、`/etc/systemd/system/ip6tables.service.d` ドロップインディレクトリで同じことを行なって下さい。このことに関する詳細は systemd のバグレポート, systemd のリリースアナウンス, FS#33478 を参照。

コマンドラインでルールを追加した後、設定ファイルは自動では変更されません — 手動で保存する必要があります:

    # iptables-save > /etc/iptables/iptables.rules

設定ファイルを手動で編集したら、リロードしてください:

    # systemctl reload iptables

もしくは iptables を使って直接ロードすることもできます:

    # iptables-restore < /etc/iptables/iptables.rules

### ガイド

- Simple stateful firewall
- Router

## ログ

`LOG` ターゲットを使うことでルールにヒットしたパケットを記録することができます。`ACCEPT` や `DROP` など他のターゲットとちがって、パケットは `LOG` ターゲットにヒットした後もチェインを通過します。つまり拒否されたパケットを全て記録するためには、それぞれの DROP ルールの前に同じ `LOG` ルールを追加する必要があります。これだと事態がややこしくなり効率的でなくなるので、代わりに `logdrop` チェインを作成します。

チェインを作成:

    # iptables -N logdrop

新しく作成したチェインに以下のルールを追加:

    # iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG
    # iptables -A logdrop -j DROP

`limit` や `limit-burst` オプションの説明は下のセクションにあります。

これで、パケットを拒否してイベントを記録したいときは、毎回 `logdrop` チェインにジャンプするようにします。例えば:

    # iptables -A INPUT -m conntrack --ctstate INVALID -j logdrop

### ログ出力の上限を設定する

上記の `logdrop` チェインは limit モジュールを使うことで iptables のログが大きくなりすぎたり不必要なハードドライブの書き込みが発生するのを防ぐことができます。上限を設定していないと、誤って設定したサービスが接続を試行したり、攻撃者によって、iptables のログへの書き込みでドライブ (少なくとも `/var` パーティション) が埋まってしまう可能性があります。

limit モジュールは `-m limit` で呼び出すことができます。そして `--limit` を使うことで平均レートを、`--limit-burst` を使うことで最初のバーストレートを設定することができます。上記の `logdrop` のサンプルなら:

    # iptables -A logdrop -m limit --limit 5/m --limit-burst 10 -j LOG

これで通過する全てのパケットを記録するルールが追加されます。最初の連続する10のパケットが記録され、それから1分ごとに5のパケットだけ記録されます。"limit burst" のカウントは log アクティビティがノーマルに自動的に戻って "limit rate" が壊れない度にリセットされます。

### 記録されたパケットを表示する

記録されたパケットは systemd の journal でカーネルメッセージとして見ることができます。

マシンが最後に起動したときから記録されたパケットを全て表示するには:

    # journalctl -k | grep "IN=.*OUT=.*" | less

### syslog-ng

syslog-ng を使っている場合、iptables のログ出力先をコントロールすることができます:

    filter f_everything { level(debug..emerg) and not facility(auth, authpriv); };

を

    filter f_everything { level(debug..emerg) and not facility(auth, authpriv) and not filter(f_iptables); };

これで iptables による `/var/log/everything.log` へのログ出力が停止されます。

iptables に `/var/log/iptables.log` 以外のファイルにログを出力して欲しい場合は、destination `d_iptables` の file の値を変更するだけで可能です (`syslog-ng.conf` にあります):

    destination d_iptables { file("/var/log/iptables.log"); };

### ulogd

ulogd は netfilter のための特別なユーザースペースパケットログデーモンで、デフォルトの `LOG` ターゲットを置き換えることができます。ulogd パッケージは `[community]` リポジトリから入手可能です。

## 参照

- ポートノッキング
- iptables 公式ウェブサイト
- iptables Tutorial 1.2.2 by Oskar Andreasson
- iptables Debian Debian wiki

Category:

- Firewalls (日本語)