■環境
まず、環境です。
●拠点A
Buffalo WZR-HP-AG300H
DD-WRT v24-sp2 (12/14/11) std - build 18007
VPNサーバ側
LAN : 192.168.1.0/24
WAN : DDNSでa.example.com
●拠点B
Buffalo WZR-G300N
DD-WRT v24-sp2 (08/07/10) vpn - build 14896
VPNクライアント側
LAN : 192.168.2.0/24
WAN : DDNSでb.example.com
この時点で「バージョンとか揃えろよwww」と言われそうですが、
・ハードウェアは今あるものを使うので揃えられない。
・拠点A側は14896以降のビルド済みバイナリが探しても出てこない。
・拠点B側は、このバージョンが安定している、と2chで見たから仕方ない。(何が
というわけで、これで強行しました。
確かA側はekoビルドだったはずです。
■証明書
さて、OpenVPNの設定ですが、その前にまずは証明書を作ります。
自分は適当なWindowsマシンに何故かOpenVPNクライアントが入っていたので、ここで作成しました。
別にLinuxで作っても良いと思います。dd-wrt上で作れるのかはわかりません。
このあたりを参考にしつつ。
cd "C:\Program Files\OpenVPN\easy-rsa"
init-config
vars.batを編集しつつ・・・
vars
clean-all
証明書を作ります。
build-ca
build-key-server server
build-key client
build-dh
C:\Program Files\OpenVPN\easy-rsa\keys
に証明書一式が作成されましたー。いぇい。
■OpenVPNの設定
A側のGUIを開きます。
Services → VPNに設定画面があります。
OpenVPN Server/Daemonをこんな感じに設定しました。
OpenVPN Server : Enable
Start Type : WAN Up
Config via : GUI
Server mode : Router (TUN)
Network : 192.168.99.0
Netmask : 255.255.255.0
Port : 1194
Tunnel Protocol : UDP
Encryption Cipher : Blowfish CBC
Hash Algorithm : SHA1
Advanced Options : Enable
LZO Compression : Disable
Redirect default Gateway : Disable
Allow Client to Client : Enable
Allow duplicate cn : Disable
TUN MTU Setting : 1280
TLS Cipher : Disable
Public Server Cert : さっき作成したファイルの中身を貼り付け※
CA Cert : さっき作成したファイルの中身を貼り付け※
Private Server Key : さっき作成したファイルの中身を貼り付け※
DH PEM : さっき作成したファイルの中身を貼り付け※
Additional Config : push "route 192.168.1.0 255.255.255.0"
※BEGINからENDまで。
書いていない項目は、空白値のままです。
B側のGUIを開きます。
OpenVPN Client
Start OpenVPN Client : Enable
Server IP/Name : a.example.com
Port : 1194
TUN MTU Setting : 1280
TUN MTU Extra : 32
TCP MSS : 1230
Use LZO Compression : Disable
Tunnel Protocol : UDP
Tunnel Device : TUN
nsCertType : on
CA Cert : さっき作成したファイルの中身を貼り付け※
Public Server Cert : さっき作成したファイルの中身を貼り付け※
Private Server Key : さっき作成したファイルの中身を貼り付け※
これでOpenVPNが繋がったはずです。
ログは、A側は/var/log/openvpnに、B側は/var/log/messagesに書かれます。
■ルーティング設定
A側のGUIの
Setup → Advanced Routing → Static Routing
で、以下のものを追加。
Route Name : Branch-B
Destination LAN NET : 192.168.2.0
Subnet Mask : 255.255.255.0
Gateway : 192.168.99.2
Interface : ANY
B側は不要です。
というのは、A側の設定で
push "route 192.168.1.0 255.255.255.0"
を入れているため、OpenVPN接続確立時に、A側からB側にPUSH_REPLYでルーティング設定が送り込まれるのです。
■終わり・・・じゃない、だと!?
さて、ここまでの設定でVPNの接続は確立します。
しかし、いくつか問題があるので、1つずつ解決していきます。
■ログに変な警告が出ている。
cnXX/xx.xx.xx.xx:xx WARNING: 'version' is used inconsistently, local='version V4', remote='version V0 UNDEF'
cnXX/xx.xx.xx.xx:xx WARNING: 'dev-type' is present in local config but missing in remote config, local='dev-type tun'
cnXX/xx.xx.xx.xx:xx WARNING: 'link-mtu' is present in local config but missing in remote config, local='link-mtu 1321'
cnXX/xx.xx.xx.xx:xx WARNING: 'tun-mtu' is present in local config but missing in remote config, local='tun-mtu 1280'
cnXX/xx.xx.xx.xx:xx NOTE: --mute triggered...
ちゃんとclient側にも設定してあるのに、何故か出てしまう。
原因は謎。
よくわからないので、無視します。(ぉぃ
■VPNトンネル経由のパケットが何一つ通過しないwww
意味ナスww
原因は、A側の仕様の不整合のようです。どう見てもバグですが。
先ほどAのGUIの設定では
LZO Compression : Disable
を指定しましたが、こうすると、/tmp/openvpn/openvpn.confには、以下の行が出現します。
comp-lzo no
これがconfファイルの仕様として正しいのかどうなのかまでは調べていませんが、
dd-wrtのopenvpnserverデーモンは、この行を正しく解釈できず、comp-lzoという行がconfに出現すると、LZO圧縮を有効にしてしまうようなのです。
なので、結果的にLZO Compression : Enableにしたときの挙動になってしまいます。
そのため、VPN通信は確立するけれど、VPNトンネルの中のパケットは何一つ通過しない、という現象になります。
(Bは圧縮せずに送信しているのに、Aは圧縮されたパケットが来たと思っているから展開しようとして失敗する。)
この現象は、フォーラムでも既知のようでした。
OpenVPN client: possible bug回避の方法はいくつかありそうですが、
自分はcomp-lzo noという行を削除してopenvpnserverを再起動するという荒業をやってみました。
GUIのAdministration → Commandsで
fix_openvpn(){
cd /tmp/openvpn/
grep "comp-lzo no" openvpn.conf > /dev/null
if [ $? -ne 0 ]; then return; fi
killall openvpnserver
sleep 10
cat openvpn.conf | grep -v "comp-lzo no" > openvpn.conf.tmp
mv openvpn.conf.tmp openvpn.conf
cd -
/tmp/openvpnserver --config /tmp/openvpn/openvpn.conf --up /tmp/openvpn/route-up.sh --down /tmp/openvpn/route-down.sh --daemon
}
case "$1" in
fix_openvpn)
$1 ;;
esac
を「Save Custom Script」して、
自分はGUIのAdministration → Management → Cronに
19 * * * * root /bin/sh /tmp/custom.sh fix_openvpn
を設定しました。
ここまで書いてから気がついたのですが、
こんなに面倒な方法を使って回避しなくても、A側は
Config via : GUI
を
Config via : Config File
にすれば良かっただけなのでは・・・。
では、気を取り直して、A側の設定をこうします。
OpenVPN Server : Enable
Start Type : WAN Up
Config via : Config File
CA Cert : さっき作成したファイルの中身を貼り付け※
Public Server Cert : さっき作成したファイルの中身を貼り付け※
Private Server Key : さっき作成したファイルの中身を貼り付け※
DH PEM : さっき作成したファイルの中身を貼り付け※
Additional Config : (以下すべて)
keepalive 10 120
verb 4
mute 5
log-append /var/log/openvpn
tls-server
management 127.0.0.1 5002
management-log-cache 50
mtu-disc yes
topology subnet
client-config-dir /tmp/openvpn/ccd
script-security 2
port 1195
proto udp
cipher bf-cbc
auth sha1
ifconfig-pool-persist /tmp/openvpn/ip-pool 86400
client-to-client
fast-io
tun-mtu 1280
server 192.168.99.0 255.255.255.0
dev tun0
push "route 192.168.1.0 255.255.255.0"
comp-lzo no以外の行はすべて、GUIで設定したときと同じ設定内容が現れるようにしました。
■BからAへのアクセスはNATがかかってしまう。
B側からA側へアクセスしたときのsource IPアドレスは、すべて192.168.99.2に置き換えられてしまいます。
また、A側からB側の端末へアクセスを行うことはできないです。
これでは微妙です。
dd-wrtでは、接続確立時に /tmp/openvpncl/route-up.shが、接続終了時に/tmp/openvpncl/route-down.shが実行されます。
クライアント側のroute-up.shは、iptablesのMASQUERADEを入れているのです。
iptables -A POSTROUTING -t nat -o tun0 -j MASQUERADE
dd-wrtでは、このスクリプトを編集したり、GUIからroute-upスクリプトのパスを指定したりすることができません。
Startupスクリプトとかで無理やり上書きすることもできるのですが、openvpnだけが再起動してしまうと、それがまた元に戻されてしまいます。
うまくいかないこんな世の中です。
そのため、Firewallの設定を追加することで回避します。
GUIのAdministration → Commandsで
iptables -I POSTROUTING -t nat -o tun0 -j RETURN
iptables -I INPUT -i tun0 -j ACCEPT
iptables -I FORWARD -o tun0 -j ACCEPT
iptables -I FORWARD -i tun0 -j ACCEPT
を「Save Firewall」します。
単純でしょ。
1行目で、route-up.shで挿入されてしまうMASQUERADEを回避します。
2~4行目で自身宛とルーティングパケットを全許可します。
■BからAへのアクセスが拒否されてしまう。
上の設定を入れても、B側の端末からA側宛のパケットが拒否されてしまう。
以下のようなログが出るのです。
us=XX cnXX/xx.xx.xx.xx:xx MULTI: bad source address from client [192.168.2.X], packet dropped
A側は、BがNATしてくることを前提にしているっぽくて、発信元アドレスがA側が認識していないレンジにあるため、拒否しているのです。
そのため、OpenVPNのCCDにirouteを追加します。
echo "iroute 192.168.2.0 255.255.255.0" > /tmp/openvpn/ccd/XXXXXX
ちなみに、XXXXXXは、B側の証明書を作成するときに使用したCN(Common Name)を使います。
まさか、changemeのまま、なんてことは、ない、です、よ、ね・・・?
■終わり!
さて、以上でA-B間が自由にアクセスできるVPNが構築できました。
なお、dd-wrtが乗る程度のHardwareですから、CPUも非力ですし、それほどスループットが出る気はしません。
速度は測ってはいないので、そのうち気が向いたら計測してみたいです。
PPTPよりはやいと良いな。
PR