«前の日記(2021-02-22) 最新 次の日記(2021-07-01)» 編集

meta's blog - The Power To Serve

筆者について

FreeBSDを通じてOSSにささかな貢献を。HTTPS化したいとは思っているんです…

OSS活動をご支援いただける方を募集しています


2021-03-27 SoftEtherVPNがWireGuardプロトコルに対応したので試してみた

SoftEtherVPNがWireGuardプロトコルに対応したので試してみた

SoftEtherVPNにWireGuardプロトコルのサポートが実装されたので、試してみました。

WireGuard サポートが実装されたのは、GitHub上でコミュニティベースで開発されている開発者版 (Developer Edition)で、softether.orgで配布されている安定版のバージョン4系ではありません。まだ実装されたばかりで各言語への翻訳もなく、とりあえず動くようになったという状態ですが、実際に繋がるのか検証して基本的な設定方法についてまとめました。

今回は 3761876 というコミットで実験しました。

前提知識

SoftEtherVPNの基本的な使い方に習熟している前提で、SoftEtherVPN自体のビルド方法や基本的な設定は大幅に省略しています。一部参考までに記載はしていますが、基本的にはWireGuard以外のプロトコルでSoftEtherVPNサーバーへ接続でき、通信ができる状態にするまでのセットアップは済んでいる前提で記述しています。 また、オリジナルのWireGuard同士でのVPNの構築方法もわかっている前提で書いています。

新たにSoftEtherVPNにWireGuardプロトコルが実装されたので、SoftEtherVPNをサーバーとしてWireGuardプロトコルで接続するための差分として捉えてください。

また、WireGuard自体はピアツーピア型のVPNプロトコルであるため、サーバーとクライアントという概念は存在しませんがここでは便宜上SoftEtherVPN側をサーバー、他方をクライアントと呼んで区別します。

準備

今回の実験で使用したのは Ubuntu 20.04 です。GitHubからソースコードを落としてきて、3761876 というコミットを取り出してきてビルドします。

$ git clone --recursive https://github.com/SoftEtherVPN/SoftEtherVPN.git
$ cd SoftEtherVPN
$ git checkout 3761876254ae00e87e261f89910d093671a95109
# apt install cmake build-essential pkg-config libreadline-dev libncurses-dev zlib1g-dev libssl-dev libsodium-dev 
$ make -C build -j 8
$ sudo build/vpnserver start

vpncmd コマンドで見てみると、以下のWireGuard用の3つのコマンドと、ネットワーク設定のコマンドが追加されています。

$ build/vpncmd /server localhost
(snip)
VPN Server>help
下記の 213 個のコマンドが使用できます:
(snip)
 SetStaticNetwork           - Set Virtual Hub static IPv4 network parameters
 WgkAdd                     - Add a WireGuard key
 WgkDelete                  - Delete a WireGuard key
 WgkEnum                    - List the WireGuard keys

それぞれのコマンドの使用方法については、"コマンド名 ?" と入力するとヘルプが表示されます。

StaticNetwork 設定の確認

WireGuardは(現時点では)他のVPNプロトコルとは異なり、動的なIPアドレス割当をサポートしていないためIPアドレスの割当やルーティング対象のサブネットの定義を手動で行う必要があります。

これを行うため、SetStaticNetworkというコマンドが追加されました。

仮想HUBでOptionsGetコマンドを実行することにより確認することができます。コマンドの結果にDefault gatewayDefault subnetが既に定義されていれば何もする必要はありませんが、以前のバージョンを使用していて設定ファイルをそのまま引き継いだ場合はこのあたりを明示的に設定しなければなりません。

VPN Server/SECURENAT>OptionsGet
OptionsGet コマンド - 仮想 HUB のオプション設定の取得
仮想 HUB "SECURENAT" のオプション設定一覧
項目                               |値
-----------------------------------+--------------
匿名ユーザーに対する仮想 HUB の列挙|許可
最大同時接続セッション数           |無制限
状態                               |オンライン
仮想 HUB の種類                    |スタンドアロン
Default gateway                    |192.168.30.1
Default subnet                     |255.255.255.0
コマンドは正常に終了しました。

