2023.11.12追記
現在の最新WSLではブリッジモードやミラーモードというネットワークモードが追加されているのでIPv6を使いたい場合にはそちらをご利用ください。
WSL2をIPv6ネットワークに接続するでは4回に分けて上流からDHCPv6-PDでプレフィクス委譲をうけてIPv6ネットワークに接続する方法を解説しました。国内家庭用回線ではフレッツ光がかなりの割合を占めるので在宅時にはこの方法で接続可能な方もそれなりにおられるかと思います。しかし、企業内、学内ネットワークがいちクライアントPCに対してプレフィクス委譲してくれることはまれなので、別の方法が必要になります。WSL仮想スイッチを外部接続にするのが一番よさそうな気はするのですが、HCS系のAPIで管理されていて詳細がつかめないものを無理に触るのはどうしても怖くなります。
直接接続できないとなると、次の手法としてはND Proxy
を使うことになると思います。
ND Proxyをどうやって実現するか?
一番望ましいのはND Proxy
を行うWindows用のプログラムを作る、あるいは探してくるということなのですが残念ながら手が出ませんでした。身近な無線ルーターなどではND Proxy
が当たり前のように搭載されていますが、比較的Linuxベースのものが多いですよね?ということはLinuxを使えば実現できそうです。
Windows上でLinuxを使う方法としてWSLが非常にお手軽なツールなのですが、Hyper-VにインストールすればWindowsホストと同じネットワークに簡単に接続できます。今回はたまたまHyper-Vにインストールされていた Rocky Linux を使って検証してみます。
必要なもの
- Hyper-V (Windows10 Pro以上)
- ndppd
- radvd
IPv6スタックはLinuxに標準搭載されているので、neighbor discovery を中継するndppd
と、RAを送出するためのradvd
の二つがあれば実現できそうです。ndppd
, radvd
は当該OSのパッケージシステムでインストールしておいてください。
Hyper-V での設定
Rocky Linuxがインストールされている状態から話を進めます。Hyper-VにLinuxディストリが無い場合にはまずインストールしてください。
Hyper-Vマネージャーで仮想スイッチを一つ作成します。仮想スイッチマネージャーから「外部」を選択して仮想スイッチを作成します。名前は「External」とでもしておいてください。
次に、Rocky に接続するネットワークを変更します。
通常はDefault Switch
になっていると思いますが、これを先ほどのExternal
に変更します。
次に「ハードウェアの追加」から、ネットワークアダプターを追加します。追加するスイッチはWSL
です。
これで、eth0がExternal, eth0がWSLに接続されます。起動すると、RockyはIPv4, IPv6ともにWindowsホストと同じネットワークに接続されます。
。。。。。
これでいいじゃん、と思われた方はWSLではなくHyper-VインスタンスのLinuxを使いましょう。その場合WSL仮想スイッチに接続する必要はありません。
しかし、WSLにはHyper-Vインスタンスにはない利便性があるのでこれはこれで使いたいものです。そう思われた方は次へと進みましょう。
radvdで経路を広告する
RockyがWindowsホスト同様の物理ネットワークに接続され、さらにWSL仮想ネットワークにも接続された状態となったので彼に中継させればWSLインスタンスも外部へと出ていけるようになりました。しかし、WSLはまだそのことを知らないのでradvdを使って、上流から受け取ったプレフィクスをそのまま下流(=WSL仮想ネットワーク)へと広告してあげましょう。
/etc/radvd.conf に以下のように記述します。サンプルそのままですが、RAを流す対象は eth1 (のはず)です。間違って、eth0に流すとネットワーク管理者から叱責されることになるので気を付けてください。念のため、上流からprefixを受け取っているインタフェースを確認するようにしてください。
interface eth1
{
AdvSendAdvert on;
prefix ::/64
{
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr off;
};
};
prefix の部分には広告するネットワークを書かないといけないのですが、動的に生成するのでひとまずこの形にしておいてください。
/proc/net/if_inet6 に IPv6 のアドレス情報があるので、そこからグローバルユニークアドレス(2::/3)に該当するアドレスを探して、フォーマットを加工します。その文字列を/etc/radvd.conf に当てはめるのですが、方法はこういう感じです。
prefix=$(sed -rn 's/^([23]...)(....)(....)(....).*$/\1:\2:\3:\4/p' /proc/net/if_inet6|head -n1)
sed -ri "s|^(\s+)prefix\s.*$|\1prefix $prefix::/64|g" /etc/radvd.conf
これで完成です。先のスクリプトで加工したコンフィグレーションで radvd を起動すると、WSL2インスタンスにも IPv6 アドレスが割り当てられるのですが、eth1側のリンクローカルアドレスが消えてうまく動かないかもしれません。
OSのIPv6パラメータを少し調整しておきます。
sudo sysctl net.ipv6.conf.eth1.autoconf=0
sudo sysctl net.ipv6.conf.all.forwarding=1
この調整でうまく機能するようになっていると思います。
NDを中継する
次に、neighbor discoveryを中継させるのですが、これはndppd
が担当してくれます。
/etc/ndppd.conf に以下のように書いておきます。
proxy eth0 {
router no
autowire yes
rule ::/0 {
iface eth1
}
}
proxy eth1 {
rule ::/0 {
iface eth0
}
}
これでsudo ndppd -d
として起動させればよいのですが、うまく動かないかもしれません。
うまく動かない場合、理由はip -6 r
で確認できるのですが、
2xxx:xxxx:xxxx:xxxx::/64 dev eth0 proto ra metric 100 pref medium
2xxx:xxxx:xxxx:xxxx::/64 dev eth1 proto ra metric 101 pref medium
このように上流から受け取ったプレフィクスへの経路がが eth0, eth1 の両方に付けられています。そして、metricで優先順位をつけられています。この場合、ND proxyで近隣の宛先は交換されている(ip neigh
で確認できる)のですが、経路設定の方が優先されて実際には通信できません。
Rocky(というかRedHat)のパッケージにはndppd 0.2.5が用意されているのですが、正式リリース版の0.2.5はずいぶん前のものです。その後、autowire
というオプションが導入されているようです。これは中継したneighborへの経路を設定してくれるオプションです。
githubのndppdリポジトリからソース一式を取ってきてコンパイルすればautowire
が使えるようになります。autowire が使えない場合にはWSLインスタンスに割り当てられたIPv6アドレスに対して経路をつけるようにしても代替できます。
ip -6 add dev eth1 2xxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
metricをいじって優先度を変えれば通信できるようになるのですが、今度は同一プレフィックスの物理ノードとの通信に支障をきたすのでおススメではありません。
実際に使うとなると
実際に使うとなると、これだけの作業のためにわざわざ Hyper-V上のLinuxインスタンスを動かすというのはメモリもディスクスペースも無駄が多いです。なにより普通に Hyper-VでLinux使えばいいじゃんになってしまいます。
なので、できるだけ小さいディストリを探して/あるいは削り落として一連の流れを起動時スクリプトで処理してしまえば起動すればND proxyを開始してホストがシャットダウンする時には自動停止するようにしておくのがよさそうです。
開始タイミングはWSL2より先に起動してしまうとWSL仮想スイッチが存在しない為にエラーになるので、以下のような感じで起動させればよいと思います。
wsl.exe echo
powershell.exe Start-Process powershell.exe -WindowStyle Hidden -Verb Runas "Start-VM -Name 'VM名'"
まとめ
Hyper-Vインスタンスのndppdを使ってND Proxyを実現すれば簡単に中継できると思ったのですが、ndppdのバージョンやそもそもHyper-Vでいいじゃん問題を露見させてしまい、今一つまとまりのない感じになってしまいました。
コンパクトなディストリというよりもルーターOSのVyOSいれれば良いような気がしてきたので次はそちらを検証してみます。