我有一台名为 的服务器gamma
,在工作中不断启动并运行。有时我从家里连接到它,在这种情况下我使用公共 IP 地址55.22.33.99
。有时,我在工作时连接到它,而不是不必要地反弹我的数据包,我通过本地 IP 地址进行连接192.168.1.100
。
目前,我将它们分成两个不同的条目~/.ssh/conf
Host gamma-local
HostName 192.168.1.100
Port 22
User andreas
Host gamma-remote
HostName 55.22.33.99
Port 12345
User andreas
所以,如果我在工作,我只需输入即可ssh gamma-local
;如果我在家(或世界其他地方),我会跑步ssh gamma-remote
。
连接到服务器时,我宁愿不必根据我所在的位置输入不同的名称,我宁愿该部分自动完成;例如,在某些情况下,我有自动脚本可以连接那些不知道我在哪里的人。
有使用 Bash 脚本解决此问题的问题首先“尝试”连接到本地,如果无法连接,则尝试连接到远程 IP 地址。这很好,但是(1)似乎效率低下(特别是因为有时您必须“等待”连接超时,因为它们并不总是立即发回错误)并且(2)需要 Bash 并拖拽脚本。
是否有另一种方法可以实现此目的,既不依赖于 Bash 脚本的使用,也不首先“测试”连接是否有效?
答案1
如果您有办法识别您所在的网络,那么您可以使用Match
关键字~/.ssh/config
做你想做的事。这需要 OpenSSH ≥6.5。
我用类似的东西
Match originalhost gamma exec "[ x$(/sbin/iwgetid --scheme) != xMyHomeESSID ]"
HostName 192.168.1.100
Port 22
Host gamma
User andreas
Port 12345
HostName 55.22.33.99
因此,我使用所用 wifi 网络的标识符来确定我是否在家用于 SSH 连接,但也可以使用检查分配给您计算机的 IP 地址或任何其他可以区分这两个网络的内容。
答案2
如果您碰巧在工作中拥有私人名称服务器,并且您在办公室和家里使用同一台笔记本电脑,则可以利用它来实现此目的:
- 修改你的
nsswitch.conf
机器以首先检查 DNS gamma
在办公室的私有 DNS 中创建一个 DNS 条目以解析为 192.168.1.100。- 在计算机的 /etc/hosts 文件中创建一个条目以解析
gamma
为 55.22.33.99。
这样,当您ssh gamma
在办公室时,它将从办公室 DNS 解析为 192.168.1.100,当您从家里连接时,它将从您的主机文件解析为 55.22.33.99。
聚苯乙烯:此答案假设您不希望 gamma 有公共 DNS 条目。另外,如果您从 Windows 计算机通过 SSH 连接到服务器,我认为应该有一些相当于 nssswitch.conf 文件的地方来覆盖主机文件条目。
答案3
几年前,我写过一个程序出于类似的目的。它可能适合您的需求。使用该程序,ssh 配置可能如下所示:
Host gamma
ProxyCommand ssh-multipath-proxy 192.168.1.100:22 55.22.33.99:12345
User andreas
答案4
~/.ssh/config
使用 IP 地址作为主机名时无法实现此目的。事实上,您不仅连接到不同的 IP 地址,还连接到不同的端口,这一事实带来了额外的复杂性,因为这几乎排除了对 DNS 解析器的任何调整。
我纠正了 - 你可以使用Match originalhost ... exec ...
组合~/.ssh/config
- 请参阅@MichałPolitowski 的回答。然而,尽管它对于 OpenSSH 来说可以完美工作,但您可能不一定在其他 SSH 客户端中找到类似的功能。
您可以使用一个简单的包装器(如果您需要从各种 shell 中使用它,则可以是 shell 函数或脚本)来解决该问题ssh
,它将检查您所在的网络并使用适当的Host
条目。最大的问题是,如何可靠地检测您所在的网络。我会想到本地 IP 地址,但它并不可靠,因为您可能从使用与工作网络相同子网的 LAN 进行连接。
如果您可以为本地和远程网络使用相同的端口,您可以/etc/resolv.conf
根据您所在的网络进行编辑 - 显然它必须自动完成(很可能是通过 DHCP 客户端的挂钩脚本)。或者 - 更好 - 运行本地名称服务器(例如dnsmasq
)并为其提供适当的配置。但这超出了这个问题的范围。
另一种选择 - 如果您只需要交互连接 - 是使用可扫描的命令完成~/.ssh/config
。这将节省您的打字时间(特别是如果您有足够多的不同Host
条目)。像这样的东西(用于bash
初始化):
# complete session names for ssh
declare -g _ssh_complete_hostlist 2> /dev/null
function _ssh_complete_init () {
_ssh_complete_hostlist=$( \
sed -nr '/^\s*Host\s*=/{s/^[^=]+= *//;s/ /\n/g;p}' ~/.ssh/config \
| sort )
}
_ssh_complete_init
function _ssh_complete () {
local match=${COMP_WORDS[${COMP_CWORD}]}
local hosts=
local default=
for h in $_ssh_complete_hostlist; do
if [[ $h =~ ^$match ]]; then
hosts="$hosts $h"
fi
done
if ! (( ${COMP_CWORD} == ${#COMP_WORDS[@]}-1 )); then
default=$( compgen -f ${COMP_WORDS[${COMP_CWORD}]} )
fi
COMPREPLY=($hosts $default)
}
complete -F _ssh_complete ssh
第一个函数创建一个完成主机的列表(通常在每个 shell 中运行一次就足够了),第二个函数执行实际的完成,尽管方式有点笨拙 - 它只在主机名是时才完成主机名。命令行上的最后一个标记。
综上所述,解决此问题的正确方法是通过 VPN 连接到工作网络,从而可以像在办公室一样访问本地工作 IP 地址。然后,您可以将地址硬连接到您喜欢的任何一层:~/.ssh/config
或/etc/resolv.conf
(恕我直言,最好的选择)办公室名称服务器。