VPNの新しいかたち、WireGuardを使ってみる

たまたまアマゾンで検索していたらVPNの使えるモバイルルータというのがあって、口コミを見ていたらWireGuardという聞きなれないVPNがあったので調べてみました。

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.

OpenVPNやStrongSwanより簡単にVPNができるとありました。口コミでも意外と好評でしたのでセットアップしてみました。まずは口コミを実証するためにOpenWrtからです。

OpenWrt

サーバ側は設定ができたらwg-quick up wg0で起動しておきます。

opkg install kmod-wireguard luci-app-wireguard luci-proto-wireguard wireguard wireguard-tools

OpenWrtの場合はダッシュボードですべて設定が可能です。パッケージをインストールしたらダッシュボードでインタフェースのwgを作りプロトコルをwireguradを選択します。 そしてプロトコルを有効にするために一旦リブートします。設定画面の一部ですが次のようになります。InterfaceのWGをZoneのWGに割り当てます。

OpenWrt
OpenWrt

鍵の作り方

鍵は至ってシンプルです。公開鍵と秘密鍵を作ります。

mkdir /etc/wireguard
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey > publickey

サーバ側の設定

Firewallの設定でListenPort 51820/udpを開けておきます。

/etc/wireguard/wg0.conf
[Interface]
 PrivateKey = <private key>
 Address = 10.0.0.1/24
 ListenPort = 51820
 [Peer]
 PublicKey = BLwj4cFU1pyZnKRUfaQ+WGILdFMsIRVmGxumbO+VwmM=
 AllowedIPs = 10.0.0.2/32
 [Peer]
 PublicKey = Vhs/vFjnel906nBh7XxvUtIEeYmT3muHbGlvXeA5Hk4=
 AllowedIPs = 10.0.0.60/32
 [Peer]
 PublicKey = Zq5v2tKFzT6T7hPGZSVatLBsy+SI64NvXX242FgaFw4=
 AllowedIPs = 10.0.0.100/32
 [Peer]
 PublicKey = cUrLly4zWa578S9jAyVRnFzdvZQPPsbK8NGpNcbOJnw=
 AllowedIPs = 10.0.0.111/32
 [Peer]
 PublicKey = qGNpf4tdsvMX21g/PU3SSTVZfpQZ6wHKVcFW88IAulE=
 AllowedIPs = 10.0.0.10/32

Debian

Debianはリポジトリを追加してインストールします。WireGuardのモジュールはメインカーネルに含まれいていないのでdkmsでカーネルモジュールを作ります。

echo "deb http://deb.debian.org/debian/ unstable main" | sudo tee /etc/apt/sources.list.d/unstable.list
echo -e "Package: *\nPin: release a=unstable\nPin-Priority: 150\n" | tee /etc/apt/preferences.d/limit-unstable
sudo apt update
sudo apt install wireguard

Ubuntu LTS

Ubuntu LTSもリポジトリを追加してインストールします。

sudo add-apt-repository ppa:wireguard/wireguard
sudo apt install wireguard

LXC

apt-get install --no-install-recommends wireguard-tools

ArchLinux ARM

Chromebook ARMのArchLinuxは以前の記事に書きましたがカーネルの不具合で、ダウングレードしています。ところがローリング・リリースなのでARMは過去のパッケージにアクセスで来ません。そこでビルドするのですが、パッチを使ってバージョンを戻します。

つぎのファイルをダウンロードするのですが、余計なヘッダーがつくので各々のファイルを手動でコピーして作ります。

ログにパッチがあるのでそれを使ってリビジョンを戻します。

カーネルをビルドしてカーネルヘッダーのパッケージのみインストールします。あとはdkmsモジュールをビルド・インストールして完了です。

作成したカーネルヘッダーパッケージと既存カーネルの置き場です。

Android

AndroidはPlay でアプリをインストールします。そこで気がついたのですがこのアプリはユーザランドで動いています。気になったので調べてたらboringtunを使うらしいです。つまりカーネルモジュールが使えない場合の方法があるということです。アンドロイドの設定は次のようにしました。サーバ側で次のように設定してqrencodeを使ってQRコードを表示させます。それをスマホで読み込むと設定が完了します。これは超簡単なのでこれから爆発的に流行りそうな潜在力を秘めています。

