服务器运维笔记(03):DNS 与域名管理

DNS(Domain Name System)是互联网的"电话簿"——它把人类可读的域名翻译成机器可读的 IP 地址。对于服务器运维工程师来说,DNS 不仅是"能用就行"的基础配置,更是影响可用性、性能和安全的关键基础设施。

本篇从原理到实战,系统梳理 DNS 与域名管理的核心知识。


一、DNS 基础

1.1 DNS 查询流程

一次完整的 DNS 解析经历以下路径:

客户端 → 本地缓存 → 递归解析器 → 根域名服务器 → TLD 服务器 → 权威域名服务器 → 返回结果

1.2 递归查询 vs 迭代查询

类型

说明

典型场景

递归查询

客户端向递归解析器发出请求,解析器负责完成全部查询流程并返回最终结果

浏览器 → 本地 DNS(如 8.8.8.8)

迭代查询

解析器逐级向各域名服务器查询,每次获得"下一步该问谁"的提示

递归解析器 → 根/TLD/权威服务器

实际观察递归查询过程:

# 使用 dig +trace 追踪完整解析链路
dig +trace example.com

# 输出示例:
# .                    518400  IN  NS  a.root-servers.net.
# com.                 172800  IN  NS  a.gtld-servers.net.
# example.com.         172800  IN  NS  a.iana-servers.net.
# example.com.         86400   IN  A   93.184.216.34

1.3 权威域名服务器

权威服务器是某个域名的"官方数据源",存储该域名的原始 DNS 记录。

# 查询某个域名的权威 NS 记录
dig NS example.com +short
# a.iana-servers.net.
# b.iana-servers.net.

# 直接向权威服务器查询(绕过缓存)
dig @a.iana-servers.net example.com A

1.4 DNS 缓存机制

DNS 缓存存在于多个层级,由 TTL(Time To Live)控制有效期:

缓存层级

位置

清除方式

浏览器缓存

Chrome/Firefox 等

清除浏览器数据或 chrome://net-internals/#dns

OS 缓存

操作系统 DNS 缓存

见下方命令

递归解析器缓存

ISP DNS / 公共 DNS

等待 TTL 过期

# 清除本地 DNS 缓存
# macOS
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder

# Windows
ipconfig /flushdns

# systemd-resolved(Ubuntu 18.04+)
sudo systemd-resolve --flush-caches

# 查看缓存统计
sudo systemd-resolve --statistics

二、记录类型详解

2.1 A 记录 —— IPv4 地址映射

将域名指向一个 IPv4 地址,是最基础的 DNS 记录。

# 查询 A 记录
dig A example.com +short
# 93.184.216.34

# 配置示例(BIND zone 文件)
# example.com.  IN  A  93.184.216.34
# www           IN  A  93.184.216.34

2.2 AAAA 记录 —— IPv6 地址映射

# 查询 AAAA 记录
dig AAAA example.com +short
# 2606:2800:220:1:248:1893:25c8:1946

# 配置示例
# example.com.  IN  AAAA  2606:2800:220:1:248:1893:25c8:1946

2.3 CNAME 记录 —— 别名

将一个域名指向另一个域名,最终解析到目标域名的 A/AAAA 记录。

# 查询 CNAME
dig CNAME blog.example.com +short
# example.github.io.

# ⚠️ 注意:CNAME 不能与其他记录共存(同一名称下)
# 错误示例:blog.example.com 同时有 CNAME 和 MX 记录
# RFC 规定 CNAME 与其他记录互斥,但 ALIAS/ANAME 可以规避此限制

常见用途:

# CDN 加速域名
cdn.example.com    CNAME   cdn.provider.com.

# 第三方服务验证
_sip._tcp.example.com  SRV  ...

# GitHub Pages
www.example.com    CNAME   username.github.io.

2.4 MX 记录 —— 邮件交换

指定负责处理该域名邮件的服务器,带有优先级。

# 查询 MX 记录
dig MX example.com +short
# 10 mail.example.com.
# 20 mail2.example.com.

# 配置示例
# example.com.  IN  MX  10 mail.example.com.
# example.com.  IN  MX  20 mail2.example.com.

# 测试邮件服务器连通性
telnet mail.example.com 25

常见邮件服务商 MX 配置:

服务商

MX 记录

优先级

Google Workspace