WireGuard 公開鍵の作成・登録

WgkAdd コマンドでクライアントの公開鍵をSoftEtherVPNに登録します。間違って秘密鍵を登録しないように注意してください。

鍵ペアはクライアント側で生成します。以下のコマンドで、公開鍵・秘密鍵を一度に生成できます。

$ wg genkey | tee privkey | wg pubkey > pubkey
$ cat pubkey
fsn4HQ3wqXg1Nl4j02HKEX91HdKx5kbFOObzdkS7vSI=

pubkeyというファイルの中身が公開鍵なので、これをSoftEtherVPNに登録します。 WgkAddコマンドを使用します。

公開鍵登録の際には、公開鍵に対応する仮想HUBと仮想HUB上のユーザーを紐づけます。これにより、SoftEtherVPNの認証システムとWireGuardの公開鍵が結び付けられます。

VPN Server/SECURENAT>WgkAdd
WgkAdd コマンド - Add a WireGuard key
Key: fsn4HQ3wqXg1Nl4j02HKEX91HdKx5kbFOObzdkS7vSI=

Hub: SECURENAT

User: meta

コマンドは正常に終了しました。

サーバー公開鍵・事前共通鍵の準備

クライアントが接続できるように、サーバーの公開鍵と事前共通鍵(PresharedKey)をクライアントに渡す必要があります。これはSoftEtherVPNの設定ファイルのvpn_server.configの中に記載されています。ただし、設定ファイルの中には秘密鍵しかないのでこれを公開鍵に変換する必要があります。

declare WireGuard
{
        bool Enabled true
        string PresharedKey aKNQj4QI1jD4ZqTFC2gqOYbAz/M60byKTDBkSZ7hYb4=
        string PrivateKey NE+s0i6fi43mvRM90d+fmvDxtNKEpjnLmL4Tbc5oA2s=
}

事前共通鍵は以下のようにして抽出することもできます。

# grep PresharedKey vpn_server.config | awk '{ print $3 }' 
aKNQj4QI1jD4ZqTFC2gqOYbAz/M60byKTDBkSZ7hYb4=

秘密鍵は以下のように抽出して、それを wg pubkey コマンドに渡すことで公開鍵に変換します。

# grep PrivateKey vpn_server.config | awk '{ print $3 }'  | wg pubkey 
H7MobrirpOVEJWiHQ4lB/gefs+qer+DTCkSTbA7EHV0=

クライアント側の設定

クライアント側の設定ファイルは以下のようになります。前述の通りWireGuardプロトコルはIPアドレスの動的割当機能を持たないため、クライアントに割り当てるIPアドレスは事前に重複しないように決めておく必要があります。

[Interface]
PrivateKey = {クライアント秘密鍵}
Address = {クライアントIPアドレス}

[Peer]
PublicKey = {サーバー公開鍵}
PresharedKey = {事前共通鍵}
AllowedIps = {VPNで使用するサブネット}
Endpoint = {サーバーホスト名}:{サーバーポート}
PersistentKeepAlive = 25

サーバー側のポートはSoftEtherVPNが待ち受けているポートなら何でも構いません。WireGuardプロトコルはUDPを使用するため、UDPポートである必要があります。

サーバー側の着信ポートは、PortsUDPGetコマンドで確認することができます。この場合は、443, 992, 1194, 5555 のいずれでも構いません。ファイアウォールなどで遮断されていないことは確認してください。

VPN Server>PortsUDPGet
PortsUDPGet コマンド - サーバーにおける着信 UDP ポートの一覧を表示します。
項目          |値
--------------+--------------------
UDP ポート一覧|443, 992, 1194, 5555
コマンドは正常に終了しました。

先の情報を具体的に当てはめると、以下のような設定ファイルになります。

[Interface]
PrivateKey = IPKW9k/CEZ64iAzzv9xw9cyM1ROtlHJTYiLFD6BymXc=
Address = 192.168.30.233

