![通过反向(远程)SSH 隧道建立 SSH 连接](https://linux22.com/image/659322/%E9%80%9A%E8%BF%87%E5%8F%8D%E5%90%91%EF%BC%88%E8%BF%9C%E7%A8%8B%EF%BC%89SSH%20%E9%9A%A7%E9%81%93%E5%BB%BA%E7%AB%8B%20SSH%20%E8%BF%9E%E6%8E%A5.png)
这是我的设置:
防火墙后面的 LAN 内部的 Linux 机器 A。
具有固定 IP 地址且可从互联网访问的 Linux 服务器。
我希望能够通过 ssh 从远处连接到防火墙后面的 Linux 机器。我读过有关 ssh 隧道的文章,我想这可能是我的解决方案。我能够在 A 和 B 之间打开一个远程 ssh 隧道。但我不知道如何使用此隧道通过 ssh 控制 A,或者这是否可行。例如:从我的笔记本电脑通过 B 连接到 A。
这是我理解的打开隧道的命令:
ssh -R 2022:localhost:22 user@serverB
(通过端口 2022 的请求通过 user@serverB 传输到目标机器上的端口 22(ssh))。
打开此隧道后,应该采取什么操作才能通过 ssh 连接到目标机器?
如果我的理解有误,请纠正我。
答案1
您所指的是“SSH 远程转发”,在“人SSH“,关于“-R“ 选项。
> man ssh
[...]
-R [bind_address:]port:host:hostport
Specifies that the given port on the remote (server) host is to
be forwarded to the given host and port on the local side.
This works by allocating a socket to listen to port on the remote
side, and whenever a connection is made to this port, the
connection is forwarded over the secure channel, and a connection is
made to host port hostport from the local machine.
[...]
在您的上下文中,其中:
- 防火墙后面的 LAN 内部的 Linux 机器 A (LINUX_BOX_A)。
- 具有固定 IP 且可从互联网访问的 Linux 服务器 B(SERVER_B)
SSH 远程转发可用于从 SERVER_B 到达 LINUX_BOX_A。唯一的条件是:LINUX_BOX_A必须能够通过 SSH 连接到 SERVER_B。
为了实现这一目标,您需要:
- 在 LINUX_BOX_A 上:
LINUX_BOX_A:~ $ ssh -R 2222:localhost:22 user@SERVER_B
这将打开从 LINUX_BOX_A 到 SERVER_B 的 ssh 连接,用于远程传入连接。
上述 ssh 连接建立后,您可以:
- 在SERVER_B上:
SERVER_B:~ $ ssh -p 2222 user@localhost
在 SERVER_B 上启动的此类 ssh 连接将被定向到本地主机上侦听的 2222 端口,该端口与之前的 ssh 连接绑定。因此,这将是“另一个 ssh 连接中的 ssh 连接”。
一些补充说明:
考虑一下,如果第一个 ssh 连接由于任何原因(包括:由于不活动而被本地防火墙杀死)超时和/或中断,您将无法进行远程转发/远程连接;
因为让第一个 ssh 连接保持活动状态很长一段时间非常重要,你可能会发现在“屏幕“ 会议
最后说明:显然,以上所有内容都有一些(可能很严重的)安全隐患,超出了本答案的范围。
答案2
我画了一些草图
输入 ssh 隧道命令的机器称为»您的主人«。
介绍
当地的:
-L Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side.
ssh -L sourcePort:forwardToHost:onPort connectToHost
意思是:使用 ssh 连接到connectToHost
,并将所有连接尝试转发到当地的sourcePort
onPort
到名为 的机器上的端口forwardToHost
,可以从该connectToHost
机器访问。偏僻的:
-R Specifies that the given port on the remote (server) host is to be forwarded to the given host and port on the local side.
ssh -R sourcePort:forwardToHost:onPort connectToHost
意思是:使用 ssh 连接到connectToHost
,并将所有连接尝试转发到偏僻的sourcePort
到onPort
名为 的机器上的端口forwardToHost
,可以从您的本地机器访问该端口。
其他选项
-f
在进行身份验证后,告诉 ssh 自己进入后台,这样您就不必坐在远程服务器上运行某些东西来让隧道保持活动状态。-N
表示您需要 SSH 连接,但实际上不想运行任何远程命令。如果您要创建的只是一条隧道,那么包含此选项可以节省资源。-T
禁用伪tty分配,这是适当的,因为您不想创建交互式shell。
你的例子
第三幅图代表了您的情况。防火墙后面的计算机,您称之为A,是您的主机,因为您必须在此计算机上执行 ssh 命令,以打开到您的主机的本地主机的隧道(参见第三张图片)。
远程主机(如图所示)是您的服务器B(可从任何地方访问)。
ssh -R 2022:localhost:22 user@serverB
所有到绿色端口的连接尝试都2022
通过 ssh 隧道转发到22
主机本地主机(受防火墙保护的计算机)上的粉色端口。
现在你可以远程控制从互联网上的任何地方到远程主机(你调用服务器B) 在端口 2022 上(使用命令:ssh -p 2022 user@serverB
从世界上的任何一台机器)并将连接到您的防火墙计算机。这意味着,您可以控制这台计算机。
自动重新连接
您可以编写一个脚本startTunnelToHidden
,使隧道保持活动状态并在每次丢失连接时重新建立连接。最好在屏幕会话中启动此脚本,甚至最好使用 ssh-agent 启动它,以便能够使用公钥进行连接(因为,否则您将如何输入密码?这是可能的,但最好使用公钥)。
要在受防火墙保护的计算机上打开隧道,请输入:
屏幕 ssh-agent bash ssh-add startTunnelToHidden 2022:localhost:22 用户@serverB
或者输入这个/etc/rc.local
(以便在受防火墙保护的计算机启动时隧道打开):
(睡眠 2 分钟;su - userOnA -c'屏幕 -S tunnelToHidden -d -m startTunnelToHidden 2022:localhost:22 serverB')&
Bash脚本的内容startTunnelToHidden
:
#!/bin/bash
# Opens and restarts a remote ssh tunnel (in case it gets disconnected).
MinReconnectTime=$((1*60))
MaxReconnectTime=$((30*60))
RTime="$MinReconnectTime"
TimeUnit="s"
count=0
while true; do
((count++))
echo "Open tunnel (try number $count)"
date
ConnTime=$(date +%s)
# Example: Open tunnel to remotehost, which forwards connections from the
# remote’s localhost:10002 to the local port 22. »-N« means do not execute
# any command (no command prompt), »-T« means no tty, and
# »-o ServerAliveInterval=60« to keep the connection alive:
# ssh -N -T -o ServerAliveInterval=60 -R 10002:localhost:22 remotehost
ssh -N -T -o ServerAliveInterval=60 -R $@
DisconnTime=$(date +%s)
SSHTime=$(($DisconnTime-$ConnTime))
echo "SSHTime=${SSHTime}${TimeUnit}"
echo "Excited Tunnel!"
# it takes 63s for ssh to timeout, minreconntime is 60s, therefore
# 2*minrectime
if [ $SSHTime -gt $(($MinReconnectTime*2)) ]; then
RTime=$MinReconnectTime
else
((RTime*=2))
if [ $RTime -gt $MaxReconnectTime ]; then
RTime=$MaxReconnectTime
fi
fi
echo "Waiting $RTime$TimeUnit"
sleep $RTime
done
使用 screen -r tunnelToHidden 将屏幕会话重新连接到隧道
答案3
如果您控制防火墙,您可以在其上使用端口转发以避免使用反向 ssh(它会更稳定)。