ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/freenet.pod
Revision: 1.9
Committed: Mon May 17 13:17:15 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.8: +11 -10 lines
Log Message:
*** empty log message ***

File Contents

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