aspmx.l.google.com

1

Microsoft 365

example-com.mail.protection.outlook.com

0

阿里企业邮

mx1.mxhichina.com

5

腾讯企业邮

mxbiz1.qq.com

5

2.5 TXT 记录 —— 文本信息

用于域名验证、SPF、DKIM、DMARC 等。

# SPF 记录(防止邮件伪造)
# example.com.  IN  TXT  "v=spf1 include:_spf.google.com ~all"

# DKIM 记录
# google._domainkey.example.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIGf..."

# DMARC 记录
# _dmarc.example.com.  IN  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

# 域名所有权验证(常见服务商)
# _dnsauth.example.com.  IN  TXT  "202306101200005abc..."

2.6 SRV 记录 —— 服务发现

指定特定服务的主机和端口,格式为 _service._proto.domain

# 查询 SRV 记录
dig SRV _sip._tcp.example.com +short
# 10 60 5060 sip1.example.com.
# 20 60 5060 sip2.example.com.

# 格式:优先级 权重 端口 目标主机
# _sip._tcp.example.com.  IN  SRV  10 60 5060 sip1.example.com.

2.7 NS 记录 —— 域名服务器

指定该域名由哪些 DNS 服务器解析。

dig NS example.com +short
# a.iana-servers.net.
# b.iana-servers.net.

2.8 SOA 记录 —— 起始授权

每个 DNS 区域的核心记录,包含序列号、刷新间隔等管理信息。

dig SOA example.com +short
# a.iana-servers.net. hostmaster.iana.org. 2023061001 3600 900 604800 86400

# 字段含义:
# 主DNS  管理员邮箱  序列号  刷新间隔  重试间隔  过期时间  最小TTL

2.9 CAA 记录 —— 证书颁发机构授权

限制哪些 CA 可以为该域名签发证书,提升 TLS 安全性。

# 查询 CAA 记录
dig CAA example.com +short
# 0 issue "letsencrypt.org"
# 0 issuewild "letsencrypt.org"
# 0 iodef "mailto:security@example.com"

# 配置示例
# example.com.  IN  CAA  0 issue "letsencrypt.org"        # 允许签发
# example.com.  IN  CAA  0 issuewild "letsencrypt.org"     # 允许通配符签发
# example.com.  IN  CAA  0 iodef "mailto:ca-alerts@example.com"  # 违规通知

2.10 PTR 记录 —— 反向解析

将 IP 地址映射回域名,常用于邮件服务器验证。

# 反向解析查询
dig -x 93.184.216.34 +short
# example.com.

# ⚠️ PTR 记录需要在 IP 所属的 ISP/托管商处配置,不能在域名 DNS 面板设置
# 配置方式:在云服务器控制台的"反向解析"或"rDNS"功能中设置

三、常见 DNS 服务商配置

3.1 阿里云 DNS

控制台: dns.console.aliyun.com

配置要点:

# 1. 域名添加后,需将 NS 记录修改为阿里云分配的 DNS 服务器
#    例如:dns1.hichina.com / dns2.hichina.com

# 2. 添加解析记录示例
# 主机记录: www
# 记录类型: A
# 记录值: 47.100.1.1
# TTL: 600

# 3. 智能解析(按运营商/地域分线路)
# 默认线路: 47.100.1.1(阿里云 ECS)
# 电信线路: 114.114.1.1
# 联通线路: 202.106.0.1

# 4. API 操作(阿里云 OpenAPI)
# 安装 SDK
pip install alibabacloud-alidns20150109

API 自动化示例:

# 通过 API 自动更新动态 DNS 记录
from alibabacloud_alidns20150109.client import Client
from alibabacloud_alidns20150109 import models

config = Config(
    access_key_id="YOUR_AK",
    access_key_secret="YOUR_SK",
    endpoint="alidns.cn-hangzhou.aliyuncs.com"
)
client = Client(config)

# 更新 A 记录
request = models.UpdateDomainRecordRequest(
    record_id="12345678",
    RR="www",
    type="A",
    value="47.100.1.2"
)
client.update_domain_record(request)

3.2 腾讯云 DNS

控制台: console.cloud.tencent.com/cns

配置要点:

# 1. NS 修改:指向腾讯云 DNSPod 服务器
#    f1g1ns1.dnspod.net / f1g1ns2.dnspod.net

