🐔

WSL2 の Ubuntu 22.04 でホスト名解決を普通っぽくする

2024/01/20に公開

WSL2 のホスト名解決は鬼門?

今まで WSL2 でのホスト名解決はしばしばトラブっていたと思うが、最近(Windows version 22H2 以降)は dnsTunneling なる機能がサポートされたためだいぶマシになった。
そこで、Ubuntu 22.04 でホスト名解決が一般的な環境に近くなるような設定を紹介する。

systemd が有効になっていることを確認する

最近は初めから systemd が有効になっているハズだが、念のため確認しておく。
Ubuntu 側で以下のコマンドを実行する。

cat /etc/wsl.conf

表示された中に下記の内容が書かれていれば OK。

[boot]
systemd=true

もし書かれていなかったら以下のコマンドを実行する。

sudo tee -a /etc/wsl.conf <<EOF
[boot]
systemd = true
EOF

dns tunneling を有効にする

Windows 側で %USERPROFILE%\.wslconfig に以下の設定を追加する。

%USERPROFILE%\.wslconfig
[wsl2]
dnsTunneling = true

これがキモで、ぶっちゃけこれだけやっておけばまぁマトモにはなる。

WSL をシャットダウンする

Windows 側で以下のコマンドを実行して WSL をシャットダウンする。

wsl --shutdown

DNS 直での名前解決も systemd-resolved 経由にする

/etc/resolv.conf を直接読みやがるヤツら(dig とか)のために、Ubuntu 側で以下のコマンドを実行する。

追記/etc/resolv.conf を直接読まなくても gethostbyname(3) とか getaddrinfo(3) とかの glibc ライブラリは /etc/nsswitch.conf 経由で /etc/resolv.conf の影響を受けるし、Golang も glibc と同じような動きをするようなので、/etc/resolv.conf の影響範囲は結構広いのかもしれない…

さらに追記:glibc ライブラリは libnss-resolve パッケージをインストールしていれば Unix Domain Socket 経由で systemd-resolved に直接問い合わせるので /etc/resolv.conf の影響は受けないようだ。一方で Golang は Cgo が使えれば getaddrinfo(3) にフォールバックするので glibc ライブラリと同じ挙動になるが、Cgo が使えないと自前で解決しようとするので /etc/resolv.conf の影響をうけるようだ。

resolv.conf の自動生成を無効にする

sudo tee -a /etc/wsl.conf <<EOF
[network]
generateResolvConf = false
EOF

resolv.conf を stub モードにする

sudo rm /etc/resolv.conf
sudo ln -s ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

systemd-resolved に dnsTunneling のアドレスを教える

sudo mkdir -p /etc/systemd/resolved.conf.d
sudo tee /etc/systemd/resolved.conf.d/dns.conf <<EOF
[Resolve]
DNS=127.0.0.42
EOF

systemd-resolved を再起動する

sudo systemctl restart systemd-resolved

注意

systemd-resolved では 127.0.0.53:53 で DNS スタブリスナが待ち受けているのだが、WSL2 で複数の環境を実行しているとこれがかち合ってしまう。
かち合うとどうなるかと言うと、後から実行した方の systemd-resolved が DNS スタブリスナの待ち受けを諦める。(systemctl status systemd-resolved で見てみるとそれっぽいログが出ているので分かると思う)
そして、その環境からの 127.0.0.53:53 への接続は先に起動していた環境の systemd-resolved に繋がってしまうため、妙なトラブルに遭遇することになる。(先に起動していた環境を停止するとホスト名解決できなくなったり、先に起動していた環境の /etc/hosts から結果を返したり…)

なので、複数環境を実行していて安定した動作を望む場合には「DNS 直での名前解決も systemd-resolved 経由にする」はやらないほうが良いだろう。

Discussion