VPN サーバをルータ化する
お品書き
iptables の基本ルール
- INPUT / OUTPUT / FORWARD は DROP。
- 一度接続が確立された(ESTABLISHED) INPUT / OUTPUT / FORWARD は許可。
iptables のスクリプトは最後に記述するとして、初めに VPN が接続されるまでにどのようなプロトコルで送られてくるかを確認しておく。
VPN (L2TP) 接続前のルール
図を見ると VPN サーバはインターネット上にあり、 eth0 というネットワークカードにグローバルIPアドレス 1.2.3.4 が割り当てられている。
# eth0 に IN する UDP:1701, UDP:500, UDP:4500 を許可する必要がある。 $IPTABLES -A INPUT -i eth0 -p udp -m multiport --dport 1701,500,4500 -j ACCEPT
※ $IPTABLES は iptables コマンドへのパスを表している
# L2TP で接続するために eth0 から OUT するパケットも許可する。 $IPTABLES -A OUTPUT -o eth0 -p udp -m multiport --sport 1701,500,4500 -j ACCEPT
# esp プロトコルが必須かどうかは未検証だが、面倒なので許可する $IPTABLES -A INPUT -i eth0 -p esp -j ACCEPT
上記の設定を行うことで、 VPN サーバと VPN クライアントは L2TP で接続される (VLAN でつながる) 。
VPN 接続後の (ルータ化)
VLAN でつながるようになったので VPN サーバのルータ化設定を行う。
VPN とインターネットの関係を簡略化するとこのようになる。
LAN とインターネットの関係とほぼ一緒ということが分かる。
図を見ると大まかに 3 種類のルールが必要となる。
SNAT (MASQUERADE)
赤いラインは VLAN (pppX) からインターネットに送られるパケットの SNAT (MASQUERADE) ルールだ。
パケットが eth0 から出ていくときに、 From の IP アドレスが 192.168.100.X になっているので、送り返されてくるパケットが行方不明になってしまう。
そこで Source IP アドレスをグローバル IP アドレスに変換することで、正常に通信できるようにする。
$IPTABLES -t nat -A POSTROUTING -o eth0 -s $VPN_RANGE -j MASQUERADE
DNAT (DMZ へのポートマップ)
青いラインはインターネット (eth0) から特定のポートに送られてくるパケットを、 DMZ の IP アドレス:ポートに変換するルールだ。
DMZ 上のサーバというのは、本来であれば LAN 内に置いた公開用 WEB サーバとかいった意味合いになるのだが、この場合は BitComet を利用したい PC の意。
$IPTABLES -t nat -A PREROUTING -i eth0 -p tcp --dport $DMZ_PORT -j DNAT --to-destination $DMZ_IP:$DMZ_PORT
VLAN の FORWARD ルール
# VLAN からインターネットに出ていくパケットを許可 (MASQUERADE 用) $IPTABLES -A FORWARD -i ppp+ -o eth0 -j ACCEPT # VLAN 間の FORWARD を許可 $IPTABLES -A FORWARD -i ppp+ -o ppp+ -j ACCEPT # インターネットから DMZ に入ってくるパケットを許可 $IPTABLES -A FORWARD -i eth0 -o ppp+ -p tcp --dport $DMZ_PORT -j ACCEPT
SNAT / DNAT / FORWARD の設定をすることで、 LAN から VLAN を通ってインターネット側に通信できるようになった。
iptables アンロード設定
VPN ルータとしての利用がメインとなるため、 iptables を再起動したときに、それまで接続していたセッションが切れるのはよろしくない。
従って iptables 再起動時にモジュールをアンロードしない設定が必要となる。
この設定をしていない場合、アンロードするとそれまで ESTABLISHED だったセッションが INVALID になる = 切れる。
# vi /etc/sysconfig/iptables-config -------------------------------------------------- 8 # Unload modules on restart and stop 9 # Value: yes|no, default: yes 10 # This option has to be 'yes' to get to a sane state for a firewall 11 # restart or stop. Only set to 'no' if there are problems unloading netfilter 12 # modules. 13 IPTABLES_MODULES_UNLOAD="no" --------------------------------------------------
※ IPTABLES_MODULES_UNLOAD を no にする。
iptables スクリプト
- ipfilter というファイル名でスクリプトを保存する
- ipfilter のパーミッションを 700 にする
- ipfilter を実行する
このサーバは cloudn の 400 [円/月] のやつなので、サービスは最低限しか起動してはいけない。
まあ、ルータとして使う分には十分のはず。入れたとしても samba くらい。
ルータ機能に影響するので、間違ってもリソース食いの Apache や postfix 等の余計なサービスは起動しないこと。
# vi /root/bin/ipfilter_allow_ssh ------------------------------ 5.6.7.8 # MyServer1 5.6.7.9 # MyServer2 ------------------------------ ※ インターネット側から SSH 許可する端末の IP アドレスを記載 ※ VPN 内は全許可のルールのため、 VPN クライアントの IP アドレスをいちいち記載しておく必要はない # vi /root/bin/ipfilter ------------------------------ (略) ------------------------------ ※ 何行か下のスクリプトをコピペ ※ 自分の環境に合わせて Environment Variable を編集すること # chmod 700 /root/bin/ipfilter # /root/bin/ipfilter
- echo "# Environment Variable Setting..."
- ####################
- # Environment Variable
- ####################
- # Network
- GLOBAL_IP='1.2.3.4'
- VPN_RANGE='192.168.100.0/24'
- DMZ_IP='192.168.100.200'
- DMZ_PORT='8080'
- # Command
- SYSCTL='/sbin/sysctl'
- MODPROBE='/sbin/modprobe'
- IPTABLES='/sbin/iptables'
- SERVICE_IPTABLES='/etc/rc.d/init.d/iptables'
- ALLOW_SSH_FILE='/root/bin/ipfilter_allow_ssh'
- # Security Parameters
- SYNLIMIT="10/s" # SYN-Flood Permit 10 times/s
- SYNBURST="25" # SYN-Flood MAX 25 times
- PINGLIMIT="6/s" # PING-Flood Permit 6 times/s
- PINGBURST="15" # PING-Flood MAX 15 times
- echo "# Load Module..."
- ####################
- # Load Module
- ####################
- $MODPROBE iptable_nat
- echo "# Set Kernel Parameters..."
- ####################
- # Kernel Parameters
- ####################
- # SYN Cookies ( TCP SYN Flood )
- $SYSCTL -w net.ipv4.tcp_syncookies=1 > /dev/null
- # Broadcast ping ( Smurf Atack )
- $SYSCTL -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null
- for dev in `ls /proc/sys/net/ipv4/conf/`
- do
- # ICMP Redirect
- $SYSCTL -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null
- # Source Routed
- $SYSCTL -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null
- done
- echo "# Initialization..."
- ####################
- # Initialization
- ####################
- $SERVICE_IPTABLES stop
- $IPTABLES -F
- $IPTABLES -X
- $IPTABLES -Z
- echo "# Default Rule is Drop..."
- ####################
- # Default Rule
- ####################
- $IPTABLES -P INPUT DROP
- $IPTABLES -P OUTPUT DROP
- $IPTABLES -P FORWARD DROP
- ####################
- # Loopback
- ####################
- $IPTABLES -A INPUT -i lo -j ACCEPT
- $IPTABLES -A OUTPUT -o lo -j ACCEPT
- ####################
- # Session Established
- ####################
- $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
- $IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
- $IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
- echo "# Security Setting..."
- ####################
- # Security
- ####################
- # Not Spoofing
- $IPTABLES -A INPUT -s 0.0.0.0 -d 224.0.0.0/4 -j ACCEPT
- $IPTABLES -A INPUT -s 0.0.0.0 -d 255.255.255.255 -j ACCEPT
- # Spoofing
- $IPTABLES -N spoofing
- $IPTABLES -A spoofing -j LOG --log-prefix "iptables-Block Spoofing: "
- $IPTABLES -A spoofing -j DROP
- $IPTABLES -A INPUT -i eth0 -s 0.0.0.0/8 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 10.0.0.0/8 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 127.0.0.0/8 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 172.16.0.0/12 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 192.0.2.0/24 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 192.168.0.0/16 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 224.0.0.0/4 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 240.0.0.0/5 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 248.0.0.0/5 -j spoofing
- $IPTABLES -A INPUT -i eth0 -s 255.255.255.255/32 -j spoofing
- # Ping flooding ( Ping of Death )
- $IPTABLES -N ping-flooding
- $IPTABLES -A ping-flooding -m limit --limit $PINGLIMIT --limit-burst $PINGBURST -j ACCEPT
- $IPTABLES -A ping-flooding -j LOG --log-prefix "iptables-Block Ping flood: "
- $IPTABLES -A ping-flooding -j DROP
- $IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ping-flooding
- $IPTABLES -A OUTPUT -p icmp --icmp-type echo-request -j ping-flooding
- # Port scan
- $IPTABLES -N port-scan
- $IPTABLES -A port-scan -m limit --limit 1/s --limit-burst 4 -j RETURN
- $IPTABLES -A port-scan -j LOG --log-prefix "iptables-Block Port Scan: "
- $IPTABLES -A port-scan -j DROP
- $IPTABLES -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j port-scan
- $IPTABLES -A OUTPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j port-scan
- # SYN flood
- $IPTABLES -N syn-flood
- $IPTABLES -A syn-flood -p tcp -m limit --limit $SYNLIMIT --limit-burst $SYNBURST -j RETURN
- $IPTABLES -A syn-flood -j LOG --log-prefix "iptables-Block SYN Flood: "
- $IPTABLES -A syn-flood -j DROP
- $IPTABLES -A INPUT -p tcp --syn -j syn-flood
- $IPTABLES -A OUTPUT -p tcp --syn -j syn-flood
- # fragment
- $IPTABLES -N fragment
- $IPTABLES -A fragment -j LOG --log-prefix "iptables-Block Fragment: "
- $IPTABLES -A fragment -j DROP
- $IPTABLES -A INPUT -f -j fragment
- # Port 113 (IDENT)
- $IPTABLES -N ident
- $IPTABLES -A ident -f -j LOG --log-prefix "iptables-Block IDENT: "
- $IPTABLES -A ident -f -j REJECT
- $IPTABLES -A INPUT -p tcp --dport 113 -j ident
- echo "# VPN Setting..."
- ####################
- # VPN Setting
- ####################
- # L2TP (from Internet)
- $IPTABLES -A INPUT -i eth0 -p udp -m multiport --dport 1701,500,4500 -j ACCEPT
- $IPTABLES -A OUTPUT -o eth0 -p udp -m multiport --sport 1701,500,4500 -j ACCEPT
- $IPTABLES -A INPUT -i eth0 -p esp -j ACCEPT
- # NetBIOS Reject (from Internet)
- $IPTABLES -A FORWARD -o eth0 -p tcp -m multiport --dport 135,137,138,139,445 -j DROP
- $IPTABLES -A FORWARD -o eth0 -p udp -m multiport --dport 135,137,138,139,445 -j DROP
- # NetBIOS Allow (in VPN)
- $IPTABLES -A OUTPUT -o ppp+ -p tcp -m multiport --dport 135,137,138,139,445 -j ACCEPT
- $IPTABLES -A OUTPUT -o ppp+ -p udp -m multiport --dport 135,137,138,139,445 -j ACCEPT
- # SNAT (MASQUERADE, from VPN to Internet)
- $IPTABLES -t nat -A POSTROUTING -o eth0 -s $VPN_RANGE -j MASQUERADE
- # DNAT (DMZ, from Internet to Local Server in VPN )
- $IPTABLES -t nat -A PREROUTING -i eth0 -p tcp --dport $DMZ_PORT -j DNAT --to-destination $DMZ_IP:$DMZ_PORT
- # FORWARD (MASQUERADE)
- $IPTABLES -A FORWARD -i ppp+ -o eth0 -j ACCEPT
- # FORWARD (allow Request from VPN to VPN)
- $IPTABLES -A FORWARD -i ppp+ -o ppp+ -j ACCEPT
- # FORWARD (DMZ)
- $IPTABLES -A FORWARD -i eth0 -o ppp+ -p tcp --dport $DMZ_PORT -j ACCEPT
- # Allow Request from VPN (ex. samba, ssh, etc...)
- $IPTABLES -A INPUT -i ppp+ -j ACCEPT
- echo "# Allow Port And Client Setting..."
- ####################
- # Allow Port And Permit Client
- ####################
- # Traceroute Command
- $IPTABLES -A OUTPUT -p udp --dport 33434:33523 -m state --state NEW -j ACCEPT
- # SSH Server
- for ip in `awk '{print $1;}' $ALLOW_SSH_FILE`
- do
- echo "## allow ssh: $ip"
- $IPTABLES -A INPUT -p tcp -s $ip --dport 22 -j ACCEPT
- done
- $IPTABLES -A OUTPUT -p tcp --sport 22 -j ACCEPT
- # SSH Client
- $IPTABLES -A OUTPUT -p tcp --dport 22 -j ACCEPT
- # WEB Client
- $IPTABLES -A OUTPUT -p tcp --dport 80 -j ACCEPT
- $IPTABLES -A OUTPUT -p tcp --dport 443 -j ACCEPT
- # FTP Client
- $IPTABLES -A OUTPUT -p tcp --dport 20:21 -j ACCEPT
- # NTP Server
- $IPTABLES -A INPUT -p udp --dport 123 -j ACCEPT
- $IPTABLES -A OUTPUT -p udp --dport 123 -j ACCEPT
- # DNS Resolve
- $IPTABLES -A OUTPUT -p udp --dport 53 -j ACCEPT
- # WHOIS Client
- $IPTABLES -A OUTPUT -p tcp --dport 43 -j ACCEPT
- $IPTABLES -A INPUT -p tcp --sport 43 -j ACCEPT
- echo "# INPUT / OUTPUT / FORWARD LOG..."
- ####################
- # Debug
- ####################
- $IPTABLES -A INPUT -j LOG --log-prefix "iptables-Debug INPUT Drop: "
- $IPTABLES -A OUTPUT -j LOG --log-prefix "iptables-Debug OUTPUT Drop: "
- $IPTABLES -A FORWARD -j LOG --log-prefix "iptables-Debug FORWARD Drop: "
- echo "# Rules Save and iptables Restart..."
- ####################
- # Save & Restart
- ####################
- $SERVICE_IPTABLES save
- $SERVICE_IPTABLES start
※ 223 ~ 225 行目はデバッグ用なので、必要に応じてコメントアウトすること。
echo でメッセージを表示させることで、エラーが出たとしても特定しやすくなる。まあ「# sh -x ipfilter」でデバッグすればいいことだが……
そんで Widowos7 の VPN クライアントから、前ページで作成した「hogeVPN」をダブルクリックして接続できれば OK。
ping 192.168.100.1 への反応がなかったり、そもそも VPN 接続が確立できない場合は、エラー内容に沿った対応が必要になる。
VPN 接続時のエラー (ざっくり)
私がはまったところだと次のような感じ。
ネゴシエーションのエラー
- 設定ファイルのミス。
最悪はカーネルが L2TP に対応していないとかだが、 /var/log/messages とかでエラー内容をググってコツコツつぶしていくしかない。
単純なところでは事前共有鍵の入力ミスとか、 VPN 接続の [セキュリティ] タブの設定ミス。 - VPN クライアント側で、 SoftEther などの余計なドライバがあると接続できない事象があった。
[プログラムと機能] で SoftEther をアンインストールしてから、 [デバイスマネージャ] – [ネットワーク アダプタ] からインストールされた VPN のネットワークアダプタを削除、再起動したら接続できるようになった。
なお [コンパネ] – [ネットワーク接続] からは上記のアダプタは削除できない。 - もう一つ可能性が高いものは、サーバの設定ファイルがかなり怪しい。
/etc/ipsec.d/l2tp-psk.conf を見直してみるとか、環境に合わせて別の設定にしてみるとか。と言っても具体的なアイディアはないわけだが。
パスワードのエラー
- 設定ファイルのミス。
- もしくは、パスワードに事前共有鍵を入れていたり、単なる入力間違い。
接続後に 192.168.100.1 に ping 飛ばない
- iptables の FOWARD あたりがあやしい。
とりあえず iptables のデフォルトルールを ACCEPT にしてみるとか?
もちろん、それで通信できたからといってそのままの設定で使わず、必ず原因を究明すること。でないとセキュリティもへったくれもない。
おまけ VPN サービス起動スクリプト
使い方の一例
- # vpnctl fullrestart
VPN サービスの再起動 & ipfilter の実行 - # vpnctl log
/var/log/messages のリアルタイムログ (tailf コマンド)
スクリプト
# vi /root/bin/vpnctl ------------------------------ (下のやつ) ------------------------------ # chmod 700 /root/bin/vpnctl # vpnctl fullrestart (とりあえず再起動)
- #!/bin/sh
- SERVICE='/sbin/service'
- IPFILTER='/root/bin/ipfilter'
- TAILF='/usr/bin/tailf'
- ERROR=0
- case "$1" in
- start)
- $SERVICE xl2tpd start
- $SERVICE ipsec start
- ;;
- fullstart)
- $0 start
- $IPFILTER
- ;;
- stop)
- $SERVICE xl2tpd stop
- $SERVICE ipsec stop
- ;;
- restart)
- $0 stop
- $0 start
- exit $?
- ;;
- fullrestart)
- $0 stop
- $0 fullstart
- exit $?
- ;;
- log)
- echo -e "\n\n############################## Stop the Log-View : press Ctrl-C key\n"
- $TAILF /var/log/messages
- exit $?
- ;;
- *)
- echo "Usage: vpnctl (start|stop|restart|fullstart|fullrestart|log)"
- exit 1
- esac
- exit $ERROR
とりあえずこんなカンジだろうか。
次はおまけの samba インストール設定。