fabric: Eine Machbarkeitsstudie für ein selbstheilendes P2P-Mesh

Wie finden sich Knoten, wenn Adressen wechseln, Verbindungen abbrechen und kein zentraler Dienst die Topologie kennt? fabric ist meine Forschungsplattform für Peer-Discovery, Route-Healing, mehrstufige Transportwege und klar begrenztes Vertrauen. Dieser Beitrag beschreibt, was bereits funktioniert, wo die Selbstheilung heute endet und warum gerade diese Grenze interessant ist.
Table of contents

Ein Mesh ist auf dem Whiteboard immer gesund. Ein paar Kreise, einige Linien dazwischen, vielleicht noch eine Wolke für „das Internet“ — fertig ist das dezentrale Netz. Interessant wird es erst, wenn man eine Linie wegradiert. Oder drei. Wenn ein Knoten umzieht, eine Adresse nur aus einem privaten Netz erreichbar ist, UDP plötzlich verschwindet und niemand mehr zuverlässig sagen kann, welcher Weg zum Ziel noch existiert.

Genau dort beginnt fabric. Das Projekt untersucht, ob sich aus wenigen, bewusst begrenzten Bausteinen ein Peer-to-Peer-Netz zusammensetzen lässt, das neue Teilnehmer sicher aufnimmt, seine Nachbarn selbst entdeckt, indirekte Wege lernt und veraltete Routen wieder überprüft. Nicht als fertiges Produkt und nicht als Versprechen, jedes kaputte Netz magisch zu reparieren, sondern als Machbarkeitsstudie für Discovery und Auto-Healing: ausführbar, testbar und offen genug, dass auch die Lücken sichtbar bleiben.

Forschungssoftware — ausschließlich für eigene oder ausdrücklich autorisierte Systeme. fabric ist pre-production, wurde nicht unabhängig auditiert und ist kein Werkzeug für den operativen Einsatz. Native Plugins laufen trotz Prozessisolation mit den Rechten des Construct-Accounts. Vor Experimenten gehören der Disclaimer und das Sicherheitsmodell gelesen.

Der erste Faden kam aus Neuromancer#

Bevor es ein Protokoll gab, gab es eine Sprache dafür. William Gibsons Neuromancer beschreibt das Netz nicht als Ansammlung von Servern, sondern als Raum, in den man sich einklinkt: mit einem Deck als Schnittstelle, Constructs als fortbestehenden Persönlichkeiten und einer unsichtbaren Struktur, die alles miteinander verbindet. Das war die ursprüngliche Idee hinter der Benennung — nicht nachträglich aufgeklebte Cyberpunk-Dekoration, sondern ein Vokabular, aus dem sich die Rollen fast von selbst ergaben.

deck ist das Werkzeug in der Hand des Operators. Es startet, verbindet sich, führt einen Befehl aus und verschwindet wieder. Kein Daemon, kein Listener, kein lokaler Mesh-Knoten. constructs sind die dauerhaften Teilnehmer: Sie besitzen eine Identität, halten Verbindungen, lernen Routen und stellen Funktionen bereit. Und fabric ist das Gewebe dazwischen — Identitäten, Transportwege, Vertrauensbeziehungen und signierte Fähigkeiten, die erst gemeinsam ein Netz ergeben.

Implementiert ist dieses Gewebe in Rust; wichtiger als die Sprache war mir jedoch die Frage, ob sich der veränderliche Zustand eines solchen Systems so ordnen lässt, dass seine Sicherheitsgrenzen beim Lesen des Codes nachvollziehbar bleiben.

Die Namen machen das Projekt anschaulich, aber sie erteilen keinerlei Rechte. Ob ein Construct einem anderen vertraut, entscheidet kein Gibson-Zitat, sondern eine Kette aus kryptografischer Identität, Enrollment, Policy und begrenzten Credentials.

Die Forschungsfrage hinter dem Code#

