使用ssh进行本地端口转发、远程端口转发的案例,可以实现内网穿透等功能
一、端口转发简介
SSH全称Secure Shell,是一种加密的网络传输协议,常用于远程登录和远程命令执行。同时,它还提供了一个非常实用的功能,即端口转发。使用SSH端口转发可以实现:
- 加密网络通信;
- 突破防火墙/内网限制,建立TCP连接。
二、使用场景
通过本文提到的端口转发,可以解决以下常见问题:
- 公司的电脑没有公网IP,想在家里或者公司外面访问公司电脑的HTTP服务、数据库或者登录公司电脑的ssh。
- 与1类似,家里的主机没有公网IP,想在外面访问家里电脑的服务。
- 公司的服务器上部署了数据库服务,数据库只允许本地访问,即只能通过IP 127.0.0.1连接,但是想在公司个人电脑上用数据库管理软件连接数据库。
- 在没有公网IP的电脑上搭建了一个网站,只能在局域网中访问,想在公网中访问网站服务。
- 在公司服务器有公网IP,上面部署了数据库服务,想在外网连接数据库服务,但是防火墙不允许来自外网的IP访问数据库服务。
- 在公共WIFI等不安全的网络中上网,加密网络,防止被恶意监听。
三、远程端口转发
1. 远程端口转发原理
场景1和场景2原理相同,在本文中,我们把要访问的服务称为服务器,另外一方为客户端。 例如,在场景1中,公司电脑为服务器,在场景2中家里的电脑为服务器,另外一端称为客户端。 网络结构如下所示:
客户端和服务器都没有公网IP,意味着客户端不能与服务器建立连接,服务器也不能与客户端建立连接。此时需要另外一台有公网IP的服务器做中转。如下图所示:
外网主机不能主动跟客户端或者内网服务器建立连接,但是反向连接却是可以的,即客户端或内网服务器可以主动与外网主机建立连接。
利用此原理,中转的过程分为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的连接呢?
修改
/etc/ssh/sshd_config
,找到GatewayPorts
,把#GatewayPorts no
改为GatewayPorts clientspecified
,这样就可以指定监听的IP了。修改完后保存,然后重启sshd服务:
sudo systemctl reload sshd.service
在内网服务器上执行
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中的问题。