まず、パケットフィルタリングにおける iptables の「基本中の基本」を頭に入れておく必要があります。
iptables コマンドの基本構文は「10分でできる iptables によるファイアウォール」で解説しています。
iptablesの基本
iptables について考えるとき次のことを念頭においてください。
- ルールは設定した順序でパケットに適用される。
- 最初にマッチしたルールを実行し、それ以降のルールは無視される。
- 「iptables -P INPUT DROP」「iptables -P OUTPUT DROP」などのポリシーは最後に適用される。
なので「ルールの順序」は超重要です。
ルールの順序を入れ替える方法
ルールの順序は設定した順序ですが、ルールを並べ替えるために都度「iptables -F」で初期化して再設定する必要はありません。
iptables は「INPUT」「OUTPUT」「FORWARD」などのチェーンごとにルール順に「行番号」が付けられているので、「行番号」を指定してルールの「挿入」や「削除」を行うことでルールの順序を変えることができます。
コマンドは次の通りです。
指定した行番号のルールを削除する
iptables -D INPUT [行番号]
指定した行番号に新しいルールを挿入する
iptables -I INPUT [行番号] [新しいルールの内容]
ルールの入れ替えは一度には行えませんので「削除」「挿入」のセットを実行する必要があります。
具体的な実行例
以前の記事でファイアウォール設定について解説しました。
これを変更することを考えてみましょう。
設定内容は次の通りです。
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# SSH
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# DNS
iptables -A OUTPUT -p udp -m state --state NEW --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state NEW --dport 53 -j ACCEPT
# NTP
iptables -A OUTPUT -p udp -m state --state NEW --dport 123 -j ACCEPT
# APT
iptables -A OUTPUT -p tcp -m state --state NEW --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp -m state --state NEW --dport 443 -j ACCEPT
# ICMP
iptables -A OUTPUT -m state --state NEW -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -m state --state NEW -p icmp -j ACCEPT
これを行番号付きで表示するには次のコマンドを実行します。
iptables -L --line-numbers
実行すると次のように表示されます。
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT tcp -- 192.168.1.0/24 anywhere state NEW tcp dpt:ssh
4 ACCEPT icmp -- anywhere anywhere state NEW
Chain FORWARD (policy DROP)
num target prot opt source destination
Chain OUTPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT udp -- anywhere anywhere state NEW udp dpt:domain
4 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:domain
5 ACCEPT udp -- anywhere anywhere state NEW udp dpt:ntp
6 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http
7 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https
8 ACCEPT icmp -- anywhere anywhere state NEW icmp echo-request
次のようにNTP問い合わせを許可しています。
iptables -A OUTPUT -p udp -m state --state NEW --dport 123 -j ACCEPT
この設定ではipアドレスを問わずNTP問い合わせについてはすべての宛先に対して発信を許可しています。
ところが特定のipアドレスにはアクセスさせたくない場合はそうすればいいでしょうか。
指定の行番号にルールを追加する
例えば複数ある debian.pool.ntp.org プールのNTPサーバーで 133.243.238.163 にはアクセスしたくないといった場合です。
次のようにルールを追加してみます。
iptables -A OUTPUT -d 133.243.238.163 -j DROP
「iptables -L OUTPUT –line-numbers」のように「OUTPUT」チェーンを指定して行番号付きでルールを表示すると次のようになります。
# iptables -L OUTPUT --line-numbers
Chain OUTPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT udp -- anywhere anywhere state NEW udp dpt:domain
4 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:domain
5 ACCEPT udp -- anywhere anywhere state NEW udp dpt:ntp
6 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http
7 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https
8 ACCEPT icmp -- anywhere anywhere state NEW icmp echo-request
9 DROP all -- anywhere ntp-b2.nict.go.jp
ルールが最後の行番号「9」に追加されているのがわかります。
ntp-b2.nict.go.jp は iptables が ipアドレス をDNS逆引きしてホスト名を表示しています。
逆引き解決せずに表示させたい場合は「-n」オプションを追加して次のようにします。
# iptables -L OUTPUT -n --line-numbers
...
9 DROP 0 -- 0.0.0.0/0 133.243.238.163
iptables では「最初にマッチしたルールを実行し、それ以降のルールは無視される」ので、せっかくルールを追加したのですがNTP問い合わせについては行番号「5」でACCEPTされて、追加したルールは「無視」されます。
133.243.238.163 にアクセスさせないルールは行番号「5」以前に挿入しなければ意味がありません。
iptables -A OUTPUT -d 133.243.238.163 -j DROP
に替えて次のように実行します。
iptables -I OUTPUT 5 -d 133.243.238.163 -j DROP
表示してみます。
# iptables -L OUTPUT --line-numbers
Chain OUTPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT udp -- anywhere anywhere state NEW udp dpt:domain
4 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:domain
5 DROP all -- anywhere ntp-b2.nict.go.jp
6 ACCEPT udp -- anywhere anywhere state NEW udp dpt:ntp
7 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http
8 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https
9 ACCEPT icmp -- anywhere anywhere state NEW icmp echo-request
10 DROP all -- anywhere ntp-b2.nict.go.jp
NTP問い合わせをACCEPTする前に 133.243.238.163(ntp-b2.nict.go.jp) へのアクセスがDROPされています。
行番号「5」以降はインクリメントされて「挿入前の行番号+1」になりました。
これで目的が達成されました。
行番号「10」は意味が無いので「削除」しても問題ありません。
iptables -D OUTPUT 10
指定の行番号のルールを入れ替える
iptables では指定の行番号のルールを一発で入れ替えることは出来ません。
状況に応じて「削除」「追加」をセットで次のいずれかを実行する必要があります。
- 指定の行番号のルールを「削除」→指定の行番号にルールを「追加」
- 指定の行番号にルールを「追加」→[指定の行番号+1]のルールを「削除」
- [指定の行番号+1]にルールを「追加」→指定の行番号にルールを「削除」
例えば ssh 接続の受け入れを 192.168.1.0/24 からに限定して次のように設定しました。
iptables -A INPUT -m state --state NEW -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
ところが ssh は接続元を問わずACCEPTするように変更したくなりました。
どうすればいいでしょうか。
現在の状況を表示します。
# iptables -L INPUT --line-numbers
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT tcp -- 192.168.1.0/24 anywhere state NEW tcp dpt:ssh
4 ACCEPT icmp -- anywhere anywhere state NEW
ssh が途切れないようにするにはまずルールの「追加」から始めます。
行番号「3」にルールを追加します。
iptables -I INPUT 3 -m state --state NEW -p tcp --dport 22 -j ACCEPT
状態を表示します。
# iptables -L INPUT --line-numbers
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
4 ACCEPT tcp -- 192.168.1.0/24 anywhere state NEW tcp dpt:ssh
5 ACCEPT icmp -- anywhere anywhere state NEW
続いて行番号「4」を削除します。
iptables -D INPUT 4
これで目的が達成されます。
# iptables -L INPUT --line-numbers
Chain INPUT (policy DROP)
num target prot opt source destination
1 ACCEPT all -- anywhere anywhere
2 ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
3 ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
4 ACCEPT icmp -- anywhere anywhere state NEW
ここで気が付くのは「INPUT」「OUTPUT」チェーンの行番号「1」です。
1 ACCEPT all -- anywhere anywhere
すべてACCEPTになっているのでそれ以降は「無視」されるのでは?
ルールのいろんな表示法
次の表示はどういう意味なのか?
1 ACCEPT all -- anywhere anywhere
これは次の設定が反映されているのではないかと疑ってしまうのですが、違います。
iptables -A INPUT -J ACCEPT
iptables -A OUTPUT -J ACCEPT
標準表示では表示項目が少ないので紛らわしいのですが、詳細表示にすればその意味が分かります。
詳細表示にするには「v」オプションを追加します。
# iptables -vL --line-numbers
Chain INPUT (policy DROP 180 packets, 21251 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- lo any anywhere anywhere
2 645 44520 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
3 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:ssh
4 0 0 ACCEPT icmp -- any any anywhere anywhere state NEW
Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- any lo anywhere anywhere
2 422 44832 ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
3 6 429 ACCEPT udp -- any any anywhere anywhere state NEW udp dpt:domain
4 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:domain
5 0 0 DROP all -- any any anywhere ntp-b2.nict.go.jp
6 6 456 ACCEPT udp -- any any anywhere anywhere state NEW udp dpt:ntp
7 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:http
8 0 0 ACCEPT tcp -- any any anywhere anywhere state NEW tcp dpt:https
9 0 0 ACCEPT icmp -- any any anywhere anywhere state NEW icmp echo-request
「in」「out」が表示項目に追加されることで納得できます。
つまり以下の反映だったんですね。
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
ほかにも「n」オプションを追加するとDNSで名前解決が行われません。
# iptables -vnL --line-numbers
Chain INPUT (policy DROP 210 packets, 26501 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT 0 -- lo * 0.0.0.0/0 0.0.0.0/0
2 727 49753 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 0 0 ACCEPT 6 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
4 0 0 ACCEPT 1 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW
Chain FORWARD (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy DROP 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT 0 -- * lo 0.0.0.0/0 0.0.0.0/0
2 484 52336 ACCEPT 0 -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 7 503 ACCEPT 17 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW udp dpt:53
4 0 0 ACCEPT 6 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:53
5 0 0 DROP 0 -- * * 0.0.0.0/0 133.243.238.163
6 7 532 ACCEPT 17 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW udp dpt:123
7 0 0 ACCEPT 6 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80
8 0 0 ACCEPT 6 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:443
9 0 0 ACCEPT 1 -- * * 0.0.0.0/0 0.0.0.0/0 state NEW icmptype 8
まとめ
- ルールは設定した順序でパケットに適用される。
- 最初にマッチしたルールを実行し、それ以降のルールは無視される。
- 「iptables -P INPUT DROP」「iptables -P OUTPUT DROP」などのポリシーは最後に適用される。
したがってルールの順序は非常に重要で、意図した通りにトラフィックを制御するためにはルールを慎重に配置する必要があるのです。