Tor Snowflake Technischer Überblick einer anderen Funktion auf zensierte Webseiten und Anwendungen zuzugreifen

Tor Snowflake Technischer Überblick einer anderen Funktion auf zensierte Webseiten und Anwendungen zuzugreifen

Snowflake ist ein neuer WebRTC Pluggable Transport. Dieses Dokument bietet einen technischen Überblick über Snowflake in Bezug auf die Komponenten, Interaktionen und den Code des Systems. Die Absicht ist es, Snowflake dem technisch weniger versierten Leser vorzustellen, sowie denjenigen, die an einem Beitrag zu diesem Projekt und Internet Freedom im Allgemeinen interessiert sind. Insbesondere wird in diesem Dokument die Verwendung von WebRTC durch Snowflake, der Ansatz für Rendezvous unter Verwendung von Domain Fronting, die Methode zur Überwindung von NAT unter Verwendung von ICE-Negotiation und eine Reihe weiterer Überlegungen erörtert, ohne dass signifikante Vorkenntnisse zu diesen Themen vorausgesetzt werden. Snowflake und dieses Live-Dokument sind ein laufendes Projekt. Sobald sich das Snowflake-Projekt weiterentwickelt, wird dieses Dokument aktualisiert, und es werden zusätzliche Dokumente zur Verfügung gestellt, um Metriken, weitere Themen und andere relevante Ergebnisse angesichts der zukünftigen Arbeit an diesem Projekt zu diskutieren.

Inhalt:
1 Einleitung
2 Überblick
3 Snowflake-Umgehungsprozess
3.1 Verhalten von Pluggable Transport Clients
3.2 WebRTC-Verbindungsaufbau
3.3 Rendezvous
3.4 NAT-Überwindung
3.5 Wiederherstellung und Multiplexing
4 Beitrag

1 Einleitung
Snowflake ist ein neues Umgehungstool, das den Zugang zum freien und offenen Internet ermöglicht. Als Pluggable Transport bietet es einen einfach zu bedienenden Zugang zu einem Zensurumgehungssystem wie Tor. Es ist inspiriert von der früheren Arbeit von Flashproxy und baut darauf auf. Snowflake ist eine Mischung aus früheren Pluggable Transports, und dieses Dokument soll als Leitfaden für die Erforschung dieses Systems dienen.

Zur Veranschaulichung im Kontext von Tor: Snowflake erlaubt es jedem, einen Browser-Tab offen zu lassen, um eine ephemere Tor-Brücke zu werden. Ähnlich wie das Flashproxy-Design beinhaltet Snowflake ein großes Netzwerk von freiwilligen Proxys, mit dem Ziel, die Fähigkeit der Zensoren, Proxy-IP-Adressen zu blockieren, zu übertreffen und eine sehr einfach zu benutzende, zuverlässige und schwer zu filternde Methode zur Umgehung der Zensur zu bieten. Bisher war es für Benutzer schwierig, die Port-Weiterleitung manuell zu konfigurieren, was die Akzeptanz älterer Tools wie Flashproxy einschränkte. Snowflake löst das Problem des NAT-Traversals, indem es es automatisch macht und nicht in der Verantwortung des Benutzers liegt, und bietet eine Reihe neuer Vorteile.

Benutzerfreundlichkeit und Zuverlässigkeit sind für das Snowflake-System von großer Bedeutung, sowohl im Hinblick auf die Vereinfachung des Verbindungsaufbaus für Menschen in zensierten Regionen als auch im Hinblick auf die Möglichkeit für Freiwillige, anderen beim Verbindungsaufbau zu helfen. Dadurch kann das Umgehungsnetzwerk sowohl die Zahl der Freiwilligen als auch die Zahl der Kunden leichter erhöhen. Auf diese Weise wird das Snowflake-System in Bezug auf Umgehungskapazität, Bandbreite und Ausfallsicherheit mit der Größe des Freiwilligen-Netzwerks immer stärker.

2 Überblick
Am Beispiel von Tor kann die Abfolge der Interaktionen in einer Snowflake-Sitzung wie folgt aussehen:

