☰
cjdns v13–v15 版本演进深度解析:从启动竞态修复到 DHT 搜索与 ETHInterface 重写
2026/10/6 2:23:56 网站建设 项目流程
  • 网络
  • 网络安全

【免费下载链接】cjdns

An encrypted IPv6 network using public-key cryptography for address allocation and a distributed hash table for routing.

项目地址:https://gitcode.com/gh_mirrors/cj/cjdns
点击查看免费下载

cjdns 是一个利用公钥加密分配 IPv6 地址、并以分布式哈希表(DHT)进行路由的加密 Mesh 网络实现。本文以仓库内 doc/cjdns/changelog.md 为骨架,逐条还原 2015 年 1 月 v13、v14、v15 三个滚动版本的变更全貌,并结合仓库源码(client/Configurator.c、dht/dhtcore/NodeStore.c、net/InterfaceController_admin.c、client/cjdroute2.c 等)验证每一条变更背后的真实实现。读完本文,你将掌握:cjdns 历史版本的启动流程竞态修复、ETHInterface 二层自动组网机制的演进、Admin API 认证策略的调整、DHT 搜索(SearchRunner)的引入,以及 NodeStore 路由选择策略的取舍逻辑。

一、文档定位:crashey 分支、master 滚动发布与 Version.h

changelog 开篇明确了 cjdns 的版本管理模型:

  • crashey 分支用于日常开发,处于不稳定状态;
  • master 分支是滚动发布(rolling release),即没有一个冻结的"正式版",master 上的代码本身就是交付物;
  • 每个版本条目都记录了crashey since:与master since:两个提交哈希及提交信息,方便追溯该版本内容的实际落地时间点。

文档特别提到 util/version/Version.h(当前仓库中对应文件为 util/version/Version.c 与 util/version/Version.h),版本号主要由它承载。文档记录的"当前状态"提交为5fa245c - remove check code (Tue Feb 3 23:25:10 2015 +0100),说明这份 changelog 撰写于 2015 年 2 月初,v13–v15 均集中于 2015 年 1 月,属于同一个月内高频迭代的产物——这也解释了为何三个版本之间存在明显的连续性:v14 修复 v13 引入的 Ethernet 校验和问题,v15 又修复了 v14 时代 peerStats 的段错误。

二、v15:启动竞态修复、工具链补全与 Admin API 免认证化

v15(2015 年 1 月末)是整个 changelog 中信息量最大的版本,涉及启动流程、构建优化、路由记忆、工具链与 Admin API 五个方面。

2.1 Configurator 启动前先 Ping 核心进程

原文档记载:

The configurator now tries to ping the core process before starting to configure it. This might fix a possible race condition during cjdroute startup.

该条目对应的源码实现可以在 client/Configurator.c 中找到完整的证据链:

  • tryPing()(L695-L706)通过 Admin RPC 调用ping函数,检查响应中的q字段是否为"pong";
  • waitUntilPong()(L720-L732)会循环最多 10 次,每次间隔 200ms(通过Timeout_setTimeout配合EventBase_beginLoop实现),直到收到 pong 为止;若 10 次全部失败,则触发Assert_failure("Failed connecting to core (perhaps you have a firewall on loopback device?)");
  • 最终在Configurator_config()(L734 起)的入口处调用waitUntilPong(&ctx)(L754),随后才继续注入authorizedPasswords、执行Security_setUser等配置步骤。

