WSL2をIPv6ネットワークに接続する(中編: RAを広告する)

## はじめに
:::note warn
2023.11.12追記
現在の最新WSLではブリッジモードやミラーモードというネットワークモードが追加されているのでIPv6を使いたい場合にはそちらをご利用ください。
この手法は旧来のネットワークモードやWindowsサンドボックスでの活用方法もありますが、基本的にはもはや必要のない方法です。
:::

前編ではWSL2はIPv6に接続できないという事実確認と何が解決すれば通信できるのかということを見てきましたが、具体的にWindowsの機能でどこまでできるのかというのをもう少し見ていきたいと思います。

本稿の構成は以下のような構成を考えています。

前編 [*WSL2がIPv6通信できない理由*](https://qiita.com/shigeokamoto/items/ba89516d1448b13f7251)
中編 *現時点のWindows標準機能だけでRAを広告する* <-- イマココ
後編 [*DHCPv6-PDでプレフィクス委譲を受ける*](https://qiita.com/shigeokamoto/items/a13f5fea5085f541a0b5)
番外 [*改良スクリプトをタスクスケジューラに登録する*](https://qiita.com/shigeokamoto/items/4e5538fcc80aba2dc4fe)


# 現時点のWindows標準機能だけでRAを広告する

Windowsの標準コマンドラインインタフェースはcmd.exe(古くはcommand.com)ですが、これに置き換わるものとしてPowerShellが登場してからもう随分と時間がたちます。PowerShellにはコマンドレットが用意されていて、これらを駆使することで様々な操作が行えます。筆者はWSLを使い始めてからPowerShellを触るようになったのですが、WSLとWindowsを連携させようと思うとPowerShellがおのずと必要になってきます。

最近のマイクロソフトはドキュメントを数多く提供してくれるのでこれを見ればできることはおおむね把握できます。
[NetTCPIP Module | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/nettcpip/)

このマニュアルとにらめっこしながら使えそうなものを選んでいきます。

Set-NetIPInterface
New-NetIPAddress
Set-NetRoute

このあたりが使えそうな気がします。
意外にも充実していて、これIPv6使えるようにできるんじゃない？と期待を持たせる内容です。IPv6アドレスの設定やルーティングだけでなく、RA on/off等もこれらのコマンドレットを使えば実現できそうです。RAを広告出来るということは、Windows側のインタフェースに設定を加えればWSL2側は自動設定が出来そうです。

## IPv6アドレスを設定する

ひとまず仮のIPv6アドレスで動作を確認していきます。

WSL2を一度起動させて、タスクマネージャなどでvEthernet (WS) が生成されたことを確認してください。
※pro以上のWindowsを使われている方は後ほどWindows Sandbox を使うので予め有効にしておくと手間が省けます。

```powershell:管理者PowerShellで実行
New-NetIPAddress -IPAddress 2001:db8::1 -PrefixLength 64 -InterfaceAlias 'vEthernet (WSL)' -SkipAsSource $True -PolicyStore ActiveStore;
```

結果が表示されて設定されたことがわかるかと思います。
オプションの`SkipAsSource`は このアドレスをソースルートには使わないというものです。`PolicyStore`はこのアドレスの状態で`ActiveStore`は起動時に有効な情報です。`PersistentStore`を指定すると再起動後も有効な情報になります。


## ルーター広告を設定する
次にRAを広告してみましょう

```powershell:PowerShellで実行
Set-NetIPInterface -InterfaceAlias 'vEthernet (WSL)' -AddressFamily IPv6 -Advertising Enabled -AdvertiseDefaultRoute Enabled -Forwarding Enabled;
```

`Advertising`, `AdvertiseDefaultRoute`というオプションがあるので両方 Enabledにしてみます。`Forwarding`はこのインタフェースがパケットを中継するかどうかなのでホストを跨いで外部やDefault Switchとやり取りするためには Enabled にする必要があります。

設定してみましたが、この時点ではまだ WSL2 を確認してもIPv6アドレスが付けられていません。
`Set-NetRoute`に`Publish`というオプションがあり、これが`No`の状態だと広告されないとのことなので`Yes`にしてみます。

```powershell:PowerShellで実行
Set-NetRoute -InterfaceAlias 'vEthernet (WSL)' -AddressFamily IPv6 -Publish Yes;
```

```shell:WSL2で確認
$ ip -6 a show dev eth0
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1280 qdisc mq state UP group default qlen 1000
    inet6 2001:db8::215:5dff:fe75:d314/64 scope global dynamic mngtmpaddr
       valid_lft forever preferred_lft forever
```

vEthernet (WSL) に設定した 2001:db8::/64 のアドレスが設定されました。
経路情報も確認してみます。

```shell:WSL2で確認
$ ip -6 route
2001:db8::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
multicast ff00::/8 dev eth0 proto kernel metric 256 pref medium
default via fe80::6da5:25ef:7bf4:e4d2 dev eth0 proto ra metric 1024 expires 1632sec pref medium
```

デフォルト経路に`fe80::6da5:25ef:7bf4:e4d2`(IPv6アドレスは環境ごとに異なります)が設定されています。このアドレスは、ipconfig で確認すると、vEthernet (WSL) につけられたリンクローカルアドレスです。

```powrshell:PowerShellで確認
PS> ipconfig
イーサネット アダプター vEthernet (WSL):

   接続固有の DNS サフィックス . . . . .:
   IPv6 アドレス . . . . . . . . . . . .: 2001:db8::6da5:25ef:7bf4:e4d2
   IPv6 アドレス . . . . . . . . . . . .: 2001:db8::1
   一時 IPv6 アドレス. . . . . . . . . .: 2001:db8::3cd2:35b0:3191:bead
   リンクローカル IPv6 アドレス. . . . .: fe80::191a:25cf:6053:999%24
   リンクローカル IPv6 アドレス. . . . .: fe80::3cd2:35b0:3191:bead%24
   リンクローカル IPv6 アドレス. . . . .: fe80::6da5:25ef:7bf4:e4d2%24 <--- default と同じアドレス
   リンクローカル IPv6 アドレス. . . . .: fe80::c5a7:ad45:94d8:b7d0%24
   IPv4 アドレス . . . . . . . . . . . .: 172.28.0.1
   サブネット マスク . . . . . . . . . .: 255.255.240.0
   デフォルト ゲートウェイ . . . . . . .:
```

つまり、WSL2のデフォルトゲートウェイにWindowsホストが指定できています。これでWSL2にIPv6アドレスが設定され、デフォルトゲートウェイも設定されました。しかし、リンクローカルアドレスが4つもありますね。どうやら`Set-NetRoute`した際に対象の経路を指定しなかったのでリンクローカルアドレスまで広告してしまっているようです。オプションに`-DestinationPrefix`を指定した方がよさそうです。

これでWSL2からのパケットが外へ出ていけるようになりました。逆方向にパケットが流入できるようになると通信が可能になります。もう一息ですね。


## Windows SandboxとIPv6で通信してみる
いきなりWindowsの外部と通信するのはハードル高いので、まずは仮想マシン同士で通信させてみましょう。<font color=eeaabb>(といっても、WSL2以外の仮想マシンを起動できるのはWindowsの品目がPro以上に限られるので Home の方は申し訳ありませんが雰囲気だけ味わってください。次回後編ではPCの外部との通信を試みます。)</font>Hyper-Vインスタンスでも構いませんが、手軽なところでWindows Sandboxを使います。Windowsサンドボックスを有効にしていない場合は`Windowsの機能の有効化または無効化`から有効にしてください。


Sandboxを起動すると vEthernet (Default Switch) ができるので一度起動させてipconfig等で仮想インタフェースが作成されていることを確認してください。vEthernet (Default Switch)が有効になったら、先ほどの vEthernet (WSL) と同じ設定を行います。IPv6アドレスは `2001:db8:0:1::/64`にして、一つずらします。

```powershell:管理者PowerShellで実行
New-NetIPAddress -IPAddress 2001:db8:0:1::1 -PrefixLength 64 -InterfaceAlias 'vEthernet (Default Switch)' -SkipAsSource $True -PolicyStore ActiveStore;
Set-NetIPInterface -InterfaceAlias 'vEthernet (Default Switch)' -AddressFamily IPv6 -Advertising Enabled -AdvertiseDefaultRoute Enabled -Forwarding Enabled -PassThru;
Set-NetRoute -InterfaceAlias 'vEthernet (Default Switch)' -AddressFamily IPv6 -Publish yes;
```

-PassThru というのは処理結果を標準出力に出力するオプションです。PowerShellのコマンドレットは基本非同期処理なので、このオプションをつけていないと処理が終わる前に次の処理へとど んどんすすんで行ってしまいます。この場合インタフェースの広告設定が完了してからNetRouteのpublish指定をしたいので追記しています。

これで、SandboxにもWSL2同様にIPv6アドレスがつきました。WSL2は`ip -6 a`, Sandboxは`ipconfig`でお互いのアドレスを調べて通信してみましょう。

```shell:WSL2からの疎通確認(IPv6アドレスは環境ごとに異なります)
$ ping 2001:db8:0:1:b1c8:1c83:9ca5:1a42
PING 2001:db8:0:1:b1c8:1c83:9ca5:1a42(2001:db8:0:1:b1c8:1c83:9ca5:1a42) 56 データ長(byte)
64 バイト応答 送信元 2001:db8:0:1:b1c8:1c83:9ca5:1a42: icmp_seq=1 ttl=127 時間=3.34ミリ秒
64 バイト応答 送信元 2001:db8:0:1:b1c8:1c83:9ca5:1a42: icmp_seq=2 ttl=127 時間=3.82ミリ秒
64 バイト応答 送信元 2001:db8:0:1:b1c8:1c83:9ca5:1a42: icmp_seq=3 ttl=127 時間=1.75ミリ秒
64 バイト応答 送信元 2001:db8:0:1:b1c8:1c83:9ca5:1a42: icmp_seq=4 ttl=127 時間=5.46ミリ秒
```

```powershell:Sandboxからの疎通確認(IPv6アドレスは環境ごとに異なります)
> ping 2001:db8::215:5dff:feac:a075
Pinging 2001:db8::215:5dff:feac:a075 with 32 bytes of data:
Reply from 2001:db8::215:5dff:feac:a075: time=6ms
Reply from 2001:db8::215:5dff:feac:a075: time=2ms
Reply from 2001:db8::215:5dff:feac:a075: time=1ms
Reply from 2001:db8::215:5dff:feac:a075: time=2ms
```


双方から通信できているようですね。



## おわりに
Hyper-Vスイッチの各インタフェースに`IPv6`アドレスをつけてRAを広告することで、WSL2を含む各仮想インスタンスに対してIPv6アドレスとデフォルトゲートを設定することが出来ました。ただ、これだけでは仮想インスタンス同士とWindowsホストとの間で通信しているだけです。この先外部との通信を実現していかないといけません。
一つの方法はWindowsホストが接続されているルータが、IPv6アドレスの経路を自由に書けるような機材(cisco や allied, yamaha, nec等)であればWindows以下に委譲するプレフィクスを決めてルータに設定すれば使えるようになります。そういう環境の方であればここまでの説明であとはなんとか出来ると思います。

次のステップとしては、上流ルータから DHCPv6-PD でプレフィクス委譲を受けて仮想スイッチに分配してみたいと思います。