ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/docs/pws2004/freenet.pod
Revision: 1.11
Committed: Tue May 18 00:22:26 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.10: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.11 =encoding utf8
2    
3 root 1.1 =head1 Freenet - Informationsfreiheit ohne Zensur, aber mit Perl
4    
5     =head2 Abstract
6    
7 root 1.2 Das Freenet-Projekt (http://www.freenetproject.org) hat es sich zur
8     Aufgabe gemacht, jedem die die Möglichkeit freier Meinungsäußerung zu
9 root 1.10 garantieren. Neben der Implementierung einer Lösung für dieses Problem
10     durch das Projekt geht es in diesem Artikel darum, wie man in Perl selbst
11     Informationen herunterlädt bzw. veröffentlicht.
12 root 1.2
13     =head1 Einführung
14    
15     Das Freenet-Projekt (http://www.freenetproject.org) hat es sich zur
16     Aufgabe gemacht, jedem die die Möglichkeit freier Meinungsäußerung
17     zu garantieren. Als Mittel zur Umsetzung hat es ein virtuelles Netzwerk
18     gewählt, in dem es nicht realistisch möglich sein wird, Einspeisung
19     von neuen Daten zu verhindern oder den Urheber von Veröffentlichungen
20     ausfindig zu machen, solange er dies nicht selbst zugibt. Darüberhinaus
21     ist es für Betreiber von Freenet-Knoten nicht möglich, zu wissen, was
22     auf ihrer Festplatte gespeichert wurde oder wo die Daten herstammen, so
23     daß es ab einer bestimmten Netzwerkgröße nicht mehr möglich ist,
24     dem Betreiber einer Freenet-Node nachzuweisen, daß er illegale Inhalte
25     besitzt bzw. weitergegeben hat oder davon gewusst hat.
26    
27     In China beispielsweise wird eine frühe Version von Freenet für ein
28     rein chinesisches Freenet-Netzwerk aktiv benutzt, um politische Inhalte
29 root 1.9 verbreiten zu können, ohne Maßnahmen von der Regierung zu befürchten.
30 root 1.2
31     =head2 Freenet für den Benutzer
32    
33 root 1.4 Freenet speichert nur relativ kleine Dokumente (<= 1MB) am Stück. Diese
34 root 1.2 Dokumente können beliebige Daten enthalten, z.B. HTML-Seiten. Dise
35     Datenblöcke können mit einem für jeden Block eindeutigen Schlüssel
36     abgerufen werden, z.B. in einem Web-Browser.
37    
38     Hier ist ein Beispiel für eine solche HTML-Seite:
39    
40 root 1.7 =for latex
41     \begin{center}\includegraphics{freenet1.png}\end{center}
42 root 1.2
43     Die hier verwendete URL ist C<http://129.13.162.73:8888/SSK@Sc6qV~D6iFhaYord6HtbjJ8MaEYPAgM/YoYo//Controversy.html>.
44     C<http://129.13.162.73:8888> ist die Adresse meines Freenet-Daemons,
45     üblicherweise C<http://127.0.0.1:8888>, der Sicherheit wegen sollte man
46     immer einen eigenen Freenet-Daemon laufen lassen. Der Schlüssel der
47     "Freesite" ist C<SSK@Sc6qV~D6iFhaYord6HtbjJ8MaEYPAgM> und in dieser wird
48     wiederum das Unterdokument C<YoYo//Controversy.html> angezeigt.
49    
50     Diese Seite ist Teil eines sehr bekannten Einsprungpunktes ins
51     Freenet. Generell bevorzugt das Freenet-Projekt keine bestimmten
52     Einsprungpunkte. Die Regel ist: kennt man den Einsprungpunkt nicht, findet
53     man die Inhalte nicht; es ist sogar unmöglich zu bestimmten, wieviel oder
54     welche Informationen im Freenet gespeichert sind: Ein Index a'la google
55     ist prinzipbedingt nicht möglich.
56    
57     Obwohl es einige Freenet-Spider und Directory-Freesites gibt ist der
58     überwältigende Teil der Information im Freenet nicht darüber zu
59     erreichen.
60    
61     Neben HTML-Inhalten gibt es auch Mail-, Foren- und Chat-Systeme im
62     Freenet.
63    
64     Die Einspeisung von Daten kann von überall im Netz
65     geschehen. Mehrfacheinspeisung ist möglich (und meistens notwendig) und
66     erhöht führt nicht zur Dupliziering von Daten.
67    
68     Natürlic gibts es auch einige Nachteile, die teilweise mit dem Design
69     und teilweise mit der Implementierung zusammenhängen. So ist der einzige
70     verfügbare Freenet-Daemon in Java implementiert und daher leider extrem
71     unportabel (läuft praktisch nur auf Linux/x86 und Windows, da das
72     benötige Sun-Java-JDK auf andreen Platformen nicht verfügbar oder
73     veraltet ist), sehr langsam und vor allem Speicherhungrig, und häufig
74     auch sehr instabil.
75    
76     Die aktuellen Versionen des Freenet-Daemons sind alle als "nicht sicher"
77     deklariert, da erst die Release 1.0 verspricht, alle Ideen umgesetzt zu
78     haben, wovon das Projekt noch 0.5 Versionen entfernt ist :)
79    
80     Designbedingt ist das Freenet eher langsam (extrem hohe Latenz,
81     akzeptabler Durchsatz) und für interkative Benutzung teilweise
82     ungeeignet, bzw. eine echte Geduldsprobe.
83    
84     Durch die Art der Speicherung kann nicht garantiert werden daß
85     Informationen überhaupt wiedergefunden werden. "Unpopuläre" Information
86     verschwindet, sofern sie nicht regelmäßig eingespeist oder abgerufen
87     wird, automatisch wieder aus dem Freenet.
88    
89     =head2 Die Freenet-Architektur
90    
91     Herkömmliche File-Sharing-Netzwerke haben zwei Große Nachteile: Entweder
92     sind sie nicht wirklich anonym (selbst anonymisierende Netzwerke oder
93     Proxies sind üblicherweise nicht vor Zugriff durch Regierungen sicher
94     (ein bekanntes Beispiel ist I<JAP>, C<http://anon.inf.tu-dresden.de>, das
95 root 1.3 zwar vollmundig vollkommene Anonymität garantiert aber schoneinmal durch
96     die Polizei gezwungen wurde, Log-Informationenen herauszugeben, wozu die
97     Betreiber nach deutschen Recht verpflichtet sind). Oder sie skalieren
98     nicht, da sie Broadcast-Algorithmen benutzen die größere Netzwerke von
99     vorneherein ausschließen (bekanntes Beispiel dafür ist I<gnutella>).
100 root 1.2
101     Das erste Problem umgeht Freenet (Achtung, vereinfacht!), indem es
102     jeden Datenblock hasht und aus diesem Hash einen Schlüssel für die
103     Verschlüsselung generiert und die Daten damit verschlüsselt (sic).
104    
105     Der Schlüssel wird ein zweitesmal gehasht. Dieser Hash wird zur
106     eindeutigen ID des Datenblocks. Diese ID und der verschlüsselte
107     Datenblock werden ins Freenet eingespeist. Dabei, wird immer derselbe
108     Key generiert (da er nur von den Daten abhängt) und der verschlüsselte
109     Block ist ebenfalls immer gleich. Daher kann er problemlos mehrfach und
110     von unterschiedlichen Parteien eingespeist werden ohne die Daten faktisch
111     mehrfach im Freenet abzulegen.
112    
113     Das ist sicher, da ein kryptographisch sicherer Hash (der die Grundlage
114     des Systems bilden muß) nur in eine Richtung funktioniert: Aus der ID
115     (== Hash des Hashes der Daten) kann nicht auf den Schlüssel geschlossen
116     werden. Speichert also ein Netzknoten die Daten und die ID dazu, kann man
117     die Daten zwar abrufen, jedoch nicht entschlüsseln. Selbst der Besitzer
118     eines Knotens kann mit vollkommenen Wissen über alle Vorgänge seines
119     Knotens die Inhalte nicht lesen.
120    
121     Eine weitere Konsequenz dieses Verfahrens ist die Tatsache, das Dokumente
122     niemals verändetr werden können: eine Änderung bewirkt eine Änderung
123     des Schlüssels und damit eine neue ID, praktisch eine völlig neue URL.
124    
125     Möchte man z.B. das grüne Blatt der Freesite "Thought Crime" herunterladen so
126     wird man mit folgendem Freenet-Key konfrontiert:
127    
128     CHK@pfAv9IejYPLQwaTLXDguEkUhiNUMAwI,blzDbhN~8Q28esq4JrfRWw
129    
130     C<CHK> steht für I<Content-Hash-Key>, der häufigste Schlüsseltyp im
131     Freenet, der das oben beschriebene Verfahren benutzt. Der CHK besteht
132     aus zwei Teilen: der ID, unter der der Schlüssel im Freenet abgelegt
133     wird (C<pfAv9IejYPLQwaTLXDguEkUhiNUMAwI>) und dem Schlüssel, mit dem die
134     Daten verschlüsselt wurden (C<blzDbhN~8Q28esq4JrfRWw>), durch ein Komma
135     getrennt.
136    
137     Das sind übrigens (mehr oder weniger) base64-encodete Daten, dekodiert
138     sieht der Schlüssel so aus:
139    
140     CHK@
141     ID = a5f02ff487a360f2d0c1a4cb5c382e12452188d50c0302
142     Key = 6e5cc36e137ef10dbc7acab826b7d15b
143    
144     (Man kann daraus tatsächlich ablesen, das der Datenblock 4k groß (0x0c
145     am Ende der ID bedeutet 2**12) ist und Twofish benutzt. Aber derartige
146     Details überläßt man lieber einem Perl-Modul).
147    
148     Nur der erste Teil wird als Anfrage ins Freenet geschickt, der zweite Teil
149     bleibt im lokalen Freenet-Daemon. Wird nun der Datenblock geliefert, kann
150     er mit dem Schlüssel dekodiert werden und wird an den Benutzer geliefert.
151    
152     Das zweite Problem (der Skalierbarkeit) wird durch lineare
153     statt exponentielle Suche gelöst: mit jeder Anfrage wird eine
154     I<Hops-To-Live>-Angabe (HTL, ähnlich wie das TTL in IPv4)
155     verknüpft. Diese Zahl, die üblicherweise zwischen 5 und 25 (maximal)
156     liegt, gibt an, wie viele Knoten die Anfrage maximal weitergeleitet
157     wird. Jeder Knoten, der die Daten nicht lokal vorrätig hat, leitet sie an
158     denjenigen Knoten weiter, der die Daten am wahrscheinlichsten hat. Da das
159     Verfahren linear ist und nicht exponentiell, skaliert es ebenfalls linear
160     mit der Netzwerkgröße.
161    
162     Lädt man das Dokument, wird man mit Metadaten und "normalen" Daten
163     konfrontiert.
164    
165     Metadaten:
166    
167     Revision=1
168     EndPart
169     Document
170     Info.Format=image/png
171     End
172    
173     Daten:
174    
175     PNG^Z...
176    
177     Nun stellt sich die Frage, wie man sicherstellt, daß Daten im Freenet
178     bleiben, da es nur endliche Speicherkapazität hat. Die Antwort ist
179     überraschend: Es geht nicht. Wenn ein Knoten sich entscheidet, Daten
180     zu löschen oder Platz für neue Daten zu schaffen, gehen zwangsläufig
181     andere Daten verloren. Dagegen hilft nur wiederholtes Einfügen und der
182     Wunsch, daß die eigenen Daten beliebt genug sind, damit sie abgerufen
183     werden und damit länger überleben.
184    
185     Absolute Anonymität und nichtnachvollziehbarkeit von Transaktionen ist
186     eben nicht vereinbar mit garantierter Datenspeicherung. Könnte man
187     garantiert Nachweisen, das ein Dokument existiert, so wäre es für
188     einen Knotenbetreiber schlecht möglich, Wissen über die Art der Daten
189     abzustreiten, die er speichert.
190    
191     =head3 SSK-Schlüssel
192    
193     Der zweite gebräuchliche Schlüsseltyp, mit dem man im Freenet
194     konfrontiert wird, ist ein C<SSK>-Schlüssel (C<SSK> steht für I<Signed
195     Subspace Key>). Hier ist einer:
196    
197     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM
198    
199     Zwei Dinge unterscheiden Sie von CHK-Schlüsseln:
200    
201     Erstens ist ein SSK-Schlüssel eigentlich ein Schlüsselpaar, ein
202     Schlüssel (der private Schlüssel) muss für das Einfügen von Daten
203     benutzt werden, der zweite Schlüssel (der öffentliche Key) wird für
204     das Auslesen der Daten benutzt. Da die Daten signiert sind, kann nur der
205     oder die Besitzer des privaten Schlüssels Daten unter diesem einfügen,
206     während die Besitzer des öffentlichen Schlüssels überprüfen könenn,
207     ob die Daten tatsächlich mit dme richtigen Schlüssel signiert wurden.
208    
209     Zweitens ist die ID, unter dem diese Date abgelegt werden, nicht von den
210     Daten sondern nur vom "Namen" (dem Key) abhängig, man kann also URIs
211     erzeugen auf Dateien, die noch nicht eingefügt wurden.
212    
213     Diese Art Schlüssel ist relativ ineffizient und kann keine großen
214 root 1.5 Datenmengen speichern (<= 32KB!), SSKs werden also vorwiegend für
215     Weiterleitungen auf CHKs benutzt.
216 root 1.2
217     Der obige SSK gehört übrigens zur "Freenet Explained"-Freesite, die die
218     einzelnen Schlüsseltypen (und mehr) erklärt. Finden kann man sie hier:
219    
220     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//
221    
222     bzw., wenn man einen Freenet-Daemon am Laufen hat, hier:
223    
224     http://127.0.0.1:8888/SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//
225    
226     =head1 Und das ganze in Perl
227    
228     Das ganze wäre relativ witzlos, wenn man nur irgendwelche
229     langweiligen Tools und/oder Java benutzen kann. Es gibt
230     zwei Perl-Module (bzw. Modulfamilien), C<Net::Freenet::FCP>
231     (C<http://www.sf.net/projects/perlfcp>) und C<Net::FCP>.
232    
233     Ersteres ist älter (und vielleicht besser benannt) und konzentriert
234     sich mehr auf die Verarbeitung von Metadaten, ist aber recht schwach
235     beim eigentlichen Protokoll-Handling. Letzteres ist sehr gut beim
236     Protokoll-Handling und stark beim Kodieren und Dekodieren von Daten,
237     überläßt das Metadatenhandling aber dem Programmierer.
238    
239     C<Net::FCP> stammt von mir und ist entstanden, weil ich das andere Modul,
240     die es nur im Freenet gab, nicht herunterladen konnte (tja, so ist das
241     eben als Freenetter). Daher gehe ich auch nur auf dieses Module ein :)
242    
243     =head2 Installation
244    
245     Zuerst braucht man einen Freenet-Daemon
246     (http://www.freenetproject.org/). Die Installation ist unglaublich komplex
247     (unter Windows gibt es einen Installer, unter Unix ein paar Skripte). Der
248     Daemon braucht eine Weile, bis er warm wird (Minuten bis Stunden), was man
249     durch Surf-Versuche unterstützen sollte.
250    
251     Das C<Net::FCP>-Paket gibt es ganz normal per CPAN.
252    
253     =head2 Einfache Abfragen
254    
255     Die Abkürzung I<FCP> steht für I<Freenet Client Protocol> und ist das
256     Protokoll zwischen Freenet-Anwedungen und dem Freenet-Daemon. Es ist
257     unglaublich ineffizient und noch dazu nicht verschlüsselt. Dies ist der
258     Grund für die Empfehlung, den Daemon nur auf dem lokalen Rechner laufen
259     zu lassen: Wäre dumm, wenn man aus dem hochsicheren Freenet über eine
260     ungesicherte Internetverbindung die Windows-Sourcen herunterlädt und
261     sicher erwischen läßt (ist alles schon vorgekommen)...
262    
263     In Perl geht dies denkbar einfach:
264    
265     use Net::FCP;
266     my $fcp = new Net::FCP;
267    
268     Man kann dem Konstruktor von C<Net::FCP> direkt Namen und Port des
269     Freenet-Daemons übergeben. Üblicherweise holt er sich diese aber aus dne
270     Environment-Variablen C<FREDHOST> und C<FREDPORT>, die auf C<127.0.0.1>
271     bzw. C<8481> defaulten.
272    
273     Übrigens wird nur eine virtuelle Verbindung aufgebaut. Möchte man
274     sicherstellen, daß tatsächlich ein Daemon erreichbar ist, kann man einen
275     C<client_hello>-Request ausführen oder einfach loslegen.
276    
277     Im Normalfall heißt das also:: no configuration required.
278    
279     Hat man ein C<Net::FCP>-Objekt, kann man schon alle Requests durchführen,
280 root 1.9 die man machen möchte:
281 root 1.2
282     my ($meta, $data) = @{ $fcp->client_get (
283     "freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//"
284     15
285     ) };
286    
287     Der C<client_get>-Request erwartet zwei Argumente: eine Freenet-URI
288     (C<< freenet:<freenet-schlüssel> >>) und eine HTL. Letztere muss man
289     nicht angeben, man sollte es aber, und vor allem sollte man dem Benutzer
290     die Wahl der HTL überlassen. Das dritte, optionale, Argument ist für
291     spezielle Anwendungen: am besten ignorieren.
292    
293     Als Ergebnis erhält man immer eine Array-Referenz mit den Metadaten
294     und den Daten. Immer. Sollte ein Fehler auftreten wird eine Exception
295     ausgelöst (auf Perl: das Modul C<die>d). C<eval {}> hilft also im
296     Zweifelsfalle, für einfache Anwendungen ist das aber overkill.
297    
298     Bricht das Programm ab, so sieht das folgendermaßen aus:
299    
300     Net::FCP::Exception<<short_data,reason:unexpected eof or internal node error>>
301    
302     Oder, wenn die Daten nicht gefunden wurden:
303    
304     Net::FCP::Exception<<data_not_found,>>
305    
306     Letzteres bedeutet übrigens nicht aufgeben, sondern nochmal versuchen,
307     z.B. mit einer höheren HTL. Ein fehlgeschlagener Versuch mit hoher HTL
308     bedeutet imemr noch nicht aufgeben. Daemons in der "Nähe" wissen nun,
309     das die Daten verlangt werden. Nach einiger Zeit ist es wahrscheinlich,
310     das die Daten auf einmal in der Nähe liegen: daher nie aufgeben, nochmal
311     probieren. Niemand hat behauptet, man bekäme die Daten einfach aus dem
312     Freenet wieder heraus...
313    
314 root 1.9 Die Metadaten sind als Textdokument gespeichert. das Format
315     dieser Metadaten ist aber relativ "krank", weshalb das Perl-Modul
316     einen Hash mit den geparsten Daten liefert (genaugenommen ein
317     C<Net::FCP::Metadata>-Objekt, aber dieses Modul ist noch in Entwicklung).
318 root 1.2
319 root 1.9 Die Metadaten und die eigentlichen Nutzdaten kann man ausgeben:
320 root 1.2
321     use Data::Dumper;
322     print STDERR Dumper $meta;
323     print $data;
324    
325 root 1.9 Damit haben wir im wesentlichen den Quelltext für das "Tool"
326     C<eg/fetch1>, mit dem man I<einen> Freenet-Datenblock herunterladen kann.
327 root 1.2
328     Ich benutze es üblicherweise so:
329    
330     eg/fetch1 SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// >data
331    
332     Das schreibt die Daten in eine Datei und gibt gleichzeitig dessen
333     Metadaten aus.
334    
335     Für den Key C<SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//> ergibt dies:
336    
337     'version' => { 'revision' => '1' },
338     'document' => [
339     {
340     'info' => { 'format' => 'image/png' },
341     'redirect' => { 'target' => 'freenet:CHK@pMKWiJyE3t-ZWvL1W9VdZvB3jcIKAwI,7pdyQiW7Hp9-8fEp-25C2w' },
342     'name' => 'activelink.png'
343     },
344     {
345     'info' => { 'format' => 'text/plain' },
346     'redirect' => { 'target' => 'freenet:CHK@2hewSY-I5ZhWpJ84dwhPbtdlvyIKAwI,ovcsrpD79xZfoW2021z91w' },
347     'name' => 'description.txt'
348     },
349     {
350     'info' => { 'format' => 'text/html' },
351     'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' },
352     'name' => 'index.html'
353     },
354     {
355     'info' => { 'format' => 'text/html' },
356     'redirect' => { 'target' => 'freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4' },
357     'name' => '.next'
358     },
359     {
360     'info' => { 'format' => 'text/html' },
361     'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' }
362     }
363     ],
364     'raw' => 'Version
365     Revision=1
366     [... gekürzt...]
367     Info.Format=text/html
368     End
369     '
370     };
371    
372 root 1.9 Die eigentlichen Daten sind leer (null Byte gross), das Dokument enthät
373 root 1.2 also nur Metadaten! Man beachte vor allem die teilweise recht tiefe
374     Verschachtelung.
375    
376     Der Key C<< $metadata->{raw} >> enthält die Metadaten, wie sie vom
377     Freenet kamen. Dies ist notwendig, da man manchmal die Metadaten
378 root 1.9 zum Prüfen in der exakten Form benötigt, wie sie hochgeladen
379 root 1.2 wurden. Ansonsten kann man sie ignorieren.
380    
381     Der Key C<< $metadata->{document} >> enthält Informationen über das
382     Dokument oder in diesem Fall die Dokumente: Ein Hash pro Dokument. Schaut
383     man sich den Inhalt an (ein Array), so sieht man in jedem Hash ein
384     C<name>-Key, der den Namen des Subdokuments angibt (bis auf den letzten,
385     darauf komme ich gleich).
386    
387     Schaut man sich dir Freenet-URIs dieser Freesite an, so sieht man
388     derartige URIs:
389    
390     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// # Hauptseite
391     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//activelink.png # Icon
392     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//description.txt # Beschreibung für Spider
393    
394     Wenn diese Dokumente mit C<client_get> anfordert, bekommt man immer obiges
395     Dokument. Freenet ignoriert nämlich alles, was hinter dem C<//> steht
396     und liefert daher immer das gleiche Dokument aus dem SSK-Bereich. (Darauf
397     verlassen soltle man sich nicht unbedingt, in Zukunft reagiert der
398     Freenet-Daemon vielleicht anders. Als Freenetter hat mans eben nicht
399     leicht).
400    
401     Der Teil hinter den beiden Slashes (C<//>) ist nun das Unterdokument, das
402     man über den Namen identifizieren kann:
403    
404     $activelink = grep $_->{name} eq "activelink.png",
405     @{ $metadata->{document} };
406    
407     Fehlet der C<name>-Eintrag ist es der Eintrag mit dem leeren Namen, in
408     diesem Fall der erste Link, der nichts nach den C<//> stehen hat. Der
409     C<name>-Key I<kann> vorhanden und leer sein: Freenet überprüft die Daten
410     nicht, daher gibt es durchaus unterschiedliche Auslegungen für das genau
411     Format.
412    
413     Die Metadaten sind etwas genauer in dem *hüstel* etwas veralteten
414     *hüstel* I<Freenet Explained>-Dokument beschrieben.
415    
416     Möchte man nun das C<activelink.png> herunterladen muss man in C<<
417     $activelink->{redirect} >> nachsehen. Meistens verweist dies auf ein
418     C<CHK>-Schlüssel. Letztere sind sozusagen Allgemeingut: jeder kann
419     sie benutzen, und da sie nicht änderbar sind, kann sie auch niemand
420     fälschen, daher muss man sie nicht signieren.
421    
422     Auf C<< $activelink->{info}{format} > sollte man sich übrigens nicht
423     verlassen.
424    
425     Und sollte kein C<redirect>-Key vorhanden sein, so ist das Dokument im
426     mitgelieferten Datenblock. Alles ganz logisch, einfach, und klar, wie man
427     sieht.
428    
429     Egal, der CHK-Key für C<activelink.png> liefert folgendes:
430    
431     'version' => { 'revision' => '1' },
432    
433     Und die Daten stellen ein PNG dar. Naja, nicht gerade üppig, die
434     Metadaten, aber man hätt's ja im Link auf dieses Dokument sehen
435     können. Als Freenetter hat mans nicht leicht.
436    
437     Aber mit diesen Erklärungen kann man schon einfacher Freenet-Spider
438     bauen. Die wichtigsten Tools sind veraltete und spärliche Dokumente
439     wie I<Freenet Explained> und Tools wie C<Data::Dumper>. "Veraltet" ist
440     übrigens nicht immer schlecht, da viele Dokumente auch alt sind oder sich
441     eh' nicht exakt an den "Standard" halten. Mit der Zeit wird hier sicher
442     eine Besserung eintreten.
443    
444     =head2 Methoden des Freesite-Managements
445    
446     Oder: "Wenn man Inhalte nicht mehr verändern kann, wie verändert man
447     sie?"
448    
449     Die offensichtliche Methode ist: "Man macht sie veränderbar". In
450     der Freenet-Gemeinde geistert seit langer Zeit der Mythos des
451     I<TUK>-Schlüssels, des I<Time Updatable Keys>. Diese Schlüssel tauchen
452     immer auf, wenn jemand über veränderbare Schlüssel spricht. Leider
453     weiss niemand, wie man sie implementieren soll, und ganz persönlich
454     fürchte ich, es wird niemals veränderbare Keys geben.
455    
456     =head3 "Editions"
457    
458     Die nächstliegende Methode nutzt die Eigenschaft von SSKs (genauer:
459     redirects) aus, das man den Namen sofort generieren kann, den Inhalt aber
460     erst später einfügt.
461    
462     Dies nutzt man aus, indem man I<Editionen> herausgibt und
463     durchnummeriert. Jede Edition enthält einen Link auf die nächste. Bis
464     man die nächste Edition einfügt, wird der Link-Inhalt nicht gefunden.
465    
466     Üblicherweise benutzt man in HTML ein C<IMG>-Element mit Link auf ein
467     Bild aus der nächsten Edition. Sieht man das Bild, weiss man, die
468     nächste Edition existiert und kann sich hinklicken.
469    
470     I<Freenet Explained> benutzt diese Methode. Der Link auf Edition 4 lautet:
471    
472     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4// # Link-Ziel
473     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4//activelink.png # IMG-SRC
474    
475     Beides existierte nicht als ich diesen Artikel schrieb (bzw. Freenet
476     konnte es nicht finden :). Wenn eine neue Edition heruasgegeben werden
477     soll, fügt der Autor einfach einen neuen Datenblock mit vielen Redirects
478     unter obigem SSK-Key ein.
479    
480     Ein C<.next>-Eintrag ist ebenfalls vorhanden: manche Spider folgen diesem
481     und können auf diese Weise immer die aktuelle Edition anzeigen, sofern
482     sie häufig genug scannen.
483    
484     Editionen sind einfach für den Autor einer Freesite und erfordern
485     keine spezielle Unterstützung. In der Benutzung sind sie allerdings
486     umständlich und häufige Updates sind auch nicht effizient.
487    
488     Daher hat sich eine zweite Methode entwickelt, die gerade bei häufig
489     geänderten Inhalten besser funktioniert:
490    
491     =head3 "Date Based Redirects"
492    
493     Freesites, die "Date Based Redirects" benutzen (kurz "DBR-Sites")
494     funktionieren ähnlich wie Editionen-basierte Freesites, nur wird statt
495     einer fortlaufenden Nummer die aktuelle Zeit benutzt.
496    
497     Die Freesite I<The Freenet Help Index>
498     (C<SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/FreenetHelp//>) benutzt diese
499     Methode. Folgende Metadaten wurden dazu hinterlegt:
500    
501     'version' => { 'revision' => '1' },
502     'document' => [
503     { 'date_redirect' => {
504     'increment' => '15180',
505     'target' => 'SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/FreenetHelp'
506     }
507     }
508     ],
509    
510     Statt einem einfachen C<redirect> gibt es jetzt einen
511     C<date_redirect>-Eintrag, und darin ein C<target> (dürfte bekannt sein)
512     und der Key C<increment>. Letzterer darf wie üblich fehlen, man sollte
513     dann C<86400> annehmen (ein Tag hat 86400 Sekunden). In diesem Beispiel
514     wird 86400 genommen (Hexadezimal 15180).
515    
516     Habe ich eigentlich schon erwähnt das jede Zahl im FCP-Protokoll oder
517     im Freenet hexadezimal kodiert wird? Also, praktisch immer, außer wenn
518     es mal nicht so ist. Und wozu man einen Offset addiert ist mir auch
519     schleierhaft. In der freien Wildbahn habe ich sowieso noch keinen gesehen.
520    
521     Der Link in C<target> ist nicht vollständig (unter anderem fehlt
522     hinten ein C<//>). Der komplette Link wird generiert, "indem die
523     aktuelle Zeit (POSIX-Zeit, üblicherweise das, was C<time> liefert),
524     auf C<increment>-Schritte gerundet und C<offset> addiert, als
525     Big-Endian-Hexadezimalzahl nach dem ersten Slash mit folgendem
526     Minuszeichen eingefügt wird."
527    
528     Und jetzt in Perl - zum Verstehen:
529    
530     my $doc = $metadata->{document][0]; # Oder [1] oder ...
531    
532     my $increment = (hex $doc->{increment}) || 86400;
533     my $offset = (hex $doc->{offset}) || 0;
534     my $target = $doc->{target} || die;
535    
536     my ($head, $tail) = split /\//, $target, 2;
537    
538     my $NOW = time;
539     my $time = $NOW - $NOW % $increment + $offset;
540    
541     my $result = sprintf "%s/%x-%s", $head, $time, $tail;
542    
543     Für "jetzt" (C<time() == 1084388445>) liefert der Algorithmus folgenden Link:
544    
545     SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/40a16900-FreenetHelp
546    
547     Und tatsächlich, unter diesem Key findet man wieder ein Dokument mit
548     vielen Redirects.
549    
550     DBRs haben den Vorteil, "automatisch" aktuell zu sein. Solange man nur
551     Redirects einfügt, ist die Belastung durch neue das Einfügen vieler
552     neuer Daten gering, Freenet kommt damit zurecht und löscht alte DBRs
553     bei Bedarf automatisch (ohne natürlich zu wissen, das sich in dne
554     Datenblöcken DBRs befinden, dnen die kann ja niemand dekodieren,d er
555     nicht den Schlüssel besitzt).
556    
557     Der Nachteil ist, das man eine aktuelle Uhrzeit braucht um die Site zu
558     finden. Schlimemr noch: die Freesite muss regelmäßig neu eingefügt
559     werden, eben alle C<increment> Sekunden.
560    
561     DBR-Freesites, die nicht mehr maintained werden, verschwinden deshalb fast
562     sofort, solange man nicht einen Zeitpunkt kennt, zu dem sie noch (bzw.
563     schon!) existierte.
564    
565     All dieses I<sollte> eigentlich in einem Metadata-Modul stattfinden. So
566     weit bin ich aber nicht, da mein Hauptziel das effiziente Herunterladen
567     großer Dateien ist.
568    
569     Womit ich beim Thema wäre.
570    
571     =head1 Effizient herunterladen
572    
573 root 1.4 Transfers im Freenet zeichnen sich durch zwei Eigenschaften aus: hohe
574     Latenz und vergleichsweise hoher Durchsatz. Dies ist ungewöhnlich, ergibt
575     sich aber aus dem Suchverfahren: die Suche nach einem Datenblock kann sehr
576     lange dauern (sogar einige Male fehlschlagen bevor die Daten eintreffen),
577     sie sind jedoch einfach parallelisierbar.
578    
579     Wie in Java üblich, erreichte man dies früher durch massive Benutzung
580     von Threads. Der Freenet-Referenz-Daemon ist davon inzwsichen abgekommen
581     (zu langsam, zu viel Speicher und zu hohe Komplexität), doche viele
582     Clients haben auch heute noch Voreinstellungen wie "Anzahl der Threads pro
583     Download" und viele sind auch so implementiert.
584    
585     Da Perls Thread-Implementierung ein Prozessmodell emuliert (kaum sharing
586     möglich) ist der overhead ebenfalls entsprechend hoch, und man erhält
587     durch Threads keinen nennenswerten Vorteil, ausser das alles etwas
588     langsamer läuft und man besser zuschauen kann :)
589    
590     Für C<Net::FCP> (oder besser: für mich) kam es deshalb nicht in Frage,
591     Parallelisierung auf Thread-Basis zu implementieren. Da sProblem auf
592     den Modul-Benutzer abzuschieben erschien mir auch nicht fair, daher
593     unterstützt C<Net::FCP> die Module L<Coro>, L<Event>, L<Glib> oder L<Tk>,
594 root 1.6 bzw. deren Event-Steuerung. Man hat also die Wahl, auf welcher Basis man sein
595 root 1.4 Programm aufbaut, und es geht auch ganz ohne Event-System (wie die obigen
596     einfachen Beispiele zeigen).
597    
598     =head2 Transaktionen
599    
600     C<Net::FCP> benutzt für jeden Request eine I<Transaktion>. Das ist ein
601     Objekt, das den Zustand und eintreffende Ergebnisse speichert.
602    
603     Jede Anfrage, (z.B. C<client_get>) wird intern in ein solches
604     Transaktionsobjekt verwandelt. Für jede "einfache" Methode wie
605     C<client_get> oder C<insert_private_key> gibt es eine entsprechende
606     Methode mit C<txn_>-Präfix, die statt des Resultats ein solches Objekt
607     liefert.
608    
609     Transaktionsobjekte besitzen einige Methoden, mit denen sie konfiguriert
610     werden können oder Ergebnisse abgefragt werden können. Die wichtigste
611     ist die C<result>-Methode, die auf das Ergebnis wartet und es
612     zurückliefert:
613    
614     # $fcp->client_get wird intern so implementiert:
615     my $txn = $fcp->txn_client_get (...);
616     return $tdn->result;
617    
618     Es ist übrigens immer gefahrlos, Transaktionsobjekte zu erzeugen. Etwaige
619     Fehler bei der Durchführung werden immer erst beim Aufruf von C<result>
620     und immer als Perl-Exceptions gemeldet.
621    
622     Um also alle Freenet-Objekte im Array C<@download> gleichzeitig
623     anzufordern, reicht folgender Code:
624    
625     map $_->result,
626     map $_->txn_client_get ($_),
627     @download;
628    
629     Zuerst werden alle URIs auf eine entsprechende Transaktion gemapped, und
630     dann von allen Transaktionen das Resultat angefordert.
631    
632     Natürlich brauchen manche Zugriffe länger als andere. Wenn Transaktionen
633     früher beendet werden, sollte man gleich eine neue starten, um Freenet
634     bei Lauen zu halten.
635    
636     Dazu benötigt man ein Signal, das eine Transaktion beendet ist. Dies
637     macht C<Net::FCP> mit Hilfe eines Callbacks:
638    
639     my $txn = $fcp->txn_client_get (...)
640     ->cb (\&callback);
641    
642     Diesen setzt man mit Hilfe der C<cb>-Methode. Alle Methoden, die ein
643     Transaktionsobjekt konfigurieren liefern das Transaktionsobjekt zurück,
644     man kann also Aufrufketten wie im Beispiel bilden.
645    
646     Der Callback wird aufgerufen, wenn der Request (erfolgreich oder nicht)
647     beendet wurde.
648    
649     Nun braucht man allerdings die Hauptschleife des jeweiligen Event-Systens,
650     da man ja nicht mehr auf ein bestimmtes Ergebis wartet, sondern auf ein
651     beliebiges.
652    
653     Dazu sollte man C<Net::FCP> auf ein bestimmtes Event-System zwingen. Das
654     folgende Beispiel tut dies und lädt die Kommandozeileargumente parallel
655     herunter:
656    
657     use Net::FCP qw(event=Event); # oder event=Glib, oder...
658    
659     my $fcp = new Net::FCP;
660     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
661    
662     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
663    
664     Die Transaktionsobjekte werden übrigens nicht gespeichert, denn sie
665     werden dem Callback übergeben und nur dort werden sie gebraucht. Der
666     Callback könnte so aussehen:
667    
668     sub finished {
669     my ($txn) = @_;
670     my ($meta, $data) = @{ $txn->result };
671     # tue etwas
672     }
673    
674     Oder, mit Fehlerprüfung:
675    
676     sub finished {
677     my ($txn) = @_;
678     my ($meta, $data) = eval { @{ $txn->result } };
679     if ($@) {
680     warn "fehler: $@, wird einfach ignoriert :)"
681     } else {
682     warn "Lo and Behold! We got soemthing!";
683     # tue etwas
684     }
685     }
686    
687     =head2 Fortschritt ist nicht aufzuhalten
688    
689     Da Zugriffe recht lange dauern können, schickt Freenet regelmäig
690     Fortschrittsreports. Man kann sich das vorstellen wie C<warn> und
691     C<die>: C<warn> liefert wichtige Informationen, C<die> einen Fehler.
692    
693     Die Fortschrittsanzeigen werden normalerweise nicht von C<Net::FCP>
694     ausgegeben (wäre irgendwie kontraproduktiv in einem GUI-Programm), man
695     kann aber einen Callback installieren:
696    
697     my $fcp = Net::FCP progress => \&progress;
698    
699     Ein solcher Progress-Callback könnte so aussehen:
700    
701     sub progress_cb {
702     my ($self, $txn, $type, $attr) = @_;
703    
704     warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
705     }
706    
707     Möchte man Informationen für den Callback bereitstellen, so bietet sich
708     die C<userdata>-Methode von Transaktionsobjekten an.
709    
710     Hier ist ein kompletter parallelisierender Client mit Fortschrittsanzeige:
711    
712     my $fcp = Net::FCP progress => \&progress;
713    
714     Ein solcher Progress-Callback könnte so aussehen:
715    
716     use Net::FCP qw(event=Event); # oder event=Glib, oder...
717    
718     my $fcp = new Net::FCP progress => \&progress_cb;
719    
720     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
721    
722     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
723    
724     sub finished {
725     my ($txn) = @_;
726     my ($meta, $data) = eval { @{ $txn->result } };
727     if ($@) {
728     warn "$txn: fehler: $@, wird einfach ignoriert :)\n"
729     } else {
730     warn "$txn: Lo and Behold! We got something!\n";
731     # tue etwas
732     }
733     }
734    
735     sub progress_cb {
736     my ($self, $txn, $type, $attr) = @_;
737    
738     warn "$txn: progress<$txn,$type," . (join ":", %$attr) . ">\n";
739     }
740    
741     Startet man ihn mit einigen gültigen und ungültigen Freenet-URIs,
742     bekommt man vieleicht folgende Ausgabe:
743    
744     Net::FCP::Txn::ClientGet=HASH(0x81e0f64): fehler: Net::FCP::Exception<<uri_error,reason:Unspecified document name>>, wird einfach ignoriert :)
745     Net::FCP::Txn::ClientGet=HASH(0x81e7254): fehler: Net::FCP::Exception<<uri_error,reason:Unknown keytype>>, wird einfach ignoriert :)
746     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data_found,data_length:74:metadata_length:74>
747     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data,chunk:116:total:116:received:116>
748     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): Lo and Behold! We got something!
749     ... usw.
750    
751     Benutzt man das C<Coro>-Modul, so kann man Callback-basierte und Thread-
752     (bzw. Coroutinen-) basierte Programmierung mischen:
753 root 1.6
754     use Net::FCP qw(event=Coro);
755    
756     my $fcp = new Net::FCP;
757 root 1.4
758     # Achtung. Pseudocode :)
759     for my $url (@urls) {
760     async {
761     my ($meta, $data) = @{ $fcp->client_get ($url) };
762    
763     if ($meta ist ein splitfile) {
764     for (@alle_splitfile_blöcke) {
765     $fcp->txn_client_get (...)
766     ->cb (\&save_splitfile_block);
767     }
768     } else {
769     # direkt speichern
770     }
771     };
772     }
773    
774     =head2 Splitfiles
775    
776     Das Them Splitfiles möchte ich hier noch erwähnen, aber nicht
777     ausführlich besprechen.
778    
779     Da die Datenblöcke im Freenet (zur Zeit) nicht größer als 1MB sein
780     können, müssen größere Dateien (Filme z.B.) aufgeteilt werden. Wenn
781     man viele Datenblöcke für eine Datei braucht, erhöht sich die
782     Wahrscheinlichkeit dafür, das ein Block mal fehlt oder nicht gefundne
783     werden kann, stark auf einen Wert, der das Herunterladen großer Dateien
784     unmöglich macht.
785    
786     Daher wird mit Fehlerkorrekturcodes die Anzahl der Blöcke um 50%
787     erhöht. Metadaten für ein Splitfile sehen so aus:
788    
789     'version' => { 'revision' => '1' },
790     'document' => [ {
791     'info' => {
792     'checksum' => '3bab309132f812cb2a281357b0dc1036920672e2',
793     'format' => 'video/mpeg',
794     'description' => 'Onion FEC v1.2 file inserted by Fuqid'
795     },
796     'split_file' => {
797     'algo_name' => 'OnionFEC_a_1_2',
798     'check_block_count' => '3f',
799     'block_count' => '7f',
800     'check_block' => {
801     '33' => 'freenet:CHK@eTNQmnQ8aoZor3CBzTSsI~oPn6EUAwI,I4XDi1SbdKlFnyGoIRZBLg',
802     '32' => 'freenet:CHK@Ee1h~wxPSqSOFKg3WZ90KXqwQZMUAwI,ppnEYTKkp7Dyk1z3Sempqw',
803     '1e' => 'freenet:CHK@5gBBquHWc7WKjfjO27kOtU0hZgkUAwI,OkfOgz9BPvMxwvtX~wfVNA',
804     [viele Zeilen fehlen hier :]
805     '3d' => 'freenet:CHK@iIT1KzjEyXptPyOToFsyyytV-roUAwI,9u3qhWXzi8v--eY7Onag1g',
806     '5' => 'freenet:CHK@EeVsnou1WxkZg9CNBNVzvTTQ1l0UAwI,q6edARpUGxg5Oh-cc79WBA'
807     },
808     'block' => {
809     '33' => 'freenet:CHK@j522RLeAYwiNah2ZK1D1q4UDnFgUAwI,XwoBGzhdGMkyXFwI5f9iyw',
810     '32' => 'freenet:CHK@VU5v9PNahADgvy-Dnk8SCt9ZKbYUAwI,iX~d0b-YKcwt3Yk0rmpM9w',
811     '5d' => 'freenet:CHK@-wbXzvl32R8aSuotK~uZbJp14zsUAwI,-bgXeuzi6SpKYvbwQeYtyA',
812     [viele Zeilen fehlen hier :]
813     '43' => 'freenet:CHK@zMXcOMm1DlNB4ee1cftvdK4~QukUAwI,o99L7InOc4E7adXUXGjrlg',
814     '5' => 'freenet:CHK@1ZDivRb~iBdn2NYTKQbDq1yCPWAUAwI,B9fXQ8jF~DzmfOx~PTZkAA',
815     '3d' => 'freenet:CHK@ZGxa5ipGqKuZEqQIf6rbr-g8btMUAwI,f0xOciFlFA0bmmxoJRzaLw'
816     },
817     'size' => '7e8e804'
818     }
819     } ],
820     }
821    
822     Die Datenblöcke und die zusätzlichen Korrekturblöcke sind getrennt
823     aufgeführt. Man braucht nur so viele Blöcke insgesamt, wie die Datei
824     groß ist. Den Rest kann man aus den heruntergeladenen erzeugen.
825    
826     Wie genau die Daten auf die Blöcker verteilt werden unterliegt einem
827     Algorithmus und ist nicht in dne Metadaten gespeichert. Der Grund ist,
828     das jedes Programm denselben Algorithmus benutzen muss und Dateien daher
829     immer gleich auf die Blöcke verteilt werden, so das Mehrfacheinfügen ins
830     Freenet keine Duplikate erstellt.
831    
832     Der genauen Algorithmus kann man in der Datei C<bin/fmd>, dem I<Freenet
833     Mass Downloader> in der Funktion C<state_splitfile> nachlesen. Der Code
834     ist weder besonders klar, noch besonders kurz noch besonders hübsch. Auch
835     dieser Teil wird irgendwann einmal in ein Modul fließen, damit er anderen
836     zugänglicher wird.
837    
838     Interessant ist noch, das man CHK-Inhalte, die aus dem Freenet
839     heruntergeladen werden einfach auf Konsistenz prüfen kann: Sie enthalten
840     schließlich den SHA1-Hash der Daten:
841    
842     use Net::FCP::Util;
843    
844     my ($meta, $data) = @{ $fcp->client_get ($uri) };
845    
846     # Extrahiere den Hash aus der URI
847     my $k1 = Net::FCP::Util::extract_chk_hash $uri;
848     # Berechne den Hash aus den Daten
849     my $k2 = Net::FCP::Util::generate_chk_hask "$meta->{raw}$data";
850    
851     # Idealerweie stimmen beide überein...
852     $k1 eq $k2 or die "Key/Content mismatch!";
853    
854     Zwar ist der Freenet-Daemon angeblich perfekt, aber früher passierte
855     es tatsächlich oft, daß man korrupte Daten geliefert bekam. Retryen
856     half. Man hat es eben nicht so leicht...
857    
858     Heute ist das zwar nicht mehr der Fall (...), aber prüfen kostet fast
859     nichts.
860    
861 root 1.7 =head1 Publizieren
862 root 1.1
863 root 1.4 Das Freenet lebt von vielen Dingen: Den Entwicklern, den Benutzern die
864     ihr Interesse bekunden, den Regierungen, die die Meinungsäußerung
865     einschränken aber vor allem dadurch, das es sinnvolle Inhalte darin gibt.
866    
867     Ich bin mir nicht so sicher, I<ob> es so viele sinnvolle Inhalte gibt,
868     aber noch gab es ja auch keine 1.0-Release...
869    
870     Nun ja, solange man nichts ins Netz stellt, darf man auch nicht klagen.
871    
872     Das kann man ändern, indem man so langweilige Dinge wie den I<Freenet
873 root 1.7 Insertion Wizard> oder das beliebte I<Fuqid> benutzt (was ich noch nie
874     getan habe). Aber die benutzen kein Perl und sind damit langweilig.
875 root 1.4
876     Mit C<Net::FCP> geht es erstmal sehr einfach:
877    
878     $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
879    
880     (Auch hier gibt es natürlich wieder die entsprechende C<txn_>-Variante).
881 root 1.7
882     Einfügen von Inhalten geht also fast geanuso wie Auslesen. C<$uri> ist
883     eine Freenet-"URI" (mit oder ohne C<freenet:>), wie man zu dieser kommt
884     gleich mehr.
885    
886     C<$metadata> kann entweder ein Freenet-Metadata-String sein oder ein Hash
887     der gleichen Form wie man ihn zurückgeliefert bekommt. C<$data> sind
888     natürlich die eigentlichen Daten und C<$htl> sind die Hops-To-Live, die
889     der Key-Insert haben soll. Höhere Werte (bis hin zu 25) speichern die
890     Daten dauerhafter, brauchen aber auch entsprechend länger.
891    
892     C<$removelocal>, auf C<1> gesetzt, sorgt dafür, daß der lokale
893     Netzknoten die Daten I<nicht> cached. Warum man das tun sollte, ist
894     einfach erklärt: Wenn Freenet beim Einfügen die Daten schon im Netz
895     vorfindet, wird der Einfügevorgang abgebrochen. Möchte man die Daten
896     regelmäßig "auffrischen" dann sorgt diese Option dafür, daß die
897     Daten den Knoten auf jeden Fall verlassen und erhöhen so die Chance auf
898     Verbreitung.
899    
900     Nun die Frage wie man zu einer URI kommt. Möchte man einen CHK-Schlüssel
901     einfügen, so setzt man die URI einfach auf den String C<CHK@>. Nach dem
902     Einfügen erhält man die eigentliche URI als Resultat:
903    
904     my $attr = $fcp->client_put ('CHK@', "", "Daten\n", 20);
905     print "eingefügte URI: $attr->{uri}\n";
906    
907     Als Ergebnis dieses C<client_put>-Requests erhielt ich:
908    
909     freenet:CHK@MT~LuxKHH8fugJehkcgp239h7C4KAwI,378rJzHVZbsQbd7VGMHxSg
910    
911     Beim Einfügen ins Freenet kann es auch einen I<Key Collision>-Fehler
912     geben, und zwar genau dann, wenn Freenet die Daten schon findet, die man
913     einfügen wollte.
914    
915     C<Net::FCP> behandelt diesen Fehler allerdings genauso wie ein
916     erfolgreicher Einfügevorgang, lediglich im Hash, den es zurückliefert,
917     wird das C<key_collision>-Element auf C<1> gesetzt. Wenn die Daten schon
918     vorhanden sind, ist das Ziel schließlich auch erreicht.
919    
920     Häufig möchte man den C<CHK>-Schlüssel aber schon im voraus
921     Wissen. Dazu kann man entweder seinen freundlichen Freenet-Daemon fragen:
922    
923     my $key = $fcp->generate_chk ($metadata, $data);
924    
925     Oder man verwendet das C<Net::FCP::Key::CHK>-Modul, das schneller ist und
926     keinen Serverzugang benötigt:
927    
928     use Net::FCP::Key;
929    
930     my $key = (new_from_data Net::FCP::Key::CHK $metadata, $data)->chk;
931    
932     =head2 SSK-Schlüssel generieren
933    
934     SSK-Schlüssel bestehen immer aus zwei Teilen, dem öffentlichen
935     (C<public_key>) und dem privaten (c<private_key>), die zusammen ein Paar
936     bilden. Neuerdings noch aus einem dritten, dem C<crypto_key>, der es
937     Brute-Force-Attacken noch schwieriger machen soll.
938    
939     Solch ein Schlüsselpaar kann man mit einem Aufruf von
940     C<generate_svk_pair> (auch hierfür gibt es eine C<txn_>-Variante)
941     erzeugen. Das "svk" ist übrigens kein Schreibfehler: SSK-Schlüssel sind
942     ein Spezialfall von SVK-Schlüsseln, die man aber als normalsterblicher
943     nirgendwo direkt antrifft.
944    
945     my ($public, $private, $crypto) = @{ $fcp->generate_svk_pair };
946    
947     Daraus kann man beliebig viele SSK-Schlüssel erzeugen, indem man die drei
948     Teile wie folgt zusammensetzt:
949    
950     # Öffentlicher Schlüssel:
951    
952     my $name = "..."; # beliebig
953    
954     my $get = "SSK\@${public}PAgM,$crypto/$name";
955     my $put = "SSK\@$private,$crypto/$name";
956    
957     Den mit C<$put> bezeichneten Schlüssel muss man zum Einfügen
958     verwenden. Mit dem mit C<$get> bezeichneten Schlüssel kann man diese
959     Daten wieder holen. Letzterer kann bedenkenlos veröffentlich werden.
960    
961     Das SSK-Management kann vom C<Net::FCP::Key::SSK>-Modul übernommen
962     werden.
963    
964     =head2 Eine Freesite erzeugen
965    
966     Um eine Freesite zu erzeugen, sollte man sich zuerst einen dauerhaften
967     SSK-Schlüssel besorgen:
968    
969     # perl -MNet::FCP -MNet::FCP::Key::SSK \
970     -e 'Net::FCP::Key::SSK->new_from_fcp (Net::FCP->new) \
971 root 1.8 ->save ($ARGV[0])' mykey
972 root 1.7
973 root 1.8 Das erzeugt einen neuen SSK-Schlüssel und speichert ihn gleich in der
974 root 1.7 Datei C<mykey>.
975 root 1.8
976     Dieser SSK-Schlüssel wird die Basis der Freesite.
977    
978     Für das Einfügen schreibt man sich am besten ein Skript, da man ides
979     regelmäßig wiederholen sollte. Zuerst ein paar Definitionen:
980    
981     my $edition = 1;
982     my $keyfile = "mykey";
983     my $htl = 10;
984    
985     Das Skript legt eine Editionenbasierte Freesite an und benutzt als Basis
986     den eben erzeugten SSK-Schlüssel. Der Hops-To-Live-Wert von 10 ist etwas
987     klein, aber so dauert das Einfügen vielleicht nur ein paar Minuten... In
988     der Praxis sollte man 20-25 vorziehen, oder das Einfügen regelmäig
989     wiederholen.
990    
991     Als nächstes benötigen wir ein paar Module:
992    
993     use Net::FCP qw(event=Event);
994     use Net::FCP::Metadata;
995     use Net::FCP::Key::SSK;
996    
997     Generell sollte man in einem Perl-Programm den verwendeten
998     Event-Mechanismus fest angeben. In Freenet-Modulen sollte man dies dagegen
999     nicht tun, um dem Benutzer die Wahl zu überlassen. Stattdessen sollte
1000     man in Modulen nur Transaktionen benutzen und diese dem Benutzer zur
1001     Verfügung stellen.
1002    
1003     Als nächstes werden ein paar notwendige Objekte erzeugt:
1004    
1005     my $fcp = new Net::FCP;
1006     my $ssk = new_from_file Net::FCP::Key::SSK $keyfile;
1007     my $manifest = new Net::FCP::Metadata;
1008    
1009     Die Metadaten für die Hauptseite (C<$manifest>) werden auch
1010     "Manifest" genannt, da man dort häufig nur Verweise auf die
1011     jeweiligen Unterseiten ablegt, also sowas wie der Grundstein einer
1012     Freesite. Das C<Net::FCP::Metadata>-Modul biette zur Zeit nur spärliche
1013     Funktionalität, für unsere Zwecke reicht das jedoch aus.
1014    
1015     Nun noch zwei Hilfsfuntionen. Zuerst C<add_key>:
1016    
1017     sub add_key {
1018     my ($name, $key, $meta, $data) = @_;
1019    
1020     # Asynchrones Einfügen
1021     $fcp->txn_client_put ($chk, $meta, $data, $htl, 1)
1022     ->cb (sub {
1023     eval {
1024     my $attr = $_[0]->result;
1025     printf "Insert of '%s' (%d bytes) ok.\n", $name, length $data;
1026     } or warn "Error while inserting '$name': $@";
1027     });
1028     }
1029    
1030     C<add_key> startet eine C<client_put>-Transaktion, ohne auf das Ende zu
1031     warten. Im Callback wird das Resultat angezeigt, oder, wenn ein Fehler
1032     Auftrat, eben dieser. Das Skript sollte so angelegt sein, das man es
1033     einfach nochmal starten kann, wenn einige Schlüssel nicht eingefügt
1034     werden konnten.
1035    
1036     Nun noch C<add_file>:
1037    
1038     # Hilfsfunktion zum Einfügen von Dateien
1039     sub add_file {
1040     my ($name, $path, $contenttype) = @_;
1041    
1042     # lies die Datei ein
1043     my $data = do {
1044     local $/;
1045     open my $fh, "<", $path
1046     or die "$path: $!";
1047     <$fh>
1048     };
1049    
1050     my $chk = $fcp->generate_chk ("", $data); # keine metadaten
1051     $manifest->add_redirect ($name => $chk, format => $contenttype);
1052     add_key $name, $chk, "", $data;
1053     }
1054    
1055     C<add_file> lädt eine externe Datei (< 1MB) und berechnet deren
1056     CHK-Schlüssel. Diesen Schlüssel fügt es als Verweis unter dem Namen
1057     C<$name> in das Manifest ein. Als letztes benutzt es C<add_key>, um die
1058     Datei einzufügen.
1059    
1060     Das Vorausberechnen des CHK-Schlüssels macht es möglich, das Manifest
1061     paralelle zu den anderen Schlüsseln einzufügen. Würde man auf den
1062     Einfügevorgang waretn, müsste man das Manifest am Ende getrennt
1063     hochladen.
1064    
1065     Nun ans Zusammebauen. Zuerst werden (unsichtbare) Verweise auf die
1066     vorherige bzw. die nächste Edition eingefügt:
1067    
1068     $manifest->add_redirect (".prev" => $ssk->gen_pub ($edition - 1)) if $edition > 1;
1069     $manifest->add_redirect (".next" => $ssk->gen_pub ($edition + 1));
1070    
1071     Dies nutzt zum einen die Eigenschaft von SSKs, einfach vorausberechnet
1072     werden zu können, als auch die Methode C<gen_pub>, die den öffentlichen
1073     SSK-Schlüssel mit optionalem Suffix generiert.
1074    
1075     Dadurch können Benutzer auch "per Hand" eine neuere oder ältere Edition
1076     suchen, indem sie einfach die Zahl (C<.../2//index.html>) vor dem C<//>
1077     ändern.
1078    
1079     Als nächstes folgt der Eigentliche Inhalt der Freesite, eine HTML-Seite,
1080     ein Bild und der Quellcode des Skriptes, der sie generiert hat:
1081    
1082     add_file "activelink.png" => "logo.png", "image/png";
1083     add_file "" => "index.html", "text/html";
1084     add_file "index.html" => "index.html", "text/html";
1085     add_file "freesite" => "freesite", "text/plain";
1086    
1087     Die Datei C<index.html> wird zweimal hinzugefügt, einmal unter dem Namen
1088     "" und ein zweitesmal unter dem Namen "C<index.html>". Dadurch kann man
1089     erreichen, was viele HTTP-Server ebenfalls machen, nämlich eine URI, die
1090     auf ein Verzeichnis zeigt, auf eine Datei darin zu verweisen. Das die
1091     Datei zweimal eingefügt wird ist kein Problem, da der CHK-Schlüssel
1092     derselbe ist (und Mehrfacheinfügen kein Fehler).
1093    
1094     Nachdem die Dateien hinzugefügt (und vor allem ins Manifest eingetragen)
1095     wurden, kann man das Manifest einfügen:
1096    
1097     my $site = $ssk->gen_pub ($edition);
1098     add_key "manifest", $site, $manifest, "";
1099    
1100     Das Manifest wird. Damit man hinterher auch weiss, was man da eingefügt
1101     hat, sollte man den Hauptschlüssel auch ausgeben:
1102    
1103     print "site generated as $site//\n";
1104    
1105     Und da die ganzen Einfügevorgange ja nur gestartet wurden, muss man auf
1106     deren Ende warten:
1107    
1108     Event::loop;
1109    
1110     Solange C<Event> noch aktive Watcher sieht, bleibt es in der
1111     Event-Schleife. Wenn es keinen aktiven Watcher mehr gibt, kehrt C<loop>
1112     automatisch zurück und das Programm ist beendet.
1113    
1114     Die Ausgabe sieht dann z.B. so aus:
1115    
1116     site generated as SSK@wgvWpYYe4QfTBRylfnDlUBfjETgPAgM,Jrm3qco-SQkUBDPfw1UO1g/1//
1117     Insert of 'freesite' (1688 bytes) ok.
1118     Insert of 'activelink.png' (1346 bytes) ok.
1119     Insert of 'index.html' (200 bytes) ok.
1120     Insert of '' (200 bytes) ok.
1121     Insert of 'manifest' (0 bytes) ok.
1122    
1123     Wenn man einen Fehler gemacht hat, kann man einfach einen neuen
1124     SSK-Schlüssel generieren. Das heißt, solange man seine Site nicht schon
1125     veröffentlicht hat.
1126    
1127     Die Alternative wäre z.B. ein täglicher Date-Based-Redirect, d.h.
1128     tägliches komplettes Neueinfügen. Da bügeln sich Fehler schnell von
1129     selbst aus, man muss sein Skript dann natürlich über Tage oder Monate
1130     regelmäßig starten.
1131    
1132     Eine offensichtliche Verbesserung wäre es, HTML-Dateien abzuändern, so
1133     daß man Links auf die nächste Revision nicht hardcodieren muss sondern
1134     etwa als C<%%NEXT%%//activelink.png> schreiben könnte.
1135    
1136     Nun ja, ich hoffe, es machen sich nun einige Leser auf, um eigene
1137     Freesites zu erstellen oder andere Anwendungen für das Freenet zu
1138     ertsellen.
1139    
1140 root 1.7
1141    
1142 root 1.1