From 002a2c3e1d0f091a48f8cc3eb7dce519870debaf Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Sat, 11 Jan 2014 18:44:50 +0100 Subject: import code --- doc/Makefile | 11 + doc/anwenderdoku.html | 1070 ++++++++++++++++++++++++++ doc/anwenderdoku.pdf | Bin 0 -> 233390 bytes doc/anwenderdoku.txt | 279 +++++++ doc/bilder/Model_model_Architektur.PNG | Bin 0 -> 16257 bytes doc/bilder/logo.png | Bin 0 -> 116499 bytes doc/bilder/model.di | 24 + doc/bilder/model.notation | 298 ++++++++ doc/bilder/model.uml | 41 + doc/bilder/screen_main.png | Bin 0 -> 53297 bytes doc/bilder/screen_pref.png | Bin 0 -> 91922 bytes doc/bilder/whiteboard_gui.jpg | Bin 0 -> 156927 bytes doc/bilder/whiteboard_intents.jpg | Bin 0 -> 99022 bytes doc/bilder/whiteboard_komponenten.jpg | Bin 0 -> 87861 bytes doc/entwicklerdoku.html | 1284 ++++++++++++++++++++++++++++++++ doc/entwicklerdoku.pdf | Bin 0 -> 408998 bytes doc/entwicklerdoku.txt | 536 +++++++++++++ doc/vorstellung.odp | Bin 0 -> 420378 bytes doc/vorstellung.pdf | Bin 0 -> 394661 bytes 19 files changed, 3543 insertions(+) create mode 100644 doc/Makefile create mode 100644 doc/anwenderdoku.html create mode 100644 doc/anwenderdoku.pdf create mode 100644 doc/anwenderdoku.txt create mode 100644 doc/bilder/Model_model_Architektur.PNG create mode 100644 doc/bilder/logo.png create mode 100644 doc/bilder/model.di create mode 100644 doc/bilder/model.notation create mode 100644 doc/bilder/model.uml create mode 100644 doc/bilder/screen_main.png create mode 100644 doc/bilder/screen_pref.png create mode 100644 doc/bilder/whiteboard_gui.jpg create mode 100644 doc/bilder/whiteboard_intents.jpg create mode 100644 doc/bilder/whiteboard_komponenten.jpg create mode 100644 doc/entwicklerdoku.html create mode 100644 doc/entwicklerdoku.pdf create mode 100644 doc/entwicklerdoku.txt create mode 100644 doc/vorstellung.odp create mode 100644 doc/vorstellung.pdf (limited to 'doc') diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..a63612e --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,11 @@ +# aptitude install texlive-lang-cyrillic txt + +all: anwenderdoku.pdf anwenderdoku.html entwicklerdoku.pdf entwicklerdoku.html + +%.html: %.txt bilder/* + asciidoc -o $@ $*.txt + +%.pdf: %.txt bilder/* + a2x -v -a encoding=utf-8 -a lang=de --dblatex-opts='-Platex.output.revhistory=0 -P latex.encoding=utf8 -P latex.unicode.use=1' $*.txt + + diff --git a/doc/anwenderdoku.html b/doc/anwenderdoku.html new file mode 100644 index 0000000..02abb35 --- /dev/null +++ b/doc/anwenderdoku.html @@ -0,0 +1,1070 @@ + + + + + +Android Iodine Anwenderdokumentation + + + + + +
+
+
+
+
+

Die Dokumentation ist zweigeteilt. Dieser Teil enthält eine Beschreibung des Programs +und einen Überblick über die Funktionsweise von DNS-Tunnel. Zur technischen Beschreibung +des Programs siehe Entwicklerdokumentation.

+

Ein DNS Tunnel ermöglicht regulären IP Verkehr durch den Internet +Namensauflösungsdienst DNS zu tunneln. Damit ist es möglich, in Netzen +die keine normales Internet Routing unterstützen, Daten auszutauschen. +Voraussetzung ist, dass das Netz gewöhnliche DNS-Auflösung unterstützt. +Die Datenpakete werden in DNS-Anfragen kodiert, die durch die hierarchische +Struktur an einen speziellen (i.d.R. third-level) Nameserver weitergeleitet werden.

+

Die Software [iodine] ist eine Implementierung eines DNS Tunnel für Linux, +Mac OS X, FreeBSD, NetBSD, OpenBSD and Windows. Diese Dokumentation beschreibt +die Portierung auf Android mit einer angepassten Benutzeroberfläche.

+
+
+
+
+
+
+

Android Systemanforderungen

+
+

Durch die Verwendung des Android VPN Framework ist mindestens Android +4.0 (API Level 14) erforderlich.

+

Für Android vor 4.0 besteht bei vorhandenem Root Zugriff die Möglichkeit +das tun.ko Kernelmodul zu laden und ein +cross-kompiliertes +iodine auszuführen.

+
+
+
+

Funktionsweise eines DNS-Tunnel

+
+

Das Domain-Name-System (DNS) wird eingesetzt um Namen (wie +"example.com") in IP-Adressen (wie "194.71.107.50" oder +"2001:db8:85a3:8d3:1319:8a2e:370:7347") zu übersetzen. DNS wurde in den +1980er Jahren ursprünglich mit dem Ziel entwickelt lokale hosts Datei +im Internet abzulösen. Inzwischen werden auch andere Informationen als +die reine Adressauflösung über DNS ausgetauscht.

+

Als DNS Tunnel bezeichnet man eine Verbindung die in der Lage ist über +das DNS Protokoll als Transportmedium generischen IP-Verkehr zu übertragen.

+
+

Einbetten von beliebigen Daten

+

Im folgenden ist der Datenverkehr zur Auflösung des Namens "bla.de" dekodiert dargestellt. +Das erste Paket ist die Anfrage des A-Record zu "bla.de". Das zweite Paket die Antwort des DNS Relay.

+

Das DNS-Relay antwortet "bla.de A IN 217.160.95.28", diese Angabe soll "5 hours, 39 minutes, +47 seconds" gültig sein. 217.160.95.28 wurde direkt binär übertragen als d9 a0 5f 1c.

+

Nichts hält einen DNS Server davon ab andere Daten als IP-Adressen in der Antwort zu verschicken und +nichts kann einen Client davon abhalten beliebige Daten in subdomains (hallowelt.bla.de) zu kodieren.

+

Aufgrund der hierarchischen Architektur von DNS kann der Inhaber einer Domains die Auflösung von +Subdomains übernehmen. Nach RFC1035 ist die maximale Länge eines auflösbaren Namens 255 Zeichen.

+
+
+
Time         Source      Destination  Protocol Info
+2.425301000  10.1.1.145  10.1.0.1     DNS      Standard query 0x5e9e A bla.de
+
+Internet Protocol Version 4, Src: 10.1.1.145 (10.1.1.145), Dst: 10.1.0.1 (10.1.0.1)
+User Datagram Protocol, Src Port: 52963 (52963), Dst Port: domain (53)
+Domain Name System (query)
+    [Response In: 16]
+    Transaction ID: 0x5e9e
+    Flags: 0x0100 Standard query
+    Questions: 1
+    Answer RRs: 0
+    Authority RRs: 0
+    Additional RRs: 0
+    Queries
+        bla.de: type A, class IN
+            Name: bla.de
+            Type: A (Host address)
+            Class: IN (0x0001)
+
+0030  00 00 00 00 00 00 03 62 6c 61 02 64 65 00 00 01   .......bla.de...
+0040  00 01                                             ..
+
+Time         Source    Destination  Protocol Info
+2.493068000  10.1.0.1  10.1.1.145   DNS      Standard query response 0x5e9e A 217.160.95.28
+
+Internet Protocol Version 4, Src: 10.1.0.1 (10.1.0.1), Dst: 10.1.1.145 (10.1.1.145)
+User Datagram Protocol, Src Port: domain (53), Dst Port: 52963 (52963)
+Domain Name System (response)
+    [Request In: 15]
+    [Time: 0.067767000 seconds]
+    Transaction ID: 0x5e9e
+    Flags: 0x8180 Standard query response, No error
+    Questions: 1
+    Answer RRs: 1
+    Authority RRs: 0
+    Additional RRs: 0
+    Queries
+        bla.de: type A, class IN
+            Name: bla.de
+            Type: A (Host address)
+            Class: IN (0x0001)
+    Answers
+        bla.de: type A, class IN, addr 217.160.95.28
+            Name: bla.de
+            Type: A (Host address)
+            Class: IN (0x0001)
+            Time to live: 5 hours, 39 minutes, 47 seconds
+            Data length: 4
+            Addr: 217.160.95.28 (217.160.95.28)
+
+0030  00 01 00 00 00 00 03 62 6c 61 02 64 65 00 00 01   .......bla.de...
+0040  00 01 c0 0c 00 01 00 01 00 00 4f a3 00 04 d9 a0   ..........O.....
+0050  5f 1c                                             _.
+
+
+

Gegenmaßnahmen

+

Die von einem idealen DNS Tunnel gestellten Anfragen sind gültig und unterscheiden sich +in erster Linie nicht von denen einer gewöhnlichen Anwendung von DNS. Um Tunnel +aufzuspüren wären daher statistische Verfahren nötig die Kriterien wie Anzahl, +Größe und Inhalt der Pakete betrachten. Aufgrund der Fehleranfälligkeit ist +es damit aber auch möglich legitime Anwendungen zu blockieren.

