- 理由・原因
- 手っ取り早い解決方法
- 環境・前提
- dig myhost.local
- dig myhost.local @10.0.0.4
- dig myhost.mydomain
- dig myhost.mydomain @10.0.0.4
- 余談
- Special Thanks
理由・原因
systemd-resolved
のローカル DNS スタブリゾルバーは .local
を外部 DNS サーバーに問い合わせないから。
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
ホスト名を解決するとき、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
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
dnsmasq の設定方法。初めてやったのでとても助かりました。