fabric versucht nicht, „P2P“ als möglichst lange Feature-Liste abzuhaken. Im Kern geht es um vier Hypothesen:

  1. Identität lässt sich von Erreichbarkeit trennen. Ein Knoten darf seine Adresse wechseln, ohne dadurch ein anderer Knoten zu werden.
  2. Discovery kann dezentral wachsen. Nach einem einzigen autorisierten Erstkontakt sollen Peer-Exchange und eine verteilte Routingstruktur genügen, um weitere Teilnehmer kennenzulernen.
  3. Heilung beginnt mit ehrlichem Zweifel. Routen dürfen altern, verschwinden und neu bewertet werden, statt für immer als Wahrheit im Speicher zu liegen.
  4. Funktionalität lässt sich nachladen, ohne die Vertrauenskette aufzugeben. Erweiterungen und Stage-Payloads müssen dieselben Signatur-, Größen- und Rollenregeln durchlaufen wie der Rest des Netzes.

Als Bild ergibt sich kein allwissender Controller, sondern ein Kreislauf:

flowchart LR B[Autorisierter Erstkontakt] --> P[Peer-Exchange] P --> D[Signierte DHT-Einträge] D --> R[Direkte und indirekte Routen] R --> V[Messung und Revalidierung] V -->|neue Erkenntnisse| R V -->|veralteter Weg| F[FindPeer über Nachbarn] F --> R

Das ist der Gegenstand der Machbarkeitsstudie. Nicht jeder Pfeil ist schon gleich weit entwickelt — und genau diese Unterschiede sind wichtiger als eine glatte „self-healing“-Plakette.

Drei Rollen, drei verschiedene Vertrauensgrenzen#

Im Netz treten drei Rollen auf:

  • Der Operator signiert Befehle, Policies, Enrollment-Grants und Plugin-Pakete. Sein Schlüssel ist die Wurzel der administrativen Autorität.
  • Ein Standard-Construct ist ein vollständiger Mesh-Knoten. Er nimmt Verbindungen an, routet Nachrichten, beteiligt sich an Discovery und DHT und beaufsichtigt Plugins.
  • Ein Minimal-Construct ist kein kleiner Standardknoten, sondern ein bewusst enger Einweg-Client. Er führt genau einen authentifizierten Stage-Austausch durch und übergibt die verifizierte Payload an den Plattform-Loader.

Deck steht außerhalb dieser dauerhaften Topologie. Eine Verbindung darf sich nicht einfach selbst zum Operator erklären: Erst ein gültig signierter erster Befehl klassifiziert sie als Operator-Session. Danach bleibt sie für die Antwort geöffnet, wird aber aus dem sichtbaren Mesh entfernt. Flüchtige Deck-Identitäten tauchen dadurch weder im Peer-Exchange noch in der Topologie als vermeintliche Constructs auf.

Diese Trennung ist mehr als Ordnungsliebe. Wird der Operator-Schlüssel kompromittiert, sind signierte Befehle und native Code-Ausführung auf allen verwalteten Constructs autorisiert. Wird dagegen ein einzelner Node-Schlüssel kompromittiert, betrifft das zunächst die Identität dieses Knotens. Unterschiedliche Rollen brauchen unterschiedliche Schlüssel — und unterschiedliche Schadensradien.

Der erste Kontakt: eine Adresse ist noch keine Identität#

Jedes dezentrale Netz hat ein Bootstrap-Problem: Um andere Peers zu entdecken, muss ein neuer Teilnehmer zunächst wenigstens einen Peer kennen. fabric löst das nicht, indem es einen Seed-Server zur ewigen Wahrheit erklärt. Ein vorbereitetes Join-Artefakt enthält stattdessen die NodeID des autorisierten Issuers und einen begrenzten Enrollment-Grant, aber keine fest eingebaute Adresse.

Die aktuelle Adresse kommt erst beim Start über FABRIC_SEEDS:

1FABRIC_SEEDS="quic://192.168.1.50:33123#<vollständige-node-id>"

Dieser String ist ein Locator, kein Vertrauensanker. Er darf veraltet sein oder auf den falschen Host zeigen; dann scheitert die Verbindung. Er darf aber nicht unbemerkt einen anderen Issuer unterschieben, denn jeder Eintrag muss exakt die vorbereitete NodeID tragen und der Endpunkt muss diese Identität anschließend kryptografisch beweisen.

Diese Trennung — Autorisierung ist nicht Location — ist eines der wichtigsten Ergebnisse des Projekts. Eine IP-Adresse beantwortet die Frage „Wo versuche ich es?“. Die NodeID beantwortet „Mit wem wollte ich sprechen?“. Beides in dasselbe Konfigurationsfeld zu falten wäre bequem, aber falsch.

Fleet-Mitgliedschaft außen, Mesh-Identität innen#

