第一部分 概述
端口转发概述
让我们先来了解一下端口转发的概念吧。我们知道,SSH 会自动加密和解密所有 SSH 客户端与服务端之间的网络数据。但是,SSH 还同时提供了一个非常有用的功能,这就是端口转发。它能够将其他 TCP 端口的网络数据通过 SSH 链接来转发,并且自动提供了相应的加密及解密服务。这一过程有时也被叫做“隧道”(tunneling),这是因为 SSH 为其他 TCP 链接提供了一个安全的通道来进行传输而得名。例如,Telnet,SMTP,LDAP 这些 TCP 应用均能够从中得益,避免了用户名,密码以及隐私信息的明文传输。而与此同时,如果您工作环境中的防火墙限制了一些网络端口的使用,但是允许 SSH 的连接,那么也是能够通过将 TCP 端口转发来使用 SSH 进行通讯。总的来说 SSH 端口转发能够提供两大功能:
1、加密 SSH Client 端至 SSH Server 端之间的通讯数据。
2、突破防火墙的限制完成一些之前无法建立的 TCP 连接。
图 1. SSH 端口转发
如上图所示,使用了端口转发之后,TCP 端口 A 与 B 之间现在并不直接通讯,而是转发到了 SSH 客户端及服务端来通讯,从而自动实现了数据加密并同时绕过了防火墙的限制。
第二部分 本地转发与远程转发
在选择端口号时要注意非管理员帐号是无权绑定 1-1023 端口的,所以一般是选用一个 1024-65535 之间的并且尚未使用的端口号即可。
假设:
墙内客户端 A 128.128.128.128
墙外代理服务器 B 138.138.138.138
目标服务器 C 158.158.158.158
如果 A不能直接访问C ,B能访问C , A能访问B。
可以采用 本地端口转发:
绑定A上的一个端口如2233 ,A向B发起建立SSH隧道连接请求,然后B再访问 C上的端口如5566
这样:访问A上的2233端口 就等于 在访问 C上5566端口
# root@root@B的IP地址 以root用户 登录 B 服务器 #-v 冗详模式. 使打印关于运行情况的调试信息. 在调试连接, 认证和配置问题时非常有用. #并联的 -v 选项能够增加冗详程度. 最多为三个. #-C 要求进行数据压缩 (包括 stdin, stdout, stderr以及转发X11和TCP/IP连接的数据) #-L port:host:hostport 将本地机[主机A]的某个端口[port]转发到远端指定机器[主机C别名host]的指定端口[hostport] # 工作原理是这样的,本地机器[主机A]上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, # 该连接就经过安全通道转发出去, 同时远程主机[主机B]和 host[主机C] 的 hostport 端口建立连接. # 可以在配置文件中指定端口的转发. 只有 root 才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport ssh -v -C -L 2233:C的IP地址:5566 root@B的IP地址 -p B的ssh端口号
那么这个端口转发可以被其他机器使用么?比如能否新增加一台 [主机X] 来直接连接 [主机A] 的 2233 端口?答案是不行的,在主流 SSH 实现中,本地端口转发绑定的是 lookback 接口,这意味着只有 localhost 或者 127.0.0.1 才能使用本机的端口转发 , 其他机器发起的连接只会得到“ connection refused. ”。好在 SSH 同时提供了 GatewayPorts 关键字,我们可以通过指定它与其他机器共享这个本地端口转发。
ssh -g -L 主机A的端口如5901:主机C:主机C的端口如5901 通过SSH连接的主机B
特殊情况下:C的IP地址:5566 可以变成 localhost:5566
localhost:5566 是针对 中间的代理服务器 来说的
这相当于A访问自己的2233端口时 等价于 直接访问B内部的5566端口[若5566端口没有暴露给别的主机,就可规避B上的防火墙]
ssh -v -C -L 2233:localhost:5566 root@B的IP地址 -p B的ssh端口号
假设:
墙内客户端 A 128.128.128.128
墙外代理服务器 B 138.138.138.138
目标服务器 C 158.158.158.158
如果 A不能直接访问C ,B能访问C , B能访问A。
可以采用 远程端口转发:
绑定A上的一个端口如2233 ,B向A发起建立SSH隧道连接请求,然后B再访问C上的端口如5566
这样:访问A上的2233端口 就等于 在访问 C上5566端口
#-R port:host:hostport 将客户机[主机A]的某个端口[port]转发到远端指定机器[主机C别名host]的指定端口[hostport] # 工作原理是这样的, 远程主机[主机A]上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, # 该连接就经过安全通道转向出去, 同时本地主机[主机B]和 host[主机C] 的 hostport 端口建立连接. # 可在配置文件中指定端口的转发.只有root登录远程主机[主机A]才能转发特权端口. # IPv6 地址用另一种格式说明: port/host/hostport ssh -v -C -R 2233:C的IP地址:5566 root@A的IP地址 -p A的ssh端口号
特殊情况下:C的IP地址:5566 可以变成 localhost:5566
localhost:5566 是针对 中间的代理服务器 来说的
这相当于A访问自己的2233端口时 等价于 直接访问B内部的5566端口[若5566端口没有暴露给别的主机,就可规避B上的防火墙]
ssh -v -C -R 2233:localhost:5566 root@A的IP地址 -p A的ssh端口号
总之,port:host:hostport 这三个参数,是按照,实际操作中,谁是代理服务器,来进行区分配置的。
第三部分 其他类型的转发
动态转发实例分析
恩,动态转发,听上去很酷。当你看到这里时,有没有想过我们已经讨论过了本地转发,远程转发,但是前提都是要求有一个固定的应用服务端的端口号,例如前面例子中的 主机C 的 5566 端口。那如果没有这个端口号怎么办?等等,什么样的应用会没有这个端口号呢?嗯,比如说用浏览器进行 Web 浏览,比如说 MSN 等等。
当我们在一个不安全的 WiFi 环境下上网,用 SSH 动态转发来保护我们的网页浏览及 MSN 信息无疑是十分必要的。让我们先来看一下动态转发的命令格式:
1
|
$ ssh -D < local port> < SSH Server> |
例如:
1
|
$ ssh -D 7001 < SSH Server> |
图 5. 动态端口转发
似乎很简单,我们选择了 7001 作为本地的端口号,其实在这里 SSH 是创建了一个 SOCKS 代理服务。来看看帮助文档中对 -D 参数的描述:
1
2
3
4
5
6
7
8
9
|
-D port This works by allocating a socket to listen to port on the local side, and whenever a connection is made to this port, the con- nection is forwarded over the secure channel, and the applica- tion protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file. |
之后的使用就简单了,我们可以直接使用 localhost:7001 来作为正常的 SOCKS 代理来使用,直接在浏览器或 MSN 上设置即可。在 SSH Client 端无法访问的网站现在也都可以正常浏览。而这里需要值得注意的是,此时 SSH 所包护的范围只包括从浏览器端(SSH Client 端)到 SSH Server 端的连接,并不包含从 SSH Server 端 到目标网站的连接。如果后半截连接的安全不能得到充分的保证的话,这种方式仍不是合适的解决方案。
X 协议转发实例分析
好了,让我们来看最后一个例子 – X 协议转发。
我们日常工作当中,可能会经常会远程登录到 Linux/Unix/Solaris/HP 等机器上去做一些开发或者维护,也经常需要以 GUI 方式运行一些程序,比如要求图形化界面来安装 DB2/WebSphere 等等。这时候通常有两种选择来实现:VNC 或者 X 窗口,让我们来看看后者。
使用 X 窗口通常需要分别安装:X Client 和 X Server 。在本例中我们的 X Client 就是所访问的远程 Linux/Unix/Solaris/HP,而我们的 X Server 则是发起访问的本地机器(例如你面前正在使用的笔记本或台式机)。把 X Client 端的 X 窗口显示在 X Server 端需要先行在 X Client 端指定 X Server 的位置,命令格式如下:
1
|
export DISPLAY=< X Server IP>:< display #>.< virtual #> |
例如:
1
|
export DISPLAY=myDesktop:1.0 |
然后直接运行 X 应用即可,X 窗口就会自动在我们的本地端打开。
一切运行正常,但是,这时候 IT 部门突然在远程 Linux/Unix/Solaris/HP 前面加了一道防火墙。非常不幸的是,X 协议并不在允许通过的列表之内。怎么办?只能使用 VNC 了么?不,其实只要使用了 SSH 端口转发即可通过,同时也对 X 通讯数据做了加密,真是一举两得。(当然,使用此方法前最好先咨询相关 IT 部门是否符合相应的安全条例,以免造成违规操作。)
建立命令也很简单,直接从本地机器(X Server 端)发起一个如下的 SSH 连接即可:
1
|
$ ssh -X < SSH Server> |
图 5. X 转发
建立连接之后就可以直接运行远程的 X 应用。注意建立 X 转发之后会自动设置 DISPLAY 环境变量,通常会被设置成localhost:10.0
,我们无需也不应该在连接之后再进行修改此环境变量。
一个比较常见的场景是,我们的本地机器是 Windows 操作系统,这时可以选择开源的 XMing 来作为我们的 XServer,而 SSH Client 则可以任意选择了,例如 PuTTY,Cygwin 均可以配置 访问 SSH 的同时建立 X 转发。
第四部分 总结
至此,我们已经完成了本地端口转发,远程端口转发,动态端口转发以及 X 转发的介绍。回顾起来,总的思路是通过将 TCP 连接转发到 SSH 通道上以解决数据加密以及突破防火墙的种种限制。对一些已知端口号的应用,例如 Telnet/LDAP/SMTP,我们可以使用本地端口转发或者远程端口转发来达到目的。动态端口转发则可以实现 SOCKS 代理从而加密以及突破防火墙对 Web 浏览的限制。对于 X 应用,无疑是 X 转发最为适用了。虽然每一部分我们都只是简单的介绍了一下,但如果能灵活应用这些技巧,相信对我们的日常生活 / 工作也是会有所帮助的。