systemd-resolved が BGP Unnumbered 環境で名前解決に失敗する問題

Loopbackインターフェイス以外にグローバルIPアドレスが一切付与されていない状態では、 (たとえネームサーバに正常に疎通できる場合であっても)systemd-resolvedは名前解決に失敗する。

Symptom

  • LoopbackインターフェイスにグローバルIPアドレスを付与している
  • 外部と接続しているネットワークインターフェイスはIPアドレスなし(Unnumbered) or IPv6 LLA(Link-Local Address)のみ
  • デフォルトゲートウェイは外部接続インターフェイスの先のLLA or Unnumbered Next-Hop

Analysys

以下のIssueで説明されている問題と同様であるが、実際にはFixできていないように見える。

systemd-resolved "now complete with from none" while network is up #15532 https://github.com/systemd/systemd/issues/15532

検証した環境のネットワーク設定は以下のとおり (Ubuntu 22.04 with netplan)

ubuntu@sv01:~$ cat /etc/netplan/01-netcfg.yaml
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    lo:
      addresses:
        - 127.0.0.1/8
        - ::1/128
        - XX.XX.XX.1/32
        - 2001:XX:XX::1/128
      nameservers:
        addresses:
          - 2001:0db8::1  # Example
          - 192.0.2.1     # Example
    enp23s0f0:
      addresses:
        - fe80::100:1/64
    enp23s0f1:
      addresses:
        - fe80::100:1/64

ubuntu@sv01:~$ ip -6 route
::1 dev lo proto kernel metric 256 pref medium
2001:XX:XX::1 dev lo proto kernel metric 256 pref medium
fe80::/64 dev enp23s0f0 proto kernel metric 256 pref medium
fe80::/64 dev enp23s0f1 proto kernel metric 256 pref medium
fe80::/64 dev eno1 proto kernel metric 256 linkdown pref medium
default proto bird src 2001:XX:XX::1 metric 32 pref medium        # BGP Default route
        nexthop via fe80::1 dev enp23s0f0 weight 1
        nexthop via fe80::2 dev enp23s0f1 weight 1
default proto ra metric 1024 expires 1780sec mtu 1500 pref medium # RA Default route (lower prority)
        nexthop via fe80::2 dev enp23s0f1 weight 1
        nexthop via fe80::1 dev enp23s0f0 weight 1

ubuntu@sv01:~$ ip route
default proto bird src XX.XX.XX.1 metric 32                       # BGP Default route
        nexthop via inet6 fe80::1 dev enp23s0f0 weight 1
        nexthop via inet6 fe80::2 dev enp23s0f1 weight 1

ubuntu@sv01:~$ resolvectl
Global
         Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: foreign                 # 問題の再現には影響なし
Current DNS Server: 2001:0db8::1
       DNS Servers: 2001:0db8::1 192.0.2.1

Link 2 (enp23s0f0)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 3 (eno1)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported

Link 4 (enp23s0f1)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
  :

この状態において、DNSサーバへの疎通性は問題ないことを確認している。

ubuntu@sv01:~$ dig google.com @2001:0db8::1

; <<>> DiG 9.18.12-0ubuntu0.22.04.2-Ubuntu <<>> google.com @2001:0db8::1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59767
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
google.com.             119     IN      A       142.250.207.46

;; Query time: 0 msec
;; SERVER: 2001:0db8::1#53(2001:0db8::1) (UDP)
;; WHEN: Thu Sep 07 16:51:59 JST 2023
;; MSG SIZE  rcvd: 55

systemd-resolved は、この状態では <network-down>と判定していまい、名前解決に失敗する。

ubuntu@sv01:~$ resolvectl query google.com
google.com: resolve call failed: Network is down

# 明示的にLoopbackインターフェイスを指定してもだめ
ubuntu@sv01:~$ resolvectl -i lo query google.com
google.com: resolve call failed: No appropriate name servers or networks for name found

ubuntu@sv01:~$ resolvectl status lo
Link 1 (lo)
Current Scopes: none
     Protocols: -DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
   DNS Servers: 2001:0db8::1 192.0.2.1

systemd-resolved は、Loopbackインターフェイスに default-route フラグを付与することはできない。

ubuntu@sv01:~$ resolvectl default-route
Global
         Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: foreign
Current DNS Server: 2001:0db8::1
       DNS Servers: 2001:0db8::1 192.0.2.1
Link 2 (enp23s0f0): no
Link 3 (eno1): no
Link 4 (enp23s0f1): no
Link 5 (eno3): no
Link 6 (eno2): no
Link 7 (eno4): no

ubuntu@sv01:~$ resolvectl default-route lo
Link 1 (lo): no

ubuntu@sv01:~$ resolvectl default-route lo yes
Failed to set default route configuration: Link lo is loopback device.

Issue では以下のパッチで修正されただろうと述べている。パッチは当たっているものの、実際には修正されていないように見える
https://github.com/systemd/systemd/commit/90bdc8be66765df09bbc355783cee7204a5ebb31

ubuntu@sv01:~$ systemd --version
systemd 249 (249.11-0ubuntu3.9)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY -P11KIT -QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified

# Source packageで実際にパッチが当たっていることを確認する
ubuntu@sv01:~$ apt list --installed | grep ^systemd/
systemd/jammy-updates,now 249.11-0ubuntu3.9 amd64 [installed]
ubuntu@sv01:~$ apt source systemd=249.11-0ubuntu3.9
  : 
ubuntu@sv01:~$ cd systemd-249.11
ubuntu@sv01:~/systemd-249.11$ grep -r "dns_query_candidate_is_routable"
ubuntu@sv01:~/systemd-249.11$ # 確かにパッチは適用されている

Resolution

これでいいのだ

root@sv01:/# unlink /etc/resolv.conf
root@sv01:/# cat > /etc/resolv.conf
nameserver 2001:0db8::1   # Example
nameserver 192.0.2.1      # Example
^D

ローカルにフルリゾルバ入れるなら個人的には dnsmasq や dbndns のほうが好きだ。