FreeBSD on Raspberry Pi 3でVPN(L2TP+IPsec)サーバーを構築する

FreeBSD on Raspberry Pi 3(以下ラズパイ3)でL2TP+IPsecのVPNサーバーを構築したので、ここに覚書を記したいと思います。

# 注意点

現在接続を確認しているクライアントOSは

- iOS/iPadOS(13)
- macOS(Catalina)
- Android(8.0)
- ChromeOS

です。
(Windowsはモバイル環境がなく、ローカル接続のみ確認していてインターネット側からの接続・通信は未確認)

# きっかけ

すでにNUC(Celeronの安いの)でracoon+mpd5(OSはFreeBSD 9.x)によるVPNを構築していましたが、iOS/macOS以外のクライアント(Android等)で接続できない問題を抱えていました。
今回、ラズパイ3を入手したことと、VPNサーバーのさらなる省電力化およびクライアントOSの選択肢を広げるため、ラズパイ上にVPNサーバーを構築することにしました。
Racoon→StrongSwanに変えた理由ですが、Linuxでも使われていて情報量が多いかなと思ったからです。

# 今回の目標

* 事前共有鍵(PSK)方式でL2TP/IPsecのVPNが張れ、内部のネットワークが参照できること

# 前提環境

## ハードウェア

* ルーター(静的NAPT設定ができ、かつVPNパススルーをサポートしているもの)
* Raspberry Pi 3 Model B+microSDカード
* SDに書き込む・接続テスト用PC
* L2TP/IPsec接続をサポートしているスマートフォン・タブレット・ノートPC

## ソフトウェア

* FreeBSD 12.1
* StrongSwan
* mpd5

## その他前提

* グローバルIPを直に割り当てられたインターネット接続があること
* DDNSが設定済みで、FQDNから上記のグローバルIPが引けること
* ルータ内はプライベートIP
* ルータ自身のプライベートIPは192.168.x.1
* ラズパイ3のIPは192.168.x.2
* VPNサーバで割り当てるIPアドレスの範囲は192.168.x.yから192.168.x.zまで

# 手順

## FreeBSDのSDカードイメージをダウンロード

ここから”RPI3”のイメージをダウンロードします。
https://www.freebsd.org/ja/where.html

## microSDカードにイメージを書き込む

macOS/UNIX系OSの方はここら辺をご参考に。
https://qiita.com/s_mitu/items/ecfcab3826fee2c873d9
Windows・ChromeOSな方は適当にググってください。

## microSDをラズパイ3に差し、OS起動

特に手順が間違っていなければ、OSが起動すると思います。起動したら、一般ユーザの作成・IPアドレス・sshの設定などをします。ここでは手順割愛。

## StrongSwan・mpd5をインストール

今回はpkgを利用してインストールします。

```
pkg install strongswan
pkg install mpd5
```

## StrongSwanの設定

参考文献を参照して作って、そこからいろいろ試行錯誤しましたが、最終的には以下の形になりました。

```/usr/local/bin/ipsec.conf
config setup
    ## 各機能に関するデバッグレベルを2に設定(デフォルトは1)
    charondebug = "dmn 4, mgr 4, ike 4, cfg 4, knl 4, net 4, esp 4"

conn %default
    ike=aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024!
    esp=aes256-sha256,aes256-sha1,3des-sha1!
 
conn L2TP-PSK-NAT
    type=transport
    authby=secret
    leftprotoport=udp/l2tp
    left=192.168.x.2
    leftsubnet=0.0.0.0/0
    leftauth=psk
    right=%any
    rightsubnet=0.0.0.0/0
    rightprotoport=udp/%any
    rightauth=psk
    auto=add
```

setupのログレベルの設定はお好みで。
conn %defaultの暗号化方式の指定は必須です。これがないとつながるものがつながりません。
leftauth, rightauth, authbyの指定はPre-shared keyにするためのものです。全部はいらないような気もしますが、とりあえずこれで動いているので。
LeftprotopointはL2TPで使うプロトコル・ポートなので指定が必要です(結局これがないと動かない?)。

```/usr/local/bin/ipsec.secrets
: PSK "事前共有鍵”
```

事前共有鍵は文字列をそのまま指定します。この文字列をできる限り複雑にしておくこととこのファイルのパーミッションは600にしておきましょう(オーナーはroot)。

## mpd5の設定

参考文献を参照して新しく作り直しました。

```/usr/local/etc/mpd5/mpd.conf
startup:
    log +ipcp +ipv6cp +lcp +link +auth +ecp +ccp        
    
default:
    load l2tp_server                                    
    
l2tp_server:
    set ippool add pool_l2tp 192.168.x.y 192.168.x.z    
    
    create bundle template B_l2tp                       
    set iface enable proxy-arp                          
    set iface enable tcpmssfix                          
    set iface group ng                                  
    set iface route default
    set ipcp ranges 192.168.x.2/24 ippool pool_l2tp      
    set ipcp dns 192.168.x.1                          
    set ipcp enable vjcomp                              
    set bundle enable compression                       
    set ccp enable mppc                                 
    set mppc enable e40                                 
    set mppc enable e128                                
    set mppc enable stateless                           
    
    create link template L_l2tp l2tp                    
    set link action bundle B_l2tp                       
    set link mtu 1354                                   
    set link keep-alive 10 60                           
    set link no pap chap eap                            
    set link enable chap-msv2                           
    set link enable chap                                
    set link enable multilink                           
    set link enable acfcomp protocomp                   
    set auth enable system-acct                         
    
    set l2tp self 192.168.x.2                         
    set l2tp enable length                              
    set l2tp disable dataseq                            
    
    set link enable incoming                   
```

