2019-08-12

WireGuard の IPv6 化

https://bike8615.blogspot.com/2019/04/vpn-wireguard_8.html

上記サイトの記事で WireGuard の導入に関して記載しました。

この記事では IPv4 での VPN でしたが、今回 IPv6 対応し IPv6 サイトへのアクセスをおこなえるようにしました。



IPv6 でしかアクセスできないサイトもアクセスできるようになり、Mac のみならず iPhone や Android 機でも同様にできるようになります。


また、IPv6 アクセスは少し速くアクセスできるようですから何か得した気分です。



WireGuard は「クライアント to サーバー型」ではなく 「ピア to ピア型」なので厳密には「サーバー」ではないのですが、便宜的に Raspberry Pi の方を「サーバー側」とし、端末を「クライアント側」とします。


さて、「サーバー側」の定義ファイルである wg0.conf の内容にピンク文字列部分を追加します。

[Interface]
Address = 10.0.0.1/32, fd86:ea04:1119::1 
→ VPN のサーバー側の仮想アドレス
ListenPort = 1194 → 例では OpenVPN と同じ 1194 を使う設定にした
PrivateKey = [server_private.key] → サーバー用プライベートキーをペーストする

PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -A FORWARD -o %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -D FORWARD -o %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
#Client1
PublicKey =
[client1_public.key] → クライアント用パブリックキーをペーストする
AllowedIPs = 10.0.0.2/32, fd86:ea04:1119::2



IPv6 アドレスはプライベートアドレスを設定しますが "fd86:……" のように fd または fe で始まるアドレスにします。




「クライアント側」もこれに合わせて次の2箇所に追記します。

Interface → Addreses 欄に 10.0.0.2/32, fd86:ea04:1119::2/128 
Peer → Allowed IPs 欄に 0.0.0.0/0, ::/0

とします。



以上の設定で、「サーバー側」アドレスは IPv4 = 10.0.0.1 / IPv6 = fd86:ea04:1119::1 となります。

また、「クライアント側」アドレスは IPv4 = 10.0.0.2 / IPv6 = fd86:ea04:1119::2 となります。




以上の設定をしたら、「サーバー側」は WireGuard の「停止 → 起動」をします。

pi@raspberrypi:~ $ sudo wg-quick down wg0
pi@raspberrypi:~ $ sudo wg-quick up wg0


「クライアント側」はアプリの「切断 → 接続」をします。


pi@raspberrypi:~ $ sudo wg


で接続状態を確認します。

お互いに ping を投げて接続を確認します。

pi@raspberrypi:~ $ ping6 fd86:ea04:1119::2
PING fd86:ea04:1119::2(fd86:ea04:1119::2) 56 data bytes
64 bytes from fd86:ea04:1119::2: icmp_seq=1 ttl=64 time=86.5 ms
64 bytes from fd86:ea04:1119::2: icmp_seq=2 ttl=64 time=78.1 ms
^C





「クライアント側」も同様にしますが、IPv6 で ping できるアプリを使います。


「Ping & Net(Ulf Dittmer)」というドイツ製アプリあたりがいいでしょう。



さて、Chrome で実際に IPv6 での接続をしてみましょう。


まずは、"ipv6.google.com" にアクセスして下図の画面になれば、接続できています。
IPv6 でアクセスできていないと、応答がタイムアウトします。






































次に、IPv6 への接続性を確認してみます。

"test-ipv6.com" に接続してみて 10/10 の判定ならば大丈夫です。


なお、黄色のビックリマークの部分は以下の2つです。

あなたのブラウザは動作するIPv6アドレスを持っています - しかし利用が回避されています。ワタシたちはこの点を憂慮しています。[詳細]

IPv4またはIPv6のいずれかのトンネルメカニズムを使用しているようです。If you are using a VPN, your VPN is only protecting one protocol, not both.

前者は、Android 版 Chrome が素直に IPv6 に接続せずに IPv4 での接続を試みるからこのメッセージになっていますが、10/10 判定からは間違いなく IPv6 が接続できていることを示しています。

後者は、IPv4 over IPv6 でトンネリングしている場合、IPv6 は VPN 保護されているが、IPv4 は VPN での保護ではなくトンネリングに基づく保護であることを示しています。




































次の画面は、"http://[2001:200:dff:fff1:216:3eff:feb1:44d7]" にアクセスしたときのものです。

IPv6 でアクセスできていれば亀が泳いでいます。






































いかがでしょうか。






これであなたも WireGuard による IPv6 化ができたことになります(もちろん、IPv4 でも大丈夫です)。








2019-08-06

WireGuard に関する考察

接続から2〜3分後に切断されてしまう問題があります。

Listen port : (random) ですが、端末側は Listen port をとくには設定していないことがあると思われ、その場合はランダムなポートが割り当たります。



ハンドシェイク(イニシエーション/レスポンス)はこのランダムなポートと、相手側の Listen port との間で行われます。


WireGuard は Client to Server 型ではなく Peer to Peer 型ですから接続はどちらからでも行えるのです。

