详解三种 SSH 端口转发
平时用 ssh 的端口转发功能也不多,总容易忘记,干脆记下来吧。
参数格式
动态端口转发:
ssh -D <local ip>:<local port> <user>@<remote host>
本地端口转发:
ssh -L <listen port>:<dest host>:<dest port> <user>@<remote host>
远程端口转发:
ssh -R <listen port>:<dest host>:<dest port> <user>@<remote host>
下面举例详解这几种转发。
动态端口转发
ssh -D 1080 user@remotehost
所有由本机1080
端口发出的流量将经remotehost
上某个端口(动态的,所以叫动态端口转发) 转发出去,此时本机1080
端口可用做 socks5 代理。
- 这里的
<local ip>
可以省略,比如上面的例子,如省略默认绑定到127.0.0.1
、::1
- 也可以使用
:1080
、*:1080
或加-g
选项,效果一样,都绑定0.0.0.0
、::
- 使用
0.0.0.0:1080
则不会绑定::
(ipv6)
本地端口转发
sudo ssh -L 443:www.baidu.com.com:443 user@remotehost
所有发往本机443
(第一个443)端口的流量都会经remotehost
转发至www.baidu.com:443
(第二个443) 端口,这时我们在/etc/hosts
中添加一行:
127.0.0.1 www.baidu.com
再打开浏览器访问 https://www.baidu.com,你会发现一切正常。
你也可以作如下转发来验证转发是否生效:
sudo ssh -L 80:ip.cn:80 user@remotehost
#绑定本地小于1024(不含1024)的端口需要root权限
再添加 hosts:
127.0.0.1 ip.cn
这时访问 http://ip.cn,就会显示远程主机remotehost
的公网 ip 了。
同理,如果你另外还有一台远程主机 remotehost2
,作如下转发:
ssh -L 2022:remotehost2:22 user@remotehost
然后就可以在本机上用ssh -p 2022 [email protected]
来连接remotehost2
上的 ssh 服务了。
以上三个例子中,有很重要的一点,我们访问本地端口时,流量都是经由远程主机remotehost
来转发,所以例子中的www.baidu.com
、ip.cn
、remotehost2
都是针对远程主机remotehost
而言的,如果换成一个内网 ip,也是远程主机remotehost
的内网。
还有一点,默认本地端口都是绑定在127.0.0.1、::1,也就是说只有本机可以访问,可以加上参数-g解除这一限制。
远程端口转发
ssh -R 80:ip.cn:80 root@remotehost
#绑定远程主机上小于1024(不含1024)的端口需要远程主机的root权限
在远程主机remotehost
上所有发往其80
(第一个80
)端口的流量将经由本机转发至ip.cn:80
(第二个80
)端口。在远程主机remotehost
添加如下 hosts:
127.0.0.1 ip.cn
再在远程主机remotehost
上访问http://ip.cn
,会显示本机的 ip:
curl http://ip.cn
这里与前面的本地端口转发一样,远程主机remotehost
上的监听端口同样是绑定在127.0.0.1
、::1
上的,并且-g
选项此时无效。
要使监听端口能够绑定到非回环地址,需要在 ssh 服务端配置中启用 GatewayPorts
选项。
实例
假设现在有两台主机 A(host-a) 与 B(host-b),均在各自的内网,另外有一台公网主机 C(host-c),想要在 B 上通过 ssh 连接到 A,可以按下面的步骤操作:
1. 在 A 上执行:
ssh -R 2022:localhost:22 userc@host-c
这里的2022
端口可自行选定,参数中的localhost:22
指的是 A 的22
端口
2. 在 B 上执行:
ssh -L 2022:localhost:2022 userc@host-c
参数中前一个2022
是 B 上的端口,localhost:2022
则是 C 上的2022
端口
3. 在 B 上执行:
ssh -p2022 usera@localhost
这样就可以直接登录到 A 了
流量是这样走的:
sshclient -> B:2022 -> sshtunnel -> C:2022 -> sshtunnel -> A:22
小结
本地端口转发和远程端口转发的参数很类似,都是<listen port>:<dest host>:<dest port>
的形式,区别和联系如下:
- 两种转发第一个参数都是监听端口,中间的主机是目标主机,最后是目标主机的端口
-L
后的监听端口是本地端口,-R
后端监听端口是远程主机的端口- 默认情况下,监听端口都绑定到
127.0.0.1
、::1
,本地端口转发可以加-g
选项绑定到0.0.0.0
、::
- 本地端口转发流量经由远程主机转发至目标主机;远程端口转发流量经本地主机转发至目标主机
- 流量由谁转发则
<dest host>
就相对谁而言;如果<dest host>
是localhost
,则本地端口转发时指远程主机,远程端口转发时指本地主机
挺好的。学习到了不少东西。