尝试多个连接参数的 SSH 包装器

尝试多个连接参数的 SSH 包装器

我正在寻找一个 SSH 包装器(或 SSH 选项,如果有的话),它可以尝试依次连接多个 IP 地址,直到其中一个成功。例如10.0.0.1,然后my_machine.example.com和最后my_machine.example.com -J me@other_machine.example.com

有什么工具可以做到这一点?

答案1

这是我的通用包装器。没有选项或地址是硬编码的。您可能需要调整的唯一内容是第 3 行中的可执行文件ssh的路径(您可以使用,我选择了完整路径)。您将在下面找到我的完整代码。sshexecutable=ssh

假设你将其保存为sshmt("ssh, multi target"),其中你$PATH指向的是 ,并使用 使其可执行chmod。然后熟悉语法:

sshmt -h

摘抄:

用法

sshmt [-v] ARGS [+[N] ARGS]... [-- COMMON]
sshmt -h

概要

ssh使用第一组参数ARGS 和公共参数调用命令COMMON。如果此命令返回退出状态255并且第二组参数ARGS 存在,ssh则将使用这些新参数ARGS和调用第二组参数COMMON;然后调用第三组,依此类推。

在您的示例中,您想像这样调用它:

sshmt 10.0.0.1 + my_machine.example.com + my_machine.example.com -J me@other_machine.example.com

或者更好的是使用一些方便的超时:

sshmt 10.0.0.1 +2 my_machine.example.com +3 my_machine.example.com -J me@other_machine.example.com +5

df -h要以直接的方式远程执行,请调用:

sshmt 10.0.0.1 df -h +2 my_machine.example.com df -h +3 my_machine.example.com -J me@other_machine.example.com df -h +5

但你不想重复自己,所以请使用这个:

sshmt 10.0.0.1 +2 my_machine.example.com +3 my_machine.example.com -J me@other_machine.example.com +5 -- df -h

管道也应该可以正常工作:

echo 123 | sshmt 10.0.0.1 +2 my_machine.example.com +3 my_machine.example.com -J me@other_machine.example.com +5 -- sh -c "cat > /tmp/foo"

实际上你可能需要定义一个别名:

alias myssh='sshmt 10.0.0.1 +2 my_machine.example.com +3 my_machine.example.com -J me@other_machine.example.com +5 --'

然后登录

myssh

或者执行如下命令

myssh uptime

这是代码。它的所有逻辑实际上只是解析命令行。

#!/usr/bin/env bash

executable=/usr/bin/ssh
exename="${executable##*/}"
myname="${0##*/}"
declare -a args
declare -a seq_opts
declare -a common_opts

main () {
  split_opts "$@"
  process_seq "${seq_opts[@]}" "+"
  exit 255
}

