坑边闲话:Debian 12 是一个完善的高级系统,在 DNS 方面,它同时支持 NetworkManagersystemd,而此二者在网络管理方面具有重叠的功能,同时启用会产生冲突。

1. 本机 DNS 配置·

一般来说,Debian 12 系统遵循大多数 Linux 采用的 DNS 配置方法,即 DNS 服务器地址、搜索域都被写在 /etc/resolv.conf 文件里。一个常见的配置文件如下所示:

1
2
nameserver 127.0.0.53
search littlenewton.cn

接下来讲解这几个网段的意思:

  • nameserver 指的是 DNS 服务器的地址,比如
    • Google 8.8.8.8
    • DNSPod 119.29.29.29
    • Cloudflare 1.1.1.1
    • 本机的某个服务,如 dnsmasqAdGuard Homesystemd-resolved 等。这些软件会在本地起一个服务端口,允许其他进程通过 TCP/IP 方式发起 DNS 请求,因此填写的一般是 127.0.0.0/8 地址。
    • 此外,多个 nameserver 可以同时填写,彼此之间使用 ,分割。
  • search 指的是搜索域,如果你在解析的时候没有写 FQDN 域名,而是只写了 host-name,则系统会将搜索域作为 host-name 的后缀,拼接后再解析。比如,nslookup epyc-truenas 时,系统会自动添加后缀 littlenewton.cn 得到 epyc-truenas.littlenewton.cn,随后解析之。在内网里这是相当方便的设计!

一般来说,所有的系统软件都会根据 /etc/resolv.conf 中的配置进行 DNS 查询,这已经是几十年的传统了。

2. systemd DNS 配置·

2.1 systemd-resolved·

systemd-resolvedsystemd 套件中的 DNS 解析服务器。与传统的 DNS 解析器相比,具有以下优势:

  • 缓存支持:它内置了一个小型的缓存,可以减少 DNS 查询的延迟和网络流量。
  • DNSSEC 支持:默认支持 DNSSEC(DNS 安全扩展),能验证收到的 DNS 回复的真实性和完整性。
  • Multicast DNS (mDNS) 支持:它可以在本地网络上解析 .local 域名,无需额外的服务或配置。
  • Link-Local Multicast Name Resolution (LLMNR) 支持:这允许未注册的名称在本地网络上被解析,有助于在没有 DNS 服务器的情况下解析本地名称。
  • DNS over TLS (DoT) 支持:这提供了在网络间增强的隐私和安全,因为 DNS 查询和回复都是加密的。
  • 切换 DNS 服务器:当多个 DNS 服务器可用时,例如在有多个网络连接或 VPN 的情况下,systemd-resolved 可以智能地切换和选择哪个服务器用于查询。
  • 网络特定的域名解析:允许基于网络连接为特定的域配置不同的 DNS 服务器。例如,可以为 VPN 连接配置专用的 DNS 服务器。
  • 集成与 systemd 相关的网络配置:它与 systemd-networkd 紧密集成,为复杂的网络配置提供了一种一致的方式。
  • 提供 D-Bus 接口:它提供了 D-Bus 接口,允许其他应用程序与其交互和查询 DNS.
  • 依旧与 /etc/resolv.conf 文件兼容:尽管 systemd-resolved 提供了很多高级功能,但它仍然与传统的 /etc/resolv.conf 文件兼容。

systemd-resolved 的配置文件是 /etc/systemd/resolved.conf,该文件使用 systemd 配置语法。现提供一个简单的方案供参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#  This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# Entries in this file show the compile time defaults. Local configuration
# should be created by either modifying this file, or by creating "drop-ins" in
# the resolved.conf.d/ subdirectory. The latter is generally recommended.
# Defaults can be restored by simply deleting this file and all drop-ins.
#
# Use 'systemd-analyze cat-config systemd/resolved.conf' to display the full config.
#
# See resolved.conf(5) for details.

[Resolve]
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com
# Google: 8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
# Quad9: 9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
DNS=10.2.2.10
FallbackDNS=8.8.8.8 119.29.29.29
Domains=littlenewton.cn
#DNSSEC=no
#DNSOverTLS=no
#MulticastDNS=yes
#LLMNR=yes
#Cache=yes
#CacheFromLocalhost=no
#DNSStubListener=yes
#DNSStubListenerExtra=
#ReadEtcHosts=yes
#ResolveUnicastSingleLabel=no

其中有几个要点:

  • DNS:可以填写多个以空格为分隔的 IP 地址,此时 systemd-resolved 会进行并发查询,以最先反馈的为准。如果你不希望这样做,就只需要写一个地址。由于我的 DNS 是由 OpenClash 负责,所以我写路由器的地址 10.2.2.10,至于我的路由器的配置细节,就是另外的故事了。
  • FallbackDNS:由于 DNS 有可能失效,比如我的路由器 DNS 对外服务宕掉,就可以启用 FallbackDNS 指示的 DNS 服务器。
  • Domains:类似于 /etc/resolv.conf 中的 search 字段。这里我写的是自己持有的域名。

由此可见,systemd-resolved 的逻辑如下:

1
2
3
4
5
6
7
8
                              指导生成
/etc/systemd/resolved.conf ------------> /run/systemd/resolve/stub-resolv.conf
|
| 软
| 链
| 接
v
/etc/resolv.conf

通过以下命令组合可实现兼容传统配置的新配置:

1
2
3
sudo vim /etc/systemd/resolved.conf
# ... 修改配置
sudo systemctl restart systemd-resolved

2.2 最佳实践·

