ssh命令实现端口转发
概念
SSH 会自动加密和解密所有 SSH 客户端与服务端之间的网络数据。但是,SSH 还同时提供了一个非常有用的功能,这就是端口转发。它能够将其他 TCP 端口的网络数据通过 SSH 链接来转发,并且自动提供了相应的加密及解密服务。这一过程有时也被叫做“隧道”(tunneling),这是因为 SSH 为其他 TCP 链接提供了一个安全的通道来进行传输而得名.
总的来说 SSH 端口转发能够提供两大功能:
-
加密 SSH Client 端至 SSH Server 端之间的通讯数据。
-
突破防火墙的限制完成一些之前无法建立的 TCP 连接
如上图所示,使用了端口转发之后,TCP 端口 A 与 B 之间现在并不直接通讯,而是转发到了 SSH 客户端及服务端来通讯,从而自动实现了数据加密并同时绕过了防火墙的限制
两台服务器的端口转发
本地转发
格式:ssh -L <``local
port>:<``remote
host>:<``remote
port> <``SSH
hostname>
环境简介
serverA:
serverA:
[root@serverA ~]# curl -I 192.168.47.131
curl: (7) Failed connect to 192.168.47.131:80; Connection refused
serverB:
[root@serverB ~]# netstat -anlp | grep 80
tcp 0 0 127.0.0.1:80 0.0.0.0:* LISTEN 2180/httpd
[root@serverB ~]# curl -I localhost
HTTP/1.1 200 OK
Date: Mon, 18 Feb 2019 21:12:04 GMT
要求 :serverA无法直接访问serverB的80端口,serverA可以ssh到serverB。
设置转发
[root@serverA ~]# ssh -L 1212:localhost:80 root@192.168.47.131
输入登录serverB的登录密码
测试
[root@serverA ~]# curl -I localhost:1212
HTTP/1.1 200 OK
Date: Mon, 18 Feb 2019 21:19:09 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Mon, 18 Feb 2019 21:09:20 GMT
ETag: "5-5823189d02b90"
Accept-Ranges: bytes
Content-Length: 5
Content-Type: text/html; charset=UTF-8
原理介绍
这里需要注意的是本例中我们选择了 1212 端口作为本地的监听端口,在选择端口号时要注意非管理员帐号是无权绑定 1-1023 端口的,所以一般是选用一个 1024-65535 之间的并且尚未使用的端口号即可
然后我们可以将远程机器(serverB)上的应用直接配置到本机的 1212 端口上(而不是 HTTP服务器的 80 端口上)。之后的数据流将会是下面这个样子:
- 我们在 serverA 上的应用将数据发送到本机的 7001 端口上,
- 而本机的 SSH Client 会将 1212 端口收到的数据加密并转发到 serverB 的 SSH Server 上。
- SSH Server 会解密收到的数据并将之转发到监听的 HTTP 80 端口上,
- 最后再将从 80 返回的数据原路返回以完成整个流程。
注意:
-
SSH 端口转发是通过 SSH 连接建立起来的,我们必须保持这个 SSH 连接以使端口转发保持生效。一旦关闭了此连接,相应的端口转发也会随之关闭。
-
我们只能在建立 SSH 连接的同时创建端口转发,而不能给一个已经存在的 SSH 连接增加端口转发。
-
你可能会疑惑上面命令中的 为什么用 localhost,它指向的是哪台机器呢?在本例中,它指向 serverB。我们为什么用 localhost 而不是 IP 地址或者主机名呢?其实这个取决于我们之前是如何限制HTTP 只有本机才能访问。如果只允许 lookback 接口访问的话,那么自然就只有 localhost 或者 IP 为 127.0.0.1 才能访问了,而不能用真实 IP 或者主机名。
-
命令中的 和 必须是同一台机器么?其实是不一定的,它们可以是两台不同的机器。我们在后面的例子里会详细阐述这点。
-
好了,我们已经在 serverA 建立了端口转发,那么这个端口转发可以被其他机器使用么?比如能否新增加一台 serverc 来直接连接 serverA 的 1212 端口?答案是不行的,在主流 SSH 实现中,本地端口转发绑定的是 lookback 接口,这意味着只有 localhost 或者 127.0.0.1 才能使用本机的端口转发 , 其他机器发起的连接只会得到“ connection refused. ”。好在 SSH 同时提供了 GatewayPorts 关键字,我们可以通过指定它与其他机器共享这个本地端口转发。
ssh -g -L <local port>:<remote host>:<remote port> <SSH hostname>
远程转发
要求 :serverA无法直接访问serverB的80端口,serverB可以ssh到serverA。
设置转发:
[root@serverB ~]# ssh -R 1212:localhost:80 root@192.168.47.128
本地转发和远程转发的对比分析
不错,SSH Server,SSH Client,LdapServertHost,LdapClientHost,本地转发,远程转发,这么多的名词的确容易让人糊涂。让我们来分析一下其中的结构吧。首先,SSH 端口转发自然需要 SSH 连接,而 SSH 连接是有方向的,从 SSH Client 到 SSH Server 。而我们的应用也是有方向的,比如需要连接 LDAP Server 时,LDAP Server 自然就是 Server 端,我们应用连接的方向也是从应用的 Client 端连接到应用的 Server 端。如果这两个连接的方向一致,那我们就说它是本地转发。而如果两个方向不一致,我们就说它是远程转发。
我们可以回忆上面的两个例子来做个对照。
本地转发时:
LdapClientHost 同时是应用的客户端,也是 SSH Client,这两个连接都从它指向 LdapServertHost(既是 LDAP 服务端,也是 SSH Server)。
远程转发时:
LdapClientHost 是应用的客户端,但却是 SSH Server ;而 LdapServertHost 是 LDAP 的服务端,但却是 SSH Client 。这样两个连接的方向刚好相反。
多台服务器转发
让我们来看一个涉及到四台机器 (A,B,C,D) 的例子。
在 SSH Client© 执行下列命令来建立 SSH 连接以及端口转发:
$ ssh -g -L 7001:<``B``>:389 <``D``>
然后在我们的应用客户端(A)上配置连接机器(C )的 7001 端口即可。注意我们在命令中指定了“ -g ”参数以保证机器(A)能够使用机器(C)建立的本地端口转发。而另一个值得注意的地方是,在上述连接中,(A)<-> © 以及 (B)<->(D) 之间的连接并不是安全连接,它们之间没有经过 SSH 的加密及解密。如果他们之间的网络并不是值得信赖的网络连接,我们就需要谨慎使用这种连接方式了。
动态转发
恩,动态转发,听上去很酷。当你看到这里时,有没有想过我们已经讨论过了本地转发,远程转发,但是前提都是要求有一个固定的应用服务端的端口号,例如前面例子中的 LDAP 服务端的 389 端口。那如果没有这个端口号怎么办?等等,什么样的应用会没有这个端口号呢?嗯,比如说用浏览器进行 Web 浏览,比如说 MSN 等等。
当我们在一个不安全的 WiFi 环境下上网,用 SSH 动态转发来保护我们的网页浏览及 MSN 信息无疑是十分必要的。让我们先来看一下动态转发的命令格式:
$ ssh -D <``local
port> <``SSH
Server>
例如:
$ ssh -D 7001 <``SSH
Server>
似乎很简单,我们依然选择了 7001 作为本地的端口号,其实在这里 SSH 是创建了一个 SOCKS 代理服务。来看看帮助文档中对 -D 参数的描述:
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 端 到目标网站的连接。如果后半截连接的安全不能得到充分的保证的话,这种方式仍不是合适的解决方案。
总结
参数 | 含义 |
---|---|
-L | 监听127.0.0.1:local_port |
-g | 监听0.0.0.0:locall_port |
-R | 远程转发 |
-D | 动态转发 |