便宜上、スマホ側を「クライアント」とし、同様に便宜上、Raspberry Pi 側を「サーバー」としておきます。



Peer to Peer なので「クライアント」側からのイニシエーションもあれば、
「サーバー」側からのイニシエーションもあるということです。


この場合イニシエーションを受けた側はレスポンスを返す決まりです。

イニシエーションを投げる側を「イニシエーター」、受け取って応答を返す側を「レスポンダー」といいます。



ハンドシェイクは概ね2分間隔で行われており、何らかの要因でこれが途絶え15秒を経過するとイニシエーターが交代するようです。



 全く最初のハンドシェイクでは Keypair の交換が行われます。



その後の再接続では、完全に切断状態でなければ Keypair 交換はなく、イニシエーション/レスポンスのやり取りだけです。



また、Keepalive はこのハンドシェイクとは別に行われます。


お互いに「設定(wg0.conf)」で設定した間隔で Keepalive パケットを投げあい、受け取り合うのです。



Keepalive はルーターの NAT で内から外へのパケットがポートを開けて通過し、設定された開放時間(例えば tcp=360s / udp=180s とか)の間に生死確認することで、ポート開放状態を維持する目的で使用されるものです。



これは自局のルーターもですが、キャリア網・4G(LTE)からインターネットに接続されるルーターもあり、WireGuard では 25秒が最適であるとしていて、この値がデフォルト推奨値です。


一般にキャリア網の開放時間は小さいという説もあり真偽は不明ながら 25秒は十分と思われます。



それでも切断が発生の場合は、この Keepalive 間隔を 25秒から 15秒あるいはそれよりも少なくする必要があるかも知れません。



ルーターが NAT を開いて、出ていくパケットに対する戻りパケットが帰ってくるとき、ポートが開いている時間内に戻ってくればハンドシェイクはうまくいきます。



tcp の場合は syn に対する ack がこれに相当しますが、udp には syn/ack のようなトランスポート層でのやり取りはありません。



より上位のレイヤー7レベルでデータパケットをやり取りすることで NAT の開放時間内の戻りを確保する必要があるのです。



Keepalive はいわば、通信経路を確保しておく手段ということになリます。



一方、ハンドシェイクは VPN 状態を確保する手段ということになります。




例えば udp ポートの開いている時間が180秒(3分)だったとし、その間に戻れないと切断が発生します。




切断回避手段ですが、自局ルーターについてはお互いの Listen Port を同じポートにすればいいのですが、4G(LTE)はキャリアのルーターがポートを開ける時間に依存しています。



つまり、下記の2点が安定した VPN を保持するために必要ということになります。


1.自局のルーターに開けたポート(「サーバー」側:WireGuard デフォルト推奨ポートは 51280)に合わせて、「クライアント」側:スマホの Listen port は "random" ではなく同じポートを使うのです。

   V6プラスの場合は、割り当てられたポートの一つに設定します。


2.ルーター/ファイアウォール対策(自局もさることながら、むしろキャリア向け対策)として、Persistent Keepalive を設定します(デフォルト推奨値 25 秒)




MVNO は LINE mobile(SB回線)と OCN mobile(D回線)を使っていますが、10時間以上スリープ状態でも、覚めてから ping がどちらの回線も正常に通ります。


WireGuard 接続状態にしておけば、外で 4G(LTE)時はもちろん、公衆 WiFi に入ったらそのまま公衆 WiFi 経由で安全なネット利用ができますし、自宅にも入れます。


自宅 WiFi に入ったとき、そのまま自宅 WiFi 経由 WireGuard 接続状態で使えますので、内/外を特に操作不要で使い分けられます。




つまり、普段から自宅 WiFi 下で WireGuard 接続しておけば、外に出るとそのまま 4G (LTE) で VPN が使え、フリー WiFi 接続されればそのまま VPN で利用でき、帰宅すれば再び自宅 WiFi で VPN 経由で利用できます。



ずーっと繋ぎっぱなしでいいので大変楽です。







2019-08-02

WireGuard を通じて外出中でも Mac や Paspberry Pi にログインする

せっかく WireGuard を使えるようになったので、フリー WiFi での安全なインターネットアクセスのみではもったいなく、Mac や Raspberry Pi にリモートログインできるようにしました。


まず、Mac の方ですが、「システム環境設定」→「共有」→「リモートログイン」にチェックを入れます。



次に「セキュリティとプライバシー」→「ファイアウォール」の「オプション」で「リモートログイン(SSH)」の外部からの接続を受け入れる設定をします。



Mac 側の設定はこれだけです。





Raspberry Pi の方に移ります。

まずは ssh のポート設定と ssh デーモンの再起動を行います。


エディターを使って ssh_config の port 22 を有効にします。
先頭行に "Port 22" を追記するか、38 行目 のコメントを外します。

pi@raspberrypi:~ $ sudo leafpad /etec/ssh_config

次に ssh デーモンの再起動をします。

pi@raspberrypi:~ $ sudo /etc/init.d/ssh restart

ファイアウォールで、VPN リモートからのログインが通るようにします。

pi@raspberrypi:~ $ sudo ufw allow in from VPNアドレス.0/24

