☰
BFE mod_doh 模块配置指南:mod_doh.conf 全参数详解与 DoH 请求转发实现
2026/10/10 2:34:13 网站建设 项目流程
  • 后端
  • 网络/通信
  • 云原生

【免费下载链接】bfe

A modern layer 7 load balancer from baidu

项目地址:https://gitcode.com/gh_mirrors/bf/bfe
点击查看免费下载

mod_doh 是 BFE(Baidu Front End,现代七层负载均衡器)内置的 DoH(DNS over HTTPS)模块,用于把经过 HTTPS 传输的 DNS 查询请求转换为标准 DNS 报文,并转发给上游 DNS 服务器。mod_doh.conf是该模块的基础配置文件,负责指定 DoH 请求的匹配条件、上游 DNS 服务器地址以及日志选项。阅读本文后,你将掌握mod_doh.conf全部配置项的含义、取值约束与默认行为,并理解这些配置项在 conf_mod_doh.go 中是如何被解析和校验的。

模块定位:BFE 如何承载 DoH 流量

从源码结构看,mod_doh 以独立目录形式存在于 bfe_modules/mod_doh/ 下,核心文件包括:

  • mod_doh.go:模块入口与请求处理主流程;
  • conf_mod_doh.go:配置结构定义、加载与校验;
  • dns_fetcher.go:DNS 客户端,负责向指定服务器发起 UDP 查询;
  • dns_msg_convert.go:HTTP 请求与 DNS 报文之间的双向转换。

在请求处理主流程dohHandler中,模块先利用Basic.Cond配置的 Condition 表达式判断当前请求是否为 DoH 请求;随后强制校验连接是否已加密(req.Session.IsSecure),非 HTTPS 请求会直接返回 403 Forbidden;最后才把请求交给dnsFetcher执行真实 DNS 查询并构造 HTTP 响应。这一设计决定了mod_doh.conf中每一项配置都与"匹配 — 鉴权 — 转发"这条链路严格对应。

配置文件位置与加载方式

mod_doh.conf位于 BFE 配置根目录下的mod_doh/子目录中,即conf/mod_doh/mod_doh.conf(仓库内置示例见 conf/mod_doh/mod_doh.conf)。模块初始化时,Init()通过bfe_module.ModConfPath(cr, m.name)拼接出配置文件绝对路径,再调用ConfLoad()完成加载,加载失败会直接导致模块初始化报错(见 mod_doh.go)。

ConfLoad()使用gopkg.in/gcfg.v1解析 INI 风格的配置文件,并将解析结果映射到ConfModDoh结构体(见 conf_mod_doh.go):

