はじめに
2023.11.12追記
Windows11のWSL2にてDNSの不調を感じる場合、Windowsのレゾルバを直接参照する機能が提供されているのでそちらをご利用ください。
[利用方法]
- WSLを最新にアップデート
wsl --update; wsl --update --pre-release
- .wslconfigに設定を追記
c:\Users<ユーザー名>.wslconfig
[wsl2] dnsTunneling=true
参考) WSLでの詳細設定の構成
WSL2でDNSサーバを見失った場合、外部の public DNSを指せば良いよというtipsを時折見かけます。
ただ、筆者はこの問題に遭遇したことがないのでそれ自体はよくわかっていません。
別件として、WSL2が参照するDNS proxy(=Windowsホスト)はTCPフォールバックをサポートしていないようです。おそらくこのDNS proxyが搭載された時期の仕様に従っているようで一部DNSサーバと通信できない場合があります。
こうした場合、/etc/resolv.conf に別のDNSサーバを追加してあげればよいのですが、Windowsホストと同様に設定したほうがなにかと都合が良い場合があります。そこで、public DNSではなく、Windowsホストが参照している情報を入手する方法を考えます。
WindowsのことはWindowsに聞け
Windowsの情報を参照するには PowerShellが役立ちます。
今回知りたいことは2点です。
- Windowsホストが参照しているDNSサーバ
- Windowsホストのドメインサーチサフィックス
###DNSサーバを取得する
WindowsのDNSサーバは接続毎に管理されているので現在有効な(=デフォルトゲートウェイになっているインタフェース)のDNSサーバを取得します。
Get-NetRoute -DestinationPrefix '0.0.0.0/0'|Get-DnsClientServerAddress
人間が見るにはこれでよいのですが、機械的に処理するには余計な情報が多いので少し加工します。
Get-NetRoute -DestinationPrefix '0.0.0.0/0'|Get-DnsClientServerAddress|%{echo "nameserver $($_.ServerAddresses)"};
% は foreach の aliasです。取得したDNSサーバオブジェクトをforeachで回して ServerAddress のみを取得します。余計な "nameserver" という文字を付けた理由は後ほど。
###サーチサフィックスを取得する
同様にサーチサフィックスを取得するのですが、以下のオブジェクトを参照することで、DNSサーバから取得したサーチサフィックスとプライマリドメインサフィックスとしてドメインから、あるいは明示的に設定した情報をまとめて取得できます。
(Get-DnsClientGlobalSetting).SuffixSearchList|%{echo "search $_" };
これらのサフィックスにさらに mshome.net(Hyper-V仮想マシンに付けられるドメイン名)も加えておけば接続環境でのサーチサフィックスは一通りそろいます。
##まとめ
ここで得られた情報を加工して /etc/resolv.conf に追加情報として反映するようにしておけば出来上がりです。
wsl.conf でインスタンス起動時に実行すればと思ったのですが、現状では~/.profile等に記述してログイン時に処理するのがよさそうです。wsl.conf [boot]の記述を処理するタイミングではまだWindowsコマンドを呼び出す相互運用の準備ができていないようですね。
先ほどnameserver や searchという識別子を付けておいたのは、これら二つをひとまとめにして powershell.exe を呼び出したいからです。WSLからWindowsコマンドを呼び出すのはコストが高い(PowerShellが遅いだけ?)ようで筆者環境でおおむね 0.6秒程度かかります。できるだけひとまとめにしてPowerShellを呼び出して時間を節約したいので、実行後にテキスト抽出しやすいようにマーカーを付けています。