把 SRV 记录加进你的区域,并不会让任何 VPN 客户端学会去查询它。客户端必须知道标签、决定发出查询,并依据返回结果行动,而这前两件事 DNS 无法提供。因此大多数失败的 SRV 方案,其实是披着 DNS 外衣的客户端问题。先读客户端如何发现服务,再只发布它真正查询的那个标签。

没人查询的记录帮不了任何人

SRV 发布的是服务所在的位置,而不是宣告服务的存在。没有任何机制把记录推给客户端,也没有解析器会主动提供一个从未被问过的名字。查找始于应用决定发出查询,因此标签只能来自产品文档,或者来自对软件在线行为的观察。如果客户端根本没有发现这一步,记录只改变了区域,别的什么也没改变。

这就是为什么同一网络里,一个产品开始正常而另一个完全不受同一次改动影响。变量是软件本身,DNS 服务器只是照做。改完也把区域读回来,因为拼错的标签很容易混在一堆看起来一样的记录里。

写之前先读字段

一条记录带四个值,各回答不同的问题:优先级给客户端可尝试的目标排序,权重在同优先级目标之间分摊负载,端口给出传输端口,目标给出主机名。规范还允许把目标写成 .,表示服务是被刻意设为不可用,这是有用的答复,而不是坏掉的答复。

这些字段都不携带凭据、证书策略或应用版本,忽略权重的客户端照样能连上,只是得不到预期的均衡。目标需要自己的地址记录,而且应当是规范主机名,而不是别名。发布指向没有监听者主机的记录,会产生看起来像 DNS 故障的连接错误,这是代价最高的误导。要么把整条链都发布,要么一条都别发。

找出客户端真正发出的标签

标签要靠证据确定,而不是猜测产品名称。要么文档写明服务名,要么抓包显示客户端启动时发出的查询。两条路都通向同一处:一个准确的名字和类型,用来对着解析器测试。

dig +short SRV _vpn._tcp.gw.example
dig +short A edge2.gw.example
tcpdump -ni any udp port 53

把答复与你发布的记录逐字符比较,因为下划线和末尾的点都是名字的一部分。查询确实发出却得到空答复,指向区域;完全没有查询,则指向客户端,这两类结论会把工作分给不同团队。真实答复就像下面这一行:优先级 20 会输给任何优先级更低的记录,客户端去拨目标上的 8443 端口。

_vpn._tcp.gw.example. 600 IN SRV 20 10 8443 edge2.gw.example.

目标本身也必须存在

能解析的目标,不等于会应答的服务。先检查目标的地址记录,再检查发布端口和协议上确实有东西在监听。TCP 记录指向只监听 UDP 的服务,这种错配再怎么改区域也修不好。目标还在变动时把 TTL 调短,名字稳定后再调长。

真正实现发现功能的客户端,遵守记录的程度各不相同。有的只用优先级,有的把权重当参考,少数干脆忽略端口、假定默认值。这些差异应当写在标签旁的记录里,否则看起来就像解析器的毛病。

发现不是身份验证

SRV 答复只说连到哪里,对你到达之后该信任谁只字未提。客户端的证书校验与服务器身份检查要保持原样,因为一条别人能伪造的记录不该变成信任决策。DNS 答复可被缓存,也可被控制区域的人修改,因此不适合用来承载策略。

对不支持发现的客户端,分发它接受的配置文件或网关 URL,并记录哪个产品用哪种方式。这份记录能阻止下一位管理员加了记录就以为处处可用。SRV 规范描述的是目标之间的选择,把它读成授权机制,正是有用的记录变成安全假设的路径。有意识地发布,在文档里写出标签名,并把客户端当作决定这一切是否有意义的那一环。

相关文章