最近工作中经常需要ssh登录到某台跳板机,再连接受限网络环境中的某台服务器。以前经常用SSH端口转发这一功能,但周围的同事好像对这个并不清楚,这里记录一下以备其它同事询问。

SSH一共提供了 3 种端口转发,分别是本地转发(-L参数)远程转发(-R参数)动态转发(-D参数)。接下来我就一一介绍这几种不同的转发方式的使用。

一些术语和约定

既然提到转发,就应该明白:这是三台主机之间要合作干的事。不然为何不两台主机直连,而要通过第三者转发?

本地主机:形式为IP或域名,你当前正在使用的这台机器;

远程主机:形式与本地主机一样。这里的远程并不是指实际的距离有多远,准确地说是另一台;

本地转发

本地转发,顾名思义就是把本地主机端口通过待登录主机端口转发到远程主机端口上去。

本地转发通过参数 -L 指定,格式:-L [本地主机:]本地主机端口:远程网络主机:远程网络主机端口。加上ssh待登录主机,这里就有了三台主机。

举例:ssh -L 0.0.0.0:50000:host2:80 user@host1。这条命令将host2的80端口映射到本地的50000端口,前提是待登录主机host1上可以正常连接到host2的80端口。

畅想一下这个功能的作用:

  1. 因为本地的mysql更顺手,想用本地的mysql客户端命令连接受限网络环境的mysql服务端。
  2. 本地安装了开发工具,想用这个开发工具连接受限网络环境中某个服务的远程调试端口。
  3. ……

远程转发

远程转发是指把登录主机所在网络中某个端口通过本地主机端口转发到远程主机上。

远程转发通过参数 -R 指定,格式:-R [登录主机:]登录主机端口:本地网络主机:本地网络主机端口

举例:ssh -R 0.0.0.0:8080:host2:80 user@host1。这条命令将host2的80端口映射到待登录主机host1的8080端口,前提是本地主机可以正常连接host2的80端口。

畅想一下这个功能的作用:

  1. 本地网络中有一个http代理,通过这个代理可以上外网,因此通过这条命令将这个http代理映射到待登录主机的某个端口,这样受限网络环境中所有其它服务器即可使用这个http代理上外网了。
  2. 在本机开发了一个web应用,想拿给别人测试,但现在你却处在内网,外网是无法直接访问内网的主机的,怎么办!?很多人可能会说,找台有公网IP的主机,重新部署一下就行了。这样可行,但太麻烦。然而自从你了解了ssh的远程转发之后,一切都变得简单了。只需在本地主机上执行一下上面例子的命令即可实现外网访问内网的web应用。

注意

  1. sshd_config里要打开AllowTcpForwarding选项,否则-R远程端口转发会失败。
  2. 默认转发到远程主机上的端口绑定的是127.0.0.1,如要绑定0.0.0.0需要打开sshd_config里的GatewayPorts选项。这个选项如果由于权限没法打开也有办法,可配合ssh -L将端口绑定到0.0.0.0,聪明的你应该能想到办法,呵呵。

动态转发

相对于本地转发和远程转发的单一端口转发模式而言,动态转发有点更加强劲的端口转发功能,即是无需固定指定被访问目标主机的端口号。这个端口号需要在本地通过协议指定,该协议就是简单、安全、实用的 SOCKS 协议。

动态转发通过参数 -D 指定,格式:-D [本地主机:]本地主机端口。相对于前两个来说,动态转发无需再指定远程主机及其端口。它们由通过 SOCKS协议 连接到本地主机端口的那个主机。

举例:ssh -D 50000 user@host1。这条命令创建了一个SOCKS代理,所以通过该SOCKS代理发出的数据包将经过host1转发出去。

怎么使用?

  1. 用firefox浏览器,在浏览器里设置使用socks5代理127.0.0.1:50000,然后浏览器就可以访问host1所在网络内的任何IP了。

  2. 如果是普通命令行应用,使用proxychains-ng,参考命令如下:

    brew install proxychains-ng
    vim /usr/local/etc/proxychains.conf # 在ProxyList配置段下添加配置 "socks5 	127.0.0.1 50000"
    proxychains-ng wget http://host2 # 在其它命令行前添加proxychains-ng即可
    
  3. 如果是ssh,则用以下命令使用socks5代理:

    ssh -o ProxyCommand='/usr/bin/nc -X 5 -x 127.0.0.1:5000 %h %p' user@host2
    

畅想一下这个功能的作用:

  1. 想访问受限网络环境中的多种服务
  2. FQ
  3. ……

SSH Over HTTP Tunnel

有一些HTTP代理服务器支持HTTP Tunnel,目前HTTP Tunnel的主要作用是辅助代理HTTPS请求,详情参见这里。今天在工作中竟发现有同事通过HTTP Tunnel连接ssh过去,猛然想起来HTTP Tunnel的原理里并没有限制连接的目标服务一定是HTTP或HTTPS服务,貌似只要是基于TCP的服务都可以。macOS下ssh走CONNECT tunnel稍微麻烦一点,参考命令如一下:

brew install corkscrew
ssh -o ProxyCommand='/usr/local/bin/corkscrew http_proxy_host http_proxy_port %h %p' user@host2

总结

都是些小技巧,不过掌握了作用还是挺大的,可以大大提高生产力的。