我正在寻找一个 SSH 包装器(或 SSH 选项,如果有的话),它可以尝试依次连接多个 IP 地址,直到其中一个成功。例如10.0.0.1
,然后my_machine.example.com
和最后my_machine.example.com -J me@other_machine.example.com
。
有什么工具可以做到这一点?
答案1
这是我的通用包装器。没有选项或地址是硬编码的。您可能需要调整的唯一内容是第 3 行中的可执行文件ssh
的路径(您可以使用,我选择了完整路径)。您将在下面找到我的完整代码。ssh
executable=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
事实证明,使用ProxyCommand
ssh 配置中的选项可以相当轻松地完成与此非常类似的操作。在我的用例中,我跳过了首先连接到 10.0.0.1 的要求,最终得到了以下结果:
Host my_machine.example.com
ProxyCommand nc "%h" "%p" || ssh -W "%h:%p" me@other_machine.example.com
通过将其与主连接(ControlMaster
,ControlPath
和ControlPersist
)相结合,该技术可以实现我最初想要的 95%,并且在重复连接时速度非常快(如果必须经过跳转,第一个连接总是会有点慢)。