foo.conf
[Interface]
 Address = 10.0.0.100/24
 PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
 DNS = 10.0.0.1
 [Peer]
 PublicKey = pGvwDzski+meZWUkm3vHhyxGgtkkdSf9/FFzQofW2gU=
 #PresharedKey = [PRE-SHARED KEY]
 AllowedIPs = 10.0.0.0/24
 Endpoint = example.com:51820
qrencode -t ansiutf8 < foo.conf

サーバ側からテストしてみます。スマホ側からテストするにはターミナルエミュレーターアプリを入れてping -c3 [address]とします。

ping 10.0.0.100
 PING 10.0.0.100 (10.0.0.100) 56(84) bytes of data.
 64 bytes from 10.0.0.100: icmp_seq=1 ttl=64 time=65.3 ms
 64 bytes from 10.0.0.100: icmp_seq=2 ttl=64 time=66.10 ms

 

Armbian 5.91 (Amls905)

追記:最新版は標準インストールされています

Armbian s9xxは非公式のカーネル5.1が入っており、リポジトリからカーネルヘッダーをダウンロードできません。そこでソースからカーネルをビルドします。

git clone https://github.com/150balbes/Amlogic_s905-kernel.git
git log
git reset --hard 065aff580a3036854bab0a977ab51b5b043367e8
ln -s GIT_DIR linux
ln -s linux $(uname -r)   
ln -s /usr/src/$(uname -r)  /lib/modules/$(uname -r)/build
cd linux
make oldconfig

Makefileを編集します

VERSION = 5
 PATCHLEVEL = 1
 SUBLEVEL = 0
 EXTRAVERSION = -aml-s905

カーネルをビルドします。

meke -j3

ビルドできたらdkmsカーネルモジュールが正しくインストールできるかチェックします。もしできたのならパッケージを作ります。

make bindeb-pkg

どういうわけかvermagicが5.1.0-aml-s905+になって、余計な「+」があるとモジュールが読み込めません。その場合は次のファイルを編集します。これでdkmsカーネルモジュールを作れば動きます。

nano include/generated/utsrelease.h
  #define UTS_RELEASE "5.1.0-aml-s905"
ln -sf  /usr/src/linux-headers-5.1.0-aml-s905+ /lib/modules/5.1.0-aml-s905/build

モジュールの情報です

modinfo wireguard
 filename:       /lib/modules/5.1.0-aml-s905/updates/dkms/wireguard.ko
 alias:          net-pf-16-proto-16-family-wireguard
 alias:          rtnl-link-wireguard
 version:        0.0.20191012
 author:         Jason A. Donenfeld Jason@zx2c4.com
 description:    WireGuard secure network tunnel
 license:        GPL v2
 srcversion:     C04EB24BB0E47CF3D9FEFE7
 depends:        ipv6
 name:           wireguard
 vermagic:       5.1.0-aml-s905 SMP preempt mod_unload aarch64

openVZ

boringtun

openvizはカーネルモジュールにアクセスできないのでユーザーランド方式を使ます。インターフェースはできるものの接続ができませんでした。現在調査中です。=> firewallの問題で解決済みです

sudo echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list
sudo printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
sudo apt update
sudo apt-get install --no-install-recommends wireguard-tools
curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env
mkdir ~/src
cd ~/src
git clone https://github.com/cloudflare/boringtun
cd boringtun
cargo build --bin boringtun --release
cp -a ./target/release/boringtun /usr/local/bin/
#sudo /usr/local/bin/boringtun wg0
sudo boringtun  --disable-multi-queue wg0
wg set wg0 private-key  privatekey  peer "pGvwDzski+meZWUkm3vHhyxGgtkkdSf9/FFzQofW2gU=" allowed-ips  10.0.0.0/24  endpoint 61.195.97.254:51820

インターフェースを起動します。

sudo ip addr add 10.0.0.111/24 dev wg0
sudo ip link set up wg0

wireguard-go

wireguard-goを使う場合、まずgoをインストールします。

wget https://dl.google.com/go/go1.12.6.linux-amd64.tar.gz

ソースをダウンロードしてコンパイルします

git clone https://git.zx2c4.com/wireguard-go

/lib/systemd/system/wg-quick@.serviceを一部変更します

Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity
Environment=WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1
cd wireguard-go
make
sudo cp wireguard-go /usr/local/bin

