Linux DNS 域名解析
Linux DNS 域名解析详解:原理与 BIND 配置
目录
- 为什么需要 DNS
- DNS 原理:域名层级、解析流程与记录类型
- 本地解析顺序:/etc/hosts 与 nsswitch.conf
- 软件包安装
- BIND 服务器部署与基础配置
- 配置正向解析与反向解析
- 客户端配置:/etc/resolv.conf
- 排错工具:nslookup、dig、host
- DNSSEC 与 DNS 安全
- 常见坑与最佳实践
- 实战:搭建企业内网 DNS 服务器
- 总结与延伸
- 参考资料
为什么需要 DNS
0.1 IP 地址与域名的关系
网络上每一台主机都有一个 IP 地址(如 192.168.1.10)。IP 地址是机器路由的“门牌号”,但对人类不友好、难记忆,而且 IP 可能变化(改机房、负载均衡漂移)。DNS(Domain Name System,域名系统) 的作用就是把人类易记的域名(如 www.example.com)解析成机器可用的 IP 地址。
一句话:DNS 是互联网的“电话簿”,把域名翻译成 IP。 没有它,我们得记一堆数字 IP,应用也无法用稳定的域名互相访问。
0.2 DNS 在运维中的地位
- 一切“用域名访问”都依赖 DNS:
curl http://www.example.com、ping、SSH、数据库连接串、浏览器,第一步几乎都是 DNS 解析。 - 服务迁移无需改客户端:服务 IP 变了,只需改 DNS 记录,客户端继续用域名即可(前提是解析正确)。
- 负载均衡与高可用:一个域名解析到多个 IP(多 A 记录)、按地域/权重解析,是现代服务发现的常见手段。
- 反向解析用于审计与安全:把 IP 反查回域名,用于日志归属、邮件反垃圾(PTR 校验)等。
正因如此,“DNS 是否配置正确”是运维排查一切网络问题的第一步之一:很多“连不上”“访问慢”“证书报错”的根因其实是解析错误或解析到了错误 IP。
0.3 本文目标
学完本文,你将能够:
- 说清域名层级、DNS 查询流程与常见记录类型;
- 理解本地
/etc/hosts与 DNS 的查询顺序; - 部署一台 BIND 域名服务器,配置 正向解析 与 反向解析;
- 配置客户端
/etc/resolv.conf,会用 nslookup / dig / host 解析与排错; - 了解 DNSSEC 与 DNS 安全注意事项。
一、DNS 原理:域名层级、解析流程与记录类型
1.1 域名层级结构
域名是一棵自右向左、从大到小的层级树,用 . 分隔:
www.example.com.
│ │ │ └─ 根域(root,最右边那个点,常省略不写)
│ │ └── 顶级域(TLD,如 .com .org .cn)
│ └──── 二级域(注册的域名,example.com)
└────── 主机名/子域(www,或 mail、ftp 等)
层级划分(从高到低):
| 层级 | 示例 | 说明 |
|---|---|---|
| 根域(root) | . |
域名树的最高层,全球 13 组根服务器(逻辑 13 个,物理多台) |
| 顶级域(TLD) | .com .org .net .cn |
由 ICANN 管理,分通用顶级域(gTLD)与国家/地区顶级域(ccTLD) |
| 二级域 | example.com |
组织/个人注册的域名,向下可无限细分 |
| 子域 / 主机 | www.example.com mail.example.com |
二级域下的具体主机或子域 |
域名层级由“权威域名服务器”逐级授权管理:根服务器告诉你去哪找
.com服务器,.com服务器告诉你去哪找example.com服务器,example.com的权威服务器才真正告诉你www的 IP。这就是“委派(delegation)”。
1.2 DNS 解析流程与查询角色
这一节是 DNS 最核心、也最容易绕晕的部分。先建立一个清晰的心智模型:整个解析过程只涉及两类角色——“发问的客户端”和“层层问路的服务器链”。下面分步讲。
1.2.1 先分清两类角色
| 角色 | 是谁 | 干什么 |
|---|---|---|
| 发起者(客户端) | 你的浏览器 / 程序 / dig / nslookup |
提出“帮我解析 www.example.com”,并把这件事整体交给配置的 DNS 服务器,等待最终 IP |
| 递归解析器(Recursive Resolver) | /etc/resolv.conf 里 nameserver 指向的那台(如 8.8.8.8、223.5.5.5、或内网 BIND) |
代替客户端完成全部查询工作,负责“问到底”,把最终 IP 交回给客户端 |
| 权威服务器(Authoritative) | 根服务器、TLD 服务器、example.com 的权威服务器 |
各管一段,回答“我这层的下一步该问谁”或“这条记录的值是什么” |
一句话:客户端只跟“递归解析器”打交道(递归查询);递归解析器再跟一层层“权威服务器”打交道(迭代查询)。你平时配置的 nameserver,就是那台帮你“跑腿到底”的递归解析器。
1.2.2 完整流程:一个例子走到底
以本机访问 www.example.com 为例,完整路径如下(①-③ 是客户端与递归解析器之间,④-⑦ 是递归解析器与权威链之间):
① 客户端先查自己的本地缓存 / /etc/hosts —— 命中就直接用,不再往下走。
② 未命中,客户端把“www.example.com 是多少?”整体丢给递归解析器。
③ 递归解析器查自己的缓存 —— 也没有,于是开始逐级“问路”。
④ 问根服务器: “www.example.com 归谁管?” → 根说:“去问 .com 的权威服务器”。
⑤ 问 .com 服务器:“example.com 归谁管?” → .com 说:“去问 example.com 的权威服务器”。
⑥ 问 example.com 权威服务器:“www 的 IP 是多少?” → 权威说:“192.168.1.20”。
⑦ 递归解析器拿到 IP,① 交回给客户端,② 并把结果缓存一段时间(TTL)。
客户端得到 IP,建立连接。
对应的图示:
客户端 递归解析器 根/权威服务器链
| | |
|--① 查本地缓存/hosts-->| |
| |--④ 问根服务器-------->| .com 在哪?
| |<----------------------| 去问 .com
| |--⑤ 问 .com 服务器---->| example.com 在哪?
| |<----------------------| 去问 example.com
| |--⑥ 问权威服务器------>| www = 192.168.1.20
| |<----------------------| 返回 IP
|<--⑦ 返回 IP + 缓存----|
v
建立连接
1.2.3 递归 vs 迭代:两种查询模式
- 递归查询(recursive):把“解析整个域名”这件完整的事交给对方,等对方查完把最终答案送回来。客户端对递归解析器就是递归查询——客户端不关心中间过程,只要结果。
- 迭代查询(iterative):我每一步只问一个具体问题,对方只告诉我“下一步该去问谁”,我自己再接着问,直到问到能给出最终答案的权威服务器。递归解析器对根/TLD/权威服务器的查询就是迭代——它自己一步步“走”完整条链。
简化记忆:递归 = “帮我查到结果再告诉我”(一次委托,等最终答案);迭代 = “我自己一步步问过去”(每步只拿一个指引,接着往下问)。 客户端→递归解析器是递归;递归解析器→各层权威是迭代。
排错提示:了解这条链有助于定位问题。
dig +trace会把你从根开始一步步的迭代过程完整打出来(见第 7 章)——如果某一步卡住或返回异常,就知道问题出在“权威数据”还是“递归/缓存”哪一层。
1.3 常见 DNS 记录类型
DNS 记录(resource record,RR)存放在**区域文件(zone file)**中。运维最常用的类型如下:
| 记录类型 | 全称 | 作用 | 示例 |
|---|---|---|---|
| A | Address | 把域名解析为 IPv4 地址 | www IN A 192.168.1.10 |
| AAAA | IPv6 Address | 把域名解析为 IPv6 地址 | www IN AAAA 2001:db8::1 |
| CNAME | Canonical Name | 把域名别名指向另一个域名(规范名) | www IN CNAME web.example.com |
| MX | Mail Exchange | 指定该域名的邮件服务器(带优先级) | example.com. IN MX 10 mail.example.com. |
| NS | Name Server | 指定该域的权威域名服务器 | example.com. IN NS ns1.example.com. |
| PTR | Pointer | 反向解析:把 IP 映射回域名 | 10.1.168.192.in-addr.arpa. IN PTR ns1.example.com. |
| TXT | Text | 任意文本,常用于 SPF/DKIM 校验、验证 | example.com. IN TXT "v=spf1 include:_spf.example.com ~all" |
| SOA | Start of Authority | 区域的起始授权记录,含主服务器、管理员邮箱、序列号等 | 见 5.2 详解 |
| SRV | Service | 指定某服务的主机与端口(如 LDAP、SIP) | _ldap._tcp IN SRV 0 100 389 ldap.example.com. |
A/AAAA 做“域名→IP”的正向解析;PTR 做“IP→域名”的反向解析(对应本文第 5 章)。CNAME 只能指向域名,不能再带其他记录;MX/NS 后的域名末尾要写完整(带结尾点)。
1.4 TTL 与缓存
每条 DNS 记录都有 TTL(Time To Live,生存时间),单位秒,表示“这条记录可以被缓存多久”。TTL 越短,更新生效越快,但查询压力越大;越长则反之。改动记录后,需等旧 TTL 过期,全球缓存才会更新——这是运维改 DNS 后“迟迟不生效”的常见原因。
二、本地解析顺序:/etc/hosts 与 nsswitch.conf
很多人以为“解析域名一定走 DNS”。其实 Linux 在走 DNS 之前,还会先查本地缓存与 /etc/hosts。顺序由 /etc/nsswitch.conf 决定。
2.1 /etc/hosts:本地静态域名表
/etc/hosts 是系统本地的“域名→IP”静态映射表,格式为:
IP地址 主机名 [别名...]
192.168.1.10 ns1.example.com ns1
127.0.0.1 localhost
作用与特点:
- 优先于 DNS(若 nsswitch 配置如此):本地有这条记录就直用,不走网络,快且稳。
- 常用于:本地测试、内网主机名映射、屏蔽/定向(把某域名指到指定 IP)。
- 缺点:需每台机器手动维护,规模大时不适用,故生产环境主要靠 DNS。
2.2 nsswitch.conf:决定查询顺序
/etc/nsswitch.conf 的 hosts: 行定义了主机名解析的顺序:
hosts: files dns
files:查/etc/hosts文件;dns:查 DNS(走/etc/resolv.conf指定的服务器);- 顺序即优先级:
files dns表示先查 /etc/hosts,再查 DNS(Linux 默认,也是推荐顺序)。
排错提醒:如果
/etc/hosts里有人写了某个域名的错误映射,即使 DNS 正确,hosts:在dns:前时也会优先命中错误记录。排查“解析到奇怪 IP”时,先看/etc/hosts。
2.3 本地缓存
现代 Linux 常用 systemd-resolved(systemd 自带的解析与缓存服务)或 nscd/systemd-nss 做 DNS 本地缓存。判断实际使用的解析器:
resolvectl status # systemd-resolved 状态
cat /etc/nsswitch.conf # 看 hosts 行用了什么 (hosts: files dns)
重要(RHEL/Rocky 特有):
systemd-resolved在 Rocky/RHEL 上默认并不安装,DNS 解析默认由 NetworkManager 管理(直接写/etc/resolv.conf)。因此要用resolvectl做本地缓存/管理 DNS,需先安装这个包(若已安装,resolvectl status报The name is not activatable、systemctl status systemd-resolved报could not be found都是“没装这个包”的表现):
sudo dnf install -y systemd-resolved # 安装 systemd-resolved
sudo systemctl enable --now systemd-resolved # 启用并启动
resolvectl status # 安装后才能正常使用
安装并启用后,
/etc/resolv.conf通常会变成指向/run/systemd-resolve/resolv.conf(或 stub-resolv.conf)的符号链接,由 systemd-resolved 接管 DNS。不装也能正常工作——Rocky 默认由 NetworkManager 管理 DNS,resolvectl只是额外的本地缓存/管理工具,按需安装即可。
缓存会“留住”旧解析结果,改 DNS 记录后本机可能仍拿到旧 IP,可用
resolvectl flush-caches清缓存(第 6 章提,需已启用 systemd-resolved)。
软件包安装
BIND 是独立的系统服务包,Minimal 安装的 Rocky/RHEL 通常未预装。使用前先确认并安装。
3.1 相关软件包
| 包(RHEL/Rocky) | 包(Debian/Ubuntu) | 提供 | 说明 |
|---|---|---|---|
bind |
bind9 |
named 守护进程、配置文件、区域文件 |
BIND 主包,装它即可 |
bind-utils |
dnsutils |
dig、nslookup、host 等客户端排错工具 |
强烈建议同时安装(排错必备) |
bind-chroot |
(较少用) | chroot 隔离运行环境(可选) | 把 named 限制在 chroot 内,增强安全性 |
经典网络里 named 就是 BIND 守护进程名(
named= “name daemon”)。两系的 systemd 服务名都叫named,但配置文件路径不同:RHEL/Rocky 主文件是/etc/named.conf,Debian/Ubuntu 是/etc/bind/named.conf(详见下方差异表)。
3.2 检查是否已安装
# ---- RHEL / Rocky / CentOS ----
rpm -q bind bind-utils
# ---- Debian / Ubuntu ----
dpkg -l bind9 dnsutils
# 两系通用:命令与服务是否存在
which named dig nslookup
systemctl status named
3.3 安装与启动
# ---- RHEL / Rocky / CentOS ----
sudo dnf install -y bind bind-utils
# ---- Debian / Ubuntu ----
sudo apt update && sudo apt install -y bind9 dnsutils
# 启动并设置开机自启(两系服务名都是 named)
sudo systemctl enable --now named
# 确认状态
systemctl status named
安装后 named 默认配置即可解析公共 DNS(作递归解析器),但要作为企业内网权威服务器(正反向解析)需修改配置,见第 4、5 章。
RHEL 系与 Debian/Ubuntu 系差异汇总:
项目 RHEL / Rocky / CentOS Debian / Ubuntu 包管理器/安装 dnf install bind bind-utilsapt install bind9 dnsutils主配置文件 /etc/named.conf/etc/bind/named.conf附加配置 /etc/named.rfc1912.zones/etc/bind/named.conf.local、named.conf.options区域文件目录 /var/named//etc/bind/(自带db.local、db.127等)systemd 服务名 namednamed默认强制访问控制 SELinux(enforcing,需 named_zone_t上下文)AppArmor(非 SELinux,通常无需 restorecon) 默认防火墙 firewalld ufw 下文示例以 RHEL/Rocky 为主。Debian/Ubuntu 只需把配置写入
/etc/bind/named.conf、区域文件放入/etc/bind/,并注意其默认自带的named.conf.local(区域声明通常写在这里)与 SELinux 步骤可跳过。
四、BIND 服务器部署与基础配置
4.1 BIND 是什么
BIND(Berkeley Internet Name Domain) 是最广泛使用的开源 DNS 服务器软件,由 ISC(Internet Systems Consortium) 维护。它既能做权威服务器(管理自己的域名区域,回答正反向解析),也能做递归解析器(代客户端查询外网)。
4.2 配置文件总览
BIND 的核心文件:
| 文件 | 作用 |
|---|---|
/etc/named.conf |
主配置文件:定义全局选项(监听地址、访问控制、转发)与区域(zone)声明 |
/etc/named.rfc1912.zones |
系统自带的本地区域声明(localhost、反向等),一般无需改动 |
/var/named/ |
区域数据文件(zone file)目录,存放各域的 A/PTR 等记录 |
/var/named/named.ca |
根服务器提示文件(root hints),递归解析用 |
/var/named/named.localhost |
localhost 正向区域文件 |
/var/named/named.loopback |
127.0.0.1 反向区域文件 |
4.3 named.conf 关键结构
/etc/named.conf 主体是选项块(options)与区域声明(zone)。一个最小示例:
options {
listen-on port 53 { 192.168.1.10; }; # 监听在哪个 IP 的 53 端口
listen-on-v6 port 53 { none; }; # 本例禁用 IPv6 监听
directory "/var/named"; # 区域文件所在目录
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
allow-query { localhost; 192.168.1.0/24; }; # 允许谁来查询
recursion yes; # 是否允许递归(解析外网)
forwarders { 8.8.8.8; 223.5.5.5; }; # 非本域查询转发到上游(可选)
};
zone "." IN {
type hint;
file "named.ca";
};
几个选项的含义:
listen-on:监听地址。默认监听所有接口;建议显式指定内网 IP,避免暴露到公网。allow-query:访问控制,只有列出的网段能查询。生产环境务必收紧。recursion yes/no:是否作为递归解析器代理外网查询。权威服务器可设no;内网递归可设yes。forwarders:上游转发服务器。本机不逐级迭代,而是把非本域的查询直接转发给列出的服务器(如公共 DNS),典型内网做法。
4.4 配置校验:named-checkconf / named-checkzone
改配置前务必先校验,避免语法错误导致 named 启动失败:
# 校验主配置文件语法
sudo named-checkconf /etc/named.conf
# 校验某个区域文件(示例:正向区域 example.com)
sudo named-checkzone example.com /var/named/example.com.zone
# 校验反向区域文件
sudo named-checkzone 1.168.192.in-addr.arpa /var/named/1.168.192.zone
无输出即通过;有错误会提示行列位置。改完配置、重启 named 前一定先跑 named-checkconf。
4.5 重启与服务管理
sudo systemctl restart named
sudo systemctl status named
journalctl -u named --since '5 minutes ago' # 查看 named 日志
SELinux 提示:Rocky/RHEL 默认 SELinux 开启,named 有独立策略。自建的区域文件必须放在
/var/named下并赋予正确的named_zone_t上下文,否则 named 因 SELinux 拒绝读取而加载失败。查看/修复:
ls -Z /var/named/ # 查看上下文(应带 named_zone_t)
sudo restorecon -Rv /var/named/ # 恢复正确上下文
Debian/Ubuntu 差异:默认强制访问控制是 AppArmor 而非 SELinux,上述
ls -Z/restorecon/named_zone_t是 RHEL 系特有,Debian/Ubuntu 一般无需执行(区域文件放/etc/bind/即可被正常读取)。
五、配置正向解析与反向解析
这是 BIND 的核心用途:管理自己负责的域名区域,回答“域名→IP”(正向)与“IP→域名”(反向)。
5.1 正向解析(Forward)
正向解析 = 把域名解析成 IP。步骤:先在 named.conf 声明一个 zone(区域),再写对应的区域数据文件。
第 1 步:在 named.conf 声明正向区域
在 /etc/named.conf 中(或新建一个 include 文件)添加:
zone "example.com" IN {
type master;
file "example.com.zone";
allow-update { none; };
};
type master:本机是该区域的主(权威)服务器;file:区域数据文件名(相对/var/named);allow-update { none; }:禁止动态更新(安全默认)。
第 2 步:编写正向区域文件 /var/named/example.com.zone
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025061301 ; serial(序列号,改记录必须递增)
3600 ; refresh(刷新间隔,秒)
900 ; retry(重试间隔)
604800 ; expire(过期时间)
86400 ) ; minimum(负缓存 TTL)
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
@ IN MX 10 mail.example.com.
ns1 IN A 192.168.1.10
ns2 IN A 192.168.1.11
www IN A 192.168.1.20
mail IN A 192.168.1.30
web IN CNAME www.example.com.
ftp IN A 192.168.1.40
区域文件每一列是什么
先建立一个通用框架:区域文件里每条记录本质上就是一行“表格”,由若干列组成。标准格式是:
[记录名/owner] [TTL] [class 类别] [type 类型] [rdata 值]
www 86400 IN A 192.168.1.20
五列各是什么意思(其中 TTL 常省略,由 $TTL 全局兜底):
| 列 | 名称 | 作用 | 本示例 |
|---|---|---|---|
| 第 1 列 | 记录名 / owner(属主) | 这条记录作用于哪个域名。三种写法:写具体主机名(www);写 @ 表示“当前区域名”(example.com.);留空/省略则继承上一行的记录名 |
www、@、ns1 |
| 第 2 列 | TTL(生存时间) | 这条记录可被缓存多久(秒),可省略,省略时用 $TTL 的值 |
省略(继承 $TTL 86400) |
| 第 3 列 | class(类别) | 记录所属类别,几乎永远是 IN(Internet 类),可省略 |
IN |
| 第 4 列 | type(类型) | 记录类型:A/AAAA/CNAME/MX/NS/PTR/TXT/SOA 等(见 1.3) |
A、NS、MX、CNAME、SOA |
| 第 5 列 | rdata(记录值) | 这条记录的具体“值”,格式随类型而定:A 是 IP,CNAME 是另一个域名,MX 是“优先级+邮件服务器”…… |
192.168.1.20 等 |
重点讲“记录名”这一列(你最容易困惑的):它表示“这条记录属于谁”。区域文件是“一行行按区域名组织”的,所以:
- 写
www这类不带点的名字,会被自动补上当前区域名,即www→www.example.com.;- 写
@就代表当前区域本身(example.com.),常用于 SOA/NS/MX 这类“整个域”的记录;- 写完整的带点域名(如
ns1.example.com.)时,结尾那个点不能丢——丢了会被当成相对名再拼一次区域名,变成错误的ns1.example.com.example.com.;- 若某一列留空,则继承上一行的记录名(BIND 允许省略,连续多条同主机记录可只写第一行)。
字段解释:
$TTL 86400:默认 TTL(86400 秒 = 1 天)。@:代表“当前区域名”(此处即example.com.)。- SOA 记录:区域起点,含主服务器(
ns1.example.com.)、管理员邮箱(admin.example.com.,注意用.代替@)、以及 5 个时间参数。 serial(序列号):区域版本号,每次修改记录都必须递增(如2025061301→2025061302),否则从服务器/缓存不认为区域有更新。- A 记录:主机名 → IPv4;CNAME:别名 → 规范名;MX:邮件服务器(数字为优先级,越小越优先)。
- 记录左侧若不带域名,默认继承当前区域名(如
www即www.example.com.);完整的域名要写结尾点(如www.example.com.)。
第 3 步:校验并重载
sudo named-checkzone example.com /var/named/example.com.zone
sudo systemctl reload named
5.2 反向解析(Reverse)
反向解析 = 把 IP 解析成域名,核心是 PTR 记录。DNS 用特殊的反向区域名(in-addr.arpa)表示:把 IPv4 地址倒过来作为区域名。
例如
192.168.1.20的反向查询:以20为主机、1.168.192.in-addr.arpa.为区域。规则是把 IP 倒序 + 后缀in-addr.arpa.:192.168.1.20→ 反向区域1.168.192.in-addr.arpa,记录主机20。
第 1 步:在 named.conf 声明反向区域
zone "1.168.192.in-addr.arpa" IN {
type master;
file "1.168.192.zone";
allow-update { none; };
};
第 2 步:编写反向区域文件 /var/named/1.168.192.zone
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025061301
3600
900
604800
86400 )
@ IN NS ns1.example.com.
@ IN NS ns2.example.com.
10 IN PTR ns1.example.com.
11 IN PTR ns2.example.com.
20 IN PTR www.example.com.
30 IN PTR mail.example.com.
40 IN PTR ftp.example.com.
反向区域里,记录名是 IP 的最后一段(如
20代表192.168.1.20),值是完整的域名(带结尾点)。这样dig -x 192.168.1.20就能查出www.example.com.。
第 3 步:校验并重载
sudo named-checkzone 1.168.192.in-addr.arpa /var/named/1.168.192.zone
sudo systemctl reload named
5.3 测试正反向解析
在本机或其他机器上,把 nameserver 指向这台 BIND 后测试(第 6、7 章讲客户端与工具):
# 正向解析
dig @192.168.1.10 www.example.com
nslookup www.example.com 192.168.1.10
# 反向解析
dig @192.168.1.10 -x 192.168.1.20
nslookup 192.168.1.20 192.168.1.10
六、客户端配置:/etc/resolv.conf
客户端要能解析,核心是告诉系统“用哪台 DNS 服务器”,配置在 /etc/resolv.conf。
6.1 resolv.conf 基本格式
/etc/resolv.conf 的核心指令:
# 指定 DNS 服务器(可多个,按顺序尝试,最多 3 个)
nameserver 192.168.1.10
nameserver 192.168.1.11
# 默认搜索域:解析不带点的短主机名时自动补全这些后缀
search example.com lab.example.com
# 选项(可选)
options timeout:2 attempts:3 rotate
常用指令说明:
| 指令/选项 | 作用 |
|---|---|
nameserver IP |
指定 DNS 服务器地址,最多 3 个;按顺序尝试,第一个无响应才用下一个 |
search 域1 域2 |
默认搜索域列表,解析短主机名(如 www)时依次追加这些后缀尝试 |
options timeout:N |
每个 nameserver 的超时时间(秒,默认 5) |
options attempts:N |
每个 nameserver 的尝试次数(默认 2) |
options rotate |
启用后轮询切换 nameserver,实现负载均衡 |
options ndots:N |
名字中含 N 个点以上时先当 FQDN 直接查询,否则先加 search 域 |
search 域与 ndots:默认
ndots:1,即名字含 1 个点以上就先按完整域名查。若内网用无点主机名,可配合 search 域简化访问(ping app自动解析成app.example.com)。
6.2 一个典型内网客户端 resolv.conf
nameserver 192.168.1.10
nameserver 192.168.1.11
search example.com
options timeout:2 attempts:2 rotate
6.3 resolv.conf 被自动覆盖的问题
常见坑:手改的 resolv.conf 重启后丢失。 因为 NetworkManager(或 systemd-resolved)会托管 resolv.conf,把它生成/覆盖掉。正确处理方式:
# 方式一:通过 NetworkManager 配置(推荐,持久)
sudo nmcli con mod '系统连接名' ipv4.dns '192.168.1.10 192.168.1.11' ipv4.ignore-auto-dns yes
sudo nmcli con up '系统连接名'
# 方式二:查看当前实际使用哪些 DNS
nmcli dev show | grep -i dns
resolvectl status
# 方式三:临时改(重启失效,仅测试用)
echo 'nameserver 192.168.1.10' | sudo tee /etc/resolv.conf
若系统用 systemd-resolved,
/etc/resolv.conf通常是指向/run/systemd/resolve/stub-resolv.conf的符号链接,由 resolved 管理。此时用resolvectl dns 接口名 IP设置,而不是直接改文件。判断方式:ls -l /etc/resolv.conf。
6.4 清缓存与切换
# systemd-resolved 清缓存
sudo resolvectl flush-caches
# 查看 DNS 缓存与配置
resolvectl status
6.5 常用公共 DNS 服务器
公共 DNS 由第三方免费提供,适合没有内网 DNS 服务器的机器直连。选择时要考虑你所在网络环境:在中国大陆,直连国外 DNS(8.8.8.8、1.1.1.1)往往延迟高、偶尔被墙/丢包,解析慢甚至失败;国内服务器建议用国内公共 DNS。
常用公共 DNS:
| 提供方 | 首选地址 | 备用地址 | 说明 |
|---|---|---|---|
| 阿里云 DNS | 223.5.5.5 |
223.6.6.6 |
国内最常用之一,速度快、稳定,支持 DoH/DoT |
| 腾讯 DNSPod | 119.29.29.29 |
— | 腾讯系,国内常用,支持 DoH/DoT |
| 114DNS(南京信风) | 114.114.114.114 |
114.114.115.115 |
老牌国内公共 DNS,另有安全版/纯净版 |
| 百度 DNS | 180.76.76.76 |
— | 百度提供,国内节点多 |
| Google Public DNS | 8.8.8.8 |
8.8.4.4 |
全球知名,但国内直连延迟高、可能被墙 |
| Cloudflare | 1.1.1.1 |
1.0.0.1 |
强调隐私,但国内直连同样不理想 |
国内 vs 国外 DNS:同样解析一个域名,国内 DNS(如
223.5.5.5)服务器在国内、就近,延迟低且稳定;8.8.8.8/1.1.1.1服务器在境外,国内直连经常超时或解析很慢。内网有自己 BIND 的机器,优先指向内网服务器(它再 forward 到公共 DNS,见 4.3);没有内网 DNS 时,国内机器建议配223.5.5.5、119.29.29.29等国内源。
配置方法就是把 nameserver 换成上面的地址:
echo 'nameserver 223.5.5.5' | sudo tee /etc/resolv.conf(测试用)或用nmcli/resolvectl持久配置(见 6.3)。
七、排错工具:nslookup、dig、host
排错工具由 bind-utils 提供:dig(功能最强,推荐首选)、nslookup(老牌、交互式)、host(简洁)。
7.1 dig:最强大的查询工具
dig 输出详细、可控性强,是运维首选。基本用法:
# 用系统默认 DNS 解析
dig www.example.com
# 指定 DNS 服务器解析
dig @192.168.1.10 www.example.com
# 只显示答案(简洁)
dig @192.168.1.10 www.example.com +short
# 指定查询类型(A / AAAA / MX / NS / TXT / CNAME)
dig @192.168.1.10 www.example.com A
dig @192.168.1.10 example.com MX
dig @192.168.1.10 example.com NS
# 反向解析
dig @192.168.1.10 -x 192.168.1.20
# 追踪完整解析路径(从根服务器一路查下来,排查权威问题)
dig +trace www.example.com
# 查询某条记录的 TTL / 权威答案信息
dig www.example.com +noall +answer
dig 输出的 ANSWER SECTION 给出解析结果;STATUS: NOERROR 表示查询成功,NXDOMAIN 表示域名不存在,SERVFAIL 表示服务器出错,REFUSED 表示被拒绝。
+trace尤其适合判断“是权威数据问题还是递归/缓存问题”:它能展示从根到权威的每一步,定位问题在哪一层。
7.2 nslookup:经典交互工具
nslookup 兼容性好,支持交互模式。基本用法:
# 直接解析
nslookup www.example.com
# 指定 DNS 服务器
nslookup www.example.com 192.168.1.10
# 指定记录类型
nslookup -type=MX example.com
# 反向解析
nslookup -type=PTR 192.168.1.20
# 进入交互模式
nslookup
> server 192.168.1.10
> set type=MX
> example.com
> exit
7.3 host:最简洁
host www.example.com # 正向
host 192.168.1.20 # 反向
host -t MX example.com # 指定类型
host www.example.com 192.168.1.10 # 指定服务器
7.4 排错思路速查
现象 1:dig 返回 NXDOMAIN(域名不存在)
- 确认域名拼写;确认查询的 nameserver 是否真的负责该区域;
- 检查该域名是否在正确的 zone 中声明了记录。
现象 2:dig 返回 SERVFAIL
- 权威服务器出错(区域文件语法错误、serial 未加载);
- 用
named-checkzone校验区域文件;看 named 日志journalctl -u named。
现象 3:dig 返回 REFUSED
- 查询被拒绝:
allow-query未包含该网段;或递归被禁用(recursion no)而你发了递归查询。
现象 4:解析到旧 IP / 缓存问题
- 等待 TTL 过期,或清客户端缓存(
resolvectl flush-caches); - 确认
serial已递增并已 reload named; - 检查是否命中了
/etc/hosts(hosts:在 nsswitch 中的顺序)。
现象 5:能 ping IP 但域名解析失败
- 检查
/etc/resolv.conf的 nameserver 是否可达(dig @该IP 某个域名); - 检查防火墙是否放行 UDP 53(查询)/TCP 53(大响应、区域传输)。
7.5 防火墙放行 53 端口
BIND 同时用 UDP 53(常规查询)与 TCP 53(响应较大、区域传输 AXFR/IXFR)。服务端需放行:
# ---- firewalld(Rocky/RHEL 默认)----
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
# ---- ufw(Debian/Ubuntu 默认)----
sudo ufw allow 53
sudo ufw status
dns是 firewalld 预定义服务别名,同时放行 TCP 53 与 UDP 53。Debian/Ubuntu 用 ufw:sudo ufw allow 53同样放行 TCP+UDP 53。
八、DNSSEC 与 DNS 安全
8.1 DNSSEC 是什么
DNSSEC(DNS Security Extensions,域名系统安全扩展) 通过数字签名保证 DNS 响应的真实性(防伪造)与完整性(防篡改),防止“DNS 欺骗/缓存投毒”把用户导向恶意 IP。核心概念:
- 公钥签名:权威服务器对区域数据用私钥签名,解析器用公钥验证;
- 信任链:从根域逐级用父域签子域的公钥,形成“信任链”,根用
root trust anchor信任。 - 记录:
DNSKEY(公钥)、RRSIG(签名)、DS(委派签名)等。
启用 DNSSEC 校验(在 options 中):
dnssec-validation yes;
dnssec-enable yes; # BIND 9.16+ 默认已启用,此行为默认值
现代 BIND(9.16+)默认
dnssec-validation yes。内网自建区域若未做 DNSSEC 签名,可对非权威的递归查询开启校验,但自签名区域不在信任链内属正常。
8.2 DNS 安全最佳实践
- 收紧
allow-query:只允许内网网段查询,避免被外部滥用做放大攻击。 - 禁止区域传输给非授权主机:
allow-transfer { none; }或指定从服务器,防止别人拖走整个区域数据(信息泄露)。 - 禁用/谨慎递归:权威服务器若
recursion no,降低被当作开放递归器(Open Resolver)的风险。 - 限制
allow-update:默认none,避免动态更新被滥用。 - 及时更新 BIND:DNS 软件漏洞(如缓存投毒)需靠版本升级修复。
- 分离视图(可选):内网/外网返回不同解析结果,用
view块实现。
一个常见安全教训:把 BIND 配成“允许所有人递归 + 允许所有人传输”并监听公网,会被用于 DNS 放大攻击 与区域数据窃取。务必收紧
allow-query、allow-transfer、recursion。
九、常见坑与最佳实践
9.1 常见坑
坑 1:SOA serial 没递增
改完区域记录忘了加 serial,从服务器/缓存认为区域没更新,改动不生效。每次改记录务必递增 serial 并 reload。
坑 2:CNAME 与其他记录冲突
一个名字若配置了 CNAME,就不能再配 A/AAAA/MX/TXT 等其他记录(RFC 规定 CNAME 独占)。报 CNAME and other data 错误。
坑 3:域名结尾点没写对
区域文件里完整的域名(如 ns1.example.com.)必须带结尾点;不带点会被当作相对名拼上当前区域,产生错误记录。
坑 4:allow-query / allow-transfer 过宽
allow-query { any; } 或 allow-transfer { any; } 会让 BIND 暴露给公网,有安全风险。生产环境收紧到内网网段。
坑 5:resolv.conf 被覆盖
手改的 /etc/resolv.conf 重启后被 NetworkManager/systemd-resolved 覆盖。用 nmcli 或 resolvectl 配置,而非直接改文件。
坑 6:防火墙只放 UDP 53,忘了 TCP 53
常规查询用 UDP,但响应较大或区域传输时用 TCP 53。只放 UDP 可能导致部分查询失败。用 --add-service=dns(同时放行 TCP+UDP)。
坑 7:SELinux 阻止 named 读区域文件
自建区域文件若不在 /var/named 下或上下文不对,named 报 permission denied(实为 SELinux 拦截)。放对目录并 restorecon。
坑 8:改 DNS 后“迟迟不生效”
多半是 TTL 未过期或客户端缓存。等 TTL 过期 + 清缓存,再验证。
9.2 最佳实践清单
- 改任何区域文件先
named-checkzone,改配置先named-checkconf。 - 每次改动记录递增 serial,并
systemctl reload named。 - 收紧
allow-query/allow-transfer/recursion,内网为主。 - 自建区域文件放
/var/named并保证named_zone_t上下文。 - 防火墙放行
dns服务(UDP+TCP 53)。 - 用
dig @服务器 +trace定位“权威 vs 递归 vs 缓存”问题。 - 客户端优先用
nmcli/resolvectl配 DNS,避免 resolv.conf 被覆盖。 - 排错先查
/etc/hosts与 nsswitch 顺序,排除本地映射干扰。
十、实战:搭建企业内网 DNS 服务器
串起全文,完成一个内网 DNS 最小闭环:一台 BIND 权威服务器负责 example.com 域的正反向解析并做内网递归,一台客户端用它解析。
10.1 拓扑
内网 BIND 服务器 192.168.1.10 (权威 example.com + 内网递归)
| UDP/TCP 53
+--------------+
| |
客户端 A 客户端 B
192.168.1.20 192.168.1.30 (nameserver 指向 192.168.1.10)
本节命令以 RHEL/Rocky 为准。Debian/Ubuntu 的差异已在第 3 章汇总,此处需做的替换:
dnf install bind bind-utils→apt install bind9 dnsutils、主配置/etc/named.conf→/etc/bind/named.conf(区域声明建议加在自带的/etc/bind/named.conf.local)、区域文件目录/var/named/→/etc/bind/、防火墙由firewall-cmd换成ufw allow 53;SELinux 的restorecon步骤在 Debian/Ubuntu(AppArmor)可跳过。
10.2 服务端配置(192.168.1.10)
① 安装并启动:
sudo dnf install -y bind bind-utils
sudo systemctl enable --now named
② 编写 /etc/named.conf(关键部分):
options {
listen-on port 53 { 192.168.1.10; };
listen-on-v6 port 53 { none; };
directory "/var/named";
allow-query { localhost; 192.168.1.0/24; };
recursion yes;
forwarders { 223.5.5.5; 8.8.8.8; }; // 非本域查询转发公共 DNS
dnssec-validation yes;
};
zone "example.com" IN {
type master;
file "example.com.zone";
};
zone "1.168.192.in-addr.arpa" IN {
type master;
file "1.168.192.zone";
};
③ 编写正向区域 /var/named/example.com.zone:
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025061301 3600 900 604800 86400 )
@ IN NS ns1.example.com.
@ IN MX 10 mail.example.com.
ns1 IN A 192.168.1.10
www IN A 192.168.1.20
mail IN A 192.168.1.30
ftp IN A 192.168.1.40
web IN CNAME www.example.com.
④ 编写反向区域 /var/named/1.168.192.zone:
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2025061301 3600 900 604800 86400 )
@ IN NS ns1.example.com.
10 IN PTR ns1.example.com.
20 IN PTR www.example.com.
30 IN PTR mail.example.com.
40 IN PTR ftp.example.com.
⑤ 校验、修复 SELinux 上下文、放行防火墙、重载:
sudo named-checkconf /etc/named.conf
sudo named-checkzone example.com /var/named/example.com.zone
sudo named-checkzone 1.168.192.in-addr.arpa /var/named/1.168.192.zone
sudo restorecon -Rv /var/named/
sudo firewall-cmd --permanent --add-service=dns
sudo firewall-cmd --reload
sudo systemctl reload named
10.3 客户端配置(192.168.1.20)
# 方式一:用 nmcli(推荐,持久)
sudo nmcli con mod 'System eth0' ipv4.dns '192.168.1.10' ipv4.ignore-auto-dns yes
sudo nmcli con up 'System eth0'
# 方式二:临时改 resolv.conf(测试用)
echo 'nameserver 192.168.1.10' | sudo tee /etc/resolv.conf
10.4 验证结果
在客户端上验证:
# 正向解析
dig @192.168.1.10 www.example.com +short
# 期望输出:192.168.1.20
# 反向解析
dig @192.168.1.10 -x 192.168.1.20 +short
# 期望输出:www.example.com.
# 用系统配置的 nameserver 直接解析(验证 resolv.conf)
nslookup www.example.com
# 内网也能解析外网(验证 forwarders 递归转发)
dig @192.168.1.10 www.qq.com +short
当客户端用默认 nslookup www.example.com 能解析出 192.168.1.20,且反向 dig -x 返回 www.example.com.,说明整条链路(配置、区域、客户端、防火墙、SELinux)全部打通。
十一、总结与延伸
11.1 本文要点回顾
- 为什么需要 DNS:把域名翻译成 IP,是“用域名访问”一切的基础;解析错误是排障第一嫌疑。
- 原理:域名层级(根→TLD→二级→主机)+ 递归/迭代查询 + A/AAAA/CNAME/MX/NS/PTR/TXT/SOA 等记录 + TTL 缓存。
- 本地解析:
/etc/hosts与/etc/nsswitch.conf(hosts: files dns)决定先查本地还是 DNS。 - BIND:
named服务 +/etc/named.conf+/var/named区域文件;named-checkconf/named-checkzone校验;SELinux 上下文与防火墙 TCP+UDP 53。 - 正反向解析:zone 声明 + 区域文件(SOA/A/NS/MX + PTR);serial 递增;反向区域用
in-addr.arpa倒序。 - 客户端:
/etc/resolv.conf(nameserver/search/options);用nmcli/resolvectl防覆盖。 - 排错:
dig(+short/+trace/-x)、nslookup、host;区分 NXDOMAIN/SERVFAIL/REFUSED/缓存。 - 安全:DNSSEC 校验、收紧 allow-query/transfer/recursion。
11.2 延伸方向
- 主从 DNS(slave):用
type slave+masters建从服务器,配合 serial 递增实现区域自动同步与高可用。 - 分离视图(split-horizon/view):内网外网返回不同结果,用
view块。 - 权威 + 递归分离:权威服务器与递归解析器分开部署,各司其职,更安全。
- dnsmasq / CoreDNS:轻量场景(局域网、容器、K8s)常用 dnsmasq 或 CoreDNS 做内部解析。
- IPv6 反向:对应
ip6.arpa区域。
掌握 DNS 原理与 BIND 配置,是 Linux 运维与网络基础设施搭建的必备技能,也是后续学习容器网络、K8s 服务发现的基石。
参考资料
- ISC BIND 官方主页:https://www.isc.org/bind/
- BIND 9 官方文档(Read the Docs):https://bind9.readthedocs.io/
- BIND 9 参考手册(BIND ARM):https://bind9.readthedocs.io/en/latest/reference.html
- BIND 9 配置详解章节:https://bind9.readthedocs.io/en/latest/chapter3.html
- resolv.conf(5) 手册(man7):https://man7.org/linux/man-pages/man5/resolv.conf.5.html
- nsswitch.conf(5) 手册(man7):https://man7.org/linux/man-pages/man5/nsswitch.conf.5.html
- dig(1) 手册(Debian manpages):https://manpages.debian.org/bookworm/bind9-dnsutils/dig.1.en.html
- nslookup(1) 手册(Debian manpages):https://manpages.debian.org/bookworm/bind9-dnsutils/nslookup.1.en.html
- dig 命令详解(菜鸟教程):https://www.runoob.com/linux/linux-comm-dig.html
- nslookup 命令详解(菜鸟教程):https://www.runoob.com/linux/linux-comm-nslookup.html
- Linux 命令大全(菜鸟教程):https://www.runoob.com/linux/linux-command-manual.html