```/usr/local/etc/mpd5/mpd.secret
ユーザー名 "パスワード"
```

ユーザー名もできるだけ複雑にしておいた方がいいと思います。
(パスワードは言わずもがな)
そしてこのファイルのパーミッションも600にしておきます(オーナーはroot)。

## rc.confの設定

たいした設定はなく、以下を追記するだけです。

```/etc/rc.conf
strongswan_enable=“YES”
mpd5_enable=“YES”
gateway_enable=“YES”
```

## サービス起動

```
service strongswan start
service mpd5 start
```

## クライアントから接続してみる(内部)

ここまでできたら、まずルータ内部から接続してみましょう。

macOSを例に説明します。

1. 「環境設定」を起動し、「ネットワーク」を開きます。
2. 左下の”+”を押します。
3. インターフェースは”VPN”、VPNタイプは”L2TP over IPSec”を選択、名前は適当に入れて「作成」。
4. 「構成」欄で「構成を追加…」を選び、適当な名前を入れて「作成」。
5. サーバ欄はラズパイ3のIPアドレス、アカウント名はmpd.secretで設定したユーザー名を入れ、「認証設定」を押す。
6. 「パスワード」が選択されていることを確認してmpd.secretで設定したパスワードを入力。
7. 「共有シークレット」が選択されていることを確認してipsec.secretsで設定した事前共有鍵を入力。
8. 「グループ名」は空欄のまま。
9. 「OK」を押して戻る。
10. 「適用」を押して設定完了。
11. あとは「接続」を押して、VPN接続ができて送受信状態が表示されればOK!

## ルーターの設定変更

概要のみ書きます。

* UDPのポート500, 1701, 4500の穴を空け、ラズパイ3に向ける
* ESPも同様
* ルーターに「VPNパススルー有効/無効」の設定があれば「有効」にする。

## クライアントから接続してみる(外部)

先ほどの内部の接続テストの環境を流用します。

1. とにかく自宅セグメントの範囲外に出ます。面倒なのでここではMacを無線LANを使ってモバイルLTEルータに接続します(当然接続先はLTEのネットワークです)。
2. 「環境設定」を起動し、「ネットワーク」を開きます。
3. 左ペインで先ほど作ったVPNを選択します。
4. サーバアドレスをDDNSのFQDNに変更して、「適用」を押します。
5. 「接続」を押して、VPN接続ができることを確認する。
6. 接続したまま、内部ネットワークの機器(ルータなど)が見えることと、そこから自宅外のサイトが見えるかを確認する。

# 感想

構築のきっかけはmacOS/iOSのPPTPサポート終了だったのですが、racoonの時と比べて意外と時間がかからずにできてしまったなー感はあります。どちらかというとこの記事を作ることに時間がかかりすぎた感じです。

# 詰まったところ

## mpd5自身が立ち上がらない

参考文献から設定を持ってきていたのですが、service mpd5 startしてstatusを確認すると立ち上がっていない…
調べた結果、mpd.confに　“#”でコメントを書いているとどうもエラーになるようで、面倒なので以下のコマンドでコメントを削除しました。いや日本語のコメントがNGなのかも。

```
sed -e ’s/#.*$//‘ mpd.conf mpd.conf.new
mv mpd.conf.new mpd.conf
```

## VPN接続するとDNSの名前が引けない

VPN接続しないうちはいいのですが、接続している間、クライアントはもちろんのこと、ラズパイ3自身もDNSの名前が引けなくなる現象が発生しました。
調べると、ルータへのDNSクエリーが正常に動作していないようです。しかし、他の機器からは正常に引けている。VPN接続を切るとDNSが引けるようになる。
原因はmpd.confのset ipcp rangesの第1パラメータをラズパイ3のIPアドレスではなくルータのIPアドレスを指定してしまっていました。やはり参考文献から設定を持ってくる際に勘違いしてしまったようです。

# スループット

ラズパイ3なのであまり期待しない方がいいと思います…

# 参考文献

https://blog.c6h12o6.org/post/freebsd-l2tp-ipsec-ipsec/
https://blog.c6h12o6.org/post/freebsd-l2tp-ipsec-l2tp/

# 終わりに

持っているルーターがNVR500なので、実はこれ単体でL2TP/IPsec通信ができることが以前実験していたときに判明してしまいました。
しかし、NVR500のL2TP/IPsec VPNは

* PSKのみ(証明書は未サポート)
* PSKの事前共有鍵は32文字まで

という制限があるので、将来的に証明書認証に乗り換えるのであればこの記事は役に立つのではないかなーと。自分もその1人ですが。
もう1つ、NVR500のNATはSymmetric NATなので、Full cone NATのルータに買い換えようかな…と思っていることもあります。
(Symmetric NATだといろいろ制約もあるのですよ…例えばスマートフォンを使ったリモートでの動画再生とか…)
あとラズパイ3用のpkgはx64のPoudriere環境を別途構築しているのでそちらから取ってくるようにしています。これについては需要があれば別途記事を上げたいと思います。