Dnsmasq 服务搭建完全教程 / 第 06 章:hosts 与自定义解析
第 06 章:hosts 与自定义解析
6.1 hosts 文件基础
6.1.1 系统 hosts 文件
Linux 系统的 /etc/hosts 文件是最基础的域名解析机制:
# /etc/hosts 格式
# <IP地址> <主机名1> [主机名2] ...
127.0.0.1 localhost
127.0.1.1 myhostname
# IPv6
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# 自定义记录
192.168.1.10 nas nas.home.lan
192.168.1.11 webserver web.home.lan
6.1.2 Dnsmasq 的 hosts 查找顺序
1. --addn-hosts 指定的附加文件(最高优先级)
2. /etc/hosts(默认读取)
3. DHCP 租约中的主机名(最低优先级)
重要:Dnsmasq 不会自动跟踪
/etc/hosts的修改。修改后需要发送 SIGHUP 或 reload。
# 修改 /etc/hosts 后
sudo systemctl reload dnsmasq
# 或
sudo kill -HUP $(pidof dnsmasq)
6.1.3 禁止读取系统 hosts 文件
# 不读取 /etc/hosts(完全使用自定义文件)
no-hosts
# 使用自定义 hosts 文件替代
addn-hosts=/etc/dnsmasq.hosts
6.2 附加 hosts 文件
6.2.1 配置附加文件
# /etc/dnsmasq.d/30-hosts.conf
# 指定附加 hosts 文件
addn-hosts=/etc/dnsmasq.hosts
# 可以指定多个文件(逗号分隔)
addn-hosts=/etc/dnsmasq.hosts,/etc/dnsmasq.extra
6.2.2 创建管理用 hosts 文件
# /etc/dnsmasq.hosts
# === 基础设施 ===
192.168.1.1 gateway gateway.home.lan
192.168.1.2 dns dns.home.lan
# === 服务器 ===
192.168.1.10 nas nas.home.lan storage.home.lan
192.168.1.11 web web.home.lan
192.168.1.12 db db.home.lan database.home.lan
192.168.1.13 git git.home.lan
# === 开发环境 ===
192.168.1.50 dev-api dev.home.lan
192.168.1.51 dev-web frontend.home.lan
192.168.1.52 dev-db
# === IoT 设备 ===
192.168.1.100 camera-front
192.168.1.101 camera-back
192.168.1.110 smart-tv
192.168.1.120 thermostat
# === IPv6 ===
fd00::10 nas6 nas6.home.lan
fd00::11 web6 web6.home.lan
6.2.3 按组织拆分 hosts 文件
# /etc/dnsmasq.d/30-hosts.conf
addn-hosts=/etc/dnsmasq.hosts.srv,/etc/dnsmasq.hosts.dev,/etc/dnsmasq.hosts.iot
# /etc/dnsmasq.hosts.srv
192.168.1.10 nas
192.168.1.11 web
# /etc/dnsmasq.hosts.dev
192.168.1.50 dev-api
192.168.1.51 dev-web
# /etc/dnsmasq.hosts.iot
192.168.1.100 camera-front
192.168.1.110 smart-tv
业务场景:大型网络中,不同部门或环境(生产、开发、测试)各自维护独立的 hosts 文件,便于管理和变更追踪。
6.3 address 指令
6.3.1 基本用法
address 指令比 hosts 文件更灵活,支持泛域名和强制解析:
# /etc/dnsmasq.d/31-address.conf
# 基本 A 记录
address=/nas.home.lan/192.168.1.10
address=/printer.home.lan/192.168.1.20
# AAAA 记录(IPv6)
address=/nas6.home.lan/fd00::10
# 同时返回 A 和 AAAA(需要两个 address 行)
address=/dual.home.lan/192.168.1.50
address=/dual.home.lan/fd00::50
# 屏蔽域名(返回 NXDOMAIN)
address=/ads.example.com/#
# 屏蔽域名(返回 0.0.0.0)
address=/ads.example.com/0.0.0.0
address=/ads.example.com/::
6.3.2 泛域名解析
# 将 example.com 及其所有子域名解析到同一 IP
address=/example.com/192.168.1.100
# www.example.com → 192.168.1.100
# api.example.com → 192.168.1.100
# mail.example.com → 192.168.1.100
# any.thing.example.com → 192.168.1.100
# 开发环境:所有 *.test 域名指向本地
address=/test/127.0.0.1
# myapp.test → 127.0.0.1
# api.test → 127.0.0.1
6.3.3 address vs hosts 对比
| 特性 | hosts 文件 | address 指令 |
|---|---|---|
| 格式 | 标准 hosts 格式 | Dnsmasq 专有格式 |
| 泛域名 | 不支持 | 支持 |
| 屏蔽域名 | 不支持 | 支持(返回 # 或 0.0.0.0) |
| PTR 反向解析 | 自动支持 | 需单独配置 |
| 多 IP 映射 | 支持(一行多主机名) | 一个域名一个 IP |
| 热重载 | 需 SIGHUP | 需 SIGHUP |
| 管理复杂度 | 低(标准格式) | 中(专有格式) |
6.4 CNAME 别名
6.4.1 基本 CNAME 配置
# /etc/dnsmasq.d/32-cname.conf
# CNAME 格式:cname=<别名>,<目标域名>
cname=www.home.lan,webserver.home.lan
cname=mail.home.lan,mailserver.home.lan
cname=ftp.home.lan,fileserver.home.lan
# 链式别名
cname=blog.home.lan,www.home.lan
解析过程:
客户端查询 blog.home.lan
→ CNAME → www.home.lan
→ CNAME → webserver.home.lan
→ A 记录 → 192.168.1.11
6.4.2 CNAME 的限制
# CNAME 不能指向 IP 地址(错误示例)
# cname=www.home.lan,192.168.1.11 ← 错误!
# CNAME 不能指向另一个 CNAME 目标(在 SOA 记录层面)
# 但 Dnsmasq 允许链式 CNAME
# CNAME 和 A 记录不能共存于同一域名
# 如果已有 address=/www.home.lan/192.168.1.11,CNAME 不生效
6.4.3 CNAME 实际应用场景
# 场景 1:服务迁移(旧域名指向新域名)
cname=old-service.internal,new-service.internal
# 场景 2:简化服务地址
cname=jenkins.dev.lan,jenkins-master-01.dev.lan
cname=grafana.monitor.lan,monitoring-01.monitor.lan
# 场景 3:版本路由
cname=api.v1.lan,api-backend-v1.lan
cname=api.v2.lan,api-backend-v2.lan
cname=api.lan,api-v2.lan
6.5 host-record 高级用法
6.5.1 host-record 语法
host-record 是 Dnsmasq 特有的记录类型,比 address 更灵活:
# 格式:host-record=<域名>,<IPv4>[,<IPv6>][,<TTL>]
# 基本用法
host-record=gateway.home.lan,192.168.1.1
host-record=nas.home.lan,192.168.1.10,fd00::10
# 带 TTL(秒)
host-record=static.home.lan,192.168.1.100,3600
# 多域名共享记录
host-record=server1.home.lan,server1-alias.home.lan,192.168.1.5
6.5.2 host-record vs address vs cname
| 需求 | 使用的指令 | 示例 |
|---|---|---|
| 域名 → IP | address 或 host-record | address=/nas/192.168.1.10 |
| 域名 → IPv4 + IPv6 | host-record | host-record=nas,192.168.1.10,fd00::10 |
| 别名 → 真实域名 | cname | cname=www,web |
| 屏蔽域名 | address | address=/ads.example.com/# |
| 泛域名 | address | address=/test/127.0.0.1 |
6.6 PTR 反向解析
6.6.1 配置反向解析
# /etc/dnsmasq.d/33-ptr.conf
# 手动 PTR 记录
# 格式:ptr-record=<反向域名>,<主机名>
ptr-record=10.1.168.192.in-addr.arpa,"nas.home.lan"
ptr-record=11.1.168.192.in-addr.arpa,"web.home.lan"
# hosts 文件中的记录自动生成 PTR
# /etc/hosts 中 "192.168.1.10 nas home.lan" 会自动生成:
# 10.1.168.192.in-addr.arpa → nas.home.lan
# 禁用 hosts 自动生成的 PTR(Dnsmasq 2.86+)
# no-ptr
6.6.2 反向解析测试
# 测试反向解析
dig -x 192.168.1.10 @127.0.0.1
# 输出示例:
# ;; ANSWER SECTION:
# 10.1.168.192.in-addr.arpa. 0 IN PTR nas.home.lan.
6.7 域名过滤与屏蔽
6.7.1 屏蔽特定域名
# /etc/dnsmasq.d/34-filter.conf
# 方法 1:返回 0.0.0.0(推荐,客户端快速失败)
address=/ads.example.com/0.0.0.0
address=/tracker.example.com/0.0.0.0
# 方法 2:返回 NXDOMAIN(域名不存在)
address=/ads.example.com/#
# 方法 3:使用外部 hosts 文件批量屏蔽
# 下载广告屏蔽列表
wget https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -O /etc/dnsmasq.blocklist.hosts
# 在配置中引用
addn-hosts=/etc/dnsmasq.blocklist.hosts
6.7.2 使用域名列表文件
# /etc/dnsmasq.d/35-blocklist.conf
# 使用 Dnsmasq 格式的域名列表
# 文件格式:每行一个域名,address 开头
bogus-priv
# Dnsmasq 格式域名列表文件
# /etc/dnsmasq.blocklist
# address=/ads.adserver.com/0.0.0.0
# address=/tracking.analytics.com/0.0.0.0
# address=/malware.example.com/#
# 引用列表文件
conf-file=/etc/dnsmasq.blocklist
6.7.3 生成域名屏蔽列表
# 从 hosts 格式转换为 Dnsmasq 格式
# 输入(hosts 格式):
# 0.0.0.0 ads.example.com
# 0.0.0.0 tracker.example.com
# 转换脚本
awk '/^0\.0\.0\.0/ {print "address=/" $2 "/0.0.0.0"}' /etc/hosts.blocklist > /etc/dnsmasq.blocklist
# 使用现成的屏蔽列表
# AdGuard 列表
wget "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt" -O /tmp/adguard.txt
awk '/^\|\|[a-z]/ && !/\^/ && !/\*/ {
gsub(/\|\|/, "");
gsub(/\^.*$/, "");
print "address=/" $0 "/0.0.0.0"
}' /tmp/adguard.txt > /etc/dnsmasq.adblock
6.8 MX 和 SRV 记录
6.8.1 MX 记录(邮件)
# /etc/dnsmasq.d/36-mx-srv.conf
# MX 记录
# 格式:mx-host=<域名>,<邮件服务器>,<优先级>
mx-host=example.com,mail.example.com,10
mx-host=example.com,mail2.example.com,20
# 设置默认 MX 目标
mx-target=mail.example.com
# 邮件交换器的 A 记录
address=/mail.example.com/192.168.1.50
address=/mail2.example.com/192.168.1.51
6.8.2 SRV 记录(服务发现)
# SRV 记录
# 格式:srv-host=<服务>,<主机>,<端口>,<优先级>,<权重>
# SIP 电话
srv-host=_sip._tcp.example.com,sip.example.com,5060,10,0
# XMPP/Jabber
srv-host=_xmpp-client._tcp.example.com,xmpp.example.com,5222,5,0
srv-host=_xmpp-server._tcp.example.com,xmpp.example.com,5269,5,0
# LDAP
srv-host=_ldap._tcp.example.com,ldap.example.com,389,10,0
# Kerberos
srv-host=_kerberos._tcp.example.com,kdc.example.com,88,10,0
srv-host=_kpasswd._tcp.example.com,kdc.example.com,464,10,0
6.8.3 TXT 记录
# SPF 记录(邮件防伪)
txt-record=example.com,"v=spf1 mx a ip4:192.168.1.0/24 ~all"
# DKIM 记录
txt-record=default._domainkey.example.com,"v=DKIM1; k=rsa; p=MIGf..."
# DMARC 记录
txt-record=_dmarc.example.com,"v=DMARC1; p=reject; rua=mailto:admin@example.com"
# 域名验证
txt-record=example.com,"google-site-verification=abcdefghijklmnop"
txt-record=_acme-challenge.example.com,"验证令牌值"
6.9 实战:构建内部 DNS 服务体系
6.9.1 完整的企业内部 DNS 配置
# /etc/dnsmasq.d/30-internal-dns-full.conf
# === 基础设置 ===
no-hosts
addn-hosts=/etc/dnsmasq.hosts
domain=corp.lan
expand-hosts
local=/corp.lan/
# === 自定义记录 ===
# 基础设施
host-record=gateway.corp.lan,10.0.0.1
host-record=dns.corp.lan,10.0.0.2
host-record=ntp.corp.lan,10.0.0.2
# 服务别名
cname=jenkins.corp.lan,build-01.corp.lan
cname=grafana.corp.lan,monitor-01.corp.lan
cname=wiki.corp.lan,docs-01.corp.lan
# 邮件
mx-host=corp.lan,mail.corp.lan,10
address=/mail.corp.lan/10.0.0.50
txt-record=corp.lan,"v=spf1 mx ip4:10.0.0.0/24 ~all"
# 服务发现
srv-host=_ldap._tcp.corp.lan,ldap.corp.lan,389,10,0
srv-host=_sip._tcp.corp.lan,sip.corp.lan,5060,10,0
# === 外部域名走公网 DNS ===
server=223.5.5.5
server=8.8.8.8
no-resolv
# /etc/dnsmasq.hosts
# === 基础设施 ===
10.0.0.1 gateway gateway.corp.lan
10.0.0.2 dns dns.corp.lan
10.0.0.3 proxy proxy.corp.lan
# === 应用服务器 ===
10.0.1.10 web-01 web-01.corp.lan
10.0.1.11 web-02 web-02.corp.lan
10.0.1.20 api-01 api-01.corp.lan
10.0.1.21 api-02 api-02.corp.lan
# === 数据库 ===
10.0.2.10 db-master db-master.corp.lan
10.0.2.11 db-slave-01 db-slave-01.corp.lan
10.0.2.12 db-slave-02 db-slave-02.corp.lan
# === 开发/运维 ===
10.0.3.10 build-01 build-01.corp.lan
10.0.3.11 monitor-01 monitor-01.corp.lan
10.0.3.12 docs-01 docs-01.corp.lan
10.0.3.20 ldap ldap.corp.lan
10.0.3.21 sip sip.corp.lan
6.10 小结
| 功能 | 关键指令 | 适用场景 |
|---|---|---|
| 系统 hosts | /etc/hosts | 单机本地解析 |
| 附加 hosts | addn-hosts= | 批量主机记录 |
| 地址覆盖 | address=/域名/IP | 泛域名、域名屏蔽 |
| CNAME | cname=别名,真实 | 域名别名 |
| host-record | host-record= | A + AAAA 同时配置 |
| PTR | ptr-record= | 反向解析 |
| MX | mx-host= | 邮件交换 |
| SRV | srv-host= | 服务发现 |
| TXT | txt-record= | SPF/DKIM/验证 |