ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/freenet.pod
Revision: 1.18
Committed: Sat Jun 26 21:32:58 2004 UTC (22 years, 3 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

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