SSH隧道

时间:2024-03-29 17:30:29
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ilanni.blog.51cto.com/526870/1696162

前几篇有关ssh的文章,我们只是介绍了ssh的登录功能。其实ssh功能不只是这些,这篇文章我们来介绍下有关ssh隧道的功能。    

ssh隧道也叫ssh端口转发,或者叫ssh tunnel,这些都是说的是ssh隧道功能。在此,我们统称为ssh隧道。

ssh隧道分为正向隧道和反向隧道,在实际工作中我们可以根据需要来随其分别使用。

下面开始对正向和反向隧道分别介绍下,由于使用平台的不同,我们分为Linux和windows平台。

一、ssh正向隧道

什么是ssh正向隧道?

就是client连上server后,然后把server能访问的IP地址和端口(当然也包括server自己)镜像到client的端口上。

在平时工作中,正向隧道是我们使用最多的一种方式。

ssh正向隧道的命令如下:

ssh –L clientC_IP:clientC_port:serverB_IP:serverB_port -p serverA_sshport [email protected]_IP

上述命令的意思是在客户端clientC上通过ssh连接服务器serverA,然后再把服务器serverB上的serverB_port端口映射到客户端clientC的clientC_port端口。

也就是说如果我们现在连接clientC的clientC_port端口的话,就是连接服务器serverB上的serverB_port的端口。

上述命令的使用场景一般是,客户端clientC在公司内部使用的是内网IP,而服务器serverA和serverB在IDC机房或者在云服务器商那边。服务器serverA有公网IP能与客户端clientC正常通信,而服务器serverB没有公网IP不能与客户端clientC直接通信,但是服务器serverA和服务器serverB是通过内网进行通信的。现在要求客户端clientC访问serverB的相关端口。

客户端clientC、服务器serverA与服务器serverB,通信示意图如下:

SSH隧道

要达到上述要求,我们就可以通过ssh正向隧道的功能。为了看出实际的效果,在此以连接后端的mysql数据库为例具体配置根据操作平台的不同,分别介绍如下。

1.1 Linux下配置ssh正向隧道

在Linux下配置ssh正向隧道比较简单,直接使用上述命令即可。如下:

ssh -g -f -NL 192.168.7.7:44010:10.66.115.185:3306 -i /home/ilanni/id_dsa_1024_0601 [email protected]

ps -ef |grep 44010

SSH隧道

上述命令的意思是在192.168.7.7这台机器通过ssh方式连接115.159.39.187这台服务器,然后把10.66.115.185这台服务器的3306端口也即是mysql端口映射为192.168.7.7的44010端口。

现在在局域网内,只要我们连接192.168.7.7的44010端口,其实就在连接10.66.115.185的3306端口。

现在我们来测试下,是否可以连接成功。在与192.168.7.7同一个LAN中的任意一台能连接192.168.7.7的44010端口的机器上,使用mysql的客户端,如下:

SSH隧道

注意:IP地址和端口一定要填写为192.168.7.7和44010,而用户名和密码只需要填写mysql数据库对应的用户名和密码即可。

SSH隧道

SSH隧道

通过上面两张图,我们可以看到连接192.168.7.7的44010端口,确实就是连接的10.66.115.185的3306端口。也即是在公司内部连接IDC内的后端数据库。

如果公司内部对访问后端数据库有权限要求的话,我们可以在服务器serverB(mysql数据库10.66.115.185)上只允许服务器serverA(115.159.39.187)访问服务器serverB(10.66.115.185)的3306端口通过相关的安全策略比如IPtables或者mysql用户授权对服务器serverA(115.159.39.187)。

然后再在服务器serverA(115.159.39.187)也即是192.168.7.7上通过IPtables配置相关的内网机器能访问44010端口。

通过这样的操作就可以在公司内部达到控制后端mysql数据库的权限控制。

1.2 windows下配置ssh正向隧道

在windows下配置ssh正向隧道,需要我们使用ssh相关的客户端软件。在此我使用的xshell,当然你也可以使用putty等之类的软件。

打开xshell,新建一个连接到serverA(115.159.39.187)的会话,如下:

SSH隧道

注意:这个地方填写的是serverA的IP地址。

SSH隧道

在这填写的用户就是serverA的用户。

SSH隧道

SSH隧道

这张图很重要,因为是ssh正向隧道,所以在此类型里面选择的是Local。

源主机填写的是clientC的IP地址(在哪台机器就填写哪台机器的IP),侦听端口就是serverB的serverB_Port端口映射到clientC上的端口。注意侦听端口可以随便自定义。

目标主机填写的是serverB的IP地址,目标端口填写的是serverB_Port端口号。

