UnixPower on Networking
  http://www.unix-power.net/

 
 Top - Linux - CentOS iptablesによるパケットフィルタ




CentOS6.3ではiptablesはデフォルトで有効になっており、カーネル再構築などは不要です。今、どういった内容でパケットフィルタが設定されているのか以下のコマンドで確認可能です。デフォルトではsshサービスへの接続しか許可されていません。


# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination


■テーブル

実際にiptableを設定するのですがiptablesを使うには、テーブルやチェインなどの概念を理解しておく必要があります。iptablesには、以下の3つの「テーブル」が用意されています。

テーブル一覧
filter パケットフィルタリングを参照するテーブルを指定する。
nat 新しいセッションを開くパケットが参照するテーブルを指定する。
mangle 特別なパケットが参照するテーブルを指定する。


■チェーン

iptablesでは特定条件に当てはまるパケットに対して処理ルールを定義します。この条件のグループをチェーンと呼びます。チェーンには最初から定義されている組み込みチェーンと後からユーザが定義するユーザ定義チェーンの2種類あります。冒頭で紹介した各ステップは組み込みチェーンとして利用できます。下記のようにテーブルによって利用できる組み込みチェーンに制限があります。


チェーン一覧 テーブル 
INPUT 入力(受信)パケット filter , mangle
OUTPUT 出力(送信)パケット filter , nat , mangle
FORWARD フォワードするパケット filter
PREROUTING 受信時を宛先アドレスを変換するチェイン nat , mangle
POSTROUTING 送信時に送信元アドレスを変換するチェイン nat


■ターゲット

-jパラメータでは、「ターゲット」を指定する必要があります。これは、パケットがマッチした際のアクション(何を行うか)のことです。主なものは次の通りです。

ターゲット一覧
ACCEPT パケットの通過を許可
DROP パケットを破棄
RETRUN チェーン内のルール評価を終了する 
MASQUERADE 「-t nat」と「-A POSTROUTING」と同時に用いて送信元IPとポート番号を書き換える
REJECT パケットを拒否し、ICMPメッセージを返信
PREROUTING 特定ポートにリダイレクト
LOG Logを採取する
SNAT パケットの送信元アドレスを修正する。natテーブルでpostroutingチェーンでのみ利用できる。 
DNAT  パケットの送信先アドレスを修正する。natテーブルでpostroutingチェーンでのみ利用できる。 


■ルール

ルールはパケットの内容との比較条件です。条件に合致したパケットは別のチェーンのルールに照らし合わせたりターゲットを指定して処理を行うことができます。iptablesに対してルールを設定する場合にはオプションの形式で指定します。以下、代表的なルールのオプションです。