Ein Benutzer in der gefilterten Region möchte auf das freie und offene Internet zugreifen. Er öffnet den Tor-Browser und wählt snowflake als Pluggable Transport. Dadurch wird der Snowflake-Client gestartet.
Freiwillige außerhalb der gefilterten Region besuchen Webseiten, die den Snowflake-Proxy-Code hosten. Die Browser dieser Freiwilligen werden dann zu temporären Proxys, die einem Snowflake-Client zur Verfügung stehen.
Der Snowflake-Client des gefilterten Benutzers findet automatisch einige dieser freiwilligen, entfernten, browserinternen Snowflake-Proxys mithilfe einer sicheren Rendezvous-Strategie, die auch NAT automatisch durchläuft.
Diese beiden Snowflake-Peers stellen eine Peer-to-Peer-Verbindung über WebRTC her.
Sobald WebRTC bereit ist, gibt der Snowflake-Client den WebRTC-Transport für die Nutzung durch Tor frei.
In der Zwischenzeit verbindet sich der Snowflake-Proxy des Freiwilligen mit einem Tor-Relay und beginnt, den Verkehr zwischen dem Snowflake-Client und dem Tor-Relay weiterzuleiten.
Tor baut einen Kreislauf auf und der Benutzer kann nun den Kreislauf umgehen.
Zur weiteren Verdeutlichung: Es ist nicht die Webseite, die Snowflake hostet, die als Snowflake-Proxy fungiert. Vielmehr ist es der Besucher der Website - sein Browser-Tab wird zum freiwilligen Proxy.

Snowflake umfasst drei Komponenten, die diesen Prozess ermöglichen:

Der Snowflake-Client, der ein Client-Transport-Plugin ist, das der Pluggable Transport Spezifikation (ptspec) entspricht. Tor benutzt es wie jeden anderen Pluggable Transport. Jedes andere ptspec-kompatible System kann das auch. Diese Komponente ist in Golang geschrieben.
Der Snowflake-Proxy ist ein Miniatur-WebRTC-Proxy im Browser. Er überträgt Daten zwischen Snowflake-Clients und einem Ziel - für Tor wäre das ein Tor-Relay. Diese Komponente ist in CoffeeScript geschrieben.
Der Broker, verantwortlich für Rendezvous. Er ist ähnlich wie der „Facilitator“ von Flashproxy, benutzt aber momentan ausschließlich Domain Fronting. Diese Komponente ist in Golang geschrieben.
Der Snowflake-Client und der Snowflake-Proxy können auch als Snowflake-Peers bezeichnet werden.

In Snowflake findet WebRTC nur zwischen den Snowflake-Peers statt: einem Snowflake-Client und einem Snowflake-In-Browser-Proxy, da WebRTC als Transportmittel für die Überwindung der Filtergrenze dient. Die Kommunikation vom Proxy zum Ziel erfolgt derzeit über einen Websocket. Die Kommunikation zum Broker erfolgt über HTTPS / Domain Fronting.

Hier ist ein Diagramm zur weiteren Veranschaulichung des Snowflake-Umgehungsprozesses:
Diese Prozesse und Komponenten sind mit vielen weiteren Details verbunden, die im Folgenden näher erläutert werden sollen:

3 Snowflake-Umgehungsprozess

3.1 Verhalten von Pluggable Transport Clients
Snowflake ist ein Pluggable Transport, der der Pluggable Transport Spezifikation entspricht.

Konkret enthält Snowflake das Client-Transport-Plugin, das einen Localhost-SOCKS-Server als Schnittstelle zwischen der Client-Anwendung und dem Transport bereitstellt. Im Kontext von Snowflake und Tor-Browser erstellt das Snowflake-Client-Transport-Plugin einen Localhost-SOCKS-Server, den die Client-Anwendung, Tor-Browser, als Proxy einstellt.

Der Snowflake-Client ist auch dafür verantwortlich, dass Verbindungen zu entfernten Snowflake-Proxies verfügbar sind, so dass der SOCKS-Server Anfragen des Tor-Browsers bearbeiten kann, indem er den Verkehr an einen Snowflake-Proxy weiterleitet. Es wird angenommen, dass diese entfernten Proxys den Verkehr an ein Tor-Relay weiterleiten, so dass das gesamte System das erwartete Verhalten als „WebRTC Transport“ für Tor erfüllt.

Bevor jedoch der Snowflake-Client den Transport nutzen kann, müssen der lokale Snowflake-Client und die Gegenstelle zuerst eine Verbindung über WebRTC aufbauen.