split_opts () {
  while [ $# -ne 0 ]; do
    if [ "$1" = "--" ]; then
      shift
      common_opts=("$@")
      break
    else
      seq_opts=("${seq_opts[@]}" "$1")
      shift
    fi
  done
}

process_seq() {
  if [ "$*" = "+" ] || [ "$1" = "-h" ]; then
    print_help; exit 0
  fi

  while [ $# -ne 0 ]; do
    if [ "${1:0:1}" != "+" ]; then
      args=("${args[@]}" "$1")
    else
      timeout="${1:1}"
      [[ "$timeout" =~ ^[0-9]*$ ]] || print_error
      if [ "${#args[*]}" -ne 0 ]; then
        printf '%s\n' "${myname}: trying ${args[*]}" >&2
        "$executable" ${timeout:+-o ConnectTimeout=$timeout} "${args[@]}" "${common_opts[@]}"
        status=$?
        [ $status -ne 255 ] && exit $status
        args=()
      fi
    fi
    shift
  done
}

print_error() {
  cat >&2 << EOF
${myname}: error parsing command line
Try '$myname -h' for more information.
EOF
  exit 254
}

print_help() {
  cat << EOF
USAGE

    $myname [-v] ARGS [+[N] ARGS]... [-- COMMON]
    $myname -h

SYNOPSIS

Invokes \`${exename}' command with the first set of arguments ARGS
and common arguments COMMON. If this command returns
exit status of 255 and the second set of arguments ARGS
exists, then the second \`ssh' will be invoked with these
new ARGS and COMMON; then the third and so on.

Empty set of arguments is discarded without invoking \`ssh'.
Successful invocation of \`ssh' stops parsing the command
line and makes the script exit.

OPTIONS

    -h     print this help and exit (must be the first option)
    +, +N  execute \`ssh' with preceding ARGS and COMMON

N, if given, specifies timeout for \`ssh' invoked with
immediately preceding ARGS. This is just a convenient
alternative for \`-o ConnectTimeout=N'.

The final set of arguments may or may not have a terminating \`+'.

EXIT STATUS

The exit status is 254 in case of an error while parsing
the command line; 255, if none of \`${exename}' managed
to connect; or an exit status of successfully connected
\`${exename}' otherwise.

EXAMPLES

To try 10.0.0.1 and, if failed, the alternative address:
    $myname 10.0.0.1 + my_machine.example.com

To execute \`df -h' with timeouts:
    $myname 10.0.0.1 +3 my_machine.example.com +5 -- df -h

LICENCE
        Creative Commons CC0.
EOF
}

main "$@"

答案2

据我所知,没有这样的内置功能。但是,这可以很容易地编写脚本:

#!/bin/bash

usage ()
{
    echo "usage:"
    echo "  $0 MYHOST"
    echo "or"
    echo "  $0 IP DNS PROXYJUMP"
}

if [[ $# -eq 1 ]]; then
    host="$1"

    ssh ${host}_ip && exit 0
    ssh ${host}_dns && exit 0
    ssh ${host}_proxyjump && exit 0
    exit 1
else if [[ $# -eq 3 ]]; then
    ip="$1"
    dns="$2"
    proxy="$3"

    ssh "$ip" && exit 0
    ssh "$dns" && exit 0
    ssh "$dns" -J "$proxy" && exit 0
    exit 1
else
    echo "Illegal number of argument"
    usage
    exit 1
fi

包含以下.ssh/config文件:

Host MYHOST_ip
  Hostname 10.0.0.1

Host MYHOST_dns
  Hostname my_machine.example.com

Host MYHOST_proxyjump
  Hostname my_machine.example.com
  ProxyJump me@other_machine.example.com

笔记例如,在使用 proxyjump 配置的情况下,连接可能需要很长时间。事实上,连接可能在 2 次超时后发生。

答案3

这听起来很像另一篇文章

无耻转发


这是一个非常好的问题,我也一直想知道。

答案是“不可以”。你不能。所以我决定自己做。

您可以使用一个简单的脚本来获得所需的功能。

我写了一个Github Pages 上的帖子


结论

在 UNIX 上,尝试以下操作
:(在 Windows 上,阅读我的Github 页面帖子

~/.ssh/scripts/检查主机指纹.sh

#!/bin/bash

fingerprints=$(ssh-keygen -lf <(ssh-keyscan $1 2>/dev/null))

for fingerprint in $fingerprints
do
        if [ "$fingerprint" == "$2" ]
        then
                exit 0
        fi
done

exit 1

〜/.ssh /配置


# Host with Global Fallback
Match host "my_auto_host" exec "/bin/bash %d/.ssh/scripts/check-host-fingerprint.sh 192.168.0.100 SHA256:12345678901234567890123456789012345678901234567"
    Hostname 192.168.0.100
    Port 22
Host my_auto_host
    User username
    Hostname server.domain.org
    Port 1022

# Secondary Host using Primary as Proxy
Host secondary
    User u5ernam3
    Hostname 192.168.0.101
    Port 22
    ProxyJump my_auto_host

请阅读我的Github Pages 帖子如果这对你不起作用。

答案4

事实证明,使用ProxyCommandssh 配置中的选项可以相当轻松地完成与此非常类似的操作。在我的用例中,我跳过了首先连接到 10.0.0.1 的要求,最终得到了以下结果:

Host my_machine.example.com
    ProxyCommand nc "%h" "%p" || ssh -W "%h:%p" me@other_machine.example.com

通过将其与主连接(ControlMasterControlPathControlPersist)相结合,该技术可以实现我最初想要的 95%,并且在重复连接时速度非常快(如果必须经过跳转,第一个连接总是会有点慢)。

相关内容