Eine Standardverbindung durchläuft zwei voneinander getrennte Schutzschichten. QUIC verwendet TLS 1.3 und prüft, ob das Zertifikat zur vorbereiteten Fleet-CA gehört; zusätzlich ist deren SPKI im Operator-Profil gepinnt. Darüber läuft Noise_XK. Noise bindet die Session an die erwartete NodeID und ist für die Identität im Mesh autoritativ.

sequenceDiagram participant A as Deck oder Construct participant Q as QUIC + TLS 1.3 participant N as Noise_XK participant B as Ziel-Construct A->>Q: Fleet-Zertifikat und SPKI-Pin prüfen Q->>N: Multiplexed Stream öffnen N->>B: XK-Handshake mit signiertem Identitätsbeweis B-->>N: erwartete NodeID bestätigt N-->>A: begrenzte, verschlüsselte Wire-v3-Nachrichten

Die NodeID ist der öffentliche Ed25519-Schlüssel des Constructs. Für Noise wird daraus deterministisch ein X25519-Schlüssel abgeleitet. Im dritten Teil des Handshakes signiert der Knoten nicht bloß einen zufälligen Text, sondern den relevanten Kontext: Protokolldomäne, Rollen, Handshake-Transkript, statischen Noise-Schlüssel und erwarteten Responder. Der Empfänger prüft außerdem, ob der behauptete X25519-Schlüssel tatsächlich zur NodeID gehört. Damit genügt weder ein kopiertes TLS-Zertifikat noch ein ausgetauschter Noise-Key, um sich als der erwartete Peer auszugeben.

Enrollment ist eine Verbrauchskette#

Nach der Identität folgt die Zulassung. Ein Operator-signierter Grant legt fest:

  • welcher Issuer enrollen darf,
  • ob der Grant für einen Standard- oder Stage-Teilnehmer gilt,
  • ab wann und bis wann er gültig ist,
  • wie viele verschiedene Nodes damit aufgenommen werden dürfen,
  • und wie lange das ausgestellte Credential lebt.

Der Issuer prüft den Grant gegen die bereits durch Noise authentifizierte NodeID. Erst wenn die Verwendung dauerhaft im Ledger verbucht ist, gibt er ein kurzlebiges, an genau diesen Knoten gebundenes JoinTicketV2 zurück. Ein Absturz zwischen „Ticket ausstellen“ und „Verwendung speichern“ soll den Grant also nicht heimlich vervielfältigen.

Wenn der direkte Weg nicht funktioniert#

UDP ist der bevorzugte Weg, aber nicht jedes Netz lässt ihn passieren. Deshalb probiert der Bootstrap pro Seed eine feste Leiter:

1QUIC/UDP
2   └─> QUIC über TCP-Tunnel
3          └─> QUIC/UDP auf Port 53
4                 └─> DNS-Tunnel
5                        └─> ICMP-Tunnel (optional)

Die fünf Varianten laufen pro Seed absichtlich nacheinander, jeweils mit einem kurzen Timeout. Mehrere Seeds werden dagegen parallel gegeneinander geraced; die erste vollständig authentifizierte Verbindung gewinnt. So entsteht nicht bei jedem Start ein auffälliger Burst aus fünf gleichzeitigen Handshakes.

Wichtig ist, was beim Wechsel des Transports nicht wechselt: NodeID-Prüfung, Noise-Transkript, Tickets, Revocation, Allowlist, Replay-Schutz und Größenlimits bleiben dieselben. Der Fallback verändert Framing, Kapazität und sichtbare Metadaten, aber er darf keinen bequemeren Seiteneingang in die Policy öffnen.

Bei temporären Fehlern wiederholt der Bootstrap die gesamte Suche mit exponentiellem Backoff bis maximal 30 Sekunden. Sobald eine Session erfolgreich registriert ist, endet dieser Bootstrap-Loop. Diese kleine Formulierung wird später noch wichtig.

Discovery: vom ersten Nachbarn zum eigenen Lagebild#

Nach der ersten Verbindung kennt ein Construct zunächst vor allem eines: seinen direkten Nachbarn. Alles Weitere muss wachsen.

Peer-Exchange mit angezogener Handbremse#

