SSH端口转发:实现反向SSH隧道内网穿透

由于最近有一个项目,部署在一台很深的虚拟主机中,具体操作起来极为不便,想直接 SSH 过去进行管理不行,甚至连剪贴板都受限了,因此极为吐血,想死的心都有了。

当然,我们有 VPN,一管捅进去,世界就清净了,但是,可能由于某些策略被封(例如 openvpn 的 1194 端口或者流量被截获之类的),这个渠道不行了。

一翻之下,找到这篇救世好文:https://my.oschina.net/abcfy2/blog/177094

前提是,我在内网的机器(A机)可以 ssh 出来,而且我有一台具备公网 IP 的服务器(B机)用于转发。

我希望在我自己的个人电脑(C机)直接 ssh 上 A机。

这个方法原理是这样,只要A机通过SSH连上了B机,那么它们之间已经建立了一条隧道,理论上讲,B机上什么东西都可以走这条隧道主动访问到A机的。

我们需要在这条隧道上面建立端口映射,把A机的22端口映射给B机的某个端口(假设是19394),这时候B机可以通过 ssh -p 19394 127.0.0.1 访问到A机。

1. 建立端口映射

在A机上面安装autossh自动连接ssh:

# 在A机上面运行
sudo apt-get install -y autossh

启动端口转发:

# 在A机上面运行
autossh -M 19393 -NR 19394:localhost:22 username_b@server_b_ip

# 这个 -M 要来干嘛不清楚,好像这个端口后面用不上,但是注意这个会占用B机的端口,如果有多个SSH转发,注意不要冲突就可以了。

# 后来阅读文档发现也可以设定 -M 0 关闭这个控制台,也是不错的选择。

# autossh --help
#    -M specifies monitor port. Overrides the environment
#       variable AUTOSSH_PORT. 0 turns monitoring loop off.
#       Alternatively, a port for an echo service on the remote
#       machine may be specified. (Normally port 7.)

这个时候在B机上面看端口映射,B机访问本机的19394端口就等于A机的22端口了:

# 在B机上面运行

netstat -anltp

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
...
tcp        0      0 127.0.0.1:19394         0.0.0.0:*               LISTEN      31380/sshd: root
...
tcp        0      0 127.0.0.1:19393          0.0.0.0:*               LISTEN      31380/sshd: root
...

说明B机已经通过隧道hold住了一个通向A机22端口的本地端口了,于是我们在B机:

# 在B机上面运行
ssh -p 19394 username_a@127.0.0.1

这个时候理论上已经可以连得上A机的ssh了!

2. 将转发的端口对外开放

离目标还差一步,我们在C机上面还不能访问到A机,因为我试图在C机上面:

# 在C机上面运行
ssh -p 19394 username_a@server_b_ip

失败了,为啥?

反正不通,因为19394只对B机本地访问开放,这个时候,我们可以如法炮制,在C机上面开放一个本地转发:

autossh -N -M 19392 -L 19394:127.0.0.1:19394 username_b@server_b_ip

这时候在C机上面访问19394就会转发到B机本地的19394,然后转发到A机的22端口,相当于直接访问到A机:

注意,如果 C 机是 Windows 系统,我们不用 autossh 命令的话,使用 Bitvise SSH Client 也可以方便地配置端口转发。

# 在C机上面运行
ssh -p 19394 username_a@127.0.0.1

就可以进去了!大功告成!

3. autossh 自动连接

OK,既然测试通过我们就让连接一直自动维持不要间断吧,例如

当重启内网B主机,谁来自动Autossh呢?

autossh有一个-f选项可以将连接运行在后台,于是,我们可以在/etc/rc.local中加入这几句启动的时候自动连接SSH做端口转发:

# 这段加在A机的 /etc/rc.local
autossh -M0 -f -NR 19394:127.0.0.1:22 username_b@server_b_ip

# 这段加在C机的 /etc/rc.local
autossh -M0 -f -NL 19394:127.0.0.1:19394 username_b@server_b_ip

4. 错误排查

4.1. 关于 SSH 自动登录

第一个,如果需要自动连接SSH,必须能够免密码登录,也就是说,A机和C机都必须能够自动登录B机。

至于如何免密码SSH登录,我们需要在客户机用户目录~/.ssh/下面创建一对 RSA 密钥,私钥命名是id_rsa,公钥命名是id_rsa.pub

然后,将id_rsa.pub的内容放进服务器的~/.ssh/authorized_keys文件中,一行一个。

我把这一个步骤写成了一个函数,将下面这段代码放进 ~/.bashrc,重新启动终端或者 source ~/.bashrc,就会多了一个可用的命令ssh_login

ssh_login() {

# 确认当前目录已经生成密钥对
mkdir -p ~/.ssh;
[ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -t rsa -f ~/.ssh/id_rsa -N '';
pub_key=$(cat ~/.ssh/id_rsa.pub)

# 将密钥插入远程
ssh $@ -T <<EOF
mkdir -m 700 -p ~/.ssh
echo "${pub_key}" >> ~/.ssh/authorized_keys
EOF

}

然后,用A机和C机的root用户分别执行:

ssh_login root@server_b_ip

会提示输入密码,输入一次之后再 SSH 上去就不用输密码了。

4.2. 连接超时问题

实际我执行这个部署的时候,还遇到过卡死的问题,当一个 SSH 连接建立之后,如果双方没有任何交互,这个 SSH 连接会卡死(大多由于网络方面的问题可能会把超时的隧道关闭)。

我们可以在 SSH 的客户端和服务器端都设置一个间隔,例如隔一分钟向对方发一个小数据包,告诉连接还在,不要算超时。

# 在A机和C机的`/etc/ssh/ssh_config`后面加上:
ServerAliveInterval 60

# 在B机的`/etc/ssh/sshd_config`后面加上:
ClientAliveInterval 60

参考教程:


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2016/10/ssh-reverse-tunnel.html【SSH端口转发:实现反向SSH隧道内网穿透】

《SSH端口转发:实现反向SSH隧道内网穿透》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注