3.2 WebRTC-Verbindungsaufbau
WebRTC ist ein relativ neuer Standard, der eine robuste Peer-to-Peer-Echtzeitkommunikation ermöglicht, die das Streaming von Video-, Audio- und beliebigen Binärdaten umfasst. Für die Zwecke von Snowflake werden nur binäre Datenkanäle über WebRTC DataChannels verwendet, nicht jedoch Medienkanäle. WebRTC DataChannels verwenden SCTP und DTLS, um einen ziemlich zuverlässigen, verschlüsselten Transport zu gewährleisten. Natürlich gibt es hier noch viele andere Aspekte zu berücksichtigen, einschließlich, aber nicht beschränkt auf Fingerprinting. In Zukunft ist es möglich, dass die RTP-Medienkanäle von WebRTC als alternative Transportmittel nützlich sein könnten.

Ursprünglich war WebRTC nur entweder über die JavaScript-APIs in modernen Versionen von Chrome und Firefox oder über die C++-Bibliothek im nativen Code verfügbar. Für die Entwicklung von Snowflake war es notwendig, eine Golang-Bibliothek zu erstellen, die die C++-WebRTC-Bibliothek mit cgo anpasst.

3.2.1 Sitzungsbeschreibungen
Programme im Webbrowser können nicht passiv auf eingehende Verbindungen warten; sie müssen die ausgehende Verbindung initiieren. Da sowohl der Snowflake-Client als auch der Proxy WebRTC-Peers sind, die dieser besonderen Einschränkung unterliegen, muss es vor der Verbindung über WebRTC eine Möglichkeit für diese Peers geben, Signale zu senden und sich gegenseitig zu erkennen, um ihre WebRTC-PeerConnection zu starten. Diese Signalisierung über einen bidirektionalen Kommunikationskanal ist für jedes WebRTC-Szenario erforderlich, obwohl sie nicht in WebRTC selbst vorgesehen ist. Rendezvous ist nicht Teil des Anwendungsbereichs von WebRTC; von allen Nutzern der WebRTC-API wird erwartet, dass sie Rendezvous für ihren eigenen Anwendungsfall handhaben.

Für Snowflake beginnt dieser Prozess, wenn ein Snowflake-Client eine neue WebRTC-PeerConnection erstellt, die noch nicht mit einem entfernten Peer verbunden ist. Diese PeerConnection erstellt dann einen einzelnen DataChannel, der eine Reihe von Ereignissen auslöst, die ein lokales SDP-Angebot (Session Description Protocol) vorbereiten, so dass der Rendezvous-Prozess beginnen kann, der im Folgenden näher beschrieben wird. Dieses SDP-Angebot beschreibt in erster Linie den Peer und seine Fähigkeiten, zusammen mit Anweisungen für einen entfernten Peer, wie er den Client über das Netz erreichen kann.

Durch den Rendezvous-Prozess erreicht das SDP-Angebot des Snowflake-Clients einen Snowflake-Proxy, der als Antwort eine SDP-Antwort generiert, die ähnliche Informationen wie das SDP-Angebot enthält, aber stattdessen den Proxy beschreibt. Wenn Rendezvous erfolgreich ist, erhält der Snowflake-Client diese SDP-Antwort, und beide WebRTC-Endpunkte haben nun die SDP-Nachrichten des jeweils anderen. An diesem Punkt können die Snowflake-Peers nun versuchen, eine direkte Verbindung aufzubauen.

3.2.2 Fertigstellung der Schaltung
Bei Erfolg werden die WebRTC-PeerConnection und ihr DataChannel auf beiden Peers geöffnet und stehen für das Streaming von Bytes zur Verfügung. Der Snowflake-Client verdrahtet dann seinen DataChannel mit dem bereits erwähnten localhost SOCKS-Proxy, um den Transport für die Client-Anwendung freizugeben. Der Snowflake-Proxy stellt eine einfache Websocket-Verbindung zu einem Tor-Relay her. An diesem Punkt ist der WebRTC-Transport bereit und verfügbar und erlaubt beliebigen Benutzerverkehr oder zum Beispiel den Aufbau einer Tor-Verbindung.

Um jedoch erfolgreich eine WebRTC PeerConnection aufzubauen, müssen die oben beschriebenen SDP-Nachrichten korrekt und sicher zwischen den Peers übertragen werden. Hier gibt es noch viele weitere Überlegungen, da der Angreifer verschiedene Rendezvous-Strategien stören könnte.

