动态 SSH隧道 - 本地、远程和动态
原文发表于:namc.in - SSH 隧道
我们大多数人都熟悉 SSH(安全外壳)——一种允许我们安全登录远程系统的协议。SSH 隧道(也称为 SSH 端口转发)是 SSH 的一项功能,用于在本地和远程系统之间转发加密连接。SSH 隧道的工作原理是使用已建立的 SSH 连接来发送额外的网络流量。
我们将研究三种类型的端口转发——本地、远程和动态。
本地端口转发
让我们看看 SSH 的手册页告诉我们什么local
local: -L
Specifies that the given port on the local (client) host is to be forwarded to the given host and port on the remote side.
因此,一般来说,该命令看起来像
$ ssh -L sourcePort:forwardToHost:destPort connectToHost
这相当于 - 使用 ssh 连接到connectToHost
,并将所有连接尝试转发到名为 的机器上的本地 sourcePort
to 端口,该端口可从 机器访问。转发也可以使用 Unix 套接字完成。destPort
forwardToHost
connectToHost
假设你的办公室网络屏蔽了 YouTube,而你又特别想看猫咪视频。那么,你可以绕过这个限制,通过一个不在你办公室网络的服务器创建一个隧道来访问 YouTube。上面的命令可以理解为:
$ ssh -L 9000:youtube.com:80 user@example.com
这里的标志-L
表示我们正在进行本地端口转发。我们连接到该user@example.com
机器。然后,我们将本地机器上任何到端口 9000 的连接转发到 上的端口 80(这是 HTTP 的默认端口)youtube.com
。现在,如果您打开浏览器并访问http://localhost:9000
,则会向 上监听的 HTTP 服务器发出请求youtube.com
。但是,您的本地机器上并没有运行任何 Web 服务器。
您仍然无法查看主页 - 所以不必担心。
浏览器中的请求localhost:9000
以 localhost 为 Host Destination 标头构建。该请求到达了youtube.com
机器。但该请求被忽略并显示错误消息 -Invalid virtual host ..
因为 localhost 不能是正在运行的服务器上的域名youtube
。
为了解决这个问题,我们更改了 Host HTTP 标头,使远程 Web 服务器能够识别相应的目的地。
$ curl -H "Host: youtube.com" -L localhost:9000
-L
curl 中的参数用于跟踪重定向。现在,只要您连接到计算机,就应该能够从youtube.com
on看到主页的内容。localhost:9000
user@example.com
还有!SSH 隧道的优点在于它们是加密的,所以没有人能看到你正在访问的网站——只有你与服务器的 SSH 连接才能看到。(Office 管理员们,注意啦!!😎)
默认情况下,任何人(即使位于不同的机器上)都可以连接到本地机器上的指定端口。可以通过提供绑定地址将连接限制为同一主机上的程序:
$ ssh -L 127.0.0.1:9000:youtube.com:80 user@example.com
SSH 绑定到本地计算机的 9000 端口。任何到达此端口的流量都会被发送到监听user@example.com
远程计算机的 SSH 服务器。远程计算机接收到流量后,会将其发送到 127.0.0.1 的 80 端口,也就是它user@example.com
本身。
连接到防火墙后面的数据库
forwardToHost
host 也可能指通过其建立 ssh 连接的远程计算机(即connectToHost
) - 在这种情况下, 的值forwardToHost
变为 127.0.0.1 或 localhost,作为其在已建立连接的上下文中的本地connectToHost
。
$ ssh -L 9000:127.0.0.1:80 user@example.com
例如,当您需要连接到数据库控制台时,出于安全原因,该控制台仅允许本地连接,在您的服务器上运行 PostgreSQL,默认情况下监听端口 5432。
$ ssh -L 9000:localhost:5432 user@example.com
此命令将本地端口 9000 转发到远程计算机的端口 5432。您可以使用 psql on localhost:9000 通过本地计算机连接到该远程 PostgreSQL 服务器,操作如下:
$ psql -h localhost -p 9000
让我们花点时间来了解一下到底发生了什么。
在 YouTube 示例中,9000:youtube.com:80
说 - 将我的本地端口 9000 转发到youtube.com
端口 80。因此,服务器上的 SSH 实际上在这两个端口之间建立了一个隧道(连接) - 其中一个位于本地计算机上,另一个位于目标计算机上。
在数据库连接的示例中,9000:localhost:5432
localhost 指的是服务器端的 localhost,而不是你机器上的 localhost。换句话说,将我的本地端口 9000 转发到服务器的 5432 端口,因为当你在服务器上时,localhost 指的是服务器本身。
小于 1024 或大于 49151 的端口号是系统保留的,只能由 root 用户转发。如果您使用任何类型的端口转发,都需要指定目标服务器,例如connectToHost
。
端口转发默认启用。如果没有启用,请AllowTcpForwarding
检查/etc/ssh/sshd_config
。
远程端口转发
再次回到手册页查看定义remote
remote: -R
Specifies that the given port on the remote (server) host is to be forwarded to the given host and port on the local side.
该命令看起来很像本地隧道,但带有一个-R
标志。
$ ssh -R sourcePort:forwardToHost:destPort connectToHost
这相当于 - 使用 ssh 连接到connectToHost
,并将所有连接尝试转发到名为 的机器上的远程 sourcePort
to 端口,该端口可从 机器访问。转发也可以使用 Unix 套接字完成。destPort
forwardToHost
connectToHost
好的!我们来看一个例子。
假设您正在本地机器上开发一个应用程序,并且您想向老板展示原型。
大多数情况下,ISP 不会向您提供公网 IP 地址,因此您无法直接通过互联网连接您的设备。虽然可以通过在路由器上配置 NAT(网络地址转换)来解决此问题,但这种方法并非总是有效,因为更改路由器配置会产生技术开销,并且您需要拥有网络管理员权限。
在这种情况下,你可以在互联网上搭建一个可公开访问且支持 SSH 访问的服务器。然后,我们让 SSH 创建一个隧道,在服务器上打开一个新端口,然后你可以通过自己机器上的本地端口连接到该服务器。
$ ssh -R 9000:localhost:3000 user@example.com
这里的语法与本地端口转发非常相似,只需将-L更改为-R即可。
SSH 将连接到远程计算机 - 在本例中为。 -Ruser@example.com
参数使 ssh 监听该计算机的 9000 端口。一旦该计算机上有进程连接到 9000 端口,则在同一台计算机上监听的 ssh 服务器会将该连接转移到本地计算机(即发起 ssh 通信的计算机),并将其转发到 localhost 的 3000 端口。
远程端口转发允许通过 SSH 将本地机器的端口映射到远程服务器上。
您需要做的另一件事是设置GatewayPorts
。在您的/etc/ssh/sshd_config
设置中
GatewayPorts yes
并重启 SSH
$ sudo service ssh restart
这允许 SSH 服务器将端口 3000 绑定到通配符地址 - 这样该端口即可供connectToHost
远程机器的公共地址使用。
您也可以设置GatewayPorts
为clientspecified
- 在这种情况下,远程端口将不会绑定到通配符地址。您可能需要显式指定一个空的绑定地址来绑定通配符地址 - 可以通过在远程端口前添加:
符号来实现。
$ ssh -R :9000:localhost:3000 user@example.com
您还可以指定允许连接到该端口的 IP 地址,这样就只允许从给定的 IP 地址连接到给定的端口。
$ ssh -R 1.2.3.4:9000:localhost:3000 user@example.com
现在,您的老板将能够通过将浏览器指向connectToHost
端口 9000 上的 IP 地址来访问端口 3000 上的应用程序。
双重转发
如果远程服务器已GatewayPorts
设置为no
,且无法更改它 - 您可以执行上述远程转发,然后使用-g
选项进行本地转发,但从远程服务器执行。
$ ssh -g -L 9000:localhost:3000 user@example.com
-g允许远程主机连接到本地转发端口,这将使服务器上的环回端口 3000 可在端口 9000 上的所有接口上访问。
动态端口转发 - SOCKS
动态端口转发允许跨一系列端口进行通信。此端口转发使用-D参数创建。这使得 SSH 充当SOCKS 代理服务器。
SOCKS 协议有两种:SOCKS4 和 SOCKS5。它们本质上是互联网协议,使用代理服务器在服务器和客户端之间路由数据包。SOCKS5 同时使用 TCP 和 UDP,而 SOCKS4 仅使用 TCP。
SOCKS 代理是一个简单的 SSH 隧道,特定应用程序通过隧道将其流量转发到远程服务器,然后代理将流量转发到常规互联网。与 VPN 不同,SOCKS 代理必须在客户端计算机上为每个应用程序单独配置。
动态端口转发可以处理来自多个端口的连接。它会分析流量以确定给定连接的目的地。但是,您可能需要配置程序以使用 SOCKS 代理服务器。
可以通过以下方式实现:
$ ssh -D 9000 -f -C -q -N connectToHost
-D告诉 SSH 在端口 9000 上创建 SOCKS 隧道。
-f将进程分叉到后台。
-C在发送数据之前压缩数据。
-q启用安静模式。
-N告诉 SSH 隧道建立后将不会发送任何命令。
使用代理的缺点是性能下降,并且由于代理会重写数据包头,错误标记会比较多。使用 SOCKS5 代理,服务器不会重写数据包头,因此性能更高,数据路由错误也更少。由于 SOCK5 代理是底层代理,因此可以处理任何类型的数据流量——程序、协议等等。
结束提示!
这些-nNT
标志将使 SSH 不分配 tty,而仅执行端口转发。这将防止每次创建隧道时都创建 shell。
$ ssh -nNT -L 9000:youtube.com:80 user@example.com