没有 SSH 的情况下,像“Localtunnel”这样的隧道服务如何工作?

Posted

技术标签:

【中文标题】没有 SSH 的情况下,像“Localtunnel”这样的隧道服务如何工作?【英文标题】:How tunneling services like 'Localtunnel' works without SSH? 【发布时间】:2019-03-06 21:43:23 【问题描述】:

我想了解我的本地 IP 地址 (localhost) 是如何暴露给 Internet 的。为此,我阅读了[here] 一种使用 SSH 进行端口转发的方法。这基本上是使用 SSH 从公开可用的服务器路由到我们的本地主机。

但我想知道像“LocalTunnel”这样的服务是如何工作的?上面的文章是这样写的:

那里的服务(例如 localtunnel)创建一条从他们的服务器返回到您的开发盒上的端口 3000 的隧道。它的功能与 SSH 隧道非常相似,但不需要您拥有服务器。

我尝试从它的 github 存储库中读取代码,我的理解是:

这些服务有一个公开可用的服务器,它生成不同的 URL,当我们点击该 URL 时,它将请求转发到与该 URL 对应的 localhost。

所以基本上它就像代理服务器一样工作。

这些理解正确吗?如果是,那么 我不明白的是,这些服务器如何访问我计算机上运行的某些本地主机?它如何执行对它的请求?我在这里缺少什么? Here 是我提到的代码。

【问题讨论】:

【参考方案1】:

简答 (TL;DR)

Remote(即您计算机上的 localtunnel 软件)初始化与 Relay 的连接(即 localtunnel.me)充当多路复用代理,当客户端(即 Web 浏览器)连接时,Relay 复用远程和客户端之间的连接通过附加带有网络信息的特殊标头。

Browser <--\                   /--> Device
Browser <---- M-PROXY Service ----> Device
Browser <--/                   \--> Device

视频演示

如果您更喜欢视频预览,我刚刚在 UtahJS Conf 2018 上做了一次演讲,其中我还谈到了所有其他潜在的解决方案:SSH Socksv5 代理(您提到的)、***、UPnP 、DHT、继电器等:

Access Ability: Access your Devices, Share your Stuff

幻灯片:http://telebit.cloud/utahjs2018

localtunnel、ngrok 和 Telebit 如何工作(长答案)

我是Telebit 的作者,它提供的服务具有与 ngrok、localtunnel 和 libp2p 提供的功能相似的服务(以及远程/客户端和中继/服务器的开源代码以自行运行) .

虽然我不知道 localtunnel 如何实现的确切内部结构,但我可以向您解释它一般是如何完成的(以及我们如何 这样做),而且很可能与他们的做法几乎相同。

您好奇的魔法发生在两个地方:远程套接字和多路复用器

远程客户端如何访问我本地主机上的服务器?

1。远程套接字

这很简单。当您运行“远程”(telebit、ngrok 和 localtunnel 在这方面的工作方式几乎相同)时,实际上是您的计算机发起请求。

因此想象一下,中继(在您的情况下为 localtunnel 代理)使用端口 7777 来接收来自“远程”(如您的计算机)的流量和您的 socket 号码(在您的计算机上随机选择的源地址)是 1234:

Devices:  [Your Computer]          (tcp 1234:7777)          [Proxy Server]
Software:    [Remote]          ----------------------->        [Relay]
                                (auth & request 5678)

但是,连接到您的客户端(例如浏览器、netcat 或其他用户代理)实际上向中继发起请求。

Devices:  [Proxy Service]            (tcp 5678)             [Client Computer]
Software:    [Relay]          <------------------------         [netcat]

如果您使用的是 tcp 端口,那么中继服务会保持内部映射,就像 NAT 一样

Internal Relay "Routing Table"

Rule:
Socket remote[src:1234]    --- Captures ------>  ALL_INCOMING[dst:5678]

Condition:
Incoming client[dst:5678]  --- MATCHES ------->  ALL_INCOMING[dst:5678]

