我的笔记本电脑上的 ssh 配置中有以下两个条目:
Host server1_int
Hostname 192.168.1.92
IdentityFile ~/.ssh/id_rsa
User me
Port 1234
Host server1_ext
Hostname 134.x.y.z
IdentityFile ~/.ssh/id_rsa
User me
Port 4321
该服务器位于 NAT 后面。当我也位于 NAT 后面时,我需要通过 ssh 进入“server1_int”。如果我在互联网上的其他地方,我需要通过 ssh 进入“server1_ext”才能访问我的服务器。有没有办法配置 ssh,使其根据我的笔记本电脑当前所在的子网选择正确的条目?
答案1
您可以使用~/.ssh/config
(或全局客户端配置)Match
关键字,并根据exec
条件运行脚本并返回判定结果(真或假):
匹配
限制以下声明(直到下一个主持人或者匹配 仅当满足 Match 关键字后的条件时才使用。匹配条件使用一个或多个条件或单个标记指定全部始终匹配。可用的条件关键字有:典范,执行,主持人,原始主机,用户, 和本地用户。 这全部标准必须单独出现或紧随其后出现典范。
[...]
这执行关键字在用户的 shell 下执行指定的命令。如果命令返回零退出状态,则条件视为真。包含空格字符的命令必须用引号引起来。执行接受 TOKENS 部分中描述的令牌。
让我们将脚本中的“尝试这个 IP 是否需要该网关?(包括检查没有网关)”作为判断~/bin/hasthisgateway.sh
(这个示例脚本,用于 Linux,可能需要改进。不要忘记chmod u+rx
它):
#!/bin/sh
gateway=$(/sbin/ip -o route get "$1" |grep -E -o ' via ([0-9]+.){3}[0-9]+'|sed 's/^ via //')
[ "$gateway" = "$2" ] # final test and return code
对于第一种情况,假设我们在同一个 LAN 中,我们不需要网关,对于第二种情况,也就是默认的剩余情况,我们不需要执行条件。虽然它会在所有位置匹配,但它不会覆盖以前的值,如男人:
对于每个参数,将使用第一个获得的值。
[...]
由于使用每个参数的第一个获得的值,因此应在文件开头附近给出更多特定于主机的声明,并在末尾给出一般默认值。
但这还不够:在其他地方主持人条目还表示它仅适用于下一个主机或者匹配条目。因此,实际上默认情况下,无论主机是什么,这些匹配条目都会被使用(它们应该与主机条目在同一级别缩进),并且我们不能Match all
对第二种情况使用简单的“要么”或“要么”会将主机名设置为任何其他设置,包括其他主机设置。为了避免这种情况,请添加一个原始主机标准:
originalhost 关键字与命令行中指定的主机名匹配。
可以在默认值之前插入更多案例(其他内部 LAN?可能有一个特定的网关,或者选择更好的标准脚本)。
~/.ssh/config
:
Host server1
#common parts
IdentityFile ~/.ssh/id_rsa
User me
#internal
Match originalhost server1 exec "~/bin/hasthisgateway.sh 192.168.1.92 ''"
Hostname 192.168.1.92
Port 1234
#external
Match originalhost server1
Hostname 134.x.y.z
Port 4321
现在,在这两种情况下,您都可以使用相同的ssh server1
命令,但其行为会有所不同。这将影响SCP,安全FTP,lftp... 也一样。在这种情况下,可能只使用 Match 条目而不使用 Host 条目。
答案2
由于 SSH 配置无法编写脚本,最简单的方法是设置端口转发并始终连接到公共 IP,或者创建一个用于连接到服务器的脚本。
Bash 脚本的伪代码
if (ip.startsWith("192.168.1.")) {
ssh [email protected] -p 1234
}
else {
ssh [email protected] -p 4321
}
请记住,如果您连接到另一个以“192.168.1”开头的网络,脚本将假定 SSH 服务器可通过本地 IP 访问,但事实并非如此。避免这种情况的唯一方法是让脚本通过运行 netcat 标头抓取或类似操作来检查它是否确实位于该 IP。