# 2. 记录管理(控制台)
# 主机记录: @     记录类型: A    记录值: 1.2.3.4    TTL: 600
# 主机记录: www   记录类型: CNAME 记录值: example.com  TTL: 600

# 3. DNSPod 特色功能
#    - 子域名递归解析
#    - URL 转发(显性/隐性)
#    - 搜索引擎推送

# 4. API 操作
pip install tencentcloud-sdk-python-dnspod

API 自动化示例:

from tencentcloud.dnspod.v20210323 import dnspod_client, models
import json

cred = credential.Credential("SecretId", "SecretKey")
client = dnspod_client.DnspodClient(cred, "ap-guangzhou")

# 修改记录
req = models.ModifyRecordRequest()
req.Domain = "example.com"
req.RecordId = 12345678
req.RecordType = "A"
req.RecordLine = "默认"
req.Value = "1.2.3.5"
client.ModifyRecord(req)

3.3 Cloudflare DNS

控制台: dash.cloudflare.com

配置要点:

# 1. 添加站点后,Cloudflare 会分配两个 NS 服务器
#    例如:aria.ns.cloudflare.com / ben.ns.cloudflare.com

# 2. 代理模式(橙色云朵 vs 灰色云朵)
#    🟠 橙色云朵:流量经过 Cloudflare 代理(CDN/WAF/DDoS 防护)
#    ⚪ 灰色云朵:仅 DNS 解析,不经过代理

# 3. Cloudflare 独有功能
#    - CNAME Flattening(根域名 CNAME 支持)
#    - Page Rules(基于 URL 的 DNS 策略)
#    - DNSSEC 一键开启
#    - Argo Smart Routing(智能路由加速)

# 4. API 操作
# 获取 Zone ID
curl -X GET "https://api.cloudflare.com/client/v4/zones?name=example.com" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json"

# 添加 A 记录
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "A",
    "name": "www",
    "content": "1.2.3.4",
    "ttl": 600,
    "proxied": true
  }'

3.4 三家服务商对比

特性

阿里云 DNS

腾讯云 DNSPod

Cloudflare

免费解析记录数

10 条

10 条

无限

最低 TTL

1 秒(付费)

1 秒(付费)

1 秒(自动)

DNSSEC

支持

支持

一键开启

智能解析

运营商/地域

运营商/地域

Geo(付费)

DDoS 防护

高防 DNS(付费)

DNS 防护(免费基础)

免费包含

API 丰富度

★★★★

★★★★

★★★★★


四、CDN 接入与 CNAME 配置

4.1 CDN 接入原理

CDN 接入的核心是将域名通过 CNAME 指向 CDN 分配的加速域名,由 CDN 的 DNS 调度系统将用户引导至最近的边缘节点。

用户请求 → DNS 解析 www.example.com → CNAME → cdn.example.com → CDN 调度 → 最近节点 IP

4.2 主流 CDN 接入配置

阿里云 CDN:

# 1. 添加加速域名:www.example.com
# 2. CDN 分配 CNAME:www.example.com.cdn.dnsv1.com
# 3. 在 DNS 中添加 CNAME 记录
#    主机记录: www
#    记录类型: CNAME
#    记录值: www.example.com.cdn.dnsv1.com

# 验证 CNAME 是否生效
dig CNAME www.example.com +short
# www.example.com.cdn.dnsv1.com.

Cloudflare CDN(代理模式):

# Cloudflare 使用代理模式接入,不需要手动配置 CNAME
# 1. 添加 A 记录指向源站 IP
#    www → 1.2.3.4(橙色云朵开启)
# 2. Cloudflare 自动代理流量

# 关闭代理(仅 DNS 模式)时,才需要 CNAME 指向第三方 CDN

腾讯云 CDN:

# 1. 添加域名:www.example.com
# 2. 获取 CNAME:www.example.com.cdn.dnsv1.com
# 3. DNSPod 中配置:
#    www → CNAME → www.example.com.cdn.dnsv1.com

4.3 根域名(@)的 CDN 接入

根域名不能直接使用 CNAME(RFC 限制),解决方案:

# 方案一:使用 ALIAS/ANAME 记录(阿里云、DNSPod 支持)
# 记录类型: 显性URL / 隐性URL
# 记录值: https://www.example.com

