在 Go 語言中進行 Yggdrasil 網路程式設計
概覽
使用此技能來建構能連接並服務於 Yggdrasil 端對端加密 IPv6 網狀網路的 Go 程式:客戶端、HTTP/TCP/UDP 伺服器、SOCKS5 代理、連接埠轉發器,以及發佈探索元資料的節點。該節點 在使用者空間 的 gVisor 網路堆疊上執行 — 無需 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/sigils 遠低於 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。
預設工作流程
- 確定應用程式的形態:嵌入式節點、HTTP 客戶端/伺服器、原始 TCP/UDP、SOCKS5、連接埠轉發、對等節點管理或 NodeInfo/sigils。
- 對應用程式使用根套件
github.com/voluminor/ratatoskr。僅透過core.Interface合約進入mod/core;除非底層套件確實需要,否則避免使用*core.Obj/UnsafeCore()。 - 擁有一個
context.Context,將其作為ratatoskr.ConfigObj.Ctx傳遞,並且 在成功啟動後仍需defer node.Close()。兩者都是必需的。 - 僅在一個地方設定對等節點:
- 靜態 Yggdrasil 對等節點:
cfg.Config.Peers - Ratatoskr 對等節點管理器:
ratatoskr.ConfigObj.Peers(然後將cfg.Config.Peers留空,否則New會返回ErrPeersConflict)。
- 靜態 Yggdrasil 對等節點:
- 對於出站 TCP/UDP 使用
node.DialContext,對於在 Yggdrasil 內的服務使用node.Listen/node.ListenPacket。 - 在 URL 和主機-連接埠字串中將 IPv6 位址用方括號括起來:
http://[200:abcd::1]:8080,絕不要使用http://200:abcd::1:8080。 - 將鏈路視為弱連線:對每次呼叫設定截止時間、限制並發性,並對大型傳輸進行分塊/驗證/續傳(參閱針對受限網狀網路的設計)。
- 當您將程式碼生成到實際專案中時,請添加編譯檢查或重點測試,而不是假設它可以構建。
模組範圍與穩定性
Yggdrasil 位址是從節點金鑰派生而來的,因此網路表面很小且穩定。優先使用函式庫視為已完成的部分;明確標記其餘部分,而不是在其上構建。
| 套件 | 狀態 | 使用方式 |
|---|---|---|
根 ratatoskr | 穩定,主要 API | New, 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 | 作為模式閱讀,絕不匯入 |
根套件 vs 子模組: 預設使用 ratatoskr.New(透過一個 Close 整合核心 + SOCKS + 對等節點管理器 + ninfo + sigils)。僅在需要最小表面(原始撥號/監聽)時降級使用 mod/core 的 core.New,或者為了自訂傳輸和測試而圍繞 core.Interface 組合子模組。每個子模組(peermgr/socks/forward/resolver/ninfo)都接受一個 core.Interface。請參閱 references/overview.md。
系統 Sigils — 優先在此發佈
NodeInfo 是節點向網路描述自身的方式。四個內建(「系統」)sigils 會被每個節點自動解析,因此您放入其中的資料會被其他參與者識別。在發明自訂 sigil 之前,請優先使用這些;透過 ratatoskr.ConfigObj.Sigils 傳遞它們。保持每個 sigil 很小 — 它們共享一個 16 KB 的 NodeInfo 預算。
| Sigil | 此處應放置的內容 | 為何使用它 |
|---|---|---|
info | 節點身分:名稱、類型、位置、聯絡方式、描述 | 讓其他人知道您的節點是什麼 / 是誰。 |
services | 您在 Yggdrasil 內部暴露的連接埠,格式為 名稱 → 連接埠 | 無需連接埠掃描即可進行服務發現。 |
public | 您的公開對等 URIs,按網路分組 | 讓其他人可以直接與您對等連接。 |
inet | 您的真實世界位址(網域名稱/IPs) | 將您的 Yggdrasil 節點映射到明網身分。 |
將可被發現的、標準的資料放入這些 sigils 中,以便整個網路都能讀取。僅為那些四個 sigils 都未涵蓋的資料定義自訂 sigil — 並且請記住,只有執行您程式碼的對等節點才能解析它。建構函式會進行驗證並返回錯誤;請在 ratatoskr.New 之前處理它們。詳細資訊、確切限制、型別化存取以及自訂 sigil 的編寫:請參閱 references/nodeinfo-sigils.md 和 references/custom-sigils.md。
參考資料映射
僅讀取當前任務所需的檔案:
- 嵌入式節點基礎知識、Ratatoskr vs yggstack、架構、範圍: references/overview.md
ratatoskr.New、ConfigObj、生命週期、執行緒安全、根方法、錯誤、快照: references/root-api.md- TCP、UDP、
DialContext、Listen、ListenPacket、HTTP 客戶端/伺服器、多播/管理、測試縫隙: references/networking.md - 靜態對等節點、對等節點管理器、SOCKS5、解析器、連接埠轉發: references/peers-socks-forwarding.md
- NodeInfo、
Ask/AskAddr、帶有確切限制的內建 sigils: references/nodeinfo-sigils.md - 型別化存取以及編寫/接線您自己的 sigils(無原始
map[string]any): references/custom-sigils.md - 客戶端/伺服器模板和框架整合(net/http、fasthttp、gRPC、gnet bridge): references/integrations.md
- 進階/進行中區域(probe、settings)和 CLI/範例應用模式: references/advanced-and-examples.md
- 可直接調整的應用程式配方: references/recipes.md
常見錯誤
| 錯誤 | 修正方法 |
|---|---|
| 為嵌入式應用啟動外部 Yggdrasil 守護行程 | 使用 ratatoskr.New;它會執行一個使用者空間的 gVisor 網路堆疊。 |
為函式庫整合推薦 yggstack | yggstack 是一個終端使用者二進位檔。對於 Go API 控制,請使用 Ratatoskr。 |
同時設定 cfg.Config.Peers 和 ConfigObj.Peers | 選擇靜態對等節點或對等節點管理器;絕不要兩者都設定 → ErrPeersConflict。 |
傳遞了 Ctx 但跳過了 Close(或反之亦然) | 兩者都要做:取消會觸發關閉,Close 會釋放資源。 |
| 建構 URL 時未使用 IPv6 方括號 | 使用 fmt.Sprintf("http://[%s]:%d", ip, port)。 |
為基本查詢建立 ninfo.New | 使用 node.Ask / node.AskAddr;根物件已構建了 ninfo。 |
| 在執行時期動態組裝或註冊 sigils | Sigils 嚴格在程式碼中被組裝;重複或覆蓋鍵(keys)是設計上的硬錯誤,而非靜默合併。透過 ConfigObj.Sigils 發佈;從 res.Node.Extra 讀取您自己的鍵。 |
預設就使用 UnsafeCore() / mod/probe / mod/settings | 停留在根 API;這些是進階或進行中的功能。 |
| 從 README 硬編碼 Go 版本 | 讀取所選模組版本的活躍 go.mod。 |
驗證
將 SKILL.md 保留為導航層,並將大量 API 細節放在 references/ 中。在發佈前,請針對 evals/evals.json 中的場景對變更進行前瞻性測試。