3.3 Rendezvous
Rendezvous ist im Wesentlichen der Prozess, bei dem sich Clients und Proxys gegenseitig finden. Um zwei Snowflake-Peers zu verbinden, müssen Signalisierungsnachrichten ausgetauscht werden, die aus den oben beschriebenen SDP-Angeboten und -Antworten bestehen. Dadurch wissen die Peers, wo sie mit der Aushandlung einer P2P-Verbindung beginnen sollen.

3.3.1 Der Broker
In Snowflake wird das Rendezvous vom Broker verwaltet, einem Server, der auf einem Webservice eines Drittanbieters läuft. Der Broker ist dafür verantwortlich, Snowflake-Clients sicher mit Snowflake-Proxys zusammenzubringen, indem er SDP-Angebote und -Antworten zwischen ihnen austauscht und gleichzeitig eine Buchführung über die Snowflake-Peers führt. Eine beliebig große Anzahl von Proxies und Clients kann gleichzeitig an diesem Prozess mit dem Broker beteiligt sein, was eine zusätzliche Kontrolle erfordert, um den Broker skalierbar, robust und widerstandsfähig gegen DDoS zu halten und gleichzeitig sicher zu halten.

Ein einzelner Rendezvous-Prozess besteht aus einer Reihe ineinander verschachtelter HTTP-Anfragen.

1. Ein frischer Snowflake-Proxy sendet eine POST-Anfrage an den Broker als Long-Poll und zeigt damit an, dass er einen Client sucht, den er bedienen kann.
2. Ein Snowflake-Client sendet eine POST-Anfrage an den Broker, die sein SDP-Angebot enthält. Der Broker hält diese Anfrage offen und leitet das SDP-Angebot als Antwort auf eine der Subscribe-Polls des Snowflake-Proxys aus Schritt 1 weiter.
3. Der Snowflake-Proxy empfängt das SDP-Angebot und erstellt eine SDP-Antwort. Er sendet dann eine weitere POST-Anfrage an den Broker, die die Antwort als Antwort für den Client enthält, der das Angebot gesendet hat.
4. Der Broker leitet die SDP-Antwort als Antwort auf die POST-Anfrage an den ursprünglichen Snowflake-Client weiter.
5. Sowohl der Snowflake-Proxy als auch der Snowflake-Client verfügen nun über die SDP-Nachrichten des jeweils anderen, was ausreicht, um eine direkte WebRTC-PeerConnection aufzubauen. Wenn ein Schritt dieses Prozesses zu lange dauert, werden die Anfragen sicher abgebrochen, und die Snowflake-Peers versuchen es erneut.

Darüber hinaus setzt dieser Austausch von Signalisierungsnachrichten einen Weg voraus, der auch sehr resistent gegen Filter ist. Insbesondere wird davon ausgegangen, dass direkte Verbindungen zum Broker vom Client in der gefilterten Region durch den Angreifer blockiert werden, ohne die Funktionalität des Brokers zu beeinträchtigen. Dies ist durch das Domain Fronting möglich.

3.3.2 Domänen-Fronting
Ähnlich wie Meek, ein weiterer Pluggable Transport, verwendet Snowflake Domain Fronting. Domain Fronting ist eine auf Kollateralfreiheit basierende Methode der Umgehung. Sie macht sich HTTPS und das Verhalten großer Webdienste von Drittanbietern zunutze. Große Internetunternehmen wie Google, Amazon und Microsoft bieten Webdienste über CDNs (Content Delivery Networks) an, die auf ihre Bedürfnisse zugeschnitten sind. Diese CDNs stellen nicht nur ihre eigenen Webdienste bereit, sondern auch Dienste, die Benutzer auf ihren Plattformen hosten können, wie z. B. App Engine. Snowflake hostet den Broker derzeit auf App Engine, wird dies aber auch auf anderen Diensten tun.

Um die Verwendung von App Engine zu veranschaulichen, nehmen wir an, ein Snowflake Broker befindet sich auf snowflake-123.appspot.com, und nehmen wir an, der Zensor blockiert bereits direkte Verbindungen zu ihm. Wenn also ein Snowflake-Client mit diesem Broker kommunizieren möchte, öffnet er eine TLS-Verbindung nicht zu snowflake-123.appspot.com, sondern zu einer gültigen Root-Domäne, nämlich google.com. Die appengine-Instanz wird jedoch nur im Host-Header der HTTP-Anfrage angegeben, so dass die HTTP-Anfrage wie folgt aussieht:

