Yggdrasil-Netzwerke in Go
Überblick
Nutzen Sie diese Fähigkeit, um Go-Programme zu erstellen, die sich mit dem Yggdrasil-Ende-zu-Ende-verschlüsselten IPv6-Mesh verbinden und darauf Dienste anbieten: Clients, HTTP/TCP/UDP-Server, SOCKS5-Proxys, Portweiterleitungen und Knoten, die Erkennungsmetadaten veröffentlichen. Der Knoten läuft im Userspace auf einem gVisor-Netstack – kein TUN-Gerät, kein Root, kein externer yggdrasil-Daemon und keine yggstack-Binärdatei. Sie verbinden sich über Yggdrasil mit den standardmäßigen Go-Interfaces (net.Conn, net.Listener, net.PacketConn, http.Transport) und hören darauf.
Die eingebettete Bibliothek ist github.com/voluminor/ratatoskr: Erstellen Sie den Knoten mit ratatoskr.New und steuern Sie alles über die Go-API. Umfang und Stabilität ihrer Pakete sind unten zusammengefasst.
Design für ein beschränktes Mesh
Yggdrasil ist ein Ende-zu-Ende-verschlüsseltes Overlay-Mesh, kein Rechenzentrumsnetzwerk. Verbindungen haben hohe Latenz, geringe Bandbreite, sind verlustbehaftet und unbeständig; ein Peer, der jetzt erreichbar ist, kann eine Sekunde später verschwunden sein, und Datenverkehr kann viele Hops durchlaufen. Bauen Sie jede Yggdrasil-Lösung so, als wäre sie für eine schwache, instabile Verbindung. Dies ist keine optionale Verfeinerung – es ist die Standardform korrekten Codes hier.
- Nie unbegrenzt. Ein Timeout für jeden Verbindungsaufbau und jede Anfrage (
context.WithTimeout); begrenzte Wiederholungsversuche; begrenzte Warteschlangen. Keine unendlichen Warteschleifen. - Parallelität begrenzen. Begrenzen Sie gleichzeitige Arbeiten: SOCKS
MaxConnections,forward.SetMaxUDPSessions,http.Transport.MaxConnsPerHost/MaxIdleConnsPerHost, Ihre eigenen Worker-Pools. Beide Standardwerte sind unbegrenzt – setzen Sie dauerhafte Grenzen. - Große Übertragungen in Chunks aufteilen, verifizieren, fortsetzen. Verschieben Sie niemals eine große Datei auf einmal. Teilen Sie sie in kleine Blöcke auf (z.B. HTTP
Range), verifizieren Sie jeden (Größe/Prüfsumme) und machen Sie ihn fortsetzbar, sodass eine unterbrochene Verbindung nur einen Block kostet, nicht die gesamte Übertragung. - Idempotent mit Backoff und Jitter wiederholen. Erwarten Sie Unterbrechungen während eines Vorgangs. Machen Sie Vorgänge fortsetzbar/idempotent; exponentieller Backoff mit Jitter; begrenzen Sie die Wiederholungsversuche.
- Nachrichten klein halten. Vermeiden Sie gesprächige Protokolle und Polling; komprimieren Sie; verwenden Sie kompakte Kodierungen. Halten Sie NodeInfo/Sigils deutlich unter dem 16-KB-Limit.
- Puffer an die Verbindung anpassen. Verwenden Sie
node.MTU()für Paketpuffer (Userspace-MTU ist dynamisch, minimal 1280). - Herunterfahren, nicht hämmern. Bei Fehlern zurückziehen und Teilergebnisse liefern; niemals einen Peer aggressiv wiederholen oder das Mesh überfluten.
Ein naiver Ansatz wie „eine große Datei über net/http bereitstellen“ oder „eine riesige Anfrage/Antwort“ ist die falsche Form. Die richtige Form ist begrenzt, in Chunks aufgeteilt, fortsetzbar und standardmäßig fehlertolerant. Siehe das Übertragungsmuster für ein beschränktes Mesh in references/integrations.md.
Quelle der Wahrheit
Das aktive Modul ist maßgeblich – nicht der Speicher, nicht veralteter README-Text, nicht diese Fähigkeit. Bevor Sie versionsspezifische Anleitungen geben, prüfen Sie, wovon das Projekt tatsächlich abhängt:
go list -m github.com/voluminor/ratatoskr # ausgewählte Version
go doc github.com/voluminor/ratatoskr # kompilierte Root-API
go doc github.com/voluminor/ratatoskr/mod/peermgr ConfigObj
Um den tatsächlichen Quellcode der ausgewählten Version zu lesen, lösen Sie ihn aus dem Modul-Cache auf, anstatt einen Pfad zu raten:
go list -m -f '{{.Dir}}' github.com/voluminor/ratatoskr
Frieren Sie die minimale Go-Version nicht aus README-Text ein – sie kann hinter der go.mod-Direktive zurückbleiben. Lesen Sie die aktive go.mod der ausgewählten Ratatoskr-Version.
Standard-Workflow
- Identifizieren Sie die Anwendungsform: eingebetteter Knoten, HTTP-Client/Server, reines TCP/UDP, SOCKS5, Portweiterleitung, Peerverwaltung oder NodeInfo/Sigils.
- Verwenden Sie das Root-Paket
github.com/voluminor/ratatoskrfür Anwendungen. Greifen Sie nur über dencore.Interface-Vertrag aufmod/corezu; vermeiden Sie*core.Obj/UnsafeCore(), es sei denn, ein Low-Level-Paket erfordert es tatsächlich. - Besitzen Sie einen
context.Context, übergeben Sie ihn alsratatoskr.ConfigObj.Ctx, und führen Sie nach erfolgreichem Start dennochdefer node.Close()aus. Beide sind erforderlich. - Konfigurieren Sie Peers an genau einer Stelle:
- Statische Yggdrasil-Peers:
cfg.Config.Peers - Ratatoskr-Peermanager:
ratatoskr.ConfigObj.Peers(danncfg.Config.Peersleer lassen, sonst gibtNewErrPeersConflictzurück).
- Statische Yggdrasil-Peers:
- Verwenden Sie
node.DialContextfür ausgehende TCP/UDP-Verbindungen undnode.Listen/node.ListenPacketfür Dienste innerhalb von Yggdrasil. - Setzen Sie IPv6-Adressen in URLs und Host-Port-Strings in eckige Klammern:
http://[200:abcd::1]:8080, niemalshttp://200:abcd::1:8080. - Behandeln Sie die Verbindung als schwach: setzen Sie ein Timeout für jeden Aufruf, begrenzen Sie die Parallelität und teilen Sie große Übertragungen auf/verifizieren/setzen Sie sie fort (siehe Design für ein beschränktes Mesh).
- Wenn Sie Code in ein reales Projekt generieren, fügen Sie eine Compile-Prüfung oder einen gezielten Test hinzu, anstatt anzunehmen, dass es kompiliert.
Modulumfang und -stabilität
Yggdrasil-Adressen werden aus dem Knotenschlüssel abgeleitet, daher ist die Netzwerkoberfläche klein und stabil. Bevorzugen Sie die Teile, die die Bibliothek als fertig betrachtet; kennzeichnen Sie den Rest explizit, anstatt darauf aufzubauen.
| Paket | Status | Nutzung über |
|---|---|---|
Root ratatoskr | Stabil, primäre API | New, EnableSOCKS, Ask/AskAddr, Snapshot, Close |
mod/core | Stabiler Vertrag | die core.Interface-Methoden, die auf dem Knoten eingebettet sind |
mod/peermgr | Stabil | ratatoskr.ConfigObj.Peers |
mod/socks | Stabil | node.EnableSOCKS (nicht direkt instanziieren) |
mod/resolver | Stabil | wird automatisch von EnableSOCKS erstellt; direkte Verwendung ist fortgeschritten |
mod/forward | Stabil | forward.New → Add* → Start |
mod/sigils (+ info, services, public, inet) | Stabil | ratatoskr.ConfigObj.Sigils |
mod/ninfo | Stabil | node.Ask / node.AskAddr |
mod/probe | Fortgeschritten / instabil – erfordert UnsafeCore(), API kann sich ändern | nur, wenn Topologie-/Routenverfolgung explizit erforderlich ist |
mod/settings | In Arbeit – Schema nicht abgeschlossen | vermeiden; stattdessen yggdrasil-go/src/config direkt verwenden |
cmd/* | Beispiel-Apps, keine importierbare Bibliotheks-API | als Muster lesen, niemals importieren |
Root vs. Submodule: Standardmäßig ratatoskr.New verwenden (core + SOCKS + Peermanager + ninfo + sigils hinter einem Close). Nur für die kleinste Oberfläche (reines Dial/Listen) auf mod/core über core.New zurückgreifen oder Submodule um core.Interface für benutzerdefinierte Transports und Tests zusammenstellen. Jedes Submodul (peermgr/socks/forward/resolver/ninfo) nimmt einen core.Interface entgegen. Siehe references/overview.md.
System-Sigils – hier zuerst veröffentlichen
NodeInfo ist die Art und Weise, wie ein Knoten sich selbst im Netzwerk beschreibt. Vier eingebaute („System-“) Sigils werden automatisch von jedem Knoten geparst, sodass Daten, die Sie dort ablegen, von anderen Teilnehmern erkannt werden. Greifen Sie zu diesen, bevor Sie ein benutzerdefiniertes Sigil erfinden; übergeben Sie sie über ratatoskr.ConfigObj.Sigils. Halten Sie jedes klein – sie teilen sich ein Budget von 16 KB NodeInfo.
| Sigil | Was hier hingehört | Warum es verwenden |
|---|---|---|
info | Knotenidentität: Name, Typ, Standort, Kontakte, Beschreibung | Ermöglicht anderen zu wissen, wer/was Ihr Knoten ist. |
services | Ports, die Sie innerhalb von Yggdrasil bereitstellen, als name → port | Dienstentdeckung ohne Port-Scanning. |
public | Ihre öffentlichen Peering-URIs, gruppiert nach Netzwerk | Ermöglicht anderen, direkt mit Ihnen zu peeren. |
inet | Ihre realen Adressen (Domains/IPs) | Ordnet Ihren Yggdrasil-Knoten einer Identität im Klarnetz zu. |
Legen Sie auffindbare, standardisierte Daten in diese Sigils ab, damit das gesamte Netzwerk sie lesen kann. Definieren Sie nur dann ein benutzerdefiniertes Sigil, wenn keines der vier die Daten abdeckt – und denken Sie daran, dass nur Peers, die Ihren Code ausführen, es parsen. Konstruktoren validieren und geben Fehler zurück; behandeln Sie diese vor ratatoskr.New. Details, genaue Grenzen, typisierter Zugriff und Erstellung benutzerdefinierter Sigils: references/nodeinfo-sigils.md und references/custom-sigils.md.
Referenzkarte
Lesen Sie nur die Dateien, die für die aktuelle Aufgabe benötigt werden:
- Grundlagen eingebetteter Knoten, Ratatoskr vs. yggstack, Architektur, Umfang: references/overview.md
ratatoskr.New,ConfigObj, Lebenszyklus, Thread-Sicherheit, Root-Methoden, Fehler, Snapshot: references/root-api.md- TCP, UDP,
DialContext,Listen,ListenPacket, HTTP-Client/Server, Multicast/Admin, Testnähte: references/networking.md - Statische Peers, Peermanager, SOCKS5, Resolver, Portweiterleitung: references/peers-socks-forwarding.md
- NodeInfo,
Ask/AskAddr, eingebaute Sigils mit genauen Grenzen: references/nodeinfo-sigils.md - Typisierter Zugriff und Erstellung/Verdrahtung eigener Sigils (kein rohes
map[string]any): references/custom-sigils.md - Client/Server-Vorlagen und Framework-Integrationen (net/http, fasthttp, gRPC, gnet-Brücke): references/integrations.md
- Fortgeschrittene/In-Arbeit-Bereiche (probe, settings) und CLI/Beispiel-App-Muster: references/advanced-and-examples.md
- Fertige, anpassbare Anwendungsrezepte: references/recipes.md
Häufige Fehler
| Fehler | Korrektur |
|---|---|
| Starten eines externen Yggdrasil-Daemons für eine eingebettete App | Verwenden Sie ratatoskr.New; es läuft ein Userspace-gVisor-Netstack. |
Empfehlen von yggstack für die Bibliotheksintegration | yggstack ist eine Endbenutzer-Binärdatei. Verwenden Sie Ratatoskr für die Go-API-Steuerung. |
Setzen von sowohl cfg.Config.Peers als auch ConfigObj.Peers | Wählen Sie statische Peers oder den Peermanager; niemals beide → ErrPeersConflict. |
Übergeben von Ctx aber Auslassen von Close (oder umgekehrt) | Führen Sie beides aus: Abbruch löst Herunterfahren aus, Close gibt Ressourcen frei. |
| Erstellen von URLs ohne IPv6-Klammern | Verwenden Sie fmt.Sprintf("http://[%s]:%d", ip, port). |
Erstellen von ninfo.New für einfache Abfragen | Verwenden Sie node.Ask / node.AskAddr; das Root-Objekt baut bereits ninfo. |
| Dynamisches Zusammenstellen oder Registrieren von Sigils zur Laufzeit | Sigils werden streng im Code zusammengestellt; doppelte oder überschreibende Schlüssel sind harte Fehler, kein stilles Zusammenführen. Veröffentlichen Sie über ConfigObj.Sigils; lesen Sie Ihre eigenen Schlüssel aus res.Node.Extra. |
Standardmäßig nach UnsafeCore() / mod/probe / mod/settings greifen | Bleiben Sie bei der Root-API; diese sind fortgeschritten oder in Arbeit. |
| Hartcodieren einer Go-Version aus README | Lesen Sie die aktive go.mod der ausgewählten Modulversion. |
Validierung
Behalten Sie SKILL.md als Navigationsebene und legen Sie schwere API-Details in references/. Testen Sie Änderungen vor der Veröffentlichung gegen die Szenarien in evals/evals.json.