=head1 Freenet - Informationsfreiheit ohne Zensur, aber mit Perl =head2 Abstract Das Freenet-Projekt (http://www.freenetproject.org) hat es sich zur Aufgabe gemacht, jedem die die Möglichkeit freier Meinungsäußerung zu garantieren. Neben den Implementation einer Lösung für dieses Problem geht es in diesem Artikel darum, wie man in Perl selbst Informationen herunterlädt bzw. veröffentlicht. =head1 Einführung Das Freenet-Projekt (http://www.freenetproject.org) hat es sich zur Aufgabe gemacht, jedem die die Möglichkeit freier Meinungsäußerung zu garantieren. Als Mittel zur Umsetzung hat es ein virtuelles Netzwerk gewählt, in dem es nicht realistisch möglich sein wird, Einspeisung von neuen Daten zu verhindern oder den Urheber von Veröffentlichungen ausfindig zu machen, solange er dies nicht selbst zugibt. Darüberhinaus ist es für Betreiber von Freenet-Knoten nicht möglich, zu wissen, was auf ihrer Festplatte gespeichert wurde oder wo die Daten herstammen, so daß es ab einer bestimmten Netzwerkgröße nicht mehr möglich ist, dem Betreiber einer Freenet-Node nachzuweisen, daß er illegale Inhalte besitzt bzw. weitergegeben hat oder davon gewusst hat. In China beispielsweise wird eine frühe Version von Freenet für ein rein chinesisches Freenet-Netzwerk aktiv benutzt, um politische Inhalte verbreiten zu können ohne Maßnahmen von der Regierung zu befürchten. =head2 Freenet für den Benutzer Freenet speichert nur relativ kleine Dokumente (<= 1MB) am Stück. Diese Dokumente können beliebige Daten enthalten, z.B. HTML-Seiten. Dise Datenblöcke können mit einem für jeden Block eindeutigen Schlüssel abgerufen werden, z.B. in einem Web-Browser. Hier ist ein Beispiel für eine solche HTML-Seite: =for latex \begin{center}\includegraphics{freenet1.png}\end{center} Die hier verwendete URL ist C. C ist die Adresse meines Freenet-Daemons, üblicherweise C, der Sicherheit wegen sollte man immer einen eigenen Freenet-Daemon laufen lassen. Der Schlüssel der "Freesite" ist C und in dieser wird wiederum das Unterdokument C angezeigt. Diese Seite ist Teil eines sehr bekannten Einsprungpunktes ins Freenet. Generell bevorzugt das Freenet-Projekt keine bestimmten Einsprungpunkte. Die Regel ist: kennt man den Einsprungpunkt nicht, findet man die Inhalte nicht; es ist sogar unmöglich zu bestimmten, wieviel oder welche Informationen im Freenet gespeichert sind: Ein Index a'la google ist prinzipbedingt nicht möglich. Obwohl es einige Freenet-Spider und Directory-Freesites gibt ist der überwältigende Teil der Information im Freenet nicht darüber zu erreichen. Neben HTML-Inhalten gibt es auch Mail-, Foren- und Chat-Systeme im Freenet. Die Einspeisung von Daten kann von überall im Netz geschehen. Mehrfacheinspeisung ist möglich (und meistens notwendig) und erhöht führt nicht zur Dupliziering von Daten. Natürlic gibts es auch einige Nachteile, die teilweise mit dem Design und teilweise mit der Implementierung zusammenhängen. So ist der einzige verfügbare Freenet-Daemon in Java implementiert und daher leider extrem unportabel (läuft praktisch nur auf Linux/x86 und Windows, da das benötige Sun-Java-JDK auf andreen Platformen nicht verfügbar oder veraltet ist), sehr langsam und vor allem Speicherhungrig, und häufig auch sehr instabil. Die aktuellen Versionen des Freenet-Daemons sind alle als "nicht sicher" deklariert, da erst die Release 1.0 verspricht, alle Ideen umgesetzt zu haben, wovon das Projekt noch 0.5 Versionen entfernt ist :) Designbedingt ist das Freenet eher langsam (extrem hohe Latenz, akzeptabler Durchsatz) und für interkative Benutzung teilweise ungeeignet, bzw. eine echte Geduldsprobe. Durch die Art der Speicherung kann nicht garantiert werden daß Informationen überhaupt wiedergefunden werden. "Unpopuläre" Information verschwindet, sofern sie nicht regelmäßig eingespeist oder abgerufen wird, automatisch wieder aus dem Freenet. =head2 Die Freenet-Architektur Herkömmliche File-Sharing-Netzwerke haben zwei Große Nachteile: Entweder sind sie nicht wirklich anonym (selbst anonymisierende Netzwerke oder Proxies sind üblicherweise nicht vor Zugriff durch Regierungen sicher (ein bekanntes Beispiel ist I, C, das zwar vollmundig vollkommene Anonymität garantiert aber schoneinmal durch die Polizei gezwungen wurde, Log-Informationenen herauszugeben, wozu die Betreiber nach deutschen Recht verpflichtet sind). Oder sie skalieren nicht, da sie Broadcast-Algorithmen benutzen die größere Netzwerke von vorneherein ausschließen (bekanntes Beispiel dafür ist I). Das erste Problem umgeht Freenet (Achtung, vereinfacht!), indem es jeden Datenblock hasht und aus diesem Hash einen Schlüssel für die Verschlüsselung generiert und die Daten damit verschlüsselt (sic). Der Schlüssel wird ein zweitesmal gehasht. Dieser Hash wird zur eindeutigen ID des Datenblocks. Diese ID und der verschlüsselte Datenblock werden ins Freenet eingespeist. Dabei, wird immer derselbe Key generiert (da er nur von den Daten abhängt) und der verschlüsselte Block ist ebenfalls immer gleich. Daher kann er problemlos mehrfach und von unterschiedlichen Parteien eingespeist werden ohne die Daten faktisch mehrfach im Freenet abzulegen. Das ist sicher, da ein kryptographisch sicherer Hash (der die Grundlage des Systems bilden muß) nur in eine Richtung funktioniert: Aus der ID (== Hash des Hashes der Daten) kann nicht auf den Schlüssel geschlossen werden. Speichert also ein Netzknoten die Daten und die ID dazu, kann man die Daten zwar abrufen, jedoch nicht entschlüsseln. Selbst der Besitzer eines Knotens kann mit vollkommenen Wissen über alle Vorgänge seines Knotens die Inhalte nicht lesen. Eine weitere Konsequenz dieses Verfahrens ist die Tatsache, das Dokumente niemals verändetr werden können: eine Änderung bewirkt eine Änderung des Schlüssels und damit eine neue ID, praktisch eine völlig neue URL. Möchte man z.B. das grüne Blatt der Freesite "Thought Crime" herunterladen so wird man mit folgendem Freenet-Key konfrontiert: CHK@pfAv9IejYPLQwaTLXDguEkUhiNUMAwI,blzDbhN~8Q28esq4JrfRWw C steht für I, der häufigste Schlüsseltyp im Freenet, der das oben beschriebene Verfahren benutzt. Der CHK besteht aus zwei Teilen: der ID, unter der der Schlüssel im Freenet abgelegt wird (C) und dem Schlüssel, mit dem die Daten verschlüsselt wurden (C), durch ein Komma getrennt. Das sind übrigens (mehr oder weniger) base64-encodete Daten, dekodiert sieht der Schlüssel so aus: CHK@ ID = a5f02ff487a360f2d0c1a4cb5c382e12452188d50c0302 Key = 6e5cc36e137ef10dbc7acab826b7d15b (Man kann daraus tatsächlich ablesen, das der Datenblock 4k groß (0x0c am Ende der ID bedeutet 2**12) ist und Twofish benutzt. Aber derartige Details überläßt man lieber einem Perl-Modul). Nur der erste Teil wird als Anfrage ins Freenet geschickt, der zweite Teil bleibt im lokalen Freenet-Daemon. Wird nun der Datenblock geliefert, kann er mit dem Schlüssel dekodiert werden und wird an den Benutzer geliefert. Das zweite Problem (der Skalierbarkeit) wird durch lineare statt exponentielle Suche gelöst: mit jeder Anfrage wird eine I-Angabe (HTL, ähnlich wie das TTL in IPv4) verknüpft. Diese Zahl, die üblicherweise zwischen 5 und 25 (maximal) liegt, gibt an, wie viele Knoten die Anfrage maximal weitergeleitet wird. Jeder Knoten, der die Daten nicht lokal vorrätig hat, leitet sie an denjenigen Knoten weiter, der die Daten am wahrscheinlichsten hat. Da das Verfahren linear ist und nicht exponentiell, skaliert es ebenfalls linear mit der Netzwerkgröße. Lädt man das Dokument, wird man mit Metadaten und "normalen" Daten konfrontiert. Metadaten: Revision=1 EndPart Document Info.Format=image/png End Daten: PNG^Z... Nun stellt sich die Frage, wie man sicherstellt, daß Daten im Freenet bleiben, da es nur endliche Speicherkapazität hat. Die Antwort ist überraschend: Es geht nicht. Wenn ein Knoten sich entscheidet, Daten zu löschen oder Platz für neue Daten zu schaffen, gehen zwangsläufig andere Daten verloren. Dagegen hilft nur wiederholtes Einfügen und der Wunsch, daß die eigenen Daten beliebt genug sind, damit sie abgerufen werden und damit länger überleben. Absolute Anonymität und nichtnachvollziehbarkeit von Transaktionen ist eben nicht vereinbar mit garantierter Datenspeicherung. Könnte man garantiert Nachweisen, das ein Dokument existiert, so wäre es für einen Knotenbetreiber schlecht möglich, Wissen über die Art der Daten abzustreiten, die er speichert. =head3 SSK-Schlüssel Der zweite gebräuchliche Schlüsseltyp, mit dem man im Freenet konfrontiert wird, ist ein C-Schlüssel (C steht für I). Hier ist einer: SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM Zwei Dinge unterscheiden Sie von CHK-Schlüsseln: Erstens ist ein SSK-Schlüssel eigentlich ein Schlüsselpaar, ein Schlüssel (der private Schlüssel) muss für das Einfügen von Daten benutzt werden, der zweite Schlüssel (der öffentliche Key) wird für das Auslesen der Daten benutzt. Da die Daten signiert sind, kann nur der oder die Besitzer des privaten Schlüssels Daten unter diesem einfügen, während die Besitzer des öffentlichen Schlüssels überprüfen könenn, ob die Daten tatsächlich mit dme richtigen Schlüssel signiert wurden. Zweitens ist die ID, unter dem diese Date abgelegt werden, nicht von den Daten sondern nur vom "Namen" (dem Key) abhängig, man kann also URIs erzeugen auf Dateien, die noch nicht eingefügt wurden. Diese Art Schlüssel ist relativ ineffizient und kann keine großen Datenmengen speichern (<= 32KB!), SSKs werden also vorwiegend für Weiterleitungen auf CHKs benutzt. Der obige SSK gehört übrigens zur "Freenet Explained"-Freesite, die die einzelnen Schlüsseltypen (und mehr) erklärt. Finden kann man sie hier: SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// bzw., wenn man einen Freenet-Daemon am Laufen hat, hier: http://127.0.0.1:8888/SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// =head1 Und das ganze in Perl Das ganze wäre relativ witzlos, wenn man nur irgendwelche langweiligen Tools und/oder Java benutzen kann. Es gibt zwei Perl-Module (bzw. Modulfamilien), C (C) und C. Ersteres ist älter (und vielleicht besser benannt) und konzentriert sich mehr auf die Verarbeitung von Metadaten, ist aber recht schwach beim eigentlichen Protokoll-Handling. Letzteres ist sehr gut beim Protokoll-Handling und stark beim Kodieren und Dekodieren von Daten, überläßt das Metadatenhandling aber dem Programmierer. C stammt von mir und ist entstanden, weil ich das andere Modul, die es nur im Freenet gab, nicht herunterladen konnte (tja, so ist das eben als Freenetter). Daher gehe ich auch nur auf dieses Module ein :) =head2 Installation Zuerst braucht man einen Freenet-Daemon (http://www.freenetproject.org/). Die Installation ist unglaublich komplex (unter Windows gibt es einen Installer, unter Unix ein paar Skripte). Der Daemon braucht eine Weile, bis er warm wird (Minuten bis Stunden), was man durch Surf-Versuche unterstützen sollte. Das C-Paket gibt es ganz normal per CPAN. =head2 Einfache Abfragen Die Abkürzung I steht für I und ist das Protokoll zwischen Freenet-Anwedungen und dem Freenet-Daemon. Es ist unglaublich ineffizient und noch dazu nicht verschlüsselt. Dies ist der Grund für die Empfehlung, den Daemon nur auf dem lokalen Rechner laufen zu lassen: Wäre dumm, wenn man aus dem hochsicheren Freenet über eine ungesicherte Internetverbindung die Windows-Sourcen herunterlädt und sicher erwischen läßt (ist alles schon vorgekommen)... In Perl geht dies denkbar einfach: use Net::FCP; my $fcp = new Net::FCP; Man kann dem Konstruktor von C direkt Namen und Port des Freenet-Daemons übergeben. Üblicherweise holt er sich diese aber aus dne Environment-Variablen C und C, die auf C<127.0.0.1> bzw. C<8481> defaulten. Übrigens wird nur eine virtuelle Verbindung aufgebaut. Möchte man sicherstellen, daß tatsächlich ein Daemon erreichbar ist, kann man einen C-Request ausführen oder einfach loslegen. Im Normalfall heißt das also:: no configuration required. Hat man ein C-Objekt, kann man schon alle Requests durchführen, die man amchen möchte: my ($meta, $data) = @{ $fcp->client_get ( "freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//" 15 ) }; Der C-Request erwartet zwei Argumente: eine Freenet-URI (C<< freenet: >>) und eine HTL. Letztere muss man nicht angeben, man sollte es aber, und vor allem sollte man dem Benutzer die Wahl der HTL überlassen. Das dritte, optionale, Argument ist für spezielle Anwendungen: am besten ignorieren. Als Ergebnis erhält man immer eine Array-Referenz mit den Metadaten und den Daten. Immer. Sollte ein Fehler auftreten wird eine Exception ausgelöst (auf Perl: das Modul Cd). C hilft also im Zweifelsfalle, für einfache Anwendungen ist das aber overkill. Bricht das Programm ab, so sieht das folgendermaßen aus: Net::FCP::Exception<> Oder, wenn die Daten nicht gefunden wurden: Net::FCP::Exception<> Letzteres bedeutet übrigens nicht aufgeben, sondern nochmal versuchen, z.B. mit einer höheren HTL. Ein fehlgeschlagener Versuch mit hoher HTL bedeutet imemr noch nicht aufgeben. Daemons in der "Nähe" wissen nun, das die Daten verlangt werden. Nach einiger Zeit ist es wahrscheinlich, das die Daten auf einmal in der Nähe liegen: daher nie aufgeben, nochmal probieren. Niemand hat behauptet, man bekäme die Daten einfach aus dem Freenet wieder heraus... Die Metadaten sind als Textdokument gespeichert. das Parsen dieser Metadaten ist aber relativ krank, weshalb das Perl-Modul einen Hash mit den geparsten Daten liefert. Die Metadaten und Daten kann man ausgeben: use Data::Dumper; print STDERR Dumper $meta; print $data; Dies ist genau der Quelltext für das "Tool" C, mit dem man I Freenet-Datenblock herunterladen kann. Ich benutze es üblicherweise so: eg/fetch1 SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// >data Das schreibt die Daten in eine Datei und gibt gleichzeitig dessen Metadaten aus. Für den Key C ergibt dies: 'version' => { 'revision' => '1' }, 'document' => [ { 'info' => { 'format' => 'image/png' }, 'redirect' => { 'target' => 'freenet:CHK@pMKWiJyE3t-ZWvL1W9VdZvB3jcIKAwI,7pdyQiW7Hp9-8fEp-25C2w' }, 'name' => 'activelink.png' }, { 'info' => { 'format' => 'text/plain' }, 'redirect' => { 'target' => 'freenet:CHK@2hewSY-I5ZhWpJ84dwhPbtdlvyIKAwI,ovcsrpD79xZfoW2021z91w' }, 'name' => 'description.txt' }, { 'info' => { 'format' => 'text/html' }, 'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' }, 'name' => 'index.html' }, { 'info' => { 'format' => 'text/html' }, 'redirect' => { 'target' => 'freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4' }, 'name' => '.next' }, { 'info' => { 'format' => 'text/html' }, 'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' } } ], 'raw' => 'Version Revision=1 [... gekürzt...] Info.Format=text/html End ' }; Die eigentlichen Daten sind leer (Null Byte gross), das Dokument enthät also nur Metadaten! Man beachte vor allem die teilweise recht tiefe Verschachtelung. Der Key C<< $metadata->{raw} >> enthält die Metadaten, wie sie vom Freenet kamen. Dies ist notwendig, da man manchmal die Metadaten zum Prüfen in der exkaten Form benötigt, wie sie hochgeladen wurden. Ansonsten kann man sie ignorieren. Der Key C<< $metadata->{document} >> enthält Informationen über das Dokument oder in diesem Fall die Dokumente: Ein Hash pro Dokument. Schaut man sich den Inhalt an (ein Array), so sieht man in jedem Hash ein C-Key, der den Namen des Subdokuments angibt (bis auf den letzten, darauf komme ich gleich). Schaut man sich dir Freenet-URIs dieser Freesite an, so sieht man derartige URIs: SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// # Hauptseite SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//activelink.png # Icon SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//description.txt # Beschreibung für Spider Wenn diese Dokumente mit C anfordert, bekommt man immer obiges Dokument. Freenet ignoriert nämlich alles, was hinter dem C steht und liefert daher immer das gleiche Dokument aus dem SSK-Bereich. (Darauf verlassen soltle man sich nicht unbedingt, in Zukunft reagiert der Freenet-Daemon vielleicht anders. Als Freenetter hat mans eben nicht leicht). Der Teil hinter den beiden Slashes (C) ist nun das Unterdokument, das man über den Namen identifizieren kann: $activelink = grep $_->{name} eq "activelink.png", @{ $metadata->{document} }; Fehlet der C-Eintrag ist es der Eintrag mit dem leeren Namen, in diesem Fall der erste Link, der nichts nach den C stehen hat. Der C-Key I vorhanden und leer sein: Freenet überprüft die Daten nicht, daher gibt es durchaus unterschiedliche Auslegungen für das genau Format. Die Metadaten sind etwas genauer in dem *hüstel* etwas veralteten *hüstel* I-Dokument beschrieben. Möchte man nun das C herunterladen muss man in C<< $activelink->{redirect} >> nachsehen. Meistens verweist dies auf ein C-Schlüssel. Letztere sind sozusagen Allgemeingut: jeder kann sie benutzen, und da sie nicht änderbar sind, kann sie auch niemand fälschen, daher muss man sie nicht signieren. Auf C<< $activelink->{info}{format} > sollte man sich übrigens nicht verlassen. Und sollte kein C-Key vorhanden sein, so ist das Dokument im mitgelieferten Datenblock. Alles ganz logisch, einfach, und klar, wie man sieht. Egal, der CHK-Key für C liefert folgendes: 'version' => { 'revision' => '1' }, Und die Daten stellen ein PNG dar. Naja, nicht gerade üppig, die Metadaten, aber man hätt's ja im Link auf dieses Dokument sehen können. Als Freenetter hat mans nicht leicht. Aber mit diesen Erklärungen kann man schon einfacher Freenet-Spider bauen. Die wichtigsten Tools sind veraltete und spärliche Dokumente wie I und Tools wie C. "Veraltet" ist übrigens nicht immer schlecht, da viele Dokumente auch alt sind oder sich eh' nicht exakt an den "Standard" halten. Mit der Zeit wird hier sicher eine Besserung eintreten. =head2 Methoden des Freesite-Managements Oder: "Wenn man Inhalte nicht mehr verändern kann, wie verändert man sie?" Die offensichtliche Methode ist: "Man macht sie veränderbar". In der Freenet-Gemeinde geistert seit langer Zeit der Mythos des I-Schlüssels, des I