Raspberry Pi に VPN を導入してからしばらく経ってますが、未だに Arch Linux をクライアントにして運用できない状態だったのでサーバー側デーモンを変更するついでに挑戦し直してみました。
今回はサーバー、クライアントともに libreswan を使用して、サーバー側を NAT の中に設置しています。
VPS など、非 NAT 環境へ配置する場合と若干設定が異なるため、以下の設定を流用する際はご注意ください
サーバー側の設定
$ yaourt -S libreswan xl2tpd
conn L2TP-NAT rightsubnet=0.0.0.0/0 also=L2TP-noNAT conn L2TP-noNAT type=transport authby=secret auto=add pfs=no rekey=no keyingtries=3 ikelifetime=8h lifetime=1h left=%defaultroute leftprotoport=17/1701 right=%any rightprotoport=17/%any # for iOS dpddelay=30 dpdtimeout=120 dpdaction=clear
IPsec の事前共有鍵を記述します。
: PSK "your preshared-key"
# chmod 600 /etc/ipsec.d/default.secrets
xl2tpd の設定を記述します。
local ip にはサーバーの IP アドレスを、ip range には VPN クライアントへの IP アドレス割当範囲をそれぞれ設定しておく。
[global] auth file = /etc/ppp/chap-secrets [lns default] ip range = 192.168.0.102-192.168.0.149 local ip = 192.168.0.101 require authentication = yes require chap = yes refuse pap = yes length bit = yes ppp debug = yes pppoptfile = /etc/ppp/options.l2tpd name = LinuxVPN
pppd 起動時に渡されるオプションを記述します。
mtu、mru、ms-dns は環境に合わせ適宜修正してください。
refuse-pap refuse-chap refuse-mschap require-mschap-v2 auth nodefaultroute proxyarp idle 1800 mtu 1420 mru 1420 ms-dns 192.168.0.1
VPN のアカウント情報を記述する。
ここで設定した値が接続ユーザID、パスワードになります。
# Secrets for authentication using CHAP # client server secret IP addresses hoge * hogefuga *
各デーモンを起動させる。
# systemctl enable ipsec xl2tpd # systemctl start ipsec xl2tpd
ファイアウォールルールを設定する
# iptables -A FORWARD -i ppp+ -j ACCEPT # iptables -A FORWARD -o ppp+ -j ACCEPT # iptables -A INPUT -p udp --dport 500 -j ACCEPT # iptables -A INPUT -p udp --dport 1701 -j ACCEPT # iptables -A INPUT -p udp --dport 4500 -j ACCEPT
クライアント側の設定
$ yaourt -S libreswan xl2tpd
right にはサーバーのグローバルアドレスを、rightid にはサーバーのローカルアドレスを記述しておきます。
conn L2TP-PSK type=transport authby=secret auto=add keyingtries=3 ikelifetime=8h keylife=1h left=%defaultroute leftprotoport=17/1701 right=xxx.xxx.yyy.yyy rightid=192.168.0.101 rightprotoport=17/1701
%any xxx.xxx.yyy.yyy : PSK "your preshared-key"
[lac vpn-connection] lns = xxx.xxx.yyy.yyy length bit = yes ppp debug = yes pppoptfile = /etc/ppp/options.l2tpd
例によって pppd に渡すオプションを記述します。
ここで、require-mschap-v2 は noauth よりも上に記述してください。(詳しくは後に説明します)
なお、サンプル*1の設定ファイルなどに記述されている refuse-eap に関しては、Windows Server との相互運用性を保つためのものであるため今回は省いています。
require-mschap-v2 noauth defaultroute usepeerdns name hoge password hogefuga
接続に必要なデーモンを起動しておく。
毎度のことながら、認証情報を記述したファイルのパーミッション修正を忘れないようにしておきましょう。
# chmod 600 /etc/ipsec.d/default.secrets # chmod 600 /etc/ppp/options.l2tpd # mkdir /var/run/xl2tpd # touch /var/run/xl2tpd/l2tp-control # systemctl enable ipsec xl2tpd # systemctl start ipsec xl2tpd
接続する
# ipsec auto --up L2TP-PSK # xl2tpd-control connect vpn-connection
pppd[10138]: Plugin pppol2tp.so loaded. pppd[10138]: pppd 2.4.7 started by root, uid 0 pppd[10138]: Using interface ppp0 pppd[10138]: Connect: ppp0 <--> pppd[10138]: CHAP authentication succeeded: Access granted pppd[10138]: CHAP authentication succeeded pppd[10138]: local IP address 192.168.0.102 pppd[10138]: remote IP address 192.168.0.101 pppd[10138]: primary DNS address 192.168.0.1 pppd[10138]: secondary DNS address 192.168.0.1
こんな感じのログが出て ppp0 が生えますが、このままだとパケットが流れないので経路を追加してあげます。
# ip route add <server global ip> via <local gateway ip> dev <interface name> # ip route add default via <ppp0 interface ip>
切断する
接続の逆を行えばOK
# ip route del default via <ppp0 interface ip> # ip route del <server global ip> via <local gateway ip> dev <interface name> # xl2tpd-control disconnect vpn-connection # ipsec auto --down L2TP-PSK
ちなみに、/etc/ppp/ip-up.d にスクリプトを置くと ppp0 が上がった時点で、/etc/ppp/ip-down.d に置くと ppp0 が落ちた時点で実行されるので経路を自動追加・削除するスクリプトを書いておくと便利。
注意点
・pppoptfile に crtscts 及び lock を書くと unrecognized option になる
ArchWiki や Libreswan Wiki などの設定サンプルに記述されているこのオプションですが、最近の pppd の変更により削除された(?)のか設定するとエラーになるので注意。
・pppoptfile の noauth の下に require-mschap-v2 を書くと接続エラーになる
なぜか noauth がスルーされて認証を要求してくるので必ず上に書くようにする。
これに気づかずドツボにはまって半日潰しました…。
xl2tpd[7966]: /usr/sbin/pppd: The remote system is required to authenticate itself xl2tpd[7966]: /usr/sbin/pppd: but I couldn't find any suitable secret (password) for it to use to do so.
・Android 6.x 系及び 7.x 系から接続できない
どうやら、Android の L2TP/IPsec における SHA2 の実装がドラフト版の古いものであることが原因のようです。
Issue も上がってます。*2
Libreswan の Wiki*3 によるとサーバー側の /etc/ipsec.d/l2tp-psk.conf に sha2-truncbug=yes を追加すればいいみたいですが、RFC に則った実装をしているクライアントが全部死ぬっぽいので、回避策として ike=、phase2alg= オプションを指定する必要があるようです。*4
ike=3des-sha1,aes-sha1,aes256-sha2_256,aes256-sha2_512 phase2alg=3des-sha1,aes-sha1,aes256-sha2_256,aes256-sha2_512 sha2-truncbug=yes
ちなみに、自分はこのオプションを追記してもなお Windows と Android 5.x 系から接続出来なかったので捨てました。
・Windows から接続できない
過去記事*5を参照。
*1 – VPN server for remote clients using IKEv1 with L2TP – Swan
*2 – Issue 196939 – android – L2TP/IPsec VPN does not work in Android 6.0.1 – Android Open Source Project – Issue Tracker – Google Project Hosting
*3 – FAQ – Swan
*4 – Android 6 MarshmallowでL2TP/IPsec VPNが動作しない問題を解決する(xl2tpd+openswan) | Web Net Force
*5 – RPi(Arch)でL2TP/IPsecなVPNを構築する – Gomasy's blog