跳到主要内容

DNS

Egern 的 DNS 子系统支持多种协议(UDP、DoT、DoH、DoQ、DoH3),并允许通过 Forward 规则把不同域名分发到不同的上游 DNS 组。Egern 内部存在两条解析路径:

  • 默认 DNS:处理用户流量的域名解析,按 Forward 规则匹配上游,未命中回退到 Bootstrap;连接上游时遵循代理规则。
  • 代理 DNS:代理服务器解析目标域名时使用,连接上游时强制直连,避免 DNS → 代理 → DNS 的循环依赖。配置 proxy_nameservers 后,所有代理 DNS 查询强制走该列表(绕过 Forward 规则);未配置时与默认 DNS 共用 Forward 规则,未命中回退到 Bootstrap。

解析流程

每次域名查询依次经过以下阶段:

  1. Hosts:命中本地映射时直接返回(IP)或将映射后的域名作为别名继续解析。
  2. Forward:按配置顺序匹配规则,第一条命中规则决定上游 DNS。SSID/BSSID/Cellular 类规则依赖当前网络状态,网络变化时匹配缓存会被清空。代理 DNS 在配置了 proxy_nameservers 时跳过此阶段,所有查询直接走该列表。
  3. 默认上游:所有 Forward 规则均未命中时使用——默认 DNS 回退到 Bootstrap;代理 DNS 在未配置 proxy_nameservers 时也回退到 Bootstrap。
  4. Block IPs:响应中匹配 block_ips 的记录被过滤;全部被过滤时视为解析失败。

Bootstrap(启动 DNS)