以上配置完毕后,我们在本机192.168.1.180上连接看看是否可以正确连接serverB的serverB_Port端口。如下:

SSH隧道

SSH隧道

SSH隧道

通过以上几张图,我们可以很明显的看出,以上配置是正确的。

注意:windows下配置ssh正向隧道和Linux还是有所不同的。windows正确配置后,如果要使用隧道的话。xshell连接serverA的会话不能关闭。也就是说clientC连接serverA的ssh会话要一直开着,而且即使正常连接后,该ssh会话也是一直存在的。如下:

SSH隧道

二、ssh反向隧道

什么是ssh反向隧道?

就是client连上server后,然后把client能访问的IP地址和端口(也包括client自己)镜像到server的端口上。

ssh反向隧道使用场景,比如你的客户端在内网,在外网是无法直接访问到的,这时用反向隧道打通一条连接,就可以从外网通过这条隧道进来了。

ssh反向隧道的命令如下:

ssh –R serverA_IP:serverA_port:clientC_IP:clientC_port -p serverA_sshport [email protected]_IP

上述命令的意思是在客户端clientC(或者clientC所在的LAN中的任意一台能连接clientC_port的机器)上通过ssh连接服务器serverA,然后再把客户端clientC的clientC_port端口映射到服务器serverA上的serverA_port端口。

也就是说如果我们现在在服务器serverB上连接服务器serverA上的serverA_port端口的话,就是连接clientC的clientC_port端口。数据流向,如下图示:

SSH隧道

注意:建议修改serverA服务器的ssh配置文件sshd_config,添加GatewayPorts yes。然后重启ssh服务。

SSH隧道

这样ssh反向隧道建立成功后,在serverA服务器监听的端口为serverA服务器的所有地址。如下:

SSH隧道

如果不这样修改的话,在serverA服务器监听的端口会为127.0.0.1。如下:

SSH隧道

2.1 Linux下配置ssh反向隧道

在Linux下配置ssh反向隧道比较简单,直接使用上述命令即可。如下:

ssh -g -f -NR 115.159.39.187:44010:192.168.5.174:3306 -i /home/ilanni/id_dsa_1024_0601 [email protected]

ps -ef |grep 44010

SSH隧道

上述命令的意思是在192.168.5.174这台机器通过ssh方式连接115.159.39.187这台服务器,然后把192.168.5.174这台服务器的3306端口也即是mysql端口在115.159.39.187服务器上映射为44010端口。

也就是说现在在公网上,只要我们连接115.159.39.187的44010端口,其实就是在连接192.168.5.174的3306端口。

为了能很实际的效果,现在我们在192.168.5.174上新建ilanni这个一个数据库。如下:

mysql -uroot -p123456

create database ilanni;

show databases;

SSH隧道

现在我们登录到115.159.39.187服务器上进行查看。如下:

netstat -tunlp

SSH隧道

通过上图,我们可以看到115.159.39.187服务器上确实在监听44010端口。

下面我们在115.159.39.187服务器上来连接下192.168.5.4的3306端口。如下:

mysql -h127.0.0.1 -P44010 -uroot -p123456

show databases;

SSH隧道

通过上图,我们可以很明显的看到在115.159.39.187服务器上连接44010端口确实连接到了192.168.5.4的3306端口。

2.2 windows下配置ssh反向隧道

在windows下配置ssh反向隧道,和配置ssh正向隧道基本一样也需要使用ssh相关的客户端软件,在此我使用的还是xshell。

注意:ssh反向隧道,我们可以在与clientC同一LAN的任意一台能访问clientC_Port端口的机器上进行。

打开xshell,新建一个连接到serverA(115.159.39.187)的会话,如下:

SSH隧道

注意:这个地方填写的是serverA的IP地址。

SSH隧道

在这填写的用户就是serverA的用户。

SSH隧道

SSH隧道

这张图很重要,因为是ssh反向隧道,所以在此类型里面选择的是Remote。

源主机填写的是serverA的IP地址,侦听端口就是clientC的clientC_Port端口映射到serverA上的端口。注意侦听端口可以随便自定义。

目标主机填写的是clientC的IP地址,目标端口填写的是clientC_Port端口号。

现在我们登录到115.159.39.187服务器上进行查看。如下:

netstat -tunlp

SSH隧道

通过上图,我们可以看到115.159.39.187服务器上确实在监听44010端口。

下面我们在115.159.39.187服务器上来连接下192.168.5.4的3306端口。如下:

mysql -h127.0.0.1 -P44010 -uroot -p123456

show databases;

SSH隧道

通过上图,我们可以很明显的看到在115.159.39.187服务器上连接44010端口确实连接到了192.168.5.4的3306端口。

