iptables起動設定
Debianにてiptablesを起動時に復元するための設定方法を調査した。どうやら、きちんと決められた方法はなく、自分でシェルスクリプトを書く必要があるらしい。 /etc/network/interfacesのpre-upに書くという方法が一番簡単そうだったが、現在のiptablesの設定はインターフェース単位ではないのでその方法はとらず、/etc/init.dにスクリプトを置くという方法をとることにした。
/etc/init.d配下のシェルスクリプトには決められた様式があり、ひな型としては、/etc/init.d/skeletonがあるが、これはデーモン用のものであるため、とりあえず、/etc/init.d/ifupdownを参考にして、前に作成したSSHのフィルタリングを行うルール(この記事を参照)を設定するように以下のスクリプトmyfirewallを作成した。
### BEGIN INIT INFO
# Provides: myfirewall
# Required-Start:
# Required-Stop: $local_fs
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Set firewall.
### END INIT INFO
[ -x /sbin/iptables ] || exit 0
. /lib/lsb/init-functions
MYNAME="${0##*/}"
report() { echo "${MYNAME}: $*" ; }
report_err() { log_failure_msg "$*" ; }
[ -r /etc/default/$MYNAME ] && . /etc/default/$MYNAME
start_firewall () {
iptables -N SSHEvil
iptables -N SSH
iptables -A INPUT -j SSH -p tcp --dport 22
iptables -A SSHEvil -m recent --name badSSH --set
iptables -A SSHEvil -j LOG --log-level DEBUG --log-prefix "evil SSH user:"
iptables -A SSHEvil -j DROP
iptables -A SSH -j ACCEPT -s 192.168.0.0/24
iptables -A SSH -p tcp ! --syn -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A SSH -p tcp --syn -m recent --name badSSH --update --seconds 600 -j REJECT
iptables -A SSH -p tcp --syn -m recent --name conSSH --rcheck --seconds 60 --hitcount 5 -j SSHEvil
iptables -A SSH -p tcp --syn -m recent --name conSSH --set
iptables -A SSH -p tcp --syn -j ACCEPT
}
stop_firewall () {
iptables -F SSHEvil
iptables -F SSH
iptables -F INPUT
iptables -X
}
case "$1" in
start)
log_begin_msg "Setting up firewall..."
start_firewall
log_end_msg 0
exit 0
;;
stop)
log_begin_msg "Stopping firewall..."
stop_firewall
log_end_msg 0
exit 0
;;
restart|force-reload)
log_begin_msg "Restarting firewall..."
stop_firewall
start_firewall
log_end_msg 0
exit 0
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
exit 0
次に実際に起動時にinitに起動してもらうため、必要なランレベルのディレクトリィにリンクを張る必要がある。Debianの/etc/inittabは以下のようになっている。
id:2:initdefault:
# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS
# What to do in single-user mode.
~~:S:wait:/sbin/sulogin
# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
基本的にネットワーク起動前にiptablesを設定する必要があるのだが、Debianの場合は起動は以前に調査した結果、/etc/init.d/udev startでeth0が起動し、/etc/init.d/networking stopでeth0が停止することがわかっている(詳細はこの記事参照)。/etc/init.d/udevは/etc/rcS.d/S03udevで開始され、/etc/init.d/networkingは/etc/rc{0,6}.d/S35networkingで停止される。続くS36ifupdownもネットワークに関連するスクリプトであり、状態ファイルの削除を行っているものである。
通常Sから始まるスクリプトは起動スクリプトであるが、initよりランレベルを引数として実際に起動されている/etc/rcスクリプトを見てみると、以下のようになっている。
case "$runlevel" in
0|6)
ACTION=stop
# Count down from 0 to -100 and use the entire bar
first_step=0
progress_size=100
step_change=-1
;;
(省略)
# First, run the KILL scripts.
if [ "$previous" != N ]
then
# Run all scripts with the same level in parallel
CURLEVEL=""
for s in /etc/rc$runlevel.d/K*
do
level=$(echo $s | sed 's/.*\/K\([0-9][0-9]\).*/\1/')
if [ "$level" = "$CURLEVEL" ]
then
continue
fi
CURLEVEL=$level
SCRIPTS=""
for i in /etc/rc$runlevel.d/K$level*
do
(省略)
SCRIPTS="$SCRIPTS $i"
done
startup stop $SCRIPTS
done
fi
# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
CURLEVEL=""
for s in /etc/rc$runlevel.d/S*
do
level=$(echo $s | sed 's/.*\/S\([0-9][0-9]\).*/\1/')
if [ "$level" = "$CURLEVEL" ]
then
continue
fi
CURLEVEL=$level
SCRIPTS=""
for i in /etc/rc$runlevel.d/S$level*
do
[ ! -f $i ] && continue
(省略)
SCRIPTS="$SCRIPTS $i"
done
startup $ACTION $SCRIPTS
done
fi
Debianではinitスクリプトのリンクを作成するコマンドupdate-rc.dがある。事前に/etc/init.d/配下にスクリプトが存在する必要があるので、上記のmyfirewallを/etc/init.d/へコピーする。update-rc.dコマンドの書式は以下となる。
{start | stop}から{.}までは複数個記述することができる。よって、以下のコマンドを実行すればよい。
Adding system startup for /etc/init.d/myfirewall ...
/etc/rc0.d/S37myfirewall -> ../init.d/myfirewall
/etc/rc6.d/S37myfirewall -> ../init.d/myfirewall
/etc/rcS.d/S03myfirewall -> ../init.d/myfirewall
■ 参考資料
Software/iptables - Debian GNU/Linux スレッドテンプレ
Manpage of IPTABLES
Manpage of BASH