SSH端口转发(SSH Tunnul)
简介
SSH 有三种端口转发模式
- 本地端口转发(Local Port Forwarding),
- 远程端口转发(Remote Port Forwarding)以及
- 动态端口转发(Dynamic Port Forwarding)。
对于本地/远程端口转发,两者的方向恰好相反。动态端口转发则可以用于科学上网。
SSH 端口转发也被称作 SSH 隧道(SSH Tunnel),因为它们都是通过 SSH 登陆之后,在 SSH 客户端与 SSH 服务端之间建立了一个隧道,从而进行通信。SSH 隧道是非常安全的,因为 SSH 是通过加密传输数据的(SSH 全称为 Secure Shell)。<数据是安全的>
在本文所有示例中,本地主机 A1 为 SSH 客户端,远程云主机 B1 为 SSH 服务端。从 A1 主机通过 SSH 登陆 B1 主机,指定不同的端口转发选项(-L、-R 和-D),即可在 A1 与 B1 之间建立 SSH 隧道,从而进行不同的端口转发。
前提是: A1(内网主机)可以通过 ssh 远程到 B1(公网主机),B1 主机仅仅开放 22 端口,现在 B1 其他端口有服务例如 3000 端口,并且此端口并没有开放。
本地端口转发
应用场景
远程云主机 B1 运行了一个服务,端口为 3000,本地主机 A1 需要访问这个服务。
示例为一个简单的 Node.js 服务(其运行在远端服务 B1):
var http = require('http');
var server = http.createServer(function(request, response)
{
response.writeHead(200,
{
"Content-Type": "text/plain"
});
response.end("Hello Fundebug\n");
});
server.listen(3000);
假设云主机 B1 的 IP 为 120.92.116.245,则该服务的访问地址为:http://120.92.116.245:3000/ 现在因 3000 端口防火墙没有通过。
为啥需要本地端口转发呢?
一般来讲,云主机的防火墙默认只打开了 22 端口,如果需要访问 3000 端口的话,需要修改防火墙。为了保证安全,防火墙需要配置允许访问的 IP 地址。但是,本地公网 IP 通常是网络提供商动态分配的,是不断变化的。这样的话,防火墙配置需要经常修改,就会很麻烦。
什么是本地端口转发?
所谓本地端口转发,就是将发送到本地端口的请求,转发到目标端口。这样,就可以通过访问本地端口,来访问目标端口的服务。使用-L 属性,就可以指定需要转发的端口,语法是这样的:
-L 本地网卡地址:本地端口:目标地址:目标端口
通过本地端口转发,可以将发送到本地主机 A1 端口 2000 的请求,转发到远程云主机 B1 的 3000 端口。
# 在本地主机A1登陆远程云主机B1,并进行本地端口转发
ssh -L localhost:2000:localhost:3000 root@120.92.116.245
这样,在本地主机 A1 上可以通过访问 http://localhost:2000 来访问远程云主机 B1 上的 Node.js 服务。
# 在本地主机A1访问远程云主机B1上的Node.js服务
curl http://localhost:2000
Hello Fundebug
实际上,-L 选项中的本地网卡地址是可以省略的,这时表示 2000 端口绑定了本地主机 A1 的所有网卡:<这样绑定后就可以通过 ip 对 2000 端口进行访问,>
理论上是这样的,但是实际操作中发现并不是这样的,可能是用的 windows 链接的原因
# 在本地主机A1登陆远程云主机B1,并进行本地端口转发。2000端口绑定本地所有网卡
ssh -L 2000:localhost:3000 root@120.92.116.245
若本地主机 A2 能够访问 A1,则 A2 也可以通过 A1 访问远程远程云主机 B1 上的 Node.js 服务。
另外,-L 选项中的目标地址也可以是其他主机的地址。假设远程云主机 B2 的局域网 IP 地址为 192.168.59.100,则可以这样进行端口转发:
# 在本地主机A1登陆远程云主机B1,并进行本地端口转发。请求被转发到远程云主机B2上
ssh -L 2000:192.168.59.100:3000 root@120.92.116.245
若将 Node.js 服务运行在远程云主机 B2 上,则发送到 A1 主机 2000 端口的请求,都会被转发到 B2 主机上。
如何退出隧道链接
如果本地到服务端配置了免密登录后执行命令,则直接会退出到命令窗口,其实这个时候已经创建隧道成功,可以使用netstat
命令查看当前通道是否存在列表中。 <这个暂时不确定是怎么看的>
但是退出的方法是 在执行 ssh tunnul 的窗口退出链接,则可以将通道关闭掉,因为他是依赖于 22 链接的。
远程端口转发
应用场景:
本地主机 A1 运行了一个服务,端口为 3000,远程云主机 B1 需要访问这个服务。
将前文的 Node.js 服务运行在本地,在本地就可以通过http://localhost:3000
访问该服务。
远程端口转发意义?
通常,本地主机是没有独立的公网 IP 的,它与同一网络中的主机共享一个 IP。没有公网 IP,云主机是无法访问本地主机上的服务的。
什么是远程端口转发?
所谓远程端口转发,就是将发送到远程端口的请求,转发到目标端口。这样,就可以通过访问远程端口,来访问目标端口的服务。使用-R 属性,就可以指定需要转发的端口,语法是这样的:
-R 远程网卡地址:远程端口:目标地址:目标端口
这时,通过远程端口转发,可以将发送到远程云主机 B1 端口 2000 的请求,转发到本地主机 A1 端口 3000。
# 在本地主机A1登陆远程云主机B1,并进行远程端口转发
ssh -R localhost:2000:localhost:3000 root@120.92.116.245
这样,在远程云主机 A1 可以通过访问 http://localhost:2000 来访问本地主机的服务。
# 在远程云主机B1访问本地主机A1上的Node.js服务
curl http://localhost:2000
Hello Fundebug
同理,远程网卡地址可以省略,目标地址也可以是其他主机地址。假设本地主机 A2 的局域网 IP 地址为 192.168.0.100。
# 在本地主机A1登陆远程云主机B1,并进行远程端口转发
ssh -R 2000:192.168.0.100:3000 root@120.92.116.245
若将 Node.js 服务运行在本地主机 A2 上,则发送到远程云主机 A1 端口 2000 的请求,都会被转发到 A2 主机上。
速记方法!
—L 是本地代理远端 第一个主机信息是本地
—R 是远端代理本地 第一个主机信息是远端
动态端口转发
应用场景:
远程云主机 B1 运行了多个服务,分别使用了不同端口,本地主机 A1 需要访问这些服务。
####为啥需要动态端口转发呢?
一方面,由于防火墙限制,本地主机 A1 并不能直接访问远程云主机 B1 上的服务,因此需要进行端口转发;另一方面,为每个端口分别创建本地端口转发非常麻烦
配置方法
-D 本地网卡地址:本地端口
这时,通过动态端口转发,可以将在本地主机 A1 发起的请求,转发到远程主机 B1,而由 B1 去真正地发起请求。
注意是代理你去发送请求,需要在浏览器中设置,将请求的数据转发给本地 3000,是通过 sokcet 设置。和-L 是不一样的,涉及到科学上网
设置的方法如下图:
# 在本地主机A1登陆远程云主机B1,并进行动态端口转发
ssh -D localhost:3000 root@120.92.116.245
链式端口转发
本地端口转发与远程端口转发结合起来使用,可以进行链式转发。
假设 A 主机在公司,B 主机在家,C 主机为远程云主机。A 主机上运行了前文的 Node.js 服务,需要在 B 主机上访问该服务。由于 A 和 B 不在同一个网络,且 A 主机没有独立公共 IP 地址,所以无法直接访问服务。
<这种场景在工作是经常遇到的! 链式的挨着转发>
这个么有具体的实践,但是一定是可行的。
通过本地端口转发,将发送到 B 主机 3000 端口的请求,转发到远程云主机 C 的 2000 端口。
# 在B主机登陆远程云主机C,并进行本地端口转发
ssh -L localhost:3000:localhost:2000 root@103.59.22.17
通过远程端口转发,将发送到远程云主机 C 端口 2000 的请求,转发到 A 主机的 3000 端口。
# 在A主机登陆远程云主机C,并进行远程端口转发
ssh -R localhost:2000:localhost:3000 root@103.59.22.17
这样,在主机 B 可以通过访问 http://localhost:3000 来访问主机 A 上的服务。
# 在主机B访问主机A上的服务
curl http://localhost:3000
Hello Fundebug