需要在备份前确保 VPN 已连通的脚本,常常直接启动 openvpn。这样就抛开了 Tunnelblick 已经管理的配置、DNS 和路由处理。受支持的途径是 Tunnelblick 自己的 AppleScript 接口,它接受针对指定配置的 connect、state 与 disconnect 请求。请使用它,让应用保持主导。

与应用对话,而不是与 openvpn 对话

OpenVPN 配置、引擎选择、脚本以及 DNS 与路由的集成都由 Tunnelblick 掌管。单独的 openvpn 二进制是另一种启动方式,并不是通往同一连接的捷径。

调用应用的脚本接口能保住这种归属关系,也让每个请求都可以复核。

这里的示例假定 Tunnelblick 位于 Applications,可用的配置名为 HQ,命令在已登录的 Mac 用户会话中运行。请把名字换成你实际拥有的那份配置。

只启动一个指定的配置

connect 请求会指明配置,而不是去连接上一次选中的东西。

在拥有该配置的用户会话中运行它:

osascript -e 'tell application "/Applications/Tunnelblick.app" to connect "HQ"'

走完常规的登录提示。macOS 可能询问调用方应用是否获准控制 Tunnelblick;批准之前先看清是哪个应用、目标是什么。自动点掉那个对话框,正好抹掉了对话框的意义。

connect 请求会在隧道就绪之前返回

Tunnelblick 的脚本指南写得很明确:connect 在连接完成之前就返回。退出状态为零只表示请求被接受,并不表示流量已经在走。

单独读取状态:

osascript -e 'tell application "/Applications/Tunnelblick.app" to get state of first configuration where name = "HQ"'

CONNECTED 是连接状态的结果。它仍然不能证明作业所需的私有资源可达,所以在开始依赖它的工作之前,要单独确认这一点。

脚本接口里的其他控件涵盖的是更宽泛的操作,只改一个配置时用不上。

带截止时间地等待,然后失败

无限轮询正是脚本挂一整夜、并挡住下一次运行的原因。给等待设定截止时间、较短的间隔,以及明确的失败结果。除 CONNECTED 以外的状态一律视为未就绪,过渡状态也包括在内。把最后看到的状态记进日志,失败时就能自我解释。

有上界的循环大致如下:

for i in $(seq 1 30); do
  state=$(osascript -e 'tell application "/Applications/Tunnelblick.app" to get state of first configuration where name = "HQ"')
  if [ "$state" = "CONNECTED" ]; then exit 0; fi
  sleep 1
done
echo "tunnel did not reach CONNECTED" >&2
exit 1

三十秒只是例子,不是通用的超时值。请按该配置实际使用的认证路径来定截止时间,并把它留在工作流的记录里。

按名字检查状态并断开

要停掉同一个配置,就用同一个名字调用 disconnect。这样请求范围窄,也不会碰其他配置。

osascript -e 'tell application "/Applications/Tunnelblick.app" to disconnect "HQ"'

把配置名与控制器一起记在工作流的记录里,并附上预期的认证与完成检查。正是这份记录让命令在半年后仍然可以复核。

随计算机启动的行为是另一种模式。请使用 Tunnelblick 有据可查的启动选项,以及它所要求的凭据设置。在已登录的桌面会话里运行的命令,与随机器启动的服务并不共享同一个上下文。不要以为登录时能跑的脚本在开机时也能跑。要单独测试启动路径,同样设定截止时间并记录日志。

相关文章