第一部分概述当你在咖啡馆享受免费WiFi的时候,有没有想到可能有人正在窃取你的密码及隐私信息?当你发现实验室的防火墙阻止了你的网络应用端口,是不是有苦难言?来看看SSH的端口转发功能能给我们带来什么好处吧!端口转发概述让我们先来了解一下端口转发的概念吧。我们知道,SSH会自动加密和解密所有SSH客户端与服务端之间的网络数据。但是,SSH还同时提供了一个非常有用的功能,这就是端口转发。它能够将其他TCP端口的网络数据通过SSH链接来转发,并且自动提供了相应的加密及解密服务。这一过程有时也被叫做“隧道”(tunneling,隧道是一种把一种网络协议封装进另外一种网络协议进行传输的技术。这里我们研究ssh隧道,所以所有的网络通讯都是ssh加密的。又被称作端口转发,因为ssh隧道通常会绑定一个本地端口,所有发向这个端口端口的数据包,都会被加密并透明地传输到远端系统。),这是因为SSH为其他TCP链接提供了一个安全的通道来进行传输而得名。例如,Telnet,SMTP,LDAP这些TCP应用均能够从中得益,避免了用户名,密码以及隐私信息的明文传输。而与此同时,如果您工作环境中的防火墙限制了一些网络端口的使用,但是允许SSH的连接,那么也是能够通过将TCP端口转发来使用SSH进行通讯。总的来说SSH端口转发能够提供两大功能:1.加密SSHClient端至SSHServer端之间的通讯数据。2.突破防火墙的限制完成一些之前无法建立的TCP连接。图1.SSH端口转发如上图所示,使用了端口转发之后,TCP端口A与B之间现在并不直接通讯,而是转发到了SSH客户端及服务端来通讯,从而自动实现了数据加密并同时绕过了防火墙的限制。第二部分本地转发与远程转发本地转发实例分析我们先来看第一个例子,在实验室里有一台LDAP服务器(LdapServerHost),但是限制了只有本机上部署的应用才能直接连接此LDAP服务器。如果我们由于调试或者测试的需要想临时从远程机器(LdapClientHost)直接连接到这个LDAP服务器,有什么方法能够实现呢?答案无疑是本地端口转发了,它的命令格式是:ssh-L[bind_address:]localport:remotehost:remoteportSSHhostname参数说明bind_address指定绑定的IP地址,默认情况会绑定在本地的回环地址(即127.0.0.1)localport指定本地绑定的端口remotehost指定数据包转发目的地址的IP,如果remotehost和SSHhostname是同一台主机时该参数可以用localhostremoteport指定数据包转发目的端口SSHhostname指定数据包中转地址的IP在LdapClientHost上执行如下命令即可建立一个SSH的本地端口转发,例如:$ssh-L7001:localhost:389LdapServerHost$ssh-L1521:92.168.40.17:1521root@92.168.40.17与$ssh-L1521:localhost:1521root@92.168.40.17效果相同图2.本地端口转发这里需要注意的是本例中我们选择了7001端口作为本地的监听端口,在选择端口号时要注意非管理员帐号是无权绑定1-1023端口的,所以一般是选用一个1024-65535之间的并且尚未使用的端口号即可。然后我们可以将远程机器(LdapClientHost)上的应用直接配置到本机的7001端口上(而不是LDAP服务器的389端口上)。之后的数据流将会是下面这个样子:我们在LdapClientHost上的应用将数据发送到本机的7001端口上,而本机的SSHClient会将7001端口收到的数据加密并转发到LdapServertHost的SSHServer上。SSHServer会解密收到的数据并将之转发到监听的LDAP389端口上,最后再将从LDAP返回的数据原路返回以完成整个流程。我们可以看到,这整个流程应用并没有直接连接LDAP服务器,而是连接到了本地的一个监听端口,但是SSH端口转发完成了剩下的所有事情,加密,转发,解密,通讯。这里有几个地方需要注意:1.SSH端口转发是通过SSH连接建立起来的,我们必须保持这个SSH连接以使端口转发保持生效。一旦关闭了此连接,相应的端口转发也会随之关闭。2.我们只能在建立SSH连接的同时创建端口转发,而不能给一个已经存在的SSH连接增加端口转发。3.你可能会疑惑上面命令中的remotehost为什么用localhost,它指向的是哪台机器呢?在本例中,它指向LdapServertHost。我们为什么用localhost而不是IP地址或者主机名呢?其实这个取决于我们之前是如何限制LDAP只有本机才能访问。如果只允许lookback接口访问的话,那么自然就只有localhost或者IP为127.0.0.1才能访问了,而不能用真实IP或者主机名。4.命令中的remotehost和SSHhostname必须是同一台机器么?其实是不一定的,它们可以是两台不同的机器。我们在后面的例子里会详细阐述这点。5.好了,我们已经在LdapClientHost建立了端口转发,那么这个端口转发可以被其他机器使用么?比如能否新增加一台LdapClientHost2来直接连接LdapClientHost的7001端口?答案是不行的,在主流SSH实现中,本地端口转发绑定的是lookback接口,这意味着只有localhost或者127.0.0.1才能使用本机的端口转发,其他机器发起的连接只会得到“connectionrefused.”。好在SSH同时提供了GatewayPorts关键字,我们可以通过指定它与其他机器共享这个本地端口转发。5.ssh-g-Llocalport:remotehost:remoteportSSHhostname注意:ssh连接是不稳定,有时候建立的本地端口转发连接会断掉。我们不可能从家里跑到单位再敲一次命令,所以搞一个自动检查连接状态的脚本是必须的。定时地(譬如说每半个小时)检查本地端口转发连接是否存在,如果不存在,马上再建立一个连接。首先需建立从本地主机到中转机器的ssh免密码连接,使用ssh登录时不需要输入密码。ssh命令的解释:ssh-C-f-N-g-L[bind_address:]localport:remotehost:remoteportSSHhostname参数说明-CEnablecompression.压缩数据传输。-fForkintobackgroundafterauthentication.后台认证用户/密码,通常和-N连用,不用登录到远程主机。-NDonotexecuteashellorcommand.不执行脚本或命令,通常与-f连用。-gAllowremotehoststoconnecttoforwardedports.允许远程主机连接到建立的转发的端口,如果不加这个参数,只允许本地主机建立连接。再将下面的脚本文件存为$HOME/session/Reverse_SSH.sh,让它是可执行的。#!/bin/shRET=`psax|grepssh-fNgL1521:localhost:1521conn@92.168.40.17|grep-vgrep`if[$RET=];thenechoTherecentSSHfailureoccuredat`date`~/session/reverse_ssh.logechoRestartreverseSSH!ssh-fNgL1521:localhost:1521conn@92.168.40.17fi最后利用crontab让机器每隔30分钟就检查一次这个映射是否存在,若不存在,马上再次建立映射。具体过程是$crontab-e将下面的命令加入crontab,保存并退出*/30****$HOME/session/Reverse_SSH.sh远程转发实例分析我们来看第二个例子,这次假设由于网络或防火墙的原因我们不能用SSH直接从LdapClientHost连接到LDAP服务器(LdapServertHost),但是反向连接却是被允许的。那此时我们的选择自然就是远程端口转发了。它的命令格式是:ssh-R[bind_address:]localport:remotehost:remoteportSSHhostname参数说明bind_address指定绑定的IP地址,默认情况会绑定在本地的回环地址(即127.0.0.1)localport指定本地绑定的端口remotehost指定数据包转发源地址的IP,如果remotehost和SSHhostname是同一台主机时该参数指定为localhostremoteport指定数据包转发源端口SSHhostname指定数据包中转地址的IP例如在LDAP服务器(LdapServertHost)端执行如下命令:$ssh-R7001:localhost:389LdapClientHost图3.远程端口转发和本地端口转发相比,这次的图里,SSHServer和SSHClient的位置对调了一下,但是数据流依然是一样的。我们在LdapClientHost上的应用将数据发送到本机的7001端口上,而本机的SSHServer会将7001端口收到的数据加密并转发到LdapServertHost的SSHClient上。SSHClient会解密收到的数据并将之转发到监听的LDAP389端口上,最后再将从LDAP返回的数据原路返回以完成整个流程。看到这里,你是不是会有点糊涂了么?为什么叫本地转发,而有时又叫远程转发?这两者有什么区别?本地转发与远程转发的对比与分析不错,SSHServer,SSHClient,LdapServertHost,LdapClientHost,本地转发,远程转发,这么多的名词的确容易让人糊涂。让我们来分析一下其中的结构吧。首先,SSH端口转发自然需要SSH连接,而SSH连接是有方向的,从SSHClient到SSHServer。而我们的应用也是有方向的,比如需要连接LDAPServer时,LDAPServer自然就是Server端,我们应用连接的方向也是从应用的Client端连接到应用的Server端。如果这两个连接的方向一致,那我们就说它是本地转发。而如果两个方向不一致,我们就说它是远程转发。我们可以回忆上面的两个例子来做个对照。本地转发时:LdapClientHost同时是应用的客户端,也是SSHClient,这两个连接都从它指向LdapServertHost(既是LDAP服务端,也是SSHServer)。远程转发时:LdapClientHost是应用的客户端,但却是SSHServer;而LdapServertHost是LDAP的服务端,但却是SSHClient。这样两个连接的方向刚好相反。另一个方便记忆的方法是,Server端的端口都是预定义的固定端口(SSHServer的端口22,LDAP的端口389),而Client端的端口都是动态可供我们选择的端口(如上述例子中选用的7001端口)。如果Server端的两个端口都在同一台机器,Client端的两个端口都在另一台机器上,那么这就是本地连接;如果这四个端口交叉分布在两个机器上,每台机器各有一个Server端端口,一个Client端端口,那就是远程连接。弄清楚了两者的区别之后,再来看看两者的相同之处。如果你所在的环境下,既允许LdapClientHost发起SSH连接到LdapServerHost,也允许LdapServerHost发起SSH连接到LdapClientHost。那么这时我们选择本地转发或远程转发都是可以的,能完成一样的功能。接着让我们来看个进阶版的端口转发。我们之前涉及到的各种连接/转发都只涉及到了两台机器,还记得我们在本地转发