动态 SSH 隧道 - 本地、远程和动态

2025-06-07

动态 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.
Enter fullscreen mode Exit fullscreen mode

因此,一般来说,该命令看起来像

$ ssh -L sourcePort:forwardToHost:destPort connectToHost
Enter fullscreen mode Exit fullscreen mode

这相当于 - 使用 ssh 连接到connectToHost,并将所有连接尝试转发到名为 的机器上的本地 sourcePortto 端口,该端口可从 机器访问。转发也可以使用 Unix 套接字完成。destPortforwardToHostconnectToHost

假设你的办公室网络屏蔽了 YouTube,而你又特别想看猫咪视频。那么,你可以绕过这个限制,通过一个不在你办公室网络的服务器创建一个隧道来访问 YouTube。上面的命令可以理解为:

$ ssh -L 9000:youtube.com:80 user@example.com
Enter fullscreen mode Exit fullscreen mode

这里的标志-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
Enter fullscreen mode Exit fullscreen mode

-Lcurl 中的参数用于跟踪重定向。现在,只要您连接到计算机,就应该能够从youtube.comon看到主页的内容。localhost:9000user@example.com

还有!SSH 隧道的优点在于它们是加密的,所以没有人能看到你正在访问的网站——只有你与服务器的 SSH 连接才能看到。(Office 管理员们,注意啦!!😎)

默认情况下,任何人(即使位于不同的机器上)都可以连接到本地机器上的指定端口。可以通过提供绑定地址将连接限制为同一主机上的程序:

$ ssh -L 127.0.0.1:9000:youtube.com:80 user@example.com
Enter fullscreen mode Exit fullscreen mode

SSH 绑定到本地计算机的 9000 端口。任何到达此端口的流量都会被发送到监听user@example.com远程计算机的 SSH 服务器。远程计算机接收到流量后,会将其发送到 127.0.0.1 的 80 端口,也就是它user@example.com本身。

连接到防火墙后面的数据库

forwardToHosthost 也可能指通过其建立 ssh 连接的远程计算机(即connectToHost) - 在这种情况下, 的值forwardToHost变为 127.0.0.1 或 localhost,作为其在已建立连接的上下文中的本地connectToHost

$ ssh -L 9000:127.0.0.1:80 user@example.com
Enter fullscreen mode Exit fullscreen mode

例如,当您需要连接到数据库控制台时,出于安全原因,该控制台仅允许本地连接,在您的服务器上运行 PostgreSQL,默认情况下监听端口 5432。

$ ssh -L 9000:localhost:5432 user@example.com
Enter fullscreen mode Exit fullscreen mode

此命令将本地端口 9000 转发到远程计算机的端口 5432。您可以使用 psql on localhost:9000 通过本地计算机连接到该远程 PostgreSQL 服务器,操作如下:

$ psql -h localhost -p 9000
Enter fullscreen mode Exit fullscreen mode

让我们花点时间来了解一下到底发生了什么。

在 YouTube 示例中,9000:youtube.com:80说 - 将我的本地端口 9000 转发到youtube.com端口 80。因此,服务器上的 SSH 实际上在这两个端口之间建立了一个隧道(连接) - 其中一个位于本地计算机上,另一个位于目标计算机上。

在数据库连接的示例中,9000:localhost:5432localhost 指的是服务器端的 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.
Enter fullscreen mode Exit fullscreen mode

该命令看起来很像本地隧道,但带有一个-R标志。

$ ssh -R sourcePort:forwardToHost:destPort connectToHost
Enter fullscreen mode Exit fullscreen mode

这相当于 - 使用 ssh 连接到connectToHost,并将所有连接尝试转发到名为 的机器上的远程 sourcePortto 端口,该端口可从 机器访问。转发也可以使用 Unix 套接字完成。destPortforwardToHostconnectToHost

好的!我们来看一个例子。

假设您正在本地机器上开发一个应用程序,并且您想向老板展示原型。

大多数情况下,ISP 不会向您提供公网 IP 地址,因此您无法直接通过互联网连接您的设备。虽然可以通过在路由器上配置 NAT(网络地址转换)来解决此问题,但这种方法并非总是有效,因为更改路由器配置会产生技术开销,并且您需要拥有网络管理员权限。

在这种情况下,你可以在互联网上搭建一个可公开访问且支持 SSH 访问的服务器。然后,我们让 SSH 创建一个隧道,在服务器上打开一个新端口,然后你可以通过自己机器上的本地端口连接到该服务器。

$ ssh -R 9000:localhost:3000 user@example.com
Enter fullscreen mode Exit fullscreen mode

这里的语法与本地端口转发非常相似,只需将-L更改为-R即可。

SSH 将连接到远程计算机 - 在本例中为。 -Ruser@example.com参数使 ssh 监听该计算机的 9000 端口。一旦该计算机上有进程连接到 9000 端口,则在同一台计算机上监听的 ssh 服务器会将该连接转移到本地计算机(即发起 ssh 通信的计算机),并将其转发到 localhost 的 3000 端口。

远程端口转发允许通过 SSH 将本地机器的端口映射到远程服务器上。

您需要做的另一件事是设置GatewayPorts。在您的/etc/ssh/sshd_config设置中

GatewayPorts yes
Enter fullscreen mode Exit fullscreen mode

并重启 SSH

$ sudo service ssh restart
Enter fullscreen mode Exit fullscreen mode

这允许 SSH 服务器将端口 3000 绑定到通配符地址 - 这样该端口即可供connectToHost远程机器的公共地址使用。

您也可以设置GatewayPortsclientspecified- 在这种情况下,远程端口将不会绑定到通配符地址。您可能需要显式指定一个空的绑定地址来绑定通配符地址 - 可以通过在远程端口前添加:符号来实现。

$ ssh -R :9000:localhost:3000 user@example.com
Enter fullscreen mode Exit fullscreen mode

您还可以指定允许连接到该端口的 IP 地址,这样就只允许从给定的 IP 地址连接到给定的端口。

$ ssh -R 1.2.3.4:9000:localhost:3000 user@example.com
Enter fullscreen mode Exit fullscreen mode

现在,您的老板将能够通过将浏览器指向connectToHost端口 9000 上的 IP 地址来访问端口 3000 上的应用程序。

双重转发

如果远程服务器已GatewayPorts设置为no,且无法更改它 - 您可以执行上述远程转发,然后使用-g选项进行本地转发,但从远程服务器执行。

$ ssh -g -L 9000:localhost:3000 user@example.com 
Enter fullscreen mode Exit fullscreen mode

-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
Enter fullscreen mode Exit fullscreen mode

-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
Enter fullscreen mode Exit fullscreen mode

更多阅读

文章来源:https://dev.to/__namc/ssh-tunneling---local-remote--dynamic-34fa
PREV
7 个实用的 JavaScript 技巧
NEXT
Node.js 底层原理 #7 - 全新 V8