Neue Construct-Sessions tauschen bekannte Peers aus, aber nicht sofort das ganze Adressbuch. Die Offenlegung ist an die beobachtete Reputation beziehungsweise Verbindungsdauer gebunden: In den ersten fünf Minuten gibt es keine Peer-Liste, danach höchstens fünf Einträge, nach einer Stunde höchstens zwanzig. Eingehende Listen und Adressmengen sind zusätzlich hart begrenzt und rate-limited.

Das verhindert keinen entschlossenen Sybil-Angriff. Es bremst aber den billigsten Fall aus: verbinden, vollständige Topologie absaugen, verschwinden. Discovery wird damit zu einem graduellen Vertrauensvorschuss statt zu einem anonymen Verzeichnisdienst.

Beim Austausch teilt ein Peer außerdem mit, unter welcher Socket-Adresse er sein Gegenüber sieht. Aus dieser reflexiven Beobachtung kann ein Construct vorsichtig ableiten, ob seine öffentliche Adresse von der lokalen abweicht. Private, widersprüchliche oder familienfremde Beobachtungen bleiben unknown; eine solche Beobachtung ist ein Hinweis, keine Erreichbarkeitsgarantie.

Eine DHT, die ihre Einträge unterschreibt#

Für Discovery jenseits der direkten Nachbarn verwendet fabric eine Kademlia-inspirierte DHT. Ein Knoten veröffentlicht keinen beliebigen Datensatz über jemand anderen, sondern einen signierten Self-Record mit:

  • epoch-abhängigem DHT-Key,
  • eigener NodeID,
  • begrenzter Adressliste,
  • Ablaufzeit,
  • und einer Signatur über den vollständigen Record.

Der Key wird aus NodeID, aktueller Epoch und einer festen Protokolldomäne abgeleitet. Eine Epoch-Rotation verändert damit den Suchraum und erschwert das dauerhafte Durchzählen bekannter Identitäten, ohne daraus Anonymität zu machen. Records laufen nach 24 Stunden aus und werden stündlich neu veröffentlicht. Zwischenknoten dürfen die signierte Ablaufzeit beim Weiterreichen nicht verlängern.

Iterative Lookups fragen bis zu drei Kandidaten parallel und isolieren langsame Peers mit einem eigenen Timeout. Die Routingtabelle wird lokal persistiert, sobald sie sich verändert hat. Ein Neustart beginnt dadurch nicht völlig blind, behandelt gespeicherte Adressen aber weiterhin nur als Kandidaten, die sich bei einer neuen authentifizierten Verbindung beweisen müssen.

Was Auto-Healing heute wirklich bedeutet#

„Selbstheilend“ klingt schnell nach einem Netz, das jede Partition bemerkt, neue Links zaubert und am Ende garantiert wieder vollständig verbunden ist. So weit ist fabric nicht — und die Machbarkeitsstudie wäre weniger wert, wenn sie das verschweigen würde.

Der aktuelle Runtime-Loop führt alle 60 Sekunden einen Healing-Tick aus. Dabei:

  1. klassifiziert er den Knoten als Connected, Degraded oder Isolated,
  2. aktualisiert die Qualität direkter Sessions anhand der aktuellen QUIC-Metriken,
  3. verwirft abgelaufene DHT-Records und räumt Rate-Limits auf,
  4. persistiert neu gelernte DHT-Routinginformationen,
  5. und sucht für Routen, die seit mehr als fünf Minuten nicht bestätigt wurden, über FindPeer nach einer neuen Bestätigung.

FindPeer wird mit einer zufälligen Query-ID an direkte Nachbarn geschickt, ist auf drei Hops und zehn Sekunden begrenzt und akzeptiert nur korrelierte Antworten für das tatsächlich gesuchte Ziel. Kommt eine Antwort über einen anderen Nachbarn zurück, kann die Route einen neuen Next Hop erhalten. Peer-Metriken frischen bekannte Wege auf; bessere Kandidaten dürfen schlechtere ersetzen.

Bricht dagegen eine direkte Session ab, entfernt der Knoten sofort alle Routen, die von ihr abhingen. Das ist korrektes Fail-Closed-Verhalten: Eine tote Linie bleibt nicht als optimistische Fantasieroute im Netzplan.