bootstrap 配置启动阶段使用的 DNS 服务器,仅支持传统 UDP 协议(端口 53),且不遵循代理规则——流量直连。它有两个用途:

  1. 解析 upstreams 中加密 DNS 服务器(tls://https:// 等)的主机名。
  2. 作为最终的 DNS 回退(详见上文「解析流程」)。

支持的值:

  • IP 或 IP:port,例如 1.1.1.18.8.8.8:53
  • 特殊值 system:合并系统 DNS 服务器(即 Wi-Fi/蜂窝网络下发的 DNS)。

未配置或解析失败时,自动使用系统 DNS 服务器。

dns:
bootstrap:
- system # 合并系统 DNS
- 223.5.5.5 # 同时加上自定义服务器

Upstreams(DNS 服务器组)

为加密 DNS 服务器分组命名,供 Forward 规则按组名引用。同一组内的多个服务器并发竞速,由响应最快者胜出。

支持的服务器格式:

格式协议默认端口
1.1.1.11.1.1.1:53传统 UDP53
udp://1.1.1.1传统 UDP53
tls://1.1.1.1DNS over TLS853
https://8.8.8.8/dns-queryDNS over HTTPS443
quic://dns.adguard-dns.comDNS over QUIC853
h3://dns.example.com/dns-queryDNS over HTTP/3443
bootstrap展开为 Bootstrap 的所有服务器
system展开为系统 DNS 的所有服务器

Forward 规则的 value 可引用 upstreams 中的组名。默认 DNS 始终通过 Forward 规则使用这些组;代理 DNS 仅在未配置 proxy_nameservers 时才会经由 Forward 命中这些组(配置后会跳过 Forward)。

dns:
upstreams:
google:
- https://8.8.8.8/dns-query
- https://8.8.4.4/dns-query
adguard:
- quic://dns.adguard-dns.com

Forward(DNS 转发规则)

按配置顺序匹配域名,第一条命中规则将查询发送到对应的上游。默认 DNS 始终按本规则集匹配;代理 DNS 仅在未配置 proxy_nameservers 时才会走 Forward(配置后强制走 proxy_nameservers,跳过 Forward)。

支持以下匹配类型:

类型说明
domain精确匹配整个域名
domain_keyword域名包含关键词(子串匹配)
domain_suffix域名后缀匹配,按 . 边界对齐:match: cn 匹配 cnexample.cn,但不匹配 examplecn
domain_wildcardglob 通配符(* / ?),不区分大小写。例如 *.google.com
domain_regexPCRE2 正则,按 find 语义——任意子串命中即匹配
proxy_rule_set引用预编译的远程规则集
ssid当前 Wi-Fi SSID 通配符匹配
bssid当前 Wi-Fi BSSID 通配符匹配
cellular当前蜂窝制式通配符匹配,例如 LTENR

每条规则的字段:

  • match (string), 必填

    匹配条件,语义随类型而定。

  • value (string), 必填

    目标上游,可以是:

    • upstreams 中定义的组名。
    • 单个 DNS 服务器地址,例如 tls://1.1.1.1(隐式上游,等价于一个只含该地址的临时组)。
    • 特殊值 bootstrap:使用 Bootstrap DNS。
    • 特殊值 system:使用系统 DNS。
    • 特殊值 reject:拒绝解析,返回空响应。
  • disabled (bool), 可选

    是否禁用此规则。默认 false

  • update_interval (integer), 可选

    proxy_rule_set 类型有效,规则集自动更新间隔(秒)。默认 86400,设为 <= 0 时禁用自动更新。

Hosts(主机映射)

将主机名(域名或 IP)按 glob 通配符模式映射到一个或多个 IP / 域名。多条规则按声明顺序匹配,第一条命中即返回。命中时:

  • 全部为 IP → 直接返回。
  • 含域名 → 把映射后的域名作为别名继续解析(按 Forward 规则走流程)。
dns:
hosts:
"*.google.com": 142.250.80.46
"example.com": www.example.com # 域名映射到另一个域名
"192.168.1.100": internal.example.com # IP 反向映射到域名
"cdn.example.com": # 多个值
- 1.2.3.4
- 5.6.7.8

Proxy Nameservers(代理 DNS 的强制上游)

配置后,所有代理 DNS 查询都强制走这里列出的服务器,Forward 规则会被跳过——这样可以让"代理用的 DNS"语义明确:显式配置即硬覆盖。所有连接均为直连(不经过代理链),从而避免 DNS → 代理 → DNS 的循环依赖。支持与 Upstreams 相同的协议格式。

未配置时,代理 DNS 与默认 DNS 共用 Forward 规则匹配,未命中回退到 Bootstrap。

dns:
proxy_nameservers:
- tls://dns.google
- https://cloudflare-dns.com/dns-query
- quic://dns.adguard-dns.com

Block IPs(屏蔽 IP)

过滤 DNS 响应中匹配的 IP(用于防止 DNS 污染)。支持 IPv4、IPv6 地址及 CIDR:

dns:
block_ips:
- 0.0.0.0
- 127.0.0.1
- 10.0.0.0/8
- "::1"

只有当响应中所有记录都被过滤时才视为解析失败;否则返回剩余记录。

Skip TLS Verify(跳过 TLS 验证)

对加密 DNS 上游(tls://https://quic://h3://)跳过 TLS 证书校验。仅当上游使用自签名证书时才需要开启(例如自建 AdGuardHome),其余情况请保持默认。

dns:
skip_tls_verify: true

Public IP Lookup URL(公网 IP 查询地址)

可选。配置一个返回纯文本 IP 的 HTTP/HTTPS URL,Egern 会定期请求该地址获取设备公网 IP,并作为 EDNS Client Subnet(ECS)参数附加到上游 DNS 查询,帮助 CDN 返回离设备更近的解析结果。

dns:
public_ip_lookup_url: https://ifconfig.me/ip

完整示例

dns:
bootstrap:
- system
upstreams:
google:
- https://8.8.8.8/dns-query
- https://8.8.4.4/dns-query
adguard:
- quic://dns.adguard-dns.com
forward:
- domain:
match: "internal.example.com"
value: "192.168.1.1"
- domain_suffix:
match: "cn"
value: bootstrap
- domain_keyword:
match: "taobao"
value: bootstrap
- domain_wildcard:
match: "*.cn"
value: bootstrap
- proxy_rule_set:
match: "https://example.com/china-domains.list"
value: bootstrap
update_interval: 86400
- domain_regex:
match: "^ad\\..*|^ads\\..*"
value: reject
- ssid:
match: "MyHome*"
value: bootstrap
- bssid:
match: "AA:BB:CC:*"
value: bootstrap
- cellular:
match: "NR"
value: google
- domain_wildcard:
match: "*"
value: google
hosts:
example.com: www.example.com
localhost: 127.0.0.1
"*.local": 192.168.1.1
proxy_nameservers:
- tls://dns.google
- https://1.1.1.1/dns-query
block_ips:
- 0.0.0.0
- 127.0.0.1
skip_tls_verify: false
public_ip_lookup_url: https://ifconfig.me/ip

常见问题

为什么有了 Upstreams 还需要 Bootstrap?

upstreams 里的加密 DNS(tls://dns.googlehttps://cloudflare-dns.com/...)本身需要先解析其主机名为 IP 才能建立连接,这一步由 Bootstrap 完成。Bootstrap 必须使用 IP 直连的传统 DNS,不能依赖尚未解析的加密上游。

Forward 规则未命中时走哪个 DNS?

默认 DNS 走 Bootstrap。代理 DNS 取决于 proxy_nameservers:未配置时走 Forward 规则,未命中回退到 Bootstrap;一旦配置,所有代理 DNS 查询都直接走 proxy_nameservers,根本不进入 Forward 匹配。

为什么 Proxy Nameservers 要直连?

代理服务器(如 Trojan、Shadowsocks)的目标域名必须先被解析为 IP 才能建立代理连接。如果代理 DNS 自身又走代理,就会陷入循环依赖。直连绕开这个环。