目次
ファイアーウォールを作る~セキュリティを高めよう
防火壁です:-)
Linux IP Connection Tracking Modules を利用して,製品レベルの firewall を設計します(とゆうか,製品にはまさにそのもの現物が使われています).
いつの間にやら複雑化してしまいましたが…
使えそうなら適当に改造して使って下さい.
どうゆう環境で?
2つのI/Fをブリッジしている環境向けです.
例えば,有線ネットワークを無線に繋いでいるイーサネットコンバーターや pppoe で ISP にアップリンクしているルーター機の場合など.
この場合,EXT=wlan0 を ppp+ などに適宜書き換えて下さい.
私は Orange Pi の様なシングルボードコンピューターをイーサネットコンバータとして使い,この firewall を走らせています.
Linux カーネル
一般的なディストリビューションなら大丈夫の筈ですが,カーネルモジュール,特に特定の LOG ターゲットなどへのモジュールがないと怒られるかも.
その場合は .config 調節してカーネルリコンパイルか,そのターゲットを使わない様に改造するとかですね.
動作原理
どうゆう設計思想でどうゆう動作原理かは…
説明したいのですが,めちゃめちゃ長くなるので,次回以降にでも(–;;
詳しくはソースを追いながら iptables のマニュアルなどを参照して下さい.
ものすごく大雑把に説明すると,
- 基本的に入ってくるパケットも出ていくパケットもすべて拒否し
- 厳密に指定したパケットのみを許可する.
- 見通し向上と扱いやすくする為に IN/OUT でチェーンを分ける.
- IP Connection Tracking Modules の機能で NEW,ESTABLISHED と ESTABLISHED を区別し,
- 開いたポートを追跡してその要求に対応するポートのみ許可する.
- なりすまし防止とか
みたいな.
※あまりにも厳密にブロックするので,何かが動かないときの原因はたいていコイツです(笑).
firewall
#! /bin/sh
## ポリシー設定.
DEFAULT_POLICY_INPUT='DROP'
DEFAULT_POLICY_OUTPUT='DROP'
DEFAULT_POLICY_FORWARD='DROP'
## ローカルの定義.
LOCAL='192.168.0.0/16'
## どこでも.
ANY='0/0'
## external IF.
EXT='wlan0'
## local IF.
INT='eth0'
## wireless 特権許可.親routerに繋がっているタブレットなど用.
#EXT_MINE='192.168.1.126'
## 追加のリスト読込. 巨大ファイルはアップリンク時のタイムアウトに注意.
#DROPLIST='./DROPLIST'
## ドロップリストをログするかどうか.
#LOG_DROPLIST=1
## ローカルアドレス.偽造されたらログして捨てる.
SPOOFING='
224.0.0.0/4
240.0.0.0/5
10.0.0.0/8
127.0.0.0/8
172.16.0.0/12
'
## デバッグ用.マーカー出力
#DEBUGMODE=1
## デバッグ用.INPUT,OUTPUT チェインをログするかどうか.
#DEBUGLOG=1
#LOGADDR='192.168.10.10/24'
## くだらない攻撃などをログするかどうか.
#LOG_JUNK_PACKETS=1
## ウイルス等の自動スキャンに使われるポート.ログしない.パケットは破棄される.
VIRUSPORTS='137 445 1433 17300'
## 137: ??, 445: DELODER, Windows trojan, 1433: Spida, SQL worm, 17300: Kuang2
## 外部からアクセスを許可するポート.
INPORTS='
'
## 外部へのアクセスを許可するポート.
OUTPORTS='
22
25
42
43
53&proto=tcp
53&proto=udp
80
113
123&proto=udp
143
443
587
873
995
11371
'
## 追加のオプションが必要な時は & で区切る.追加出来るオプションは以下の通り.
## inchain= ルールを追加するチェイン.
## outchain= ルールを追加するチェイン.
## src= 接続元IP
## proto= プロトコル.tcp,udp,icmp,all 等.
## state= 二つ以上追加する時は , で区切る.
## 20: ftp-data
## 21: ftp
## 22: ssh
## 23: telnet
## 25: smtp
## 42: name
## 43: whois
## 53: named
## 80: www
## 110: pop3
## 113: auth
## 123: ntp
## 143: imap
## 443: https
## 587: submission port
## 873: rsync
## 995: pop for gmail
## 6660: irc
## 8080: delegate
## 8123: polipo
## 9050:9051: Tor
## 11371: hkp gnupg
## 49999: rtorrent
## ---------------------------------------------------------------------------------
## 全ルール消去,空チェイン削除,カウンタリセット.
[ ! -z ${DEBUGMODE} ] && echo '>> reset...'
iptables -F -t nat
iptables -F
iptables -X
iptables -Z
## ポリシー設定.
[ ! -z ${DEBUGMODE} ] && echo '>> set policy...'
iptables -P INPUT ${DEFAULT_POLICY_INPUT}
iptables -P OUTPUT ${DEFAULT_POLICY_OUTPUT}
iptables -P FORWARD ${DEFAULT_POLICY_FORWARD}
## マスカレード.
[ ! -z ${DEBUGMODE} ] && echo '>> set masq...'
iptables -A FORWARD -s ${LOCAL} -j ACCEPT
iptables -A FORWARD -d ${LOCAL} -j ACCEPT
iptables -t nat -A POSTROUTING -o ${EXT} -j MASQUERADE
## NAT
#iptables -t nat -A PREROUTING -i ${EXT} --dport 843 -j DNAT --to-destination 192.168.10.10
#iptables -t nat -A PREROUTING -i ${EXT} --dport 991:999 -j DNAT --to-destination 192.168.10.10
#iptables -t nat -A PREROUTING -i ${EXT} --dport 8094:8099 -j DNAT --to-destination 192.168.10.10
## NAT を有効に.
[ ! -z ${DEBUGMODE} ] && echo '>> NAT enable...'
echo 1 > /proc/sys/net/ipv4/ip_forward
## I/O: ループバック内を全て許可.
[ ! -z ${DEBUGMODE} ] && echo '>> accept loopback...'
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
## I/O: ローカル内を全て許可.
[ ! -z ${DEBUGMODE} ] && echo '>> accept local...'
iptables -A INPUT -i ${INT} -s ${LOCAL} -j ACCEPT
iptables -A OUTPUT -o ${INT} -d ${LOCAL} -j ACCEPT
## ---------------------------------------------------------------------------------
## I/O: 攻撃分離チェーン作成,適用.
[ ! -z ${DEBUGMODE} ] && echo '>> make filter chain...'
iptables -N filter
iptables -A INPUT -i ${EXT} -j filter
## IN: spoofing.
[ ! -z ${DEBUGMODE} ] && echo '>> for spoofing...'
for SRC in ${SPOOFING}
do
[ ! -z ${LOG_JUNK_PACKETS} ] && iptables -A filter -i ${EXT} -s ${SRC} -j LOG --log-prefix 'FILTER-SPOOFING:'
iptables -A filter -i ${EXT} -s ${SRC} -j DROP
done
## I/O: ping of death.
[ ! -z ${DEBUGMODE} ] && echo '>> for ping of death...'
iptables -A filter -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
[ ! -z ${LOG_JUNK_PACKETS} ] && iptables -A filter -p icmp --icmp-type echo-request -j LOG --log-prefix 'FILTER-PING-OF-DEATH:'
iptables -A filter -p icmp --icmp-type echo-request -j DROP
## I/O: port scaner.
[ ! -z ${DEBUGMODE} ] && echo '>> for port scaner...'
iptables -A filter -p tcp --tcp-flag SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
[ ! -z ${LOG_JUNK_PACKETS} ] && iptables -A filter -p tcp --tcp-flag SYN,ACK,FIN,RST RST -j LOG --log-prefix 'FILTER-PORT-SCAN:'
iptables -A filter -p tcp --tcp-flag SYN,ACK,FIN,RST RST -j DROP
## I/O: syn flood.
[ ! -z ${DEBUGMODE} ] && echo '>> for syn flood...'
iptables -A filter -p tcp --syn -m limit --limit 1/s --limit-burst 8 -j ACCEPT
[ ! -z ${LOG_JUNK_PACKETS} ] && iptables -A filter -p tcp --syn -j LOG --log-prefix 'FILTER-SYN-FLOOD:'
iptables -A filter -p tcp --syn -j DROP
## I/O: ウイルス等の既知の自動スキャンを破棄.
[ ! -z ${DEBUGMODE} ] && echo '>> for virusports...'
if [ ! -z "${VIRUSPORTS}" ];then
for PORT in ${VIRUSPORTS}
do
iptables -A filter -p tcp --dport ${PORT} -j DROP
iptables -A filter -p udp --dport ${PORT} -j DROP
done
fi
## ---------------------------------------------------------------------------------
## wireless 特権許可
[ ! -z ${DEBUGMODE} ] && echo '>> accept wireless mine...'
if [ ! -z ${EXT_MINE} ];then
iptables -A INPUT -s ${EXT_MINE} -j ACCEPT
iptables -A OUTPUT -d ${EXT_MINE} -j ACCEPT
fi
## I/O: gate (一時的に追加するルール等を入れる)
[ ! -z ${DEBUGMODE} ] && echo '>> make gate chain...'
iptables -N gate
iptables -A INPUT -i ${EXT} -j gate
iptables -A OUTPUT -o ${EXT} -j gate
## I/O: 落すアドレスのログ保存専用チェーン作成.
[ ! -z ${DEBUGMODE} ] && echo '>> make gate-log chain...'
iptables -N gate-log
[ ! -z ${LOG_DROPLIST} ] && iptables -A gate-log -j LOG --log-prefix 'GATE-DENY-ADDRESS:'
iptables -A gate-log -j DROP
## I/O: 落すアドレスをゲートチェーンに入れる.
if [ "${1}" = 'drop' ];then
source ${DROPLIST}
for LST in ${DENYADDRESS}
do
iptables -A gate -s ${LST} -i ${EXT} -j gate-log
done
fi
## I/O: wlan 分離して INPUT, OUTPUT から遠ざける.
[ ! -z ${DEBUGMODE} ] && echo '>> make wlan-out chain...'
iptables -N wlan-in
iptables -N wlan-out
iptables -A INPUT -i ${EXT} -j wlan-in
iptables -A OUTPUT -o ${EXT} -j wlan-out
## デバッグログの取得.
if [ ! -z ${DEBUGLOG} ];then
[ -z ${LOGADDR} ] && LOGADDR=${ANY}
iptables -A wlan-in -s ${LOGADDR} -j LOG --log-prefix 'DEBUG-INPUT:'
iptables -A wlan-out -d ${LOGADDR} -j LOG --log-prefix 'DEBUG-OUTPUT:'
fi
## OUT: ping を許可.
[ ! -z ${DEBUGMODE} ] && echo '>> accept ping/pong/traceroute...'
iptables -A wlan-out -p icmp -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
## IN: pong を許可.
iptables -A wlan-in -p icmp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
## OUT: traceroute を許可.
iptables -A wlan-out -p udp --dport 33434:33534 -m conntrack --ctstate NEW -j ACCEPT
## ---------------------------------------------------------------------------------
## IN: 外側からのアクセスを許可.
[ ! -z ${DEBUGMODE} ] && echo '>> accept ports from external...'
for LST in ${INPORTS}
do
INCHAIN='wlan-in'; OUTCHAIN='wlan-out'; SRC=${ANY}; PROTO='tcp'; PORT=''; STATE='';
if (echo ${LST} | grep -i 'inchain' > /dev/null);then
INCHAIN=echo ${LST} | sed -e 's/.*inchain=\([0-9a-z\-_]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'outchain' > /dev/null);then
OUTCHAIN=echo ${LST} | sed -e 's/.*outchain=\([0-9a-z\-_]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'src' > /dev/null);then
SRC=echo ${LST} | sed -e 's/.*src=\([0-9a-z\.\/]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'proto' > /dev/null);then
PROTO=echo ${LST} | sed -e 's/.*proto=\([a-z\.]*\).*/\1/i'
fi
PORT=echo ${LST} | sed -e 's/^\([0-9a-z:]*\).*$/\1/i'
if (echo ${LST} | grep -i 'state' > /dev/null);then
STATE=,echo ${LST} | sed -e 's/.*state=\([A-Z,]*\).*/\1/'
fi
iptables \
-A ${INCHAIN} \
-s ${SRC} \
-p ${PROTO} \
--dport ${PORT} \
-m conntrack \
--ctstate NEW,ESTABLISHED${STATE} \
-j ACCEPT
iptables \
-A ${OUTCHAIN} \
-d ${SRC} \
-p ${PROTO} \
--sport ${PORT} \
-m conntrack \
--ctstate ESTABLISHED${STATE} \
-j ACCEPT
done
## ---------------------------------------------------------------------------------
## OUT: 外側へのアクセスを許可.
[ ! -z ${DEBUGMODE} ] && echo '>> accept ports to external...'
for LST in ${OUTPORTS}
do
INCHAIN='wlan-in'; OUTCHAIN='wlan-out'; SRC=${ANY}; PROTO='tcp'; PORT=''; STATE='';
if (echo ${LST} | grep -i 'inchain' > /dev/null);then
INCHAIN=echo ${LST} | sed -e 's/.*inchain=\([0-9a-z\-_]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'outchain' > /dev/null);then
OUTCHAIN=echo ${LST} | sed -e 's/.*outchain=\([0-9a-z\-_]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'src' > /dev/null);then
SRC=echo ${LST} | sed -e 's/.*src=\([0-9a-z\.\/]*\).*/\1/i'
fi
if (echo ${LST} | grep -i 'proto' > /dev/null);then
PROTO=echo ${LST} | sed -e 's/.*proto=\([a-z\.]*\).*/\1/i'
fi
PORT=echo ${LST} | sed -e 's/^\([0-9a-z:]*\).*$/\1/i'
if (echo ${LST} | grep -i 'state' > /dev/null);then
STATE=,echo ${LST} | sed -e 's/.*state=\([A-Z,]*\).*/\1/'
fi
iptables \
-A ${OUTCHAIN} \
-d ${SRC} \
-p ${PROTO} \
--dport ${PORT} \
-m conntrack \
--ctstate NEW,ESTABLISHED${STATE} \
-j ACCEPT
iptables \
-A ${INCHAIN} \
-s ${SRC} \
-p ${PROTO} \
--sport ${PORT} \
-m conntrack \
--ctstate ESTABLISHED${STATE} \
-j ACCEPT
done
## ---------------------------------------------------------------------------------
## IN: それら以外に入って来るパケットを記録して破棄.
[ ! -z ${DEBUGMODE} ] && echo '>> logging drops...'
iptables -A wlan-in -j LOG --log-prefix 'WLAN-IN-DROP:'
## OUT: 未知の新規パケットを特に記録,
if [ ! ${DEFAULT_POLICY_OUTPUT} = 'ACCEPT' ];then
iptables -A wlan-out -p tcp --syn -m conntrack --ctstate NEW -j LOG --log-prefix 'WLAN-OUT-DROP-NEW:'
iptables -A wlan-out -j LOG --log-prefix 'WLAN-OUT-DROP:'
fi
droplist
こんな感じでリストにする.
./DROPLIST.src
DENYADDRESS='
207.68.128.0/18
207.68.192.0/20
'
確認
# iptables -L -nダウンロード
本体: firewall.src 一行目と最終行を削除してね.
落とすリスト:DROPLIST.src 大陸とかからの執拗な攻撃をまとめてばっさり拒否.

