隧道建立成功,证书也通过验证,随后对话框提示无法设置 DNS 服务器或域。在 Linux 上,这个对话框通常与网关无关:客户端通过 D-Bus 把名称配置交给 systemd-resolved,一旦交接被拒绝,接口仍保持连接,而 名称解析仍指向旧链路。同一台笔记本在配置文件获得后缀之前解析正常,这正是值得追查的线索。对话框出现的那一刻,隧道本身没有任何变化。

没有后缀时,客户端只推送名称服务器。加上一个搜索域后,就会有第二次调用加入进来,SetLinkDomains,它带有自己的授权检查,所以同一个配置文件在 Windows 上能用,在这里却失败。两种情况下网关推送的设置完全相同,拒绝这些设置的组件就在本地。

确认由 systemd-resolved 负责解析

这个客户端只与 systemd-resolved 打交道,不与任何其他组件通信。Arch 等若干发行版默认将其禁用,而 /etc/resolv.conf 也可能完全属于另一个解析器,所以在查看权限之前先确定所有者。

三条命令即可确认:

systemctl status systemd-resolved
ls -l /etc/resolv.conf
resolvectl status

你要找的是处于活动状态的服务、指向 /run/systemd/resolve/stub-resolv.conf 的符号链接,以及 resolvectl 中按链路给出的 DNS。如果所有者是 NetworkManager,就把它交给 resolved,而不是和客户端较劲;下面的 drop-in 会同时设置两个键:

[main]
dns=systemd-resolved
systemd-resolved=true

该文件存在后重启一次 NetworkManager。解析器处于非活动状态、客户端却仍在调用它的 D-Bus 名称,产生的错误不会点出任何一方的名字。

观察失败的那次 D-Bus 调用

这一步能把对话框变成具体答案。在一个终端观察解析器接口,在另一个终端观察日志,然后重新连接:

sudo dbus-monitor --system "interface='org.freedesktop.resolve1.Manager'"
journalctl -fu systemd-resolved

应该出现三次调用:SetLinkDNS、SetLinkDomains 和 SetLinkDefaultRoute。以错误应答返回的那次就是要修的目标。该应答通常会说明原因,例如 org.freedesktop.DBus.Error.AccessDenied 对 SetLinkDomains。记下是哪一次调用,因为下一节正是关于如何放行这次调用。

授予客户端所需的 polkit 动作

写规则之前先读策略。以服务方式运行的客户端无法应答交互式提示,因此隐式的 auth_admin_keep 是死路一条。

pkaction --verbose --action-id org.freedesktop.resolve1.set-domains
pkaction --action-id org.freedesktop.resolve1.set-dns-servers --verbose

如果答案是 auth_admin_keep,客户端就需要一条显式规则。下面的片段允许 VPN 客户端在连接期间使用的四个 resolve1 动作,其余一切仍停留在 polkit.Result.NOT_HANDLED:

polkit.addRule(function(action, subject) {
  var allowed = [
    "org.freedesktop.resolve1.set-dns-servers",
    "org.freedesktop.resolve1.set-domains",
    "org.freedesktop.resolve1.set-default-route",
    "org.freedesktop.resolve1.revert"
  ];
  if (allowed.indexOf(action.id) !== -1 &&
      subject.isInGroup("wheel")) {
    return polkit.Result.YES;
  }
  return polkit.Result.NOT_HANDLED;
});

把它放进 /etc/polkit-1/rules.d/,取一个日后容易辨认的文件名,例如 50-azurevpn.rules,并在注销再登录之前把片段中的组名换成你自己的。要保持范围很窄,因为对每个账户允许全部 resolve1 动作,既比这个客户端需要的更宽,日后也更难审计。

改 polkit 之前先检查配置文件 XML

手工改过的配置文件可能被无声忽略。Microsoft 记录了扁平布局,其中 dnsserver 条目直接放在 dnsservers 里,后缀则放在 dnssuffixes 里。在每个地址外面再套一层包装元素就不是这种形状,客户端会悄悄退回网关推送的内容。

动 polkit 之前先做移除测试。去掉后缀块,重新连接,观察对话框是否变化。如果变化了,失败的调用就是域交接,修法是授权,而不是再改一次 XML。

在隧道链路上验证该域

重新连接并再次读取 resolvectl status,确认隧道链路同时带有名称服务器和搜索域。解析一个短的私有名称,而不是公网名称。如果名称能解析、但后面的服务没有应答,说明 DNS 交接已经成功,剩下的问题是路由。

把解析器所有者、失败的 D-Bus 调用、规则文件和配置文件版本写进工单。这四行能让下一台 Linux 笔记本变成一次简短修复,而不是一次重复调查。

相关文章