2014年4月20日日曜日

DD-WRT でゲスト用 WiFi AP を作る

訳あってゲスト用 WiFi アクセスポイント (WAN とは繋がるが LAN の他機器とは繋がらない AP) を作ることにした.といっても物理的な WiFi ルータを増設するわけではなく,DD-WRT なら仮想 WiFi I/F を作れるので,設定だけで下のようなネットワークを構成できる.
WAN--DD_WRT-+-有線,WiFi I/F [192.168.0.x/24] ←本来の LAN
            +-仮想 WiFi I/F  [192.168.1.x/24] ←ゲスト用 WiFi
というわけでここを見ながら仮想 WiFi I/F の追加と DHCP の設定までしたところで,本来の LAN から外に一切出れなくなった.参照ページの後ろの方に iptables の設定が載っているので仮想 WiFi⇔WAN 通信には iptables 設定が必要なのだろうけど,I/F 足しただけでなんで本来 LAN に影響が出るんだ? と思って,iptables -nvL してみたら,
root# iptables -nvL
Chain INPUT (policy ACCEPT 46 packets, 4591 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 28 packets, 1912 bytes)
 pkts bytes target     prot opt in     out     source               destination
root#


ルールがカラなうえ,default が全部 ACCEPT とかもうね.内から外に出られないばかりか,外からは丸見え状態www
なんか仮想 WiFi I/F 足しただけで,iptables の設定はすべて吹っ飛ぶのね…

というわけで昔 Linux でルータ組んだ時のことを思い出しつつ下のような iptables スクリプトを組んだ.
長ったらしいけど,キモは FORWARD チェインのところで,*->WAN, WAN->* のパケットを先に ACCEPT なり DROP なりした後,ゲスト LAN->*, *->ゲスト LAN のパケットを全破棄すれば,「ゲスト LAN は WAN しかアクセス出来ない」ということが実現できる.
#! /bin/sh

WanIF=ppp0              # WAN I/F
LanIF=br0               # 本来 LAN I/F
LanGstIF=ath0.1         # ゲスト WiFi I/F
LanIP=192.168.0.0/16    # 本来 LAN とゲスト LAN をカバーする IP アドレス・マスク

echo 1 > /proc/sys/net/ipv4/ip_forward

### local service ############################################################

State(){
    iptables -A $1 -m state --state ESTABLISHED,RELATED -j ACCEPT   # 接続済みを許可
    iptables -A $1 -p tcp ! --syn -m state --state NEW -j DROP      # おかしいパケットを廃棄
}

# ポート開放用のサブルーチン
OpenLocalPort(){
    iptables -A WanIn -p tcp --dport $1 -j ACCEPT
}

# ポートフォワーディング用のサブルーチン
PortForward(){  # sport, dip, dport
    iptables -t nat -A PREROUTING -p tcp -i $WanIF --dport $3 -j DNAT --to-destination $2:$3
    iptables -A WanInFwd -p tcp -d $2 --dport $3 -j ACCEPT
}

### Flush & Reset ############################################################

iptables -F
iptables -t nat -F
iptables -X

### WAN in/out filter ########################################################

# WAN->lo 入力フィルタ
iptables -N WanIn
OpenLocalPort 80                        # ポート開放例
iptables -A WanIn -j DROP

# WAN->どこか (FWD) 入力フィルタ
iptables -N WanInFwd
PortForward 21211 192.168.0.13 21211    # ポートフォワーディング例
iptables -A WanInFwd -j DROP

# WAN へ出力フィルタ
#  ローカルアドレスを外に出さない
iptables -N WanOut
for ip in 10.0.0.0/8 176.16.0.0/12 192.168.0.0/16 127.0.0.0/8; do
    iptables -A WanOut -d   $ip -j DROP
done

# SMB 関係のパケットを外に出さない
for port in 137:139 445 111; do
    iptables -A WanOut -p tcp --dport $port -j DROP
    iptables -A WanOut -p udp --dport $port -j DROP
done

iptables -A WanOut -j ACCEPT

# ゲスト LAN からの入力フィルタ
#  ゲスト LAN からルータの http サーバや SMB サーバにアクセスさせない
iptables -N LanGstIn
for port in 80 8080 22 137:139 445 111; do
    iptables -A LanGstIn -p tcp --dport $port -j DROP
    iptables -A LanGstIn -p udp --dport $port -j DROP
done
iptables -A LanGstIn -j ACCEPT          # Guest LAN->lo を許可

### Deafult Rule #############################################################

iptables -P INPUT ACCEPT
State INPUT                                 # ステートフルパケットフィルタ
iptables -A INPUT -i $WanIF -j WanIn        # WAN->lo を filter
iptables -A INPUT -i $LanGstIF -j LanGstIn  # ath0.1 からのパケットフィルタ

iptables -P OUTPUT ACCEPT
State OUTPUT                                # ステートフルパケットフィルタ
iptables -A OUTPUT -o $WanIF -j WanOut      # lo->WAN を filter

iptables -P FORWARD ACCEPT
State FORWARD                                       # ステートフルパケットフィルタ
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -A FORWARD -i $WanIF -j WanInFwd           # WAN->*   を filter
iptables -A FORWARD -o $WanIF -j WanOut             # *  ->WAN を filter
iptables -A FORWARD -i $LanGstIF -j DROP            # Guest->* を DROP
iptables -A FORWARD -o $LanGstIF -j DROP            # *->Guest を DROP

# NAT
iptables -t nat -A POSTROUTING -s $LanIP -o $WanIF -j MASQUERADE