WireGuard 上的 mDNS:对等方应答前的三道关口
Avahi 需要合格接口、通往组的路由,以及拥有目标地址的对等方。三道关口、三次独立检查,且没有任何分发。
在 WireGuard 设备上设置多播标志只会让接口对发现软件合格,标志的作用仅此而已。它不会告诉协议组包该去往何处,而在拥有多个对等方的设备上并不存在唯一显然的答案。运行中的守护进程与已发现的服务之间横着三道独立的关口。
请按顺序测试,因为通过一道并不能说明下一道的情况。
第一道关口:标志与守护进程的策略
Linux 的 WireGuard 设备被创建为不带 ARP 的点对点链路,默认不携带多播标志。添加标志是一次本地接口变更,由管理该设备的任何组件执行。在此之上 Avahi 有自己的一套世界观,其默认策略完全跳过点对点接口。因此,在任何一个数据包移动之前,就已经有两项独立的合格性测试。
所以守护进程需要的是一个明确的决定,而不只是一个正在运行的进程。其有文档记录的控件包括 allow-interfaces、deny-interfaces 和 allow-point-to-point,最后一项正是人们容易忽略的设置。
下面的检查会报告链路标志、多播路由,以及守护进程的配置究竟能否被解析:
ip -d link show wg0
ip route get 224.0.0.251
avahi-daemon --check
成功启动的守护进程未必在你关心的接口上打开了套接字。请阅读它的有效配置,而不是假定服务状态等同于覆盖范围。
第二道关口:通往组的路由
第二道关口是普通的路由。发往 224.0.0.251 的数据包会像其他任何流量一样遵循转发表,如果转发表把它从物理 LAN 接口送出,那么任何 WireGuard 配置都改变不了这一点。先修好路由,余下的排查就会变短。在触碰任何对等方密钥之前,先看看内核对组地址报告了什么。
| Observation | Gate it belongs to | What it does not prove |
|---|---|---|
Multicast flag present on wg0 | Interface eligibility | The daemon will use the interface |
Route to the group via wg0 | Forwarding | Any peer will receive it |
| Destination inside a peer's allowed list | Peer selection | That peer's network will answer |
没有特定路由时,内核会退回链路自身的多播处理,这就是为什么默认行为在扁平 LAN 上看起来正确,而一旦同一组流量需要经隧道送出就立刻出错。失败从发送方一侧看是无声的:查询去了某个地方,应答却永远不会到达。
第三道关口:WireGuard 为每个数据包选择一个对等方
WireGuard 通过在允许地址集合中查找目标来选择出站对等方,而 Linux 的发送路径对每个数据包执行一次该查找。结果只有一个,数据包就是为该对等方加密的。同一个组前缀出现在多个对等方的允许列表中并不会产生成员关系或复制;它产生的是一次含糊的查找,最终落到其中之一。
在两端点的专用链路上,这正是你想要的,因为故意承载的组流量只有一个预期接收者。在拥有五个对等方的接口上,这是限制而非特性,修复应当落在设计里,而不是某个对等方的配置里。
分发式设计需要显式中继、独立链路,或者完全不同的发现机制。因为每个客户端都能 ping 通网关就把两端点方案当作多客户端解法发布,正是这类方案被错误部署的方式。
入站方向的检查方式不同:收到数据包的源必须落在已认证对等方的允许列表之内。在那里添加多播目标 并不能替代发送方真实的源归属。
反射是边界,不是桥梁
Avahi 的反射器在它选定的接口之间于应用层重现 mDNS 报文。它是网络之间的发现边界,不是以太网桥,也不是通用多播路由器。两个连接到相同网络的反射器会乐此不疲地制造重复通告的环路。
反射还会把服务名称及其元数据交给另一个网络,这既是路由决定,也是隐私决定。请限制所选接口,并在已安装版本支持时使用服务过滤器,从而只让获得授权的用户所需的通告跨越边界。
发现与使用仍然是两个独立的结果。客户端可能看到某服务的通告,而其通告地址从客户端所在位置不可达,或其端口被访问策略拒绝。通告出现后请确认服务连接;如果应用支持稳定的 DNS 名称或明确的服务器地址,请优先采用这些方式,而不是扩展链路本地发现。加密密钥路由说明涵盖了这一切所依赖的基于目标的对等方选择。