4. SSH 端口转发

4.1. 概述

回顾开篇, ssh 创建了一条隧道,允许数据在其中传输:

../_images/ssh.png

如果本地 ssh 和远程 sshd 各创建一个端口,用于收发数据,那就可以实现任意数据的转发。

4.2. 网络参数

在介绍转发前,先说明一些网络编程的概念,下表列出了 ssh 端口转发所涉及的地址:

IP版本

通配地址

回环地址(本地地址)

指定地址

IPv4

0.0.0.0

127.0.0.1/localhost

合法 IPv4 单播地址

IPv6

[::0]

[::1]

合法 IPv6 单播地址

  • * 表示 IPv4 和 IPv6 地址,理论上本地地址无所谓 IPv4 和 IPv6。

  • IPv6 地址很长,使用 :: 代表补足 128 bit 的 0,有时还使用 [] 包裹,详见 IPv6 协议。

假设主机有如下地址(数据合理性未考虑,只是为了说明数据传入情况):

0.0.0.0                     # 通配地址,实际不存在
[::0]                       # 通配地址,实际不存在
127.0.0.1/localhost         # 回环地址,IPv4 地址,位于 lo 接口
[::1]                       # 回环地址,IPv6 地址,位于 lo 接口
10.0.0.1                    # IPv4 地址,位于 eth0 接口
192.168.1.10                # IPv4 地址,位于 eth0 接口
192.168.2.10                # IPv4 地址,位于 eth1 接口
400::1                      # IPv6 地址,位于 eth0 接口
200::1                      # IPv6 地址,位于 eth0 接口
300::1                      # IPv6 地址,位于 eth0 接口
  • 通配地址: 表示允许任意地址接入

0.0.0.0             # 数据可以从任意一个 IPv4 地址传入,包括回环地址,也不区分接口
[::0]               # 数据可以从任意一个 IPv6 地址传入,包括回环地址,也不区分接口
*                   # 数据可以从任意一个地址传入,包括回环地址,也不区分接口
  • 回环地址: 表示只允许本地地址连入

127.0.0.1/localhost # 数据只能从该地址传入,也就是本机 IPv4 数据
[::1]               # 数据只能从该地址传入,也就是本机 IPv6 数据
  • 指定地址: 表示只允许指定地址连入

10.0.0.1            # 数据只能从该地址传入,也就是 eth0 接口, 10.0.0.1 地址
192.168.1.10        # 数据只能从该地址传入,也就是 eth0 接口, 192.168.1.10 地址
192.168.2.10        # 数据只能从该地址传入,也就是 eth1 接口, 192.168.2.10 地址
400::1              # 数据只能从该地址传入,也就是 eth0 接口, 400::1 地址
200::1              # 数据只能从该地址传入,也就是 eth0 接口, 200::1 地址
300::1              # 数据只能从该地址传入,也就是 eth1 接口, 300::1 地址

备注:此处不考虑 IPv4 与 IPv6 的互操作性,也就是两者严格区分,详见 《unix 网络编程》。

4.3. 转发选项

端口转发时,往往和以下三个选项组合使用。

-f

后台运行

-N

不执行远程命令

-C

压缩数据

4.4. 本地转发 (-L)

../_images/local_port_forwarding.png

本地转发就是本地主机收到的数据通过远程主机转到目的地址,上图对应的命令如下:

ssh -fCNL 0.0.0.0:9999:4.4.4.4:8080 sshserver@3.3.3.3

对应格式为 -L [bind_address:]port:host:hostport

如果只是本机数据转发,则可以减少地址范围:

ssh -fCNL 9999:4.4.4.4:8080 sshserver@3.3.3.3               # 默认只允许本机转发
ssh -fCNL 127.0.0.1:9999:4.4.4.4:8080 sshserver@3.3.3.3

UNIX 域套接字也属于网络范畴,因此也可作为监听地址或目的地址,完整的帮助信息如下:

-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket

4.5. 动态转发 (-D)

本地转发需要确立目的地址,然后手动维护转发规则,这难以应对目的地址过多或变动的情况。动态转发会根据目的地址自动维护转发规则,只需绑定本地地址。

ssh/ssh_image/dynamic_port_forwarding.png

帮助信息:

-D [bind_address:]port

举例:

ssh -D           9999 sshserver     # 绑定 IPv4 本地地址,由 sshserver 转发数据
ssh -D 127.0.0.1:9999 sshserver     # 绑定 IPv4 本地地址,由 sshserver 转发数据
ssh -D   0.0.0.0:9999 sshserver     # 绑定 IPv4 通配地址,由 sshserver 转发数据
ssh -D     [::0]:9999 sshserver     # 绑定 IPv6 通配地址,由 sshserver 转发数据

未确认信息: 动态转发为 socks5 代理,数据带有目的地址,sshd 根据目的地址自动维护转发规则。

4.6. 远程转发 (-R)

ssh/ssh_image/remote_port_forwarding.png

远程转发就是远程主机收到的数据通过本地主机转到目的地址,工作原理如下:

示例命令:

-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket

举例:

ssh -R 9999:localhost:8080 user@sshserver

4.7. 自动重连

yum install autossh

autossh -M 7281 -fCNR 7280:localhost:22 root@123.123.123.123

最核心的不同在于代理的对象不同。

正向代理是代理客户端

。反向代理是代理服务器。

而根据这核心的区别,我们也可以记住:代理哪端便可以隐藏哪端。

也就是说:

正向代理隐藏真实客户端反向代理隐藏真实服务端