+

Möchte man lediglich iodine als konkrete Implementierung blockieren ist dies sehr einfach möglich. +Der vom iodine Client Verwendete "ping" Aufruf kann sehr einfach erkannt werden, es könnte jeder Client +der regelmäßíg eine Subdomain mit dem Anfangsbuchstaben "p" der gleichen Restdomain erfragt geblockt werden.

+

In einem durch Proxy Server sowieso schon stark eingeschränkten Netzwerk ist es denkbar, dass auf die Auflösung von +Namen ausserhalb der lokalen Domain durch den DNS Server allgemein verzichtet wird. +Sowohl ein HTTP-Proxyserver als auch ein SOCKS Server kann dies für +den Client übernehmen.

+

In einer Konfiguration für einen Internet Hotspot mit Autorisation der Benutzer (z.B. nach Bezahlvorgang) ist +es unbedingt sinnvoll die Autoriserungsregeln auch auf den DNS Server anzuwenden, sodass für den nicht autorisierten +Benutzer nur das Loginformular aufrufbar ist. Dies in vielen öffentlichen Hotspots momentan nicht umgesetzt. +Für weitere Informationen zum Blockieren von DNS Tunneln siehe [schillinger11].

+
+
+
+
+

Bedienung

+
+

Im folgenden wird die Bedienung der Android Oberfläche beschrieben. Die Anwendungen +teilt sich für den Benutzer in zwei Bereiche: Die Steuerung der Tunnel und die +Verbindungskonfiguration.

+
+

Hauptbildschirm

+
+
+
+bilder/screen_main.png +
+
+

Der Hauptbildschirm zeigt die konfigurierten Verbindungsprofile. Eine Verbindung wird +mit Auswahl des Eintrags gestartet.

+

Mit dem Einstellungsbutton +../res/drawable/ic_bt_config.png + können +die Verbindungsparameter geändert werden.

+

Mit dem Button +../res/drawable/device_access_new_account.png + in der ActionBar +wird ein neues Verbindungsprofil angelegt.

+
+
+
+

Verbindungskonfiguration

+
+
+
+bilder/screen_pref.png +
+
+

In der Verbindungskonfiguration werden Parameter festgelegt die beim Starten +des Tunnels gesetzt werden. Die Änderungen werden sofort übernommen.

+

Zu jeder Einstellung kann mit Drücken des Hilfebuttons die Hilfe aus der Nachfolgenden +Tabelle aufgerufen werden.

+

Mit mit der Auswahl von +../res/drawable/delete.png + wird +die aktuell geöffnete Konfiguration gelöscht.

+
+
+ + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Tabelle 1. Parameter
Parameter Beschreibung

Name

Name für diese Verbindungskonfiguration<

Lazy-Mode

Lazy mode erhöht den Durchsatz und senkt die Reaktionszeit. + Eine kleine Minderheit an DNS Relays scheint damit nicht klarzukommen was + darin resultiert dass keine oder fast keine Daten übertragen werden. + Der Client wird dies aber in der Regel feststellen und den Lazy mode ausschalten. + Falls nicht, kann lazy-mode mit dieser Option ausgeschaltet werden.

Tunnel Nameserver

Der Nameserver/DNS Relay, der verwendet wird um mit iodined zu kommunizieren. + Dieses Feld ist optional und wenn es nicht gesetzt ist wird der im System hinterlegte + DNS Server verwendet

Nameserver-Mode

Legt fest wie der Nameserver gesetzt werden soll nachdem der Tunnel aufgebaut wurde

Nameserver

IP-Adresse eine speziellen Nameserver der gesetzt werden soll + wenn Nameserver Modus = Custom ist.

Password

Dieses Feld ist optional. Es werden nur die ersten 32 Zeichen verwendet. + pwasswo cont

Raw-Mode

Falls gesetzt wird iodine versuchen die öffentliche IP-Adresse des iodined Server + aufzulösen und testen ob er direkt erreichbar ist. Falls ja, wird er den Traffic + direkt an den Server senden anstatt an ein DNS relay

Request-Type

Typ der DNS Abfragen. Standardmäßig wird die beste Request type automatisch ausgewählt.

Top-Domain

Der DNS Traffic wird als Anfragen für subdomains unterhalb dieser Topdomain gesendert. + Dies ist gewöhnlich eine Domain die Dir gehört. Verwende eine kurze + Domain um mehr Durchsatz zu erzielen. + Diese Einstellung muss am Server und am Client gleich sein

Default Route

Legt fest ob die Default Route gesetzt wird nachdem die Verbindung aufgebaut wurde

+
+
+
+
+
+

Einrichtung eines iodine Server

+
+

Vorraussetzung für den Betrieb eines Iodine Server ist eine öffentlich erreichbare IP-Adresse und +ein freier Port 53/dns.

+

Es muss ein NS-Record für diese IP-Adresse eingerichtet werden. Angenommen die Tunnel Toplevel Domain +soll "t.example.com" sein und der Server hat die IP-Adresse 192.0.43.10, dann lautet der Eintrag:

+
+
+
t.example.com.       8192    IN  NS    192.0.43.10
+
+

Die Konfiguration der IP-Adressen erfolgt nicht über DHCP oder statisch, sondern diese werden den Clients +vom iodine Server, aus einem IP Subnetz das beim Start festgelegt wird, zugewiesen.

+
+
+
iodined -c -P PASSWORD 192.168.0.1/24 t.example.com
+
+

Die Option -c ist nicht immer erforderlich. Sie bewirkt, dass iodine die Quelladressen der Anfragen +nicht überprüft. Die Überprüfung ist nicht möglich wenn die DNS Anfragen über ein Cluster verarbeitet werden, +sodass die beim Server einkommenden Pakete von verschiedenen Quelladressen stammen.

+

Der Server legt ein TUN-Device an (typischerweise "dns0"), je nach Zweck ist noch das +IP Routing/Masquerade zu konfigurieren.

+
+

Testen

+

Die Funktionstüchtigkeit eines iodine Server kann mit einfachen DNS Anfragen getestet werden:

+
+
+
$ dig -t A zabc.t.example.com
+....
+;; QUESTION SECTION:
+;zabc.t.example.com.      IN  A
+
+;; ANSWER SECTION:
+zabc.t.example.com.   0 IN  CNAME hpjqweyzo.dh.
+
+$ ./base32 d pjqweyz
+Decoded 4 bytes:
+0x7a (z) 0x61 (a) 0x62 (b) 0x63 (c)
+

Unter http://code.kryo.se/iodine/check-it/ wird ein Online Service zum Testen der Konfiguration angeboten.

+
+
+
+
+

Anhang

+ +
+
+