[Peer]
PublicKey = H7MobrirpOVEJWiHQ4lB/gefs+qer+DTCkSTbA7EHV0=
PresharedKey = aKNQj4QI1jD4ZqTFC2gqOYbAz/M60byKTDBkSZ7hYb4=
AllowedIps = 192.168.30.0/24
Endpoint = softether-server.example.com:443
PersistentKeepAlive = 25

この設定ファイルを /etc/wireguard/wgse0.conf として保存します。wgse0の部分は何でも構いませんが、WireGuardが使用するインターフェイス名になります。設定ファイルを保存したら、wg-quick up wgse0 コマンドでWireGuardを起動します。

# wg-quick up wgse0

wg show コマンドで現在の状態を確認します。

# wg show 
interface: wgse0
  public key: vbXNEl9sJeQbf2kIHDuoafhNJynwvZvwgnwbwYXKrzM=
  private key: (hidden)
  listening port: 17357

peer: H7MobrirpOVEJWiHQ4lB/gefs+qer+DTCkSTbA7EHV0=
  preshared key: (hidden)
  endpoint: softether-server.example.com:443
  allowed ips: 192.168.30.0/24

WireGuardはステートレスなVPNプロトコルであるため、この時点ではまだ接続されていません。本来は接続という概念もありませんが、ここではSoftEtherVPN側のIPアドレステーブルに対向(クライアント)側のIPアドレスが登録されることをもって便宜上接続と呼びます。

接続するためには、ping などでなにか実際の通信を発生させる必要があります。

$ ping 192.168.30.1
PING 192.168.30.1 (192.168.30.1): 56 data bytes
64 bytes from 192.168.30.1: icmp_seq=0 ttl=128 time=28.876 ms

何度かパケットを送っていると、transfer のところに表示される通信量が増えているのが確認できます。

# wg show 
interface: wgse0
  public key: vbXNEl9sJeQbf2kIHDuoafhNJynwvZvwgnwbwYXKrzM=
  private key: (hidden)
  listening port: 64022

peer: H7MobrirpOVEJWiHQ4lB/gefs+qer+DTCkSTbA7EHV0=
  preshared key: (hidden)
  endpoint: softether-server.example.com:443
  allowed ips: 192.168.30.0/24
  latest handshake: 1 minute, 6 seconds ago
  transfer: 2.67 KiB received, 4.32 KiB sent

サーバー側での確認

実際に通信を発生させてpingが通っていることを確認できたら、SoftEtherVPN側の管理コマンドを使用して接続中のクライアントなどの情報を見てみます。

VPN Server/SECURENAT>SessionList
SessionList コマンド - 接続中のセッション一覧の取得
項目            |値
----------------+------------------------------------
セッション名    |SID-SECURENAT-1
VLAN ID         |-
場所            |SecureNAT セッション
ユーザー名      |SecureNAT
接続元ホスト名  |仮想ホスト
TCP コネクション|なし
転送バイト数    |34,902
転送パケット数  |549
----------------+------------------------------------
セッション名    |SID-META-[WIREGUARD]-4
VLAN ID         |-
場所            |ローカルセッション
ユーザー名      |meta
接続元ホスト名 |wireguard-client.example.com
TCP コネクション|1 / 1
転送バイト数    |2,420
転送パケット数  |37
コマンドは正常に終了しました。

セッションリストで、WireGuardプロトコルで接続しているクライアントがいることが確認できます。セッションの詳細を見てみると、以下のように暗号化アルゴリズムに ChaCha20-Poly1305 が使用されていることが確認できます。