起動します

systemctl enable wg-quick@wg0 
systemctl start wg-quick@wg0

サーバの稼働状況

wg
 interface: wg0
   public key: pGvwDzski+meZWUkm3vHhyxGgtkkdSf9/FFzQofW2gU=
   private key: (hidden)
   listening port: 51820
 peer: Vhs/vFjnel906nBh7XxvUtIEeYmT3muHbGlvXeA5Hk4=
   endpoint: 110.66.173.233:51860
   allowed ips: 10.0.0.60/32
   latest handshake: 24 seconds ago
   transfer: 11.59 KiB received, 3.30 KiB sent
 peer: Zq5v2tKFzT6T7hPGZSVatLBsy+SI64NvXX242FgaFw4=
   endpoint: 110.66.173.233:35183
   allowed ips: 10.0.0.100/32
   latest handshake: 51 seconds ago
   transfer: 437.93 KiB received, 516.82 KiB sent
 peer: qGNpf4tdsvMX21g/PU3SSTVZfpQZ6wHKVcFW88IAulE=
   endpoint: 110.66.173.233:51810
   allowed ips: 10.0.0.10/32
   latest handshake: 59 seconds ago
   transfer: 10.77 KiB received, 3.86 KiB sent
 peer: BLwj4cFU1pyZnKRUfaQ+WGILdFMsIRVmGxumbO+VwmM=
   allowed ips: 10.0.0.2/32
 peer: cUrLly4zWa578S9jAyVRnFzdvZQPPsbK8NGpNcbOJnw=
   allowed ips: 10.0.0.111/32

稼働状況はこのようになっています。endpointがないものはサーバに接続ができていません。

以上です。

追記:ルーティング

ルーティングについてちょっとハマったので追記しました。

サーバ側

iptablesに設定を追加します。私はshorewallを使っているのでそこで追加します。ほかもinterfaces, zones, policy, rules等必要な箇所は追加します。shorewallの基本なのでここでは割愛します。

/etc/shorewall/snat

SNAT(61.xx.xx.xx)    10.0.0.0/24     eth0

DNSはVPN内で完結するようにします。DNSが漏れないように設定します。

/etc/shorewall/rules:

#DNS(ACCEPT)    wg      net
DNS(ACCEPT)     wg      $FW

dnsmasqをインストールします。ほかのやり方はちょっと思いつきません。

apt install dnsmasq

/etc/dnsmasq.conf


port=53
resolv-file=/etc/dnsmasq.resolv.conf
listen-address=127.0.0.1, 10.0.0.1
domain=mydomain.tld

/etc/dnsmasq.resolv.conf

nameserver 8.8.8.8
nameserver 1.1.1.1

クライアント側

追記:EndPointはDNSの問い合わせのあるFQDNではなくIPアドレスのほうが好ましい。

apt isntall openresolv
[Interface]
 PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
 Address = 10.0.0.2/24
 ListenPort = 51821
 DNS = 10.0.0.1   # VPN server IP
 
 [Peer]
  PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
  AllowedIPs = 0.0.0.0/0
  EndPoint = example.com:51820
  PersistentKeepAlive = 25

ルーティングはwg-quickがすべてやってくれるので追加はありません。例外的にルーティングを追加する場合です。

[Interface]
 PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
 Address = 10.0.0.2/24
 ListenPort = 51821
 DNS = 10.0.0.1   # VPN server IP
 
 [Peer]
  PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
  AllowedIPs = 0.0.0.0/0
  EndPoint = example.com:51820
  PersistentKeepAlive = 25

例外的に追加する場合はPostUp/Postdownを使います。

[Interface]
 PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
 Address = 10.0.0.2/24
 ListenPort = 51821
 DNS = 10.0.0.1   # VPN server IP
 PostUp = ip route add 10.10.0.0/24 via 192.168.1.1
 Postdown = ip route del 10.10.0.0/24 via 192.168.1.1

 [Peer]
  PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
  AllowedIPs = 0.0.0.0/0
  EndPoint = example.com:51820
  PersistentKeepAlive = 25

Troubleshooting

  • wgコマンドでインターフェースが起動してることを確認する
  • peerのアドレスが0.0.0.0/0の場合、ルーティングをチェックすること。WireGuardが通信できる経路を確保すること。
  • Firewallを見直す。

参考