# 方案二:Cloudflare CNAME Flattening
# Cloudflare 会将根域名的 CNAME "扁平化"为 A/AAAA 记录返回

# 方案三:使用 DNS 服务商的 ALIAS 记录
# 阿里云:将 @ 的 CNAME 记录改为 ALIAS 类型
# DNSPod:使用 @ 的 CNAME 记录(自动扁平化)

# 方案四:直接使用 A 记录指向 CDN Anycast IP

五、DNS 负载均衡

5.1 加权轮询(Weighted Round Robin)

按权重比例分配流量到不同服务器。

# 阿里云加权轮询配置
# www  A  记录值: 1.2.3.4  权重: 70  线路: 默认
# www  A  记录值: 5.6.7.8  权重: 30  线路: 默认

# Cloudflare 负载均衡(Load Balancing 功能)
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/load_balancers" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  --data '{
    "name": "www.example.com",
    "fallback_pool": "pool-backup",
    "default_pools": ["pool-primary", "pool-secondary"],
    "steering_policy": "weighted",
    "session_affinity": "cookie"
  }'

5.2 地理路由(GeoDNS)

根据用户所在地区返回不同的 IP 地址。

# PowerDNS GeoIP 配置示例(geoipbackend)
# /etc/pdns/geoip.yaml
domains:
  - domain: example.com
    ttl: 300
    records:
      www:
        - a:
            - 1.2.3.4        # 默认(亚洲)
            - 5.6.7.8        # 欧洲
            - 9.10.11.12     # 北美
        - a:
            default: 1.2.3.4
            eu: 5.6.7.8
            na: 9.10.11.12
            cn: 47.100.1.1   # 中国

阿里云智能解析(简化版 GeoDNS):

# 运营商线路解析
www  A  47.100.1.1    线路: 电信
www  A  119.29.1.1    线路: 联通
www  A  101.226.1.1   线路: 移动

# 地域线路解析(付费版)
www  A  47.100.1.1    线路: 华东
www  A  119.29.1.1    线路: 华南
www  A  101.226.1.1   线路: 华北

5.3 故障转移(Failover)

当主服务器不可用时,自动切换到备用服务器。

# Cloudflare Load Balancing 健康检查配置
curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/pools" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  --data '{
    "name": "pool-primary",
    "origins": [
      {"name": "primary", "address": "1.2.3.4", "enabled": true},
      {"name": "secondary", "address": "5.6.7.8", "enabled": true}
    ],
    "minimum_origins": 1,
    "monitor": {
      "type": "https",
      "expected_codes": "200",
      "method": "GET",
      "path": "/health",
      "interval": 60,
      "timeout": 5,
      "retries": 2
    }
  }'

# DNS 服务商的故障转移(需付费支持)
# 阿里云:全局流量管理(GTM)
# 腾讯云:DNSPod 企业版 Failover

简单的脚本实现(基于 DNS API 的故障转移):

#!/bin/bash
# health_check_failover.sh - 简易 DNS 故障转移脚本
PRIMARY="1.2.3.4"
BACKUP="5.6.7.8"
DOMAIN="www.example.com"

while true; do
    if ! curl -sf --max-time 5 "http://${PRIMARY}/health" > /dev/null; then
        echo "[$(date)] Primary down, switching to backup..."
        # 调用 DNS API 切换记录(以阿里云为例)
        aliyun alidns UpdateDomainRecord \
          --RecordId "12345678" \
          --RR "www" \
          --Type "A" \
          --Value "${BACKUP}"
    fi
    sleep 30
done

六、DNSSEC 原理与配置

6.1 DNSSEC 工作原理

DNSSEC 通过数字签名保护 DNS 响应的完整性和真实性,防止 DNS 缓存投毒攻击。

信任链:
根域(.)→ 签发 → TLD(.com)→ 签发 → 域名(example.com)→ 签发 → 记录

关键记录:
- DNSKEY:存储公钥,用于验证签名
- RRSIG:资源记录签名,每条记录对应一个签名
- DS:Delegation Signer,父域存储的子域 DNSKEY 哈希
- NSEC/NSEC3:用于证明"域名不存在"(Authenticated Denial)

6.2 Cloudflare DNSSEC 一键配置

# Cloudflare 配置 DNSSEC 最简单
# 1. 控制台:DNS → Settings → Enable DNSSEC
# 2. Cloudflare 自动生成密钥对
# 3. 在域名注册商处添加 DS 记录(Cloudflare 提供具体值)

