iptables

提供: ArchWiki
2015年1月12日 (月) 19:32時点におけるKusakata (トーク | 投稿記録)による版
ナビゲーションに移動 検索に移動

関連記事

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

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

インストール

標準の 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つだけです: filternat。他のテーブルは複数のルーターやルーティングの判定が関わる複雑な設定のためにあり、どちらにしろ導入の域を超えています。

チェイン

テーブルはチェインで構成されています。チェインは順番に並べられたルールのリストです。デフォルトのテーブル、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 で、ターゲットの拡張は REJECTLOG などです。ターゲットが組み込みターゲットだった場合、パケットの運命はすぐに決まり、現在のテーブルのパケットの処理は停止します。ターゲットがユーザー定義チェインだった場合で、さらにこの2番目のチェインをパケットが通過した場合、元のチェインの次のルールに移ります。ターゲットの拡張は終了 (組み込みターゲットと同じ) と非終了 (ユーザー定義チェインと同じ) のいずれも可能です。詳しくは man 8 iptables-extensions を見て下さい。

チェインの通過

あらゆるインターフェースで受け取られたネットワークパケットは フローチャート で示されている順番でテーブルのトラフィック制御チェインを通過していきます。最初のルーティングの決定はパケットの最終目的地がローカルマシンなのか (その場合パケットは INPUT チェインを通過します) もしくは他のところなのか (その場合パケットは FORWARD チェインを通過します) 判断するところからです。次のルーティングの決定は送出パケットにどのインターフェースを割り当てるかの決定を伴います。この経路にあるチェインごとに、全てのルールが順番に評価され、ルールが一致すれば、対応するターゲット・ジャンプのアクションが実行されます。最も一般的に使われるターゲットのビッグスリーは ACCEPTDROP、そしてユーザー定義チェインへのジャンプです。組み込みチェインにはデフォルトポリシーを設定できますが、ユーザー定義チェインではできません。ジャンプした先のチェインのルールがどれも完全一致しないときは、パケットは こちら に描かれているように元のチェインに戻ります。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
警告: このセクションは iptables のルールに関する構文と構想を伝えるためにあります。サーバーのセキュリティを確保するための方法を記述しているわけではありません。システムのセキュリティを向上させる方法については、最小限セキュアな iptables の設定について書かれた Simple stateful firewall や、一般的な視点で Arch Linux のセキュリティを上げる方法を説明しているセキュリティのページを参照してください。

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

ノート: ここでは 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

オリジナルのルールをコンピュータのポート 1750010.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 によって読み込まれます。このサービスを起動する方法は上と同じです。

ノート: iptables 1.4.21-1 パッケージの iptables.serviceip6tables.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

ガイド

ログ

LOG ターゲットを使うことでルールにヒットしたパケットを記録することができます。ACCEPTDROP など他のターゲットとちがって、パケットは 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

limitlimit-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] リポジトリから入手可能です。

参照

この項目について詳しくは Wikipedia の記事を見て下さい: iptables