ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/freenet.pod
Revision: 1.13
Committed: Fri May 21 18:52:06 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.12: +17 -1 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 root 1.12 Da Perls aktuelle Thread-Implementierung ein Prozessmodell simuliert
586     ist der Overhead ebenfalls entsprechend hoch, und man erhält bei
587     Thread-Benutzung viele ihrer Nachteile, jedoch keine nennenswerten
588     Vorteile, außer das alles etwas langsamer läuft und man daher besser
589     zuschauen kann :)
590 root 1.4
591     Für C<Net::FCP> (oder besser: für mich) kam es deshalb nicht in Frage,
592     Parallelisierung auf Thread-Basis zu implementieren. Da sProblem auf
593     den Modul-Benutzer abzuschieben erschien mir auch nicht fair, daher
594     unterstützt C<Net::FCP> die Module L<Coro>, L<Event>, L<Glib> oder L<Tk>,
595 root 1.6 bzw. deren Event-Steuerung. Man hat also die Wahl, auf welcher Basis man sein
596 root 1.4 Programm aufbaut, und es geht auch ganz ohne Event-System (wie die obigen
597     einfachen Beispiele zeigen).
598    
599     =head2 Transaktionen
600    
601     C<Net::FCP> benutzt für jeden Request eine I<Transaktion>. Das ist ein
602     Objekt, das den Zustand und eintreffende Ergebnisse speichert.
603    
604     Jede Anfrage, (z.B. C<client_get>) wird intern in ein solches
605     Transaktionsobjekt verwandelt. Für jede "einfache" Methode wie
606     C<client_get> oder C<insert_private_key> gibt es eine entsprechende
607     Methode mit C<txn_>-Präfix, die statt des Resultats ein solches Objekt
608     liefert.
609    
610     Transaktionsobjekte besitzen einige Methoden, mit denen sie konfiguriert
611     werden können oder Ergebnisse abgefragt werden können. Die wichtigste
612     ist die C<result>-Methode, die auf das Ergebnis wartet und es
613     zurückliefert:
614    
615     # $fcp->client_get wird intern so implementiert:
616     my $txn = $fcp->txn_client_get (...);
617     return $tdn->result;
618    
619     Es ist übrigens immer gefahrlos, Transaktionsobjekte zu erzeugen. Etwaige
620     Fehler bei der Durchführung werden immer erst beim Aufruf von C<result>
621     und immer als Perl-Exceptions gemeldet.
622    
623     Um also alle Freenet-Objekte im Array C<@download> gleichzeitig
624     anzufordern, reicht folgender Code:
625    
626     map $_->result,
627     map $_->txn_client_get ($_),
628     @download;
629    
630     Zuerst werden alle URIs auf eine entsprechende Transaktion gemapped, und
631     dann von allen Transaktionen das Resultat angefordert.
632    
633     Natürlich brauchen manche Zugriffe länger als andere. Wenn Transaktionen
634     früher beendet werden, sollte man gleich eine neue starten, um Freenet
635     bei Lauen zu halten.
636    
637     Dazu benötigt man ein Signal, das eine Transaktion beendet ist. Dies
638     macht C<Net::FCP> mit Hilfe eines Callbacks:
639    
640     my $txn = $fcp->txn_client_get (...)
641     ->cb (\&callback);
642    
643     Diesen setzt man mit Hilfe der C<cb>-Methode. Alle Methoden, die ein
644     Transaktionsobjekt konfigurieren liefern das Transaktionsobjekt zurück,
645     man kann also Aufrufketten wie im Beispiel bilden.
646    
647     Der Callback wird aufgerufen, wenn der Request (erfolgreich oder nicht)
648     beendet wurde.
649    
650     Nun braucht man allerdings die Hauptschleife des jeweiligen Event-Systens,
651     da man ja nicht mehr auf ein bestimmtes Ergebis wartet, sondern auf ein
652     beliebiges.
653    
654     Dazu sollte man C<Net::FCP> auf ein bestimmtes Event-System zwingen. Das
655     folgende Beispiel tut dies und lädt die Kommandozeileargumente parallel
656     herunter:
657    
658     use Net::FCP qw(event=Event); # oder event=Glib, oder...
659    
660     my $fcp = new Net::FCP;
661     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
662    
663     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
664    
665     Die Transaktionsobjekte werden übrigens nicht gespeichert, denn sie
666     werden dem Callback übergeben und nur dort werden sie gebraucht. Der
667     Callback könnte so aussehen:
668    
669     sub finished {
670     my ($txn) = @_;
671     my ($meta, $data) = @{ $txn->result };
672     # tue etwas
673     }
674    
675     Oder, mit Fehlerprüfung:
676    
677     sub finished {
678     my ($txn) = @_;
679     my ($meta, $data) = eval { @{ $txn->result } };
680     if ($@) {
681     warn "fehler: $@, wird einfach ignoriert :)"
682     } else {
683     warn "Lo and Behold! We got soemthing!";
684     # tue etwas
685     }
686     }
687    
688     =head2 Fortschritt ist nicht aufzuhalten
689    
690     Da Zugriffe recht lange dauern können, schickt Freenet regelmäig
691     Fortschrittsreports. Man kann sich das vorstellen wie C<warn> und
692     C<die>: C<warn> liefert wichtige Informationen, C<die> einen Fehler.
693    
694     Die Fortschrittsanzeigen werden normalerweise nicht von C<Net::FCP>
695     ausgegeben (wäre irgendwie kontraproduktiv in einem GUI-Programm), man
696     kann aber einen Callback installieren:
697    
698     my $fcp = Net::FCP progress => \&progress;
699    
700     Ein solcher Progress-Callback könnte so aussehen:
701    
702     sub progress_cb {
703     my ($self, $txn, $type, $attr) = @_;
704    
705     warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
706     }
707    
708     Möchte man Informationen für den Callback bereitstellen, so bietet sich
709     die C<userdata>-Methode von Transaktionsobjekten an.
710    
711     Hier ist ein kompletter parallelisierender Client mit Fortschrittsanzeige:
712    
713     my $fcp = Net::FCP progress => \&progress;
714    
715     Ein solcher Progress-Callback könnte so aussehen:
716    
717     use Net::FCP qw(event=Event); # oder event=Glib, oder...
718    
719     my $fcp = new Net::FCP progress => \&progress_cb;
720    
721     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
722    
723     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
724    
725     sub finished {
726     my ($txn) = @_;
727     my ($meta, $data) = eval { @{ $txn->result } };
728     if ($@) {
729     warn "$txn: fehler: $@, wird einfach ignoriert :)\n"
730     } else {
731     warn "$txn: Lo and Behold! We got something!\n";
732     # tue etwas
733     }
734     }
735    
736     sub progress_cb {
737     my ($self, $txn, $type, $attr) = @_;
738    
739     warn "$txn: progress<$txn,$type," . (join ":", %$attr) . ">\n";
740     }
741    
742     Startet man ihn mit einigen gültigen und ungültigen Freenet-URIs,
743     bekommt man vieleicht folgende Ausgabe:
744    
745     Net::FCP::Txn::ClientGet=HASH(0x81e0f64): fehler: Net::FCP::Exception<<uri_error,reason:Unspecified document name>>, wird einfach ignoriert :)
746     Net::FCP::Txn::ClientGet=HASH(0x81e7254): fehler: Net::FCP::Exception<<uri_error,reason:Unknown keytype>>, wird einfach ignoriert :)
747     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data_found,data_length:74:metadata_length:74>
748     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data,chunk:116:total:116:received:116>
749     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): Lo and Behold! We got something!
750     ... usw.
751    
752     Benutzt man das C<Coro>-Modul, so kann man Callback-basierte und Thread-
753     (bzw. Coroutinen-) basierte Programmierung mischen:
754 root 1.6
755     use Net::FCP qw(event=Coro);
756    
757     my $fcp = new Net::FCP;
758 root 1.4
759     # Achtung. Pseudocode :)
760     for my $url (@urls) {
761     async {
762     my ($meta, $data) = @{ $fcp->client_get ($url) };
763    
764     if ($meta ist ein splitfile) {
765     for (@alle_splitfile_blöcke) {
766     $fcp->txn_client_get (...)
767     ->cb (\&save_splitfile_block);
768     }
769     } else {
770     # direkt speichern
771     }
772     };
773     }
774    
775     =head2 Splitfiles
776    
777     Das Them Splitfiles möchte ich hier noch erwähnen, aber nicht
778     ausführlich besprechen.
779    
780     Da die Datenblöcke im Freenet (zur Zeit) nicht größer als 1MB sein
781     können, müssen größere Dateien (Filme z.B.) aufgeteilt werden. Wenn
782     man viele Datenblöcke für eine Datei braucht, erhöht sich die
783     Wahrscheinlichkeit dafür, das ein Block mal fehlt oder nicht gefundne
784     werden kann, stark auf einen Wert, der das Herunterladen großer Dateien
785     unmöglich macht.
786    
787     Daher wird mit Fehlerkorrekturcodes die Anzahl der Blöcke um 50%
788     erhöht. Metadaten für ein Splitfile sehen so aus:
789    
790     'version' => { 'revision' => '1' },
791     'document' => [ {
792     'info' => {
793     'checksum' => '3bab309132f812cb2a281357b0dc1036920672e2',
794     'format' => 'video/mpeg',
795     'description' => 'Onion FEC v1.2 file inserted by Fuqid'
796     },
797     'split_file' => {
798     'algo_name' => 'OnionFEC_a_1_2',
799     'check_block_count' => '3f',
800     'block_count' => '7f',
801     'check_block' => {
802     '33' => 'freenet:CHK@eTNQmnQ8aoZor3CBzTSsI~oPn6EUAwI,I4XDi1SbdKlFnyGoIRZBLg',
803     '32' => 'freenet:CHK@Ee1h~wxPSqSOFKg3WZ90KXqwQZMUAwI,ppnEYTKkp7Dyk1z3Sempqw',
804     '1e' => 'freenet:CHK@5gBBquHWc7WKjfjO27kOtU0hZgkUAwI,OkfOgz9BPvMxwvtX~wfVNA',
805     [viele Zeilen fehlen hier :]
806     '3d' => 'freenet:CHK@iIT1KzjEyXptPyOToFsyyytV-roUAwI,9u3qhWXzi8v--eY7Onag1g',
807     '5' => 'freenet:CHK@EeVsnou1WxkZg9CNBNVzvTTQ1l0UAwI,q6edARpUGxg5Oh-cc79WBA'
808     },
809     'block' => {
810     '33' => 'freenet:CHK@j522RLeAYwiNah2ZK1D1q4UDnFgUAwI,XwoBGzhdGMkyXFwI5f9iyw',
811     '32' => 'freenet:CHK@VU5v9PNahADgvy-Dnk8SCt9ZKbYUAwI,iX~d0b-YKcwt3Yk0rmpM9w',
812     '5d' => 'freenet:CHK@-wbXzvl32R8aSuotK~uZbJp14zsUAwI,-bgXeuzi6SpKYvbwQeYtyA',
813     [viele Zeilen fehlen hier :]
814     '43' => 'freenet:CHK@zMXcOMm1DlNB4ee1cftvdK4~QukUAwI,o99L7InOc4E7adXUXGjrlg',
815     '5' => 'freenet:CHK@1ZDivRb~iBdn2NYTKQbDq1yCPWAUAwI,B9fXQ8jF~DzmfOx~PTZkAA',
816     '3d' => 'freenet:CHK@ZGxa5ipGqKuZEqQIf6rbr-g8btMUAwI,f0xOciFlFA0bmmxoJRzaLw'
817     },
818     'size' => '7e8e804'
819     }
820     } ],
821     }
822    
823     Die Datenblöcke und die zusätzlichen Korrekturblöcke sind getrennt
824     aufgeführt. Man braucht nur so viele Blöcke insgesamt, wie die Datei
825     groß ist. Den Rest kann man aus den heruntergeladenen erzeugen.
826    
827     Wie genau die Daten auf die Blöcker verteilt werden unterliegt einem
828     Algorithmus und ist nicht in dne Metadaten gespeichert. Der Grund ist,
829     das jedes Programm denselben Algorithmus benutzen muss und Dateien daher
830     immer gleich auf die Blöcke verteilt werden, so das Mehrfacheinfügen ins
831     Freenet keine Duplikate erstellt.
832    
833     Der genauen Algorithmus kann man in der Datei C<bin/fmd>, dem I<Freenet
834     Mass Downloader> in der Funktion C<state_splitfile> nachlesen. Der Code
835     ist weder besonders klar, noch besonders kurz noch besonders hübsch. Auch
836     dieser Teil wird irgendwann einmal in ein Modul fließen, damit er anderen
837     zugänglicher wird.
838    
839     Interessant ist noch, das man CHK-Inhalte, die aus dem Freenet
840     heruntergeladen werden einfach auf Konsistenz prüfen kann: Sie enthalten
841     schließlich den SHA1-Hash der Daten:
842    
843     use Net::FCP::Util;
844    
845     my ($meta, $data) = @{ $fcp->client_get ($uri) };
846    
847     # Extrahiere den Hash aus der URI
848     my $k1 = Net::FCP::Util::extract_chk_hash $uri;
849     # Berechne den Hash aus den Daten
850     my $k2 = Net::FCP::Util::generate_chk_hask "$meta->{raw}$data";
851    
852     # Idealerweie stimmen beide überein...
853     $k1 eq $k2 or die "Key/Content mismatch!";
854    
855     Zwar ist der Freenet-Daemon angeblich perfekt, aber früher passierte
856     es tatsächlich oft, daß man korrupte Daten geliefert bekam. Retryen
857     half. Man hat es eben nicht so leicht...
858    
859     Heute ist das zwar nicht mehr der Fall (...), aber prüfen kostet fast
860     nichts.
861    
862 root 1.7 =head1 Publizieren
863 root 1.1
864 root 1.4 Das Freenet lebt von vielen Dingen: Den Entwicklern, den Benutzern die
865     ihr Interesse bekunden, den Regierungen, die die Meinungsäußerung
866     einschränken aber vor allem dadurch, das es sinnvolle Inhalte darin gibt.
867    
868     Ich bin mir nicht so sicher, I<ob> es so viele sinnvolle Inhalte gibt,
869     aber noch gab es ja auch keine 1.0-Release...
870    
871     Nun ja, solange man nichts ins Netz stellt, darf man auch nicht klagen.
872    
873     Das kann man ändern, indem man so langweilige Dinge wie den I<Freenet
874 root 1.7 Insertion Wizard> oder das beliebte I<Fuqid> benutzt (was ich noch nie
875     getan habe). Aber die benutzen kein Perl und sind damit langweilig.
876 root 1.4
877     Mit C<Net::FCP> geht es erstmal sehr einfach:
878    
879     $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
880    
881     (Auch hier gibt es natürlich wieder die entsprechende C<txn_>-Variante).
882 root 1.7
883     Einfügen von Inhalten geht also fast geanuso wie Auslesen. C<$uri> ist
884     eine Freenet-"URI" (mit oder ohne C<freenet:>), wie man zu dieser kommt
885     gleich mehr.
886    
887     C<$metadata> kann entweder ein Freenet-Metadata-String sein oder ein Hash
888     der gleichen Form wie man ihn zurückgeliefert bekommt. C<$data> sind
889     natürlich die eigentlichen Daten und C<$htl> sind die Hops-To-Live, die
890     der Key-Insert haben soll. Höhere Werte (bis hin zu 25) speichern die
891     Daten dauerhafter, brauchen aber auch entsprechend länger.
892    
893     C<$removelocal>, auf C<1> gesetzt, sorgt dafür, daß der lokale
894     Netzknoten die Daten I<nicht> cached. Warum man das tun sollte, ist
895     einfach erklärt: Wenn Freenet beim Einfügen die Daten schon im Netz
896     vorfindet, wird der Einfügevorgang abgebrochen. Möchte man die Daten
897     regelmäßig "auffrischen" dann sorgt diese Option dafür, daß die
898     Daten den Knoten auf jeden Fall verlassen und erhöhen so die Chance auf
899     Verbreitung.
900    
901     Nun die Frage wie man zu einer URI kommt. Möchte man einen CHK-Schlüssel
902     einfügen, so setzt man die URI einfach auf den String C<CHK@>. Nach dem
903     Einfügen erhält man die eigentliche URI als Resultat:
904    
905     my $attr = $fcp->client_put ('CHK@', "", "Daten\n", 20);
906     print "eingefügte URI: $attr->{uri}\n";
907    
908     Als Ergebnis dieses C<client_put>-Requests erhielt ich:
909    
910     freenet:CHK@MT~LuxKHH8fugJehkcgp239h7C4KAwI,378rJzHVZbsQbd7VGMHxSg
911    
912     Beim Einfügen ins Freenet kann es auch einen I<Key Collision>-Fehler
913     geben, und zwar genau dann, wenn Freenet die Daten schon findet, die man
914     einfügen wollte.
915    
916     C<Net::FCP> behandelt diesen Fehler allerdings genauso wie ein
917     erfolgreicher Einfügevorgang, lediglich im Hash, den es zurückliefert,
918     wird das C<key_collision>-Element auf C<1> gesetzt. Wenn die Daten schon
919     vorhanden sind, ist das Ziel schließlich auch erreicht.
920    
921     Häufig möchte man den C<CHK>-Schlüssel aber schon im voraus
922     Wissen. Dazu kann man entweder seinen freundlichen Freenet-Daemon fragen:
923    
924     my $key = $fcp->generate_chk ($metadata, $data);
925    
926     Oder man verwendet das C<Net::FCP::Key::CHK>-Modul, das schneller ist und
927     keinen Serverzugang benötigt:
928    
929     use Net::FCP::Key;
930    
931     my $key = (new_from_data Net::FCP::Key::CHK $metadata, $data)->chk;
932    
933     =head2 SSK-Schlüssel generieren
934    
935     SSK-Schlüssel bestehen immer aus zwei Teilen, dem öffentlichen
936     (C<public_key>) und dem privaten (c<private_key>), die zusammen ein Paar
937     bilden. Neuerdings noch aus einem dritten, dem C<crypto_key>, der es
938     Brute-Force-Attacken noch schwieriger machen soll.
939    
940     Solch ein Schlüsselpaar kann man mit einem Aufruf von
941     C<generate_svk_pair> (auch hierfür gibt es eine C<txn_>-Variante)
942     erzeugen. Das "svk" ist übrigens kein Schreibfehler: SSK-Schlüssel sind
943     ein Spezialfall von SVK-Schlüsseln, die man aber als normalsterblicher
944     nirgendwo direkt antrifft.
945    
946     my ($public, $private, $crypto) = @{ $fcp->generate_svk_pair };
947    
948     Daraus kann man beliebig viele SSK-Schlüssel erzeugen, indem man die drei
949     Teile wie folgt zusammensetzt:
950    
951     # Öffentlicher Schlüssel:
952    
953     my $name = "..."; # beliebig
954    
955     my $get = "SSK\@${public}PAgM,$crypto/$name";
956     my $put = "SSK\@$private,$crypto/$name";
957    
958     Den mit C<$put> bezeichneten Schlüssel muss man zum Einfügen
959     verwenden. Mit dem mit C<$get> bezeichneten Schlüssel kann man diese
960     Daten wieder holen. Letzterer kann bedenkenlos veröffentlich werden.
961    
962     Das SSK-Management kann vom C<Net::FCP::Key::SSK>-Modul übernommen
963     werden.
964    
965     =head2 Eine Freesite erzeugen
966    
967     Um eine Freesite zu erzeugen, sollte man sich zuerst einen dauerhaften
968     SSK-Schlüssel besorgen:
969    
970     # perl -MNet::FCP -MNet::FCP::Key::SSK \
971     -e 'Net::FCP::Key::SSK->new_from_fcp (Net::FCP->new) \
972 root 1.8 ->save ($ARGV[0])' mykey
973 root 1.7
974 root 1.8 Das erzeugt einen neuen SSK-Schlüssel und speichert ihn gleich in der
975 root 1.7 Datei C<mykey>.
976 root 1.8
977     Dieser SSK-Schlüssel wird die Basis der Freesite.
978    
979     Für das Einfügen schreibt man sich am besten ein Skript, da man ides
980     regelmäßig wiederholen sollte. Zuerst ein paar Definitionen:
981    
982     my $edition = 1;
983     my $keyfile = "mykey";
984     my $htl = 10;
985    
986     Das Skript legt eine Editionenbasierte Freesite an und benutzt als Basis
987     den eben erzeugten SSK-Schlüssel. Der Hops-To-Live-Wert von 10 ist etwas
988     klein, aber so dauert das Einfügen vielleicht nur ein paar Minuten... In
989     der Praxis sollte man 20-25 vorziehen, oder das Einfügen regelmäig
990     wiederholen.
991    
992     Als nächstes benötigen wir ein paar Module:
993    
994     use Net::FCP qw(event=Event);
995     use Net::FCP::Metadata;
996     use Net::FCP::Key::SSK;
997    
998     Generell sollte man in einem Perl-Programm den verwendeten
999     Event-Mechanismus fest angeben. In Freenet-Modulen sollte man dies dagegen
1000     nicht tun, um dem Benutzer die Wahl zu überlassen. Stattdessen sollte
1001     man in Modulen nur Transaktionen benutzen und diese dem Benutzer zur
1002     Verfügung stellen.
1003    
1004     Als nächstes werden ein paar notwendige Objekte erzeugt:
1005    
1006     my $fcp = new Net::FCP;
1007     my $ssk = new_from_file Net::FCP::Key::SSK $keyfile;
1008     my $manifest = new Net::FCP::Metadata;
1009    
1010     Die Metadaten für die Hauptseite (C<$manifest>) werden auch
1011     "Manifest" genannt, da man dort häufig nur Verweise auf die
1012     jeweiligen Unterseiten ablegt, also sowas wie der Grundstein einer
1013     Freesite. Das C<Net::FCP::Metadata>-Modul biette zur Zeit nur spärliche
1014     Funktionalität, für unsere Zwecke reicht das jedoch aus.
1015    
1016     Nun noch zwei Hilfsfuntionen. Zuerst C<add_key>:
1017    
1018     sub add_key {
1019     my ($name, $key, $meta, $data) = @_;
1020    
1021     # Asynchrones Einfügen
1022     $fcp->txn_client_put ($chk, $meta, $data, $htl, 1)
1023     ->cb (sub {
1024     eval {
1025     my $attr = $_[0]->result;
1026     printf "Insert of '%s' (%d bytes) ok.\n", $name, length $data;
1027     } or warn "Error while inserting '$name': $@";
1028     });
1029     }
1030    
1031     C<add_key> startet eine C<client_put>-Transaktion, ohne auf das Ende zu
1032     warten. Im Callback wird das Resultat angezeigt, oder, wenn ein Fehler
1033     Auftrat, eben dieser. Das Skript sollte so angelegt sein, das man es
1034     einfach nochmal starten kann, wenn einige Schlüssel nicht eingefügt
1035     werden konnten.
1036    
1037     Nun noch C<add_file>:
1038    
1039     # Hilfsfunktion zum Einfügen von Dateien
1040     sub add_file {
1041     my ($name, $path, $contenttype) = @_;
1042    
1043     # lies die Datei ein
1044     my $data = do {
1045     local $/;
1046     open my $fh, "<", $path
1047     or die "$path: $!";
1048     <$fh>
1049     };
1050    
1051     my $chk = $fcp->generate_chk ("", $data); # keine metadaten
1052     $manifest->add_redirect ($name => $chk, format => $contenttype);
1053     add_key $name, $chk, "", $data;
1054     }
1055    
1056     C<add_file> lädt eine externe Datei (< 1MB) und berechnet deren
1057     CHK-Schlüssel. Diesen Schlüssel fügt es als Verweis unter dem Namen
1058     C<$name> in das Manifest ein. Als letztes benutzt es C<add_key>, um die
1059     Datei einzufügen.
1060    
1061     Das Vorausberechnen des CHK-Schlüssels macht es möglich, das Manifest
1062     paralelle zu den anderen Schlüsseln einzufügen. Würde man auf den
1063     Einfügevorgang waretn, müsste man das Manifest am Ende getrennt
1064     hochladen.
1065    
1066     Nun ans Zusammebauen. Zuerst werden (unsichtbare) Verweise auf die
1067     vorherige bzw. die nächste Edition eingefügt:
1068    
1069     $manifest->add_redirect (".prev" => $ssk->gen_pub ($edition - 1)) if $edition > 1;
1070     $manifest->add_redirect (".next" => $ssk->gen_pub ($edition + 1));
1071    
1072     Dies nutzt zum einen die Eigenschaft von SSKs, einfach vorausberechnet
1073     werden zu können, als auch die Methode C<gen_pub>, die den öffentlichen
1074     SSK-Schlüssel mit optionalem Suffix generiert.
1075    
1076     Dadurch können Benutzer auch "per Hand" eine neuere oder ältere Edition
1077     suchen, indem sie einfach die Zahl (C<.../2//index.html>) vor dem C<//>
1078     ändern.
1079    
1080     Als nächstes folgt der Eigentliche Inhalt der Freesite, eine HTML-Seite,
1081     ein Bild und der Quellcode des Skriptes, der sie generiert hat:
1082    
1083     add_file "activelink.png" => "logo.png", "image/png";
1084     add_file "" => "index.html", "text/html";
1085     add_file "index.html" => "index.html", "text/html";
1086     add_file "freesite" => "freesite", "text/plain";
1087    
1088     Die Datei C<index.html> wird zweimal hinzugefügt, einmal unter dem Namen
1089     "" und ein zweitesmal unter dem Namen "C<index.html>". Dadurch kann man
1090     erreichen, was viele HTTP-Server ebenfalls machen, nämlich eine URI, die
1091     auf ein Verzeichnis zeigt, auf eine Datei darin zu verweisen. Das die
1092     Datei zweimal eingefügt wird ist kein Problem, da der CHK-Schlüssel
1093     derselbe ist (und Mehrfacheinfügen kein Fehler).
1094    
1095     Nachdem die Dateien hinzugefügt (und vor allem ins Manifest eingetragen)
1096     wurden, kann man das Manifest einfügen:
1097    
1098     my $site = $ssk->gen_pub ($edition);
1099     add_key "manifest", $site, $manifest, "";
1100    
1101     Das Manifest wird. Damit man hinterher auch weiss, was man da eingefügt
1102     hat, sollte man den Hauptschlüssel auch ausgeben:
1103    
1104     print "site generated as $site//\n";
1105    
1106     Und da die ganzen Einfügevorgange ja nur gestartet wurden, muss man auf
1107     deren Ende warten:
1108    
1109     Event::loop;
1110    
1111     Solange C<Event> noch aktive Watcher sieht, bleibt es in der
1112     Event-Schleife. Wenn es keinen aktiven Watcher mehr gibt, kehrt C<loop>
1113     automatisch zurück und das Programm ist beendet.
1114    
1115     Die Ausgabe sieht dann z.B. so aus:
1116    
1117     site generated as SSK@wgvWpYYe4QfTBRylfnDlUBfjETgPAgM,Jrm3qco-SQkUBDPfw1UO1g/1//
1118     Insert of 'freesite' (1688 bytes) ok.
1119     Insert of 'activelink.png' (1346 bytes) ok.
1120     Insert of 'index.html' (200 bytes) ok.
1121     Insert of '' (200 bytes) ok.
1122     Insert of 'manifest' (0 bytes) ok.
1123    
1124     Wenn man einen Fehler gemacht hat, kann man einfach einen neuen
1125     SSK-Schlüssel generieren. Das heißt, solange man seine Site nicht schon
1126     veröffentlicht hat.
1127    
1128     Die Alternative wäre z.B. ein täglicher Date-Based-Redirect, d.h.
1129     tägliches komplettes Neueinfügen. Da bügeln sich Fehler schnell von
1130     selbst aus, man muss sein Skript dann natürlich über Tage oder Monate
1131     regelmäßig starten.
1132    
1133     Eine offensichtliche Verbesserung wäre es, HTML-Dateien abzuändern, so
1134     daß man Links auf die nächste Revision nicht hardcodieren muss sondern
1135     etwa als C<%%NEXT%%//activelink.png> schreiben könnte.
1136    
1137     Nun ja, ich hoffe, es machen sich nun einige Leser auf, um eigene
1138     Freesites zu erstellen oder andere Anwendungen für das Freenet zu
1139 root 1.13 erstellen.
1140    
1141     =head1 Verweise
1142    
1143     =over 4
1144    
1145     =item C<http://www.freenetproject.org/>
1146    
1147     Die Hauptseite des Freenet-Projekts. Hier gibt es auch White-Papers, etwas
1148     Dokumentation und Mailinglisten(-archive).
1149    
1150     =item C<http://www.freenethelp.org/>
1151    
1152     Hier findet der gestresste Freenetter Hilfe beim Einrichten und Betrieb
1153     seines Knotens. Vielleicht.
1154    
1155     =back
1156 root 1.8
1157 root 1.7
1158    
1159 root 1.1