如果有一台终端服务器可以通过代理服务器 a 或代理服务器 b 连接,但有时只有其中一台工作。有没有办法指定 ProxyJump 可以是代理服务器 a 或 b config
?ProxyCommand
也还好,但命令行解决方案(带有参数或 bash 脚本)是不可接受的。
Host proxya proxyb
HostName %h.example.com
User user1
# Proxy servers
Host end-server.example.com
User user1
ProxyJump # Here, how should I configure "either `proxy1` or `proxy2`"?
答案1
这个答案依赖于 shell 脚本...但在 openssh 的配置阶段执行。
使用Match
AMatch
宣言(这是声明的超集Host
)允许应用除主机名之外的标准。在这些标准中,有一个exec
关键字可以运行脚本以获取其返回码为 true 或 false 结果:
该
exec
关键字在用户的 shell 下执行指定的命令。如果命令返回零退出状态,则条件被视为 true。包含空白字符的命令必须用引号引起来。exec
接受令牌部分中描述的令牌的参数。
它可用于判断代理是否已启动,但不能用于提供要使用的代理,因为需要布尔类型的结果。这意味着Match
必须为每个可能的代理配置一个条目。像往常一样,将使用第一个匹配条目(但另请参阅末尾的警告)。
例如,将脚本放入~/.ssh/bin
:
mkdir ~/.ssh/bin
对于 TCP 层的最小检测,可以使用socat
(nc
或nmap
其他候选者)检查与提供的主机和端口参数的 TCP 连接。可以将其设为可执行以避免sh
下面配置中的额外内容。
~/.ssh/bin/isjumphostavailable.sh
:
#!/bin/sh
MAXDELAY=4
socat /dev/null tcp:"$1":"$2",connect-timeout="$MAXDELAY"
这里socat
不会等待超过 4 秒,如果连接会立即结束(因为/dev/null
's EOF)。它的返回代码提供脚本的返回代码:如果连接成功,则返回 0 (=> true),否则返回 0 (=> false)。
要使用上面的脚本,配置变为:
# Jump hosts' fixed settings
Host proxya proxyb
Hostname %h.example.com
User user1
# End server's fixed settings (the factorized part)
Host end-server.example.com
User user1
# End server's settings with runtime detection (2 lines per distinct proxy)
Match host end-server.example.com exec "sh ~/.ssh/bin/isjumphostavailable.sh proxya.example.com 22"
ProxyJump proxya
Match host end-server.example.com exec "sh ~/.ssh/bin/isjumphostavailable.sh proxyb.example.com 22"
ProxyJump proxyb
笔记:
host
继承先前参数的分辨率Hostname
(如果有)并用作,
分隔符。因此host !proxy*.example.com,*.example.com
可以用于应用到除代理本身之外的任何其他终端服务器情况。exec
接受单个字符串作为参数:所有内容都必须在双引号内提供。
警告:
exec
该脚本将始终针对配置中的每个匹配条目进行评估,因此即使proxya
可用并因此用作第一个匹配项,proxyb
仍将被扫描。为了避免这种情况,可以在脚本中添加额外的智能,例如使用额外的文件存储状态和先前的决策(也可以用作缓存)来限制它实际探测的次数。如果它是关于可用路由而不是可用服务器(例如:VPN 是否添加了某些特定路由?),则ip -json route get ... | jq ...
可以在脚本中使用而不发出任何内容。你明白了。
使用ProxyCommand
ProxyJump
主要是一个包装ProxyCommand
。即使ssh
在详细模式下也可以写出如下内容:
debug1: Setting implicit ProxyCommand from ProxyJump: ssh -v -W '[%h]:%p' proxya
debug1: Executing proxy command: exec ssh -v -W '[end-server.example.com]:22' proxya
因此,只需使用除此包装器之外的其他包装器,这一次将直接选择第一个可用的代理候选者,从而克服之前的Match ... exec
警告。该脚本将包含要尝试的代理列表,并将使用第一个找到的可访问的代理。
~/.ssh/bin/usefirstavailablejumphost.sh
:
#!/bin/sh
MAXDELAY=4
for p in proxya proxyb; do
if socat /dev/null tcp:"$p".example.com:22,connect-timeout="$MAXDELAY"; then
exec ssh -W "[$1]:$2" "$p"
fi
done
exit 1
注意:这对[]
(刚刚从 的使用中复制ProxyJump
)还允许使用该-W
参数正确处理 IPv6 地址。
使用此脚本进行配置:
# Jump hosts' fixed settings
Host proxya proxyb
Hostname %h.example.com
User user1
# End server's settings
Host end-server.example.com
User user1
ProxyCommand sh ~/.ssh/bin/usefirstavailablejumphost.sh %h %p
和以前一样,该行(其行为与sHost
不完全相同)也可以写为:Match
host
Host !proxy* *.example.com
答案2
没有用于指定多个备用ProxyJump
服务器的语法,但您可以执行以下操作:
Host end-server-p1
Hostname end-server.example.com
User user1
ProxyJump proxy1
Host end-server-p2
Hostname end-server.example.com
User user1
ProxyJump proxy2
现在你可以尝试一下ssh end-server-p1
,如果这不起作用,你可以运行end-server-p2
。