type ConfModDoh struct { Basic struct { Cond string } Dns DnsConf Log struct { OpenDebug bool } } type DnsConf struct { Address string RetryMax int Timeout int // In Millisecond. }

配置文件结构因此固定为三个段:[Basic]、[Dns]、[Log]。解析完成后会立即执行Check()校验,任何一项不合法都会返回错误并中断模块启动。

配置项总览

配置项类型含义是否必填补充说明生效条件
Basic.CondStringDoH 请求的匹配条件是语法见 Condition 表达式语法必须是合法的 Condition 表达式
Dns.AddressString上游 DNS 服务器地址是示例:127.0.0.1:53必须是合法的 UDP 地址
Dns.RetryMaxIntegerDNS 查询最大重试次数否默认0(不重试)取值必须>= 0
Dns.TimeoutIntegerDNS 查询的累计超时时间,单位毫秒是—取值必须> 0
Log.OpenDebugBoolean是否开启调试日志否默认False—

各配置项详解与源码级校验逻辑

Basic.Cond:DoH 请求匹配条件

Basic.Cond决定哪些请求会被 mod_doh 接管。模块启动时通过condition.Build()将该字符串编译为 Condition 对象(见 mod_doh.go),编译失败即初始化失败;运行时每个请求都会先执行m.cond.Match(req),不匹配的请求直接放行给后续处理链(BfeHandlerGoOn)。

Condition 表达式语法支持丰富的请求维度原语,例如:

[Basic] Cond = "req_host_in(\"example.org\") && req_path_prefix_in(\"/dns-query\", false)"

即"仅当请求 Host 为example.org且 URI 路径以/dns-query开头时才视为 DoH 请求",这是 conf/mod_doh/mod_doh.conf 中内置的示例。RFC 8484 规定的 DoH 标准路径正是/.well-known/dns-query,实际部署时可用req_path_prefix_in("/.well-known/dns-query", false)配合req_host_in(...)精确圈定服务域名。完整语法参考 Condition 表达式语法。

Dns.Address:上游 DNS 服务器

Dns.Address是模块转发查询的目标地址,典型写法为127.0.0.1:53。校验逻辑(见 conf_mod_doh.go)调用net.ResolveUDPAddr("udp", cfg.Dns.Address),因此:

  • 必须能被解析为合法 UDP 地址(IP:端口 或可解析的主机名:端口);
  • 解析失败会在配置加载阶段直接报错,模块无法启动。

该地址在NewDnsClient()中被写入DnsClient.address(见 dns_fetcher.go),所有查询都通过dns.Client.Exchange(msg, c.address)发出,网络协议固定为 UDP。

Dns.RetryMax:查询重试次数

Dns.RetryMax控制单次 DNS 查询失败后的重试次数,默认0表示失败即返回、不重试。校验要求>= 0,负值会触发"RetryMax should >= 0."错误(见 conf_mod_doh.go)。

底层重试逻辑位于exchangeWithRetry()(见 dns_fetcher.go):循环执行retry < c.retryMax+1次client.Exchange,只要某次成功立即返回结果;全部失败则返回最后一次错误。每次失败时若开启调试日志,会记录错误与当前重试序号。

Dns.Timeout:DNS 查询累计超时

Dns.Timeout是单次 UDP 查询的超时上限,单位毫秒,必填且必须> 0(校验失败报"Timeout should > 0.")。它会被转换为 Go 的time.Duration传入dns.Client:

dnsClient.client = dns.Client{ Net: "udp", Timeout: time.Duration(dnsConf.Timeout) * time.Millisecond, UDPSize: dns.MaxMsgSize, }

即每次Exchange的超时均为Timeout毫秒;若同时配置了重试,总耗时上限约为(RetryMax+1) × Timeout毫秒。UDPSize固定取dns.MaxMsgSize(65535),保证大响应报文不被截断。

Log.OpenDebug:调试日志开关

Log.OpenDebug是布尔开关,默认False。开启后,模块会在以下场景输出 debug 级日志(见 dns_fetcher.go):

  • HTTP 请求转 DNS 报文失败(RequestToDnsMsg出错);
  • 单次 DNS 查询 Exchange 失败(含重试序号);
  • DNS 响应转 HTTP 响应失败(DnsMsgToResponse出错)。

该开关在Init()中被赋给包级变量openDebug,供整个模块共享。生产环境建议保持关闭,仅在排查 DNS 查询故障时临时开启。

完整配置示例

仓库内置示例 conf/mod_doh/mod_doh.conf:

[Basic] Cond = "req_host_in(\"example.org\") && req_path_prefix_in(\"/dns-query\", false)" [Dns] Address = "127.0.0.1:53" Timeout = 1000 [Log] OpenDebug = false

配置文件校验(ConfLoad+Check)对应测试用例见 conf_mod_doh_test.go,其中TestConfLoad验证了 bfe_modules/mod_doh/testdata/mod_doh/mod_doh.conf 可被正确解析,且Basic.Cond被完整读出。

配置项对运行时行为的影响

理解各配置项后,可以将其与 mod_doh.go 的完整处理链路对应起来:

  1. 匹配:Basic.Cond不匹配的请求直接放行;
  2. 安全校验:匹配后检查req.Session.IsSecure,非 HTTPS 请求计数DohRequestNotSecure并返回 403——DoH 要求加密传输,因此mod_doh.conf无需也不能放宽此约束;
  3. 报文转换:RequestToDnsMsg()支持 GET(?dns=携带 base64url 编码报文)与 POST(Content-Type: application/dns-message,body 上限 8192 字节)两种 RFC 8484 请求格式,并自动附加 EDNS Client Subnet(基于真实客户端 IP,IPv4 掩码 32 / IPv6 掩码 128),便于上游按地域优化解析;
  4. 转发:Dns.Address+Dns.Timeout+Dns.RetryMax共同决定 UDP 查询行为;
  5. 响应:成功时以application/dns-message返回二进制 DNS 响应,Cache-Control: max-age取 Answer 区最小 TTL(遵循 RFC 8484 第 5.1 节);查询失败返回 500,并累计DohRequest/FetchDnsErr等监控指标。

模块同时注册了mod_doh与mod_doh.diff两个 web-monitor 监控端点(见monitorHandlers()),可用于观察 DoH 请求量与失败率,辅助调优Dns.Timeout与Dns.RetryMax。

配置速查与常见问题

  • 模块未接管请求:检查Basic.Cond是否与实际请求的 Host、路径匹配,可用default_t()(匹配全部请求)临时验证模块链路本身是否正常——这是 conf_mod_doh_test.go 测试数据采用的条件。
  • 查询总是超时:确认Dns.Address指向可达的 UDP DNS 服务端口(如127.0.0.1:53),并适当增大Dns.Timeout(毫秒级,示例为1000);开启Log.OpenDebug = true可在日志中看到每次 Exchange 错误详情。
  • 需要高可用:为Dns.RetryMax设置大于 0 的值(如2),注意总耗时上限为(RetryMax+1) × Timeout。
  • 配置不生效/启动失败:模块启动时即完成全部校验(Condition 合法性、UDP 地址可解析、RetryMax >= 0、Timeout > 0),启动报错应先检查conf/mod_doh/mod_doh.conf是否满足上述约束。
  • 后端
  • 网络/通信
  • 云原生

【免费下载链接】bfe

A modern layer 7 load balancer from baidu

项目地址:https://gitcode.com/gh_mirrors/bf/bfe
点击查看免费下载

相关推荐

上一篇:Moodle TinyMCE 编辑器升级指南:editor_tiny_get_configuration 外部函数与 helplinktext 变更解析
下一篇:Translumo:5分钟跑通Windows实时屏幕翻译的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询