ssh端口转发穿越多重跳板机的方法

Posted by kevin on January 16, 2022

preface

本篇文章简单介绍一下三种 SSH 端口转发的操作,本篇文章创建的日期为 1.16,真正动手写的日期是 2.16,刚好鸽了一个月,笑死。本来想好好写一下的,现在就稍微写一下吧,知识这个东西,一旦你掌握了,就再也无法忘记了。

本地端口转发

本地端口转发就是访问本地端口的流量通过 ssh 被转发到远程机器上,常见情景是本地通过一个公网跳板机访问内网的服务器,可以直接将本地一个端口通过跳板机与目标机的端口进行绑定,访问本地的端口就等于在访问目标机器。

远程端口转发

远程端口转发就是访问远程端口的流量通过 ssh 被转发到本地上,常见情景是本地 (内网) 有一个服务,需要映射到公网被人访问,所以将公网的一个端口与本地的服务端口映射起来,然后通过访问远程的端口就可以访问到内网的服务。(默认关闭,要开启)

开启的方法也很简单,编辑 /etc/ssh/sshd_config,注意不是 ssh_config, 找到 Gatewayforward,默认是 no,改成 yes,然后 sudo systemctl restart sshd 重启 ssh- daemon 服务就开启成功了。

动态端口转发

前面两种端口转发的方法都是端口对端口的转发,也就是服务端和客户端的端口都得确定好才能够连接上。动态端口转发,顾名思义,就是不指定端口,只要服务器能够访问到的端口我们都能够直接访问。其原理就是在服务端开启一个 socks 代理,通过代理服务器连接它所能够连接到的任何机器,不限定某一个机器或者某一个端口。这样能有什么用呢,比如我的电脑访问不了外网,但是内网中另一台机器可以访问外网,我们就可以代理到这台机器上,借助他的网络上网。这样子有一个非常好的好处就是可以隐藏自己真实的 ip。

比如我们在 localhost:6666 与 1.2.3.4 之间建立了一个动态转发,我们访问 1.2.3.4:999 的过程中流量的经过顺序是

localhost:6666 -> localhost:22 -> 1.2.3.4:22 -> 1.2.3.4:999

可以看到,这些隧道都是走 ssh 的,会经过加密,所以非常安全。

要访问动态转发的机器,我们就得使用支持 socks 协议的代理软件, Proxifier 这款软件我试过不错,如果有多个代理的话,还可以随机选择一个代理或者形成代理链,功能强大,可以指定规则与应用使用代理,后面有空介绍一下。

示意图

从参考链接里面看到的一张图,生动形象,其中还给出了端口转发的命令行,不过我建议直接用图形化工具建立转发,一方面记这些命令太繁琐,另一方面,建立之后想取消的话很麻烦,推荐用 mobaxterm,后面会介绍。

Diagram: SSH port forwarding visualized

根据场景利用 Mobaxterm 建立端口转发

本地转发

第一个例子,我本机能访问到华为的公网跳板,由公网跳板才能访问到华为内部的一个跳板,再通过这个跳板才可以访问到我真正要访问的机器,这样就有两个跳板了,怎么办呢,很简单,建立两个本地转发就行了,因为本地转发是不能跳级的,只能一个一个来,先建立本机和第二个跳板的连接,这时候访问我们本地一个端口就相当于在访问第二个跳板机,那只需要再建立一个目标机和第一次连接的转发就行了,直接看截图更明白。

本机:不用管
第一个跳板:user@1.2.3.4
第二个跳板:user1@172.31.0.0
目标机:user2@172.31.1.1

local_forawrd_1

local_forawrd_2

这样子搞一下的话,我们直接 ssh user2@localhost -p 6667 就相当于直接 ssh user2@172.31.1.1 了,为原本不能相连的两个机器之间打了两条隧道。

所以不管有多少台跳板,用这种方法直接可以一步到位,只不过多建立几条转发就行了。其实也有另一个办法,就是在最后一层跳板处建立一个动态转发,然后 ssh 连接的时候在 mobaxterm 里面使用 socks 代理,也是能够达到效果的,只不过稍微麻烦一些,而且 pycharm 远程连接不支持 socks 代理。

另外一个例子,也很有意思,阿里云这种服务器一般都会把很多端口关闭只留下几个常用的端口,所以如果在阿里云服务器上开一个 jupyter server (端口为 8888),我们大概率是不能从公网上直接访问的,但是通过本地转发却可以很轻易达到目的。

本机:不用管
跳板:kevin@1.2.3.4
目标:1.2.3.4:8888

我们只需要在目标机上填上 localhost:8888,因为目标机是相对跳板机来说的,跳板机的 localhost 就是他本身,所以我们通过访问本地的 10086 端口就可以直接访问到跳板机的 8888 端口。链路如下:

localhost:10086 -> localhost:22 -> 1.2.3.4:22 -> 1.2.3.4:8888

local_forward_3

远程转发

比如说校园内网有个 jupyter 服务,我想要在出学校的时候也能访问到,这时候就可以使用远程端口转发,以前都是用 frp 内网穿透来实现的,其实一个 ssh 就行了,原理是一样的。不过想公网访问的话就需要一个公网服务器,阿里云这种就够了。

本机:不用管
跳板机:user@1.2.3.4
目标机:172.31.0.0:8888

如下图,这样的话,我们直接访问 1.2.3.4:10086 就能够访问到我们内网的 jupyter 服务了。

remote_forward_1

不过远程转发的设置稍微麻烦一点,因为 ssh server 默认是不允许进行远程转发的,所以我们建立完转发连接之后要在服务器上查看一下是否有端口的映射:

netstat -lntp | grep PORT
lsof -i:PORT

PORT 指的是我们用来建立连接的端口,如果查看到远端机是 127.0.0.1:PORT 的话就说明只能他本地访问,建立的连接是失败的,要 0.0.0.0:PORT 才能够使所有的 IP 都能访问,这时应该去检查一下 sshd_config 是不是开启了允许转发的选项。

动态转发

动态转发很好玩,其实就是相当于一个代理,自己访问不了的东西,让代理帮你访问,相当于假借了代理的网络去发送请求, mobaxterm 里面也有,很方便就能够建立 。

下面我们就通过本地的 10000 端口代理到了 1.2.3.4 服务器,然后我们通过 socks 代理软件就能够访问到 1.2.3.4 这台机器所能访问到的所有机器。这里我们用 Proxifier 这款软件

dynamic_forward_1

建立好转发连接后,我们用 Proxifier 进行代理如下

Proxifier_1

我们可以制定一系列规则,什么应用适用什么代理,对于什么 ip 的请求使用什么代理等等,甚至可以建立多个动态连接形成一个代理池,每次随机用一个代理访问,功能十分强大。

Proxifier_2

reference

利用SSH隧道构建多级Tunnel (非常棒)

SSH 通过跳板机直接访问内网机器 - 知乎 (zhihu.com)

彻底搞懂SSH端口转发命令(非常棒)

mobaxterm多层隧道的配置

Proxifier 4.07 破解版 - 最强大的代理客户端

SSH 端口转发 - SSH 教程 - 网道 (wangdoc.com)

SSH 远程端口转发

Dirk Loss: SSH Port Forwarding visualized (dirk-loss.de)

【秒懂】5分钟学会SSH端口转发,远程工作用得着