Therefore:
Incoming client[dst:5678]  --- Forwards To --->  remote[src:1234]

两个连接都是“传入”连接,但“南端”的远程连接被授权接收来自另一个传入源的流量(没有某种形式的授权会话,任何人都可以声称使用该端口或地址并劫持您的交通)。

[Client Computer]  (tcp 5678)       [Proxy Service]      (tcp 1234)   [Your Computer]
   [netcat]      -------------->     <--[Relay]-->     <------------    [remote]

2。多路复用器

您可能已经注意到上述描述中存在一个严重缺陷。如果您只是按原样路由流量,您的计算机(远程)只能一次处理一个连接。如果另一个客户端(浏览器、netcat 等)跳到连接上,您的计算机将无法分辨哪些数据包来自哪里。

Browser <--\                   /--> Device
Browser <---- M-PROXY Service ----> Device
Browser <--/                   \--> Device

本质上,中继(即本地隧道代理)和远程(即您的计算机)所做的就是在客户端要接收的所有数据前面放置一个标头。它需要与 HAProxy 的代理协议非常相似,但也适用于非本地流量。它可能看起来像这样:

<src-address>,<src-port>,<sni>,<dst-port>,<protocol-guess>,<datalen>

例如

172.2.3.4,1234,example.com,443,https,1024

该信息可以在每个路由的数据包之前发送或附加到每个数据包。

同样,当远程响应中继时,它必须包含该信息,以便中继知道数据包正在响应哪个客户端。

详情请见https://www.npmjs.com/package/proxy-packer

旁注/咆哮:端口与 TLS SNI

我最初给出的解释是使用 tcp 端口,因为它很容易理解。但是,localtunnel、ngrok 和 telebit 都可以使用 tls servername indicator (SNI) 而不是依赖端口号。

[Client Computer]        (https 443)       [Proxy Service]      (wss 443)   [Your Computer]
 [netcat+openssl]   -------------------->   <--[Relay]-->     <------------    [remote]
 (or web browser)  (sni:xyz.somerelay.com)                 (sni:somerelay.com)

MITM 与 p2p

仍然有几种不同的方法可以解决这个问题(这就是我想为 Telebit 提供一个无耻的插件的地方,因为如果你喜欢去中心化和点对点,这就是我们大放异彩的地方!)

如果您只使用 tls sni 进行路由(这是我上次检查时 localtunnel 和 ngrok 的默认工作方式)所有流量都在中继处解密.

Anther 方式需要 ACME/Let's Encrypt 集成(即Greenlock.js),以便流量保持加密、端到端,无需解密即可将 tls 流量路由到客户端。出于所有实际目的,此方法充当 点对点 通道(中继仅充当 Internet 网络上的另一个不透明“开关”,不知道流量的内容)。

此外,如果 remotes(例如,通过安全 WebSockets)和客户端都使用 https,那么客户端看起来就像任何其他类型的 https 请求,而 不会受到配置不当的防火墙或其他恶劣/不利的网络条件的阻碍。

现在,基于 libp2p 构建的解决方案为您提供了虚拟化的对等连接,但它更加间接,并且需要通过不受信任的各方进行路由。我不喜欢这种方式,因为它通常速度较慢,而且我认为它的风险更大。我坚信网络联盟将在长期内战胜匿名化(如 libp2p)。 (对于我们的用例,我们需要可以联合的东西——由独立的受信任方运行——这就是我们以我们的方式构建解决方案的原因)

【讨论】:

以上是关于没有 SSH 的情况下,像“Localtunnel”这样的隧道服务如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ssh 在没有 -t 的情况下等待我的子 shell,然后用 -t 杀死它们?

是否可以使用 ngrok 或 localtunnel 来测试本地 gRPC 服务器?

如何在没有密码的情况下 ssh 到 localhost?

可与 Windows 的“localtunnel”相媲美的东西 [关闭]

如何在没有服务器的情况下在本地测试我的 ssh 密钥

如何在没有提示的情况下执行 ssh-keygen