# 通过 API 启用
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dnssec" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  --data '{"status": "active"}'

# 获取 DS 记录信息(添加到注册商)
curl -X GET "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dnssec" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

6.3 手动配置 DNSSEC(BIND)

# 1. 生成 ZSK(Zone Signing Key)
dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com

# 2. 生成 KSK(Key Signing Key)
dnssec-keygen -a ECDSAP256SHA256 -n ZONE -f KSK example.com

# 3. 将密钥包含到 zone 文件
# $INCLUDE "Kexample.com.+013+12345.key"
# $INCLUDE "Kexample.com.+013+67890.key"

# 4. 签名 zone 文件
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) \
  -N INCREMENT -o example.com -t example.com.zone

# 5. 验证签名
dnssec-verify -o example.com example.com.zone.signed

# 6. 更新 BIND 配置,加载签名后的 zone 文件
# 7. 在注册商处添加 DS 记录
dnssec-dsfromkey -f Kexample.com.+013+67890.key example.com

6.4 验证 DNSSEC

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

# 检查 DS 记录
dig DS example.com +short

# 使用在线工具验证
# https://dnssec-analyzer.verisignlabs.com/example.com
# https://dnsviz.net/d/example.com/dnssec/

# 使用 delv 工具深入验证
delv @8.8.8.8 example.com A +rtrace

七、子域名管理策略

7.1 通配符域名

通配符(Wildcard)记录匹配所有未明确定义的子域名。

# 通配符 A 记录
# *.example.com  IN  A  1.2.3.4

# 测试通配符
dig test123.example.com +short
# 1.2.3.4

# ⚠️ 注意事项:
# 1. 通配符不会匹配已明确定义的子域名
# 2. 通配符只匹配一级子域名(*.example.com 不匹配 a.b.example.com)
# 3. 需要多级匹配时,每级都要单独配置通配符

安全风险提醒:

# 通配符 + 泛解析可能导致子域名接管风险
# 攻击者可以通过 CNAME 指向已接管的第三方服务
# 建议:避免使用通配符,使用明确的子域名列表

# 使用 amass/subfinder 扫描暴露的子域名
amass enum -d example.com -o subdomains.txt
subfinder -d example.com -silent

7.2 泛解析的实际应用

# 场景一:SaaS 平台多租户
# 每个租户分配子域名:tenant1.example.com, tenant2.example.com
# 使用通配符 + 应用层路由实现

# 场景二:开发环境
# *.dev.example.com → 开发服务器
# dev.example.com   → 开发环境入口

# 场景三:短链接服务
# 通配符指向短链接服务器,应用层解析路径

# BIND 配置示例
# $ORIGIN example.com.
# *          IN  A    1.2.3.4
# @          IN  A    1.2.3.4
# www        IN  A    1.2.3.5   # 明确定义,不受通配符影响

7.3 多级子域管理

# 常见的子域名分层策略
# 主站:     example.com
# 国家站:   cn.example.com, us.example.com
# 环境:     staging.example.com, dev.example.com
# 服务:     api.example.com, app.example.com, admin.example.com
# 团队:     team-a.dev.example.com, team-b.dev.example.com

# 子域名委派(将子域的 DNS 管理权限交给其他 DNS 服务器)
# dev.example.com.  IN  NS  ns1.dev.internal.
# dev.example.com.  IN  NS  ns2.dev.internal.
# 这样 dev 团队可以独立管理 *.dev.example.com

7.4 子域名安全加固

# 1. 使用 CAA 记录限制证书颁发
# *.example.com  IN  CAA  0 issue "letsencrypt.org"

# 2. 定期扫描子域名
# 使用 crt.sh 查询证书透明度日志
curl -s "https://crt.sh/?q=%.example.com&output=json" | jq '.[].name_value' | sort -u

# 3. 监控新增子域名
# 设置告警:当发现新的 DNS 记录时通知

八、DNS 诊断工具

8.1 dig —— DNS 查询瑞士军刀

# 基本查询
dig example.com A

# 指定 DNS 服务器
dig @8.8.8.8 example.com A

# 查询所有记录类型
dig example.com ANY

# 精简输出
dig example.com +short

# 追踪解析路径
dig example.com +trace