Die noch offene Grenze liegt einen Schritt danach. Der Produktionspfad besitzt derzeit keinen allgemeinen Connection-Manager, der nach dem Verlust einer bereits erfolgreichen Bootstrap-Session selbstständig DHT-Kandidaten auswählt, neue Links aufbaut und so lange weiterwählt, bis eine gewünschte Mindestkonnektivität wieder erreicht ist. Auch die vorhandenen Bausteine für NAT-Punching — reflexive Adressen, Kandidatenaustausch und parallele Verbindungsversuche — sind noch kein vollständiger autonomer Reparaturplaner.

Damit demonstriert fabric heute Discovery und Route-Healing, aber noch keine garantierte Topology-Healing. Genau das ist für mich keine peinliche Fußnote, sondern die präzise nächste Forschungsfrage: Welche Regeln wählen neue Nachbarn, ohne dass alle Nodes dieselben Hotspots erzeugen, Angreifer die Auswahl dominieren oder ein instabiles Netz in permanentes Reconnect-Flattern gerät?

Ein deterministischer Simulator prüft bereits Routinginvarianten unter Churn und Partitionen. Er zeigt, dass die Graph- und Lookup-Regeln konvergieren können; er beweist nicht, dass die reale Runtime verlorene Links schon vollständig selbst neu knüpft. Simulation und Implementierung bleiben deshalb bewusst getrennte Evidenz.

Ein Besitzer für den veränderlichen Zustand#

Die vielleicht unspektakulärste, aber folgenreichste Architekturentscheidung steckt im Main-Loop. Der gesamte veränderliche Sicherheits- und Routingzustand gehört einem Task:

1 Connection-Task A ──┐
2 Connection-Task B ──┼──> begrenzte Inbox ──> Main-Task
3 Connection-Task C ──┘                           │
4                                                ├── Sessions
5                                                ├── Mesh und Routen
6                                                ├── DHT
7                                                ├── Reputation
8                                                ├── Rate-Limits
9                                                └── Security-State

Connection-Tasks erledigen begrenzte Handshakes und reichen akzeptierte Streams an diese Inbox weiter. Policy, Nonce-Fenster, Routing und Sessionzustand werden anschließend seriell verändert. Das reduziert die Zahl möglicher Interleavings genau dort, wo ein Race sicherheitsrelevant wäre, und macht die Reihenfolge der Entscheidungen im Code sichtbar.

Der Preis ist ebenso klar: Der Main-Task ist ein serieller Flaschenhals. Für eine Forschungsplattform mit begrenzten Sessions, kurzen Kontrollnachrichten und strikten Rate-Limits ist das ein sinnvoller Tausch. Sollte fabric einmal auf Tausende hochaktive Nachbarn zielen, wäre diese Annahme neu zu messen statt nostalgisch zu verteidigen.

Was die Plattform heute kann#

Discovery und Healing sind der Kern der Untersuchung, aber sie brauchen reale Arbeit, die über das Netz läuft. Sonst blieben sie ein Graphenmodell ohne Druck aus der Praxis.

BereichImplementierter Funktionsumfang
BedienungEphemeres deck, direkte und weitergeleitete Sessions, ping, Peer-Liste, Identitäts- und Topologieabfragen, Attach/Detach und Proxy-Pfade
MeshDirekte Sessions, Weiterleitung über begrenzte Hops, Peer-Exchange, signierte DHT-Records, reflexive Adressbeobachtung und Link-Metriken
ZulassungBegrenzte Enrollment-Grants, knotengebundene Tickets, Allowlist, Revocation, Replay-Fenster und signierte Operator-Key-Rotation
TransportQUIC als Primärpfad sowie TCP-, Port-53-, DNS- und optionale ICMP-Fallbacks unter derselben Identitätsprüfung
ErweiterungenSignierte, plattformspezifische native Plugins mit Capability-Liste, begrenztem IPC und eigenem Runner-Prozess
StagingMinimal-Construct, recipient-verschlüsselte Stage-Antwort, authentifiziertes Chunking und Linux-Handover aus dem Speicher
LieferketteGetrennte OCI-Indizes für Constructs und Plugins, Cosign-Verifikation und lokale Operator-Signatur vor dem Deployment

Die sichtbaren Referenz-Plugins sind bewusst praktisch gewählt:

  • whoami ergänzt deck id um strukturierte Systeminformationen,
  • shell stellt eine begrenzte PTY-Session bereit,
  • portfwd demonstriert kontrollierte Mesh-Streams,
  • stage-2:fuchsia übernimmt den Sprung vom Minimal- zum Standard-Construct.

