本日も乙

ただの自己満足な備忘録。

Ubuntu 20.04 LTSで「.local」への名前解決ができない場合の対応方法

Linux サーバで Active Directy ドメインに参加しようとしたらできなかったのでその時の対応メモです。なお、この事象は Ubuntu 16.04 LTS 以上であれば起こり得るのですが、私の場合 Ubuntu 20.04 LTS で発覚しました。

事象

realm join で Active Directory に加入しようとすると realm: No such realm found というエラーが出てしまいました。realm discover でドメインを探そうとしますが同じエラーになってしまいました。ドメインは example.local としています。

% realm join -v example.local
 * Resolving: example.local
 * No results: example.local
realm: No such realm found
% realm discover example.local -v
 * Resolving: example.local
 * No results: example.local
realm: No such realm found: example.local

調査

example.local の名前解決ができないのが原因のようです。IP アドレスが正引きできるかを確かめるとたしかに引けないことがわかります。ここで SERVER: 127.0.0.53#53(127.0.0.53) が気になります。というのも DHCP オプションセットで AmazonProvidedDNS を有効にしているため、DNS サーバの IP アドレスは VPC IPv4 CIDR にプラス 2 したものになるはずだからです(10.0.0.0/16 なら 10.0.0.2)。

DHCP オプションセット - Amazon Virtual Private Cloud

% dig example.local

; <<>> DiG 9.16.1-Ubuntu <<>> example.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: 7884
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

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

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Fri Jun 05 20:32:19 JST 2020
;; MSG SIZE  rcvd: 39

resolv.conf を見ると DNS サーバが 127.0.0.53 になっていて、This file is managed by man:systemd-resolved(8). Do not edit. と書かれています。

% cat /etc/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must 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 127.0.0.53
options edns0
search example.com

systemd-resolved とは

systemd-resolved は動的な DNS リゾルバです。Ubuntu 16.04 LTS から採用されています。 /etc/resolv.conf は systemd-resolved によって生成されたファイル(/run/systemd/resolve/stub-resolv.conf)のシンボリックリンクになっています。

$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 May 30 06:49 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf

DNS の設定を変更するには、/etc/systemd/resolved.conf を編集するか、/etc/systemd/resolved.conf.d/ 以下に <適当なファイル名>.conf を設置して systemd-resolved を再起動します。

スタブリゾルバ

DNS サーバが 127.0.0.53 となっていますが、これはスタブリゾルバと呼ばれ、外部 DNS サービスに問い合わせをする仲介役となっています。スタブリゾルバは DNS サーバの応答をキャッシュするなどの役割を果たします。

なぜ 「.local」 で名前解決ができないのか

ここで resolvectl status を実行してみると、DNS Servers: 10.0.0.2 とあり、AmazonProvidedDNS に向いています。

% resolvectl status
Global
       LLMNR setting: no
MulticastDNS setting: no
  DNSOverTLS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
          DNSSEC NTA: 10.in-addr.arpa
           ...(省略)....

Link 2 (ens5)
      Current Scopes: DNS
DefaultRoute setting: yes
       LLMNR setting: yes
MulticastDNS setting: no
  DNSOverTLS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
  Current DNS Server: 10.0.0.2
         DNS Servers: 10.0.0.2
          DNS Domain: example.com

example.local 以外のドメインでは名前解決はできていました。

% dig test.example.com

; <<>> DiG 9.16.1-Ubuntu <<>> test.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58839
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;test.example.com. IN A

;; ANSWER SECTION:
test.example.com. 299 IN A xxx.xxx.xxx.xxx

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Fri Jun 05 20:43:55 JST 2020
;; MSG SIZE  rcvd: 90

また、AmazonProvidedDNS を直接指定すると example.local も IP アドレスの正引きができることも確認できました。

% dig example.local @10.0.0.2

; <<>> DiG 9.16.1-Ubuntu <<>> example.local @10.0.0.2
;; 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: 4439
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.local.                    IN      A

;; ANSWER SECTION:
example.local.             300     IN      A       10.0.10.10
example.local.             300     IN      A       10.0.11.20

;; Query time: 3 msec
;; SERVER: 10.0.0.2#53(10.0.0.2)
;; WHEN: Fri Jun 05 20:57:59 JST 2020
;; MSG SIZE  rcvd: 60

ではなぜ example.local の名前解決ができないのでしょうか。man を見ると下のように書いてあり、つまりは example.local はスタブリゾルバ(127.0.0.53)から DNS フォワードされないため名前解決ができないのが原因のようです(多分)。

Other multi-label names are routed to all local interfaces that have a DNS server configured, plus the globally configured DNS servers if there are any. 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.