+ + + diff --git a/doc/anwenderdoku.pdf b/doc/anwenderdoku.pdf new file mode 100644 index 0000000..9dba3da Binary files /dev/null and b/doc/anwenderdoku.pdf differ diff --git a/doc/anwenderdoku.txt b/doc/anwenderdoku.txt new file mode 100644 index 0000000..f38c7bf --- /dev/null +++ b/doc/anwenderdoku.txt @@ -0,0 +1,279 @@ +Android Iodine Anwenderdokumentation +==================================== +Yves Fischer +April 2013 +:toc: +:doctype: article +:lang: de +:icons: + + +[abstract] +-- +Die Dokumentation ist zweigeteilt. Dieser Teil enthält eine Beschreibung des Programs +und einen Überblick über die Funktionsweise von DNS-Tunnel. Zur technischen Beschreibung +des Programs siehe 'Entwicklerdokumentation'. + +Ein DNS Tunnel ermöglicht regulären IP Verkehr durch den Internet +Namensauflösungsdienst DNS zu tunneln. Damit ist es möglich, in Netzen +die keine normales Internet Routing unterstützen, Daten auszutauschen. +Voraussetzung ist, dass das Netz gewöhnliche DNS-Auflösung unterstützt. +Die Datenpakete werden in DNS-Anfragen kodiert, die durch die hierarchische +Struktur an einen speziellen (i.d.R. third-level) Nameserver weitergeleitet werden. + +Die Software <> ist eine Implementierung eines DNS Tunnel für Linux, +Mac OS X, FreeBSD, NetBSD, OpenBSD and Windows. Diese Dokumentation beschreibt +die Portierung auf Android mit einer angepassten Benutzeroberfläche. +-- + +Android Systemanforderungen +--------------------------- + +Durch die Verwendung des Android VPN Framework ist mindestens Android +4.0 (API Level 14) erforderlich. + +Für Android vor 4.0 besteht bei vorhandenem Root Zugriff die Möglichkeit +das tun.ko Kernelmodul zu laden und ein +http://code.kryo.se/iodine/iodine-latest-android.zip[cross-kompiliertes +iodine] auszuführen. + + + +Funktionsweise eines DNS-Tunnel +------------------------------- + +Das Domain-Name-System (DNS) wird eingesetzt um Namen (wie +"example.com") in IP-Adressen (wie "194.71.107.50" oder +"2001:db8:85a3:8d3:1319:8a2e:370:7347") zu übersetzen. DNS wurde in den +1980er Jahren ursprünglich mit dem Ziel entwickelt lokale `hosts` Datei +im Internet abzulösen. Inzwischen werden auch andere Informationen als +die reine Adressauflösung über DNS ausgetauscht. + +Als DNS Tunnel bezeichnet man eine Verbindung die in der Lage ist über +das DNS Protokoll als Transportmedium generischen IP-Verkehr zu übertragen. + +Einbetten von beliebigen Daten +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Im folgenden ist der Datenverkehr zur Auflösung des Namens "bla.de" dekodiert dargestellt. +Das erste Paket ist die Anfrage des A-Record zu "bla.de". Das zweite Paket die Antwort des DNS Relay. + +Das DNS-Relay antwortet "bla.de A IN 217.160.95.28", diese Angabe soll "5 hours, 39 minutes, +47 seconds" gültig sein. `217.160.95.28` wurde direkt binär übertragen als `d9 a0 5f 1c`. + +Nichts hält einen DNS Server davon ab andere Daten als IP-Adressen in der Antwort zu verschicken und +nichts kann einen Client davon abhalten beliebige Daten in subdomains (hallowelt.bla.de) zu kodieren. + +Aufgrund der hierarchischen Architektur von DNS kann der Inhaber einer Domains die Auflösung von +Subdomains übernehmen. Nach RFC1035 ist die maximale Länge eines auflösbaren Namens 255 Zeichen. + +[source,c] +------------------------------------------------------------------------------------------------------------- +Time Source Destination Protocol Info +2.425301000 10.1.1.145 10.1.0.1 DNS Standard query 0x5e9e A bla.de + +Internet Protocol Version 4, Src: 10.1.1.145 (10.1.1.145), Dst: 10.1.0.1 (10.1.0.1) +User Datagram Protocol, Src Port: 52963 (52963), Dst Port: domain (53) +Domain Name System (query) + [Response In: 16] + Transaction ID: 0x5e9e + Flags: 0x0100 Standard query + Questions: 1 + Answer RRs: 0 + Authority RRs: 0 + Additional RRs: 0 + Queries + bla.de: type A, class IN + Name: bla.de + Type: A (Host address) + Class: IN (0x0001) + +0030 00 00 00 00 00 00 03 62 6c 61 02 64 65 00 00 01 .......bla.de... +0040 00 01 .. + +Time Source Destination Protocol Info +2.493068000 10.1.0.1 10.1.1.145 DNS Standard query response 0x5e9e A 217.160.95.28 + +Internet Protocol Version 4, Src: 10.1.0.1 (10.1.0.1), Dst: 10.1.1.145 (10.1.1.145) +User Datagram Protocol, Src Port: domain (53), Dst Port: 52963 (52963) +Domain Name System (response) + [Request In: 15] + [Time: 0.067767000 seconds] + Transaction ID: 0x5e9e + Flags: 0x8180 Standard query response, No error + Questions: 1 + Answer RRs: 1 + Authority RRs: 0 + Additional RRs: 0 + Queries + bla.de: type A, class IN + Name: bla.de + Type: A (Host address) + Class: IN (0x0001) + Answers + bla.de: type A, class IN, addr 217.160.95.28 + Name: bla.de + Type: A (Host address) + Class: IN (0x0001) + Time to live: 5 hours, 39 minutes, 47 seconds + Data length: 4 + Addr: 217.160.95.28 (217.160.95.28) + +0030 00 01 00 00 00 00 03 62 6c 61 02 64 65 00 00 01 .......bla.de... +0040 00 01 c0 0c 00 01 00 01 00 00 4f a3 00 04 d9 a0 ..........O..... +0050 5f 1c _. +------------------------------------------------------------------------------------------------------------- + + +[[gegenmasnahmen,Gegenmaßnahmen]] +Gegenmaßnahmen +~~~~~~~~~~~~~~ + +Die von einem idealen DNS Tunnel gestellten Anfragen sind gültig und unterscheiden sich +in erster Linie nicht von denen einer gewöhnlichen Anwendung von DNS. Um Tunnel +aufzuspüren wären daher statistische Verfahren nötig die Kriterien wie Anzahl, +Größe und Inhalt der Pakete betrachten. Aufgrund der Fehleranfälligkeit ist +es damit aber auch möglich legitime Anwendungen zu blockieren. + +Möchte man lediglich iodine als konkrete Implementierung blockieren ist dies sehr einfach möglich. +Der vom iodine Client Verwendete "ping" Aufruf kann sehr einfach erkannt werden, es könnte jeder Client +der regelmäßíg eine Subdomain mit dem Anfangsbuchstaben "p" der gleichen Restdomain erfragt geblockt werden. + +In einem durch Proxy Server sowieso schon stark eingeschränkten Netzwerk ist es denkbar, dass auf die Auflösung von +Namen ausserhalb der lokalen Domain durch den DNS Server allgemein verzichtet wird. +Sowohl ein HTTP-Proxyserver als auch ein SOCKS Server kann dies für +den Client übernehmen. + +In einer Konfiguration für einen Internet Hotspot mit Autorisation der Benutzer (z.B. nach Bezahlvorgang) ist +es unbedingt sinnvoll die Autoriserungsregeln auch auf den DNS Server anzuwenden, sodass für den nicht autorisierten +Benutzer nur das Loginformular aufrufbar ist. Dies in vielen öffentlichen Hotspots momentan nicht umgesetzt. +Für weitere Informationen zum Blockieren von DNS Tunneln siehe <>. + + +Bedienung +--------- + +Im folgenden wird die Bedienung der Android Oberfläche beschrieben. Die Anwendungen +teilt sich für den Benutzer in zwei Bereiche: Die Steuerung der Tunnel und die +Verbindungskonfiguration. + + +Hauptbildschirm +~~~~~~~~~~~~~~~ + +unfloat::[] + +image::bilder/screen_main.png[width="300px",scaledwidth="50%",float="left"] + +Der Hauptbildschirm zeigt die konfigurierten Verbindungsprofile. Eine Verbindung wird +mit Auswahl des Eintrags gestartet. + +Mit dem Einstellungsbutton image:../res/drawable/ic_bt_config.png[width="32px"] können +die Verbindungsparameter geändert werden. + +Mit dem Button image:../res/drawable/device_access_new_account.png[width="32px"] in der ActionBar +wird ein neues Verbindungsprofil angelegt. + +unfloat::[] + +Verbindungskonfiguration +~~~~~~~~~~~~~~~~~~~~~~~~ + +unfloat::[] + +image::bilder/screen_pref.png[width="300px",scaledwidth="50%",float="left"] + +In der Verbindungskonfiguration werden Parameter festgelegt die beim Starten +des Tunnels gesetzt werden. Die Änderungen werden sofort übernommen. + +Zu jeder Einstellung kann mit Drücken des Hilfebuttons die Hilfe aus der Nachfolgenden +Tabelle aufgerufen werden. + +Mit mit der Auswahl von image:../res/drawable/delete.png[width="32px"] wird +die aktuell geöffnete Konfiguration gelöscht. + +unfloat::[] + +.Parameter +[options="header"] +|===================================== +|Parameter | Beschreibung +|Name | Name für diese Verbindungskonfiguration< +|Lazy-Mode | Lazy mode erhöht den Durchsatz und senkt die Reaktionszeit. + Eine kleine Minderheit an DNS Relays scheint damit nicht klarzukommen was + darin resultiert dass keine oder fast keine Daten übertragen werden. + Der Client wird dies aber in der Regel feststellen und den Lazy mode ausschalten. + Falls nicht, kann lazy-mode mit dieser Option ausgeschaltet werden. +|Tunnel Nameserver | Der Nameserver/DNS Relay, der verwendet wird um mit iodined zu kommunizieren. + Dieses Feld ist optional und wenn es nicht gesetzt ist wird der im System hinterlegte + DNS Server verwendet +|Nameserver-Mode | Legt fest wie der Nameserver gesetzt werden soll nachdem der Tunnel aufgebaut wurde +|Nameserver | IP-Adresse eine speziellen Nameserver der gesetzt werden soll + wenn Nameserver Modus = Custom ist. +|Password | Dieses Feld ist optional. Es werden nur die ersten 32 Zeichen verwendet. + pwasswo cont +|Raw-Mode | Falls gesetzt wird iodine versuchen die öffentliche IP-Adresse des iodined Server + aufzulösen und testen ob er direkt erreichbar ist. Falls ja, wird er den Traffic + direkt an den Server senden anstatt an ein DNS relay +|Request-Type | Typ der DNS Abfragen. Standardmäßig wird die beste Request type automatisch ausgewählt. +|Top-Domain | Der DNS Traffic wird als Anfragen für subdomains unterhalb dieser Topdomain gesendert. + Dies ist gewöhnlich eine Domain die Dir gehört. Verwende eine kurze + Domain um mehr Durchsatz zu erzielen. + Diese Einstellung muss am Server und am Client gleich sein +|Default Route | Legt fest ob die Default Route gesetzt wird nachdem die Verbindung aufgebaut wurde +|==================================== + +Einrichtung eines iodine Server +------------------------------- + +Vorraussetzung für den Betrieb eines Iodine Server ist eine öffentlich erreichbare IP-Adresse und +ein freier Port 53/dns. + +Es muss ein NS-Record für diese IP-Adresse eingerichtet werden. Angenommen die Tunnel Toplevel Domain +soll "t.example.com" sein und der Server hat die IP-Adresse 192.0.43.10, dann lautet der Eintrag: + + t.example.com. 8192 IN NS 192.0.43.10 + +Die Konfiguration der IP-Adressen erfolgt nicht über DHCP oder statisch, sondern diese werden den Clients +vom iodine Server, aus einem IP Subnetz das beim Start festgelegt wird, zugewiesen. + + iodined -c -P PASSWORD 192.168.0.1/24 t.example.com + +Die Option `-c` ist nicht immer erforderlich. Sie bewirkt, dass iodine die Quelladressen der Anfragen +nicht überprüft. Die Überprüfung ist nicht möglich wenn die DNS Anfragen über ein Cluster verarbeitet werden, +sodass die beim Server einkommenden Pakete von verschiedenen Quelladressen stammen. + +Der Server legt ein TUN-Device an (typischerweise "dns0"), je nach Zweck ist noch das +IP Routing/Masquerade zu konfigurieren. + +Testen +~~~~~~ + +Die Funktionstüchtigkeit eines iodine Server kann mit einfachen DNS Anfragen getestet werden: + +[source,bash] +-------------------------------------------------------------------------------------------------------- +$ dig -t A zabc.t.example.com +.... +;; QUESTION SECTION: +;zabc.t.example.com. IN A + +;; ANSWER SECTION: +zabc.t.example.com. 0 IN CNAME hpjqweyzo.dh. + +$ ./base32 d pjqweyz +Decoded 4 bytes: +0x7a (z) 0x61 (a) 0x62 (b) 0x63 (c) +-------------------------------------------------------------------------------------------------------- + +Unter http://code.kryo.se/iodine/check-it/ wird ein Online Service zum Testen der Konfiguration angeboten. + +[bibliography] +Anhang +------ + +[bibliography] +- [[[schillinger11]]] + http://www.data.ks.uni-freiburg.de/download/praxisseminarSS11/dns-tunnel/Fabian%20Schillinger%20-%20DNS-Tunnel.pdf[Fabian Schillinger, DNS-Tunnel, Universität Freiburg 2011] +- [[[iodine]]] http://code.kryo.se/iodine/ + diff --git a/doc/bilder/Model_model_Architektur.PNG b/doc/bilder/Model_model_Architektur.PNG new file mode 100644 index 0000000..b326f5f Binary files /dev/null and b/doc/bilder/Model_model_Architektur.PNG differ diff --git a/doc/bilder/logo.png b/doc/bilder/logo.png new file mode 100644 index 0000000..5c28e32 Binary files /dev/null and b/doc/bilder/logo.png differ diff --git a/doc/bilder/model.di b/doc/bilder/model.di new file mode 100644 index 0000000..c2b1564 --- /dev/null +++ b/doc/bilder/model.di @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/bilder/model.notation b/doc/bilder/model.notation new file mode 100644 index 0000000..d1dbcc3 --- /dev/null +++ b/doc/bilder/model.notation @@ -0,0 +1,298 @@ + + + + +
+ + +
+ + +
+ + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/bilder/model.uml b/doc/bilder/model.uml new file mode 100644 index 0000000..1bc0ff6 --- /dev/null +++ b/doc/bilder/model.uml @@ -0,0 +1,41 @@ + + + + action.MAIN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/bilder/screen_main.png b/doc/bilder/screen_main.png new file mode 100644 index 0000000..6a5f6d4 Binary files /dev/null and b/doc/bilder/screen_main.png differ diff --git a/doc/bilder/screen_pref.png b/doc/bilder/screen_pref.png new file mode 100644 index 0000000..7592d66 Binary files /dev/null and b/doc/bilder/screen_pref.png differ diff --git a/doc/bilder/whiteboard_gui.jpg b/doc/bilder/whiteboard_gui.jpg new file mode 100644 index 0000000..b778fac Binary files /dev/null and b/doc/bilder/whiteboard_gui.jpg differ diff --git a/doc/bilder/whiteboard_intents.jpg b/doc/bilder/whiteboard_intents.jpg new file mode 100644 index 0000000..2aed674 Binary files /dev/null and b/doc/bilder/whiteboard_intents.jpg differ diff --git a/doc/bilder/whiteboard_komponenten.jpg b/doc/bilder/whiteboard_komponenten.jpg new file mode 100644 index 0000000..c468377 Binary files /dev/null and b/doc/bilder/whiteboard_komponenten.jpg differ diff --git a/doc/entwicklerdoku.html b/doc/entwicklerdoku.html new file mode 100644 index 0000000..eea35fb --- /dev/null +++ b/doc/entwicklerdoku.html @@ -0,0 +1,1284 @@ + + + + + +Android Iodine Entwicklerdokumentation + + + + + +
+
+
+
+
+

