🔍 第16课:DNS解析

阶段三:网络配置第4/6课

📚 课程目标

一、DNS概述

1.1 DNS解析流程

浏览器 → 本地缓存 → /etc/hosts → DNS解析器 → 递归查询
  │
  │  递归查询路径:
  │  本地DNS → 根DNS服务器 → .com DNS → example.com DNS
  │
  └──→ 返回IP地址: 93.184.216.34

1.2 DNS记录类型

类型说明示例
AIPv4地址example.com. IN A 93.184.216.34
AAAAIPv6地址example.com. IN AAAA 2606:2800:220:1:...
CNAME别名www IN CNAME example.com.
MX邮件交换example.com. IN MX 10 mail.example.com.
NS名称服务器example.com. IN NS ns1.example.com.
TXT文本记录example.com. IN TXT "v=spf1 include:..."
SRV服务记录_sip._tcp IN SRV 10 60 5060 sip.example.com.
PTR反向解析34.216.184.93.in-addr.arpa. IN PTR example.com.

二、Linux DNS配置

2.1 /etc/resolv.conf

$ cat /etc/resolv.conf
# This is /run/systemd/resolve/stub-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 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 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 127.0.0.53
options edns0 trust-ad
search .
# 常用配置
nameserver 8.8.8.8           # DNS服务器
nameserver 8.8.4.4           # 备用DNS
search example.com           # 搜索域
options timeout:2            # 超时2秒
options attempts:3           # 最多重试3次
options rotate               # 轮询DNS服务器

2.2 /etc/hosts

$ cat /etc/hosts
127.0.1.1 localhost.localdomain VM-4-3-ubuntu
127.0.0.1 localhost

::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
# 静态DNS解析,优先级高于DNS查询
# 格式:IP 主机名 [别名]
127.0.0.1       localhost
192.168.1.10    web1.example.com web1
192.168.1.11    web2.example.com web2
192.168.1.100   db1.example.com db1

2.3 NSS解析顺序

$ cat /etc/nsswitch.conf | grep -v '^#' | grep -v '^$'
passwd:         files systemd
group:          files systemd
shadow:         files systemd
gshadow:        files systemd
hosts:          files dns
networks:       files
protocols:      db files
services:       db files
ethers:         db files
rpc:            db files
netgroup:       nis

hosts行决定解析顺序:files dns表示先查/etc/hosts再查DNS。

三、systemd-resolved

$ systemctl status systemd-resolved | head -10
● systemd-resolved.service - Network Name Resolution
     Loaded: loaded (/usr/lib/systemd/system/systemd-resolved.service; enabled; preset: enabled)
     Active: active (running) since Tue 2026-05-19 02:15:52 CST; 19h ago
       Docs: man:systemd-resolved.service(8)
             man:org.freedesktop.resolve1(5)
             https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
             https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
   Main PID: 803 (systemd-resolve)
     Status: "Processing requests..."
      Tasks: 1 (limit: 9127)
# 配置 /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 8.8.4.4
FallbackDNS=1.1.1.1 9.9.9.9
Domains=example.com
LLMNR=no
DNSOverTLS=opportunistic

# 重启服务
sudo systemctl restart systemd-resolved

# 查看DNS统计
resolvectl statistics

# 查询特定域
resolvectl query google.com

四、DNS诊断工具

# dig - 最强大的DNS查询工具
dig google.com                  # 基本查询
dig google.com +short           # 仅返回IP
dig google.com MX               # 查MX记录
dig google.com ANY              # 查所有记录
dig -x 8.8.8.8                  # 反向解析
dig @8.8.8.8 google.com         # 指定DNS服务器
dig google.com +trace           # 跟踪完整解析路径

# nslookup - 简单查询
nslookup google.com
nslookup google.com 8.8.8.8

# host - 简洁输出
host google.com
host -t MX google.com

# 检查DNS传播
# https://dnschecker.org/ 或 dnspython

五、自建DNS服务器(Bind9)

# 安装
sudo apt install bind9 bind9utils

# /etc/bind/named.conf.options
options {
    directory "/var/cache/bind";
    forwarders {
        8.8.8.8;
        8.8.4.4;
    };
    dnssec-validation auto;
};

# 正向区域 /etc/bind/db.example.com
$TTL 604800
@   IN  SOA ns1.example.com. admin.example.com. (
            2024010101  ; Serial
            3600        ; Refresh
            900         ; Retry
            604800      ; Expire
            86400 )     ; Negative Cache TTL
    IN  NS  ns1.example.com.
ns1 IN  A   192.168.1.1
web IN  A   192.168.1.10

# 检查配置
sudo named-checkconf
sudo named-checkzone example.com /etc/bind/db.example.com

六、故障排查

❌ DNS解析失败

# 1. 测试DNS
dig google.com
nslookup google.com

# 2. 检查resolv.conf
cat /etc/resolv.conf

# 3. 检查/etc/hosts
cat /etc/hosts

# 4. 检查resolved状态
systemctl status systemd-resolved

# 5. 刷新DNS缓存
sudo resolvectl flush-caches
sudo systemd-resolve --flush-caches  # 旧版

七、练习

📝 DNS排查实战

# 1. 查询域名解析
dig google.com +short
dig google.com MX

# 2. 反向解析
dig -x 8.8.8.8 +short

# 3. 跟踪解析路径
dig google.com +trace | head -30

# 4. 检查本地DNS配置
cat /etc/resolv.conf
🏆

成就解锁:DNS解析师

✅ 理解DNS解析流程