Ihre Namen sind Beispiele, keine eingebaute Autorisierungsliste. Entscheidend sind Paketformat, Zielplattform, Revision, signierte Capabilities und der Operator-Schlüssel.

Native Plugins: isoliert ist nicht eingesperrt#

Ein Plugin kommt zunächst als plattformspezifische Distribution. Beim Bezug aus der Registry prüft Deck zusätzlich die Herkunft aus dem Cosign-verifizierten OCI-Bundle; eine lokale Datei bleibt dagegen eine ausdrückliche Vertrauensentscheidung ohne diesen Herkunftsnachweis. In beiden Fällen validiert Deck Format, Architektur, ABI und Digest und erzeugt daraus im Speicher ein vom Operator signiertes Deployment-Paket. Der Construct prüft alles erneut, bevor er einen separaten Runner-Prozess startet.

Zwischen Host und Runner liegen begrenzte, authentifizierte Postcard-Nachrichten. Timeouts, kaputte Antworten, Panics und Prozessabstürze werden zu Plugin-Fehlern, ohne den Main-Task direkt mitzureißen. Die signierte Capability-Liste bestimmt, welche Actions das Paket aufrufen darf.

Das ist Prozessisolation, keine Sandbox. Der Runner begrenzt Fehlerausbreitung und Ressourcen, entzieht dem Plugin aber nicht die Dateisystem- oder Netzwerkberechtigungen des Betriebssystemkontos. Eine gültige Plugin-Signatur ist deshalb praktisch eine Autorisierung für nativen Code. Wer diesen Unterschied übersieht, missversteht die wichtigste Grenze des Plugin-Modells.

Staging: vom schmalen Erstkontakt zum vollen Construct#

Das Stage-System untersucht einen anderen Bootstrap-Fall: Was, wenn zunächst nur ein sehr kleiner Client laufen kann, der eigentliche Standard-Construct aber erst sicher nachgeladen werden soll?

Ein Minimal-Construct erzeugt beziehungsweise lädt seine Node-Identität, verbindet sich über TCP und denselben Noise-Identitätsbeweis mit dem autorisierten Stage-Issuer und sendet einen rollenbegrenzten Grant. Der Issuer konsumiert den Grant transaktional, wählt das passende signierte Stage-Paket und verschlüsselt die Antwort für genau den anfragenden Knoten. Große Antworten laufen durch das allgemeine Chunking mit Transfer-ID, Gesamtlänge und BLAKE3-Digest.

Der Client prüft Manifest, Signatur, Plattform, Länge, Digest und Recipient-Binding, bevor er entschlüsselt. Unter Linux landet der Klartext in einem memfd, das gegen Schreiben, Wachsen und Schrumpfen versiegelt und anschließend mit execveat gestartet wird. Eine zweite versiegelte Speicherdatei trägt den Handover-Zustand für NodeID, Bootstrap-Material und Runtime-Pfade.

Optional kann die signierte Stage-Antwort recipient-verschlüsselt zwischengespeichert werden. Auf dem Datenträger liegt dann nicht die ausführbare Klartext-Payload, sondern ein nur für diesen Node-Key brauchbarer Cache-Record. Ein gültiger Cache wird beim Neustart erneut vollständig geprüft, bevor daraus der Handover entsteht.

Windows-Stage-Artefakte bleiben bewusst deaktiviert. Ein reflektiver PE-Loader müsste Sections, Relocations, Imports, TLS- und Unwind-Strukturen korrekt verarbeiten und mit eigener Fuzz- sowie End-to-End-Abdeckung belegt sein. Solange diese Arbeit fehlt, wäre „unterstützt“ das falsche Wort.

Begrenzungen sind Teil des Protokolls#

Ein P2P-System verarbeitet fast alles, was ein entfernter Teilnehmer ihm schickt. Deshalb ist „bounded“ im Code kein Stilwort, sondern ein wiederkehrendes Konstruktionsprinzip:

  • Wire-v3-Nachrichten haben eine zentrale Versions- und Größenprüfung.
  • Größere logische Nachrichten werden in authentifizierte Chunks zerlegt.
  • Reassembly begrenzt Anzahl, Gesamtlänge und Lebenszeit eines Transfers.
  • DHT-, Peer-, Adress-, Capability- und Sessionmengen besitzen eigene Obergrenzen.
  • Befehle tragen monotone Nonces und landen in dauerhaft gespeicherten Replay-Fenstern.
  • Security-State wird authentifiziert, über eine temporäre Datei geschrieben, synchronisiert und atomar ersetzt.
  • Fehlgeschlagene Persistenz rollt die zugehörige In-Memory-Änderung zurück.