オプション一覧
-p [!] <protocol> ルールで使うプロトコル(tcp、udp、icmp、all)を指定
-s [!] <address> [/<netmask>] 送信元アドレス。IPアドレスのほかにホスト名などでも指定できる
-d [!] <address> [/<netmask>] 接続先アドレス。IPアドレスのほかにホスト名などでも指定できる
--sport <port> 送信元ポートを指定する。
--dport <port> 送信先ポートを指定する。
-i <interface> パケットが入ってくるインターフェイス(eth0、eth1など)を指定
-o <interface> パケットが出ていくインターフェイスを指定
-j <target> パケットがマッチしたときのアクション(ターゲット)を指定
-t <table> テーブル(filter、nat、mangle)を指定
-m <module> モジュールを指定する。-pで暗黙に指定されるので省略することも可。
--icmp-type [!] <type> ICMPでタイプ名を指定する。( iptables -p icmp -hで表示されるタイプを指定。
 ! -p、-s、-dなどで、条件を反転する。「! 192.168.0.1」とすると、「192.168.0.1以外」という意味になる


■ヘルパーモジュール

CentOSの標準設定で使われているstateモジュールはアクティブモードのFTPやamandaなどの特殊なコネクションの通信を追跡する機能をもっています。但し、これらのプロトコルの通信を追跡するにはプロトコルごとのヘルパーモジュールを読み込む必要があります。下記はそのヘルパーモジュールの一覧です。


モジュール  対応プロトコル 
nf_conntrack_amanda  Amanda 
nf_conntrack_ftp  FTP 
nf_conntrack_netbios_ns  NetBIOS Name Service 
nf_conntrack_pptp  PPTP 
nf_conntrack_tftp  TFTP 


これらのモジュールを読み込むには/etc/sysconfig/iptables-configのIPTABLES_MODULESのIPTABLES_MODULEに該当モジュールを追記します。

# Load additional iptables modules (nat helpers)
#   Default: -none-
# Space separated list of nat helpers (e.g. 'ip_nat_ftp ip_nat_irc'), which
# are loaded after the firewall rules are applied. Options for the helpers are
# stored in /etc/modprobe.conf.
IPTABLES_MODULES="nf_conntrack_netbios_ns"


■stateモジュール

stateモジュールを利用することで通信の段階に応じた制限をかけることが可能です。一般的には一旦接続を受け付けた通信は全て許可し、接続の可否だけを制御します。書式は下記のようになります。

-m state [!] --state <state>


--stateで指定可能なものは以下があります。

名称 状態 
INVALID  既存のコネクションとは関係のないパケット 
NEW  新しいコネクションの接続に関するパケット 
ESTABLISHED  接続済みコネクションのパケット 
RELATED  接続済みコネクションに関連して発生した新たなコネクションパケット 


■iptablesコマンド

iptablesコマンドで設定を実施していきます。iptablesの主なコマンドとして以下があります。全ての操作でテーブルの指定は省略することができ、省略した場合はfilterテーブルに対して操作が行われます。

コマンド一覧
iptables [ -t <table> ] -A append。最後尾に追加。
iptables [ -t <table> ] -L line-numbers。設定内容表示。
iptables [ -t <table> ] -D delete。既存のルールの削除。
iptables [ -t <table> ] -F flush。指定したチェーン全てを削除。
iptables [ -t <table> ] -I insert。先頭にチェーンを追加。ルール番号を指定することで任意の場所に挿入。
iptables [ -t <table> ] -P チェーン内全体で有効なポリシーを定義。デフォルトはAccept。
iptables [ -t <table> ] -N new。新しいチェーンを作成。



■全体ポリシーとICMPの許可


パケットフィルタリングを設定する前に既存のフィルタリングルールは全て破棄する必要があります。以下のコマンドで実行することにより全てのルールが削除されます。チェーンは特に明記していませんが、省略した場合、全てのチェーンに適用されます。

# /sbin/iptables -t filter -F


ルールを削除したらポリシーの設定を行います。チェーンにはINPUT, OUTPUT, FORWARDのみ指定できユーザ定義チェーンは指定できません。またtargetにはDROPまたはACCEPTのみ設定できます。以下ではINPUT/OUTPUTチェーンにDROPポリシーを設定しています。


# /sbin/iptables -P INPUT DROP
# /sbin/iptables -P OUTPUT DROP
# /sbin/iptables -P FORWARD DROP


続いて許可ルールを追加していくわけですが、まず最初に制御用の通信であるICMPの設定を行います。ICMPのルールを設定する場合にはオプションでプロトコルにicmpを設定します。icmpには以下のタイプがあります。

番号
メッセージタイプ
0 Echo Reply
3 Destination Unreachable
4 Source Quench
5 Redirect
8 Echo Request
11 Time Exceeded
12 Parameter Problem
13 Timestamp Request
14 Timestamp Reply
15 Information Request
16 Information Reply
17 Address Mask Request
18 Address Mask Reply


次の例ではfilterテーブルのINPUT,OUTPUTチェーンにタイプを指定せずにICMPをまるごと許可するルールを追加しています。


# /sbin/iptables -A INPUT -p icmp -j ACCEPT
# /sbin/iptables -A OUTPUT -p icmp -j ACCEPT
# /sbin/iptables -A FORWARD -p icmp -j ACCEPT


pingにだけ応答するようにするのであればタイプ0と8のecho requestとecho replayを指定してもOKです。下記はecho requestを受け付けてecho replayを許可するルールになります。

# /sbin/iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
# /sbin/iptables -A OUTPUT -p icmp --icmp-type 0 -j ACCEPT


iptablesによる通信の制御はループバックに対しても適用されます。通常はループバックに対しては通信を制限しないため許可ルールを設定しておきます。次のようにオプションでloインターフェイスを指定して通信許可の設定を追加します。


# /sbin/iptables -A INPUT -i lo -j ACCEPT
# /sbin/iptables -A OUTPUT -o lo -j ACCEPT


■TCP/UDPのルール追加


TCPやUDPのルールを追加する場合にはオプションでプロトコルtcp/udpを指定し、さらにポート番号、送信元アドレスやポート、送信先アドレスやポートを指定することで細かな設定をすることができます。またstateモジュールを利用することで通信の段階に応じた制限も可能です。一般的には一旦受け付けた接続は通信は全て許可し、接続の可否だけ制御します。

最初に受け付けた通信を許可する設定を行います。-mオプションでstateモジュールの利用を宣言し、--stateオプションでルールの対象となる状態を指定します。以下ではESTABLISHEDとRELATEDのパケットを許可していますので一旦コネクションを接続した後の全ての通信が許可されます。

# /sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# /sbin/iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# /sbin/iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT


次に接続を許可する設定を行います。例えば自身で公開しているWWW ( TCP/80 )への接続を全て許可する場合は--dportを使って以下のように設定を行います。-m tcpでTCP用モジュールを指定し、プロトコル、宛先ポートを指定しています。


# /sbin/iptables -A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT


特定の相手からのみ接続を許可するには-sオプションを使用します。以下の例は192.168.12.5からのSSH ( TCP/22 )を許可する場合の例です。


# /sbin/iptables -A INPUT -m state --state NEW -p tcp -s 192.168.12.5 --dport 22 -j ACCEPT

UDPの場合も同様です。例えばDNS ( UDP/53 )への通信を全て許可する場合には次のように設定を行います。

# /sbin/iptables -A INPUT -m state --state NEW -p udp --dport 53 -j ACCEPT

またサーバ内部から外部への通信の設定はOUTPUTチェーンに対して行います。次はサーバ内部から外部へのSSH ( TCP/22 )とNTP ( UDP/123 )の接続を許可する設定の例です。

# /sbin/iptables -A OUTPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT
# /sbin/iptables -A OUTPUT -m state --state NEW -p udp --dport 123 -j ACCEPT

-dオプションを使えば接続相手のIPアドレスを明示的に指定することもできます。以下は192.168.12.2へのSMTP接続を許可する設定です。

# /sbin/iptables -A OUTPUT -m state --state NEW -p tcp -d 192.168.12.2 --dport 25 -j ACCEPT

FORWARDチェーンへ同様の設定をすることでルータとして転送する場合の通信許可も同様に行うことができます。

# /sbin/iptables -A FORWARD -m state --state NEW -p tcp -d 192.168.12.2 --dport 25 -j ACCEPT


■hashlimitによるDoS対策


前述したbrute force attackは既に古い手法であり、これを使うのであればhashlimitモジュールの使用をおすすめします。hashlimitはクライアントのIPアドレスごとに一定期間の接続回数をカウントし、閾値を超えた場合はドロップするといったことが可能となります。ありがちなのはWebメールサーバなどにおいて辞書攻撃を受けて不正にログインされSPAMを送られるということが過去にありました。こういったケースでは短時間に猛烈なアクセスをかけてくるので、こういった類の攻撃を防ぐのにも役立つと思います。

このhashlimitを使ったiptablesのconfigは以下のようになります。

-A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 22 \
-m hashlimit --hashlimit-burst 5 --hashlimit 1/m --hashlimit-mode srcip \
--hashlimit-htable-expire 120000 --hashlimit-name ssh-limit -j ACCEPT


長いので3行にわけて記載しています。各項目の意味は以下のようになります。

項目 説明 
-m hashlimit hashlimitモジュールを使用する 
-hashlimit-burst 5  規定時間内に5パケット受信すればリミットを有効にする 
-hashlimit 1/m  リミット時には1分間に1パケットを上限とする 
-hashlimit-mode srcip ソースIPを元にアクセスを制限する 
-hashlimit-htable-expire 120000  リミットの有効期間。単位はmsで120000は2分間。 
-hashlimit-name ssh-limit 送信元IPを記録するファイル名。 


繰り返しますがハッシュリミットは規定時間内にどれだけのパケットを受理するのかを制限するためのものです。-hashlimit-htable-expireでその規定時間を設定します。上では2分という値を設定しており、これが一定の区切りとなります。この2分の間に同一送信元IPから5パケット以上届けばリミットが有効となり、その後は毎分5パケットのみ許可されるようになります。2分が経過すると送信元IPが一旦リフレッシュされ、以降は同様の動きとなります。

hashlimit-nameで指定するファイルは送信元IPアドレスは以下に記録されます。

# tail /proc/net/ipt_hashlimit/ssh-limit
1171 192.168.12.2:0->0.0.0.0:0 1293728 1920000 1920000





■実際の設定


これまではINPUT/OUTPUTの両方でフィルタリングを考慮してきましが、実際の現場ではINPUTのみ設定することが多いです。市販のFirewall製品のようにiptablesはセッション情報まで保持しておらずこれまでみてきたように入力/出力パケットの両方を考慮しなければならず机上で設計した内容を適用してみると想定どおりに動かないことがよくあります。そもそもサーバ手前のFirewallでフィルタリングすることが多いのでiptablesではINPUTのみで良いように思います。


起動のたびにiptablesコマンドをうつのは非現実的なので/etc/sysconfig/iptablesに書き込んでいき起動の際に自動的に適用されるよう設定してゆきます。


# vi /etc/sysconfig/iptables

# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# 任意からHTTP/HTTPSアクセスを受け付ける
-A INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT

# 規定時間内に192.168.12.0/24からSSHアクセスを受け付ける
-A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 22 \
-m hashlimit --hashlimit-burst 5 --hashlimit 1/m --hashlimit-mode srcip \
--hashlimit-htable-expire 120000 --hashlimit-name ssh-limit -j ACCEPT

# 192.168.12.0/24からFTPアクセスを受け付ける
-A INPUT -m state --state NEW -p tcp -s 192.168.12.0/24 --dport 20:21 -j ACCEPT

# 任意へのDNS/NTPアクセスの戻りパケットを受け付ける
-A INPUT -p udp --sport 53 -j ACCEPT
-A INPUT -p udp --sport 123 -j ACCEPT

# 192.168.12.0/24からのNTPアクセスを受け付ける
-A INPUT -m state --state NEW -p udp -s 192.168.12.0/24 --dport 123 -j ACCEPT

# TCP戻りパケットを受け付ける
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMPパケットは全て許可
-A INPUT -p icmp -j ACCEPT

# ループバックインターフェイスに対して全て許可
-A INPUT -i lo -j ACCEPT

# ログを取得する。レベルはdebug/info/notice/warning/error/crit/emergから選択可能
-A INPUT -j LOG --log-prefix "iptables:" --log-level=error

# 上のルールを実行する
COMMIT


ログに関しては環境によっては膨大な数になるかもしれないので採取しないというのもありだと思います。また、IPアドレスなど明示的に指定しなければそれは任意(全て)という意味になります。これでiptablesを起動します。


# /etc/rc.d/init.d/iptables start


iptables -Lで確認します。


# iptables -L
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:https
ACCEPT     tcp  --  192.168.12.0/24      anywhere            state NEW tcp dpt:ssh \
limit: up to 1/min burst 5 mode srcip htable-expire 120000
ACCEPT     tcp  --  192.168.12.0/24      anywhere            state NEW tcp dpts:ftp-data:ftp
ACCEPT     udp  --  anywhere             anywhere            udp spt:domain
ACCEPT     udp  --  anywhere             anywhere            udp spt:ntp
ACCEPT     udp  --  192.168.12.0/24      anywhere            state NEW udp dpt:ntp
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination




■パケットフィルタの状態表示

iptablesによるパケットフィルタの状態を表示するユーティリティとしてiptstateを利用することができます。ログを採取することでもある程度の状態を把握することができますが、大量に出力されるためこういったツールを用いることでも有用に活用できると思います。iptstateを利用するには以下のようにインストールを行います。

# yum install iptstate
# rpm -qa | grep iptstate
iptstate-2.2.2-4.el6.i686


iptstateをrootユーザで起動すると次のような画面が表示されます。

                                 IPTState - IPTables State Top
Version: 2.2.2        Sort: SrcIP           b: change sorting   h: help
Source                             Destination                        Prt State       TTL
192.168.12.1:40501                 192.168.12.20:80                   tcp TIME_WAIT     0:00:08
192.168.12.1:40509                 192.168.12.20:80                   tcp TIME_WAIT     0:00:36
192.168.12.1:40521                 192.168.12.20:80                   tcp TIME_WAIT     0:01:28
192.168.12.20:42143                192.168.12.1:53                    udp               0:00:01
192.168.12.20:22                   192.168.12.2:54504                 tcp ESTABLISHED 119:59:59
192.168.12.20:42958                192.168.12.1:53                    udp               0:00:24
192.168.12.20:54388                192.168.12.1:53                    udp               0:01:53
192.168.12.20:54379                192.168.12.1:53                    udp               0:00:09
192.168.12.20:50001                192.168.12.1:53                    udp               0:00:17
192.168.12.20:123                  189.211.62.210:123                 udp               0:00:26
192.168.12.20:59379                192.168.12.1:53                    udp               0:00:06
192.168.12.20:44900                192.168.12.1:53                    udp               0:00:52
192.168.12.20:57550                192.168.12.1:53                    udp               0:02:55
192.168.12.20:55899                192.168.12.1:53                    udp               0:02:39
192.168.12.20:34487                192.168.12.1:53                    udp               0:00:52
192.168.12.20:54236                192.168.12.1:53                    udp               0:01:53 


 Copyright(C) 2003-2015 UnixPower on Networking All rights reserved.