Kodama's home / tips.
-->INPUT-->routing-->FORWARD(masquerade)--+-->OUTPUT--> | | +------->(local)------------->+
-->PREROUTING(DNAT)-->routing -----> FORWARD -----> +-->POSTROUTING(SNAT)--> | | +-->INPUT-->(local)-->OUTOUT-->+
まず, デフォルトの chain の構成がかなり違っている. 自分自身の入出力のパケット制限を行うだけならほとんど変わりは無いが, ルータ兼ファイアウォールとして使う場合, INPUT, OUTPUT の適用が, 全てのパケットだったものが, local に処理されるパケットのみに変更になっている. 言い替えると, 転送するパケットの入出力の制限は, FORWARD で行うのが基本となる.
masquerade(マスカレード, 内部から外部へのパケットのアドレス変換) は POSTROUTING(SNAT)で行う.
SET_FORWARD(){ echo forward/masquerade(SNAT) for $1 iptables -A FORWARD -j ACCEPT -s $1 -i ${INSIDE_DEVICE} -d ${WORLD} iptables -t nat -A POSTROUTING -s $1 -o ${OUTSIDE_DEVICE} -j MASQUERADE } SET_FORWARD 192.168.1.0/24
port-forwarding(外部から内部への転送) は PREROUTING(DNAT)で行うことになる.
SET_DNAT () { echo "DNAT: --protocol $1 --dport $2 --to $3:$2. (open for the WORLD)" iptables -A PREROUTING -t nat -d ${OUTSIDE_IP} -p $1 --dport $2 -j DNAT --to $3:$2 iptables -A FORWARD -j ACCEPT -d $3 -p $1 --dport $2 } SET_DNAT tcp 25 192.168.1.100
ルータ,ファイアウォールなどで区切られたセグメントが SEG0, SEG1, SEG2 の3個ある.
WORLD(The Internet, 0.0.0.0/0) | SEG0(DMZ, 10.0.0.0/8)--SERVER0(10.0.0.100, outer server, mail gateway) | (OUTSIDE_DEVICE=eth0, OUTSIDE_IP=10.0.0.200) Firewall (INSIDE_DEVICE=eth1, INSIDE_IP=192.168.1.1) | SEG1(192.168.1.0/24)--SERVER1(192.168.1.100, inner server, mail hub, http proxy, www server) | router | SEG2(192.168.2.0/24)--User's PC(192.168.2.*)
上の "Firewall" が Linux ベースの アドレス変換(NAT) と パケットフィルタによるファイアウォール.
SEG0 は The Internet からアクセスできる所謂 DMZ(DeMilitarized Zone). 例では 10.*.*.* のプライベートアドレスを書いているが, 実際にはプロバイダから与えられた公開用のアドレスを用いる.
DMZ に対外的なサービスを行うサーバ SERVER0 を置く. SERVER0 では 外部向けの メールサーバ(SERVER1 と 外部の転送の中継) などを行う.
SEG1 は firewall で保護されている, サーバ類を置く領域.
SERVER1 で メールサーバ, 外部用 WWW サーバ, 内部用 http proxy などを行う.
SEG2 は一般の PC を置く領域とする. ここからは smtp(メール), http(WWW) は直接には外部にアクセスできないようにする. (メールサーバ, http Proxy を利用してもらうため.)
iptables -L で表示したとき, 先頭側にあるルールから優先して適用される. -A で条件を追加すると既存のルールの末尾に追加される. つまり, 次のように並んでいたら, 上の ACCEPT の方が適用され, DROP の方は無視される.
iptables -A INPUT -j ACCEPT ... iptables -A INPUT -j DROP ...
iptables 関連の必要なモジュールは適宜組み込んでおくこと. (ipt_MARK, ipt_TOS, ipt_LOG, ip_conntrack_ftp, ip_conntrack_irc, iptable_mangle, ip_nat_ftp, ip_nat_irc, ipt_tos, ipt_mark, ipt_limit など.)
# Network Interfaces OUTSIDE_DEVICE=eth0 OUTSIDE_IP=10.0.0.200 INSIDE_DEVICE=eth1 INSIDE_IP=192.168.1.1 # Networks LOCAL_NETWORK=127.0.0.0/8 WORLD=0.0.0.0/0 SEG0=10.0.0.0/8 ; OUTSIDE_NETWORK=${SEG0} # DMZ SEG1=192.168.1.0/24 # server segment SEG2=192.168.2.0/24 # user's segment # Servers SERVER0=10.0.0.100 # outer server SERVER1=192.168.1.100 # inner server
## This script is based on FloppyFw-2.0.8(http://www.zelow.no/floppyfw/download.html) echo "Disabling IP forwarding." echo "0" > /proc/sys/net/ipv4/ip_forwardiptables の初期化. 大きく分けると, デフォルトで許可して拒否するものを明記するやりかたと, デフォルトで拒否して許可するものを明記するやりかたがあります. ここでは, 拒否をデフォルトとしておきます.
DROP と DENY のどちらも接続を拒否します. DENY では相手に接続出来ないという知らせのパケットを返しますが, DROP では単に無視します.
# Flushing the chains. iptables -F for i in `cat /proc/net/ip_tables_names`; do iptables -F -t $i ; done iptables -X iptables -Z echo Policy for forwarding, input and output.(DROP,DENY,ACCEPT) iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROPssh, telnet の様な対話型の利用では反応を特に重視します. メールの配送のような即座の反応を要しない場合についての優先度を下げて 対話型の利用が快適になるように配慮します.
echo Some attempt to get interactive sesions a bit more interactive under load: # ssh/22, ftp/21, ftp-data/20, http/80, nntp/119, smtp/25 iptables -A PREROUTING -t mangle -p tcp --sport 22 -j TOS --set-tos Minimize-Delay iptables -A PREROUTING -t mangle -p tcp --sport 21 -j TOS --set-tos Minimize-Delay iptables -A PREROUTING -t mangle -p tcp --sport 20 -j TOS --set-tos Maximize-Throughput iptables -A PREROUTING -t mangle -p tcp --sport 80 -j TOS --set-tos Maximize-Throughput iptables -A PREROUTING -t mangle -p tcp --sport 119 -j TOS --set-tos Minimize-Cost iptables -A PREROUTING -t mangle -p tcp --sport 25 -j TOS --set-tos Minimize-Cost内部の LAN で使用している Windows のファイル共有などが誤って外に出ない様にします.
echo "We do not like the NetBIOS and Samba leaking.." iptables -A FORWARD -j DROP -d ${WORLD} -p tcp --dport 135:139 iptables -A FORWARD -j DROP -d ${WORLD} -p udp --dport 135:139 iptables -A FORWARD -j DROP -d ${WORLD} -p tcp --dport 445 iptables -A FORWARD -j DROP -d ${WORLD} -p udp --dport 445マシンの内的な処理のために 127.*.*.* を許可しておきます.
# echo "loopback 127.0.0.0/8" iptables -A INPUT -j ACCEPT -s ${LOCAL_NETWORK} -d ${LOCAL_NETWORK} -i lo iptables -A OUTPUT -j ACCEPT -s ${LOCAL_NETWORK} -d ${LOCAL_NETWORK}
内部から外部に向けてのマスカレードを行う. 外部からは Firewall の外側アドレスからのパケットのように見えることになる.
ついでに内部同士(SEG1,SRG2)のルーティングも許可. (本来は内部のルータで行うべきだが, こうすると, SERVER1 のルーティングがいい加減でもなんとかなる. つまり, 正しくは, SERVER1 では, SEG0 方向と SEG2 方向へのルーティングをちゃんと設定するべきだが, SEG0 方向にパケットを投げればとりあえず動く....)
SET_FORWARD(){ echo forward/masquerade(SNAT) for $1 iptables -A FORWARD -j ACCEPT -s $1 -i ${INSIDE_DEVICE} -d ${WORLD} iptables -t nat -A POSTROUTING -s $1 -o ${OUTSIDE_DEVICE} -j MASQUERADE }
一般の(ユーザが使う) PC 用のセグメントから直接外部に出したくないプロトコルなどを止める. セキュリティ方針に従って, 内部ルータやサーバのアクセス制限と組み合わせる. 複数のセキュリティレベルがある場合には, それにあわせて制限をつける.
SET_FORWARD_DROP () { echo "DROP services for $1" # echo mail/25, http/80, http proxy/8080 deny iptables -A FORWARD -j DROP -s $1 -p tcp --dport 25 iptables -A FORWARD -j DROP -s $1 -p udp --dport 25 iptables -A FORWARD -j DROP -s $1 -p tcp --dport 80 iptables -A FORWARD -j DROP -s $1 -p udp --dport 80 iptables -A FORWARD -j DROP -s $1 -p tcp --dport 8080 iptables -A FORWARD -j DROP -s $1 -p udp --dport 8080 }
上のスクリプトを使って実際にパケット転送を設定.
SET_FORWARD ${SEG1} # server segment SET_FORWARD_DROP ${SEG2} ; SET_FORWARD ${SEG2} # user segment
メールサーバにはユーザが登録されているので直接外部に露出したくない. そこで中継サーバを置く事にする.
内部のユーザが使うメールサーバは SERVER1. 外部向けのメールはここから SERVER0 に転送してから当該サイトのサーバに送り込む.
一般のPCからは外部に直接 smtp 接続を出来ない様にする. これによって, PC がウイルスやワームに感染した場合でも, 外部への踏台となる事は避けられる.
外部からのメールは, 一旦 SERVER0 で受け取ってから, SERVER1 に転送する. Firewall は SERVER0 からの smtp パケットを SERVER1 に転送しなければならない.
更に, サーバでの透過的なウイルス検出も行うと良いが, ここでは解説しない.
The Internet | SERVER0 (mail gateway) | Firewall | SERVER1 (mail hub) | User's PC
WWW サーバは DMZ に置かずに firewall の内側に置いてみた. 外部向けのサービスを行うので, 外からの http パケットがここに到達する必要がある. Firewall は http/https パケットを SERVER1 に転送しなければならない. 外部からは Firewall の外側アドレスに WWW サーバがあるように見える.
The Internet | Firewall | SERVER1 (WWW)
SET_DNAT は外部(The Internet) から内部サーバへのパケット転送. SET_DNAT_DMZ は DMZ のサーバから内部サーバへのパケット転送.
echo Corresponding rules for the port-forward/DNAT. echo Takes care of connections from the outside to the inside. SET_DNAT () { echo "DNAT: --protocol $1 --dport $2 --to $3:$2. (open for the WORLD)" iptables -A PREROUTING -t nat -d ${OUTSIDE_IP} -p $1 --dport $2 -j DNAT --to $3:$2 iptables -A FORWARD -j ACCEPT -d $3 -p $1 --dport $2 } SET_DNAT_DMZ () { echo "DNAT: --proocol $1 --dport $2 --to $3:$2. (restricted DMZ only)" iptables -A PREROUTING -t nat -d ${OUTSIDE_IP} -p $1 --dport $2 -j DNAT --to $3:$2 iptables -A FORWARD -j ACCEPT -s ${OUTSIDE_NETWORK} -d $3 -p $1 --dport $2 iptables -A FORWARD -j DROP -s ${WORLD} -d $3 -p $1 --dport $2 }
実際にサービス毎に転送を設定.
SET_DNAT_DMZ tcp 25 ${SERVER1} # smtp/25 tcp port forward to mail hub SET_DNAT tcp 80 ${SERVER1} # http/80 tcp port forward to WWW server SET_DNAT tcp 443 ${SERVER1} # https/443 tcp port forward to WWW server
echo "drop private/multicast addresses" SET_DROP(){ iptables -A INPUT -j DROP -s $1 iptables -A FORWARD -j DROP -s $1 } SET_DROP 127.0.0.0/8 # loopback SET_DROP 10.0.0.0/8 # private SET_DROP 172.0.0.0/12 # private SET_DROP 192.168.0.0/16 # private SET_DROP 224.0.0.0/4 # multicast SET_DROP 0.0.0.0/8 # reserved SET_DROP 255.255.255.255 # broadcast
安直に ICMP を全て止めているサイトもあるようだが...それで良いのか?
echo Ping and friends. iptables -A INPUT -j ACCEPT -p icmp --icmp-type destination-unreachable # MTU check. required iptables -A INPUT -j ACCEPT -p icmp --icmp-type echo-reply # ping iptables -A INPUT -j ACCEPT -p icmp --icmp-type echo-request # ping iptables -A INPUT -j ACCEPT -p icmp --icmp-type time-exceeded # traceroute iptables -A INPUT -j DROP -p icmp
以下で接続が確立したものについては通信を許可している. INPUT, FORWARD のルールについては 通信の開始を許可するかどうかを(ここより上で)指示すると良い事になる. OUTPUT は NEW を許可しているので, 自分から接続を開始することはできる.
echo Keep state. iptables -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -m state --state ESTABLISH,RELATED -j ACCEPT iptables -A FORWARD -m state --state ESTABLISH,RELATED -j ACCEPT # So, basically, we have to write rules about NEW state for INPUT table (and FORWARD if needed).
IP forwarding を有効にしておしまい.
echo "Enabling TCP syn cookies." echo "1" > /proc/sys/net/ipv4/tcp_syncookies echo "Enabling anti spoofing." for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 1 > $f done echo "Enabling dynamic IP address following." echo 7 > /proc/sys/net/ipv4/ip_dynaddr echo "trying to stop some smurf attacks.(broadcast ping attack)" echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts echo "Enabling IP forwarding." echo "1" > /proc/sys/net/ipv4/ip_forward echo List all rules. iptables -L -n
Kodama's home / tips.