SSH支持三种端口转发方式,分别是:
- 本地转发(
-L
参数) - 远程转发(
-R
参数) - 动态转发(
-D
参数)
简单介绍一下每种用法:
本地转发(Local Forwarding)
可以将远程主机的指定端口映射到本地主机的指定端口,指令格式如下:
ssh -L [本地主机host:]本地主机port:远程主机host:远程主机port username@远程主机host
举个例子,现在我远程主机 123.123.123.123
上有一个 MySQL 服务,端口为 3306
。因为防火墙端口限制,我无法直接访问到该远程主机的 3306 端口,但我还是想连接这个 MySQL 服务,所以需要通过 SSH 把它的 3306 端口映射到我本地的某个端口上。
比如我执行下面这个指令:
ssh -L 0.0.0.0:3306:123.123.123.123:3306 user@123.123.123.123
然后我就可以像访问本地服务一样,直接连接 localhost:3306
来访问远程主机的 MySQL 服务了(前提是本地没有其他服务占用这个端口)。
注意:这里使用的本地主机host是0.0.0.0
,而不是127.0.0.1
。0.0.0.0
表示本机上的所有IPv4地址,也就是监听所有网络接口。
远程转发(Remote Forwarding)
可以将本地主机的指定端口映射到远程主机的指定端口,指令格式如下:
ssh -R [远程主机host:]远程主机port:本地主机host:本地主机port username@远程主机host
还是举个例子:现在我有一台网络访问受限的远程主机 123.123.123.123
,也就是这台服务器访问不了公网,我就可以用 SSH 把我本地的代理端口映射过去,让这台远程主机通过我的网络上网。这在一些无法直接连网的服务器很有用。
我遇到的一个实际场景:
因为工作原因,现在有一台非涉密纯内网服务器(不能访问公网,公网也无法访问该服务器)。但系统中有一个模块需要在线更新,所以用了 SSH 的远程端口转发功能来解决这个问题。
注意:如果不想包吃包住的话,就千万不要在任何涉密机器上执行这种操作!!!
我使用的是 FlClash(因为我最常用,而且界面最好看 XD),当然你也可以使用其他 Clash 客户端比如 Clash Verge 或者直接用内核 clash-core。
首先,配置代理端口为 7890
,然后开启 局域网代理,如下图:
然后设置出站模式为“直连”,点击右下角启动:
接着打开 Terminal,执行如下 SSH 指令:
ssh -R 0.0.0.0:7891:127.0.0.1:7890 user1@172.1.2.3
意思是连接服务器172.1.2.3
,并且把我本地 Clash 的 7890
端口,通过 SSH 映射到服务器上的 7891
端口。
连接上去之后,在服务器上设置一下代理环境变量:
export https_proxy=http://127.0.0.1:7891
export http_proxy=http://127.0.0.1:7891
export all_proxy=socks5://127.0.0.1:7891
这样大部分 Linux 工具(比如 curl、apt、wget)就能走代理上网了。
但是,有些程序是不走系统代理的,比如 Java 程序(当然了,还取决于程序的代码逻辑),这个时候就得手动设置参数:
需要在启动 Java 程序的脚本里加上这个参数:
-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=7891
就可以让 Java 程序也走代理了。
动态转发(Dynamic Forwarding)
这是一种更加灵活的端口转发方式,它不像本地/远程转发那样指定固定的目标地址和端口,相当于在本地启动了一个 SOCKS 代理服务器,可以让任意支持 SOCKS5 协议的软件通过它来访问远程主机网络。
指令格式如下:
ssh -D 本地主机port username@远程主机host
举个例子,比如我执行:
ssh -D 1080 user@123.123.123.123
那么就相当于在我本地的 1080
端口上开了一个 SOCKS5 代理服务。只要保持这个 SSH 连接,那么我电脑上所有支持 SOCKS5 的程序(比如浏览器、Git、curl等等)都可以通过 127.0.0.1:1080
去远程访问到远程主机的网络。
我觉得你应该也想到了,动态转发是不是可以用来搭建“那种服务”?但很可惜并不行。
原因很简单,SSH 协议的特征太明显了,非常容易被识别。而且开启动态转发后,你本机上的各种客户端会发起大量像 DNS、HTTP、TLS 这样的请求,这种流量行为和正常的 SSH 使用完全不一样。
正常的 SSH 流量其实蛮轻的,毕竟咱们大多数时候只是间歇性地输入命令,哪怕是传文件,流量特征也是稳定连续的。但浏览网页、看视频这类操作的流量波动就很大,和 SSH 的流量特征完全对不上,一眼就能被识别出来。
所以呢,并不适合用来做“那种事”。