# 查看完整响应(包含 TTL、flags 等)
dig example.com +noall +answer +comments

# 批量查询
dig -f domains.txt +short

# 查询特定类(CH=Chaosnet, 用于查询 BIND 版本)
dig @ns1.example.com CH TXT version.bind

# TCP 查询(而非默认的 UDP)
dig example.com +tcp

8.2 nslookup —— 交互式查询

# 交互模式
nslookup
> server 8.8.8.8
> set type=MX
> example.com
> exit

# 非交互模式
nslookup -type=MX example.com 8.8.8.8
nslookup -type=TXT example.com

# 反向解析
nslookup 93.184.216.34

8.3 host —— 简洁查询

# 基本查询
host example.com

# 查询特定类型
host -t MX example.com
host -t TXT example.com

# 反向解析
host 93.184.216.34

# 指定 DNS 服务器
host example.com 8.8.8.8

# 显示详细信息
host -v example.com

8.4 whois —— 域名注册信息

# 查询域名注册信息
whois example.com

# 查询 IP 归属
whois 1.2.3.4

# 安装 whois
# Ubuntu/Debian
sudo apt install whois

# CentOS/RHEL
sudo yum install whois

# 过滤关键信息
whois example.com | grep -E "Name Server|Expiry|Registrar"

8.5 DNS 传播检查

# 全球 DNS 传播检查在线工具
# https://www.whatsmydns.net/
# https://dnschecker.org/
# https://dns.google/query?name=example.com

# 使用脚本检查多个公共 DNS 的解析结果
#!/bin/bash
DOMAIN="example.com"
DNS_SERVERS=(
    "8.8.8.8"           # Google
    "1.1.1.1"           # Cloudflare
    "223.5.5.5"         # 阿里
    "119.29.29.29"      # 腾讯
    "114.114.114.114"   # 114DNS
    "9.9.9.9"           # Quad9
)

echo "=== DNS Propagation Check: $DOMAIN ==="
for dns in "${DNS_SERVERS[@]}"; do
    result=$(dig @$dns $DOMAIN A +short 2>/dev/null | head -1)
    printf "%-15s → %s\n" "$dns" "${result:-TIMEOUT}"
done

输出示例:

=== DNS Propagation Check: example.com ===
8.8.8.8         → 93.184.216.34
1.1.1.1         → 93.184.216.34
223.5.5.5       → 93.184.216.34
119.29.29.29    → 93.184.216.34
114.114.114.114 → 93.184.216.34
9.9.9.9         → 93.184.216.34

8.6 其他实用工具

# dnstracer - 追踪完整解析路径
dnstracer example.com

# drill - dig 的现代替代(LDNS 工具包)
drill example.com @8.8.8.8

# dog - 更友好的 DNS 查询工具(Rust 编写)
dog example.com A @8.8.8.8

# dnsx - 快速批量 DNS 解析(ProjectDiscovery)
echo "example.com" | dnsx -a -resp

# massdns - 高性能批量 DNS 解析
massdns -r resolvers.txt -t A -o S domains.txt

九、常见 DNS 问题排查

9.1 解析不生效

排查步骤:

# 步骤一:确认记录已正确添加
dig @ns1.your-dns.com example.com A +short

# 步骤二:检查 NS 记录是否已切换
dig NS example.com +short

# 步骤三:检查 TTL 和缓存
dig example.com A +noall +answer
# 查看 TTL 值,等待其过期后重试

# 步骤四:检查是否存在 CNAME 冲突
dig example.com ANY +noall +answer

# 步骤五:清除本地缓存
sudo systemd-resolve --flush-caches  # Linux
sudo dscacheutil -flushcache          # macOS

常见原因:

1. NS 记录未生效(需等待 24-48 小时)
2. TTL 未过期,旧记录仍被缓存
3. CNAME 与其他记录冲突
4. 记录值格式错误(如末尾多了空格)
5. DNS 服务商配置未保存/未发布

9.2 缓存污染

DNS 缓存污染(Cache Poisoning)是指恶意数据被注入 DNS 缓存。

# 检测方法:对比不同 DNS 服务器的解析结果
dig @8.8.8.8 example.com A +short
dig @1.1.1.1 example.com A +short
dig @114.114.114.114 example.com A +short

# 如果结果不一致,可能存在缓存污染