三、实际应用

以上介绍了ssh正反向隧道详细使用方法,以mysql的3306端口为例子。下面我就结合实际的工作需求,介绍下ssh隧道的其他使用场合。

3.1 远程桌面

ssh隧道也是代理可以在windows以及Linux的远程桌面的,这种场合一般是在这样的场合下使用。

公司对外提供v*n服务,但是该v*n服务器在网络DMZ防火区。v*n服务器可以访问lan内的机器,但是lan内的机器不能访问v*n服务器。结构图,如下:

SSH隧道

v*n客户端连接进来后,我们只需要在DMZ区的服务器上,建议一条ssh正向隧道即可连接隧道指定的lan机器。

如下:

ssh -g -f -N -L 7002:192.168.5.140:3389 [email protected]

SSH隧道

上述命令的意思是把192.168.5.140的3389端口映射到192.168.7.7的7002端口。也就说我们现在在v*n客户端连接192.168.7.7的7002端口其实就是连接192.168.5.140的3389端口。如下:

SSH隧道

SSH隧道

SSH隧道

通过上图,我们可以很明显的看出ssh正向隧道已经代理了远程桌面。

3.2 nginx访问

现在公司线上云服务器上有一台业务serverB,前端使用nginx做反向代理,后端使用的是nodejs,serverB只对云服务器提供访问。

目前要求在公司内部也可以访问serverB上的nginx,并且不是公司内部所有人员都可以访问,只有指定的个别人才能有权限访问。

分析:如果要使公司内部访问serverB上的nginx,我们只需要在serverB开放对公司公网的IP访问权限即可。

但是如果还要控制访问权限的话,这个就需要借助ssh正向隧道来实现了。

在云服务器上开放一台serverA,serverA能访问serverB的nginx(该访问权限的控制可以通过nginx或者iptables进行控制),而serverA又对公司的公网IP开放SSH端口。

然后在公司内网的任意一台lanC上,做一条ssh正向隧道。该隧道把serverB的nginx端口映射到serverC上一个PortC端口。

此时我们再在lanC上对PortC端口的访问权限进行控制(该访问权限的控制可以通过nginx或者iptables进行控制)即可达到上述要求。

现在lanC上使用如下命令:

ssh -g -f -NL 192.168.5.4:8080:10.104.13.164:80 -i id_dsa_1024_0601 [email protected]

ps -ef |grep 8080

SSH隧道

上述命令的意思是在192.168.5.4上通过115.159.44.136这台服务器把10.105.12.163这台服务器的80端口映射为192.168.5.4的8080端口。

lanC的nginx配置如下:

server {

listen 80;

server_name 192.168.5.4;

allow 127.0.0.1;

allow 192.168.5.140;

deny all;

location / {

proxy_pass http://192.168.5.4:8080;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection $connection_upgrade;

proxy_connect_timeout 200;

proxy_send_timeout 200;

proxy_read_timeout 600;

}

}

上述nginx配置的意思是允许192.168.5.140这台机器访问192.168.5.4的80端口,而192.168.5.4会把访问192.168.5.4:80的请求交给192.168.5.4:8080进行处理。

这样就达到了前文的要求。

现在在192.168.5.140*问192.168.5.4的80端口。如下:

SSH隧道

通过上图,我们可以很明显的看出ssh正向隧道已经可以代理nginx。

3.3 ssh多级隧道跳转

ssh多级隧道跳转看起来感觉很难,其实如果细细拆分的话很简单的。

下面有一个实际的要求,我们来分析下。

情况介绍:

serverC只允许serverB连接serverC的1001端口其他端口不允许serverB连接,而serverB只允许serverA能连接serverB的22端口,不能连接serverC的1001端口,同时serverA是只对公网开放的ssh的22端口其他端口不对公网开放。

要求:

现在要求lan内部的clientC能连接serverC的1001端口。

分析:

如果我们直接serverC的1001端口那是不可能的,因为安全策略有限制。那么我们可以通过ssh正向隧道来解决此问题。

首先在serverA上通过serverB做一条ssh正向隧道把serverC的1001端口映射为serverA的1002端口。

即访问serverA的1002端口就是访问serverC的1001端口。

因为serverA的1002端口不对公网开放,那么为了能访问serverA的1002端口,我们可以在clientC通过serverA再做一条ssh正向隧道把serverA的1002端口映射为clientC的1003端口。

也就是说此时我们连接clientC的1003端口其实就是在连接serverC的1001端口。

以上ssh多级隧道跳转的原理介绍清楚了,在次就不在进行演示。如果有哪位不懂的可以多多理解理解上面的描述。