「iptables」によるパケットフィルタリング

「iptables」を利用してパケットフィルタリングを行う。
また、その他にもkernelのパラメータを変更し、不要な通信を行わないようにする。
なお、ここでは通信のみの制御で、ルータとしての機能は行わない事とする。
当然の事ながら、ここでの設定はあくまで一例なので、この通りに行えば良い、という訳ではなく各自の環境に合わせて設定する。
なお、「Swatch」を利用してログを監視し、アクセス制限を行う場合はこちらを参照。

「iptables」の設定

iptableではチェインをグループ化したものをテーブルとする。
テーブルによって利用できるチェインが異なる。
デフォルトで存在するテーブルは以下の通り。

テーブル 説明
filter: -t オプションが指定されない場合のデフォルトのテーブル。
nat: 新しい接続を開くようなパケットに対して参照される。
Linuxをルータとして利用する場合には重要。
mangle: 特別なパケット変換に使われる。

iptableではチェインごとに通信を制御する。
主なチェインは以下の通り。

チェイン 説明
INPUT 入力されるパケット
OUTPUT 出力されるパケット
FORWARD 転送するパケット

ルール時に使用する主なパラメータは以下の通り。

ターゲット 説明
ACCEPT 許可
DROP 廃棄
REJECT 拒否(接続元に通知)

iptableコマンドに対してのオプションのコマンドで主なものは以下の通り。

コマンド 説明
-A チェインの最後にルールを追加する。
-D チェインのルールを削除する。
-I ルール番号を指定してチェインにルールを挿入する。
ルール番号が省略された場合、先頭に挿入する。
-R チェインのルールを置換する。
-L チェインのルールを表示する。
-F チェインのルールを全て削除する。
-Z すべてのチェインのパケットカウンタとバイトカウンタをゼロにする
-N ユーザ定義チェインを作成する。
-X ユーザ定義チェインを削除する。
-P チェインのポリシーを設定する。
-E ユーザ定義チェインの名前を変更する。

ルール時に使用する主なパラメータは以下の通り。

パラメータ 説明
-s 送信元
-d 送信先
-p プロトコル
--sport 送信元ポート
--dport 送信先ポート
-j ルールのターゲット
-i 受信するインタフェース
-o 送信するインタフェース
-c パケットカウンタとバイトカウンタを初期化する
-v 詳細な出力を表示する
-n IPアドレスやポート番号を数値で表示する
-x 厳密な数値で表示する

-m または --match でパケットマッチングモジュールを利用することが出来る。
利用できる主なものは以下の通り。
なお、ここでは一部しか記述していないが、大部分のものは ! を前に記述することにより、条件を逆に出来る。

パラメータ 説明
--limit 単位時間あたりの平均マッチ回数の最大値。
/second、/minute、/hour、/day が利用出来る。
デフォルトは 3/hour。
--limit-burst パケットがマッチする回数の最大初期値。
デフォルトは5。

上記はほんの一部で、この他にも数多くのオプション等が存在するが、数が多いし、書籍やネット上にも多くの情報があるので割愛。
ルールの作成はコマンドラインから行えるが、シェルスクリプトで行う方が一般的。

[root@Fedora ~]# vi filter_table.sh <= パケットフィルタ用スクリプトの作成
#!/bin/sh
IPTABLES="/sbin/iptables"
WGET="/usr/bin/wget"
RM="/bin/rm"

# 国別IPアドレスリスト取得
$WGET -q http://ftp.apnic.net/stats/apnic/delegated-apnic-latest # APNIC
$WGET -q ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest # ARIN

# ルールをクリア
$IPTABLES -F
$IPTABLES -X
$IPTABLES -Z

# デフォルト破棄
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP

# デフォルト許可
$IPTABLES -P OUTPUT ACCEPT 


# 指定した国からのアクセスを破棄
DROP_COUNTRY(){
  for IP in `cat $1 | grep "$2|$3|ipv4|"`
  do
    ADDR=`echo $IP |cut -d "|" -f 4`
    TEMP=`echo $IP |cut -d "|" -f 5`
    CIDR=32
    while [ $TEMP -ne 1 ];
    do
      TEMP=`expr "$TEMP" / 2`
      CIDR=`expr "$CIDR" - 1`
    done
    $IPTABLES -A INPUT -s $ADDR/$CIDR -j DROP
  done
}

# 中国
DROP_COUNTRY delegated-apnic-latest apnic CN
DROP_COUNTRY delegated-arin-latest arin CN
# 韓国
DROP_COUNTRY delegated-apnic-latest apnic KR
DROP_COUNTRY delegated-arin-latest arin KR
# 北朝鮮
DROP_COUNTRY delegated-apnic-latest apnic KP
DROP_COUNTRY delegated-arin-latest arin KP
# 台湾
DROP_COUNTRY delegated-apnic-latest apnic TW
DROP_COUNTRY delegated-arin-latest arin TW

# 国別IPアドレスリスト削除
$RM delegated-apnic-latest
$RM delegated-arin-latest


# 拒否しているINPUTから許可するものを設定
# 自端末からのアクセスを許可
$IPTABLES -A INPUT -i lo -j ACCEPT

# LAN内の他端末からのアクセスを許可
$IPTABLES -A INPUT -i eth0 -s 192.168.0.0/24 -j ACCEPT

