ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/docs/pws2004/freenet.pod
Revision: 1.18
Committed: Sat Jun 26 21:32:58 2004 UTC (22 years, 2 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +2 -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.16 Das Freenet-Projekt (L<http://www.freenetproject.org>) hat es sich zur
6 root 1.14 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 root 1.10 durch das Projekt geht es in diesem Artikel darum, wie man in Perl selbst
9 root 1.14 Informationen herunterlädt bzw. veröffentlicht.
10 root 1.2
11 root 1.16 =head2 Einführung
12 root 1.2
13 root 1.16 Das Freenet-Projekt (L<http://www.freenetproject.org>) hat es sich zur
14 root 1.14 Aufgabe gemacht, jedem die die Möglichkeit freier Meinungsäußerung
15 root 1.2 zu garantieren. Als Mittel zur Umsetzung hat es ein virtuelles Netzwerk
16 root 1.14 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 root 1.2 auf ihrer Festplatte gespeichert wurde oder wo die Daten herstammen, so
21 root 1.14 daß es ab einer bestimmten Netzwerkgröße nicht mehr möglich ist,
22     dem Betreiber einer Freenet-Node nachzuweisen, daß er illegale Inhalte
23 root 1.2 besitzt bzw. weitergegeben hat oder davon gewusst hat.
24    
25 root 1.14 In China beispielsweise wird eine frühe Version von Freenet für ein
26 root 1.2 rein chinesisches Freenet-Netzwerk aktiv benutzt, um politische Inhalte
27 root 1.14 verbreiten zu können, ohne Maßnahmen von der Regierung zu befürchten.
28 root 1.2
29 root 1.16 =head3 Freenet für den Benutzer
30 root 1.2
31 root 1.14 Freenet speichert nur relativ kleine Dokumente (<= 1MB) am Stück. Diese
32 root 1.16 Dokumente können beliebige Daten enthalten, z.B. HTML-Seiten. Diese
33 root 1.14 Datenblöcke können mit einem für jeden Block eindeutigen Schlüssel
34 root 1.2 abgerufen werden, z.B. in einem Web-Browser.
35    
36 root 1.14 Hier ist ein Beispiel für eine solche HTML-Seite:
37 root 1.2
38 root 1.15 =for html
39     <img src="freenet1.png" />
40    
41 root 1.7 =for latex
42 root 1.15 \begin{center}\includegraphics[scale=0.55]{freenet1.png}\end{center}
43    
44 root 1.16 =for pp
45     \IMAGE{src="freenet1.png"}
46    
47 root 1.15 Die hier verwendete URL ist:
48    
49     http://129.13.162.73:8888/...
50     ...SSK@Sc6qV~D6iFhaYord6HtbjJ8MaEYPAgM/YoYo//Controversy.html
51 root 1.2
52 root 1.16 =for latex
53     \begin{sloppypar}
54    
55 root 1.2 C<http://129.13.162.73:8888> ist die Adresse meines Freenet-Daemons,
56 root 1.14 ü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 root 1.16 ``Freesite'' ist C<SSK@Sc6qV~D6iFhaYord6HtbjJ8MaEYPAgM> und in dieser wird
59 root 1.2 wiederum das Unterdokument C<YoYo//Controversy.html> angezeigt.
60    
61 root 1.16 =for latex
62     \end{sloppypar}
63    
64 root 1.2 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 root 1.14 man die Inhalte nicht; es ist sogar unmöglich zu bestimmten, wieviel oder
68 root 1.2 welche Informationen im Freenet gespeichert sind: Ein Index a'la google
69 root 1.14 ist prinzipbedingt nicht möglich.
70 root 1.2
71     Obwohl es einige Freenet-Spider und Directory-Freesites gibt ist der
72 root 1.14 überwältigende Teil der Information im Freenet nicht darüber zu
73 root 1.2 erreichen.
74    
75     Neben HTML-Inhalten gibt es auch Mail-, Foren- und Chat-Systeme im
76     Freenet.
77    
78 root 1.14 Die Einspeisung von Daten kann von überall im Netz
79     geschehen. Mehrfacheinspeisung ist möglich (und meistens notwendig) und
80 root 1.16 führt nicht zur Dupliziering von Daten.
81 root 1.14
82 root 1.16 Natürlich gibts es auch einige Nachteile, die teilweise mit dem Design
83 root 1.14 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 root 1.16 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 root 1.2 auch sehr instabil.
89    
90 root 1.16 Die aktuellen Versionen des Freenet-Daemons sind alle als ``nicht sicher''
91 root 1.2 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 root 1.16 akzeptabler Durchsatz) und für interaktive Benutzung teilweise
96 root 1.2 ungeeignet, bzw. eine echte Geduldsprobe.
97    
98 root 1.16 Durch die Art der Speicherung kann nicht garantiert werden, daß
99     Informationen überhaupt wiedergefunden werden. ``Unpopuläre'' Information
100 root 1.14 verschwindet, sofern sie nicht regelmäßig eingespeist oder abgerufen
101 root 1.2 wird, automatisch wieder aus dem Freenet.
102    
103 root 1.16 =head3 Die Freenet-Architektur
104 root 1.2
105 root 1.16 =for latex
106     \begin{sloppypar}
107    
108     Herkömmliche File-Sharing-Netzwerke haben zwei große Nachteile: Entweder
109 root 1.2 sind sie nicht wirklich anonym (selbst anonymisierende Netzwerke oder
110 root 1.14 Proxies sind üblicherweise nicht vor Zugriff durch Regierungen sicher
111 root 1.16 (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 root 1.3 die Polizei gezwungen wurde, Log-Informationenen herauszugeben, wozu die
114 root 1.16 Betreiber nach deutschem Recht verpflichtet sind). Oder sie skalieren
115     nicht, da sie Broadcast-Algorithmen benutzen, die größere Netzwerke von
116 root 1.14 vorneherein ausschließen (bekanntes Beispiel dafür ist I<gnutella>).
117 root 1.2
118 root 1.16 =for latex
119     \end{sloppypar}
120    
121 root 1.2 Das erste Problem umgeht Freenet (Achtung, vereinfacht!), indem es
122 root 1.14 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 root 1.2
125 root 1.14 Der Schlüssel wird ein zweitesmal gehasht. Dieser Hash wird zur
126     eindeutigen ID des Datenblocks. Diese ID und der verschlüsselte
127 root 1.16 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 root 1.2 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 root 1.14 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 root 1.2 werden. Speichert also ein Netzknoten die Daten und die ID dazu, kann man
137 root 1.14 die Daten zwar abrufen, jedoch nicht entschlüsseln. Selbst der Besitzer
138     eines Knotens kann mit vollkommenen Wissen über alle Vorgänge seines
139 root 1.2 Knotens die Inhalte nicht lesen.
140    
141     Eine weitere Konsequenz dieses Verfahrens ist die Tatsache, das Dokumente
142 root 1.16 niemals verändert werden können: eine Änderung bewirkt eine Änderung
143 root 1.14 des Schlüssels und damit eine neue ID, praktisch eine völlig neue URL.
144 root 1.2
145 root 1.16 Möchte man z.B. das grüne Blatt der Freesite ``Thought Crime'' herunterladen so
146 root 1.2 wird man mit folgendem Freenet-Key konfrontiert:
147    
148     CHK@pfAv9IejYPLQwaTLXDguEkUhiNUMAwI,blzDbhN~8Q28esq4JrfRWw
149    
150 root 1.14 C<CHK> steht für I<Content-Hash-Key>, der häufigste Schlüsseltyp im
151 root 1.2 Freenet, der das oben beschriebene Verfahren benutzt. Der CHK besteht
152 root 1.14 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 root 1.2 getrennt.
156    
157 root 1.14 Das sind übrigens (mehr oder weniger) base64-encodete Daten, dekodiert
158     sieht der Schlüssel so aus:
159 root 1.2
160     CHK@
161     ID = a5f02ff487a360f2d0c1a4cb5c382e12452188d50c0302
162     Key = 6e5cc36e137ef10dbc7acab826b7d15b
163    
164 root 1.14 (Man kann daraus tatsächlich ablesen, das der Datenblock 4k groß (0x0c
165 root 1.2 am Ende der ID bedeutet 2**12) ist und Twofish benutzt. Aber derartige
166 root 1.14 Details überläßt man lieber einem Perl-Modul).
167 root 1.2
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 root 1.14 er mit dem Schlüssel dekodiert werden und wird an den Benutzer geliefert.
171 root 1.2
172     Das zweite Problem (der Skalierbarkeit) wird durch lineare
173 root 1.14 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 root 1.2 liegt, gibt an, wie viele Knoten die Anfrage maximal weitergeleitet
177 root 1.14 wird. Jeder Knoten, der die Daten nicht lokal vorrätig hat, leitet sie an
178 root 1.2 denjenigen Knoten weiter, der die Daten am wahrscheinlichsten hat. Da das
179     Verfahren linear ist und nicht exponentiell, skaliert es ebenfalls linear
180 root 1.14 mit der Netzwerkgröße.
181 root 1.2
182 root 1.16 Lädt man das Dokument, wird man mit Metadaten und ``normalen'' Daten
183 root 1.2 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 root 1.14 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 root 1.16 garantiert nachweisen, das ein Dokument existiert, so wäre es für
208 root 1.14 einen Knotenbetreiber schlecht möglich, Wissen über die Art der Daten
209 root 1.2 abzustreiten, die er speichert.
210    
211 root 1.16 =head4 SSK-Schlüssel
212 root 1.2
213 root 1.14 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 root 1.2 Subspace Key>). Hier ist einer:
216    
217     SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM
218    
219 root 1.14 Zwei Dinge unterscheiden Sie von CHK-Schlüsseln:
220 root 1.2
221 root 1.14 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 root 1.2 das Auslesen der Daten benutzt. Da die Daten signiert sind, kann nur der
225 root 1.14 oder die Besitzer des privaten Schlüssels Daten unter diesem einfügen,
226 root 1.16 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 root 1.2
229 root 1.16 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 root 1.14 erzeugen auf Dateien, die noch nicht eingefügt wurden.
232 root 1.2
233 root 1.14 Diese Art Schlüssel ist relativ ineffizient und kann keine großen
234     Datenmengen speichern (<= 32KB!), SSKs werden also vorwiegend für
235 root 1.5 Weiterleitungen auf CHKs benutzt.
236 root 1.2
237 root 1.16 Der obige SSK gehört übrigens zur ``Freenet Explained''-Freesite, die die
238 root 1.14 einzelnen Schlüsseltypen (und mehr) erklärt. Finden kann man sie hier:
239 root 1.2
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 root 1.16 =head2 Und das ganze in Perl
247 root 1.2
248 root 1.14 Das ganze wäre relativ witzlos, wenn man nur irgendwelche
249 root 1.2 langweiligen Tools und/oder Java benutzen kann. Es gibt
250     zwei Perl-Module (bzw. Modulfamilien), C<Net::Freenet::FCP>
251 root 1.16 (L<http://www.sf.net/projects/perlfcp>) und C<Net::FCP>.
252 root 1.2
253 root 1.14 Ersteres ist älter (und vielleicht besser benannt) und konzentriert
254 root 1.2 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 root 1.14 überläßt das Metadatenhandling aber dem Programmierer.
258 root 1.2
259     C<Net::FCP> stammt von mir und ist entstanden, weil ich das andere Modul,
260 root 1.16 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 root 1.2
263 root 1.16 =head3 Installation
264 root 1.2
265     Zuerst braucht man einen Freenet-Daemon
266 root 1.16 (L<http://www.freenetproject.org>). Die Installation ist unglaublich komplex
267 root 1.2 (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 root 1.14 durch Surf-Versuche unterstützen sollte.
270 root 1.2
271     Das C<Net::FCP>-Paket gibt es ganz normal per CPAN.
272    
273 root 1.16 =head3 Einfache Abfragen
274 root 1.2
275 root 1.14 Die Abkürzung I<FCP> steht für I<Freenet Client Protocol> und ist das
276 root 1.16 Protokoll zwischen Freenet-Anwendungen und dem Freenet-Daemon. Es ist
277 root 1.14 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 root 1.16 zu lassen: wäre dumm, wenn man aus dem hochsicheren Freenet über eine
280 root 1.14 ungesicherte Internetverbindung die Windows-Sourcen herunterlädt und
281 root 1.16 sich erwischen läßt (ist alles schon vorgekommen) ...
282 root 1.2
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 root 1.16 Freenet-Daemons übergeben. Üblicherweise holt er sich diese aber aus den
290 root 1.2 Environment-Variablen C<FREDHOST> und C<FREDPORT>, die auf C<127.0.0.1>
291     bzw. C<8481> defaulten.
292    
293 root 1.14 Ü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 root 1.2
297 root 1.14 Im Normalfall heißt das also:: no configuration required.
298 root 1.2
299 root 1.14 Hat man ein C<Net::FCP>-Objekt, kann man schon alle Requests durchführen,
300     die man machen möchte:
301 root 1.2
302     my ($meta, $data) = @{ $fcp->client_get (
303     "freenet:SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//"
304     15
305     ) };
306    
307 root 1.16 =for latex
308     \begin{sloppypar}
309    
310 root 1.2 Der C<client_get>-Request erwartet zwei Argumente: eine Freenet-URI
311 root 1.14 (C<< freenet:<freenet-schlüssel> >>) und eine HTL. Letztere muss man
312 root 1.2 nicht angeben, man sollte es aber, und vor allem sollte man dem Benutzer
313 root 1.14 die Wahl der HTL überlassen. Das dritte, optionale, Argument ist für
314 root 1.2 spezielle Anwendungen: am besten ignorieren.
315    
316 root 1.16 =for latex
317     \end{sloppypar}
318    
319 root 1.14 Als Ergebnis erhält man immer eine Array-Referenz mit den Metadaten
320 root 1.2 und den Daten. Immer. Sollte ein Fehler auftreten wird eine Exception
321 root 1.14 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 root 1.2
324 root 1.14 Bricht das Programm ab, so sieht das folgendermaßen aus:
325 root 1.2
326 root 1.16 Net::FCP::Exception<<short_data,reason:unexpected eof or
327     internal node error>>
328 root 1.2
329     Oder, wenn die Daten nicht gefunden wurden:
330    
331     Net::FCP::Exception<<data_not_found,>>
332    
333 root 1.14 Letzteres bedeutet übrigens nicht aufgeben, sondern nochmal versuchen,
334     z.B. mit einer höheren HTL. Ein fehlgeschlagener Versuch mit hoher HTL
335 root 1.16 bedeutet immer noch nicht aufgeben. Daemons in der ``Nähe'' wissen nun,
336 root 1.2 das die Daten verlangt werden. Nach einiger Zeit ist es wahrscheinlich,
337 root 1.14 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 root 1.2 Freenet wieder heraus...
340    
341 root 1.16 Die Metadaten sind als Textdokument gespeichert. Das Format
342     dieser Metadaten ist aber relativ ``krank'', weshalb das Perl-Modul
343 root 1.9 einen Hash mit den geparsten Daten liefert (genaugenommen ein
344     C<Net::FCP::Metadata>-Objekt, aber dieses Modul ist noch in Entwicklung).
345 root 1.2
346 root 1.9 Die Metadaten und die eigentlichen Nutzdaten kann man ausgeben:
347 root 1.2
348     use Data::Dumper;
349     print STDERR Dumper $meta;
350     print $data;
351    
352 root 1.16 Damit haben wir im wesentlichen den Quelltext für das ``Tool''
353 root 1.9 C<eg/fetch1>, mit dem man I<einen> Freenet-Datenblock herunterladen kann.
354 root 1.2
355 root 1.14 Ich benutze es üblicherweise so:
356 root 1.2
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 root 1.14 Für den Key C<SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//> ergibt dies:
363 root 1.2
364     'version' => { 'revision' => '1' },
365     'document' => [
366     {
367     'info' => { 'format' => 'image/png' },
368 root 1.15 'redirect' => { 'target' => 'freenet:CHK@pMKW...KAwI,7...-25C2w' },
369 root 1.2 'name' => 'activelink.png'
370     },
371     {
372     'info' => { 'format' => 'text/plain' },
373 root 1.15 'redirect' => { 'target' => 'freenet:CHK@2hew...KAwI,o...21z91w' },
374 root 1.2 'name' => 'description.txt'
375     },
376     {
377     'info' => { 'format' => 'text/html' },
378 root 1.15 'redirect' => { 'target' => 'freenet:CHK@kME~...QAwI,3...dy4OkA' },
379 root 1.2 'name' => 'index.html'
380     },
381     {
382     'info' => { 'format' => 'text/html' },
383 root 1.15 'redirect' => { 'target' => 'freenet:SSK@0OhV...PAgM/fx/4' },
384 root 1.2 'name' => '.next'
385     },
386     {
387     'info' => { 'format' => 'text/html' },
388 root 1.15 'redirect' => { 'target' => 'freenet:CHK@kME~...QAwI,3...dy4OkA' }
389 root 1.2 }
390     ],
391     'raw' => 'Version
392     Revision=1
393 root 1.14 [... gekürzt...]
394 root 1.2 Info.Format=text/html
395     End
396     '
397     };
398    
399 root 1.14 Die eigentlichen Daten sind leer (null Byte gross), das Dokument enthät
400 root 1.2 also nur Metadaten! Man beachte vor allem die teilweise recht tiefe
401     Verschachtelung.
402    
403 root 1.14 Der Key C<< $metadata->{raw} >> enthält die Metadaten, wie sie vom
404 root 1.2 Freenet kamen. Dies ist notwendig, da man manchmal die Metadaten
405 root 1.14 zum Prüfen in der exakten Form benötigt, wie sie hochgeladen
406 root 1.2 wurden. Ansonsten kann man sie ignorieren.
407    
408 root 1.14 Der Key C<< $metadata->{document} >> enthält Informationen über das
409 root 1.2 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 root 1.15 SSK@0OhVDWutibbBMbXmbxNXW0M6YFoPAgM/fx/3//description.txt # für Spider
420 root 1.2
421     Wenn diese Dokumente mit C<client_get> anfordert, bekommt man immer obiges
422 root 1.14 Dokument. Freenet ignoriert nämlich alles, was hinter dem C<//> steht
423 root 1.2 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 root 1.14 man über den Namen identifizieren kann:
430 root 1.2
431     $activelink = grep $_->{name} eq "activelink.png",
432     @{ $metadata->{document} };
433    
434 root 1.16 Fehlt der C<name>-Eintrag, ist es der Eintrag mit dem leeren Namen, in
435 root 1.2 diesem Fall der erste Link, der nichts nach den C<//> stehen hat. Der
436 root 1.14 C<name>-Key I<kann> vorhanden und leer sein: Freenet überprüft die Daten
437 root 1.16 nicht, daher gibt es durchaus unterschiedliche Auslegungen für das genaue
438 root 1.2 Format.
439    
440 root 1.14 Die Metadaten sind etwas genauer in dem *hüstel* etwas veralteten
441     *hüstel* I<Freenet Explained>-Dokument beschrieben.
442 root 1.2
443 root 1.16 =for latex
444     \begin{sloppypar}
445    
446 root 1.14 Möchte man nun das C<activelink.png> herunterladen muss man in C<<
447 root 1.16 $activelink->{redirect} >> nachsehen. Meistens verweist dies auf einen
448 root 1.14 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 root 1.2
452 root 1.16 =for latex
453     \end{sloppypar}
454    
455 root 1.15 Auf C<< $activelink->{info}{format} >> sollte man sich übrigens nicht
456 root 1.2 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 root 1.14 Egal, der CHK-Key für C<activelink.png> liefert folgendes:
463 root 1.2
464     'version' => { 'revision' => '1' },
465    
466 root 1.14 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 root 1.2
470 root 1.16 Aber mit diesen Erklärungen kann man schon einfache Freenet-Spider
471 root 1.14 bauen. Die wichtigsten Tools sind veraltete und spärliche Dokumente
472 root 1.16 wie I<Freenet Explained> und Tools wie C<Data::Dumper>. ``Veraltet'' ist
473 root 1.14 übrigens nicht immer schlecht, da viele Dokumente auch alt sind oder sich
474 root 1.16 eh' nicht exakt an den ``Standard'' halten. Mit der Zeit wird hier sicher
475 root 1.2 eine Besserung eintreten.
476    
477 root 1.16 =head3 Methoden des Freesite-Managements
478 root 1.2
479 root 1.16 Oder: ``Wenn man Inhalte nicht mehr verändern kann, wie verändert man
480     sie?''
481 root 1.2
482 root 1.16 Die offensichtliche Methode ist: ``Man macht sie veränderbar''. In
483 root 1.2 der Freenet-Gemeinde geistert seit langer Zeit der Mythos des
484 root 1.14 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 root 1.2
489 root 1.16 =head4 ``Editions''
490 root 1.2
491 root 1.14 Die nächstliegende Methode nutzt die Eigenschaft von SSKs (genauer:
492 root 1.2 redirects) aus, das man den Namen sofort generieren kann, den Inhalt aber
493 root 1.14 erst später einfügt.
494 root 1.2
495     Dies nutzt man aus, indem man I<Editionen> herausgibt und
496 root 1.14 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 root 1.2
499 root 1.14 Ü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 root 1.2
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 root 1.16 Beides existierte nicht, als ich diesen Artikel schrieb (bzw. Freenet
509     konnte es nicht finden :). Wenn eine neue Edition herausgegeben werden
510 root 1.14 soll, fügt der Autor einfach einen neuen Datenblock mit vielen Redirects
511 root 1.2 unter obigem SSK-Key ein.
512    
513     Ein C<.next>-Eintrag ist ebenfalls vorhanden: manche Spider folgen diesem
514 root 1.14 und können auf diese Weise immer die aktuelle Edition anzeigen, sofern
515     sie häufig genug scannen.
516 root 1.2
517 root 1.14 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 root 1.2
521 root 1.14 Daher hat sich eine zweite Methode entwickelt, die gerade bei häufig
522     geänderten Inhalten besser funktioniert:
523 root 1.2
524 root 1.16 =head4 ``Date Based Redirects''
525 root 1.2
526 root 1.16 Freesites, die ``Date Based Redirects'' benutzen (kurz ``DBR-Sites'')
527 root 1.14 funktionieren ähnlich wie Editionen-basierte Freesites, nur wird statt
528 root 1.2 einer fortlaufenden Nummer die aktuelle Zeit benutzt.
529    
530 root 1.16 =for latex
531     \begin{sloppypar}
532    
533 root 1.2 Die Freesite I<The Freenet Help Index>
534 root 1.16 (C<SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/ FreenetHelp//>) benutzt diese
535 root 1.2 Methode. Folgende Metadaten wurden dazu hinterlegt:
536    
537 root 1.16 =for latex
538     \end{sloppypar}
539    
540 root 1.2 '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 root 1.14 C<date_redirect>-Eintrag, und darin ein C<target> (dürfte bekannt sein)
551 root 1.16 und den Key C<increment>. Letzterer darf wie üblich fehlen, man sollte
552 root 1.2 dann C<86400> annehmen (ein Tag hat 86400 Sekunden). In diesem Beispiel
553     wird 86400 genommen (Hexadezimal 15180).
554    
555 root 1.16 Habe ich eigentlich schon erwähnt, daß jede Zahl im FCP-Protokoll oder
556 root 1.14 im Freenet hexadezimal kodiert wird? Also, praktisch immer, außer wenn
557 root 1.16 es mal nicht so ist. Und wozu man einen Offset addiert, ist mir auch
558 root 1.2 schleierhaft. In der freien Wildbahn habe ich sowieso noch keinen gesehen.
559    
560 root 1.14 Der Link in C<target> ist nicht vollständig (unter anderem fehlt
561 root 1.16 hinten ein C<//>). Der komplette Link wird generiert, ``indem die
562 root 1.14 aktuelle Zeit (POSIX-Zeit, üblicherweise das, was C<time> liefert),
563 root 1.2 auf C<increment>-Schritte gerundet und C<offset> addiert, als
564     Big-Endian-Hexadezimalzahl nach dem ersten Slash mit folgendem
565 root 1.16 Minuszeichen eingefügt wird.''
566 root 1.2
567     Und jetzt in Perl - zum Verstehen:
568    
569 root 1.17 my $doc = $metadata->{document}[0]; # Oder [1] oder ...
570 root 1.2
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 root 1.16 Für ``jetzt'' (C<time() == 1084388445>) liefert der Algorithmus folgenden Link:
583 root 1.2
584     SSK@rjYFfgPHfolmcStiaoxESFfBXz8PAgM/40a16900-FreenetHelp
585    
586 root 1.14 Und tatsächlich, unter diesem Key findet man wieder ein Dokument mit
587 root 1.2 vielen Redirects.
588    
589 root 1.16 DBRs haben den Vorteil, ``automatisch'' aktuell zu sein. Solange man nur
590 root 1.14 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 root 1.16 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 root 1.14 nicht den Schlüssel besitzt).
595 root 1.2
596     Der Nachteil ist, das man eine aktuelle Uhrzeit braucht um die Site zu
597 root 1.16 finden. Schlimmer noch: die Freesite muss regelmäßig neu eingefügt
598 root 1.2 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 root 1.14 großer Dateien ist.
607 root 1.2
608 root 1.14 Womit ich beim Thema wäre.
609 root 1.2
610 root 1.16 =head2 Effizient herunterladen
611 root 1.2
612 root 1.4 Transfers im Freenet zeichnen sich durch zwei Eigenschaften aus: hohe
613 root 1.14 Latenz und vergleichsweise hoher Durchsatz. Dies ist ungewöhnlich, ergibt
614 root 1.4 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 root 1.14 Wie in Java üblich, erreichte man dies früher durch massive Benutzung
619 root 1.16 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 root 1.4
624 root 1.12 Da Perls aktuelle Thread-Implementierung ein Prozessmodell simuliert
625 root 1.14 ist der Overhead ebenfalls entsprechend hoch, und man erhält bei
626 root 1.12 Thread-Benutzung viele ihrer Nachteile, jedoch keine nennenswerten
627 root 1.16 Vorteil, außer das alles etwas langsamer läuft und man daher besser
628 root 1.12 zuschauen kann :)
629 root 1.4
630 root 1.14 Für C<Net::FCP> (oder besser: für mich) kam es deshalb nicht in Frage,
631 root 1.16 Parallelisierung auf Thread-Basis zu implementieren. Das Problem auf
632 root 1.4 den Modul-Benutzer abzuschieben erschien mir auch nicht fair, daher
633 root 1.14 unterstützt C<Net::FCP> die Module L<Coro>, L<Event>, L<Glib> oder L<Tk>,
634 root 1.6 bzw. deren Event-Steuerung. Man hat also die Wahl, auf welcher Basis man sein
635 root 1.4 Programm aufbaut, und es geht auch ganz ohne Event-System (wie die obigen
636     einfachen Beispiele zeigen).
637    
638 root 1.16 =head3 Transaktionen
639 root 1.4
640 root 1.14 C<Net::FCP> benutzt für jeden Request eine I<Transaktion>. Das ist ein
641 root 1.4 Objekt, das den Zustand und eintreffende Ergebnisse speichert.
642    
643     Jede Anfrage, (z.B. C<client_get>) wird intern in ein solches
644 root 1.16 Transaktionsobjekt verwandelt. Für jede ``einfache'' Methode wie
645 root 1.4 C<client_get> oder C<insert_private_key> gibt es eine entsprechende
646 root 1.14 Methode mit C<txn_>-Präfix, die statt des Resultats ein solches Objekt
647 root 1.4 liefert.
648    
649     Transaktionsobjekte besitzen einige Methoden, mit denen sie konfiguriert
650 root 1.14 werden können oder Ergebnisse abgefragt werden können. Die wichtigste
651 root 1.4 ist die C<result>-Methode, die auf das Ergebnis wartet und es
652 root 1.14 zurückliefert:
653 root 1.4
654     # $fcp->client_get wird intern so implementiert:
655     my $txn = $fcp->txn_client_get (...);
656 root 1.18 return $txn->result;
657 root 1.4
658 root 1.14 Es ist übrigens immer gefahrlos, Transaktionsobjekte zu erzeugen. Etwaige
659     Fehler bei der Durchführung werden immer erst beim Aufruf von C<result>
660 root 1.4 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 root 1.14 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 root 1.16 am Laufen zu halten.
675 root 1.4
676 root 1.16 Dazu benötigt man ein Signal, daß eine Transaktion beendet ist. Dies
677 root 1.4 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 root 1.16 Transaktionsobjekt konfigurieren, liefern das Transaktionsobjekt zurück,
684 root 1.4 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 root 1.16 Nun braucht man allerdings die Hauptschleife des jeweiligen Event-Systems,
690 root 1.4 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 root 1.14 folgende Beispiel tut dies und lädt die Kommandozeileargumente parallel
695 root 1.4 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 root 1.14 Die Transaktionsobjekte werden übrigens nicht gespeichert, denn sie
705 root 1.16 werden dem Callback übergeben, und nur dort werden sie gebraucht. Der
706 root 1.14 Callback könnte so aussehen:
707 root 1.4
708     sub finished {
709     my ($txn) = @_;
710     my ($meta, $data) = @{ $txn->result };
711     # tue etwas
712     }
713    
714 root 1.14 Oder, mit Fehlerprüfung:
715 root 1.4
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 root 1.16 =head3 Fortschritt ist nicht aufzuhalten
728 root 1.4
729 root 1.14 Da Zugriffe recht lange dauern können, schickt Freenet regelmäig
730 root 1.4 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 root 1.14 ausgegeben (wäre irgendwie kontraproduktiv in einem GUI-Programm), man
735 root 1.4 kann aber einen Callback installieren:
736    
737     my $fcp = Net::FCP progress => \&progress;
738    
739 root 1.14 Ein solcher Progress-Callback könnte so aussehen:
740 root 1.4
741     sub progress_cb {
742     my ($self, $txn, $type, $attr) = @_;
743    
744     warn "progress<$txn,$type," . (join ":", %$attr) . ">\n";
745     }
746    
747 root 1.14 Möchte man Informationen für den Callback bereitstellen, so bietet sich
748 root 1.4 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 root 1.14 Ein solcher Progress-Callback könnte so aussehen:
755 root 1.4
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 root 1.14 Startet man ihn mit einigen gültigen und ungültigen Freenet-URIs,
782 root 1.4 bekommt man vieleicht folgende Ausgabe:
783    
784 root 1.15 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 root 1.4 ... usw.
799    
800     Benutzt man das C<Coro>-Modul, so kann man Callback-basierte und Thread-
801     (bzw. Coroutinen-) basierte Programmierung mischen:
802 root 1.6
803     use Net::FCP qw(event=Coro);
804    
805     my $fcp = new Net::FCP;
806 root 1.4
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 root 1.14 for (@alle_splitfile_blöcke) {
814 root 1.4 $fcp->txn_client_get (...)
815     ->cb (\&save_splitfile_block);
816     }
817     } else {
818     # direkt speichern
819     }
820     };
821     }
822    
823 root 1.16 =head3 Splitfiles
824 root 1.4
825 root 1.14 Das Them Splitfiles möchte ich hier noch erwähnen, aber nicht
826     ausführlich besprechen.
827 root 1.4
828 root 1.14 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 root 1.16 Wahrscheinlichkeit dafür, daß ein Block mal fehlt oder nicht gefundne
832 root 1.14 werden kann, stark auf einen Wert, der das Herunterladen großer Dateien
833     unmöglich macht.
834 root 1.4
835 root 1.14 Daher wird mit Fehlerkorrekturcodes die Anzahl der Blöcke um 50%
836     erhöht. Metadaten für ein Splitfile sehen so aus:
837 root 1.4
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 root 1.15 '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 root 1.4 [viele Zeilen fehlen hier :]
854 root 1.15 '3d' => 'freenet:CHK@iIT1...yOToFsyyytV-roUAwI,9u3...-eY7Onag1g',
855     '5' => 'freenet:CHK@EeVsn...CNBNVzvTTQ1l0UAwI,q6e...Oh-cc79WBA'
856 root 1.4 },
857     'block' => {
858 root 1.15 '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 root 1.4 [viele Zeilen fehlen hier :]
862 root 1.15 '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 root 1.4 },
866     'size' => '7e8e804'
867     }
868     } ],
869     }
870    
871 root 1.14 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 root 1.4
875 root 1.14 Wie genau die Daten auf die Blöcker verteilt werden unterliegt einem
876 root 1.16 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 root 1.4 Freenet keine Duplikate erstellt.
880    
881 root 1.16 Den genauen Algorithmus kann man in der Datei C<bin/fmd>, dem I<Freenet
882 root 1.4 Mass Downloader> in der Funktion C<state_splitfile> nachlesen. Der Code
883 root 1.16 ist weder besonders klar, noch besonders kurz, noch besonders hübsch. Auch
884 root 1.14 dieser Teil wird irgendwann einmal in ein Modul fließen, damit er anderen
885     zugänglicher wird.
886 root 1.4
887 root 1.16 Interessant ist noch, daß man CHK-Inhalte, die aus dem Freenet
888     heruntergeladen werden, einfach auf Konsistenz prüfen kann: sie enthalten
889 root 1.14 schließlich den SHA1-Hash der Daten:
890 root 1.4
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 root 1.14 # Idealerweie stimmen beide überein...
901 root 1.4 $k1 eq $k2 or die "Key/Content mismatch!";
902    
903 root 1.14 Zwar ist der Freenet-Daemon angeblich perfekt, aber früher passierte
904     es tatsächlich oft, daß man korrupte Daten geliefert bekam. Retryen
905 root 1.4 half. Man hat es eben nicht so leicht...
906    
907 root 1.14 Heute ist das zwar nicht mehr der Fall (...), aber prüfen kostet fast
908 root 1.4 nichts.
909    
910 root 1.16 =head2 Publizieren
911 root 1.1
912 root 1.4 Das Freenet lebt von vielen Dingen: Den Entwicklern, den Benutzern die
913 root 1.14 ihr Interesse bekunden, den Regierungen, die die Meinungsäußerung
914 root 1.16 einschränken - aber vor allem dadurch, daß es sinnvolle Inhalte darin gibt.
915 root 1.4
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 root 1.14 Das kann man ändern, indem man so langweilige Dinge wie den I<Freenet
922 root 1.7 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 root 1.4
925     Mit C<Net::FCP> geht es erstmal sehr einfach:
926    
927     $fcp->client_put ($uri, $metadata, $data, $htl, $removelocal);
928    
929 root 1.14 (Auch hier gibt es natürlich wieder die entsprechende C<txn_>-Variante).
930 root 1.7
931 root 1.14 Einfügen von Inhalten geht also fast geanuso wie Auslesen. C<$uri> ist
932 root 1.18 eine Freenet-``URI'' (mit oder ohne C<freenet:>), wie man zu dieser kommt
933 root 1.7 gleich mehr.
934    
935     C<$metadata> kann entweder ein Freenet-Metadata-String sein oder ein Hash
936 root 1.14 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 root 1.7
941 root 1.14 C<$removelocal>, auf C<1> gesetzt, sorgt dafür, daß der lokale
942 root 1.7 Netzknoten die Daten I<nicht> cached. Warum man das tun sollte, ist
943 root 1.16 einfach erklärt: wenn Freenet beim Einfügen die Daten schon im Netz
944 root 1.14 vorfindet, wird der Einfügevorgang abgebrochen. Möchte man die Daten
945 root 1.16 regelmäßig ``auffrischen'' dann sorgt diese Option dafür, daß die
946 root 1.14 Daten den Knoten auf jeden Fall verlassen und erhöhen so die Chance auf
947 root 1.7 Verbreitung.
948    
949 root 1.14 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 root 1.7
953     my $attr = $fcp->client_put ('CHK@', "", "Daten\n", 20);
954 root 1.14 print "eingefügte URI: $attr->{uri}\n";
955 root 1.7
956     Als Ergebnis dieses C<client_put>-Requests erhielt ich:
957    
958     freenet:CHK@MT~LuxKHH8fugJehkcgp239h7C4KAwI,378rJzHVZbsQbd7VGMHxSg
959    
960 root 1.14 Beim Einfügen ins Freenet kann es auch einen I<Key Collision>-Fehler
961 root 1.7 geben, und zwar genau dann, wenn Freenet die Daten schon findet, die man
962 root 1.14 einfügen wollte.
963 root 1.7
964     C<Net::FCP> behandelt diesen Fehler allerdings genauso wie ein
965 root 1.14 erfolgreicher Einfügevorgang, lediglich im Hash, den es zurückliefert,
966 root 1.7 wird das C<key_collision>-Element auf C<1> gesetzt. Wenn die Daten schon
967 root 1.14 vorhanden sind, ist das Ziel schließlich auch erreicht.
968 root 1.7
969 root 1.14 Häufig möchte man den C<CHK>-Schlüssel aber schon im voraus
970 root 1.7 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 root 1.14 keinen Serverzugang benötigt:
976 root 1.7
977     use Net::FCP::Key;
978    
979     my $key = (new_from_data Net::FCP::Key::CHK $metadata, $data)->chk;
980    
981 root 1.16 =head3 SSK-Schlüssel generieren
982 root 1.7
983 root 1.14 SSK-Schlüssel bestehen immer aus zwei Teilen, dem öffentlichen
984 root 1.16 (C<public_key>) und dem privaten (C<private_key>), die zusammen ein Paar
985 root 1.7 bilden. Neuerdings noch aus einem dritten, dem C<crypto_key>, der es
986     Brute-Force-Attacken noch schwieriger machen soll.
987    
988 root 1.14 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 root 1.16 erzeugen. Das ``svk'' ist übrigens kein Schreibfehler: SSK-Schlüssel sind
991 root 1.14 ein Spezialfall von SVK-Schlüsseln, die man aber als normalsterblicher
992 root 1.7 nirgendwo direkt antrifft.
993    
994     my ($public, $private, $crypto) = @{ $fcp->generate_svk_pair };
995    
996 root 1.14 Daraus kann man beliebig viele SSK-Schlüssel erzeugen, indem man die drei
997 root 1.7 Teile wie folgt zusammensetzt:
998    
999 root 1.14 # Öffentlicher Schlüssel:
1000 root 1.7
1001     my $name = "..."; # beliebig
1002    
1003     my $get = "SSK\@${public}PAgM,$crypto/$name";
1004     my $put = "SSK\@$private,$crypto/$name";
1005    
1006 root 1.14 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 root 1.7
1010 root 1.14 Das SSK-Management kann vom C<Net::FCP::Key::SSK>-Modul übernommen
1011 root 1.7 werden.
1012    
1013 root 1.16 =head3 Eine Freesite erzeugen
1014 root 1.7
1015     Um eine Freesite zu erzeugen, sollte man sich zuerst einen dauerhaften
1016 root 1.14 SSK-Schlüssel besorgen:
1017 root 1.7
1018     # perl -MNet::FCP -MNet::FCP::Key::SSK \
1019     -e 'Net::FCP::Key::SSK->new_from_fcp (Net::FCP->new) \
1020 root 1.8 ->save ($ARGV[0])' mykey
1021 root 1.7
1022 root 1.14 Das erzeugt einen neuen SSK-Schlüssel und speichert ihn gleich in der
1023 root 1.7 Datei C<mykey>.
1024 root 1.8
1025 root 1.14 Dieser SSK-Schlüssel wird die Basis der Freesite.
1026 root 1.8
1027 root 1.14 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 root 1.8
1030     my $edition = 1;
1031     my $keyfile = "mykey";
1032     my $htl = 10;
1033    
1034 root 1.16 Das Skript legt eine editionenbasierte Freesite an und benutzt als Basis
1035 root 1.14 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 root 1.8 wiederholen.
1039    
1040 root 1.14 Als nächstes benötigen wir ein paar Module:
1041 root 1.8
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 root 1.14 nicht tun, um dem Benutzer die Wahl zu überlassen. Stattdessen sollte
1049 root 1.8 man in Modulen nur Transaktionen benutzen und diese dem Benutzer zur
1050 root 1.14 Verfügung stellen.
1051 root 1.8
1052 root 1.14 Als nächstes werden ein paar notwendige Objekte erzeugt:
1053 root 1.8
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 root 1.14 Die Metadaten für die Hauptseite (C<$manifest>) werden auch
1059 root 1.16 ``Manifest'' genannt, da man dort häufig nur Verweise auf die
1060 root 1.8 jeweiligen Unterseiten ablegt, also sowas wie der Grundstein einer
1061 root 1.14 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 root 1.8
1064     Nun noch zwei Hilfsfuntionen. Zuerst C<add_key>:
1065    
1066     sub add_key {
1067     my ($name, $key, $meta, $data) = @_;
1068    
1069 root 1.14 # Asynchrones Einfügen
1070 root 1.8 $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 root 1.14 einfach nochmal starten kann, wenn einige Schlüssel nicht eingefügt
1083 root 1.8 werden konnten.
1084    
1085     Nun noch C<add_file>:
1086    
1087 root 1.14 # Hilfsfunktion zum Einfügen von Dateien
1088 root 1.8 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 root 1.14 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 root 1.8 C<$name> in das Manifest ein. Als letztes benutzt es C<add_key>, um die
1107 root 1.14 Datei einzufügen.
1108 root 1.8
1109 root 1.14 Das Vorausberechnen des CHK-Schlüssels macht es möglich, das Manifest
1110 root 1.16 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 root 1.8 hochladen.
1113    
1114 root 1.16 Nun ans Zusammenbauen. Zuerst werden (unsichtbare) Verweise auf die
1115 root 1.14 vorherige bzw. die nächste Edition eingefügt:
1116 root 1.8
1117 root 1.15 $manifest->add_redirect (".prev" => $ssk->gen_pub ($edition - 1))
1118     if $edition > 1;
1119 root 1.8 $manifest->add_redirect (".next" => $ssk->gen_pub ($edition + 1));
1120    
1121     Dies nutzt zum einen die Eigenschaft von SSKs, einfach vorausberechnet
1122 root 1.14 werden zu können, als auch die Methode C<gen_pub>, die den öffentlichen
1123     SSK-Schlüssel mit optionalem Suffix generiert.
1124 root 1.8
1125 root 1.16 Dadurch können Benutzer auch ``per Hand'' eine neuere oder ältere Edition
1126 root 1.8 suchen, indem sie einfach die Zahl (C<.../2//index.html>) vor dem C<//>
1127 root 1.14 ändern.
1128 root 1.8
1129 root 1.16 Als nächstes folgt der eigentliche Inhalt der Freesite, eine HTML-Seite,
1130 root 1.8 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 root 1.14 Die Datei C<index.html> wird zweimal hinzugefügt, einmal unter dem Namen
1138 root 1.16 ``'' und ein zweitesmal unter dem Namen ``C<index.html>''. Dadurch kann man
1139 root 1.14 erreichen, was viele HTTP-Server ebenfalls machen, nämlich eine URI, die
1140 root 1.8 auf ein Verzeichnis zeigt, auf eine Datei darin zu verweisen. Das die
1141 root 1.14 Datei zweimal eingefügt wird ist kein Problem, da der CHK-Schlüssel
1142     derselbe ist (und Mehrfacheinfügen kein Fehler).
1143 root 1.8
1144 root 1.14 Nachdem die Dateien hinzugefügt (und vor allem ins Manifest eingetragen)
1145     wurden, kann man das Manifest einfügen:
1146 root 1.8
1147     my $site = $ssk->gen_pub ($edition);
1148     add_key "manifest", $site, $manifest, "";
1149    
1150 root 1.14 Das Manifest wird. Damit man hinterher auch weiss, was man da eingefügt
1151     hat, sollte man den Hauptschlüssel auch ausgeben:
1152 root 1.8
1153     print "site generated as $site//\n";
1154    
1155 root 1.14 Und da die ganzen Einfügevorgange ja nur gestartet wurden, muss man auf
1156 root 1.8 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 root 1.14 automatisch zurück und das Programm ist beendet.
1163 root 1.8
1164     Die Ausgabe sieht dann z.B. so aus:
1165    
1166 root 1.15 site generated as SSK@wg...TBRylfnDlUBfjETgPAgM,Jr...UBDPfw1UO1g/1//
1167 root 1.8 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 root 1.14 SSK-Schlüssel generieren. Das heißt, solange man seine Site nicht schon
1175     veröffentlicht hat.
1176 root 1.8
1177 root 1.14 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 root 1.8
1186     Nun ja, ich hoffe, es machen sich nun einige Leser auf, um eigene
1187 root 1.14 Freesites zu erstellen oder andere Anwendungen für das Freenet zu
1188 root 1.13 erstellen.
1189    
1190 root 1.16 =head2 Verweise
1191 root 1.13
1192     =over 4
1193    
1194 root 1.16 =item L<http://www.freenetproject.org/>
1195 root 1.13
1196     Die Hauptseite des Freenet-Projekts. Hier gibt es auch White-Papers, etwas
1197     Dokumentation und Mailinglisten(-archive).
1198    
1199 root 1.16 =item L<http://www.freenethelp.org/>
1200 root 1.13
1201     Hier findet der gestresste Freenetter Hilfe beim Einrichten und Betrieb
1202     seines Knotens. Vielleicht.
1203    
1204     =back
1205 root 1.8
1206 root 1.7
1207    
1208 root 1.1