SSH Tunneling
ssh端口转发,用来实现翻墙的操作。
它有几种不同的称呼:ssh端口映射,端口转发,ssh隧道,英文(SSH port forward, SSH tunneling )实际上是指同样的意思。
动态转发
动态转发指的是,本机与 SSH 服务器之间创建了一个加密连接,然后本机内部针对某个端口的通信,都通过这个加密连接转发。它的一个使用场景就是,访问所有外部网站,都通过 SSH 转发。
动态转发需要把本地端口绑定到 SSH 服务器。至于 SSH 服务器要去访问哪一个网站,完全是动态的,取决于原始通信,所以叫做动态转发。
$ ssh -D local-port tunnel-host -N
上面命令中,-D
表示动态转发,local-port
是本地端口,tunnel-host
是 SSH 服务器,-N
表示这个 SSH 连接只进行端口转发,不登录远程 Shell,不能执行远程命令,只能充当隧道。
举例来说,如果本地端口是2121
,那么动态转发的命令就是下面这样。
$ ssh -D 2121 tunnel-host -N
注意,这种转发采用了 SOCKS5 协议。访问外部网站时,需要把 HTTP 请求转成 SOCKS5 协议,才能把本地端口的请求转发出去。
下面是 SSH 隧道建立后的一个使用实例。
$ curl -x socks5://localhost:2121 http://www.example.com
上面命令中,curl 的-x
参数指定代理服务器,即通过 SOCKS5 协议的本地2121
端口,访问http://www.example.com
。
Test tunnel
curl --socks5-hostname "socks5://localhost:2121" ifconfig.me
如果经常使用动态转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
DynamicForward tunnel-host:local-port
建立本地ssh隧道
典型场景
我想要从自己的机器直接访问远程服务的8080端口,可以建立本机的隧道监听端口,实现方法:
在MyPC操作(192.168.0.111)
前提:通过ssh 可以直接从MyPC连接Jump Server
ssh -N -f -L 1111:10.0.1.4:8080 redhat@40.74.67.218
检查本地新出现的监听端口
$ netstat -an | grep LISTEN | grep 1111
tcp4 0 0 127.0.0.1.1111 *.* LISTEN
tcp6 0 0 ::1.1111 *.* LISTEN
本机打开浏览器,地址栏输入 http://localhost:1111 ,把本地 1111端口通过一台机器做跳板映射到了远程8080端口,可以直接访问。
连续跳转
当访问内部服务器需要跳过两个jump server,可以在jump机器上建立跳转,然后本机再做一次。
第一次在靠近自己的跳板机(Jump1)上做。
ssh -i mykey jump2 -N -f -L 8443:real-server:8443
第二次在本机做映射
ssh -N -f -L 1111:localhost:8443 jump1
于是,在本机就可以访问端口1111了。
建立远程ssh隧道
假设由于网络或防火墙的原因我们不能用 SSH 直接从 本机 连接到 跳板 服务器(40.74.67.218),但是反向连接却是被允许的。那此时我们的选择自然就是远程端口转发了。
(场景:MyPC -> ssh -> Jump 被禁止;MyPC <- ssh <- Jump 允许)
因为本机使用内网IP, 不能直接反向直连,我找了另外一台服务器做例子,如下图:
在 Jump 机操作(40.74.67.218)
ssh -N -f -R 2222:10.0.1.4:8080 redhat@40.83.72.19
在 Work 机验证(40.83.72.19)
$ netstat -an | grep 2222
tcp 0 0 127.0.0.1:2222 0.0.0.0:* LISTEN
tcp6 0 0 ::1:2222 :::* LISTEN
$ wget http://localhost:2222
本地转发与远程转发的对比
SSH 端口转发自然需要 SSH 连接,而 SSH 连接是有方向的,从 SSH Client 到 SSH Server 。而我们的应用也是有方向的,比如需要连接 Web Server 时,Web Server 自然就是 Server 端,我们应用连接的方向也是从应用的 Client 端连接到应用的 Server 端。如果这两个连接的方向一致,那我们就说它是本地转发。而如果两个方向不一致,我们就说它是远程转发。
本地转发时:
MyPC 同时是应用的客户端,也是 SSH Client,这两个连接都从它指向 Jump所在网络。
远程转发时:
Work 是应用的客户端,但却是 SSH Server ;而 Jump 所在网络是 Web 的服务端,但却是 SSH Client 。这样两个连接的方向刚好相反。
另一种简单粗暴的区分:所有操作在同一台机器完成,这就是本地转发;否则就是远程转发。
过程中使用参数的解释
-f Fork into background after authentication.
-N Do not execute a shell or command.
-L port:host:hostport
-R port:host:hostport
中文再解释一遍,这里我们用到了SSH客户端的三个参数:
-N 告诉SSH客户端,这个连接不需要执行任何命令。仅仅做端口转发
-f 告诉SSH客户端在后台运行
-L 做本地映射端口,被冒号分割的三个部分含义分别是
需要使用的本地端口号 (端口:1111)
需要访问的目标机器IP地址(IP: 10.0.1.4)
需要访问的目标机器端口(端口: 8080)
最后一个参数是我们用来建立隧道的中间机器的IP地址(IP: 40.74.67.218)
我们再重复一下-L参数的行为。-L X:Y:Z的含义是,将IP为Y的机器的Z端口通过中间服务器映射到本地机器的X端口。
命令使用格式:
ssh -f -N -L listen_port:DST_Host:DST_port user@Tunnel_Host (本地转发)
ssh -f -N -R listen_port:DST_Host:DST_port user@Tunnel_Host (远程转发)
Windows SSH App 端口转发的方法
以Xshell 为例