@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Ubuntu 22.04 で dig myhost.local が名前解決できない(dig @XX.XX.XX.XX myhost.local は名前解決できる)

理由・原因

systemd-resolved のローカル DNS スタブリゾルバーは .local を外部 DNS サーバーに問い合わせないから。

PROTOCOLS AND ROUTING

   The lookup requests that systemd-resolved.service receives are
   routed to the available DNS servers, LLMNR, and MulticastDNS
   interfaces according to the following rules:

   •   Multi-label names with the domain suffix ".local" are
       resolved using MulticastDNS on all local interfaces where
       MulticastDNS is enabled. As with LLMNR, IPv4 address lookups
       are sent via IPv4 and IPv6 address lookups are sent via IPv6.

   •   Queries for multi-label names are routed via unicast DNS on
       local interfaces that have a DNS server configured, plus the
       globally configured DNS servers if there are any. Which
       interfaces are used is determined by the routing logic based
       on search and route-only domains, described below. Note that
       by default, lookups for domains with the ".local" suffix are
       not routed to DNS servers, unless the domain is specified
       explicitly as routing or search domain for the DNS server and
       interface. This means that on networks where the ".local"
       domain is defined in a site-specific DNS server, explicit
       search or routing domains need to be configured to make
       lookups work within this DNS domain. Note that these days,
       it's generally recommended to avoid defining ".local" in a
       DNS server, as RFC6762[2] reserves this domain for exclusive
       MulticastDNS use.

ローカル DNS スタブリゾルバーというのは、ローカル DNS キャッシュ用のデーモンプロセスで、systemd-resolved の一部。/etc/resolv.conf/run/systemd/resolved/stub-resolv.conf のシンボリックリンクになっていると使われる。Ubuntu の 20.04 だか、少し前のバージョンからデフォルトでローカル DNS スタブリゾルバーを使う設定になっている。

azureuser@myvm2:~$ ls -lah /etc/resolv.conf
lrwxrwxrwx 1 root root 37 Jun  7 15:32 /etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf

手っ取り早い解決方法

ローカル DNS スタブリゾルバーを迂回すれば良い。

/etc/resolv.conf/run/systemd/resolve/stub-resolv.conf のシンボリックリンクになっていると、ローカル DNS スタブリゾルバーを使う。

外部ネームサーバーに DNS 名前解決クエリを転送する用の設定ファイル /run/systemd/resolve/resolv.conf があるので、シンボリックリンクをこっちに書き換えれば解決する。

sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

環境・前提

  • 仮想ネットワーク 10.0.0.0/16
  • サブネット 10.0.0.0/24
  • 10.0.0.4 ... DNS サーバー(dnsmasq)が port 53 を listen している。上位ネームサーバーは 1.1.1.1
  • 10.0.0.5 ... systemd-resolved のローカル DNS スタブリゾルバーが port 53 を listen している。systemd-resolved が名前解決に使うネームサーバーは 10.0.0.4
  • dnsmasq が参照する hosts ファイルには以下のエントリがある
127.0.0.103 myhost.local
127.0.0.104 myhost.mydomain

dig myhost.local

-rw-r--r-- 1 systemd-resolve systemd-resolve 788 Jun  7 16:32 /run/systemd/resolve/resolv.conf
azureuser@myvm2:~$ dig myhost.local

; <<>> DiG 9.18.24-1-Debian <<>> myhost.local
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 9497
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;myhost.local.          IN  A

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Jun 07 16:37:16 UTC 2024
;; MSG SIZE  rcvd: 41

以下の警告メッセージが出ているが、(マルチキャスト DNS とは何か、普通の(=ユニキャスト)DNS と何が違うのか、などを)知っていればわかる、という感じ。。

;; WARNING: .local is reserved for Multicast DNS ;; You are currently testing what happens when an mDNS query is leaked to DNS

マルチキャストDNS

ホスト名を解決するとき、mDNSクライアントはIPマルチキャストクエリメッセージを送信し、そのホスト名を自分のものとしているホストに呼びかける。その後対象の機器は自身のIPアドレスを含むメッセージをマルチキャストする。サブネット内にいるすべての機器はこの情報を基に自身のmDNSキャッシュを更新できる。この情報はTime to Live (TTL) をゼロにした応答パケットを送ることで任意のホストが破棄できる。

デフォルトでは、mDNSは.local(英語版)トップレベルドメインで終わるホスト名のみを解決する。これはmDNSを実装していないが従来のユニキャストDNSサーバーで解決できるホストが.localドメインに含まれている際に問題となりうる。そのような衝突を解決するにはmDNSが衝突を回避するようネットワーク設定を変更する必要がある。