Die Dokumentation ist zweigeteilt. Dieser Teil enthält eine technische Beschreibung. +Die Bedienung und Funktionsweise ist in der Anwenderdokumentation beschrieben.

+
+
+
+
+
+
+

Aufbau

+
+

Die Anwendung besteht im groben aus 4 Komponenten

+
    +
  • +

    +Activity .IodineMain +

    +
  • +
  • +

    +Activity Verbindungseinstellungen .IodinePref +

    +
  • +
  • +

    +Tunnel Service VpnService und den JNI Bindings IodineClient +

    +
  • +
  • +

    +Konfigurationsverwaltung .config.ConfigDatabase und .config.IodineConfiguration +

    +
  • +
+

[whiteboard-komponenten] zeigt Architektur der Anwendung:

+
+
+bilder/Model_model_Architektur.PNG +
+
Abbildung 1. Architektur der Anwendung
+
+
+

Benutzeroberfläche

+

Die Haupt Activity .IodineMain startet den "VpnService" und steuert +ihn über Broadcast Intents. In dieser Activity steuert der Benutzer den +Auf- und Abbau der Tunnel. Über ein Button in der ActionToolbar kann +eine neue Tunnelkonfiguration angelegt werden.

+

Die Interaktion zwischen des Benutzers in der Anwendung ist in +[whiteboard-gui] visuell dargestellt:

+
+
+bilder/whiteboard_gui.jpg +
+
Abbildung 2. Graphischer Aufbau der GUI
+
+
+
+

Konfiguration

+

Die Tunnelkonfigurationen werden in einer SQLite Datenbank abgelegt. Es +existiert mit .config.IodineConfiguration ein leichtgewichtiger Proxy +um die Android ContentValues Klasse. Die .config.ConfigDatabase Klasse +ist ein SQLiteOpenHelper und kann mehrfach instanziert werden.

+
+
+

VPN-Service

+

Der VPN Service hat 5 Zustände die er über Broadcast Intents mitteilt. +Eine solche Mitteilung wird verschickt wenn sich der Zustand ändert oder +dies über ACTION_CONTROL_UPDATE angefordert wurde.

+

Die Kommunikation der Oberfläche mit dem VPN Service erfolgt mit Broadcasts Intents.

+

[whiteboard-intents] zeigt die Zustände des Iodine VPN-Service. Rot nummeriert sind die +Intents die der Service verschickt um über Statusänderungen zu informieren. Blau nummeriert +sind Intents mit denen der Service gesteuert werden kann.

+
+
+bilder/whiteboard_intents.jpg +
+
Abbildung 3. Status Informations und Steuerungs Intents des VPN Service
+
+
+
+

JNI

+

Die JNI Methoden für iodine befinden sich in der Klasse .IodineClient +bzw. /jni/iodine-client.c. IodineClient#connect ersetzt dabei prinzipiell +die main() des ursprünglichen iodine Client.

+

Weitere Methoden dienen dem Austausch der vom Server übermittelten Konfiguration +und des im System eingestellten DNS Server.

+
+
+
+
+

Android VPN-Framework

+
+

Seit API Level 14/Android 4 ist es möglich VPN Verbindungen mit Android +Anwendungen aufzubauen und zu verwalten.

+

Die Application benötigt dazu die Permission +android.permission.BIND_VPN_SERVICE.

+

Bevor eine Anwendung das erste mal eine VPN Verbindung aufbauen darf +wird Android sicherheitshalber den Benutzer explizit um Erlaubnis +fragen.

+

Dazu wird IodineVpnService.prepare(this) [vpnapi] +aufgerufen. Wird null zurückgegeben hat der Benutzer VPN Verbindungen +dieser App bereits früher zugestimmt. Andernfalls wird ein Intent +zurückgegeben mit dem die Benutzernachfrage initiiert werden kann.

+
+
+
  public void tunnel() {
+    Intent intent = IodineVpnService.prepare(this);
+    if (intent != null) {
+      // Ask for permission
+      intent.putExtra(IodineVpnService.EXTRA_CONFIGURATION_ID, configuration.getId());
+      startActivityForResult(intent, INTENT_REQUEST_CODE_PREPARE);
+    } else {
+      // Permission already granted
+      startVPNService();
+    }
+  }
+
+  @Override
+  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    if (requestCode == INTENT_REQUEST_CODE_PREPARE) {
+      if (resultCode == RESULT_OK) {
+        startVPNService();
+      } else {
+        // User denied permission
+      }
+    }
+  }
+
+  private void startVPNService() {
+    // Start VPN with VPNService.Builder
+  }
+

