开源 Rust 语言的 XMPP 服务端项目 Lonewolf 在 11 月 13 日发布了 v0.3.0 版本。距离 10 月 27 日的 v0.1 初版还不到一个月,开发者 ortuman 就为这个内嵌 redb 数据库、单二进制运行的轻量服务器补上了跨服联邦(Federation)能力。同日,ortuman 将发布消息提交至 Hacker News,引发了社区关于 Prosody、XMPP 与 Matrix 对比及协议支持度的讨论。

激进的证书洁癖与摇摆的边界

本次 v0.3.0 的核心动作,是在打通服务器间联邦的同时做了一次激进的协议减法:

砍掉旧回拨严守跨服认证,却在证书吊销检查上默认放行(示意图)
砍掉旧回拨严守跨服认证,却在证书吊销检查上默认放行(示意图)
  • 默认开启跨服联邦.只要配置好证书和公网 DNS,节点就能跨服交换消息、在线状态、IQ 和花名册,且支持双向复用单连接(XEP-0288)和前置流量限制协商(XEP-0478)。
  • 彻底砍掉 Server Dialback:跨服认证强制要求公网受信任证书配合 SASL EXTERNAL,同时新增首字节 Direct TLS(XEP-0368)。
  • 桌面端扩展与不可逆升级.补齐私有 XML 存储(XEP-0049)和版本查询(XEP-0092);引入可选的 SCRAM-SHA-512 认证,但新生成的密码凭证无法直接回滚至 v0.2.0。
Lonewolf v0.3.0 的安全取舍:大门极严,侧门妥协 激进的现代主义(做减法) • 强制 SASL EXTERNAL 证书认证 • 彻底砍掉传统 Server Dialback • 支持首字节 Direct TLS (XEP-0368) 代价:无法互通仅支持回拨的老旧节点 妥协的实用边界(留后门) • 纯 HTTP 拉取 CRL 吊销列表 • CRL 下载失败默认放行 (fail-open) • 引入已过期草案 SCRAM-SHA-512 代价:破坏密码学洁癖,新版凭证不可回滚

XMPP 诞生于上世纪末,传统的 Server Dialback(服务器回拨)有着旧协议的安全隐患与历史包袱。

Lonewolf 直接砍掉回拨,强制要求 SASL EXTERNAL。在 Let's Encrypt 早已普及的今天,我赞赏这种不替旧时代背包的干脆。代价也很直接:现存 XMPP 联邦网络里有不少长尾老旧节点,如果对方没配好双向证书链、只支持回拨,Lonewolf 就直接拒之门外。

但我不太买账的是它在安全边界上的左右摇摆。跨服认证卡得死死的,到了检查证书吊销列表(CRL)时,却走纯 HTTP 下载,且一旦下载失败就默认放行。加上它顺手塞进来的 SCRAM-SHA-512 其实出自一份已过期的互联网草案,并非正式 RFC 标准,也没在 IANA 注册。一边是激进的现代密码学洁癖,一边是怕连不上网的实用主义放水,这种工程取舍多少有点拧巴。


协议跑通与日常可用的鸿沟

看到单二进制、内嵌 redb、支持跨服联邦,很多自托管玩家第一反应是终于可以替掉手里的 Prosody 了。如果真把主力账号迁过去,不出十分钟就会卡死在日常体验上。

缺失流管理协议,连接中断或重启时未发消息会被直接丢弃(示意图)
缺失流管理协议,连接中断或重启时未发消息会被直接丢弃(示意图)
在 XMPP 的世界里,写完核心协议连万里长征的第一步都算不上。

现代即时通讯的体面,全靠几十个 XEP 扩展协议在底下撑着。把 Lonewolf 目前的规划表和统治生态多年的 Prosody(Lua 编写)、ejabberd(Erlang 编写)放一起对比,差距一目了然。

跨越可用性鸿沟:Lonewolf v0.3.0 的三层协议现状 顶层:现代 IM 刚需扩展(均在规划中,尚未实现) 缺失 PEP (卡死 OMEMO 加密) | 缺失 MAM (无多端历史同步) | 缺失 MUC (无群聊) | 缺失 HTTP 传文件 中层:传输可靠性与抗弱网(残缺,易丢消息) 仅支持消息抄送 (XEP-0280);无流管理 (XEP-0198),断连不重发,服务器关机直接丢弃待发队列 底层:核心路由与跨服联邦(v0.3.0 已跑通) 单二进制 Rust + redb | 跨服消息与状态互通 | Direct TLS (XEP-0368) | 双向单连接 (XEP-0288)

最致命的短板有两个。一是没有实现个人事件协议(PEP,XEP-0163),客户端无法通过服务器分发密钥包,导致现代 XMPP 标配的 OMEMO 端到端加密直接报废;二是没有消息归档(MAM,XEP-0313),手机和电脑切着用时,离线期间的历史消息根本没法同步。至于建群聊(MUC)和发图片文件(XEP-0363),也全在未兑现的路线图上。

更底层的隐患在于可靠性。Lonewolf 目前没有流管理(XEP-0198),官方文档也写得很实在:中断的传输不会重发,服务器关闭时等待发送的消息会被直接丢弃。

  • 风险.现阶段把 Lonewolf 用于生产环境,不仅意味着裸奔聊天、不能建群、不能发图,在手机进电梯或服务端重启时还会静默丢消息。

别拿空载的 Rust 去比满载的 Erlang

每次有基础设施用 Rust 重写,社区里总会涌起一股性能狂热。这次 v0.3.0 把内置压测工具改名成了 lonewolfbench,虽宣称资源占用极低,但官方至今没有公布任何具体的吞吐量、延迟或内存跑分。

空载的极简骨架无法与满载三十万用户的成熟服务直接比跑分(示意图)
空载的极简骨架无法与满载三十万用户的成熟服务直接比跑分(示意图)

就算明天放出跑分,我也劝各位看客冷静。

《孙子兵法》讲“委积不多,非久战之计”。即时通讯服务端真正的性能泥潭,从来不是空载时转发几条纯文本 XML 流,而是重负载下的状态维护与读写放大:成百上千人群聊的消息扇出(MUC fan-out)、落盘归档(MAM)的密集写入、以及 PEP 节点海量的状态缓存。

老牌霸主 ejabberd 靠 Erlang/OTP 征战二十年,官方文档给出的基准参考是单台 16 GB 内存、4 核机器可稳扛 20 万至 30 万在线用户;中小社区首选的 Prosody 虽然用 Lua 写就,胜在模块生态极其成熟。Lonewolf 现在把归档、群聊、流管理这些吃内存又耗 I/O 的脏活累活全留白,拿着一个只做内存转发和轻量 redb 写入的空壳去跟全副武装的前辈比轻快,本身就不在一个维度上。

用 Rust 加上嵌入式 redb 重写 XMPP,真正的工程价值不在跑分高低,而在于降低自托管的运维心智。它把过去需要折腾运行时环境、配外部数据库、调几十个插件的繁琐流程,压进了一个开箱即用的静态二进制文件里。

按照路线图,Lonewolf 必须通过 2023 合规套件中的高级服务器认证,并跑通基于 PostgreSQL 的多节点集群,才算正式迈入 1.0。单二进制的骨架已经立起来了,接下来把 MAM 归档、PEP 加密支撑和流管理这一地鸡毛的扩展挨个啃下来,才是它真正上牌桌的时候。