Communitygithub.com

voluminor/skill-yggdrasil

用于在 Go 中构建 Yggdrasil 网状网络应用的智能体技能(通过 ratatoskr 库):嵌入客户端、HTTP/TCP/UDP 服务器、SOCKS5、端口转发、对等节点管理、NodeInfo 符号 — 用户态,无需 TUN 或 root 权限。

skill-yggdrasil 是什么?

该技能旨在帮助开发者使用 Go 语言和 ratatoskr 库构建 Yggdrasil 端到端加密 IPv6 网状网络应用。它支持嵌入节点、HTTP/TCP/UDP 服务器、SOCKS5 代理、端口转发以及通过 NodeInfo 和符号发布发现元数据。节点完全运行在用户态(基于 gVisor netstack),无需 TUN 设备、root 权限或外部 yggdrasil 守护进程。应用通过标准的 Go 接口(如 net.Conn、net.Listener、http.Transport)进行通信,并使用 ratatoskr.New 创建节点。该技能特别强调在受限网状网络上设计应用:必须处理高延迟、低带宽、丢包和间歇性连接,建议使用上下文超时、限制并发、分块传输并添加重试退避策略。适用于 Claude Code、Cursor 等 AI 编码智能体,提供详细的参考文档、常见错误列表和标准工作流程指导。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add voluminor/skill-yggdrasil

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

在 Go 中实现 Yggdrasil 网络编程

概述

使用此技能构建连接到 Yggdrasil 端到端加密 IPv6 网状网络并提供服务的 Go 程序:客户端、HTTP/TCP/UDP 服务器、SOCKS5 代理、端口转发器以及发布发现元数据的节点。节点在 用户态 基于 gVisor netstack 运行 — 无需 TUN 设备、无需 root 权限、无需外部 yggdrasil 守护进程,也无需 yggstack 二进制文件。您可以使用标准的 Go 接口(net.Conn、net.Listener、net.PacketConn、http.Transport)通过 Yggdrasil 进行拨号和监听。

嵌入库为 github.com/voluminor/ratatoskr:使用 ratatoskr.New 创建节点,并通过其 Go API 驱动一切。其包的范围和稳定性总结如下。

针对受限网状网络的设计

Yggdrasil 是一个端到端加密的覆盖 网状网,而不是数据中心架构。链路存在高延迟、低带宽、丢包和间歇性特点;当前可达的对等节点下一秒可能消失,流量可能经过多跳。每一个 Yggdrasil 方案都应按照针对弱、不稳定连接来构建。这不是可选的优化 — 这是这里正确代码的默认形态。

  • 绝无无界操作。 为每个拨号和请求设置截止时间(context.WithTimeout);限制重试次数;限制队列大小。绝无无限等待。
  • 限制并发。 限制在途工作:SOCKS 的 MaxConnections、转发的 SetMaxUDPSessions、http.Transport.MaxConnsPerHost/MaxIdleConnsPerHost,以及您自己的工作池。两者默认都是 无限制 — 请设置实际限制。
  • 分块传输大文件,验证并支持断点续传。 绝不在一次操作中传输大文件。拆分为小分块(例如 HTTP Range),验证每个分块(大小/校验和),并使其可续传,这样连接断开时仅损失一个分块,而非整个传输。
  • 使用退避 + 抖动进行幂等重试。 预期操作过程中可能断开。使操作可续传/幂等;使用带抖动的指数退避;限制重试次数。
  • 保持有效载荷较小。 避免高频率协议和轮询;进行压缩;使用紧凑的编码格式。保持 NodeInfo/符号远低于 16 KB 的限制。
  • 根据链路调整缓冲区大小。 使用 node.MTU() 获取数据包缓冲区大小(用户态 MTU 是动态的,最低为 1280)。
  • 优雅降级,不要猛攻。 失败时退避并返回部分结果;绝不对对等节点进行激进重试或向网络洪泛。

一个简单的 "通过 net/http 提供大文件服务" 或 "单次大请求/响应" 是错误的形态。正确的形态是默认有界、分块、可续传、容错的。请参阅 references/integrations.md 中的受限网状传输模式。

事实来源

活跃模块是权威来源 — 而不是内存、过时的 README 文本或此技能。在编写特定版本的指导之前,检查项目实际依赖的内容:

go list -m github.com/voluminor/ratatoskr   # 选定的版本
go doc github.com/voluminor/ratatoskr       # 编译时的根 API
go doc github.com/voluminor/ratatoskr/mod/peermgr ConfigObj

要读取选定版本的实际源代码,请从模块缓存中解析其路径,而不是猜测路径:

go list -m -f '{{.Dir}}' github.com/voluminor/ratatoskr

不要从 README 文本中固定最低 Go 版本 — 它可能落后于 go.mod 指令。请读取选定 Ratatoskr 版本的活跃 go.mod。