Der weitere Weg mit dem VPNService.Builder ist geradelinig. Im Fall +von iodine wird zunächst der Tunnel über DNS aufgebaut bevor das +tun-Interface geöffnet wird.

+

Nachdem vom Server die IP-Konfiguration mitgeteilt wurde, wird diese im +Builder gesetzt und der Tunnel geöffnet:

+
+
+
    // .... IodineVpnService.java :: runTunnel()
+    b.addAddress(hostAddress, netbits);
+    b.addRoute("0.0.0.0", 0); // Default Route
+    b.setMtu(mtu);
+
+    // Opens tun device
+    ParcelFileDescriptor parcelFD = b.establish();
+
+    // prevent dns traffic to get through its own tunnel
+    protect(IodineClient.getDnsFd());
+
+    // get the filedescriptor
+    int tun_fd = parcelFD.detachFd();
+
+    // pass the filedescriptor to iodine
+    IodineClient.tunnel(tun_fd);
+
+
+
+

iodine

+
+
+

Verbindungsaufbau (Handshake)

+

Der folgende Text zeigt ein Beispiel für den Ablauf eines Handshake. Der genaue Ablauf kann +variieren jenachdem wie die Verbindungsparameter gewählt werden.

+

Hier sind gewählt -m 768 fragment size und ein 9 Zeichen +Passwort. Die Gegenstelle ist t.yves.tw. Eine Raw (direkte UDP) Verbindung +wurde verhindert indem der Rechner zum Testzeitpunkt keine default Route hatte.

+

RX/TX aus der Sicht des Servers. Die "*" in den Hostnamen markieren Zeichen die +sich aus Random Daten ergeben.

+
+
+
    == Der Client testet die Qualitaet der Uebertragung
+    <-- client.c:handshake_qtype_autodetect()
+              -> handshake_qtypetest()
+              -> send_downenctest()
+      hostname[0] = "y"
+      hostanme[1] = downenc = 'r'
+      hostname[2] = variant = 1 = 'b' (b32)
+      hostname[3..5] = rand_seed++
+      RX: yrb***.t.yves.tw
+
+    --> 48 bytes aus encoding.h:DOWNCODECHECK
+      TX: yrb***.t.yves.tw, 48 bytes data
+
+    == Austausch der Versionsinformationen
+    <-- client.c:send_version()
+      VERSION=0x00 00 05 02
+      hostname[0] = cmd = 'v'
+      hostname[1..6] = b32(0,0,5,2,random<<8,random)
+      hostname = "vAAAAKAR__"
+      RX: vaaaaka****.t.yves.tw
+
+    --> iodined.c:send_version_response()
+      der Server bestaetigt mit
+      data[0..8] = "VACK" b32(seed>>24, seed>>16, seed>>8, seed, userid)
+      TX: vaaaaka***.t.yves.tw, 9 bytes data
+
+
+    == Senden von Passwort und IP-Konfiguration (Subnetz)
+    <-- client.c:send_login()
+      cmd = 'l'
+      hostname[1..16] = login/password mit seed xored und md5
+      hostname[17..18] = seed
+      RX: lad24srn4ezmg21qjsfy13msagd0srfq.t.yves.tw
+
+    --> iodined.c:handle_null_request()
+      Sendet bei Erfolg die IP Einstellungen wie
+      "172.16.0.1-172.16.0.2-1130-16"
+      server="172.16.0.1"
+      client="172.16.0.2"
+      mtu=1130
+      netbits=16
+      TX: lad24srn4ezmg21qjsfy13msagd0srfq.t.yves.tw
+        = 3137322e31362e302e312d3137322e31362e302e322d313133302d3136 (_16)
+        = 172.16.0.1-172.16.0.2-1130-16
+
+    == Senden der IP Adresse des Clients
+    <-- Request for IP address
+      RX: iamin.t.yves.tw
+
+    --> iodined.c:handle_null_request()
+        addr = externe IP Adresse des Server (-n Switch)
+        reply[0] = 'I';
+        reply[1] = (addr >> 24) & 0xFF;
+        reply[2] = (addr >> 16) & 0xFF;
+        reply[3] = (addr >>  8) & 0xFF;
+        reply[4] = (addr >>  0) & 0xFF;
+      TX: iamin.t.yves.tw
+        = 494e2f737d (_16)
+
+    == Testen auf EDNS Erweiterung
+    <-- client.c:handshake_edns0_check()
+              -> send_downenctest()
+      downenc = 'r' fuer T_NULL 't'
+      variant = 1 = 'b' (b32)
+      data[0..5]  = "y" downenc variant rand_seed[0..2]
+      RX: yrb***.t.yves.tw
+
+    --> iodined.c:handle_null_login() : 937
+               -> write_dns( type='R')
+      Der Server antwortet mit 48 bytes aus encoding.h:DOWNCODECHECK
+      TX: yrb***.t.yves.tw, 48 bytes data
+
+
+    == Testen der Kodierungen mit verschiedenen Patterns
+    <-- client.c:handshake_upenc_autodetect()
+      In den folgenden Tests testet der Client ob mit Base128
+      kodierte Nachrichten vom DNS Relay korrekt verarbeitet werden.
+
+    --> Der Server schickt die Patterns einfach wieder zurueck.
+
+    == Client legt Kodierung fest, Server bestaetigt
+    <-- client.c:handshake_switch_codec()
+      hostname[0] = command 's'
+      hostname[1] = b32(userid)
+      hostname[2] = 'h' (7)
+      hostname[3..5] = rand_seed++
+      rand_seed++;
+      RX: sahmiut.yves.tw
+
+    --> iodined.c:840
+      Schreibt den Namen des ausgewaehlten Codecs:
+      data="Base128" (kein encoding!)
+      TX: sahmiut.yves.tw, 7 bytes of data
+
+    == Anschalten lazy mode (an: Server beantwortet Anfragen nicht sofort)
+    <-- client.c:send_lazy_switch()
+      hostname[0] = 'o'
+      hostname[1] = b32(userid) = 'a'
+      hostname[2] = 'l' fuer lazy mode oder 'i'
+      hostname[3..5] = rand_seed++
+      RX: oalmiv.t.yves.tw
+
+    --> iodined.c:919
+      data="Lazy" (kein encoding!)
+      TX: oalmiv.t.yves.tw, 4 bytes of data
+
+    ==
+    <-- client.c:send_set_downstream_fragsize()
+      data[0] = userid;
+      data[1] = (fragsize & 0xff00) >> 8;
+      data[2] = (fragsize & 0x00ff);
+      data[3] = (rand_seed >> 8) & 0xff;
+      data[4] = (rand_seed >> 0) & 0xff;
+      hostname = 'n' + b32(data)
+      RX: naabqbmiw.t.yves.tw
+
+    --> iodined.c:1042
+      bestaetigt empfangene Framesize durch Wiederholung
+
+    == Regelmaesige pings fragen den Server nach anstehenden Daten ab
+    <-- client.c:send_ping()
+      data[0] = userid;
+      data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15);
+      data[2] = (rand_seed >> 8) & 0xff;
+      data[3] = (rand_seed >> 0) & 0xff;
+      hostname = 'p' + b32(data)
+      RX: paaalcfy.t.yves.tw
+
+    --> iodined.c:1067
+      Der Server nutzt die regelmaessigen Pings um Daten an den Client zu liefern.
+
+

Der lazy Modus

+

Wie in der Anwenderdokumentation beschrieben erhöht der Lazy Modus den Durchsatz +und senkt die Latenzzeit, wird aber nicht von allen DNS-Relays unterstützt.

+

Lazy bezieht sich auf das Verhalten des Servers. Der Server wird im Lazy-mode +alle Antworten auf Anfragen solange zurückhalten bis er neue Daten für den +Client erhalten hat. Im Idealfall also bis das Antwortpaket der getunnelten +IP Verbindung angekommen ist.

+

Diese Verzögerung kann mit manchen DNS-Relays Probleme machen. Der Server kann dies jedoch +anhand der Duplikate in den Anfragen erkennen und damit den lazy-mode ausschalten.

+

Ohne diesen Mechanismus müsste der Client jedoch viel häufiger nach neuen Daten +pollen (vgl. HTTP Long polling in Comet oder BOSH).

+
+
+
+

iodine base(32) Kodierung

+

Dieses Programm bietet die Base32 Kodierung von iodine für die +Kommandozeile zum Debuggen an.

+
+
+
#include <stdio.h>
+#include <string.h>
+
+#include "src/base32.h"
+#include "src/encoding.h"
+
+int main(int argc, char *argv[]) {
+    struct encoder *b32 = get_base32_encoder();
+    char buf[512];
+    size_t len = 512;
+
+    if (argc != 3) return 0;
+    if (*argv[1] == 'd') {
+        int r = b32->decode(buf, &len, argv[2], strlen(argv[2]));
+        int i;
+        printf("Decoded %d bytes:\n", r);
+        for (i = 0; i< r; i++) {
+            printf("0x%02hhx (%c) ", buf[i], (buf[i] >= '0' && buf[i] <= 'z') ? buf[i] : ' ');
+        }
+        printf("\n");
+    } else if (*argv[1] == 'e') {
+        int r = b32->encode(buf, &len, argv[2], strlen(argv[2]));
+        printf("Encoded %d bytes in %ld output bytes: >%s<\n", len, r, buf);
+    }
+    return 0;
+}
+
+
+
+
# gcc test.c src/base32.c -o test
+# ./test e abcdefg
+Encoded 7 12 bytes: >mfrggzdfmztq<
+
+
+
+

