iptables
Iptables は netfilter プロジェクトの一つとして Linux カーネルに組み込まれている強力なファイアウォールです。直接、または様々なフロントエンドや GUI を使って設定することができます。IPv4 では iptables が、IPv6 では ip6tables が使用されます。Both iptables and ip6tables have the same syntax, but some options are specific to either IPv4 or IPv6.
目次
インストール
標準の 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つのテーブルがあります:
raw
は接続追跡の対象から外れるようパケットを設定するのに使われます。filter
はデフォルトのテーブルで、主としてファイアウォールが備えるべきアクションは全てここで行われます。nat
はネットワークアドレス変換に使われます (例: ポートフォワーディング)。mangle
は特別なパケット変換に使われます (Mangled packet を参照)。security
は強制アクセス制御のネットワークルールに使われます (例: SELinux -- 詳しくは この記事 を参照)。
ほとんどの場合、使用するテーブルは2つだけです: filter と nat。他のテーブルは複数のルーターやルーティングの判定が関わる複雑な設定のためにあり、どちらにしろ導入の域を超えています。
チェイン
テーブルはチェインで構成されています。チェインは順番に並べられたルールのリストです。デフォルトのテーブル、filter
には3つの組み込みチェインが含まれます: INPUT
, OUTPUT
, FORWARD
。フローチャート で示されているように、パケットのフィルタリングプロセスの別々の場所で使われます。nat テーブルには PREROUTING
, POSTROUTING
, OUTPUT
チェインが含まれます。
他のテーブルの組み込みチェインの説明は man 8 iptables
を見て下さい。
デフォルトでは、チェインにはルールが何も入っていません。使用したいチェインにルールを追加するのはあなたの手に委ねられています。チェインにはデフォルトのポリシーが存在し、基本的には ACCEPT
に設定されていますが、あなたのルールセットを何も通り抜けられないようにしたい場合は DROP
に設定しなおすことができます。デフォルトのポリシーは常にチェインの一番最後に適用されます。故に、パケットはデフォルトポリシーの適用の前にチェインに存在するルール全てを通過する必要があります。
ユーザー定義チェインを追加すればルールセットをより効率的に、または簡単に修正できるようにすることができます。ユーザー定義チェインをどうやって使うかの例はシンプルなステートフルファイアウォールを見て下さい。
ルール
パケットフィルタリングは複数のマッチ (ルールが適用されるパケットの条件) と一つのターゲット (パケットが全ての条件に一致したときのアクション) によって記された、ルールに基づきます。ルールがマッチするものはパケットが入ってくるインターフェース (例: 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
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
そして今度は、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
によって読み込まれます。このサービスを起動する方法は上と同じです。
コマンドラインでルールを追加した後、設定ファイルは自動では変更されません — 手動で保存する必要があります:
# iptables-save > /etc/iptables/iptables.rules
設定ファイルを手動で編集したら、リロードしてください:
# systemctl reload iptables
もしくは iptables を使って直接ロードすることもできます:
# iptables-restore < /etc/iptables/iptables.rules
ガイド
ログ
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