默认工作流程

  1. 确定应用形态:嵌入节点、HTTP 客户端/服务器、原始 TCP/UDP、SOCKS5、端口转发、对等节点管理,或 NodeInfo/符号。
  2. 对于应用,使用根包 github.com/voluminor/ratatoskr。仅通过 core.Interface 契约进入 mod/core;除非底层包确实需要,否则避免使用 *core.Obj/UnsafeCore()。
  3. 拥有一个 context.Context,将其作为 ratatoskr.ConfigObj.Ctx 传递,并且在成功启动后仍然使用 defer node.Close()。两者都是必需的。
  4. 在恰好一个地方配置对等节点:
    • 静态 Yggdrasil 对等节点:cfg.Config.Peers
    • Ratatoskr 对等节点管理器:ratatoskr.ConfigObj.Peers(然后将 cfg.Config.Peers 留空,否则 New 将返回 ErrPeersConflict)。
  5. 使用 node.DialContext 进行出站 TCP/UDP 连接,使用 node.Listen / node.ListenPacket 在 Yggdrasil 内部提供服务。
  6. 在 URL 和主机-端口字符串中使用方括号括起 IPv6 地址:http://[200:abcd::1]:8080,绝不要使用 http://200:abcd::1:8080。
  7. 将链路视为弱连接:为每个调用设置截止时间,限制并发,并对大传输进行分块/验证/续传(请参阅“针对受限网状网络的设计”)。
  8. 当您将代码生成到实际项目中时,添加编译检查或针对性测试,而不是假设它能构建。

模块范围与稳定性

Yggdrasil 地址从节点密钥派生,因此网络表面小且稳定。优先使用库视为已完成的部分;明确标记其余部分,而不是在其上构建。

包状态通过其使用
根包 ratatoskr稳定,主要 APINew、EnableSOCKS、Ask/AskAddr、Snapshot、Close
mod/core稳定契约嵌入在节点上的 core.Interface 方法
mod/peermgr稳定ratatoskr.ConfigObj.Peers
mod/socks稳定node.EnableSOCKS(不要直接实例化)
mod/resolver稳定由 EnableSOCKS 自动创建;直接使用属高级用法
mod/forward稳定forward.New → Add* → Start
mod/sigils(+ info、services、public、inet)稳定ratatoskr.ConfigObj.Sigils
mod/ninfo稳定node.Ask / node.AskAddr
mod/probe高级/不稳定 — 需要 UnsafeCore(),API 可能变更仅在明确需要拓扑/路由追踪时使用
mod/settings进行中 — 架构未最终确定避免使用;直接使用 yggdrasil-go/src/config
cmd/*示例应用,不可导入的库 API作为模式阅读,切勿导入

根包与子模块: 默认使用 ratatoskr.New(核心 + SOCKS + 对等节点管理器 + ninfo + 符号,通过一个 Close 管理)。仅在需要最小表面(原始拨号/监听)时通过 core.New 降级到 mod/core,或围绕 core.Interface 组合子模块以用于自定义传输和测试。每个子模块(peermgr/socks/forward/resolver/ninfo)都接受一个 core.Interface。请参阅 references/overview.md。

系统符号 — 优先在此发布

NodeInfo 是节点向网络描述自身的方式。每个节点都会自动解析四种 内置(“系统”)符号,因此您放入其中的数据会被其他参与者识别。在发明自定义符号之前,优先使用这些符号;通过 ratatoskr.ConfigObj.Sigils 传递它们。保持每个符号非常小 — 它们共享一个 16 KB 的 NodeInfo 预算。

符号属于此处的内容为什么使用它
info节点身份:名称、类型、位置、联系人、描述让其他人知道您的节点是什么。
services您在 Yggdrasil 内部暴露的端口,格式为 name → port无需端口扫描即可进行服务发现。
public您按网络分组的公共对等连接 URI让其他人直接与您对等连接。
inet您的现实世界地址(域名/IP)将您的 Yggdrasil 节点映射到明文网络身份。

将可发现的、标准的数据放入这些符号中,以便 整个网络 都能读取。仅为这四个符号都不涵盖的数据定义自定义符号 — 并记住只有运行您代码的对等节点才会解析它。构造函数会进行验证并返回错误;在 ratatoskr.New 之前处理它们。详细信息、精确限制、类型化访问和自定义符号编写:请参阅 references/nodeinfo-sigils.md 和 references/custom-sigils.md。

参考地图

仅读取当前任务所需的文件:

常见错误

错误更正
为嵌入应用启动外部 Yggdrasil 守护进程使用 ratatoskr.New;它运行用户态 gVisor netstack。
推荐 yggstack 用于库集成yggstack 是最终用户二进制文件。对于 Go API 控制,请使用 Ratatoskr。
同时设置 cfg.Config.Peers 和 ConfigObj.Peers选择静态对等节点或对等节点管理器;绝不能同时设置 → ErrPeersConflict。
传递 Ctx 但跳过 Close(或反之)两者都执行:取消触发关闭,Close 释放资源。
构建没有 IPv6 方括号的 URL使用 fmt.Sprintf("http://[%s]:%d", ip, port)。
为基本查询创建 ninfo.New使用 node.Ask / node.AskAddr;根对象已构建 ninfo。
在运行时动态组装或注册符号符号 严格在代码中 组装;重复或覆盖键在设计中是硬错误,而非静默合并。通过 ConfigObj.Sigils 发布;从 res.Node.Extra 读取您自己的键。
默认就使用 UnsafeCore() / mod/probe / mod/settings保持在根 API 上;这些是高级或进行中的功能。
从 README 硬编码 Go 版本读取选定模块版本的活跃 go.mod。

验证

保持 SKILL.md 作为导航层,将详细的 API 信息放在 references/ 中。在发布前,根据 evals/evals.json 中的场景对更改进行前向测试。

相关技能