ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2004/freenet.pod
Revision: 1.15
Committed: Fri May 28 19:50:13 2004 UTC (22 years, 5 months ago) by root
Branch: MAIN
Changes since 1.14: +75 -58 lines
Log Message:
*** empty log message ***

File Contents

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