RPi(Arch)でL2TP/IPsecなVPNを構築する

今回は、サードパーティアプリケーションが不要で、かつ対応 OS の多い L2TP/IPsec を使用した VPN サーバーを構築してみました。
以前から検討していたんだけど、


なわけで放り投げていましたが、やっと修正されたカーネルが降ってきたみたいなので試してみます。

必要なパッケージの導入

  • xl2tpd
  • openswan

構築にあたって以下のパッケージのインストールが必要になります。
後者は AUR にありますが、Arch Linux ARM の場合バイナリパッケージが提供されているので、yaourt を使用する必要はないようです(ありがたい)

$ sudo pacman -S xl2tpd openswan
$ sudo systemctl enable xl2tpd
$ sudo systemctl enable openswan

Openswan の設定

/etc/ipsec.conf

…
	# which IPsec stack to use. auto will try netkey, then klips then mast
	protostack=netkey // ← 37行目: autoをnetkeyに
	# Use this to log to a file, or disable logging on embedded systems (like openwrt)
	#plutostderrlog=/dev/null

# Add connections here
include /etc/ipsec.d/*.conf // ← 42行目: 追記
…

/etc/ipsec.d/l2tp-psk.conf

$ sudo cp /etc/ipsec.d/samples/l2tp-psk.conf /etc/ipsec.d
conn L2TP-PSK-NAT
	rightsubnet=0.0.0.0/0 // ← 2行目: vhost:%privを0.0.0.0/0へ変更
	also=L2TP-PSK-noNAT

…

	# l2tp-over-ipsec is transport mode
	type=transport
	#
	left=192.168.0.101 // ← 33行目: サーバーのIPアドレス(NAT配下はプライベートアドレス)を記入
	#
	# For updated Windows 2000/XP clients,
	# to support old clients as well, use leftprotoport=17/%any
	leftprotoport=17/1701
	#
	# The remote user.
	#
	right=%any
	# Using the magic port of "%any" means "any one single port". This is
	# a work around required for Apple OSX clients that use a randomly
	# high port.
	rightprotoport=17/%any

// ↓ ここらへん全部コメントアウト
# Normally, KLIPS drops all plaintext traffic from IP's it has a crypted
# connection with. With L2TP clients behind NAT, that's not really what
# you want. The connection below allows both l2tp/ipsec and plaintext
# connections from behind the same NAT router. 
# The l2tpd use a leftprotoport, so they are more specific and will be used
# first. Then, packets for the host on different ports and protocols (eg ssh)
# will match this passthrough conn.
# conn passthrough-for-non-l2tp
#         type=passthrough
#         left=YourServerIP
#         leftnexthop=YourGwIP
#         right=0.0.0.0
#         rightsubnet=0.0.0.0/0
#         auto=route

事前共有鍵

# echo ": PSK \"hogehoge\"" >> /etc/ipsec.secrets

xl2tpd の設定

/etc/xl2tpd/xl2tpd.conf

[global]
auth file = /etc/ppp/chap-secrets

[lns default]
ip range = 192.168.0.102-192.168.0.199 // ← IPアドレスの割り当て範囲
local ip = 192.168.0.101 // ← サーバーのIPアドレス
length bit = yes
require authentication = yes
require chap = yes
refuse pap = yes
ppp debug = yes
pppoptfile = /etc/ppp/options.l2tpd
name = gomasy.jp // ← サーバーのホスト名など

/etc/ppp/options.l2tpd

ipcp-accept-local
ipcp-accept-remote

auth
crtscts
debug
idle 1800
lock
mtu 1440 // 回線に合わせて変更
mru 1440 // 回線に合わせて変更
nodefaultroute
persist
proxyarp

refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2

logfile /var/log/xl2tpd.log

※ おおよその MTU 値はここで計測できます。

/etc/ppp/chap-secrets

# Secrets for authentication using CHAP
# client	server	secret			IP addresses
user		*	password		*

ユーザー認証時に使う ID とパスワードを記入。

動作確認

$ sudo systemctl start openswan
$ sudo systemctl start xl2tpd

でデーモンを起動。
とりあえず手持ちの Android 端末では接続できた。

Windows で接続出来ない場合

Windows では、次のようなエラーが出て接続出来ないことがあります。
これは、Windows の NAT トラバーサル機能がデフォルトでは有効になっていないためです。

有効にするには、レジストリの \\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgent に、AssumeUDPEncapsulationContextOnSendRule という名前の DWORD 値を作成します。
ここで設定できる値は次のようになります。

  • 0: NAT-T 無効(デフォルト)
  • 1: NAT-T 有効、サーバー・クライアントのうち片方が NAT 配下。
  • 2: NAT-T 有効、サーバー・クライアントの双方が NAT 配下。

僕の環境では双方が NAT 配下であるため、”2″ を設定して再起動したところ、無事接続できるようになりました。