如何让 SSH 的 ControlPath 区分 IPv4 和 IPv6?

如何让 SSH 的 ControlPath 区分 IPv4 和 IPv6?

我在用着

ControlMaster   auto
ControlPath     ~/.ssh/tmp/%l_%r@%h:%p

在 my 中,~/.ssh/config通过 SSH 访问主机时使用同一连接打开多个会话。

这对于大多数用例来说效果很好,但不允许我同时通过 IPv4 和 IPv6 连接到同一主机名;所有其他连接都使用第一个连接创建的控制套接字,因为不允许ControlPath区分 IPv4 和 IPv6 连接。

有没有办法为 IPv4 和 IPv6 连接提供单独的控制套接字(也许通过找到一种使用远程 IP 而不是套接字路径中的远程主机名的方法)?


编辑#1

我只记得和文件Match中可用的选项并尝试:ssh_configsshd_config

Match AddressFamily inet
    ControlPath     ~/.ssh/tmp/%l_%r@%h:%p.inet

Match AddressFamily inet6
    ControlPath     ~/.ssh/tmp/%l_%r@%h:%p.inet6

不幸的是,这失败了“不支持 Match 属性 AddressFamily“当我尝试连接到任何主机时,我又回到了原点......

答案1

这不是典型的用例,因此没有直接的方法可以做到这一点。但是,如果您不需要太多远程主机,您可以使用用户配置文件来解决此问题:

Host hostname-4
    Hostname hostname
    AddressFamily inet
    ControlPath ~/.ssh/master4-%l%h%p%r
Host hostname-6
    Hostname hostname
    AddressFamily inet6
    ControlPath ~/.ssh/master6-%l%h%p%r

答案2

我已将我的答案分成两个单独的答案,以便您可以分别对“包装器”和“补丁”方法进行上/下投票。

解决方案1:编写包装函数

ssh ()
{
    controlpath=""
    for argument in $@
    do
        if [[ "$argument" = "-"*"4"* ]]
        then
            controlpath="~/.ssh/tmp/%l_%r@%h:%p.inet"
        fi
        if [[ "$argument" = "-"*"6"* ]]
        then
            controlpath="~/.ssh/tmp/%l_%r@%h:%p.inet6"
        fi
    done

    if [ -n "$controlpath" ]
    then
        /usr/bin/ssh -o "ControlPath=$controlpath" $@
    else
        /usr/bin/ssh $@
    fi
}

该包装函数将指示为、和ssh创建单独的控制套接字。 它可能无法正确解析类似的内容(即使技术上允许),但它应该是简单场景的最简单的解决方法。ssh hostssh -4 hostssh -6 host
ssh -464466 host

答案3

我已将我的答案分成两个单独的答案,以便您可以分别对“包装器”和“补丁”方法进行上/下投票。

解决方案2:使用来源,卢克!

就像我在回答更新中提到的那样,OpenSSH 不支持Match AddressFamily然而。在解析中
添加相应的子句相当容易Match读取conf.c。我的概念验证补丁有效,但涉及一堆硬编码字符串,因此在我将其提交给 OpenSSH 维护人员考虑之前,它肯定需要做更多的工作。

%a如果我们不能仅添加另一个占位符(例如)来ControlPath定义计算结果为any,inet或,这也可能值得一看,inet6具体取决于所使用的地址族。然而,这会导致问题,具体取决于评估和存储选项
的顺序,因此可能需要进行一些相当广泛的更改才能起作用。 同样的问题也适用于我将占位符扩展为用于连接的实际地址族的最初想法:地址族依赖于在存在合适的控制套接字时甚至不进行的调用。AddressFamilyControlPath
gethostbyname()

相关内容