ssh 配置文件的多个替代 ProxyJump

ssh 配置文件的多个替代 ProxyJump

如果有一台终端服务器可以通过代理服务器 a 或代理服务器 b 连接,但有时只有其中一台工作。有没有办法指定 ProxyJump 可以是代理服务器 a 或 b configProxyCommand也还好,但命令行解决方案(带有参数或 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 层的最小检测,可以使用socatncnmap其他候选者)检查与提供的主机和端口参数的 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不完全相同)也可以写为:Matchhost

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

相关内容