その他のマルチラベル名は、DNSサーバーが設定されているすべてのローカルインターフェースにルーティングされ、さらにグローバルに設定されたDNSサーバーがある場合は、グローバルに設定されたDNSサーバーにルーティングされます。デフォルトでは、「.local」サフィックスを持つドメインの検索は、そのドメインがDNSサーバーとインターフェースのルーティングまたは検索ドメインとして明示的に指定されていない限り、DNSサーバーにルーティングされないことに注意してください。(DeepL による翻訳)

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 within this DNS domain work. 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.

つまり、「.local」ドメインがサイト固有のDNSサーバーで定義されているネットワークでは、このDNSドメイン内での検索を動作させるために、明示的な検索またはルーティングドメインを設定する必要があるということです。最近では、RFC6762[2]がこのドメインをMulticastDNSの排他的な使用のために予約しているため、DNSサーバーで「.local」を定義しないことが一般的に推奨されていることに注意してください。(DeepL による翻訳)

https://www.man7.org/linux/man-pages/man8/systemd-resolved.service.8.html

解決策

解決策は2つあります。

  1. systemd-resolved をやめて /etc/resolv.conf に直書き
  2. systemd-resolved でスタブリゾルバ(127.0.0.53)を使わないようにする

1 はVPCネットワーク(VPC IPv4 CIDR)が変わると、毎回 DNS サーバの IP アドレスを変更しなければなりません。AmazonProvidedDNS によって動的に DNS サーバを設定しているため、直書きするようなことは極力控えたいです。

2 については再び man を見ると次のように書いてありました。

systemd-resolved maintains the /run/systemd/resolve/resolv.conf file for compatibility with traditional Linux programs. This file may be symlinked from /etc/resolv.conf and is always kept up-to-date, containing information about all known DNS servers. Note the file format's limitations: it does not know a concept of per-interface DNS servers and hence only contains system-wide DNS server definitions. Note that /run/systemd/resolve/resolv.conf should not be used directly by applications, but only through a symlink from /etc/resolv.conf. If this mode of operation is used local clients that bypass any local DNS API will also bypass systemd-resolved and will talk directly to the known DNS servers.

systemd-resolved は、従来の Linux プログラムとの互換性を保つために /run/systemd/resolve/resolv.conf ファイルを管理しています。このファイルは /etc/resolv.conf からシンボリックリンクされており、常に最新の状態に保たれており、すべての既知の DNS サーバに関する情報を含んでいます。このファイル形式には制限があることに注意してください: このファイルはインターフェイスごとの DNS サーバの概念を知らないので、システム全体の DNS サーバの定義しか含まれていません。/run/systemd/resolve/resolv.conf はアプリケーションによって直接使用されるべきではなく、/etc/resolv.conf からのシンボリックリンクを介してのみ使用されるべきであることに注意してください。この操作モードが使用されている場合、ローカル DNS API をバイパスするローカルクライアントは systemd-resolve もバイパスし、既知の DNS サーバーと直接通信することになります。(DeepL による翻訳)

https://www.man7.org/linux/man-pages/man8/systemd-resolved.service.8.html

ここで /run/systemd/resolve/resolv.conf というファイルが出てきます。この中身を見ると、DNS サーバが 外部 DNS サーバ(AmazonProvidedDNS)が指定されていました。

% cat /run/systemd/resolve/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# 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 must 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.2
search example.com

つまり、/run/systemd/resolve/stub-resolv.conf はスタブリゾルバを利用するための設定ファイルで、/run/systemd/resolve/resolv.conf 外部 DNS サーバを利用するための設定ファイルであるようです。

systemd-resolved でスタブリゾルバを使わないようにする

Ubuntu 18.04 の systemd-resolved で local DNS stub listener の利用をやめる - Qiita に書いてあるとおりにやれば良いです。

# スタブリゾルバを使用しない
% sed -i"" -e "s/.*DNSStubListener=yes/DNSStubListener=no/" /etc/systemd/resolved.conf

# リゾルバファイルのシンボリックリンク先を変更
% cd /etc
% ln -sf ../run/systemd/resolve/resolv.conf resolv.conf

# 再起動して反映
% systemctl restart systemd-resolved.service

これで example.local への名前解決ができるようになりました。

% dig example.local

; <<>> DiG 9.16.1-Ubuntu <<>> example.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: NOERROR, id: 4439
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;example.local.                    IN      A

;; ANSWER SECTION:
example.local.             300     IN      A       10.0.10.10
example.local.             300     IN      A       10.0.11.20

;; Query time: 3 msec
;; SERVER: 10.0.0.2#53(10.0.0.2)
;; WHEN: Fri Jun 05 20:57:59 JST 2020
;; MSG SIZE  rcvd: 60

まとめ

Ubuntu 16.04 LTS から採用された systemd-resolved によって「.local」の名前解決ができない問題について調査し対応しました。
そもそもとして「.local」を使ってはいけないという情報もあるので、ドメイン名が悪いのはたしかなのですが、気軽のドメイン名を変えるのが難しいので systemd-resolved の設定変更で対応することにしました。

参考文献