LoginSignup
10
9

More than 3 years have passed since last update.

WSL1 (Windows Subsystem for Linux) で mDNS な `.local` アドレスを解決する

Posted at

それは、一通の Slack メッセージが始まりでした。

WSL(Ubuntu 18.04) で .local を解決できるようにするのってどうすればいいんですかね

結論

powershell.exe を WSL 内の bash から呼んでしまえばいい。

$ powershell.exe "Resolve-DnsName raspberrypi.local"

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
raspberrypi.local                              A      120   Answer     192.168.1.116

環境

Windows 10 Pro
バージョン 1909 (November 2019 Update)
ビルド 18363.535
WSL: Version 1 (WSL2 の足音が聞こえているので明確に 1 としました)

Windows 10 で mDNS (.local アドレス) の名前解決は可能です

mDNSを使ってローカルDNSサーバーを廃止する によると、バージョン 1909(= November 2019 Update)で mDNS 周りの不具合がかなり解消されており、 PowerShell の Resolve-DnsName や cmd.exe での ping で .local アドレスが発見できるようになりました。

さて、 WSL1 にインストールした Ubuntu 等の ping を始めとしたコマンドは、 libresolv.so.2 1 から nsswitch.conf を経由して 2 名前解決が行われます。
要するに Windows 側の名前解決の仕組みは一切使われません。2016 年から話題になってたみたいですね。 Can't resolve ".local" (mDNS) hosnames

この時 mDNS なアドレスを解決するアプローチは2つあります。

  1. libnss-mdns を入れて Linux 上での名前解決ができるようにする
  2. なんとかして Windows 側で名前解決する

libnss-mdns は討ち死にする

libnss-mdns は avahi-daemon を必要とし、そして avahi-daemon は dbus を必要としますが、 dbus が WSL1 で動きません。討ち死にです。

参考: Need help making mDNS work

Windows 側で名前解決する

今回の TIPS のメインです。
PowerShell の Resolv-DnsNameは Windows 側の名前解決を利用します(するようです)。
WSL の bash といっても所詮 cmd.exe の代わりに bash.exe が動いているだけなので、 bash 上で Windows の .exe も実行できちゃいます。

以上のことから powershell.exe を bash シェルから呼び出すという今回の TIPS が成立したのです。

シェル芸、やりたい放題

PowerShell からの出力は bash の STDOUT に流れてくるため、パイプでつなげたい放題です。
PowerShell からは JSON で出力しつつ jq で受けるといったこともできます。

$ powershell.exe "Resolve-DnsName raspberrypi.local | ConvertTo-Json"
{
    "IP4Address":  "192.168.1.116",
    "Name":  "raspberrypi.local",
    "Type":  1,
    "CharacterSet":  1,
    "Section":  1,
    "DataLength":  4,
    "TTL":  120,
    "Address":  "192.168.1.116",
    "IPAddress":  "192.168.1.116",
    "QueryType":  1
}
$ powershell.exe "Resolve-DnsName raspberrypi.local | ConvertTo-Json" | jq -r .IPAddress
192.168.1.116

function を定義すればコマンド化も可能です。

nsfind() {
    powershell.exe "Resolve-DnsName $1 | ConvertTo-Json" | jq -r .IPAddress
}
$ ssh pi@`nsfind raspberrypi.local`

※ ちょっと微妙な感じですが、とりあえず動く!

注意点

もちろん Windows 10 バージョン 1909 の話です。それ以前の方は、まず Windows 10 を最新にしましょう。話はそれからです。

WSL2 になったら Hyper-V 上の VM になるそうなので、たぶん dbus とか動くから avahi-daemon 経由で mDNS が解決できるような気がする。

あとがき

この方法を見つける前までは

なのでcmd.exeかPowerShellで解決したIPv4 or IPv6アドレスをコピペするという雑な解決方法

こんな事してたんですけど、自分の書込みをみて思ったわけです。「あれ?WSL から powershell 呼べればいいんじゃね?」と。

さて、、、、仕事しよう。暇じゃないよ。

EoT


  1. ldd /bin/ping でリンク先ライブラリが確認できます。 

  2. sudo strace ping raspberrypi.local でトレースできます。 

10
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9