Änderungen an iodine

+

Der Code basiert auf der letzten Iodine Version 0.6.0-rc1. Die +Änderungen wurden absichtlich möglichst gering gehalten und betragen +im wesentlichsten nur ca. 80 Zeilen.

+

Ein Hauptteil der Änderungen verhindern, dass Android als Linux erkannt wird. +Im Gegensatz zu vielen Linux Installationen verwenden Android nicht die GNU libc +sondern Bionic libc. Dies ist eine besonders kleine, auf die BSD libc zurückgehende +standard C Library. Es fehlen einige Features der glibc wie wide-character support, +volle POSIX Thread Unterstützung oder locale Unterstützung. Das Ziel von Bionic ist +nicht eine vollständige C Standardbibliothek sondern lediglich eine schlanke Implementierung +aller für ein Android nötigen Funktionen.

+

Im einfachsten Fall scheitert die Ausführung von iodine unter Android an einem system() Aufruf +mit dem iodine die IP-Konfiguration anwendet.

+
+

Android.mk

+

Das ursprüngliche iodine Makefile wird nicht verwendet. Es wird das +Android NDK Buildsystem verwendet, die Anweisungen dazu liegen in +jni/Android.mk. Aus dem Projektverzeichnis kann die Übersetzung der +C-Quellen angestossen werden.

+
+
+
org.xapek.andiodine % ~/$NDK_ROOT/ndk-build clean
+Clean: iodine-client [armeabi]
+Clean: stdc++ [armeabi]
+org.xapek.andiodine % ~/$NDK_ROOT/ndk-build
+Compile thumb  : iodine-client <= iodine-client.c
+Compile thumb  : iodine-client <= tun.c
+Compile thumb  : iodine-client <= dns.c
+Compile thumb  : iodine-client <= read.c
+Compile thumb  : iodine-client <= encoding.c
+Compile thumb  : iodine-client <= login.c
+Compile thumb  : iodine-client <= base32.c
+Compile thumb  : iodine-client <= base64.c
+Compile thumb  : iodine-client <= base64u.c
+Compile thumb  : iodine-client <= base128.c
+Compile thumb  : iodine-client <= md5.c
+Compile thumb  : iodine-client <= common.c
+Compile thumb  : iodine-client <= client.c
+Compile thumb  : iodine-client <= util.c
+SharedLibrary  : libiodine-client.so
+Install        : libiodine-client.so => libs/armeabi/libiodine-client.so
+
+

Die Library wird vom Android SDK automatisch in die APK-Datei eingefügt.

+
+
+

common.c daemon()

+

Die daemon() Funktion in src/common.c ist gedacht um iodine als +Hintergrundprozess laufen zu lassen. Sie ist nur für Linux und BSD +vorgesehen.

+

Das #ifdef erkennt Android als Linux, Bionic unterstützt daemon() +jedoch nicht, da die Funktionalität der daemon() Funktion für eine +Android App nicht benötigt wird.

+

Auch in diesem Fall brauchen wir die daemon() Funktion nicht, da iodine +in einem von Java gesteuerten Thread laufen wird.

+
+
+

common.c warn()

+

Die warn() Funktion existiert nicht in der Bionic libc. Die +bereitgestellte Implementierung verwendet fprintf auf stderr. Die +Meldungen werden in das Android Logging System umgeleitet und sind auch +über Logcat nutzbar.

+
+
+

tun.c write_tun() / read_tun()

+

Wie bei FreeBSD und Windows muss beim schreiben auf das Tun device +(write_tun ) kein 4 byte großer Header mit der Adress Family angefügt werden. +Entsprechend wird dieser in read_tun() im Fall von Android, FreeBSD +und Windows nicht entfernt.

+
+
+

tun.c tun_setip()

+

Je nach Plattform werden wird die IP-Adresse unterschiedlich gesetzt. Im +Fall von Linux geschieht dies mit einem fragwürdigen +system("/sbin/ifconfig") Aufruf.

+

Dies ist unter Android so nicht möglich. Es wurde daher eine globale +Datenstruktur tun_config_android (tun.h) angelegt in welcher die zu +setzende IP-Adresse, Gegenstelle IP-Adresse und Netzmaske abgelegt wird. +Die Inhalte dieser Datenstruktur können von Java über JNI Funktionen +abgefragt werden.

+

Das setzen der IP-Adressen und Routen geschieht über Methoden des +Android VPN-Framework in Java.

+
+
+

DNS Headerfiles

+

Iodine benötigt Konstanten aus arpa/nameser_compat.h und arpa/nameser.h +das nicht Teil der Android Libc ist. Die Header wurden als +src/dns_android.h hinzugefügt.

+
+
+
+
+
+

Projekt öffnen und bauen

+
+
+

C Quellcodes übersetzen

+

Um das Projekt zu bauen ist neben dem Android SDK auch das Android NDK erforderlich. Mit dem daraus +bereitgestellten Kommando ndk-build werden die C-Quellcodes unterhalb des Verzeichnisses jni/ +übersetzt.

+
+
+
andiodine$ $NDK_ROOT/ndk-build clean
+Clean: iodine-client [armeabi]
+Clean: stdc++ [armeabi]
+Clean: iodine-client [x86]
+Clean: stdc++ [x86]
+
+andiodine$ $NDK_ROOT/ndk-build
+Compile thumb  : iodine-client <= iodine-client.c
+.....
+SharedLibrary  : libiodine-client.so
+Install        : libiodine-client.so => libs/armeabi/libiodine-client.so
+Compile x86    : iodine-client <= iodine-client.c
+.....
+SharedLibrary  : libiodine-client.so
+Install        : libiodine-client.so => libs/x86/libiodine-client.so
+
+
+
+

Entwickeln mit Eclipse

+

Das Projekt kann über den Importassistenten eingebunden werden:

+

Import → Android → Existing Android Code Into Workspace

+
+
+

Entwickeln mit Android Studio

+
    +
  • +

    +Choose Import Project, choose project Folder. +

    +
  • +
  • +

    +Select "Create project from existing sources". +

    +
  • +
+
+
+

Übersetzen mit ant

+

Using ant

+
+
+
   android project --path .
+   ant debug
+
+

Die APK liegt unterhalb von bin und kann mit dem ant target install über adb installiert werden.

+
+
+
+
+

Anhang

+
+
+
+
+
+

