希曼日记

macOS分域名DNS解析部署

本页目录 5
  1. 1 描述
  2. 2 环境
  3. 3 安装步骤
  4. 4 测试
  5. 5 引用

macOS 分域名 DNS 解析部署

1 描述

把指定域名后缀的解析交给局域网内的一台 DNS 服务器,其余域名继续使用系统默认 DNS。

用途:为开发域名提供统一解析,不修改 macOS 全局 DNS,也不在多台机器上维护 /etc/hosts

组成部分:

  • Ubuntu 上运行 dnsmasq,应答开发域名后缀,其余查询转发到公共上游。
  • macOS 上放置 /etc/resolver 配置文件,把该后缀的查询指向 Ubuntu。

后缀使用 .test。RFC 6761 将 .test 保留给测试用途,公网 DNS 不解析该后缀。不要使用 .local,RFC 6762 将其定义为 mDNS 语义,会被 Bonjour 特殊处理。

2 环境

角色地址职责
macOS192.168.3.220开发机,开发域名的解析目标
Ubuntu192.168.3.202运行 dnsmasq,应答开发域名

两台机器在同一局域网内互通。

本文使用以下变量,按实际环境修改:

变量取值含义
DEV_DOMAINdev.test开发域名后缀
TARGET_IP192.168.3.220开发域名解析到的地址
DNS_IP192.168.3.202运行 dnsmasq 的地址
UPSTREAM_DNS223.5.5.5其余域名的上游 DNS

3 安装步骤

3.1 Ubuntu 侧

声明变量。后续命令在同一个终端会话中执行。

export DEV_DOMAIN=dev.test
export TARGET_IP=192.168.3.220
export DNS_IP=192.168.3.202
export UPSTREAM_DNS=223.5.5.5

安装 dnsmasq 和 dig。

sudo apt update
sudo apt install -y dnsmasq dnsutils

创建开发域名配置。各配置项含义见文件内注释。

sudo tee /etc/dnsmasq.d/dev-domains.conf >/dev/null <<EOF
# $DEV_DOMAIN 及其所有子域解析到 $TARGET_IP
address=/$DEV_DOMAIN/$TARGET_IP

# 该后缀只在本机应答,任何记录类型都不转发到上游
local=/$DEV_DOMAIN/

# 不读 /etc/resolv.conf 取上游
no-resolv
# 显式指定上游:$DEV_DOMAIN 之外的域名走这里
# 使用 no-resolv 后不写本行,则没有任何上游,其余域名全部解析失败
server=$UPSTREAM_DNS

# 本机自用
listen-address=127.0.0.1
# 局域网地址,供 macOS 发送查询
listen-address=$DNS_IP

# 只绑定上面列出的地址,不监听通配地址
bind-interfaces
EOF

检查配置语法。本命令只做语法检查,不检查地址绑定。

sudo dnsmasq --test

启动服务并设置开机自启。

sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq
sudo systemctl status dnsmasq --no-pager

预期结果:Active: active (running)

3.2 macOS 侧

声明变量。

export DEV_DOMAIN=dev.test
export DNS_IP=192.168.3.202

创建 /etc/resolver 目录。使用 install -d -m 而非 mkdir -p,权限不受当前 umask 影响。

sudo install -d -m 0755 /etc/resolver

创建 resolver 配置文件。文件名即匹配的域名后缀,不能添加扩展名。

printf 'nameserver %s\n' "$DNS_IP" | sudo tee /etc/resolver/$DEV_DOMAIN

刷新系统 DNS 缓存。两条命令成功时都没有输出。

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

4 测试

4.1 Ubuntu 侧

在 Ubuntu 上查询本机 dnsmasq。RFC 7766 要求 DNS 同时支持 UDP 和 TCP,两种方式都要测试。

dig @127.0.0.1 foo.$DEV_DOMAIN A +short
dig +tcp @127.0.0.1 foo.$DEV_DOMAIN A +short

预期输出:

192.168.3.220

4.2 macOS 侧直接查询

在 macOS 上直接查询 Ubuntu,验证链路和 dnsmasq。

dig @$DNS_IP foo.$DEV_DOMAIN A +short
dig +tcp @$DNS_IP foo.$DEV_DOMAIN A +short

预期输出:

192.168.3.220

验证上游转发。

dig @$DNS_IP www.baidu.com A +short

预期输出:返回公网 IP 地址。

4.3 macOS 系统解析路径

dig @服务器 指定了服务器地址,不经过 macOS 的多 resolver 选择,无法验证 /etc/resolver 是否生效。以下命令走系统解析路径。

确认 resolver 已被系统加载。

scutil --dns | grep -A 3 "domain.*$DEV_DOMAIN"

预期输出:

  domain   : dev.test
  nameserver[0] : 192.168.3.202
  flags    : Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

查询一级子域、多级子域和裸域。

dscacheutil -q host -a name foo.$DEV_DOMAIN
dscacheutil -q host -a name a.b.c.$DEV_DOMAIN
dscacheutil -q host -a name $DEV_DOMAIN

预期输出(以一级子域为例):

name: foo.dev.test
ip_address: 192.168.3.220

dscacheutil 解析失败时没有任何输出,退出码同样为 0。以输出内容判断结果,不以退出码判断。

4.4 其余域名未受影响

分域名解析要求其余域名仍走系统默认 DNS。

dscacheutil -q host -a name www.baidu.com

预期输出:返回公网 IP 地址,且与 $DNS_IP 无关。

5 引用