一、前言

SSH 是一种建立在应用层基础上的安全协议,利用SSH进行数据传输时也是较为可靠和安全的。当有明文数据传输时,为保障其安全,可以利用SSH隧道对其进行加密安全传输,本文中讲到的SSH隧道用法均可以保障安全传输,文中不详做介绍,本文着重讲解除安全传输之外的其他使用场景,来分别分析三种SSH隧道的用法。

文中会用到以下SSH参数,先看一下man文档中对以下SSH参数的解释:

-L port:host:hostport

将本地机(客户机)的某个端口转发到远端指定机器的指定端口. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同时远程主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有 root 才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport

-R port:host:hostport

将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口. 工作原理是这样的, 远程主机上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转向出去, 同时本地主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有用 root 登录远程主机 才能转发特权端口. IPv6 地址用另一种格式说明: port/host/hostport

-D port

指定一个本地机器 “动态的” 应用程序端口转发. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去,根据应用程序的协议可以判断出远程主机将和哪里连接. 目前支持 SOCKS4 协议, ssh 将充当 SOCKS4 服务器. 只有 root 才能转发特权端口. 可以在配置文件中指定动态端口的转发.

-N

不执行远程命令. 用于转发端口. (仅限协议第二版)

-f

要求 ssh 在执行命令前退至后台. 它用于当 ssh 准备询问口令或密语, 但是用户希望它在后台进行. 该选项隐含了 -n 选项. 在远端机器上启动 X11 程序的推荐手法就是类似于 ssh -f host xterm 的命令.

-g

允许远端主机连接本地转发的端口.

二. 本地转发

1.功能解释

本地转发即在A服务器执行ssh命令登录B服务器来启用SSH隧道,以实现通过访问A服务器的转发端口,达到实际访问为B服务器的目标端口的目的。如下图所示:

img

2. 使用场景

当客户端可以访问主机A的任意端口,但由于网络或安全的原因客户端无法访问到主机B的任意端口。如果现在客户端想要访问主机B的某个服务时(如mysql数据库),此时只要主机A可以访问到主机B的SSH端口,这里就可以使用SSH隧道,实现客户端访问主机A的转发端口即可访问到主机B的mysql数据库。

3. 命令示例

以下命令均在A主机执行:

SSH登录后启用ssh隧道,但仅监听A主机127.0.0.1地址,退出ssh登录后隧道断开

ssh -L A转发port:B主机IP:B目的端口 root@B主机

SSH命令后不登录B主机,仅启用ssh隧道,仅监听A主机127.0.0.1地址,关闭A主机终端后隧道断开

ssh -N -L A转发port:B主机IP:B目的端口 root@B主机

SSH命令后不登录B主机,仅启用ssh隧道,仅监听A主机127.0.0.1地址,关闭A主机终端后隧道不会断开

ssh -f -N -L A转发port:B主机IP:B目的端口 root@B主机

指定A主机中ssh隧道转发端口绑定的网卡

ssh -f -N -L A主机IP:A转发port:B主机IP:B目的端口 root@B主机

将转发端口绑定至A主机所有网卡

ssh -g -f -N -L A转发port:B主机:B目的端口 root@B主机

三、远程转发

1. 功能解释

上面我们知道了本地转发是在A服务器执行ssh命令后将转发端口设置在A服务器本身,远程转发则相反,是将转发端口设置在ssh命令的目标服务器上。

远程转发即在B服务器执行ssh命令登录A服务器来启用SSH隧道,以实现通过访问A服务器的转发端口,达到实际访问为B服务器的目标端口的目的。如下图所示:

img

2. 使用场景

远程转发使用场景较为广泛且实用。

如果我们在家庭电脑上跑了一个tomcat服务并想提供到互联网访问,由于家庭电脑一般是通过路由器来访问互联网的(即在nat网络中),我们需要在家庭路由器中进行端口映射来实现。

如果我们是公共路由器没有权限怎么办?又或者在权限管控严格的公司中我们没有权限怎么办?

巧合的是,我们手上还有一台拥有公网IP的主机(如阿里云主机等),我们的家庭电脑是可以访问到互联网的(即可以SSH访问到拥有公网IP的主机),直接使用SSH隧道就可以解决以上问题。

3. 命令示例

以下命令均在B主机执行:

SSH命令后不登录A主机,仅启用ssh隧道,仅监听A主机127.0.0.1地址,关闭B主机终端后隧道不会断开

ssh -f -N -R A主机转发端口:B主机IP:B目的端口 root@A主机

看到这里,你一定会联想到以下两条指令来实现绑定到非lookback地址:

ssh -f -N -R A主机IP:A主机转发端口:B主机IP:B目的端口 root@A主机

ssh -g -f -N -R A主机转发端口:B主机IP:B目的端口 root@A主机

不过当你实验时敲下以下指令,会发现A主机的SSH隧道监听地址仍然是127.0.0.1,这又是为什么呢?

4. 将远程转发绑定到网卡

上一小节我们尝试建立远程转发隧道后,仅监听127.0.0.1地址,这是因为在SSH服务的配置文件/etc/ssh/sshd_config中有这样一个配置

GatewayPorts 是否允许远程主机连接本地的转发端口,默认值为 no。

将此项配置为yes并重启SSH服务后,再次执行命令

ssh -f -N -R A主机转发端口:B主机IP:B目的端口 root@A主机

这时远程转发的转发端口会设置在A主机的所有网卡上,即0.0.0.0

当然除了这种方法,我们还可以使用其他技术手段来实现允许其他主机访问A主机127.0.0.1地址的转发端口,例如在A主机用其他程序去反向代理127.0.0.1的转发端口,使用Nginx反代实现方式和配置可以点开我的主页,查看《Nginx实现socket代理》这篇文章。

四、 动态转发

1. 功能解释

动态转发即通过配置一个本地端口,将通过隧道的数据转发到目标端地址网络。

img

如上图所示,动态转发不像本地转发与远程转发一样转发端口与目标端口是一对一的,动态转发中的转发端口对应的目标是目标主机所在的整个网络。不过使用动态转发访问目标主机所在网络时需要应用程序本身支持代理配置或者使用socket代理工具。

2. 使用场景

同样如上图所示,如果存在一个子网1与子网2之间设有防火墙,主机A只能访问到主机B的ssh端口,这时如果主机A或者外部客户端想要访问子网2中的任意IP的任意端口时,可以使用动态转发隧道实现。

3. 命令示例

以下命令均在A主机执行:

SSH命令后不登录B主机,仅启用ssh隧道,仅监听A主机127.0.0.1地址,关闭A主机终端后隧道不会断开

ssh -f -N -D A主机转发端口 root@A主机

SSH命令后不登录B主机,仅启用ssh隧道,监听A主机指定网卡IP地址,关闭A主机终端后隧道不会断开

ssh -f -N -D A主机IP地址:A主机转发端口 root@A主机

4. 客户端代理配置

当隧道创建好之后我们需要通过代理客户端进行设置之后才会使用隧道,如果应用程序支持配置直接配置即可,如果是不支持配置代理的应用程序可以使用到socket代理工具来搭配使用,我常用的客户端代理工具是Proxifier,关于用法可以参考我主页的另一篇文章《Socket代理神器客户端Proxifier+服务端ss5》。