# 新規接続がSYNで始まらない接続パケットは破棄
$IPTABLES -A INPUT -p tcp ! --syn -m state --state NEW -j DROP

# 接続が確立したパケットの応答は許可
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# ping
$IPTABLES -A INPUT -p icmp --icmp-type echo-request -s 192.168.0.0/24 -j ACCEPT

# SSH
$IPTABLES -A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# DNS
$IPTABLES -A INPUT -p tcp -m state --state NEW --dport 53 -s 192.168.0.0/24 -j ACCEPT
$IPTABLES -A INPUT -p udp --dport 53 -s 192.168.0.0/24 -j ACCEPT

# Ident
$IPTABLES -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset


# 許可しているOUTPUTから拒否するものを設定
# Samba
$IPTABLES -A OUTPUT -p tcp --dport 137:139 -s ! 192.168.0.0/24 -j DROP
$IPTABLES -A OUTPUT -p udp --dport 137:139 -s ! 192.168.0.0/24 -j DROP
$IPTABLES -A OUTPUT -p tcp --dport 445 -s ! 192.168.0.0/24 -j DROP
$IPTABLES -A OUTPUT -p udp --dport 445 -s ! 192.168.0.0/24 -j DROP

# Ident
$IPTABLES -A OUTPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset


# ログの設定
$IPTABLES -N LOGGING
$IPTABLES -A LOGGING -m limit -j LOG --log-level warning --log-prefix "DROP:"
$IPTABLES -A LOGGING -j DROP
$IPTABLES -A INPUT -j LOGGING
$IPTABLES -A FORWARD -j LOGGING


[root@Fedora ~]# chmod 700 filter_table.sh <= 作成したスクリプトに実行権限付加

設定の保存

ルールを設定しても再起動すると元に戻ってしまうので、ルールを保存する。

[root@Fedora ~]# iptables-save > filter_table.cfg <= 現在の設定をファイルに書き込む
[root@Fedora ~]# iptables-restore < filter_table.cfg <= ファイルから設定を読み込む

[root@Fedora ~]# iptables-save -c > filter_table.cfg <= パケットカウンタやバイトカウンタもファイルに書き込む
[root@Fedora ~]# iptables-restore -c < filter_table.cfg <= パケットカウンタやバイトカウンタも読み込む

以下のようにスクリプトを実行しても保存される。

[root@Fedora ~]# /etc/rc.d/init.d/iptables save

「iptables」の初期化ファイルは
/etc/sysconfig/iptables
であり、上記のスクリプト内でもこのファイルに書き込む処理を行っている。

接続に時間がかかる場合

iptablesを設定後、接続に時間がかかるが接続できる場合、多くはDNS関連の問題である。
例えば、SSH接続でクライアント側でMulticast DNS(mDNS)を利用している場合に サーバ側のUDPの5353番ポートを空けていないと逆引き出来ずに認証に時間がかかる事がある。
その場合、上記の設定用のスクリプトに

$IPTABLES -A INPUT -p udp --dport 5353 -d 224.0.0.251 -j ACCEPT

のルールを追加すれば、すぐに接続できるようになる。
基本的に上記の設定で問題ないが、ポートを出来るだけ空けたくない場合、クライアント側で

[root@Fedora ~]# vi /etc/nsswitch.conf
hosts:          files mdns4_minimal [NOTFOUND=return] dns mdns4
↓
hosts:          files dns [NOTFOUND=return] mdns4_minimal mdns4

といった感じで、mdns4を利用しないようにすれば良い。

kernelの設定

kernelの設定

kernelのパラメータで通信関係の設定で主なものは以下の通り。

パラメータ 説明
/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts ネットワークのブロードキャストアドレスのping。
/proc/sys/net/ipv4/icmp_ignore_bogus_error_responses ブロードキャストアドレス向けに対して不正に反応したために発したICMPerror。
/proc/sys/net/ipv4/ip_forward IPマスカレード。
/proc/sys/net/ipv4/tcp_syncookies SYNクッキーが有効かどうか。
/proc/sys/net/ipv4/conf/*/accept_source_route Source-routedパケット。
/proc/sys/net/ipv4/conf/*/accept_redirects ICMP Redirectパケット。

上記の内容もシェルスクリプトに記述すると便利。

[root@Fedora ~]# vi filter_kernel.sh <= パケットフィルタ用スクリプトの作成
#!/bin/sh

# ネットワークのブロードキャストアドレスのpingを無視
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

# ブロードキャストアドレス向けに対して不正に反応したために発したICMPerrorを無視
echo 1 > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

# IPマスカレードを使用しない
echo 0 > /proc/sys/net/ipv4/ip_forward

# SYN Flood攻撃を防ぐ
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

# Source-routedパケットを拒否
for i in /proc/sys/net/ipv4/conf/*/accept_source_route
do
  echo 0 > $i
done

# ICMP Redirectパケットを拒否
for i in /proc/sys/net/ipv4/conf/*/accept_redirects
do
  echo 0 > $i
done

設定の保存

上記の内容は再起動すると初期化されるので、設定ファイルに記述する。
設定したい内容に合わせて、設定ファイルの初期値を設定する。

[root@Fedora ~]# vi /etc/sysctl.conf <= 設定ファイルの編集
以下になるように該当個所を修正
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.ip_forward = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.accept_redirects = 0
▲ページのトップへ