ratatoskr @ v1.1.0
integrity
- size
- 262.3 KiB
- downloaded
- last checked
- overlays
- go
- detected
- go module github.com/voluminor/ratatoskr
release notes
Ratatoskr v1.1.0 is the first stable release of the project. It establishes the final v1 architecture for embedding Yggdrasil mesh nodes and individual networking components into Go applications.
Ratatoskr runs Yggdrasil through a userspace gVisor TCP/IP stack. It does not require a TUN device or root privileges.
This release is not backward compatible with the pre-1.0 API. The old contracts were intentionally changed where they prevented clear ownership, consistent lifecycle management, bounded resource use, or predictable behavior under load. This is why the project has moved to the stable v1 line.
API stability
The exported root and module APIs are now stable.
Future v1.x releases will preserve public API compatibility. Development within v1 will focus on bug fixes, security and stability improvements, performance work, documentation, and backward-compatible additions.
Any intentional breaking change to the public Go API will require a new major version.
Why the redesign was needed
Earlier releases contained the required networking components, but they had evolved with different configuration, lifecycle, and ownership models.
The main issues were:
- inconsistent constructors and shutdown behavior between modules;
- unclear ownership of configuration and returned data;
- insufficiently bounded work in some TCP, UDP, SOCKS5, resolver, and probe paths;
- different cancellation semantics between modules;
- root-level access to core functionality through interface embedding;
- duplicated synchronization and deadline logic;
- weak visibility into overload and shutdown state;
- obsolete settings and command paths;
- public contracts that could not be corrected without breaking compatibility.
Preserving the pre-1.0 API would also have preserved these constraints. The v1 redesign replaces them with one consistent model.
Root package
The root ratatoskr package now provides a coordinated lifecycle for:
- the embedded Yggdrasil core;
- local and remote NodeInfo;
- optional peer management;
- optional SOCKS5 and DNS services;
- shared shutdown and runtime state.
The root object exposes common networking operations directly. Advanced core operations such as multicast, admin access, peer retry, and low-level diagnostics are available explicitly through Core().
The root object no longer embeds core.Interface. This keeps the public boundary visible and prevents applications from accidentally depending on internal composition details.
Close() is now:
- idempotent;
- safe for concurrent calls;
- bounded by CloseTimeout;
- dependency-aware;
- error-preserving.
Dependent services are stopped before the underlying Yggdrasil core. Components that exceed the shutdown deadline cannot indefinitely block the application shutdown path.
Core module
The core module was hardened around explicit ownership and predictable teardown.
Changes include:
- config-based construction;
- validation before startup;
- safe handling of nil contexts;
- copied caller-owned NodeInfo and multicast configuration;
- tracked listeners and packet connections;
- coordinated NIC and gVisor netstack shutdown;
- correct MTU handling;
- fail-closed public-key restrictions;
- explicit multicast lifecycle;
- isolated admin integration;
- fixes for shutdown races, RST handling, and resource leaks.
The core module remains independently usable through mod/core.
TCP and UDP forwarding
The forwarding module was rebuilt around immutable mappings and controlled resource use.
It now provides:
- local-to-Yggdrasil TCP forwarding;
- Yggdrasil-to-local TCP forwarding;
- local-to-Yggdrasil UDP forwarding;
- Yggdrasil-to-local UDP forwarding;
- transactional validation and binding;
- TCP admission limits;
- UDP session limits;
- idle session cleanup;
- backend dial deadlines;
- TCP idle deadlines;
- bounded UDP packet queues;
- bounded UDP payload sizes;
- overload drop counters;
- terminal error counters;
- retry and backoff for transient listener errors;
- standalone TCP and UDP proxy helpers.
Applications exposing forwarding to untrusted traffic should configure finite MaxTCPConnections and MaxUDPSessions values.
SOCKS5
The SOCKS5 module now has a complete bounded server lifecycle and supports both TCP and UDP traffic.
Implemented functionality includes:
- TCP CONNECT;
- UDP ASSOCIATE;
- TCP listeners;
- protected Unix socket listeners;
- connection admission limits;
- handshake deadlines;
- outbound dial deadlines;
- established tunnel idle deadlines;
- server-wide UDP target limits;
- per-session UDP target limits;
- optional per-principal limits;
- bounded UDP packet and byte queues;
- a bounded resolve-and-dial worker pool;
- fail-closed DNS behavior by default;
- tracked outbound connections;
- owned resolver shutdown;
- overload and runtime snapshots.
Closing the SOCKS5 server now terminates the active listener, accepted connections, UDP sessions, workers, tracked targets, and owned resolver.
The server handle may be started and stopped across multiple generations without sharing generation-specific state.
Resolver
The resolver supports:
- canonical .pk.ygg public-key domains;
- IPv4 and IPv6 literals;
- DNS through a caller-provided Yggdrasil dialer;
- coalescing of concurrent lookups for the same normalized name;
- a fixed limit on concurrent distinct lookups;
- positive caching;
- bounded negative caching;
- independent caller cancellation;
- copied return values;
- coordinated shutdown.
Shared DNS work belongs to the resolver rather than to the first caller. A caller can stop waiting without invalidating work that may still be useful to another caller or to the cache.
When the distinct-flight limit is reached, new names return ErrLookupBusy. Existing flights remain joinable. This provides bounded work and explicit load shedding under pressure.
NodeInfo
Remote NodeInfo handling now provides:
- coalesced requests for the same node;
- bounded concurrent work;
- caller-specific cancellation;
- bounded retry duration;
- bounded address resolution;
- response size validation;
- safe parsing of partial or malformed data;
- copied result structures;
- custom sigil parser support;
- predictable shutdown.
NodeInfo configuration and returned values follow explicit ownership rules so callers cannot unintentionally mutate internal state.
Sigils
Sigils remain separated into independent packages. This is intentional: each sigil can be added, tested, or modified atomically, while the generator collects all built-in sigils into one registry.
The v1 sigil system includes:
- clone-based ownership;
- typed accessors;
- explicit parsing contracts;
- conflict validation;
- reserved built-in names;
- deterministic metadata generation;
- generated registration of built-in sigils;
- isolated support for custom parsers.
The generated built-in registry is internal and cannot be modified globally by consumers. Applications that need a customizable set can request a fresh parser map and modify their own copy.
Peer management
The peer manager was rebuilt around bounded active probing and explicit candidate ownership.
It now provides:
- peer URI normalization and validation;
- credential redaction in errors and logs;
- protocol-aware candidate grouping;
- bounded probe windows;
- active peer limits;
- failed-add backoff;
- minimum-peer monitoring;
- passive recovery;
- no-reachable-peer handling;
- immutable configuration;
- runtime snapshots.
The module depends only on the narrow peer and state operations it requires and remains independently usable through mod/peermgr.
Topology probing
The probe module now treats topology discovery as a bounded diagnostic operation.
It provides:
- breadth-first topology traversal;
- spanning-tree paths;
- route tracing;
- pathfinder hops;
- combined trace results;
- limits on total nodes and peers per node;
- bounded remote concurrency;
- coalesced remote requests;
- explicit truncation reporting;
- partial results during shutdown or limit exhaustion;
- consistent error handling.
Obsolete probe cache and worker-pool layers were removed. This reduced hidden state and made traversal ownership easier to reason about.
The probe module remains separate from the root package because it is an optional diagnostic component rather than part of the required data path.
Shared internal infrastructure
Common lifecycle and concurrency code was consolidated under internal/common.
Shared primitives now cover:
- task ownership and cancellation;
- dynamic admission limits;
- deadline refresh;
- shutdown coordination;
- logger normalization;
- public-key parsing;
- admin handler capture;
- NodeInfo cloning with depth and cycle checks.
This removes duplicated synchronization logic and gives modules consistent behavior for shutdown, deadlines, limits, and ownership.
Breaking changes from pre-1.0 releases
Users upgrading from 0.x must update their integrations.
Important changes include:
- the root Obj no longer embeds core.Interface;
- advanced core operations must be accessed through Core();
- CoreStopTimeout was replaced by CloseTimeout;
- module constructors now use module-specific ConfigObj values;
- forwarding configuration and constructor contracts changed;
- peer manager configuration and lifecycle contracts changed;
- SOCKS5 configuration and lifecycle contracts changed;
- shutdown behavior is now bounded and explicit;
- several error and snapshot types changed;
- built-in sigil names can no longer be overridden;
- the old mod/settings package was removed;
- obsolete yggstack command code was removed;
- legacy settings generation was removed;
- old command configuration is not automatically compatible with the new model.
Applications should review the root README and the README for every directly imported module before upgrading.
Command scope
The cmd tree was updated where required to build against and exercise the v1 APIs.
This includes:
- migration to the new module constructors;
- updated configuration handling;
- command documentation;
- command-specific tests;
- CI build coverage;
- removal of obsolete command paths.
The command applications were not fully redesigned to the same extent as the reusable library. The root package and modules under mod/ are the primary result of this release.
The v1 compatibility guarantee applies to the exported Go library APIs. Command applications may continue to receive internal cleanup, usability improvements, and new options without changing the stable library contracts.
Documentation and build tooling
Project documentation was rewritten around the embeddable library and module boundaries.
The repository now includes:
- a complete root README;
- dedicated documentation for each module;
- documented lifecycle and ownership contracts;
- security and overload guidance;
- updated contribution instructions;
- generated-file workflow documentation;
- Docker integration test documentation;
- throughput and profiling methodology;
- cross-platform CI checks;
- simplified metadata and generation workflows.
English documentation is now the single maintained source.
Validation
The final architecture was validated with:
- unit tests across the root package and modules;
- regression tests for previously identified lifecycle defects;
- full race-detector runs;
- go vet;
- staticcheck;
- golangci-lint;
- Linux, Windows, and macOS cross-build checks;
- Docker-based multi-node integration tests;
- node health and peer establishment checks;
- TCP echo tests;
- UDP echo tests;
- SOCKS5 TCP tests;
- SOCKS5 UDP ASSOCIATE tests;
- .pk.ygg resolution through SOCKS5;
- admission and overload tests;
- shutdown and cancellation tests;
- CPU profiling;
- runtime tracing;
- TCP and UDP throughput benchmarks.
The integration and diagnostic tooling is available under tests/. Throughput results and profile attribution are documented in THROUGHPUT_BENCHMARK.md.
Using Ratatoskr v1
Applications can use Ratatoskr in two supported ways:
- Import the root ratatoskr package for an embedded node with one coordinated lifecycle.
- Import individual packages from mod/ and compose only the required components through their narrow interfaces.
Both integration styles use the same ownership, lifecycle, error, and resource-management principles.
Ratatoskr v1.1.0 is the stable architectural baseline for the v1 release line. Further v1 releases will build on this design without breaking the public Go API.
Contributors
- @SUNsung (https://github.com/SUNsung) — architecture, implementation, documentation, tests, and release preparation.
- @dependabot (https://github.com/apps/dependabot) — GitHub Actions dependency updates.
Release history
This is the first published stable release, so it contains the complete project history from the initial repository setup through the final v1 architecture.
- Final v1 architecture pull request (https://github.com/voluminor/ratatoskr/pull/11)
- All commits included in v1.1.0 (https://github.com/voluminor/ratatoskr/commits/v1.1.0)
download
curl -fL -o v1.1.0.zip https://ratatoskr.space/pkg/ratatoskr/v1.1.0.zip
printf '%s %s\n' 'ade14a94f4032940eed3407c50940ce7f8954709220038f9119b5d2aef9eb383' 'v1.1.0.zip' | sha256sum -c -
$url = "https://ratatoskr.space/pkg/ratatoskr/v1.1.0.zip"
$out = "v1.1.0.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "ade14a94f4032940eed3407c50940ce7f8954709220038f9119b5d2aef9eb383") { throw "sha256 mismatch" }
curl -fL -o v1.1.0.tar.gz https://ratatoskr.space/pkg/ratatoskr/v1.1.0.tar.gz
printf '%s %s\n' 'fc5849fbdd4754a6ed839f10c0a6b91ff61fdcbee3db2fa952ff5706d422cf60' 'v1.1.0.tar.gz' | sha256sum -c -
$url = "https://ratatoskr.space/pkg/ratatoskr/v1.1.0.tar.gz"
$out = "v1.1.0.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "fc5849fbdd4754a6ed839f10c0a6b91ff61fdcbee3db2fa952ff5706d422cf60") { throw "sha256 mismatch" }
download via yggdrasil mesh
curl -fL -o v1.1.0.zip http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.zip
printf '%s %s\n' 'ade14a94f4032940eed3407c50940ce7f8954709220038f9119b5d2aef9eb383' 'v1.1.0.zip' | sha256sum -c -
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.zip"
$out = "v1.1.0.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "ade14a94f4032940eed3407c50940ce7f8954709220038f9119b5d2aef9eb383") { throw "sha256 mismatch" }
curl -fL -o v1.1.0.tar.gz http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.tar.gz
printf '%s %s\n' 'fc5849fbdd4754a6ed839f10c0a6b91ff61fdcbee3db2fa952ff5706d422cf60' 'v1.1.0.tar.gz' | sha256sum -c -
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.tar.gz"
$out = "v1.1.0.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "fc5849fbdd4754a6ed839f10c0a6b91ff61fdcbee3db2fa952ff5706d422cf60") { throw "sha256 mismatch" }
| artifact | format | size | hashes |
|---|---|---|---|
| v1.1.0.zip | zip | 263.9 KiB |
blake3-24 a00e0d6b000378d949d1e2e666a934566edcb8ea569ed0f8
sha256 ade14a94f4032940eed3407c50940ce7f8954709220038f9119b5d2aef9eb383
sha1 c90fd202f66475f165277f36bc7f6b2b494ad5ad
|
| v1.1.0.tar.gz | tar.gz | 196.8 KiB |
blake3-24 be1f9c5d412a60cce008a8aa02200489e243f7969dea83ce
sha256 fc5849fbdd4754a6ed839f10c0a6b91ff61fdcbee3db2fa952ff5706d422cf60
sha1 3956487b57a63ad7cc1502e1093a06562fe852d3
|
go module archive
module zip with the module path rewritten to this mirror; fetched by go get through the
GOPROXY route
| artifact | format | size | hashes |
|---|---|---|---|
| v1.1.0.zip | zip | 266.9 KiB |
blake3-24 426d2344f4f33362f8c853e07e16e30a8956b6ef0c58bd48
sha256 e90c108325265297877bb5eb7a9c02548daf1a66464cecdec4cba93f5a8dcba6
sha1 e5d408d344a7880728bdc46d09e087c3c491f8e7
|
install
http_archive(
name = "ratatoskr",
urls = ["https://ratatoskr.space/pkg/ratatoskr/v1.1.0.tar.gz"],
integrity = "sha256-/FhJ+91HVKbtg58QwKa5H/Yf3L7j2y+pUv9XBtQiz2A=",
strip_prefix = "ratatoskr-v1.1.0",
)
.url = "https://ratatoskr.space/pkg/ratatoskr/v1.1.0.tar.gz",
GOPROXY=https://ratatoskr.space GOSUMDB=off go get ratatoskr.space/pkg/ratatoskr@v1.1.0
install via yggdrasil mesh
http_archive(
name = "ratatoskr",
urls = ["http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.tar.gz"],
integrity = "sha256-/FhJ+91HVKbtg58QwKa5H/Yf3L7j2y+pUv9XBtQiz2A=",
strip_prefix = "ratatoskr-v1.1.0",
)
.url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr/v1.1.0.tar.gz",
GOPROXY=http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg GOSUMDB=off GOINSECURE=14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/* go get 14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ratatoskr@v1.1.0