GET / HTTP/1.1 host: snowflake-123.appspot.com
Wenn die Serving-Infrastruktur von Google diese Anfrage erhält, erkennt sie, dass sie die gewünschte App Engine-Instanz bereitstellen kann. (Wenn der Host-Header eine beliebige Adresse enthält, die über diese Domain nicht verfügbar ist, wird normalerweise eine Fehlermeldung wie 403 Forbidden zurückgegeben). Amazon und Microsoft können etwas Ähnliches mit ihren jeweiligen Diensten tun. Da die HTTP-Anfrage über TLS gesendet wird, kann der Zensor den Host-Header nicht sehen, also sieht die Anfrage wie eine harmlose Anfrage an google.com aus. Dies bedeutet, dass der Zensor den Broker nicht blockieren kann, ohne ganz Google oder ganz Amazon zu blockieren, was zu einer kollateralen Freiheit führt.

Eine umfassendere Darstellung von Domain Fronting finden Sie hier.

Da Snowflake Domain Fronting nur für das Rendezvous und nicht wie Meek für den Transport selbst verwendet, ist die Ressourcennutzung weitaus geringer, da die kurzen Signalisierungsnachrichten an den Broker aus weit weniger Bytes bestehen als der gesamte Nutzerverkehr. Dadurch werden die Kosten für Drittanbieter und CDN-Gebühren erheblich gesenkt, was die Skalierung des Tools zur Unterstützung von weitaus mehr Benutzern ermöglicht. Dies ist einer der beiden Hauptvorteile, die Snowflake gegenüber älteren Umgehungstools bietet.

3.4 NAT-Umgehung
Der zweite Hauptvorteil von Snowflake ist sein Ansatz zur NAT-Überwindung. Snowflake geht unter anderem davon aus, dass sich sowohl der Client als auch der Proxy hinter NAT (Network Address Translation) befinden und dass dies in der Verantwortung von Snowflake liegt.

Die meisten Geräte befinden sich hinter einem Router, der NAT implementiert, was weltweit weit verbreitet ist. Obwohl NAT verschiedene Vorteile bietet, wie z. B. die Überwindung der Adressraumbeschränkung von IPv4, führt es auch eine Barriere beim Aufbau von Peer-to-Peer-Verbindungen ein, die es schwieriger macht, einen direkten Weg zwischen Peers zu bestimmen.

Snowflake findet diesen Weg, ohne dass der Benutzer die Portweiterleitung manuell konfigurieren muss. Da die Umgehung von NAT nun automatisch erfolgt und nicht mehr in der Verantwortung des Benutzers liegt, werden die Probleme der Benutzerfreundlichkeit behoben, die die Akzeptanz früherer Umgehungstools eingeschränkt haben.

Automatisches NAT-Traversal in Snowflake ist dank ICE-Verhandlung möglich.

3.4.1 ICE-Verhandlung
Snowflake verwendet für die NAT-Überwindung die ICE-Verhandlung (Interactive Connectivity Establishment) von WebRTC.

Wenn ein Peer an ICE teilnimmt, sammelt er zunächst ICE-Kandidaten durch eine Reihe von Fallbacks. Jeder ICE-Kandidat ist eine lokale oder übersetzte öffentliche IP-Adresse, die es anderen Geräten ermöglichen könnte, sie entweder direkt, durch UDP-Lochung über STUN oder als letzten Ausweg über ein TURN-Relay zu erreichen. ICE erwartet dann, dass diese ICE-Kandidaten die Gegenstelle irgendwie erreichen. In WebRTC sind diese ICE-Kandidaten ein Bestandteil der SDP-Nachrichten, deren Zustellung durch den Rendezvous-Prozess über den oben erwähnten Broker abgewickelt wird. Sobald beide Peers die ICE-Kandidaten des jeweils anderen haben, probieren die Peers jeden ICE-Kandidaten aus, bis sie eine P2P-Verbindung aufbauen können.