「VPNアドレス.0/24」は VPN アドレス帯が例えば 10.0.0.0/24 ならばこれを入力します。





クライアント側の設定です。

iPhone の場合は iTerminal か Termius あたりのアプリをインストールします。

前者のフリー版は広告が表示されます。
後者は原則有料で、お試し期間だけ無料です。

これらのアプリは接続先情報(アドレス/ポート番号/ユーザー名/パスワード)を設定して "Connect" ボタンをクリックして接続します。

接続されればターミナル画面になります。




Android 用は Termux に openssh を次のコマンドでインストールします。

$ apt update
$ apt upgrade
$ apt install openssh

Termux はいろいろなパッケージをインストールすることで便利にできるのが素晴らしい。

iPhone のように ssh アプリを Google Store からインストールしなくても、Termux のパッケージとしてインストールできます。

iPhone 用の Termux があれば一番いいのですが、残念ながら Android 版しかありません。


Termux にインストールした ssh コマンドで接続することができます。


最初からターミナル画面なので、PC で行う場合と同じにできるので違和感がありません。



Android での Termux での画面は以下のような画面です。

















ssh pi@1vv.xxx.yyy.zzz
パスワード










ログイン完了後のプロンプト







iPhone での iTerminal での画面は次のようになります。


































以上のような画面で Raspberry Pi の操作ができます。

Mac についても ssh でログインすることで、同様に操作ができます。













次世代 VPN・WireGuard の安定性

一晩 VPN を張った状態で放置してみましたが、ちゃんと VPN 状態は保持されています。


この間、端末側はスリープに入っています。

安定しているといえます。



ただ、素直に接続しないことがあり、その場合は iPhone や Android 機の「キャッシュクリア」→「アプリ起動」→「接続」とすることが必要になります。



iPhone の場合は電源ボタン長押しで「スライドで電源オフ」がでたらホームボタンを長押ししますと、数秒でキャッシュクリアされて、もとのホーム画面に戻ります。

Android 機は「設定」→「アプリ」→「WireGuard」→「ストレージ」→「キャッシュ削除」とします。


端末側アプリにはキャッシュに不要なものが残り、これが接続を妨げるバグがあると思われます。



接続されたかどうかは端末側からサーバーの VPN アドレスに向けて ping して確認します。

サーバーから端末側への ping の方がやりやすいのですが、外で家のネットに接続して使うわけですから端末側から ping とします。




ping アプリは、iPhone ならば "Ping - network utility" がいいかと思います。
このアプリは無料ながら広告が表示されませんからおすすめです。



















また、対象のアドレス入力欄には過去の入力履歴が残っていますので、例えば 1 を入力すると 10.10.0.1 とか、1.1.1.1 とか過去に入力したことがあるアドレスが表示されますからその中のサーバーの VPN アドレスを指定して ping すれば接続 ok か ng かがわかります。






Android ならば "Ping" というアプリでしょうか。
これは無料アプリで広告が出ますが、使い勝手はいいです。

これも過去使ったアドレスが右上の欄にあり、その中から選べばいいようになっています。

もちろん最初は入力します。

























実際に WireGuard VPN 接続中に "Ping" アプリで ping したのが下記です。

例では "www.google.com" への ping を確認しています。




























WireGuard ではサーバーとクライアント(またはサーバー同士)の接続は、対等の動作になっています。

つまりどちらが「主」でどちらが「従」ということはありません。

ハンドシェイクを始める側を「イニシエーター」、受け取る側を「レスポンダー」といっていますが、どちも「イニシエーター」にも「レスポンダー」にもなります。




サーバー側(?)の設定ファイルでも [Intaerface] と [Peer] です。
クライアント側(?)の設定もまた然りです。


つまり自分の側が [Interface] であり、相手側が [Peer] です。



こういう部分は OpenVPN やほかの VPN と大きく異る点ですね。

WireGuard は IP アドレスの隠蔽は目的としていなくて、通信の秘匿性を保つことを目的としており、この点もほかの VPN と異なる点です。




お互いに VPN 状態を保つために以下のやり取りをおこなっています。


これは端末側がスリープに入っていても行われます。


1つ目は、お互いに Keepalive を送受して通信状態を保ちます。
2つ目は、お互いにハンドシェイクを送受して通信状態を保ちます。
3つ目は、お互いにハンドシェイクと keypair 交換をおこなって通信状態を保ちます。


これらの3つは、タイミングに一定の法則があるようには見えません。
1〜2分間隔で行われています。


まれに失敗しても次の送受では回復しているようです。

つまり、送受失敗でもそれがなかったかのように次の送受を繰り返すようになっていて、成功で VPN 状態が回復、ということです。

リトライタイマーが働くこともありますが、これは通信経路保持の一つの方法でしょう。


keepalive はお互いの設定に基づいているようです。

とくに設定がない場合は1〜2分間隔になっています。




VPN 状態を保つために行われている3つの通信(送受)はどちらが「主」でどちらが「従」ということはなく、お互いが送信側であったり、受信側であったりしています。


ログ上からはそのように見えます。