SSH - Port Forwarding Overview
本文试图整理 openssh(before v8.0) 的几种流量转发模式。
Local Forward
本地转发
CLI Options
1 | ssh -L [bind-address:]bind-port:target-host:target-port |
Configuration File
1 | LocalForward [bind-address:]bind-port target-host:target-port |
Description
ssh 客户端会在本地监听一个端口,即参数中的 bind-port 字段。发往该端口的流量会被封装在 ssh 流量中发往远程 sshd 服务端,再由服务端转发至目标地址,即参数中的 target-host:target-port 字段。这个功能在客户端无法直接访问目标地址时非常有用,可以透明得将目标端口“移动”到本地。
在不指定 bind-address 时,默认监听地址根据 ssh_config 文件中的 GatewayPorts
选项决定,若为 no
则默认监听在本地 loopback 上,否则默认监听在泛地址。若需要指定监听地址可以设置参数中的 bind-address 字段,比如想把其他子网中的某个服务暴露给本地网络的其他机器时可以监听在本机的内网地址上。参数为 unix domain socket 时效果类似。
缺点即是一个本地端口只能绑定一个目标地址。
Remote Forward
远程转发
CLI Options
1 | ssh -R [bind-address:]bind-port:local-host:local-port #1 |
Configuration File
1 | # Equivalent to CLI option #1 |
Description
对于命令行参数的 #1-4,sshd 服务端会在远程监听在 bind-port 上。发往该端口的流量会被封装在 ssh 流量中发往本地 ssh 客户端,再由客户端转发给位于本地的目标。可以看到该过程和上述本地转发相反,这个功能在本地目标对外部不可访问时非常有用,比如把内网的某个服务暴露给其他子网(即内网穿透),相当于透明得把本地端口“移动”到远程。这种配置一次也只能绑定一个目标地址。
对于命令行参数的 #5,sshd 服务端同样会在远程监听在 bind-port 上。但运行在该端口的是一个 socks4/socks5 代理,该代理会把目标地址和发往目标地址的流量一起转发给本地的 ssh 客户端,再由客户端转发给目标地址。可以看到,与 #1-4 的区别是在参数中没有指明目的地址,目的地址是由每个发往代理的连接动态决定的,即该选项会将本地网络完全地暴露在 sshd 所在服务器上。该选项的优点是配置一次可以转发所有流量给本地(虽然容易造成安全性问题)。缺点就是这种转发不再是透明的,想要访问位于本地的目标的应用需要设置自己的代理为远程服务器的 socket 地址。
为了增强安全性,在不指定 bind-address
时 sshd 会监听在服务器的 loopback 上。客户端也可以指定监听地址,但是一定要在 ssh_config 中添加 GatewayPorts yes
才能监听成功。
Dynamic Forward
动态转发
CLI Options
1 | ssh -D [bind-address:]bind-port |
Configuration File
1 | DynamicForward [bind-address:]bind-port |
Description
类似 Remote Forward 中的 #5 配置,ssh 客户端在本地监听在 bind-port 上,在这个端口上运行 socks4/socks5 代理,该代理会把目的地址和发往目的地址的流量一起转发给远程的 sshd 服务端,再由服务端去访问目的地址。这个选项可以用来建立一条 ssh 加密隧道,可能是最方便的 bypass 防火墙(你懂的)技术。
可以该选项即是动态版的本地转发,不知道为什么 openssh 不把这个功能集成到 Local Forward 里去。
Standard I/O Forward
转发标准输入输出
CLI Options
1 | ssh -W target-host:target-port |
Description
该选项将 ssh 客户端的标准输入输出通过 ssh 协议转发到 sshd 服务端,再由服务端转发给目标地址。功能上即是一个 ssh 版的 netcat 命令,可以用来简化 ssh 跳板机的配置,有机会详细写一下详见这里。