这意味着 v15 之前存在一种竞态:cjdroute 核心进程尚未在 Admin 端口(默认udp://localhost:11234)就绪时,Configurator 已开始写入配置,导致配置丢失或启动失败。v15 通过"先 ping、再配置"的握手机制消除了这一窗口期。

2.2 构建优化旗标与路由记忆

  • -Ocflag 修复:-O编译优化旗标此前无法正常设置,v15 起可传-O2(面向性能优化)或-Os(面向磁盘空间优化)。这属于构建系统 node_build/builder.js 与 node_build/make.js 所管辖的编译参数传递逻辑,适合嵌入式/低存储场景。
  • 记住最后已知路由:节点会尝试记住并复用前往某个节点的最后已知路径,而不是每次从头路由。这与 dht/dhtcore/NodeStore.c 中基于 label 的路径缓存机制相关,可减少重复寻路开销。
  • 短格式 IPv6 地址支持:工具与配置接受压缩书写形式的 IPv6 地址(如fc00::1风格),相关解析能力由 util/AddrTools.c 提供。

2.3 工具链迁移与新增

  • contrib/nodejs/tools/下的工具整体迁移到仓库根目录的 tools/,此后 cjdns 的运维工具统一收口在顶层tools/下;
  • 新增sessionStats 工具,用于查看会话统计;
  • ping 与 traceroute 工具支持解析 DNS 域名,不再只能输入 IPv6 地址;
  • 新增search 工具,且 DHT 搜索通过 Admin API 暴露为SearchRunner_search()。

SearchRunner_search()在源码中的注册位置为 dht/dhtcore/SearchRunner_admin.c,注册时auth参数为true(L161 的Admin_registerFunction("SearchRunner_search", search, ctx, true, ...)),即该操作仍需要认证——搜索属于可能泄露路由信息的敏感操作。

-c选项(设置搜索/ ping 次数)在两个工具的源码中均可找到:

  • tools/ping:解析-c参数作为maxCount,达到上限后停止输出;
  • tools/search:-c被解析为搜索次数上限,并传给cjdns.SearchRunner_search(target, count, handleMessage)。

2.4 Admin API 免认证化:NodeStore 查询开放

v15 规定NodeStore_nodeForAddr()与NodeStore_getLink()不再要求认证。源码证据在 dht/dhtcore/NodeStore_admin.c:

  • Admin_registerFunction("NodeStore_getLink", getLink, ctx, false, ...)(L338,false即免认证);
  • Admin_registerFunction("NodeStore_nodeForAddr", nodeForAddr, ctx, false, ...)(L343)。

这两者分别用于"根据 IPv6 地址查询节点"和"查询两个节点间的链路信息",本质是只读的路由表查询。将其开放给未经认证的调用方,是为了方便网络诊断工具(如 traceroute、pathfinderTree)无需携带密码即可工作。

三、v14:Hidden Peers 修复、ETHInterface 增强与 InterfaceController 重写

v14(2015 年 1 月中)的重点是二层组网稳定性和路由数据正确性。

3.1 Hidden Peers 与 getPeers 数据错误

  • Hidden Peers 问题:此前在 switch 层因 ping 被丢弃而导致 peerings 反复抖动(flapping),v14 修复了该问题。"Hidden Peers" 是指已建立对等关系但在路由表中不显式出现的节点,抖动会导致其连接状态不稳定;
  • NodeStore_getPeers() 修复:该函数此前总是返回相同的 peers,修复后每次调用能返回正确的、针对给定 label 的邻居列表。对应实现位于 dht/dhtcore/NodeStore.c,它会先按NumberCompress_bitsUsedForLabel()截断 label 再遍历PeerRBTree收集邻居。

3.2 ETHInterface:二层以太网自动组网

v14 对 interface/ETHInterface_linux.c(及 darwin 变体)做了三项关键增强:

  1. 绑定all接口:ETHInterface 可以绑定到all,即在所有网络接口上启用自动对等(auto-peering),从而对运行期间接口的上/下变动更具韧性——某个网口被拔掉或恢复时不会影响其他接口上的对等关系;
  2. 启动时自动 bring up 接口:ETHInterface 启动时会主动将相应网口置为 up 状态;
  3. switch ping 错误响应位对齐崩溃修复:switch ping 的错误响应在位对齐上存在问题,特定场景下会触发崩溃,v14 修复了该路径。

ETHInterface 的 auto-peering 机制是 cjdns 在同一局域网内零配置互联的关键:多个节点只需连接到同一台交换机(或同一 Wi-Fi),即能通过以太网帧自动发现并建立加密隧道,无需手工配置connectTo。这也是下一节 v13 中--eth生成配置开关的意义所在。

3.3 工具改进与接口控制器重构

  • ping 与 pingAll 工具改进:pingAll 现在同时执行 router ping 和 switch ping(switch ping 用于探测 switch 层的可达性与路径质量),配合 net/SwitchPinger.c 工作;
  • InterfaceController 重写:重写后的 net/InterfaceController.c 让自定义接口的开发更容易——接口控制器的职责是管理每个对等会话的密钥交换、加密状态与生命周期,重写后新增接口类型只需实现标准的事件回调即可接入;
  • 新增流量分析调试文档:即 doc/TrafficAnalysis.md,帮助开发者从流量特征角度调试网络行为。

四、v13:协议兼容断代、Ethernet 长度字段与路由策略注释

v13(2015 年 1 月初)包含一次明确的协议断代和多项基础修复,其中不少决策以源码注释的形式保留至今。

4.1 v11 及以下节点不再受支持

v13 起,运行 v11 及以下版本的节点:

  • 仍能与任何其他节点(包括 v13)建立对等连接;
  • 但从 v13 开始,它们的流量不再被 switch 转发;
  • 它们也不会再进入 v13 节点的路由表。

这是 cjdns 历史上的一次显式协议断代:旧版本节点被保留"能连通、不能路由"的过渡状态,避免瞬间全网分裂,同时推动全网升级。版本号与协议能力之间的对应关系由 util/version/Version.c 维护。

4.2 ETHInterface 线协议增加 payload 长度字段

v13 发现一个真实世界的问题:部分以太网适配器不会剥离发送方追加在报文末尾的校验和(checksum),导致解密器被混淆。修复方式是在 ETHInterface 的线协议中加入 payload 长度字段,使接收方能精确判定有效载荷边界,从而不受尾部校验和干扰。这也是 v14 中"位对齐崩溃修复"的相邻问题——两者都源于以太网帧边界处理。

4.3 NodeStore_getBest() 移除 DHT k-buckets 考量

v13 将 dht/dhtcore/NodeStore.c 中NodeStore_getBest()对 DHT k-buckets 的考量代码注释掉。changelog 引用了源码注释原文:

The network is small enough that a per-bucket lookup is inefficient Basically, the first bucket is likely to route through an "edge" node In theory, it scales better if the network is large.

也就是说:当时网络规模足够小,按桶(bucket)逐桶查找反而低效——第一个桶大概率会经由"边缘"节点绕路;理论上网络变大后按桶查找会更优,因此代码被保留为注释而非删除。当前 NodeStore.c#L1743-L1762 的实现印证了这一取舍:NodeStore_getBest()先尝试NodeStore_nodeForAddr()直接命中目标,若失败则通过getBestCycle()在 keyspace 中寻找更近的合法下一跳,循环上限 10000 次,并不涉及按桶划分的查找。

这是一个值得细读的工程决策案例:当理论最优算法与当前网络规模不匹配时,先以注释形式保留理论、以实际规模为准选择实现。

4.4 Admin API 与配置生成的新能力

  • InterfaceController_peerStats()现在返回 peer 的protocolVersion字段,且不再要求认证。源码证据:net/InterfaceController_admin.c 中Admin_registerFunction("InterfaceController_peerStats", adminPeerStats, ctx, false, ...)。结合 contrib/doc/peerStats.md 可以理解该输出的字段含义——protocolVersion是判断对端是否还能路由流量(即是否 ≥ v13)的关键指标;
  • cjdroute --genconf新增--eth开关,用于启用 ETHInterface 并打开自动对等。源码证据在 client/cjdroute2.c(帮助文本)与 L645-L646(--eth参数解析后传入genconf(allocator, rand, eth, ...))。生成配置中 ETHInterface 段默认以_disabled_前缀注释,只有加--eth才会生成激活版本(client/cjdroute2.c#L215-L216);
  • 新增脚本 contrib/bash/peers.sh:peers.sh user user@example.net <user's ipv6>,一次性把对等密码同时写入配置文件与运行中的进程,免去重启才能生效的旧流程;
  • Android 的若干小修复;支持在 macOS 主机上为 ARM 交叉编译(对应 cross-do 与 android_do 脚本);contrib/ 下的文档与脚本整体改进。

五、三个版本的演进脉络总结

将 v13–v15 放在一起看,可以提炼出四条清晰的演进主线,这也是 changelog 最值得深挖的资产:

主线v13v14v15佐证源码
启动/配置可靠性——Configurator 先 ping 核心再配置client/Configurator.c
二层以太网组网线协议加 payload 长度绑定 all、启动 bring up、位对齐崩溃修复auto-peering bug 修复interface/ETHInterface_linux.c、client/cjdroute2.c
Admin API 开放策略peerStats 免认证并含 protocolVersion—nodeForAddr/getLink 免认证;SearchRunner_search 仍需认证net/InterfaceController_admin.c、dht/dhtcore/NodeStore_admin.c、dht/dhtcore/SearchRunner_admin.c
路由选择getBest 不再按 k-buckets 查找getPeers 返回错误修复、记住最后已知路由短格式 IPv6、search/sessionStats 工具dht/dhtcore/NodeStore.c、tools/search

5.1 Admin API 的认证边界设计

值得单独强调的是:v13–v15 并非简单"放开一切"。三个版本开放的InterfaceController_peerStats、NodeStore_nodeForAddr、NodeStore_getLink都是只读的诊断类查询,而会触发路由搜索行为的SearchRunner_search()始终要求认证。这种"读开放、写与搜索封闭"的边界,至今仍是 cjdns Admin API 的设计基调,读者在 doc/admin-api.md 与各*_admin.c文件的Admin_registerFunction调用中可逐一核对每个函数的auth参数。

5.2 工具链的沉淀

从 v13 引入 traceroute/cjdnslog,到 v15 把工具迁入根目录 tools/ 并加入 sessionStats、DNS 解析与-c次数控制,cjdns 的运维工具集在这一时期完成了从散落到统一的收口。如今 tools/ 下的 ping、search、traceroute、sessionStats、peerStats 等脚本仍可直接运行,配合 contrib/python3/cjdnsadmin 与 tools/lib/cjdnsadmin 客户端库使用。

六、如何在当前仓库中进一步验证

  • 版本常量:util/version/Version.c 与 util/version/Version.h 承载协议版本号,配合NodeStore_getPeers、peerStats输出中的protocolVersion理解协议断代;
  • Admin 函数注册清单:在dht/dhtcore/、net/、interface/下搜索Admin_registerFunction,可逐条核对每个 API 的认证要求与参数签名;
  • 构建与交叉编译:do、cross-do、android_do 对应 v13 提到的 macOS→ARM 交叉编译能力;-O2/-Os的编译旗标传递逻辑在 node_build/builder.js;
  • 工具脚本:tools/ping、tools/search、tools/traceroute、tools/sessionStats 可直接阅读-c、DNS 解析等 v15 特性的实现;
  • 以太网自动组网:interface/ETHInterface_linux.c 与 interface/ETHInterface_darwin.c 是 v14 各项 ETHInterface 增强的落点,--eth生成的配置格式见 client/cjdroute2.c。

结语

cjdns 的 v13–v15 是一个典型的"高速迭代 + 显式断代"窗口:一个月内完成了启动竞态修复、二层自动组网加固、路由数据正确性修复、协议版本断代、Admin API 认证边界调整与运维工具链统一。阅读 doc/cjdns/changelog.md 的价值在于,它不仅是变更清单,更是一份浓缩的架构决策记录——尤其是NodeStore_getBest()中"理论留注释、实现随规模"的取舍,以及"诊断接口免认证、搜索接口需认证"的 API 安全边界,这些决策思路对今天构建去中心化网络系统仍有直接借鉴意义。

  • 网络
  • 网络安全

【免费下载链接】cjdns

An encrypted IPv6 network using public-key cryptography for address allocation and a distributed hash table for routing.

项目地址:https://gitcode.com/gh_mirrors/cj/cjdns
点击查看免费下载

相关推荐

上一篇:二分查找的底层逻辑:解空间、有序性与"折半"中心思想
下一篇:英雄联盟录像编辑完全指南:用免费开源工具打造专业游戏视频

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询