# 缓解措施:
# 1. 使用支持 DNSSEC 的 DNS 服务器
# 2. 使用 DNS over HTTPS (DoH) 或 DNS over TLS (DoT)
# 3. 部署本地 DNS 缓存(如 unbound)

# 配置 DoH(Cloudflare)
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1
DNSOverTLS=yes

9.3 TTL 调优

# TTL 值选择参考
# 类型              推荐 TTL    说明
# 高频变更(迁移中)  60-300s    切换最快,但 DNS 查询量大
# 常规 Web 服务      600-3600s  平衡性能与灵活性
# 稳定服务(MX/NS)   86400s     变更频率低,减少查询
# CDN CNAME          300-600s   需要快速切换时

# 实际调优示例:迁移前降低 TTL
# 迁移前 72 小时:TTL 设置为 300
# 迁移完成后:TTL 恢复为 3600
# 这样可以确保切换后 5 分钟内全球生效

TTL 与查询量的关系:

TTL=60    → 1440 次/天/客户端(高查询量,快速生效)
TTL=3600  → 24 次/天/客户端(低查询量,1小时生效)
TTL=86400 → 1 次/天/客户端(极低查询量,24小时生效)

9.4 DNS 劫持

# DNS 劫持类型:
# 1. 运营商 DNS 劫持(插入广告、重定向)
# 2. 路由器 DNS 劫持(恶意修改路由器 DNS 设置)
# 3. 本地恶意软件修改 hosts 文件

# 检测方法
# 对比本地解析与权威服务器解析
dig @ns1.iana-servers.net example.com A +short  # 权威结果
dig example.com A +short                        # 本地结果

# 检查 hosts 文件
cat /etc/hosts | grep example.com

# 防护措施
# 1. 使用加密 DNS(DoH/DoT)
# 2. 定期检查路由器 DNS 设置
# 3. 使用 VPN

# 配置 DoH 客户端
# 安装 cloudflared
cloudflared proxy-dns --port 5053 --upstream https://1.1.1.1/dns-query

# systemd-resolved 配置 DoT
# /etc/systemd/resolved.conf
[Resolve]
DNS=1.1.1.1#cloudflare-dns.com
DNSOverTLS=yes

十、最佳实践

10.1 TTL 选择策略

┌─────────────────────────────────────────────────────────┐
│                    TTL 选择决策树                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  是否在迁移/变更中?                                      │
│    ├─ 是 → TTL = 60~300s                                │
│    └─ 否 → 是否使用 CDN/负载均衡?                        │
│              ├─ 是 → TTL = 300~600s                      │
│              └─ 否 → 是否为关键基础设施(MX/NS)?          │
│                       ├─ 是 → TTL = 3600~86400s          │
│                       └─ 否 → TTL = 600~3600s(默认)     │
│                                                         │
└─────────────────────────────────────────────────────────┘

10.2 DNS 迁移步骤

# 完整的 DNS 迁移流程

# 阶段一:准备(T-7天)
# 1. 在新 DNS 服务商添加所有记录
# 2. 验证记录完整性(逐条比对)
# 3. 将 TTL 降低至 300s(在旧 DNS 服务商操作)

# 验证脚本
#!/bin/bash
OLD_DNS="old-ns.example.com"
NEW_DNS="new-ns.example.com"
DOMAINS=("example.com" "www.example.com" "api.example.com" "mail.example.com")

for domain in "${DOMAINS[@]}"; do
    old=$(dig @$OLD_DNS $domain +short | sort)
    new=$(dig @$NEW_DNS $domain +short | sort)
    if [ "$old" = "$new" ]; then
        echo "✅ $domain: 一致"
    else
        echo "❌ $domain: 不一致"
        echo "   旧: $old"
        echo "   新: $new"
    fi
done

# 阶段二:切换(T=0)
# 4. 在域名注册商处修改 NS 记录
#    旧:dns1.old.com, dns2.old.com
#    新:ns1.new.com, ns2.new.com

# 阶段三:验证(T+1~2天)
# 5. 全球 NS 传播检查
dig NS example.com @8.8.8.8 +short
dig NS example.com @1.1.1.1 +short

# 6. 检查旧 DNS 服务器查询量是否归零

# 阶段四:收尾(T+7天)
# 7. 确认旧 DNS 无查询后,删除旧记录
# 8. 恢复正常 TTL(3600s 或更高)

