SSH反向代理相关介绍(网上摘抄+修改)
有时我们会碰到这样一个需求。在公司内部有一台可以上外网Linux主机(也可能为虚拟机,假设该机器命名为A)用于日常工作,其内网IP地址为192.168.1.A,该机器已经开了某些远程访问的服务,在同网段的下主机可以访问A。当我们在公司外面时需要远程访问该机器,有什么方法可以实现呢?你可能想到通过VPN。远程登录到公司VPN,然后使用A的内网IP直接访问该机器,但是如果A主机所在的网
问题提出
有时我们会碰到这样一个需求。在公司内部有一台可以上外网Linux主机(也可能为虚拟机,假设该机器命名为A)用于日常工作,其内网IP地址为192.168.1.A,该机器已经开了某些远程访问的服务,在同网段的下主机可以访问A。当我们在公司外面时需要远程访问该机器,有什么方法可以实现呢?
你可能想到通过VPN。远程登录到公司VPN,然后使用A的内网IP直接访问该机器,但是如果A主机所在的网络是公司内部网络的子网甚至是子网的子网,或者公司没有VPN服务器该怎么办呢?有没有其他更简单的方法呢?答案是肯定的。
其中一个简单的方法便是使用本文所要讲述的SSH反向代理方法。不过使用SSH反向代理的前提是在公司外部需要有一台具有公网IP的Linux主机,或者虽然没有公网IP,但是提供一个公网IP对外开放的端口转发,通过该端口可以直接访问到该台Linux主机,假设该台Linux主机命名为B。
网络环境描述
主机 | IP | 备注 |
A | 192.168.1.A | 公司内部主机,在局域网内,可以访问B |
B | 223.72.211.B | 外部Linux主机,具有公网IP,不能直接访问A |
在现实中,B机器可能是我们家里的电脑,通过宽带拨号上网从运营商获取临时的独立IP,或者是一台具有独立IP的VPS主机。
目标
从B机器能够访问A。
解决方案
使用SSH的远程转发功能,把A机器的指定端口PortA远程转发到B机器上的某个端口PortB,在B机器上访问PortB就相当于访问A机器的PortA。
环境需求
在B机器上需要安装SSH服务端,A机器上需要有SSH客户端。
实施步骤
在A机器上执行远程端口转发命令,其基本命令格式为:
ssh -R [B机IP或*号或省略:]<PortB>:<A机IP>:<PortA> <B机用户名@B机公网IP> [-p B机ssh服务端口(默认22)]
这里假设要把A机23端口(Telnet服务器监听端口)转发到B机9022端口,实现在B机上通过Telnet命令登录到A机;假设B机用户名为root,ssh服务器端口号为8022。在A机上执行命令如下:
ssh –R 9022:127.0.0.1:23 root@223.72.211.B –p 8022
A机上执行上述命令时,会发现该过程跟通过ssh远程登录B机是一样的,要求输入root密码,完成后会登入B机shell。这时在B上执行netstat -an|grep 9022,会发现已经有进程在监听9022端口了,如图1.1所示。
图1.1 sshd进程监听9022端口
这时在B机执行telnet 127.0.0.1 9022,会发现能够通过Telnet远程登录A机了。
其他有用的参数:
-N Donotexecute a remote command. This is useful for just forwarding ports (protocol version 2 only).
-f Requests ssh to goto background just before command execution.
在A机上退出上次的登陆,添加以上两个参数并再次执行:
ssh –NfR 9022:127.0.0.1:23 root@223.72.211.B –p 8022
输入B机密码后,会发现立刻返回A机shell。同时在B机上依然能够远程登录A机。
原理推测
首先整理下上面连接过程:在内网中的A机执行ssh反向连接命令,相当于把127.0.0.1:PortA远程映射到了B机的127.0.0.1:PortB,在B上连接127.0.0.1:PortB,其效果跟在A机内连接127.0.0.1:PortA是一样的。
考虑到NAT防火墙的存在,不可能在PortB和PortA之间又建立了一条连接,它们之间的数据传输应该还是通过ssh这条通路进行传递的,因此推断整个连接过程如下。
1) A机:执行ssh反向连接命令,AB机之间建立ssh连接;A同时告诉B:你去监听localhost:PortB,把PortB上监听到的数据通过ssh通路传输给我
2) B机:ssh服务端在收到上面指令后就去localhost:PortB上监听数据,如果有数据通过PortB传入(该数据是向localhost:PortB上发起连接的客户端数据,如上面例子中Telnet连接命令),B机便把这些数据打包成一个特征包,通过ssh连接发给A
3) A机:ssh客户端接收到B机发来的特征包后,把该特征包转发到localhost:PortA,如果监听PortA的服务有回应,则把回应数据打包成特征包通过ssh通路发给B
4) B机:ssh服务端收到A机传来的特征包后,把这些特征包返回给发起连接的客户端(Telnet客户端)
由此整个代理通路打通。
进阶1
考虑下面的需求。B是我们的某台服务器,现在已知我们可以在B机shell里面访问A机了,也就是要访问A机,必须首先登录到B机,然后在B机shell里执行登录命令才能访问A机。这样有点麻烦,我们能不能跳过登录B机,以B机作为跳板,在任意一台能上网的电脑上访问A机呢?或者情况是B机不带界面,但是转发的PortA是一个UI服务器的监听端口(比如3389端口,远程桌面),我们想在B机里登录A机的远程桌面是不可能的,因为B机不带界面;你可能想到我们能不能在一台联网的windows机器上通过远程桌面客户端使用 B机公网IP:PortB 地址远程登录A呢?以上答案是肯定的。
下面是ssh man page里对-R参数说明的摘抄。
-R [bind_address:]port:host:hostport
... ...
Bydefault, the listening socket on the server will be boundto
the loopback interface only. This may be overridden by
specifying a bind_address. An empty bind_address, or the address
`*', indicates that the remote socket should listen on all
interfaces. Specifying a remote bind_address will only succeed
if the server's GatewayPorts option is enabled (sshd_config(5)).
通过上面的man page我们发现,默认情况下bind_address只是绑定到B机的loopback接口,也就是127.0.0.1地址,这就是上面我们在B机shell里为什么用127.0.0.1的地址来访问A。但是我们可以通过指定一个空的bind_address或者‘*’来绑定到B机的所有可用端口上,前提是需要配置B机的ssh服务器使能GatewayPorts。
GatewayPorts应该是ssh服务的一个安全选项,如果使能该功能,ssh服务便能向ssh客户端指定的任意IP:Port监听/转发数据包。下面具体来实施。首先说明一下,我的B机所用Linux发行版为Debian,Ubuntu等基于Debian的发行版应该是一样的,其他发行版可能稍有不同。
- |配置sshd,打开GatewayPorts
vi /etc/ssh/sshd_config,在最后一行增加配置:GatewayPortsyes,完成后保存
- |重启sshd服务
/etc/init.d/ssh restart
- |防火墙允许PortB传入连接
B机ssh服务端监听B机公网IP的PortB,如果B机使能了防火墙,需要在该端口上允许数据传入。
做完上面步骤后,在A上执行:
ssh –NfR *:9022:127.0.0.1:23 root@223.72.211.B –p 8022
连接建立后,在任意一台能上网主机上执行telnet 223.72.211.B 9022,发现能够直接登录A机了。
上面PortA不只是23端口,可以是A上提供TCP服务的其他任意端口,如ssh服务(22)、web服务(80)、远程桌面服务(3389)等,假如A机提供远程桌面服务,在A上执行:
ssh –NfR *:9022:127.0.0.1:3389 root@223.72.211.B –p 8022
连接建立后,在任意一台能上网的windowas主机上打开远程桌面客户端,远程连接地址填写223.72.211.B:9022,便能连接A机远程桌面了。
进阶2
有时我们可能还有下面的需求。AB机都是Linux主机,但是跟A在同一局域网的C机是Windows主机(假设其IP地址为192.168.1.C),C提供远程桌面服务。现在我们能够通过B机远程连接A了,能不能通过B机、A机访问C机的远程桌面呢?答案也是肯定的。
在A上执行:
ssh –NfR *:9022:192.168.1.C:3389 root@223.72.211.B –p 8022
连接建立后,在任意一台能上网的windowas主机(假设为D)上打开远程桌面客户端,远程连接地址填写223.72.211.B:9022,便能连接C机远程桌面了。
该过程也很好理解:A机ssh客户端把从B机传来的远程桌面连接特征包转发到192.168.1.C:3389,C机远程桌面服务接收到连接请求后把回应返回给A,A再把回应包转给B,B把该包再回给远程桌面客户端便可以了,过程如下。
发起远程桌面连接:D机远程桌面客户端 -> B机IP:9022 -> B机ssh服务 -> A机ssh客户端 -> C机IP:3389 -> C机远程桌面服务
远程桌面服务回应:C机远程桌面服务 -> (A机IP:A机发起连接时随机端口) -> A机ssh客户端 -> B机ssh服务端 -> (D机连接时外网IP:NAT源端口号) -> D机远程桌面客户端。
上面过程,在C机看来,就是A机连接了C机远程桌面服务,C机并不知道有B机和D机的存在;从D机看,相当于搭建了一条到C机的隧道。
参考链接
ssh支持的端口转发类型不只远程转发(反向代理),还支持本地转发(正向代理)和动态转发。正向代理:把上面ssh命令行中的-R换成-L即可,把B机的PortB端口转发到A机的PortA端口。ssh端口转发参考参链接:
https://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/
不只Linux的ssh客户端(ssh也有Windows版本)支持端口转发,在Windows下的plink工具、Putty、SecureCRT和Xshell等都支持ssh端口转发功能。参考链接:http://blog.csdn.net/fgf00/article/details/51284335。
ssh端口转发优点:对全程传输的数据进行加密,安全性高;支持传输数据压缩,提高传输效率。
更多推荐
所有评论(0)