3.4.2 Vorbehalte für STUN und TURN
Der ICE-Verhandlungsprozess führt zu weiteren Implikationen bezüglich der Verfügbarkeit von STUN- und TURN-Servern im öffentlichen Internet, da der Umgehungsprozess nun von der Verfügbarkeit mindestens eines dieser Server abhängt. STUN-Server sind öffentlich und relativ preiswert, so dass viele im öffentlichen Internet verfügbar sind. TURN-Server sind seltener und werden für etwa 10 % der Peer-Kombinationen benötigt, bei denen STUN nicht funktioniert, insbesondere in symmetrischen NAT-Fällen, die normales UDP-Hole-Punching verhindern.

Zurzeit ist Snowflake standardmäßig nur für die Verwendung von STUN konfiguriert. Die Einbeziehung von TURN-Servern in die Konfiguration ist trivial, wenn sie verfügbar sind.

Es ist zwar durchaus möglich, dass der Zensor auch STUN- und TURN-Server blockiert, aber diese Server werden typischerweise für jede Art von Peer-to-Peer-Verbindungsaufbau benötigt, der in verschiedenen anderen Domänen und Anwendungen üblich ist. Das bedeutet, dass STUN und TURN bereits ein gewisses Maß an kollateraler Freiheit mit sich bringen, aber es gibt keine Garantien dafür. Die Bereitstellung einer hochverfügbaren Population von nicht blockierten, leistungsfähigen STUN- und TURN-Servern für den Client bleibt eine Frage, die im Laufe der Einführung zu klären ist. Die Adressen der STUN- und TURN-Server können auch über einen Domain Fronted Channel bereitgestellt werden.

Um diesen verbleibenden 10 % der Nutzer eine gute Erfahrung zu bieten, sind wahrscheinlich weitere umfangreiche zukünftige Arbeiten mit TURN und Snowflake erforderlich.

3.5 Wiederherstellung und Multiplexing
Sobald snowflake WebRTC vorbereitet und als Pluggable Transport aktiviert hat, muss es auch in der Lage sein, sich schnell und zuverlässig wiederherzustellen, wenn die Verbindung getrennt wird. Dies ist in jedem Fall besonders wichtig, da davon ausgegangen wird, dass die Snowflake-Proxys kurzlebig sind.

Für den Snowflake-Client gibt es zwei primäre Möglichkeiten, wie der Transport ausfallen kann:

Der entfernte Snowflake-Proxy wird geschlossen, die Verbindung wird unterbrochen oder es tritt ein Fehler auf, weil der Freiwillige die Seite verlässt, die Registerkarte schließt, die Verbindung verliert oder ein anderes Szenario, das den WebRTC DataChannel aus der Ferne beendet.
Es liegt ein lokaler Fehler auf der SOCKS-Seite vor. Dies ist viel seltener.
In jedem Fall versucht snowflake, eine hohe Zuverlässigkeit und Konnektivität sowie eine hohe Qualität des Browsing-Erlebnisses für den Benutzer im Tor-Browser-Anwendungsfall aufrechtzuerhalten, indem snowflake-Clients und Proxies sich gegenseitig multiplexen. Wenn ein einzelner WebRTC DataChannel ausfällt, erneuert der Snowflake-Client die Verbindung mit einem neuen WebRTC-Peer. Wenn der WebRTC DataChannel aktiv als Transport verwendet wurde, löst der Snowflake-Client einen erneuten SOCKS-Handler aus, der den Transport auf einen anderen WebRTC DataChannel umstellt.

Die Anzahl der gemultiplexten WebRTC DataChannels, die auf dem Snowflake-Client gesucht und gepflegt werden sollen, kann mit dem Flag -max N konfiguriert werden.

4 Beitrag
Snowflake befindet sich in aktiver Entwicklung, und es ist noch viel Arbeit für die absehbare Zukunft erforderlich. Vieles davon ist in dem aktualisierten Snowflake OTF-Vorschlag beschrieben. Dazu gehören unter anderem reproduzierbare Builds, Audits, Metriken zur Nutzung und Akzeptanz, Fingerprinting des Datenverkehrs, eine Headless-Snowflake-Proxy-Implementierung, eine Browser-Erweiterungsimplementierung oder die Integration mit bestehenden Erweiterungen wie Cupcake sowie weitere Ergänzungen oder unabhängige Implementierungen für eine Vielzahl von Anwendungsfällen.

Wenn Sie dies lesen und begeistert oder neugierig darauf sind, Snowflakes Ansatz zur Internetfreiheit voranzutreiben, zögern Sie bitte nicht, Serene zu kontaktieren oder einen Pull-Request zu senden.