Loading... ssh 端口转发相关说明 ssh 本身除了 shell (命令行)和作为外壳(SCP/SFTP)等,自己还带了诸如端口转发、SOCKS 代理等多种功能。 常见的有如下三种方式 * Local Port Forwarding(-L) * Remote Port Forwarding(-R) * Dynamic Port Forwarding(Socks5 Proxy)(-D) 区别的话,Local 和 Remote 是转发某个端口,其中,Local 模式最终是在本地开放监听,而 Remote 是在远程开放监听(这样要好记,即 Local 从远程发到本地,而 Remote 从本地发到远程) # SSH 端口转发 ## Local Port Forwarding 远程的端口发到本地(实际开的端口是本地端口) 常用的形式是 `ssh -L [bind_host:]bind_port:remote_host:remote_port user@host`,例如 `ssh -L 2222:127.0.0.1:22 user@example.com`,将 `example.com` 的 `127.0.0.1:22` 转发到本地的 `2222` 端口 > `bind` 部分是相对于本机说的,即绑定的 IP 和端口,可以指定一个 IP 或者是使用 `0.0.0.0` 或 `*` 表示全部接口。如果不提供则根据本地 `config` 内的 `GatewayPorts` 进行设定,默认是只限定 `127.0.0.1` 访问 > > 而 `remote` 部分相对的是远程主机,即比如 `127.0.0.1` 是远程的 `127.0.0.1` ,也就是是后面登录的服务器 常见的需求比如 * 在 ssh 下工作,但是需要本地连接远程服务器特定端口进行调试 * 只开放了 ssh,但是需要其他协议连接(比如 VNC/RDP/其他本地服务如 MySQL) * 远程能到达但是本地不能到达的网络 ### **对于场景一** 服务器开启一个服务器,例如 `python -m http.server 8000` 即可开启一个监听在 `0.0.0.0` 和 `::1` 的 HTTP 服务器 假定这个不能直接访问,那么可以通过 `ssh -L 88:127.0.0.1:8000 user@xxx.com` 将远程的 8000 端口转发到本地。这样通过 `127.0.0.1:88` 就可以访问了 ### **对于场景二** 例如只放行了 SSH,而远程是 Windows 主机(Windows 10/11 内置了可选功能 Openssh-server) 那么就可以 `ssh -L 3390:127.0.0.1:3389 user@123.123.123.123` 将远程的 `3389` 端口开放到本地的 `3390` 当然,这里还有一种方法,使用 `127.0.0.1/8` 均被划分成了本地回环的特性 `ssh -L 127.0.0.2:3389:127.0.0.1:3389 user@123.123.123.123` 将远程的 3389 端口绑定到本地的 `127.0.0.2:3389` 端口,这样就可以直接通过 `127.0.0.2` 进行访问了(SMB 协议,即 Windows 自带的文件共享似乎不支持这么做。折腾黑群晖的经验) ### **对于场景三** 比如一个很经典的校园网络,`172.17.0.0/16` 是互通的校园网环境 而你在寝室有一个路由器,其 IP 是 `172.17.23.45`,是将 ssh 暴露在校内的(即 WAN 口允许 ssh 登录) 路由器使用的网段是 `192.168.1.1/24`,其下有一个设备是 `192.168.1.2` 这时,可以通过 `ssh -L 2222:192.168.1.2:22 root@172.17.23.45` 将 `192.168.1.2` 的 `22` 端口发送到本地的 `2222` 端口 ## Remote Port Forwarding 本地的端口发往远程(实际上是在远程开的端口) 常见的形式是 `ssh -R [bind_addr:]bind_port:local_addr:local_port user@host` > `bind` 部分是相对于远程主机说的,默认只允许 `127.0.0.1`访问,可以通过`0.0.0.0`或`*`指定任意 IP(但是这样需要首先在`config`内修改`GatewayPorts`改为`yes`,否则即使指定也仅本机访问) > > 而 `local` 部分则是本地主机为基准的地址 常见场景如 * frp (但是建议临时使用,长时间仍然更推荐专门的 frp 等工具) * 端口穿透(类似 frp,不过我想的是应用在路由器的。没试过能不能这么干,主要取决于 openwrt 自带的 dropbear 是否支持了) * shell 反弹(也不完全是标准的 shell 反弹(即 stdio - netio),比如想象一个场景,你同学在配置 ubuntu 出了问题想你求助,你想帮他操作,但是没有办法访问他的设备,在有 ssh 的情况下,可以将 22 端口临时开到某个共哦 三个场景实际类似,以场景三为例 `ssh -R 2222:127.0.0.1:22 user@host` ,将本地的 `22` 端口开放到远程的 `2222` 端口 之后取决于 `GatewayPorts` 设置,是本地或者公网访问了 ## Dynamic Port Forwarding(SOCKS5 Proxy) 本质上是一个 SOCKS5 代理 使用 SOCKS5 代理协议,发往某个主机的数据,会被代理到远程发送,应该也算是一种动态的端口转发了吧 使用很简单,`ssh -D [addr:]port user@host` 即可。在 `[addr:]port` 上监听一个 SOCKS5 代理,数据发往远端 常见场景 * openwrt 访问内网 * ~~临时梯子~~ 因为和任何代理是一样的,发往代理的流量会发送到代理服务器后发出,因此用这个方式可以直接到达本不能到达的地方 例如 `Local Port Forwarding` 内场景三,如果需要访问部署在局域网内的服务(尤其是 HTTP 服务) 可以直接 `ssh -D 1080 root@172.17.23.45`,然后浏览器配置 SOCKS5 代理,且不忽略局域网地址(即局域网地址,如 `192.168.1.1/24` 同样走代理)的情况下,可以直接通过例如 `192.168.1.1` 访问路由器,或者其他地址访问局域网内的 web 服务(我很长一段时间就是这么干的) (利用这个特性,同样可以比如作为临时的梯子使用) > 题外话 > > 虽然确实套了一层壳,有一层加密,但是过墙的有效性以及安全性(指被 ban IP)暂持怀疑态度,这种方式临时用用就行了,不建议作为主要方式使用,毕竟挂一个服务器成本还是挺高的 > > 因为有一次我去 Google `ssh -D 流量特征` ,出来的第一篇文章是 [方滨兴:如何从SSH加密流量中区分出ssh,scp,sftp,tunnel等流量 | 藤桥 (free-hoster.net)](http://babydick.free-hoster.net/archives/61) > > ![image.png](https://blog.zsh2517.com/usr/uploads/2021/11/3169466624.png) # ssh 跳板 首先,三种转发方式,在应用支持的情况下,都是可以作为**广义的**跳板的(即通过某个 ssh 连接到一个无法到达的 ssh 服务器) 假设自己是 A,能到达某设备 B,B 后面有一个 C 无法从 A 直接访问 比如利用 `ssh -L` 利用 B 能访问 C 的特性,将 C 的 ssh 端口转发到自己的某个端口,然后自己直接连接到该端口 或者,利用 `ssh -R` ,让 C 在 B 上开一个端口,之后自己连接到 B 再或者,`ssh -D` 直接形成 socks5 代理,之后通过代理进行 ssh 当然除此之外,ssh 本身是提供了跳板的功能的。比如 `ssh zsh2517@192.168.9.11 -J root@172.20.3.3,root@192.168.9.1` 通过 `172.20.3.3` 的路由器和 `192.168.9.1` 的路由器,连接到最后一跳(`192.168.9.1`)到达的 `192.168.9.11` 上 使用 `-J` 进行跳板的时候,仍然可以加 `-L/-R/-D` 的端口转发。这时仍然是本机和登录上去的远程服务器 # 动态的开放端口转发 详见 `man ssh` 的 `ESCAPE CHARACTERS` 节 假设已经在一个 ssh 连接中了,这时如果需要新增一个端口转发,可以通过 `Escape Character` 提供的命令进行操作 `~#` 查看当前存在的连接(已经连接的才算,只是开了通道但是没有连接不算) `~C` 打开 ssh 自身的命令行,在这里可以添加或者取消转发 例如(第三次什么也没输入,多按了一个回车。二四次是 `~C` 进行的操作,进入 `ssh shell`) ![image.png](https://blog.zsh2517.com/usr/uploads/2021/11/2060008645.png) 完整 `man ssh` 文档 ```python ESCAPE CHARACTERS When a pseudo-terminal has been requested, ssh supports a number of functions through the use of an escape char‐ acter. A single tilde character can be sent as ~~ or by following the tilde by a character other than those described below. The escape character must always follow a newline to be interpreted as special. The escape character can be changed in configuration files using the EscapeChar configuration directive or on the command line by the -e option. The supported escapes (assuming the default ‘~’) are: ~. Disconnect. ~^Z Background ssh. ~# List forwarded connections. ~& Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate. ~? Display a list of escape characters. ~B Send a BREAK to the remote system (only useful if the peer supports it). ~C Open command line. Currently this allows the addition of port forwardings using the -L, -R and -D op‐ tions (see above). It also allows the cancellation of existing port-forwardings with -KL[bind_address:]port for local, -KR[bind_address:]port for remote and -KD[bind_address:]port for dy‐ namic port-forwardings. !command allows the user to execute a local command if the PermitLocalCommand option is enabled in ssh_config(5). Basic help is available, using the -h option. ~R Request rekeying of the connection (only useful if the peer supports it). ~V Decrease the verbosity (LogLevel) when errors are being written to stderr. ~v Increase the verbosity (LogLevel) when errors are being written to stderr. ``` 最后修改:2021 年 11 月 21 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