✅ 掌握Linux DNS配置

✅ 学会dig/nslookup诊断

✅ 了解Bind9自建DNS

八、DNS缓存与性能

# 查看DNS缓存
sudo resolvectl statistics

# 刷新DNS缓存
sudo resolvectl flush-caches

# 启用DNS缓存(dnsmasq)
sudo apt install dnsmasq
# /etc/dnsmasq.conf
server=8.8.8.8
server=8.8.4.4
cache-size=1000
listen-address=127.0.0.1

# 测试DNS性能
dig @127.0.0.1 google.com   # 第一次查询
dig @127.0.0.1 google.com   # 第二次(应更快)

九、DNS over HTTPS (DoH)

# systemd-resolved启用DoH
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com 9.9.9.9#dns.quad9.net
DNSOverTLS=opportunistic

sudo systemctl restart systemd-resolved

十、DNS故障场景

❌ DNS劫持/污染

# 检查DNS响应是否被篡改
dig @8.8.8.8 twitter.com
# 对比不同DNS服务器的结果
dig @1.1.1.1 twitter.com
dig @8.8.8.8 twitter.com

# 使用DNSSEC验证
dig +dnssec example.com

# 使用DoH防止中间人
curl -H 'accept: application/dns-json' 'https://cloudflare-dns.com/dns-query?name=example.com&type=A'

十一、Split DNS配置

# 内外网使用不同DNS解析
# /etc/systemd/resolved.conf
[Resolve]
DNS=10.0.0.1
Domains=internal.example.com

# 外部查询走公共DNS
# /etc/systemd/resolved.conf.d/public.conf
[Resolve]
DNS=8.8.8.8 1.1.1.1

# dnsmasq实现Split DNS
server=/internal.example.com/10.0.0.1
server=/example.com/8.8.8.8
address=/dev.example.com/127.0.0.1

十二、DNS监控脚本

#!/bin/bash
# dns-monitor.sh
DOMAINS="google.com github.com cloudflare.com"
DNS_SERVERS="8.8.8.8 1.1.1.1 9.9.9.9"
ALERT_THRESHOLD=500  # ms

for domain in $DOMAINS; do
    for dns in $DNS_SERVERS; do
        time_ms=$(dig +stats @{$dns} $domain | grep "Query time" | awk '{print $4}')
        if [ "$time_ms" -gt "$ALERT_THRESHOLD" ] 2>/dev/null; then
            echo "⚠️  $domain via $dns: ${time_ms}ms (slow!)"
        else
            echo "✅ $domain via $dns: ${time_ms}ms"
        fi
    done
done

十三、DNS负载均衡

# DNS轮询(Round Robin) - 最简单的负载均衡
# 同一个域名多个A记录
www.example.com. IN A 192.168.1.10
www.example.com. IN A 192.168.1.11
www.example.com. IN A 192.168.1.12

# dig查询会轮流返回不同IP
dig www.example.com +short
# 192.168.1.10
# 192.168.1.11
# 192.168.1.12

# 缺点:无法感知服务器健康状态
# 改进方案:使用GeoDNS或全局负载均衡(GSLB)

十四、DNS排错流程图

DNS解析失败
  │
  ├── 检查 /etc/resolv.conf
  │     ├── nameserver配置正确?
  │     └── 是否被systemd-resolved管理?
  │
  ├── 检查 /etc/hosts
  │     └── 是否有冲突的静态映射?
  │
  ├── 本地DNS测试
  │     ├── dig @127.0.0.1 domain
  │     └── 指定DNS: dig @8.8.8.8 domain
  │
  ├── 网络连通性
  │     ├── ping DNS服务器IP
  │     └── 检查53端口: nc -zv DNS_IP 53
  │
  └── 缓存问题
        ├── resolvectl flush-caches
        └── 重启systemd-resolved

十五、DNS查询优化

# 1. 启用DNS缓存减少查询延迟
# systemd-resolved默认缓存
resolvectl statistics | grep "Cache"

# 2. 使用预取(prefetch)减少过期查询延迟
# Bind9配置
options {
    prefetch 2 9;  # TTL<2秒时预取,9秒后执行
};

# 3. 负面缓存优化
# 减少NXDOMAIN响应的缓存时间
# /etc/systemd/resolved.conf
CacheFromLocalhost=yes

# 4. 并行查询
# 同时查询多个DNS服务器,取最快响应
# /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 1.1.1.1 9.9.9.9

# 5. 本地hosts优化
# 高频域名直接写入/etc/hosts
echo "151.101.1.140 github.global.ssl.fastly.net" | sudo tee -a /etc/hosts
echo "192.30.253.112 github.com" | sudo tee -a /etc/hosts

十六、DNS与CDN集成

CDN通过DNS CNAME将用户请求路由到最近的边缘节点。

# DNS配置CDN
www.example.com. IN CNAME www.example.com.cdn.cloudflare.net.

# 查询CDN解析过程
dig www.example.com +trace
# 可以看到CNAME链和最终IP

# GeoDNS:根据用户地理位置返回不同IP
# 服务商:CloudFlare, AWS Route53, 阿里云DNS, DNSPod

十七、DNSSEC验证

# 检查域名是否启用DNSSEC
dig +dnssec example.com
# 如果有RRSIG记录,说明启用了DNSSEC

# 验证DNSSEC
delv example.com
# 输出 "fully validated" 表示验证通过

# 启用DNSSEC验证(resolved)
# /etc/systemd/resolved.conf
DNSSEC=allow-downgrade