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