由于我的网络是通过 WireGuard IPv6 隧道组成的异地大内网,因此有如下配置。 图 1. 以 WireGuard 协议为基石构建了内网,尽管有不同网段,彼此之间需要路由进行协调,但是用起来已经没有不舒服的地方。这得益于 Allowed-IP 的配置。 最佳实践:流量优先级 IPv6 直连 = WireGuard 内网 >= Tailscale 连接。下面解释原因。

  • IPv6 优先级是最高的。
    • 因为 IPv6 的防火墙策略还不够完善,用户能享有比较高的网络性能,虽然不知道什么时候监管升级,但是最近两年,IPv6 的体验非常不错。在这里吐槽一下各个运营商恶心的 QoS 机制以及地址分发策略
  • WireGuard 优先级同样最高。
    • 由于 WireGuard 采用内核级实现,而且是通过 IPv6 建立隧道,所以可以认为 WireGuard 隧道与 IPv6 直连区别不大。
  • Tailscale 作为保底方案。
    • Tailscale 的 fallback 机制会使用海外中转服务器,因此有一定概率产生较大延迟。虽然 Tailscale 一般都能 NAT 打洞成功,但是万一失败了呢?Tailscale 建立的 Full-Mesh 网络是最后的保障,毕竟 Tailscale 会尽力保持连接,而 WireGuard 和 IPv6 是 P2P 且无回退的极客方案。
    • Tailscale 在大多数情况下也会使用 WireGuard 内网地址,因此两层 WireGuard 协议封装没有意义,徒增功耗
    • Tailscale 自建中转 DERP 服务也可以,但是其难易程度与自建 WireGuard 相当,甚至 WireGuard 建立起来更简单一些。因此除非有特殊需求,不要自己搞 DERP 服务。

现在总有人嘲讽,认为 systemd 集成了太多的东西,甚至颇有点儿 Systemd-OS 的感觉。但是我个人认为完全不必担心,因为软件本身并非 monolithic,其本质必然也是在一个封闭的小区域里做模块化设计。

2.3 resolvectl 常用技能·

清空 DNS 缓存:

1
sudo resolvectl flush-caches

3. Tailscale·

参考

3.1 MagicDNS 兼容性·

Tailscale 是基于 WireGuard 协议构建的网络连接技术,它使得在任何网络设备间创建安全、端到端加密的点对点连接变得简单。使用 Tailscale 构建的大内网一般称为 Tailnet.

MagicDNS 是 Tailscale 提供的一个功能,它允许自动解析 Tailnet 里的设备的 DNS 名称。MagicDNS 的基本原理如下:

  • 自动生成 DNS 记录:当设备加入 Tailnet 时,它会为设备自动生成一个 DNS 记录。例如,如果设备的名称是 my-device,Tailscale 会为其生成 my-device.xxx.ts.net 这样的 DNS 名称。
  • 本地 DNS 重写:Tailscale 客户端会拦截发往 .ts.net 后缀的 DNS 请求,并重写为 Tailnet 内的对应 IP 地址。这意味着,当你尝试连接到 my-device.xxx.ts.net 时,Tailscale 客户端会直接返回该设备在 Tailnet 上的 IP 地址,而无需通过外部 DNS 服务器。
  • 与其他 DNS 解析器集成:为了使其与其他 DNS 解析器(如 systemd-resolvedNetworkManager 或传统的 resolv.conf)集成,Tailscale 可能会修改系统的 DNS 设置,使其使用 Tailscale 提供的 DNS 服务器作为首选 DNS.
  • Split DNS:Tailscale 支持分裂 DNS,这意味着它可以根据请求的域名来决定是否应该通过 Tailnet 或公共网络进行查询。这对于混合云环境或需要访问内部网络资源的场景特别有用。
  • 与云 DNS 服务集成:Tailscale 还允许与例如 Google Cloud DNS、AWS Route 53 等云 DNS 服务集成,从而提供更为灵活的 DNS 解析策略。

因此,在修改了 systemd-resolved 的配置文件并重启服务后,还需要重启 tailscaled 服务,以使得 MagicDNS 重新集成。命令如下:

1
2
3
4
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
sudo systemctl restart NetworkManager
sudo systemctl restart tailscaled

3.2 最佳实践(续)·

如此,有几个好处:

  • 由于 Domains 字段是 littlenewton.cn 在前,xxx.ts.net 在后,因此在使用主机名直接解析的时候,会优先使用 host-name.littlenewton.cn,而这个地址我已经在局域网的 DNS 服务器做了重写,直接获得的是 WireGuard 内网地址,优先级最高
  • 如果使用 host-name-v6 发起解析,将会请求 host-name-v6.littlenewton.cn,获得的是 AAAA 记录,即 IPv6 地址,优先级也最高。
  • 如果本地 DNS 服务器宕机,则查无此 IP,系统将会使用 Tailscale MagicDNS 查询,使用 Full-Mesh 的 Tailnet 进行连接。由此可见,无论怎么处理,连接优先级都能按照我们设想的完成解析,而优先级本身与连接的带宽、可靠性呈正相关。

4. NetworkManager 兼容性·

我一般是用 NetworkManager 配置接口地址,不使用它做 DNS 解析,因此 NetworkManagersystemd-resolved 可以共存。

图 2. NetworkManager 提供的 nmtui 命令也可以对接口进行定义,特别是 DNS 部分。通过 NetworkManager 可以对某个接口上的 DNS 服务器做特殊限定。

总结·

本文详细介绍了在 Debian 12 环境下配置网络 DNS 的实践,其中最关键的是 Tailnet,这在国际环境下非常重要。