目次
ファイアーウォールを作る~セキュリティを高めよう
防火壁です:-)
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 大陸とかからの執拗な攻撃をまとめてばっさり拒否.