开发者生态
morning
sanstun:Rust 中的无 IO、并行友好的 WireGuard 实现
摘要
Today, we are announcing sanstun : a sans-IO Rust implementation of the WireGuard® state machine, optimized for ease of use, security and performance through a parallel-friendly and idiomatic API. san...
and
sans
the
that
with
was
are
boringtun
Rust
API
2026-10-31
1 阅读
约6分钟阅读
wh33zle
字号:
今天,我们宣布推出 sanstun :WireGuard® 状态机的 sans-IO Rust 实现,通过并行友好且惯用的 API 针对易用性、安全性和性能进行了优化。 sans-IO 是指您设计系统时将 IO 和副作用与状态和“业务逻辑”完全分离。 sans-IO 中的 IO 不仅仅意味着文件或网络 IO。它还包括诸如时间和随机性之类的东西!由于没有副作用,sans-IO 组件组合得非常好并且相对容易测试。该设计还避免了函数着色等问题,并且与 Rust 的所有权规则很好地配合。本文中的代码示例和参考资料均采用 Rust 语言,但 sans-IO 根本不是 Rust 特定的。它的模式和思想可以应用于任何语言。如需更深入的解释,我们的 sans-IO 帖子是一个很好的起点。当我们第一次构建 Firezone 时,我们选择了 Boringtun 作为我们的 WireGuard 实现。 boringtun 或多或少做了我们想要的,但随着时间的推移,我们发现自己一遍又一遍地修补我们的分支,修复错误并添加 API。目标是让这些补丁仍然能够在上游运行,因此我们始终保持现有 API 的工作方式。我们发现,随着我们产品需求的发展,保持与上游 100% API 兼容性变得越来越困难。我们对 Boringtun 所做的第一个重大改变是在时间处理方面使其完全无 IO ( firezone/boringtun#5 )。这意味着为带有 _at 后缀的所有内容添加新的 API,这需要 Instant 。如果您想准确地模拟整个系统,sans-IO 时间处理非常重要。请参阅此博文以了解有关我们如何做到这一点的更多信息。我们标记的另一件事是内部缓冲。首先,如果您还没有(或不再有)并且您正在尝试发送数据包,boringtun 会自动建立会话,这似乎很方便。然而,内部缓冲存在几个问题:在某些时候,需要耗尽缓冲区。 boringtun 通过要求您使用零长度数据报调用 decapsulate 来解决这个问题。相当不直观。它会产生额外的分配(至少以在boringtun中实现的方式)。缓冲区大小应该是可配置/可调的。所有这些问题都指向同一个解决方案:只是不要在库中缓冲。它简化了双方的接口和实现。补丁和修复的完整列表相当长。即使排除依赖性碰撞,也有超过 70 个 PR。其中有几个是针对我们发现的边缘情况的修复。其他人添加新的 API 或使某些方面可配置。经过两年多的使用和修补 Boringtun ,我们非常清楚用户空间 WireGuard 实现的整体 API 应该是什么样的。现在它以 sanstun 的形式存在。 sans-IO API 的核心构建块现在是: 处理入站数据包:Tunnel::handle_handshake_initiation Tunnel::handle_handshake_response Tunnel::handle_cookie_reply Tunnel::begin_decapsulate & Tunnel::commit_decapsulate 处理出站数据包:Tunnel::begin_encapsulate 处理计时器更新:Tunnel::handle_timeout & Tunnel::poll_timeout 处理事件: Tunnel::poll_event 如果没有内部缓冲,就没有 API 契约要求您在循环中调用某些 API,这更适合整体 sans-IO 模型。要发送数据包,请调用 Tunnel::begin_encapsulate 。如果您还没有会话,则由您来缓冲数据包。创建新会话意味着发送握手。您可以随时使用 Tunnel::initiate_handshake 启动新的握手。这些 API 的设计经过深思熟虑,如果我们快速回顾一下 WireGuard 协议,就会更有意义。 WireGuard的消息格式支持4种类型的消息:握手初始化、握手响应、cookie回复和加密数据。每个 WireGuard 会话都以 Diffie-Hellman 密钥交换开始,这是一项成本适中的操作。 WireGuard 的设计可确保暴露端点不会带来 DoS 机会。任何知道端点公钥的人都可以轻松创建伪造的握手启动并伪造传入 UDP 数据包的源 IP。接收 WireGuard 实现必须运行一半的 DH 操作,然后才能判断提供的握手数据是伪造的。但此时,CPU 资源已经被耗尽。发送足够的握手启动,接收端将花费其所有 CPU 周期来处理不相关的握手。为了防止这种情况,WireGuard 指定了一种 cookie 机制,强制远程端证明其声明的源 IP 的所有权,从而允许对每个源 IP 进行速率限制握手。这些速率限制适用于整个 WireGuard 接口,而不仅仅是单个隧道。一旦握手完成,双方就可以使用对称密码交换加密的数据包。作为握手的一部分,同行们还交换了信息
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