0%

SSH端口转发原理和实战

使用ssh进行本地端口转发、远程端口转发的案例,可以实现内网穿透等功能

一、端口转发简介

SSH全称Secure Shell,是一种加密的网络传输协议,常用于远程登录和远程命令执行。同时,它还提供了一个非常实用的功能,即端口转发。使用SSH端口转发可以实现:

  1. 加密网络通信;
  2. 突破防火墙/内网限制,建立TCP连接。

二、使用场景

通过本文提到的端口转发,可以解决以下常见问题:

  1. 公司的电脑没有公网IP,想在家里或者公司外面访问公司电脑的HTTP服务、数据库或者登录公司电脑的ssh。
  2. 与1类似,家里的主机没有公网IP,想在外面访问家里电脑的服务。
  3. 公司的服务器上部署了数据库服务,数据库只允许本地访问,即只能通过IP 127.0.0.1连接,但是想在公司个人电脑上用数据库管理软件连接数据库。
  4. 在没有公网IP的电脑上搭建了一个网站,只能在局域网中访问,想在公网中访问网站服务。
  5. 在公司服务器有公网IP,上面部署了数据库服务,想在外网连接数据库服务,但是防火墙不允许来自外网的IP访问数据库服务。
  6. 在公共WIFI等不安全的网络中上网,加密网络,防止被恶意监听。

三、远程端口转发

1. 远程端口转发原理

场景1和场景2原理相同,在本文中,我们把要访问的服务称为服务器,另外一方为客户端。 例如,在场景1中,公司电脑为服务器,在场景2中家里的电脑为服务器,另外一端称为客户端。 网络结构如下所示:

客户端和服务器都没有公网IP,意味着客户端不能与服务器建立连接,服务器也不能与客户端建立连接。此时需要另外一台有公网IP的服务器做中转。如下图所示:

外网主机不能主动跟客户端或者内网服务器建立连接,但是反向连接却是可以的,即客户端或内网服务器可以主动与外网主机建立连接。
利用此原理,中转的过程分为3步:

  1. 内网服务器建立与外网主机的连接;
  2. 客户端建立与外网主机的连接;
  3. 外网主机作为“中间人”把客户端发来的数据转发到内网服务器,同理把内网服务器的数据转发到客户端。

经过以上步骤,相当于建立了客户端与内网服务器的连接。

2. 远程端口转发实战

以场景1为例,在家里登录公司电脑的ssh服务(22端口)。首先在内网服务器上执行命令:

ssh -NT -R 8888:localhost:22 root@111.111.111.111

以上命令行的含义是,使用root用户登录到外网主机111.111.111.111,并在外网主机上监听端口8888,一旦有数据发往8888端口,就将数据转发到内网服务器的22端口。意味着,只要连接到了外网主机的8888端口,就相当于连接到了内网服务器的22端口。现在,登录到外网主机的ssh,并执行命令 ssh root@127.0.0.1 -p 8888 即可登录到内网服务器的ssh。

但是如果是在客户端执行命令ssh root@111.111.111.111 -p 8888,其实并不能连接到内网服务器,只能先登录到外网主机的ssh,然后再通过ssh登录到内网客户端。这是因为ssh出于安全考虑,默认只允许本机连接8888端口。执行命令netstat -an|grep LISTEN可以看到端口监听状态,其中有一行:

tcp        0      0 127.0.0.1:8888          0.0.0.0:*               LISTEN

其中127.0.0.1表示只允许本机连接。

如何让它监听来自所有ip的连接呢?

  1. 修改/etc/ssh/sshd_config,找到GatewayPorts,把#GatewayPorts no改为GatewayPorts clientspecified,这样就可以指定监听的IP了。

  2. 修改完后保存,然后重启sshd服务:

    sudo systemctl reload sshd.service

  3. 在内网服务器上执行

    ssh -NT -R :8888:localhost:22 root@111.111.111.111

与之前的命令相比,8888端口号前多了一个“**:**“,代表监听IP 0.0.0.0。
现在,客户端可以通过以下命令登录到内网服务器的ssh:

ssh root@111.111.111.111 -p 8888

如果再查看端口监听状态,可以看到监听8888端口的IP为0.0.0.0

tcp        0      0 0.0.0.0:8888            0.0.0.0:*               LISTEN

四、本地端口转发

在上例中,在修改GatewayPorts之前,8888端口只能在111.111.111.111这个服务器上访问,不能在其它电脑上连接,这其实跟场景3是一样的。如果不修改ssh配置文件,能不能在客户端连接内网服务器呢?当然可以,就是通过本地端口转发来实现。

假设在外网服务器上监听了端口8888,且该端口只能通过该外网服务器连接。现在通过本地端口转发,使得客户端能够连接到外网服务器的8888端口。在客户端执行以下命令:

ssh -NT -L 9999:127.0.0.1:8888 root@111.111.111.111

该命令行的意思是,在客户端监听9999端口,并将发送到9999端口的数据转发到外网服务器的8888端口。现在只要在客户端执行以下命令,就可以登录到内网服务器的上述(首先转发到外网服务器的8888端口,随后被转发到内网服务器的22端口):

ssh -p 9999 root@127.0.0.1

五、远程端口转发和本地端口转发的区别

通过前面的例子,我们知道,本地端口转发,是将发送本机到指定端口(9999)的数据,转发到远程端口(8888)。而远程端口转发是将发送到远程端口(111.111.111.111:8888)的数据转发到本机指定端口(22)。通过两种转发结合,实现了客户端之间登录到内网服务器。使用本地端口转发,可以解决场景3、4、5中的问题。