dig myhost.local @10.0.0.4

azureuser@myvm2:~$ dig myhost.local @10.0.0.4

; <<>> DiG 9.18.24-1-Debian <<>> myhost.local @10.0.0.4
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58071
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myhost.local.          IN  A

;; ANSWER SECTION:
myhost.local.       0   IN  A   127.0.0.103

;; Query time: 4 msec
;; SERVER: 10.0.0.4#53(10.0.0.4) (UDP)
;; WHEN: Fri Jun 07 16:42:12 UTC 2024
;; MSG SIZE  rcvd: 57

dnsmasq の log-queries オプションを有効化して、受け取った DNS 名前解決クエリをログに出力させていると、以下のようなログが出る。

Jun 07 16:42:12 myvm1 dnsmasq[2471]: query[A] myhost.local from 10.0.0.5
Jun 07 16:42:12 myvm1 dnsmasq[2471]: /etc/hosts-dnsmasq myhost.local is 127.0.0.103

dig myhost.mydomain

azureuser@myvm2:~$ dig myhost.mydomain

; <<>> DiG 9.18.24-1-Debian <<>> myhost.mydomain
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11644
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;myhost.mydomain.       IN  A

;; ANSWER SECTION:
myhost.mydomain.    0   IN  A   127.0.0.104

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Jun 07 16:46:53 UTC 2024
;; MSG SIZE  rcvd: 60

DHCP のせいで(?)ネームサーバーが 168.63.129.16(とは)に勝手に書き変わってしまうことがある。ちゃんと治すべきだが方法がわからない。netplan で eth0 の nameserver を上書き(?)して apply すれば暫定的に動く。

azureuser@myvm2:~$ cat /etc/netplan/99-my.yaml # このファイルを以下の内容で作る
  network:
    version: 2
    ethernets:
      eth0:
        nameservers:
          addresses: [10.0.0.4]
sudo netplan apply
azureuser@myvm2:~$ resolvectl status
Global
       Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (eth0)
    Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
         Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 10.0.0.4
       DNS Servers: 10.0.0.4 168.63.129.16

UPDATE: networking - What is the correct way to use specific DNS servers if using DHCP in a no-desktop Ubuntu 20.04 install, and can you use DNS over TLS? - Ask Ubuntu が正解っぽい。

azureuser@myvm2:~$ cat /run/systemd/resolve/resolv.conf
# This is /run/systemd/resolve/resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 10.0.0.4
search .
azureuser@myvm2:~$ cat /etc/netplan/99-my.yaml
  network:
    version: 2
    ethernets:
      eth0:
        dhcp4-overrides:
          use-dns: false
        nameservers:
          addresses: [10.0.0.4]

DHCP 経由で与えられる DNS サーバー(今回は Azure の仮想ネットワーク内に仮想マシンを作ったので Azure の仮想パブリック IP アドレスが割り当てられる)が、DNS Servers に現れなくなった。

azureuser@myvm2:~$ resolvectl status
Global
       Protocols: +LLMNR +mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (eth0)
Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
     Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
   DNS Servers: 10.0.0.4

dig myhost.mydomain @10.0.0.4

azureuser@myvm2:~$ dig myhost.mydomain @10.0.0.4

; <<>> DiG 9.18.24-1-Debian <<>> myhost.mydomain @10.0.0.4
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15619
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myhost.mydomain.       IN  A

;; ANSWER SECTION:
myhost.mydomain.    0   IN  A   127.0.0.104

;; Query time: 0 msec
;; SERVER: 10.0.0.4#53(10.0.0.4) (UDP)
;; WHEN: Fri Jun 07 16:50:13 UTC 2024
;; MSG SIZE  rcvd: 60

余談

最初は Vagrant で実験していたが、dnsmasq を動かしてない側のホストで systemd-resolved が参照するネームサーバーをうまく書き換えられず(VirtualBox が DHCP 経由で(?)提供する DNS サーバーのアドレス 10.0.0.2 だか .3 だかになってしまう)、調べた感じだと Vagrant/VirtualBox 特有のクセみたいな話で、そこを克服するのがやりたいことではない・・ということでプラットフォームごと変えて Azure を使った(が、結果的に大差なかったのかもしれない、まだよくわかってない)

Special Thanks

qiita.com

dnsmasq の設定方法。初めてやったのでとても助かりました。