假设以下场景:

  1. 你有台服务器,上面开着个数据库,但该数据库不对外开放,只能通过ssh登录到服务器上才能对其操作,但有时候,你想在本地直接访问该数据库来做些测试,怎么办?
  2. 假设在公司内网有台服务器,你想在家里直接ssh连到该服务器上,怎么办?

这些功能都可以通过ssh的端口转发(port forwarding)来实现。

下面我们通过一些实验来模拟这些场景,看下ssh的端口转发是如何解决这些问题的。

首先看第一个场景,我们先在一台服务器上用ncat命令模拟一个tcp服务,该服务只能在本机访问,不对外开放:

u3@h3:~$ ncat -lk 127.0.0.1 9000

我们在其他机器上尝试访问下,看是否能连上:

$ ncat h3 9000
Ncat: Connection refused.

如我们预想的一样,其他机器是连不上的。

下面在我们在这台机器开启ssh端口转发,使该机器可以通过ssh隧道的方式来访问服务器上的服务:

$ ssh -N -L 127.0.0.1:8000:127.0.0.1:9000 u3@h3

执行完该命令后,ssh会建立一个本机到h3服务器的ssh隧道,同时会监听本机的8000端口,当我们的程序访问本机的8000端口时,数据会先通过ssh隧道传到h3服务器的ssh端,h3服务器的ssh端会把数据再传给服务器本机的9000端口。

这样,我们访问本机的8000端口,就相当于访问服务器的9000端口了。

我们来试下:

$ ncat localhost 8000
hello

看下服务端ncat终端的输出:

u3@h3:~$ ncat -lk 127.0.0.1 9000
hello

由上可以看到,在我们访问本地的8000端口,发送hello字符串后,服务端的ncat终端也输出了hello,说明该tcp连接是建立成功的。

至此,场景1的问题完美解决,我们再来看下场景2。

假设h2是一台内网服务器,h3是一台外网服务器,h2和我们家里的机器都可以访问h3,但h3和家里的机器都不能直接访问h2,此时我们想在家里的机器上直接通过ssh登录h2,该功能通过以下步骤可以实现:

  1. 建立h2到h3的ssh隧道。
u2@h2:~$ ssh -N -R localhost:8022:localhost:22 u3@h3

注意,这里使用的参数是-R不是-L,它的意思是,如果在h3上访问8022端口,数据会通过这个ssh隧道转发到h2的22端口,也就是h2的sshd服务端口。

  1. 建立家里的机器到h3的ssh隧道。
$ ssh -N -L localhost:8022:localhost:8022 u3@h3

该命令的意思是,如果我们访问本机的8022端口,数据就会被转发到h3的8022端口上。

通过以上两条命令,我们建立了两条ssh隧道,当我们访问本机的8022端口时,数据会先通过本机到h3的ssh隧道,转发到h3的ssh端,h3的ssh端接着会把数据转发到h3的8022端口,又因为有h2到h3的ssh隧道存在,转发到h3的8022端口的数据又会通过h2到h3的隧道被转发到h2的ssh端,最后h2的ssh端又把数据再转发到h2的22端口,即h2的sshd服务端口。

通过这两条ssh隧道的数据转发,我们就可以在家里的机器上直接访问h2的sshd服务了,试下:

$ ssh u2@localhost -p 8022
Last login: Fri Sep  6 19:16:20 2019 from 127.0.0.1
u2@h2:~$

成功!

至此,场景2的问题也完美解决。

以上ssh命令建立的端口转发隧道都是在前台执行的,也就是说,它们会占着终端,终端关闭了它们也会被关闭。

如果想让这些ssh端口转发隧道在后台执行,只要再额外加个 -f 参数就行了。

有关ssh端口转发更多介绍,请参考ssh的man文档。

完。

更多原创文章,请关注我微信公众号:

底层技术研究


wangyuntao
30 声望3 粉丝