强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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

需求使用的指令示例
域名 → IPaddresshost-recordaddress=/nas/192.168.1.10
域名 → IPv4 + IPv6host-recordhost-record=nas,192.168.1.10,fd00::10
别名 → 真实域名cnamecname=www,web
屏蔽域名addressaddress=/ads.example.com/#
泛域名addressaddress=/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:[email protected]"

# 域名验证
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单机本地解析
附加 hostsaddn-hosts=批量主机记录
地址覆盖address=/域名/IP泛域名、域名屏蔽
CNAMEcname=别名,真实域名别名
host-recordhost-record=A + AAAA 同时配置
PTRptr-record=反向解析
MXmx-host=邮件交换
SRVsrv-host=服务发现
TXTtxt-record=SPF/DKIM/验证

6.11 扩展阅读