+ + + diff --git a/doc/entwicklerdoku.pdf b/doc/entwicklerdoku.pdf new file mode 100644 index 0000000..edfdd2d Binary files /dev/null and b/doc/entwicklerdoku.pdf differ diff --git a/doc/entwicklerdoku.txt b/doc/entwicklerdoku.txt new file mode 100644 index 0000000..ce92eeb --- /dev/null +++ b/doc/entwicklerdoku.txt @@ -0,0 +1,536 @@ +Android Iodine Entwicklerdokumentation +====================================== +Yves Fischer +April 2013 +:toc: +:doctype: article +:lang: de +:icons: + +[abstract] +-- +Die Dokumentation ist zweigeteilt. Dieser Teil enthält eine technische Beschreibung. +Die Bedienung und Funktionsweise ist in der 'Anwenderdokumentation' beschrieben. +-- + +Aufbau +------ +Die Anwendung besteht im groben aus 4 Komponenten + +* Activity `.IodineMain` +* Activity Verbindungseinstellungen `.IodinePref` +* Tunnel Service `VpnService` und den JNI Bindings `IodineClient` +* Konfigurationsverwaltung `.config.ConfigDatabase` und `.config.IodineConfiguration` + +<> zeigt Architektur der Anwendung: + +[[whiteboard-komponenten]] +.Architektur der Anwendung +image::bilder/Model_model_Architektur.PNG[width="500px",align="center"] + + + +Benutzeroberfläche +~~~~~~~~~~~~~~~~~~~ +Die Haupt Activity `.IodineMain` startet den "VpnService" und steuert +ihn über Broadcast Intents. In dieser Activity steuert der Benutzer den +Auf- und Abbau der Tunnel. Über ein Button in der ActionToolbar kann +eine neue Tunnelkonfiguration angelegt werden. + +Die Interaktion zwischen des Benutzers in der Anwendung ist in +<> visuell dargestellt: + +[[whiteboard-gui]] +.Graphischer Aufbau der GUI +image::bilder/whiteboard_gui.jpg[width="500px",align="center"] + +Konfiguration +~~~~~~~~~~~~~ +Die Tunnelkonfigurationen werden in einer SQLite Datenbank abgelegt. Es +existiert mit `.config.IodineConfiguration` ein leichtgewichtiger Proxy +um die Android `ContentValues` Klasse. Die `.config.ConfigDatabase` Klasse +ist ein `SQLiteOpenHelper` und kann mehrfach instanziert werden. + +VPN-Service +~~~~~~~~~~~ + +Der VPN Service hat 5 Zustände die er über Broadcast Intents mitteilt. +Eine solche Mitteilung wird verschickt wenn sich der Zustand ändert oder +dies über ACTION_CONTROL_UPDATE angefordert wurde. + +Die Kommunikation der Oberfläche mit dem VPN Service erfolgt mit Broadcasts Intents. + +<> zeigt die Zustände des Iodine VPN-Service. Rot nummeriert sind die +Intents die der Service verschickt um über Statusänderungen zu informieren. Blau nummeriert +sind Intents mit denen der Service gesteuert werden kann. + +[[whiteboard-intents]] +.Status Informations und Steuerungs Intents des VPN Service +image::bilder/whiteboard_intents.jpg[align="center",width="500px"] + +JNI +~~~ + +Die JNI Methoden für iodine befinden sich in der Klasse `.IodineClient` +bzw. `/jni/iodine-client.c`. `IodineClient#connect` ersetzt dabei prinzipiell +die `main()` des ursprünglichen iodine Client. + +Weitere Methoden dienen dem Austausch der vom Server übermittelten Konfiguration +und des im System eingestellten DNS Server. + + +Android VPN-Framework +--------------------- +Seit API Level 14/Android 4 ist es möglich VPN Verbindungen mit Android +Anwendungen aufzubauen und zu verwalten. + +Die Application benötigt dazu die Permission +`android.permission.BIND_VPN_SERVICE`. + +Bevor eine Anwendung das erste mal eine VPN Verbindung aufbauen darf +wird Android sicherheitshalber den Benutzer explizit um Erlaubnis +fragen. + +Dazu wird `IodineVpnService.prepare(this)` <> +aufgerufen. Wird null zurückgegeben hat der Benutzer VPN Verbindungen +dieser App bereits früher zugestimmt. Andernfalls wird ein Intent +zurückgegeben mit dem die Benutzernachfrage initiiert werden kann. + +[source,java] +-------------------------------------------------------------------------------------- + public void tunnel() { + Intent intent = IodineVpnService.prepare(this); + if (intent != null) { + // Ask for permission + intent.putExtra(IodineVpnService.EXTRA_CONFIGURATION_ID, configuration.getId()); + startActivityForResult(intent, INTENT_REQUEST_CODE_PREPARE); + } else { + // Permission already granted + startVPNService(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == INTENT_REQUEST_CODE_PREPARE) { + if (resultCode == RESULT_OK) { + startVPNService(); + } else { + // User denied permission + } + } + } + + private void startVPNService() { + // Start VPN with VPNService.Builder + } +-------------------------------------------------------------------------------------- + +Der weitere Weg mit dem `VPNService.Builder` ist geradelinig. Im Fall +von iodine wird zunächst der Tunnel über DNS aufgebaut bevor das +tun-Interface geöffnet wird. + +Nachdem vom Server die IP-Konfiguration mitgeteilt wurde, wird diese im +`Builder` gesetzt und der Tunnel geöffnet: + +[source,java] +-------------------------------------------------------- + // .... IodineVpnService.java :: runTunnel() + b.addAddress(hostAddress, netbits); + b.addRoute("0.0.0.0", 0); // Default Route + b.setMtu(mtu); + + // Opens tun device + ParcelFileDescriptor parcelFD = b.establish(); + + // prevent dns traffic to get through its own tunnel + protect(IodineClient.getDnsFd()); + + // get the filedescriptor + int tun_fd = parcelFD.detachFd(); + + // pass the filedescriptor to iodine + IodineClient.tunnel(tun_fd); +-------------------------------------------------------- + +iodine +------ + +Verbindungsaufbau (Handshake) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Der folgende Text zeigt ein Beispiel für den Ablauf eines Handshake. Der genaue Ablauf kann +variieren jenachdem wie die Verbindungsparameter gewählt werden. + +Hier sind gewählt -m 768 fragment size und ein 9 Zeichen +Passwort. Die Gegenstelle ist `t.yves.tw`. Eine Raw (direkte UDP) Verbindung +wurde verhindert indem der Rechner zum Testzeitpunkt keine default Route hatte. + +RX/TX aus der Sicht des Servers. Die "*" in den Hostnamen markieren Zeichen die +sich aus Random Daten ergeben. + +[source,java] +--------------------------------------------------------------------- + == Der Client testet die Qualitaet der Uebertragung + <-- client.c:handshake_qtype_autodetect() + -> handshake_qtypetest() + -> send_downenctest() + hostname[0] = "y" + hostanme[1] = downenc = 'r' + hostname[2] = variant = 1 = 'b' (b32) + hostname[3..5] = rand_seed++ + RX: yrb***.t.yves.tw + + --> 48 bytes aus encoding.h:DOWNCODECHECK + TX: yrb***.t.yves.tw, 48 bytes data + + == Austausch der Versionsinformationen + <-- client.c:send_version() + VERSION=0x00 00 05 02 + hostname[0] = cmd = 'v' + hostname[1..6] = b32(0,0,5,2,random<<8,random) + hostname = "vAAAAKAR__" + RX: vaaaaka****.t.yves.tw + + --> iodined.c:send_version_response() + der Server bestaetigt mit + data[0..8] = "VACK" b32(seed>>24, seed>>16, seed>>8, seed, userid) + TX: vaaaaka***.t.yves.tw, 9 bytes data + + + == Senden von Passwort und IP-Konfiguration (Subnetz) + <-- client.c:send_login() + cmd = 'l' + hostname[1..16] = login/password mit seed xored und md5 + hostname[17..18] = seed + RX: lad24srn4ezmg21qjsfy13msagd0srfq.t.yves.tw + + --> iodined.c:handle_null_request() + Sendet bei Erfolg die IP Einstellungen wie + "172.16.0.1-172.16.0.2-1130-16" + server="172.16.0.1" + client="172.16.0.2" + mtu=1130 + netbits=16 + TX: lad24srn4ezmg21qjsfy13msagd0srfq.t.yves.tw + = 3137322e31362e302e312d3137322e31362e302e322d313133302d3136 (_16) + = 172.16.0.1-172.16.0.2-1130-16 + + == Senden der IP Adresse des Clients + <-- Request for IP address + RX: iamin.t.yves.tw + + --> iodined.c:handle_null_request() + addr = externe IP Adresse des Server (-n Switch) + reply[0] = 'I'; + reply[1] = (addr >> 24) & 0xFF; + reply[2] = (addr >> 16) & 0xFF; + reply[3] = (addr >> 8) & 0xFF; + reply[4] = (addr >> 0) & 0xFF; + TX: iamin.t.yves.tw + = 494e2f737d (_16) + + == Testen auf EDNS Erweiterung + <-- client.c:handshake_edns0_check() + -> send_downenctest() + downenc = 'r' fuer T_NULL 't' + variant = 1 = 'b' (b32) + data[0..5] = "y" downenc variant rand_seed[0..2] + RX: yrb***.t.yves.tw + + --> iodined.c:handle_null_login() : 937 + -> write_dns( type='R') + Der Server antwortet mit 48 bytes aus encoding.h:DOWNCODECHECK + TX: yrb***.t.yves.tw, 48 bytes data + + + == Testen der Kodierungen mit verschiedenen Patterns + <-- client.c:handshake_upenc_autodetect() + In den folgenden Tests testet der Client ob mit Base128 + kodierte Nachrichten vom DNS Relay korrekt verarbeitet werden. + + --> Der Server schickt die Patterns einfach wieder zurueck. + + == Client legt Kodierung fest, Server bestaetigt + <-- client.c:handshake_switch_codec() + hostname[0] = command 's' + hostname[1] = b32(userid) + hostname[2] = 'h' (7) + hostname[3..5] = rand_seed++ + rand_seed++; + RX: sahmiut.yves.tw + + --> iodined.c:840 + Schreibt den Namen des ausgewaehlten Codecs: + data="Base128" (kein encoding!) + TX: sahmiut.yves.tw, 7 bytes of data + + == Anschalten lazy mode (an: Server beantwortet Anfragen nicht sofort) + <-- client.c:send_lazy_switch() + hostname[0] = 'o' + hostname[1] = b32(userid) = 'a' + hostname[2] = 'l' fuer lazy mode oder 'i' + hostname[3..5] = rand_seed++ + RX: oalmiv.t.yves.tw + + --> iodined.c:919 + data="Lazy" (kein encoding!) + TX: oalmiv.t.yves.tw, 4 bytes of data + + == + <-- client.c:send_set_downstream_fragsize() + data[0] = userid; + data[1] = (fragsize & 0xff00) >> 8; + data[2] = (fragsize & 0x00ff); + data[3] = (rand_seed >> 8) & 0xff; + data[4] = (rand_seed >> 0) & 0xff; + hostname = 'n' + b32(data) + RX: naabqbmiw.t.yves.tw + + --> iodined.c:1042 + bestaetigt empfangene Framesize durch Wiederholung + + == Regelmaesige pings fragen den Server nach anstehenden Daten ab + <-- client.c:send_ping() + data[0] = userid; + data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15); + data[2] = (rand_seed >> 8) & 0xff; + data[3] = (rand_seed >> 0) & 0xff; + hostname = 'p' + b32(data) + RX: paaalcfy.t.yves.tw + + --> iodined.c:1067 + Der Server nutzt die regelmaessigen Pings um Daten an den Client zu liefern. +--------------------------------------------------------------------- + +Der lazy Modus +^^^^^^^^^^^^^^ + +Wie in der Anwenderdokumentation beschrieben erhöht der Lazy Modus den Durchsatz +und senkt die Latenzzeit, wird aber nicht von allen DNS-Relays unterstützt. + +Lazy bezieht sich auf das Verhalten des Servers. Der Server wird im Lazy-mode +alle Antworten auf Anfragen solange zurückhalten bis er neue Daten für den +Client erhalten hat. Im Idealfall also bis das Antwortpaket der getunnelten +IP Verbindung angekommen ist. + +Diese Verzögerung kann mit manchen DNS-Relays Probleme machen. Der Server kann dies jedoch +anhand der Duplikate in den Anfragen erkennen und damit den lazy-mode ausschalten. + +Ohne diesen Mechanismus müsste der Client jedoch viel häufiger nach neuen Daten +pollen (vgl. HTTP Long polling in Comet oder BOSH). + + +iodine base(32) Kodierung +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Dieses Programm bietet die Base32 Kodierung von iodine für die +Kommandozeile zum Debuggen an. + +[code,c] +---------------------------------------------------------------------------------------------------- +#include +#include + +#include "src/base32.h" +#include "src/encoding.h" + +int main(int argc, char *argv[]) { + struct encoder *b32 = get_base32_encoder(); + char buf[512]; + size_t len = 512; + + if (argc != 3) return 0; + if (*argv[1] == 'd') { + int r = b32->decode(buf, &len, argv[2], strlen(argv[2])); + int i; + printf("Decoded %d bytes:\n", r); + for (i = 0; i< r; i++) { + printf("0x%02hhx (%c) ", buf[i], (buf[i] >= '0' && buf[i] <= 'z') ? buf[i] : ' '); + } + printf("\n"); + } else if (*argv[1] == 'e') { + int r = b32->encode(buf, &len, argv[2], strlen(argv[2])); + printf("Encoded %d bytes in %ld output bytes: >%s<\n", len, r, buf); + } + return 0; +} +---------------------------------------------------------------------------------------------------- + +--------------------------------------- +# gcc test.c src/base32.c -o test +# ./test e abcdefg +Encoded 7 12 bytes: >mfrggzdfmztq< +--------------------------------------- + +Änderungen an iodine +~~~~~~~~~~~~~~~~~~~~ + +Der Code basiert auf der letzten Iodine Version 0.6.0-rc1. Die +Änderungen wurden absichtlich möglichst gering gehalten und betragen +im wesentlichsten nur ca. 80 Zeilen. + +Ein Hauptteil der Änderungen verhindern, dass Android als Linux erkannt wird. +Im Gegensatz zu vielen Linux Installationen verwenden Android nicht die GNU libc +sondern 'Bionic libc'. Dies ist eine besonders kleine, auf die BSD libc zurückgehende +standard C Library. Es fehlen einige Features der glibc wie wide-character support, +volle POSIX Thread Unterstützung oder locale Unterstützung. Das Ziel von Bionic ist +nicht eine vollständige C Standardbibliothek sondern lediglich eine schlanke Implementierung +aller für ein Android nötigen Funktionen. + +Im einfachsten Fall scheitert die Ausführung von iodine unter Android an einem `system()` Aufruf +mit dem iodine die IP-Konfiguration anwendet. + +Android.mk +^^^^^^^^^^ + +Das ursprüngliche iodine Makefile wird nicht verwendet. Es wird das +Android NDK Buildsystem verwendet, die Anweisungen dazu liegen in +`jni/Android.mk`. Aus dem Projektverzeichnis kann die Übersetzung der +C-Quellen angestossen werden. + +[code,c++] +---------------------------------------------------------------------------------------------------- +org.xapek.andiodine % ~/$NDK_ROOT/ndk-build clean +Clean: iodine-client [armeabi] +Clean: stdc++ [armeabi] +org.xapek.andiodine % ~/$NDK_ROOT/ndk-build +Compile thumb : iodine-client <= iodine-client.c +Compile thumb : iodine-client <= tun.c +Compile thumb : iodine-client <= dns.c +Compile thumb : iodine-client <= read.c +Compile thumb : iodine-client <= encoding.c +Compile thumb : iodine-client <= login.c +Compile thumb : iodine-client <= base32.c +Compile thumb : iodine-client <= base64.c +Compile thumb : iodine-client <= base64u.c +Compile thumb : iodine-client <= base128.c +Compile thumb : iodine-client <= md5.c +Compile thumb : iodine-client <= common.c +Compile thumb : iodine-client <= client.c +Compile thumb : iodine-client <= util.c +SharedLibrary : libiodine-client.so +Install : libiodine-client.so => libs/armeabi/libiodine-client.so +---------------------------------------------------------------------------------------------------- + + +Die Library wird vom Android SDK automatisch in die APK-Datei eingefügt. + +common.c daemon() +^^^^^^^^^^^^^^^^^ + +Die `daemon()` Funktion in src/common.c ist gedacht um iodine als +Hintergrundprozess laufen zu lassen. Sie ist nur für Linux und BSD +vorgesehen. + +Das `#ifdef` erkennt Android als Linux, Bionic unterstützt `daemon()` +jedoch nicht, da die Funktionalität der `daemon()` Funktion für eine +Android App nicht benötigt wird. + +Auch in diesem Fall brauchen wir die `daemon()` Funktion nicht, da iodine +in einem von Java gesteuerten Thread laufen wird. + +common.c warn() +^^^^^^^^^^^^^^^ + +Die `warn()` Funktion existiert nicht in der Bionic libc. Die +bereitgestellte Implementierung verwendet `fprintf` auf stderr. Die +Meldungen werden in das Android Logging System umgeleitet und sind auch +über Logcat nutzbar. + +tun.c write_tun() / read_tun() +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Wie bei FreeBSD und Windows muss beim schreiben auf das Tun device +(`write_tun` ) kein 4 byte großer Header mit der Adress Family angefügt werden. +Entsprechend wird dieser in `read_tun()` im Fall von Android, FreeBSD +und Windows nicht entfernt. + +tun.c tun_setip() +^^^^^^^^^^^^^^^^^ + +Je nach Plattform werden wird die IP-Adresse unterschiedlich gesetzt. Im +Fall von Linux geschieht dies mit einem fragwürdigen +`system("/sbin/ifconfig")` Aufruf. + +Dies ist unter Android so nicht möglich. Es wurde daher eine globale +Datenstruktur `tun_config_android` (tun.h) angelegt in welcher die zu +setzende IP-Adresse, Gegenstelle IP-Adresse und Netzmaske abgelegt wird. +Die Inhalte dieser Datenstruktur können von Java über JNI Funktionen +abgefragt werden. + +Das setzen der IP-Adressen und Routen geschieht über Methoden des +Android VPN-Framework in Java. + +DNS Headerfiles +^^^^^^^^^^^^^^^ + +Iodine benötigt Konstanten aus arpa/nameser_compat.h und arpa/nameser.h +das nicht Teil der Android Libc ist. Die Header wurden als +src/dns_android.h hinzugefügt. + +Projekt öffnen und bauen +------------------------ + +C Quellcodes übersetzen +~~~~~~~~~~~~~~~~~~~~~~~ + +Um das Projekt zu bauen ist neben dem Android SDK auch das Android NDK erforderlich. Mit dem daraus +bereitgestellten Kommando `ndk-build` werden die C-Quellcodes unterhalb des Verzeichnisses `jni/` +übersetzt. + +[verbatim] +---------------------------------------------------------------------------------------------------- +andiodine$ $NDK_ROOT/ndk-build clean +Clean: iodine-client [armeabi] +Clean: stdc++ [armeabi] +Clean: iodine-client [x86] +Clean: stdc++ [x86] + +andiodine$ $NDK_ROOT/ndk-build +Compile thumb : iodine-client <= iodine-client.c +..... +SharedLibrary : libiodine-client.so +Install : libiodine-client.so => libs/armeabi/libiodine-client.so +Compile x86 : iodine-client <= iodine-client.c +..... +SharedLibrary : libiodine-client.so +Install : libiodine-client.so => libs/x86/libiodine-client.so +---------------------------------------------------------------------------------------------------- + +Entwickeln mit Eclipse +~~~~~~~~~~~~~~~~~~~~~~ + +Das Projekt kann über den Importassistenten eingebunden werden: + +Import -> Android -> Existing Android Code Into Workspace + + +Entwickeln mit Android Studio +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Choose Import Project, choose project Folder. + +* Select "Create project from existing sources". + + +Übersetzen mit ant +~~~~~~~~~~~~~~~~~~ +Using ant + +[verbatim] +---------------------------------------------------------------------------------------------------- + android project --path . + ant debug +---------------------------------------------------------------------------------------------------- + +Die APK liegt unterhalb von `bin` und kann mit dem ant target `install` über adb installiert werden. + +[bibliography] +Anhang +------ + +[bibliography] +- [[[vpnapi]]] + http://developer.android.com/reference/android/net/VpnService.html Dokumentation + zu den Android VPN Service API + diff --git a/doc/vorstellung.odp b/doc/vorstellung.odp new file mode 100644 index 0000000..4a62f57 Binary files /dev/null and b/doc/vorstellung.odp differ diff --git a/doc/vorstellung.pdf b/doc/vorstellung.pdf new file mode 100644 index 0000000..129224c Binary files /dev/null and b/doc/vorstellung.pdf differ -- cgit v1.2.1