VPN Server/SECURENAT>sessionget SID-META-[WIREGUARD]-4
SessionGet コマンド - セッション情報の取得
項目                                |値
------------------------------------+-------------------------------------------------------------
クライアント IP アドレス            |172.16.83.3
クライアントホスト名                |wireguard-client.example.com
ユーザー名 (認証)                   |meta
ユーザー名 (データベース)           |meta
VLAN ID                             |-
サーバー製品名                      |SoftEther VPN Server Developer Edition (64 bit) (Open Source)
サーバーバージョン                  |5.01
サーバービルド番号                  |Build 9675
接続開始時刻                        |2021年 3月27日(土) 17時 0分44秒
初回セッションの確立時刻            |2021年 3月27日(土) 17時 0分44秒
現在のセッションの確立時刻          |2021年 3月27日(土) 17時 0分44秒
半二重 TCP コネクションモード       |いいえ (全二重モード)
VoIP / QoS 対応機能                 |無効
TCP コネクション数                  |1
TCP コネクション数最大値            |1
暗号化の使用                        |はい (暗号化アルゴリズム: ChaCha20-Poly1305)
圧縮の使用                          |いいえ (圧縮無し)
物理通信に使用中のプロトコル        |Legacy VPN - WIREGUARD
UDP 高速化機能をサポート            |いいえ
UDP 高速化機能を使用中              |いいえ
セッション名                        |SID-META-[WIREGUARD]-4
コネクション名                      |CID-5
セッションキー (160bit)             |34CA1A2C12074BE53A2479F7B097261DA98E7F0C
ブリッジ / ルータモード             |いいえ
モニタリングモード                  |いいえ
送信データサイズ                    |7,254 バイト
受信データサイズ                    |7,806 バイト
送信ユニキャストパケット数          |94 パケット
送信ユニキャスト合計サイズ          |7,212 バイト
送信ブロードキャストパケット数      |1 パケット
送信ブロードキャスト合計サイズ      |42 バイト
受信ユニキャストパケット数          |48 パケット
受信ユニキャスト合計サイズ          |2,072 バイト
受信ブロードキャストパケット数      |94 パケット
受信ブロードキャスト合計サイズ      |5,734 バイト
クライアント製品名 (申告)           |WireGuard
クライアントバージョン (申告)       |5.01
クライアントビルド番号 (申告)       |Build 9675
クライアント OS 名 (申告)           |WireGuard
クライアント OS バージョン (申告)   |-
クライアント OS プロダクト ID (申告)|-
クライアントホスト名 (申告)         |
クライアント IP アドレス (申告)     |172.16.83.3
クライアントポート番号 (申告)       |62395
サーバーホスト名 (申告)             |0.0.0.0
サーバー IP アドレス (申告)         |0.0.0.0
サーバーポート番号 (申告)           |443
コマンドは正常に終了しました。

同様に、IPアドレステーブルにもクライアントのIPアドレスが登録されています。

VPN Server/SECURENAT>iptable
IpTable コマンド - IP アドレステーブルデータベースの取得
項目        |値
------------+-----------------------
ID          |3038997077
セッション名|SID-SECURENAT-1
IP アドレス |192.168.30.1
作成時刻    |2021-03-27 16:51:57
更新時刻    |2021-03-27 16:58:12
場所        |SoftEtherVPN-develop 上
------------+-----------------------
ID          |3431872817
セッション名|SID-META-[WIREGUARD]-4
IP アドレス |192.168.30.238
作成時刻    |2021-03-27 17:00:44
更新時刻    |2021-03-27 17:02:04
場所        |SoftEtherVPN-develop 上

コマンドは正常に終了しました。

まとめ

SoftEtherVPNは独自プロトコル(ネイティブプロトコル)、SSTP、L2TP/IPsec、EtherIP/IPsec、OpenVPNなど様々なプロトコルに対応したオールインワンVPNですが、対応するプロトコルに新たに新時代のプロトコルであるWireGuardが追加されたのはとても喜ばしいことです。

ただし、SoftEtherVPNとWireGuardの両方に精通していないと設定は少々難しいですし、WireGuardが動的なIPアドレスの割当をサポートしていないことから、WireGuardプロトコルだけ運用・管理スキームが他のプロトコルと異なる部分が生まれてしまい、使いにくい部分はあります。

設定方法・手順をまとめ、通信できることを確認したので一旦はここまでにします。後日、オリジナルのWireGuardとの速度の比較などを行う予定です。