pilot.md: step-by-step for connecting two households (link-agnostic), measurement protocol M0-M4 (link baseline, uplink baseline, pooled, concurrent downloads, sn-fair Soll/Ist comparison), safety/legal checklist, and a results section to be filled after the pilot. Cross-linked from Home, documentation README, roadmap, architecture and server README; roadmap marks sn-fair v0 done.
SpiderNet-Node — Server/Software
Die Software, die aus "Nachbarschafts-LAN" ein gepooltes Bandbreitennetz macht. Sprache: Rust.
Status
sn-fetch PoC v0 ist implementiert (siehe crates/sn-fetch/):
- Range-Probe (
HEAD+ 1-Byte-GET-Fallback) erkenntAccept-Ranges - Gewichteter Planner (Exits nach Kapazität, optionale Sub-Segmente pro Exit, Mindest-Segmentgröße mit Merge-Fix, validated: lückenlose, vollständige Abdeckung)
- Parallele Segment-Downloads (Streaming, eigener reqwest-Client pro Exit)
- Retry mit Exit-Reassignment: fehlgeschlagene Segmente werden (wieder- holbar, Standard 3 Versuche) bevorzugt auf einem anderen Exit wiederholt; nicht-retrybare Fehler (4xx, korrupte Parts) brechen sofort ab — ein halbfertiges File wird nie als Erfolg ausgegeben
- Progress:
ProgressSink-Events (Segment started/finished/failed,BytesTracker) +tracing-Logging - Per-Exit-Egress:
Direct(eigener Uplink) oderProxy(HTTP-Proxy eines Nachbarn — der Weg fürsn-exitüber das Overlay); end-to-end getestet gegen einen echten Forward-Proxy - Reassembly in Index-Reihenfolge + Streaming-SHA-256 + Längen-Check
- Fallback: range-hostile Server werden als single-stream geladen
- CLI:
sn-fetch <url> [-o out] [-e "1=2,2=1@http://[ygg]:8080"] [-s n] [--max-attempts n] [--sha256 hex] --probe-only
Verifiziert gegen einen echten Server (Debian-CD-Mirror, 756 MB, 8 Segmente,
SHA-256 entspricht der offiziellen SHA256SUMS).
sn-node v0 ist implementiert (siehe crates/sn-node/):
sn-node genconf: erzeugt eine Yggdrasil-Config aus validierten Einstellungen — Basis ist immer der echteyggdrasil -genconf -jsonOutput (keine hartcodierten Defaults), gepatcht mitPeers,Listen,MulticastInterfaces,AdminListen,AllowedPublicKeys(Nachbarschafts- ACL),IfName,PrivateKeyPath; Output-Datei wird auf 600 gesetztsn-node status: fragt den Admin-Socket ab (getSelf/getPeersüber TCPlocalhost:9001oder Unix-Socket) — Overlay-Adresse, Subnetz, Version, aktive Peer-Verbindungen
sn-exit v0 ist implementiert (siehe crates/sn-exit/):
- HTTP-Proxy-Dienst, der auf der Yggdrasil-Adresse des Haushalts lauscht und Nachbar-Requests über den eigenen Uplink holt — Sharing ist opt-in durch Starten des Dienstes, Stoppen ist der Kill-Switch
- Transparentes Byte-Relay: absolute-URI-GETs (HTTP) und CONNECT-
Tunnel (HTTPS) werden unverändert weitergeleitet; TLS bleibt end-to-end
zwischen Neighbor-Client und Origin, Range-Header und Retries
funktionieren (Segmentierung bleibt Sache von
sn-fetch) - Quota pro Neighbor: Bytes pro Zeitfenster (fixed window),
erschöpft → HTTP 503 mit
Retry-After; Accounting auch bei abgebrochenen Verbindungen (Counter-Wrapper, nicht Copy-Ergebnis) - SSRF-Schutz: Origins, die zu Loopback/Private/Link-Local/ULA/ Yggdrasil-Ranges auflösen, werden abgewiesen — Nachbarn können nicht in Heim-LAN oder Admin-Sockets des Exit-Haushalts fetchen
- Source-Allowlist: nur gelistete Neighbor-Adressen; ohne Liste nur Loopback (Dev-Mode)
- Verifiziert end-to-end:
sn-fetchüber einen laufendensn-exitlädt die Debian-ISO (756 MB, 4 Segmente, SHA-256 korrekt)
sn-fair v0 ist implementiert (siehe crates/sn-fair/):
- Gewichtetes Max-Min-Fairness-Engine (zwei Klassen): Contributors (Haushalte mit Exit-Angebot, konfigurierbares Gewicht) teilen sich die Gesamtkapazität nach Max-Min-Fairness; Leeches (Empfang ohne Beitrag, ausdrücklich legitim) bekommen die Restkapazität — bei Sättigung zuerst gedrosselt, nie ausgeschlossen
- Deterministische, overflow-sichere Berechnung (u128-Arithmetik,
Restverteilung in ID-Ordnung), validierte Newtypes
(
ParticipantId,Weight,Rate,Capacity) - Demo-CLI in Mbit/s für den Piloten: Soll-Aufteilung simulieren und gegen die gemessene Ist-Aufteilung halten (siehe Pilot, M4)
- Runtime-Integration in
sn-fetch(echte gleichzeitige Downloads drosseln) ist Phase 2, siehe Roadmap
Noch nicht drin: sn-node-Daemon (Supervisor, der yggdrasil +
sn-exit + sn-fetch orchestriert), Freenet-Integration, Cache.
Details zum Overlay: Overlay. Pilot-Handbuch mit Messprotokoll: Pilot.
Haftungsausschluss (muss im Produkt sichtbar sein)
KEINE GARANTIE. Diese Software wird "as is" ohne jegliche Garantie bereitgestellt (AGPL §§ 15/16). Die Betreiber und Contributor:innen dieses Projekts übernehmen keinerlei Verantwortung oder Haftung dafür, wozu Nutzer:innen die Software verwenden oder welche Inhalte über sie übertragen werden. Die Verantwortung für gesendete und empfangene Inhalte liegt vollständig bei den Nutzer:innen.
Dieser Hinweis muss prominent sichtbar sein: im README, im Startup-Banner des Daemons und in der Weboberfläche.
Zielbild
Pro Haushalt läuft ein SpiderNet-Node (sn-node, Mini-PC oder
Einplatinenrechner), der:
- Das Nachbarschafts-Overlay bildet (Yggdrasil als erste Wahl)
- Seinen eigenen ISP-Uplink als Exit anbietet (opt-in, Kontingent)
- Downloads über alle verfügbaren Exits segmentiert und parallel lädt
- Traffic fair zwischen allen Teilnehmenden aufteilt (max-min Fairness)
- Einen geteilten Nachbarschafts-Cache bedient (lancache-Prinzip)
- (später)
freenet-coreals Sidecar laufen lässt für verteilte Inhalte/Apps
Geplante Komponenten
| Crate/Binary | Zweck |
|---|---|
sn-node |
Node-Glue: Yggdrasil-Config (genconf), Overlay-Status (status), später Daemon/Supervisor |
sn-exit |
Exit-Dienst: kontingentierter Uplink-Proxy auf der Yggdrasil-Adresse (v0: Byte-Relay + Quota + SSRF-Schutz) |
sn-fetch |
Segmentierter Multi-Exit-Downloader (HTTP-API + CLI) |
sn-fair |
Fairness-Scheduler (max-min, Exit-Kontingente, Karma, Leech-Modus) — v0: zwei-Klassen-Max-Min-Engine + Demo-CLI |
sn-cache |
Transparenter Nachbarschafts-Cache (DNS-basiert) |
sn-freenet |
Integration von freenet-core (Contracts für Nachbarschafts-Inhalte) |
MVP (Phase 1→2, siehe Roadmap)
Kleinster brauchbarer Schnitt:
- Zwei Nodes peeren (Yggdrasil)
- Ein Download wird über beide Uplinks gleichzeitig per HTTP-Range gesplittet, reassembliert, hash-verifiziert
- Fair-Share: zwei gleichzeitige Downloads teilen sich die Gesamt- kapazität fair
- Exit opt-in per Konfig-Datei; Leech-Modus (Sharing aus, nur empfangen) jederzeit umschaltbar; Kill-Switch (Exit aus = Node nutzt nur den eigenen Uplink)
Nicht-Ziele (bewusst)
- Keine Bezahl-/Krypto-Infrastruktur (Kontrast: Althea)
- Keine Anonymitätsversprechen (Freenet selbst bietet keine; wir auch nicht)
- Kein Zentralserver, keine zentrale Datensammlung
- Keine inhaltliche Kontrolle oder Zensur durch die Software selbst — die Software transportiert Dateien/Webseiten aller Art; was übertragen wird, liegt in der Verantwortung der Nutzer:innen (Haftungsausschluss oben)
Code-Standards: maximale Type-Safety in Rust
Der Code soll so sicher sein, dass ganze Fehlerklassen schon beim Kompilieren
unmöglich werden. Verbindliche Regeln für jede Crate in server/:
Maschinell erzwungen (Workspace-Lints in server/Cargo.toml, in jeder
Crate via [lints] workspace = true aktiviert):
unsafe_code = "deny"+#![forbid(unsafe_code)]im Crate-Rootclippy::unwrap_used = "deny"— keinunwrap()(Panic-Quelle, kein Test)clippy::expect_used = "deny"— keinexpect()(Panic-Quelle, kein Test)clippy::panic = "deny",clippy::unreachable = "deny"clippy::all = "deny",clippy::pedantic = "warn"(Deny-Ziel vor Release)
Verifiziert: ein eingebautes unwrap() in lib.rs wurde von Clippy mit
error: used unwrap() ... #unwrap_used abgelehnt. Tests dürfen
unwrap()/expect() (explizites #![allow(...)] pro Test-Crate).
#![forbid(unsafe_code)]in jedem Crate-Root (undunwrap,expectnur in#[cfg(test)]-Kontext).- Newtypes statt roher Primitive für alles, was Bedeutung hat:
struct NodeId(NonZeroU64),struct BytesPerSecond(u64),struct SegmentIndex(u32),struct ExitQuotaBytes(…)— keine nacktenu64/Stringin Domänen-Typen. - Exhaustive Enums statt Strings/Bool-Flags für Zustände (z. B.
enum ExitState { OptedIn(Quota), Leeching, Suspended }),matchohne_-Arm, damit Compiler-Checks beim Erweitern greifen. - Typestate-Pattern für Protokoll-/Lebenszyklus-Zustände (z. B.
Download<Started>→Download<Split>→Download<Assembled>), damit illegale Zustandsübergänge nicht kompilieren. TryFrom/TryIntostatt stiller Konvertierung, keine panicking Operationen in nicht-Test-Code; Fehler viathiserror-Enums, Bubble-up statt Logging-and-continue.- Parsed-data-is-validated: unsichere Eingaben (Konfig, Netzwerk) werden
direkt beim Einlesen in validierte Typen transformiert; danach trägt der
Typ die Invariante (z. B.
struct ValidatedConfig(ConfigInner)stattConfigmit Optionals). - Keine globalen
Mutex/static mut; Shared State explizit als Besitz-/Kanal-Struktur (tokio::syncprimitives mit bewusster Wahl). deny(clippy::all, clippy::pedantic)-basierte CI-Checks, sobald Code existiert;cargo-denyfür Dependencies.
Technologiestack (Vorschlag)
- Rust (tokio),
axumfür APIs - Yggdrasil als Overlay (später evtl. Babel + WireGuard)
freenet-stdlib/ WebSocket-API für Freenet-Integration- HTTP Range Requests + SHA-256-Verifizierung für Segmentierung
- Lizenz: siehe Lizenz (Empfehlung: AGPL-3.0)