10.3 多 DNS 服务商容灾

# 方案一:多 NS 记录(最简单)
# example.com.  IN  NS  ns1.primary-dns.com.
# example.com.  IN  NS  ns2.primary-dns.com.
# example.com.  IN  NS  ns1.backup-dns.com.
# example.com.  IN  NS  ns2.backup-dns.com.
# DNS 查询会随机选择一个 NS 服务器,天然容灾

# 方案二:使用 DNS 服务商的 Anycast 网络
# Cloudflare:全球 300+ 节点
# 阿里云:全球 30+ 节点
# Anycast 网络本身具有容灾能力

# 方案三:DNS 区域传输(AXFR/IXFR)
# 在两个 DNS 服务商之间同步 zone 数据
# /etc/named.conf(主 DNS 服务器)
zone "example.com" {
    type master;
    file "example.com.zone";
    allow-transfer { 1.2.3.4; };  # 备用 DNS 服务器 IP
    also-notify { 1.2.3.4; };
};

# 方案四:使用 OctoDNS 管理多服务商
# pip install octodns
# octodns-sync --config-file=config.yaml

OctoDNS 配置示例:

# config.yaml
providers:
  cloudflare:
    class: octodns_cloudflare.CloudflareProvider
    token: YOUR_CLOUDFLARE_TOKEN
  route53:
    class: octodns_route53.Route53Provider
    access_key_id: YOUR_AWS_KEY
    secret_access_key: YOUR_AWS_SECRET

zones:
  example.com.:
    sources:
      - config
    targets:
      - cloudflare
      - route53

10.4 DNS 安全加固清单

□ 启用 DNSSEC(防止缓存投毒)
□ 配置 CAA 记录(限制证书颁发)
□ 使用 DoH/DoT(加密 DNS 查询)
□ 配置 SPF/DKIM/DMARC(防止邮件伪造)
□ 定期扫描子域名(发现影子资产)
□ 监控 DNS 记录变更(及时发现异常)
□ 禁用不必要的区域传输(AXFR)
□ 使用强密码保护 DNS 管理账号
□ 启用双因素认证(2FA)
□ 审计 DNS 日志(发现异常查询)

10.5 监控与告警

# DNS 监控脚本(定期检查解析状态)
#!/bin/bash
# dns_monitor.sh
DOMAINS=("example.com" "api.example.com" "www.example.com")
EXPECTED_IP="1.2.3.4"
ALERT_EMAIL="ops@example.com"

for domain in "${DOMAINS[@]}"; do
    current_ip=$(dig +short $domain A @8.8.8.8 | head -1)
    if [ "$current_ip" != "$EXPECTED_IP" ]; then
        echo "[ALERT] $domain resolved to $current_ip (expected $EXPECTED_IP)" | \
          mail -s "DNS Alert: $domain" $ALERT_EMAIL
    fi
done

# crontab 配置(每 5 分钟执行一次)
# */5 * * * * /opt/scripts/dns_monitor.sh >> /var/log/dns_monitor.log 2>&1

附录:速查表

常用 DNS 服务器

DNS 服务器

地址

特点

Google

8.8.8.8 / 8.8.4.4

全球覆盖,支持 ECS

Cloudflare

1.1.1.1 / 1.0.0.1

最快,支持 DoH/DoT

阿里

223.5.5.5 / 223.6.6.6

国内最快

腾讯

119.29.29.29

国内稳定

114DNS

114.114.114.114

国内老牌

Quad9

9.9.9.9

自动拦截恶意域名

常用命令速查

# 查询
dig example.com A                    # A 记录
dig example.com MX                   # 邮件记录
dig example.com +trace               # 追踪解析路径
dig @8.8.8.8 example.com +short     # 指定 DNS 查询

# 反向解析
dig -x 1.2.3.4

# DNSSEC 验证
dig +dnssec example.com

# 区域传输
dig @ns1.example.com example.com AXFR

# 批量查询
dig -f domains.txt +short

# 在线工具
# https://dns.google/query
# https://www.whatsmydns.net
# https://dnsviz.net

运维格言: DNS 是互联网中最容易被忽视、也最容易引发故障的基础设施。90% 的"网站打不开"问题,最终都指向 DNS。把 DNS 管理好,就是把运维的根基打牢。