LabHub
学习 学习路径 课程

网络基础 — 在 Linux 虚拟机里动手

把名字解析的路走到底

在 LabHub 中继续学习

本实验在 VM 中运行

Ubuntu 24.04 由 systemd-resolved 负责名称解析。我们还会使用 dnsmasq 搭建一台自己的 DNS 服务器,在两层之间来回观察名称从哪里获得应答。 dnsmasq 已经安装,但服务处于失败状态——找出原因 就是第 3 步。

目标

通过命令确认 /etc/resolv.conf 中的存根地址是什么、真正的上游服务器在哪里、如何让自己的 DNS 服务器只处理特定域名,以及 /etc/hosts 为什么会 优先于 DNS。

为什么重要

“无法运行”时遇到的第一个岔路口就是名称。但在现代 Linux 中,名称解析 并非只有一层——应用程序调用 libc 的 getaddrinfo,它会 按照 nsswitch.conf 的顺序先查看 /etc/hosts,然后询问 resolv.conf 中的 存根(127.0.0.53),存根再查看各链路的设置并转发到上游。dig 则 只会直接访问其中的最后一个阶段。因此,实际中确实会发生 dig 成功但 curl 失败的 情况,只有知道哪一层存在差异,才能修复问题。

步骤

  1. /etc/resolv.conf 指向的实际文件路径和 nameserver 行保存到 /root/dns/resolv.txt
  2. 将存根实际询问的上游 DNS 服务器地址保存到 /root/dns/upstream.txt,内容为 upstream=<주소> 一行。
  3. 找出 dnsmasq 无法启动的原因,并将显示占用端口 53 的进程的 ss 输出保存到 /root/dns/port53.txt
  4. 为虚拟接口 dns0 添加 10.53.0.1/24,并通过 /etc/dnsmasq.d/lab.conf 让 dnsmasq 只监听 10.53.0.1,为 app.lab.internal10.53.0.10db.lab.internal10.53.0.20 提供应答,然后恢复服务。
  5. dig @10.53.0.1 app.lab.internal 的完整输出保存到 /root/dns/dig.txt
  6. 使用 resolvectldns0 链路指定 DNS 服务器 10.53.0.1 和路由域 ~lab.internal,使 getent hosts app.lab.internal 能够成功,并将 resolvectl status dns0 保存到 /root/dns/link.txt
  7. /etc/hosts 中加入 10.53.0.99 db.lab.internal,并将 getentdig @10.53.0.1 的应答保存到 /root/dns/hosts.txt,内容为 getent=dig= 两行。
  8. /root/dns/report.md 中写入 stub=upstream=local= 三行、dnsmasq 查询日志中包含 app.lab.internal 的一行,以及 /etc/hosts 优先于 DNS 的原因。

参考

resolv.conf 的真实身份

/etc/resolv.conf 指向的实际文件路径和 nameserver 行保存到 /root/dns/resolv.txt

readlink -f /etc/resolv.conf 会给出符号链接末端的真实路径。使用 grep nameserver /etc/resolv.conf 查看存根地址。将两者写入同一个文件。

真正的服务器在哪里

将存根实际询问的上游 DNS 服务器地址保存到 /root/dns/upstream.txt,内容为 upstream=<주소> 一行。

resolvectl status 的链路条目中有 Current DNS Server。它是默认路由接口(enp1s0)的值。resolvectl dns enp1s0 更简短。

dnsmasq 为什么无法启动

找出 dnsmasq 无法启动的原因,并将显示占用端口 53 的进程的 ss 输出保存到 /root/dns/port53.txt

systemctl status dnsmasqjournalctl -u dnsmasq 中有 Address already in use。要确认由谁占用,请使用 ss -ulpn 'sport = :53'——-p 会显示进程名称(必须是 root)。

搭建自己的 DNS 服务器

为虚拟接口 dns0 添加 10.53.0.1/24,并通过 /etc/dnsmasq.d/lab.conf 让 dnsmasq 只监听 10.53.0.1,为 app.lab.internal10.53.0.10db.lab.internal10.53.0.20 提供应答,然后恢复服务。

执行 ip link add dns0 type dummy 后配置地址并设为 UP。配置中使用 listen-address=10.53.0.1bind-interfaces,使其只占用该地址,并像 address=/app.lab.internal/10.53.0.10 这样固定名称。no-resolv 表示不使用上游。完成后执行 systemctl restart dnsmasq,再执行 systemctl is-active dnsmasq

使用 dig 直接查询

dig @10.53.0.1 app.lab.internal 的完整输出保存到 /root/dns/dig.txt

@서버 会忽略 resolv.conf,直接询问该服务器。输出的 ANSWER SECTION 中应显示 A 记录,开头应显示 status: NOERROR

将自己的服务器接入存根

使用 resolvectldns0 链路指定 DNS 服务器 10.53.0.1 和路由域 ~lab.internal,使 getent hosts app.lab.internal 能够成功,并将 resolvectl status dns0 保存到 /root/dns/link.txt

执行 resolvectl dns dns0 10.53.0.1resolvectl domain dns0 '~lab.internal'。带 ~ 的域是一条路由规则,意思是“将对此域的查询发送到此链路的服务器”。使用 getent hosts app.lab.internal 检查——应输出 10.53.0.10。

/etc/hosts 优先

/etc/hosts 中加入 10.53.0.99 db.lab.internal,并将 getentdig @10.53.0.1 的应答保存到 /root/dns/hosts.txt,内容为 getent=dig= 两行。

执行 echo '10.53.0.99 db.lab.internal' >> /etc/hosts。然后执行 getent hosts db.lab.internal | awk '{print $1}'dig @10.53.0.1 db.lab.internal +short。两个值不同——这正是本步骤的要点。

学到了什么

/root/dns/report.md 中写入 stub=upstream=local= 三行、dnsmasq 查询日志中包含 app.lab.internal 的一行,以及 /etc/hosts 优先于 DNS 的原因。

stub 是第 1 步中的 nameserver,upstream 是第 2 步中的值,local 是自己的 dnsmasq 地址。日志使用 journalctl -u dnsmasq --no-pager | grep 'query\[A\] app.lab.internal'。原因中必须包含 nsswitch 或 files 一词。