Diese Regeln machen das System nicht automatisch sicher. Sie sorgen aber dafür, dass Parser, State-Maschinen und Ressourcenverbrauch überhaupt in einer Form vorliegen, die sich testen und fuzz-en lässt.

Was fabric ausdrücklich nicht verspricht#

Eine Machbarkeitsstudie ist nur dann nützlich, wenn ihre Grenzen genauso deutlich sind wie ihre gelungenen Teile:

  • Keine Produktionsreife. Protokoll und Implementierung haben kein unabhängiges Audit erhalten.
  • Keine garantierte Selbstheilung. Routen werden revalidiert und tote Abhängigkeiten entfernt; ein vollständiger autonomer Wiederverbindungsplaner fehlt noch.
  • Keine Anonymität. Noise schützt Inhalte, nicht Adressen, Timing, Paketgrößen oder Beziehungsmetadaten. Padding und Transportvariation ändern daran grundsätzlich nichts.
  • Keine Plugin-Sandbox. Signierter nativer Code besitzt die Rechte des Construct-Accounts.
  • Keine gleichwertige Plattformabdeckung. Linux amd64 ist der praktisch erprobte Pfad; andere Ziele werden teilweise nur gebaut und statisch geprüft.
  • Keine harmlose Operator-Kompromittierung. Wer den Operator-Schlüssel kontrolliert, kontrolliert Befehle, Enrollment und Plugin-Deployment.
  • Kein zentraler Retter. Fällt eine Topologie auseinander, gibt es absichtlich keinen Controller mit einer vollständigen Sicht, der sie von außen rekonstruiert.

Gerade der letzte Punkt macht das Projekt interessant. In einem zentral verwalteten System ist „Healing“ oft nur ein anderer Name für „der Controller hat den gewünschten Zustand erneut durchgesetzt“. In einem P2P-Mesh muss jeder Knoten aus begrenzten, potenziell veralteten und teilweise feindlichen Beobachtungen selbst entscheiden, welche Verbindung er als Nächstes versucht. Das ist kein Reconcile-Loop mit schlechterem Empfang, sondern ein anderes Problem.

Was ich aus der Machbarkeitsstudie mitnehme#

fabric beantwortet seine Forschungsfrage nicht mit einem einfachen Ja. Es zeigt vielmehr, an welchen Stellen sich Selbstorganisation in überprüfbare Mechanismen zerlegen lässt.

Identität und Adresse zu trennen macht Seeds austauschbar, ohne Vertrauen austauschbar zu machen. Peer-Exchange und signierte Self-Records reichen aus, damit aus einem Erstkontakt ein wachsendes Lagebild entsteht. Alte Routen aktiv anzuzweifeln ist ein brauchbarer Anfang für Healing. Und ein einziger Besitzer des veränderlichen Policy-Zustands hält die daraus entstehende Komplexität lesbar.

Die offene Arbeit beginnt dort, wo Discovery in Handeln übergehen muss: Welchen neu entdeckten Peer wählt ein isolierter Knoten? Wie viele parallele Verbindungen sind genug? Wann ist ein Reconnect sinnvoll, wann bloß Flattern? Wie verhindert man, dass eine manipulierte Nachbarschaft alle Reparaturversuche auf dieselben Angreifer lenkt? Diese Fragen lassen sich nicht mit einem weiteren Fallback-Transport wegkonfigurieren.

Damit ist fabric genau das, was es sein soll: kein fertiges Fernadministrationsprodukt, sondern ein ausführbares Forschungsprojekt über ein P2P-Mesh, das lernen soll, sich selbst wiederzufinden. Einige Fäden tragen bereits. Andere enden sichtbar an der Kante des derzeit Machbaren. Und statt diese Kante hinter einem großen Architekturdiagramm zu verstecken, markiert der Code ziemlich genau, wo als Nächstes weitergewebt werden muss.

Der Quellcode und die vollständige technische Dokumentation liegen auf meinem Radicle-Seed . Gebaut und als signierte OCI-Artefakte veröffentlicht wird das Projekt über denselben CI-Broker , der auch den übrigen Stack versorgt.