ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/freenet.pod
Revision: 1.8
Committed: Sun May 16 19:53:21 2004 UTC (22 years, 4 months ago) by root
Branch: MAIN
Changes since 1.7: +167 -2 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     verbreiten zu können ohne Maßnahmen von der Regierung zu befürchten.
28    
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     die man amchen möchte:
279    
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     Die Metadaten sind als Textdokument gespeichert. das Parsen dieser
313     Metadaten ist aber relativ krank, weshalb das Perl-Modul einen Hash mit
314     den geparsten Daten liefert.
315    
316     Die Metadaten und Daten kann man ausgeben:
317    
318     use Data::Dumper;
319     print STDERR Dumper $meta;
320     print $data;
321    
322     Dies ist genau der Quelltext für das "Tool" C<eg/fetch1>, mit dem man
323     I<einen> Freenet-Datenblock herunterladen kann.
324    
325     Ich benutze es üblicherweise so:
326    
327     eg/fetch1 SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// >data
328    
329     Das schreibt die Daten in eine Datei und gibt gleichzeitig dessen
330     Metadaten aus.
331    
332     Für den Key C<SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//> ergibt dies:
333    
334     'version' => { 'revision' => '1' },
335     'document' => [
336     {
337     'info' => { 'format' => 'image/png' },
338     'redirect' => { 'target' => 'freenet:CHK@pMKWiJyE3t-ZWvL1W9VdZvB3jcIKAwI,7pdyQiW7Hp9-8fEp-25C2w' },
339     'name' => 'activelink.png'
340     },
341     {
342     'info' => { 'format' => 'text/plain' },
343     'redirect' => { 'target' => 'freenet:CHK@2hewSY-I5ZhWpJ84dwhPbtdlvyIKAwI,ovcsrpD79xZfoW2021z91w' },
344     'name' => 'description.txt'
345     },
346     {
347     'info' => { 'format' => 'text/html' },
348     'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' },
349     'name' => 'index.html'
350     },
351     {
352     'info' => { 'format' => 'text/html' },
353     'redirect' => { 'target' => 'freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4' },
354     'name' => '.next'
355     },
356     {
357     'info' => { 'format' => 'text/html' },
358     'redirect' => { 'target' => 'freenet:CHK@kME~NY2lX3q-em40ExTAFkyr~NkQAwI,3T2hFmTrPbLhCBANdy4OkA' }
359     }
360     ],
361     'raw' => 'Version
362     Revision=1
363     [... gekürzt...]
364     Info.Format=text/html
365     End
366     '
367     };
368    
369     Die eigentlichen Daten sind leer (Null Byte gross), das Dokument enthät
370     also nur Metadaten! Man beachte vor allem die teilweise recht tiefe
371     Verschachtelung.
372    
373     Der Key C<< $metadata->{raw} >> enthält die Metadaten, wie sie vom
374     Freenet kamen. Dies ist notwendig, da man manchmal die Metadaten
375     zum Prüfen in der exkaten Form benötigt, wie sie hochgeladen
376     wurden. Ansonsten kann man sie ignorieren.
377    
378     Der Key C<< $metadata->{document} >> enthält Informationen über das
379     Dokument oder in diesem Fall die Dokumente: Ein Hash pro Dokument. Schaut
380     man sich den Inhalt an (ein Array), so sieht man in jedem Hash ein
381     C<name>-Key, der den Namen des Subdokuments angibt (bis auf den letzten,
382     darauf komme ich gleich).
383    
384     Schaut man sich dir Freenet-URIs dieser Freesite an, so sieht man
385     derartige URIs:
386    
387     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3// # Hauptseite
388     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//activelink.png # Icon
389     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//description.txt # Beschreibung für Spider
390    
391     Wenn diese Dokumente mit C<client_get> anfordert, bekommt man immer obiges
392     Dokument. Freenet ignoriert nämlich alles, was hinter dem C<//> steht
393     und liefert daher immer das gleiche Dokument aus dem SSK-Bereich. (Darauf
394     verlassen soltle man sich nicht unbedingt, in Zukunft reagiert der
395     Freenet-Daemon vielleicht anders. Als Freenetter hat mans eben nicht
396     leicht).
397    
398     Der Teil hinter den beiden Slashes (C<//>) ist nun das Unterdokument, das
399     man über den Namen identifizieren kann:
400    
401     $activelink = grep $_->{name} eq "activelink.png",
402     @{ $metadata->{document} };
403    
404     Fehlet der C<name>-Eintrag ist es der Eintrag mit dem leeren Namen, in
405     diesem Fall der erste Link, der nichts nach den C<//> stehen hat. Der
406     C<name>-Key I<kann> vorhanden und leer sein: Freenet überprüft die Daten
407     nicht, daher gibt es durchaus unterschiedliche Auslegungen für das genau
408     Format.
409    
410     Die Metadaten sind etwas genauer in dem *hüstel* etwas veralteten
411     *hüstel* I<Freenet Explained>-Dokument beschrieben.
412    
413     Möchte man nun das C<activelink.png> herunterladen muss man in C<<
414     $activelink->{redirect} >> nachsehen. Meistens verweist dies auf ein
415     C<CHK>-Schlüssel. Letztere sind sozusagen Allgemeingut: jeder kann
416     sie benutzen, und da sie nicht änderbar sind, kann sie auch niemand
417     fälschen, daher muss man sie nicht signieren.
418    
419     Auf C<< $activelink->{info}{format} > sollte man sich übrigens nicht
420     verlassen.
421    
422     Und sollte kein C<redirect>-Key vorhanden sein, so ist das Dokument im
423     mitgelieferten Datenblock. Alles ganz logisch, einfach, und klar, wie man
424     sieht.
425    
426     Egal, der CHK-Key für C<activelink.png> liefert folgendes:
427    
428     'version' => { 'revision' => '1' },
429    
430     Und die Daten stellen ein PNG dar. Naja, nicht gerade üppig, die
431     Metadaten, aber man hätt's ja im Link auf dieses Dokument sehen
432     können. Als Freenetter hat mans nicht leicht.
433    
434     Aber mit diesen Erklärungen kann man schon einfacher Freenet-Spider
435     bauen. Die wichtigsten Tools sind veraltete und spärliche Dokumente
436     wie I<Freenet Explained> und Tools wie C<Data::Dumper>. "Veraltet" ist
437     übrigens nicht immer schlecht, da viele Dokumente auch alt sind oder sich
438     eh' nicht exakt an den "Standard" halten. Mit der Zeit wird hier sicher
439     eine Besserung eintreten.
440    
441     =head2 Methoden des Freesite-Managements
442    
443     Oder: "Wenn man Inhalte nicht mehr verändern kann, wie verändert man
444     sie?"
445    
446     Die offensichtliche Methode ist: "Man macht sie veränderbar". In
447     der Freenet-Gemeinde geistert seit langer Zeit der Mythos des
448     I<TUK>-Schlüssels, des I<Time Updatable Keys>. Diese Schlüssel tauchen
449     immer auf, wenn jemand über veränderbare Schlüssel spricht. Leider
450     weiss niemand, wie man sie implementieren soll, und ganz persönlich
451     fürchte ich, es wird niemals veränderbare Keys geben.
452    
453     =head3 "Editions"
454    
455     Die nächstliegende Methode nutzt die Eigenschaft von SSKs (genauer:
456     redirects) aus, das man den Namen sofort generieren kann, den Inhalt aber
457     erst später einfügt.
458    
459     Dies nutzt man aus, indem man I<Editionen> herausgibt und
460     durchnummeriert. Jede Edition enthält einen Link auf die nächste. Bis
461     man die nächste Edition einfügt, wird der Link-Inhalt nicht gefunden.
462    
463     Üblicherweise benutzt man in HTML ein C<IMG>-Element mit Link auf ein
464     Bild aus der nächsten Edition. Sieht man das Bild, weiss man, die
465     nächste Edition existiert und kann sich hinklicken.
466    
467     I<Freenet Explained> benutzt diese Methode. Der Link auf Edition 4 lautet:
468    
469     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4// # Link-Ziel
470     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/4//activelink.png # IMG-SRC
471    
472     Beides existierte nicht als ich diesen Artikel schrieb (bzw. Freenet
473     konnte es nicht finden :). Wenn eine neue Edition heruasgegeben werden
474     soll, fügt der Autor einfach einen neuen Datenblock mit vielen Redirects
475     unter obigem SSK-Key ein.
476    
477     Ein C<.next>-Eintrag ist ebenfalls vorhanden: manche Spider folgen diesem
478     und können auf diese Weise immer die aktuelle Edition anzeigen, sofern
479     sie häufig genug scannen.
480    
481     Editionen sind einfach für den Autor einer Freesite und erfordern
482     keine spezielle Unterstützung. In der Benutzung sind sie allerdings
483     umständlich und häufige Updates sind auch nicht effizient.
484    
485     Daher hat sich eine zweite Methode entwickelt, die gerade bei häufig
486     geänderten Inhalten besser funktioniert:
487    
488     =head3 "Date Based Redirects"
489    
490     Freesites, die "Date Based Redirects" benutzen (kurz "DBR-Sites")
491     funktionieren ähnlich wie Editionen-basierte Freesites, nur wird statt
492     einer fortlaufenden Nummer die aktuelle Zeit benutzt.
493    
494     Die Freesite I<The Freenet Help Index>
495     (C<SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/FreenetHelp//>) benutzt diese
496     Methode. Folgende Metadaten wurden dazu hinterlegt:
497    
498     'version' => { 'revision' => '1' },
499     'document' => [
500     { 'date_redirect' => {
501     'increment' => '15180',
502     'target' => 'SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/FreenetHelp'
503     }
504     }
505     ],
506    
507     Statt einem einfachen C<redirect> gibt es jetzt einen
508     C<date_redirect>-Eintrag, und darin ein C<target> (dürfte bekannt sein)
509     und der Key C<increment>. Letzterer darf wie üblich fehlen, man sollte
510     dann C<86400> annehmen (ein Tag hat 86400 Sekunden). In diesem Beispiel
511     wird 86400 genommen (Hexadezimal 15180).
512    
513     Habe ich eigentlich schon erwähnt das jede Zahl im FCP-Protokoll oder
514     im Freenet hexadezimal kodiert wird? Also, praktisch immer, außer wenn
515     es mal nicht so ist. Und wozu man einen Offset addiert ist mir auch
516     schleierhaft. In der freien Wildbahn habe ich sowieso noch keinen gesehen.
517    
518     Der Link in C<target> ist nicht vollständig (unter anderem fehlt
519     hinten ein C<//>). Der komplette Link wird generiert, "indem die
520     aktuelle Zeit (POSIX-Zeit, üblicherweise das, was C<time> liefert),
521     auf C<increment>-Schritte gerundet und C<offset> addiert, als
522     Big-Endian-Hexadezimalzahl nach dem ersten Slash mit folgendem
523     Minuszeichen eingefügt wird."
524    
525     Und jetzt in Perl - zum Verstehen:
526    
527     my $doc = $metadata->{document][0]; # Oder [1] oder ...
528    
529     my $increment = (hex $doc->{increment}) || 86400;
530     my $offset = (hex $doc->{offset}) || 0;
531     my $target = $doc->{target} || die;
532    
533     my ($head, $tail) = split /\//, $target, 2;
534    
535     my $NOW = time;
536     my $time = $NOW - $NOW % $increment + $offset;
537    
538     my $result = sprintf "%s/%x-%s", $head, $time, $tail;
539    
540     Für "jetzt" (C<time() == 1084388445>) liefert der Algorithmus folgenden Link:
541    
542     SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/40a16900-FreenetHelp
543    
544     Und tatsächlich, unter diesem Key findet man wieder ein Dokument mit
545     vielen Redirects.
546    
547     DBRs haben den Vorteil, "automatisch" aktuell zu sein. Solange man nur
548     Redirects einfügt, ist die Belastung durch neue das Einfügen vieler
549     neuer Daten gering, Freenet kommt damit zurecht und löscht alte DBRs
550     bei Bedarf automatisch (ohne natürlich zu wissen, das sich in dne
551     Datenblöcken DBRs befinden, dnen die kann ja niemand dekodieren,d er
552     nicht den Schlüssel besitzt).
553    
554     Der Nachteil ist, das man eine aktuelle Uhrzeit braucht um die Site zu
555     finden. Schlimemr noch: die Freesite muss regelmäßig neu eingefügt
556     werden, eben alle C<increment> Sekunden.
557    
558     DBR-Freesites, die nicht mehr maintained werden, verschwinden deshalb fast
559     sofort, solange man nicht einen Zeitpunkt kennt, zu dem sie noch (bzw.
560     schon!) existierte.
561    
562     All dieses I<sollte> eigentlich in einem Metadata-Modul stattfinden. So
563     weit bin ich aber nicht, da mein Hauptziel das effiziente Herunterladen
564     großer Dateien ist.
565    
566     Womit ich beim Thema wäre.
567    
568     =head1 Effizient herunterladen
569    
570 root 1.4 Transfers im Freenet zeichnen sich durch zwei Eigenschaften aus: hohe
571     Latenz und vergleichsweise hoher Durchsatz. Dies ist ungewöhnlich, ergibt
572     sich aber aus dem Suchverfahren: die Suche nach einem Datenblock kann sehr
573     lange dauern (sogar einige Male fehlschlagen bevor die Daten eintreffen),
574     sie sind jedoch einfach parallelisierbar.
575    
576     Wie in Java üblich, erreichte man dies früher durch massive Benutzung
577     von Threads. Der Freenet-Referenz-Daemon ist davon inzwsichen abgekommen
578     (zu langsam, zu viel Speicher und zu hohe Komplexität), doche viele
579     Clients haben auch heute noch Voreinstellungen wie "Anzahl der Threads pro
580     Download" und viele sind auch so implementiert.
581    
582     Da Perls Thread-Implementierung ein Prozessmodell emuliert (kaum sharing
583     möglich) ist der overhead ebenfalls entsprechend hoch, und man erhält
584     durch Threads keinen nennenswerten Vorteil, ausser das alles etwas
585     langsamer läuft und man besser zuschauen kann :)
586    
587     Für C<Net::FCP> (oder besser: für mich) kam es deshalb nicht in Frage,
588     Parallelisierung auf Thread-Basis zu implementieren. Da sProblem auf
589     den Modul-Benutzer abzuschieben erschien mir auch nicht fair, daher
590     unterstützt C<Net::FCP> die Module L<Coro>, L<Event>, L<Glib> oder L<Tk>,
591 root 1.6 bzw. deren Event-Steuerung. Man hat also die Wahl, auf welcher Basis man sein
592 root 1.4 Programm aufbaut, und es geht auch ganz ohne Event-System (wie die obigen
593     einfachen Beispiele zeigen).
594    
595     =head2 Transaktionen
596    
597     C<Net::FCP> benutzt für jeden Request eine I<Transaktion>. Das ist ein
598     Objekt, das den Zustand und eintreffende Ergebnisse speichert.
599    
600     Jede Anfrage, (z.B. C<client_get>) wird intern in ein solches
601     Transaktionsobjekt verwandelt. Für jede "einfache" Methode wie
602     C<client_get> oder C<insert_private_key> gibt es eine entsprechende
603     Methode mit C<txn_>-Präfix, die statt des Resultats ein solches Objekt
604     liefert.
605    
606     Transaktionsobjekte besitzen einige Methoden, mit denen sie konfiguriert
607     werden können oder Ergebnisse abgefragt werden können. Die wichtigste
608     ist die C<result>-Methode, die auf das Ergebnis wartet und es
609     zurückliefert:
610    
611     # $fcp->client_get wird intern so implementiert:
612     my $txn = $fcp->txn_client_get (...);
613     return $tdn->result;
614    
615     Es ist übrigens immer gefahrlos, Transaktionsobjekte zu erzeugen. Etwaige
616     Fehler bei der Durchführung werden immer erst beim Aufruf von C<result>
617     und immer als Perl-Exceptions gemeldet.
618    
619     Um also alle Freenet-Objekte im Array C<@download> gleichzeitig
620     anzufordern, reicht folgender Code:
621    
622     map $_->result,
623     map $_->txn_client_get ($_),
624     @download;
625    
626     Zuerst werden alle URIs auf eine entsprechende Transaktion gemapped, und
627     dann von allen Transaktionen das Resultat angefordert.
628    
629     Natürlich brauchen manche Zugriffe länger als andere. Wenn Transaktionen
630     früher beendet werden, sollte man gleich eine neue starten, um Freenet
631     bei Lauen zu halten.
632    
633     Dazu benötigt man ein Signal, das eine Transaktion beendet ist. Dies
634     macht C<Net::FCP> mit Hilfe eines Callbacks:
635    
636     my $txn = $fcp->txn_client_get (...)
637     ->cb (\&callback);
638    
639     Diesen setzt man mit Hilfe der C<cb>-Methode. Alle Methoden, die ein
640     Transaktionsobjekt konfigurieren liefern das Transaktionsobjekt zurück,
641     man kann also Aufrufketten wie im Beispiel bilden.
642    
643     Der Callback wird aufgerufen, wenn der Request (erfolgreich oder nicht)
644     beendet wurde.
645    
646     Nun braucht man allerdings die Hauptschleife des jeweiligen Event-Systens,
647     da man ja nicht mehr auf ein bestimmtes Ergebis wartet, sondern auf ein
648     beliebiges.
649    
650     Dazu sollte man C<Net::FCP> auf ein bestimmtes Event-System zwingen. Das
651     folgende Beispiel tut dies und lädt die Kommandozeileargumente parallel
652     herunter:
653    
654     use Net::FCP qw(event=Event); # oder event=Glib, oder...
655    
656     my $fcp = new Net::FCP;
657     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
658    
659     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
660    
661     Die Transaktionsobjekte werden übrigens nicht gespeichert, denn sie
662     werden dem Callback übergeben und nur dort werden sie gebraucht. Der
663     Callback könnte so aussehen:
664    
665     sub finished {
666     my ($txn) = @_;
667     my ($meta, $data) = @{ $txn->result };
668     # tue etwas
669     }
670    
671     Oder, mit Fehlerprüfung:
672    
673     sub finished {
674     my ($txn) = @_;
675     my ($meta, $data) = eval { @{ $txn->result } };
676     if ($@) {
677     warn "fehler: $@, wird einfach ignoriert :)"
678     } else {
679     warn "Lo and Behold! We got soemthing!";
680     # tue etwas
681     }
682     }
683    
684     =head2 Fortschritt ist nicht aufzuhalten
685    
686     Da Zugriffe recht lange dauern können, schickt Freenet regelmäig
687     Fortschrittsreports. Man kann sich das vorstellen wie C<warn> und
688     C<die>: C<warn> liefert wichtige Informationen, C<die> einen Fehler.
689    
690     Die Fortschrittsanzeigen werden normalerweise nicht von C<Net::FCP>
691     ausgegeben (wäre irgendwie kontraproduktiv in einem GUI-Programm), man
692     kann aber einen Callback installieren:
693    
694     my $fcp = Net::FCP progress => \&progress;
695    
696     Ein solcher Progress-Callback könnte so aussehen:
697    
698     sub progress_cb {
699     my ($self, $txn, $type, $attr) = @_;
700    
701     warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
702     }
703    
704     Möchte man Informationen für den Callback bereitstellen, so bietet sich
705     die C<userdata>-Methode von Transaktionsobjekten an.
706    
707     Hier ist ein kompletter parallelisierender Client mit Fortschrittsanzeige:
708    
709     my $fcp = Net::FCP progress => \&progress;
710    
711     Ein solcher Progress-Callback könnte so aussehen:
712    
713     use Net::FCP qw(event=Event); # oder event=Glib, oder...
714    
715     my $fcp = new Net::FCP progress => \&progress_cb;
716    
717     $fcp->txn_client_get ($_)->cb (\&finished) for @ARGV;
718    
719     Event::loop; # hier passierts, loop ist die Hauptschleife von Event
720    
721     sub finished {
722     my ($txn) = @_;
723     my ($meta, $data) = eval { @{ $txn->result } };
724     if ($@) {
725     warn "$txn: fehler: $@, wird einfach ignoriert :)\n"
726     } else {
727     warn "$txn: Lo and Behold! We got something!\n";
728     # tue etwas
729     }
730     }
731    
732     sub progress_cb {
733     my ($self, $txn, $type, $attr) = @_;
734    
735     warn "$txn: progress<$txn,$type," . (join ":", %$attr) . ">\n";
736     }
737    
738     Startet man ihn mit einigen gültigen und ungültigen Freenet-URIs,
739     bekommt man vieleicht folgende Ausgabe:
740    
741     Net::FCP::Txn::ClientGet=HASH(0x81e0f64): fehler: Net::FCP::Exception<<uri_error,reason:Unspecified document name>>, wird einfach ignoriert :)
742     Net::FCP::Txn::ClientGet=HASH(0x81e7254): fehler: Net::FCP::Exception<<uri_error,reason:Unknown keytype>>, wird einfach ignoriert :)
743     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data_found,data_length:74:metadata_length:74>
744     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): progress<Net::FCP::Txn::ClientGet=HASH(0x81e0c4c),data,chunk:116:total:116:received:116>
745     Net::FCP::Txn::ClientGet=HASH(0x81e0c4c): Lo and Behold! We got something!
746     ... usw.
747    
748     Benutzt man das C<Coro>-Modul, so kann man Callback-basierte und Thread-
749     (bzw. Coroutinen-) basierte Programmierung mischen:
750 root 1.6
751     use Net::FCP qw(event=Coro);
752    
753     my $fcp = new Net::FCP;
754 root 1.4
755     # Achtung. Pseudocode :)
756     for my $url (@urls) {
757     async {
758     my ($meta, $data) = @{ $fcp->client_get ($url) };
759    
760     if ($meta ist ein splitfile) {
761     for (@alle_splitfile_blöcke) {
762     $fcp->txn_client_get (...)
763     ->cb (\&save_splitfile_block);
764     }
765     } else {
766     # direkt speichern
767     }
768     };
769     }
770    
771     =head2 Splitfiles
772    
773     Das Them Splitfiles möchte ich hier noch erwähnen, aber nicht
774     ausführlich besprechen.
775    
776     Da die Datenblöcke im Freenet (zur Zeit) nicht größer als 1MB sein
777     können, müssen größere Dateien (Filme z.B.) aufgeteilt werden. Wenn
778     man viele Datenblöcke für eine Datei braucht, erhöht sich die
779     Wahrscheinlichkeit dafür, das ein Block mal fehlt oder nicht gefundne
780     werden kann, stark auf einen Wert, der das Herunterladen großer Dateien
781     unmöglich macht.
782    
783     Daher wird mit Fehlerkorrekturcodes die Anzahl der Blöcke um 50%
784     erhöht. Metadaten für ein Splitfile sehen so aus:
785    
786     'version' => { 'revision' => '1' },
787     'document' => [ {
788     'info' => {
789     'checksum' => '3bab309132f812cb2a281357b0dc1036920672e2',
790     'format' => 'video/mpeg',
791     'description' => 'Onion FEC v1.2 file inserted by Fuqid'
792     },
793     'split_file' => {
794     'algo_name' => 'OnionFEC_a_1_2',
795     'check_block_count' => '3f',
796     'block_count' => '7f',
797     'check_block' => {
798     '33' => 'freenet:CHK@eTNQmnQ8aoZor3CBzTSsI~oPn6EUAwI,I4XDi1SbdKlFnyGoIRZBLg',
799     '32' => 'freenet:CHK@Ee1h~wxPSqSOFKg3WZ90KXqwQZMUAwI,ppnEYTKkp7Dyk1z3Sempqw',
800     '1e' => 'freenet:CHK@5gBBquHWc7WKjfjO27kOtU0hZgkUAwI,OkfOgz9BPvMxwvtX~wfVNA',
801     [viele Zeilen fehlen hier :]
802     '3d' => 'freenet:CHK@iIT1KzjEyXptPyOToFsyyytV-roUAwI,9u3qhWXzi8v--eY7Onag1g',
803     '5' => 'freenet:CHK@EeVsnou1WxkZg9CNBNVzvTTQ1l0UAwI,q6edARpUGxg5Oh-cc79WBA'
804     },
805     'block' => {
806     '33' => 'freenet:CHK@j522RLeAYwiNah2ZK1D1q4UDnFgUAwI,XwoBGzhdGMkyXFwI5f9iyw',
807     '32' => 'freenet:CHK@VU5v9PNahADgvy-Dnk8SCt9ZKbYUAwI,iX~d0b-YKcwt3Yk0rmpM9w',
808     '5d' => 'freenet:CHK@-wbXzvl32R8aSuotK~uZbJp14zsUAwI,-bgXeuzi6SpKYvbwQeYtyA',
809     [viele Zeilen fehlen hier :]
810     '43' => 'freenet:CHK@zMXcOMm1DlNB4ee1cftvdK4~QukUAwI,o99L7InOc4E7adXUXGjrlg',
811     '5' => 'freenet:CHK@1ZDivRb~iBdn2NYTKQbDq1yCPWAUAwI,B9fXQ8jF~DzmfOx~PTZkAA',
812     '3d' => 'freenet:CHK@ZGxa5ipGqKuZEqQIf6rbr-g8btMUAwI,f0xOciFlFA0bmmxoJRzaLw'
813     },
814     'size' => '7e8e804'
815     }
816     } ],
817     }
818    
819     Die Datenblöcke und die zusätzlichen Korrekturblöcke sind getrennt
820     aufgeführt. Man braucht nur so viele Blöcke insgesamt, wie die Datei
821     groß ist. Den Rest kann man aus den heruntergeladenen erzeugen.
822    
823     Wie genau die Daten auf die Blöcker verteilt werden unterliegt einem
824     Algorithmus und ist nicht in dne Metadaten gespeichert. Der Grund ist,
825     das jedes Programm denselben Algorithmus benutzen muss und Dateien daher
826     immer gleich auf die Blöcke verteilt werden, so das Mehrfacheinfügen ins
827     Freenet keine Duplikate erstellt.
828    
829     Der genauen Algorithmus kann man in der Datei C<bin/fmd>, dem I<Freenet
830     Mass Downloader> in der Funktion C<state_splitfile> nachlesen. Der Code
831     ist weder besonders klar, noch besonders kurz noch besonders hübsch. Auch
832     dieser Teil wird irgendwann einmal in ein Modul fließen, damit er anderen
833     zugänglicher wird.
834    
835     Interessant ist noch, das man CHK-Inhalte, die aus dem Freenet
836     heruntergeladen werden einfach auf Konsistenz prüfen kann: Sie enthalten
837     schließlich den SHA1-Hash der Daten:
838    
839     use Net::FCP::Util;
840    
841     my ($meta, $data) = @{ $fcp->client_get ($uri) };
842    
843     # Extrahiere den Hash aus der URI
844     my $k1 = Net::FCP::Util::extract_chk_hash $uri;
845     # Berechne den Hash aus den Daten
846     my $k2 = Net::FCP::Util::generate_chk_hask "$meta->{raw}$data";
847    
848     # Idealerweie stimmen beide überein...
849     $k1 eq $k2 or die "Key/Content mismatch!";
850    
851     Zwar ist der Freenet-Daemon angeblich perfekt, aber früher passierte
852     es tatsächlich oft, daß man korrupte Daten geliefert bekam. Retryen
853     half. Man hat es eben nicht so leicht...
854    
855     Heute ist das zwar nicht mehr der Fall (...), aber prüfen kostet fast
856     nichts.
857    
858 root 1.7 =head1 Publizieren
859 root 1.1
860 root 1.4 Das Freenet lebt von vielen Dingen: Den Entwicklern, den Benutzern die
861     ihr Interesse bekunden, den Regierungen, die die Meinungsäußerung
862     einschränken aber vor allem dadurch, das es sinnvolle Inhalte darin gibt.
863    
864     Ich bin mir nicht so sicher, I<ob> es so viele sinnvolle Inhalte gibt,
865     aber noch gab es ja auch keine 1.0-Release...
866    
867     Nun ja, solange man nichts ins Netz stellt, darf man auch nicht klagen.
868    
869     Das kann man ändern, indem man so langweilige Dinge wie den I<Freenet
870 root 1.7 Insertion Wizard> oder das beliebte I<Fuqid> benutzt (was ich noch nie
871     getan habe). Aber die benutzen kein Perl und sind damit langweilig.
872 root 1.4
873     Mit C<Net::FCP> geht es erstmal sehr einfach:
874    
875     $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
876    
877     (Auch hier gibt es natürlich wieder die entsprechende C<txn_>-Variante).
878 root 1.7
879     Einfügen von Inhalten geht also fast geanuso wie Auslesen. C<$uri> ist
880     eine Freenet-"URI" (mit oder ohne C<freenet:>), wie man zu dieser kommt
881     gleich mehr.
882    
883     C<$metadata> kann entweder ein Freenet-Metadata-String sein oder ein Hash
884     der gleichen Form wie man ihn zurückgeliefert bekommt. C<$data> sind
885     natürlich die eigentlichen Daten und C<$htl> sind die Hops-To-Live, die
886     der Key-Insert haben soll. Höhere Werte (bis hin zu 25) speichern die
887     Daten dauerhafter, brauchen aber auch entsprechend länger.
888    
889     C<$removelocal>, auf C<1> gesetzt, sorgt dafür, daß der lokale
890     Netzknoten die Daten I<nicht> cached. Warum man das tun sollte, ist
891     einfach erklärt: Wenn Freenet beim Einfügen die Daten schon im Netz
892     vorfindet, wird der Einfügevorgang abgebrochen. Möchte man die Daten
893     regelmäßig "auffrischen" dann sorgt diese Option dafür, daß die
894     Daten den Knoten auf jeden Fall verlassen und erhöhen so die Chance auf
895     Verbreitung.
896    
897     Nun die Frage wie man zu einer URI kommt. Möchte man einen CHK-Schlüssel
898     einfügen, so setzt man die URI einfach auf den String C<CHK@>. Nach dem
899     Einfügen erhält man die eigentliche URI als Resultat:
900    
901     my $attr = $fcp->client_put ('CHK@', "", "Daten\n", 20);
902     print "eingefügte URI: $attr->{uri}\n";
903    
904     Als Ergebnis dieses C<client_put>-Requests erhielt ich:
905    
906     freenet:CHK@MT~LuxKHH8fugJehkcgp239h7C4KAwI,378rJzHVZbsQbd7VGMHxSg
907    
908     Beim Einfügen ins Freenet kann es auch einen I<Key Collision>-Fehler
909     geben, und zwar genau dann, wenn Freenet die Daten schon findet, die man
910     einfügen wollte.
911    
912     C<Net::FCP> behandelt diesen Fehler allerdings genauso wie ein
913     erfolgreicher Einfügevorgang, lediglich im Hash, den es zurückliefert,
914     wird das C<key_collision>-Element auf C<1> gesetzt. Wenn die Daten schon
915     vorhanden sind, ist das Ziel schließlich auch erreicht.
916    
917     Häufig möchte man den C<CHK>-Schlüssel aber schon im voraus
918     Wissen. Dazu kann man entweder seinen freundlichen Freenet-Daemon fragen:
919    
920     my $key = $fcp->generate_chk ($metadata, $data);
921    
922     Oder man verwendet das C<Net::FCP::Key::CHK>-Modul, das schneller ist und
923     keinen Serverzugang benötigt:
924    
925     use Net::FCP::Key;
926    
927     my $key = (new_from_data Net::FCP::Key::CHK $metadata, $data)->chk;
928    
929     =head2 SSK-Schlüssel generieren
930    
931     SSK-Schlüssel bestehen immer aus zwei Teilen, dem öffentlichen
932     (C<public_key>) und dem privaten (c<private_key>), die zusammen ein Paar
933     bilden. Neuerdings noch aus einem dritten, dem C<crypto_key>, der es
934     Brute-Force-Attacken noch schwieriger machen soll.
935    
936     Solch ein Schlüsselpaar kann man mit einem Aufruf von
937     C<generate_svk_pair> (auch hierfür gibt es eine C<txn_>-Variante)
938     erzeugen. Das "svk" ist übrigens kein Schreibfehler: SSK-Schlüssel sind
939     ein Spezialfall von SVK-Schlüsseln, die man aber als normalsterblicher
940     nirgendwo direkt antrifft.
941    
942     my ($public, $private, $crypto) = @{ $fcp->generate_svk_pair };
943    
944     Daraus kann man beliebig viele SSK-Schlüssel erzeugen, indem man die drei
945     Teile wie folgt zusammensetzt:
946    
947     # Öffentlicher Schlüssel:
948    
949     my $name = "..."; # beliebig
950    
951     my $get = "SSK\@${public}PAgM,$crypto/$name";
952     my $put = "SSK\@$private,$crypto/$name";
953    
954     Den mit C<$put> bezeichneten Schlüssel muss man zum Einfügen
955     verwenden. Mit dem mit C<$get> bezeichneten Schlüssel kann man diese
956     Daten wieder holen. Letzterer kann bedenkenlos veröffentlich werden.
957    
958     Das SSK-Management kann vom C<Net::FCP::Key::SSK>-Modul übernommen
959     werden.
960    
961     =head2 Eine Freesite erzeugen
962    
963     Um eine Freesite zu erzeugen, sollte man sich zuerst einen dauerhaften
964     SSK-Schlüssel besorgen:
965    
966     # perl -MNet::FCP -MNet::FCP::Key::SSK \
967     -e 'Net::FCP::Key::SSK->new_from_fcp (Net::FCP->new) \
968 root 1.8 ->save ($ARGV[0])' mykey
969 root 1.7
970 root 1.8 Das erzeugt einen neuen SSK-Schlüssel und speichert ihn gleich in der
971 root 1.7 Datei C<mykey>.
972 root 1.8
973     Dieser SSK-Schlüssel wird die Basis der Freesite.
974    
975     Für das Einfügen schreibt man sich am besten ein Skript, da man ides
976     regelmäßig wiederholen sollte. Zuerst ein paar Definitionen:
977    
978     my $edition = 1;
979     my $keyfile = "mykey";
980     my $htl = 10;
981    
982     Das Skript legt eine Editionenbasierte Freesite an und benutzt als Basis
983     den eben erzeugten SSK-Schlüssel. Der Hops-To-Live-Wert von 10 ist etwas
984     klein, aber so dauert das Einfügen vielleicht nur ein paar Minuten... In
985     der Praxis sollte man 20-25 vorziehen, oder das Einfügen regelmäig
986     wiederholen.
987    
988     Als nächstes benötigen wir ein paar Module:
989    
990     use Net::FCP qw(event=Event);
991     use Net::FCP::Metadata;
992     use Net::FCP::Key::SSK;
993    
994     Generell sollte man in einem Perl-Programm den verwendeten
995     Event-Mechanismus fest angeben. In Freenet-Modulen sollte man dies dagegen
996     nicht tun, um dem Benutzer die Wahl zu überlassen. Stattdessen sollte
997     man in Modulen nur Transaktionen benutzen und diese dem Benutzer zur
998     Verfügung stellen.
999    
1000     Als nächstes werden ein paar notwendige Objekte erzeugt:
1001    
1002     my $fcp = new Net::FCP;
1003     my $ssk = new_from_file Net::FCP::Key::SSK $keyfile;
1004     my $manifest = new Net::FCP::Metadata;
1005    
1006     Die Metadaten für die Hauptseite (C<$manifest>) werden auch
1007     "Manifest" genannt, da man dort häufig nur Verweise auf die
1008     jeweiligen Unterseiten ablegt, also sowas wie der Grundstein einer
1009     Freesite. Das C<Net::FCP::Metadata>-Modul biette zur Zeit nur spärliche
1010     Funktionalität, für unsere Zwecke reicht das jedoch aus.
1011    
1012     Nun noch zwei Hilfsfuntionen. Zuerst C<add_key>:
1013    
1014     sub add_key {
1015     my ($name, $key, $meta, $data) = @_;
1016    
1017     # Asynchrones Einfügen
1018     $fcp->txn_client_put ($chk, $meta, $data, $htl, 1)
1019     ->cb (sub {
1020     eval {
1021     my $attr = $_[0]->result;
1022     printf "Insert of '%s' (%d bytes) ok.\n", $name, length $data;
1023     } or warn "Error while inserting '$name': $@";
1024     });
1025     }
1026    
1027     C<add_key> startet eine C<client_put>-Transaktion, ohne auf das Ende zu
1028     warten. Im Callback wird das Resultat angezeigt, oder, wenn ein Fehler
1029     Auftrat, eben dieser. Das Skript sollte so angelegt sein, das man es
1030     einfach nochmal starten kann, wenn einige Schlüssel nicht eingefügt
1031     werden konnten.
1032    
1033     Nun noch C<add_file>:
1034    
1035     # Hilfsfunktion zum Einfügen von Dateien
1036     sub add_file {
1037     my ($name, $path, $contenttype) = @_;
1038    
1039     # lies die Datei ein
1040     my $data = do {
1041     local $/;
1042     open my $fh, "<", $path
1043     or die "$path: $!";
1044     <$fh>
1045     };
1046    
1047     my $chk = $fcp->generate_chk ("", $data); # keine metadaten
1048     $manifest->add_redirect ($name => $chk, format => $contenttype);
1049     add_key $name, $chk, "", $data;
1050     }
1051    
1052     C<add_file> lädt eine externe Datei (< 1MB) und berechnet deren
1053     CHK-Schlüssel. Diesen Schlüssel fügt es als Verweis unter dem Namen
1054     C<$name> in das Manifest ein. Als letztes benutzt es C<add_key>, um die
1055     Datei einzufügen.
1056    
1057     Das Vorausberechnen des CHK-Schlüssels macht es möglich, das Manifest
1058     paralelle zu den anderen Schlüsseln einzufügen. Würde man auf den
1059     Einfügevorgang waretn, müsste man das Manifest am Ende getrennt
1060     hochladen.
1061    
1062     Nun ans Zusammebauen. Zuerst werden (unsichtbare) Verweise auf die
1063     vorherige bzw. die nächste Edition eingefügt:
1064    
1065     $manifest->add_redirect (".prev" => $ssk->gen_pub ($edition - 1)) if $edition > 1;
1066     $manifest->add_redirect (".next" => $ssk->gen_pub ($edition + 1));
1067    
1068     Dies nutzt zum einen die Eigenschaft von SSKs, einfach vorausberechnet
1069     werden zu können, als auch die Methode C<gen_pub>, die den öffentlichen
1070     SSK-Schlüssel mit optionalem Suffix generiert.
1071    
1072     Dadurch können Benutzer auch "per Hand" eine neuere oder ältere Edition
1073     suchen, indem sie einfach die Zahl (C<.../2//index.html>) vor dem C<//>
1074     ändern.
1075    
1076     Als nächstes folgt der Eigentliche Inhalt der Freesite, eine HTML-Seite,
1077     ein Bild und der Quellcode des Skriptes, der sie generiert hat:
1078    
1079     add_file "activelink.png" => "logo.png", "image/png";
1080     add_file "" => "index.html", "text/html";
1081     add_file "index.html" => "index.html", "text/html";
1082     add_file "freesite" => "freesite", "text/plain";
1083    
1084     Die Datei C<index.html> wird zweimal hinzugefügt, einmal unter dem Namen
1085     "" und ein zweitesmal unter dem Namen "C<index.html>". Dadurch kann man
1086     erreichen, was viele HTTP-Server ebenfalls machen, nämlich eine URI, die
1087     auf ein Verzeichnis zeigt, auf eine Datei darin zu verweisen. Das die
1088     Datei zweimal eingefügt wird ist kein Problem, da der CHK-Schlüssel
1089     derselbe ist (und Mehrfacheinfügen kein Fehler).
1090    
1091     Nachdem die Dateien hinzugefügt (und vor allem ins Manifest eingetragen)
1092     wurden, kann man das Manifest einfügen:
1093    
1094     my $site = $ssk->gen_pub ($edition);
1095     add_key "manifest", $site, $manifest, "";
1096    
1097     Das Manifest wird. Damit man hinterher auch weiss, was man da eingefügt
1098     hat, sollte man den Hauptschlüssel auch ausgeben:
1099    
1100     print "site generated as $site//\n";
1101    
1102     Und da die ganzen Einfügevorgange ja nur gestartet wurden, muss man auf
1103     deren Ende warten:
1104    
1105     Event::loop;
1106    
1107     Solange C<Event> noch aktive Watcher sieht, bleibt es in der
1108     Event-Schleife. Wenn es keinen aktiven Watcher mehr gibt, kehrt C<loop>
1109     automatisch zurück und das Programm ist beendet.
1110    
1111     Die Ausgabe sieht dann z.B. so aus:
1112    
1113     site generated as SSK@wgvWpYYe4QfTBRylfnDlUBfjETgPAgM,Jrm3qco-SQkUBDPfw1UO1g/1//
1114     Insert of 'freesite' (1688 bytes) ok.
1115     Insert of 'activelink.png' (1346 bytes) ok.
1116     Insert of 'index.html' (200 bytes) ok.
1117     Insert of '' (200 bytes) ok.
1118     Insert of 'manifest' (0 bytes) ok.
1119    
1120     Wenn man einen Fehler gemacht hat, kann man einfach einen neuen
1121     SSK-Schlüssel generieren. Das heißt, solange man seine Site nicht schon
1122     veröffentlicht hat.
1123    
1124     Die Alternative wäre z.B. ein täglicher Date-Based-Redirect, d.h.
1125     tägliches komplettes Neueinfügen. Da bügeln sich Fehler schnell von
1126     selbst aus, man muss sein Skript dann natürlich über Tage oder Monate
1127     regelmäßig starten.
1128    
1129     Eine offensichtliche Verbesserung wäre es, HTML-Dateien abzuändern, so
1130     daß man Links auf die nächste Revision nicht hardcodieren muss sondern
1131     etwa als C<%%NEXT%%//activelink.png> schreiben könnte.
1132    
1133     Nun ja, ich hoffe, es machen sich nun einige Leser auf, um eigene
1134     Freesites zu erstellen oder andere Anwendungen für das Freenet zu
1135     ertsellen.
1136    
1137 root 1.7
1138    
1139 root 1.1