Static Console Binaries für Android mit GO

Diesmal mache ich es richtig!

Wie man an den letzten Beiträgen wohl mitbekommen hat, beschäftige ich mich immer mal wieder damit, mit Go Dinge™ für Android zu kompilieren.
Dabei zielen die von Google und der Community bereitgestellten Tools hauptsächlich darauf ab, Apps zu schreiben.

Mein Interesse ist es dabei eher, das darunter liegende Linux für mich nutzbar zu machen. Detailierter habe ich mich dazu schon im letzten Beitrag ausgelassen, weshalb ich das hier jetzt auch nicht unnötig in die Länge ziehen will.

War es mir bis jetzt nicht möglich, wirklich statische Binaries zu bauen, so lag die Lösung des Problems mit dem Position Independend Code (siehe auch dazu den letzten Beitrag) näher, als ich dachte.

Entgegen dem nativen Fall scheint der Go Compiler beim erstellen der Binaries für Android immer den externen Linker auf zu rufen.
Diesen Sachverhalt kann man sich zu Nutze machen, wenn man es schafft, die nötigen Flags für den Linker durch zu reichen.

Ich hebe das deshalb so hervor, weil es echt ein Krampf ist, die passenden Flags zu finden und dann auch noch so zu escapen, dass die eigentlichen Linker Flags dort auch ankommen.

Im Netz findet man relativ wenig dazu und die Hilfe der Go Tools – sagen wir mal … sie könnte besser sein.

Hier gehts los:

Für Ungeduldige, die vielleicht gerade auf der 2 Seite der Suche angekommen sind und schon etwas genervt sind, versuche ich es so kurz wie möglich zu halten.

Benötigt wird für das folgende Skript nur ein lokaler gcc und wget.
Der gcc wird benötigt, um die Go Tools um einige Tools für Android zu erweitern, wget nutze ich (Überraschung) um Sachen umkompliziert aus dem Netz zu ziehen.
Diesmal zerhacke ich die Befehle absichtlich nicht in lauter kleine Brocken, die keiner mehr copypasten will. Dafür gibts aber auch keine weiteren Erklärungen. Alles nötige sollte in den Kommentaren stehen.
Der komplette Blob kann so wie er ist in die Shell geworfen werden, alle weiter nötigen Tools werden direkt aus dem Netz bezogen.
Kein sudo erforderlich!

# we need Go1.4 to bootstrap GO1.5 for Android
wget https://storage.googleapis.com/golang/go1.4.3.linux-amd64.tar.gz
wget https://storage.googleapis.com/golang/go1.5.1.linux-amd64.tar.gz

# unpack
tar xvzf go1.4.3.linux-amd64.tar.gz
# bootstrap process will search for $HOME/go1.4
mv go go1.4
tar xvzf go1.5.1.linux-amd64.tar.gz

# get & unpack native development kit for Android
wget http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin
chmod 744 android-ndk-r10e-linux-x86_64.bin 
./android-ndk-r10e-linux-x86_64.bin 

#build toolchain
android-ndk-r10e/build/tools/make-standalone-toolchain.sh \
--arch=arm --platform=android-21 --install-dir=toolchain
#export Android gcc
export CC_FOR_TARGET=$HOME/toolchain/arm-linux-androideabi/bin/gcc

#prepare Go1.5 to build Android compatible binaries
cd go/src/
GOOS=android GOARCH=arm GOARM=7 ./make.bash

# burp a hello world to disk
cd
cat > hello.go << EOF
package main

import "fmt"

func main() {
    fmt.Println("Hello, 世界")
}
EOF

#include go1.5 bin path to searchpath
export PATH=$PATH:$HOME/go/bin
#magic
GOOS=android GOARCH=arm GOARM=7 go build \
-ldflags '-extldflags "-Wl,-pie"' hello.go

Das Skript konnte ich ohne Modifikation in eine
docker run -it ubuntu bash -l
Shell werfen (nachdem ich dort wget und gcc installiert hatte).
Es sollte also keine Probleme geben.

Achso: Der Schnipsel ist offensichtlich (wie immer) für irgendein Linux/x64.
Für MAC oder auch Linux/i386 muss offensichtlich ein bisschen was angepasst werden.

Console Binaries für Android mit GO

wie man mit ein bisschen gefrickel®

Go Binaries auf Android zum laufen bekommt

Dieser Artikel ist eigentlich ein Beiwerk, dass in den Vorbereitungen zu meinem letzten Artikel entstanden ist.

Wenn man sich so viel Mühe macht, tools zu bauen, damit man Apps in Go schreiben kann, ist man doch schnell versucht, mal gar keine App zu schreiben, sondern einfach eine standalone Binary.

1. Motivation

Die Motivation dazu ist relativ einfach zu geben. Wenn man neben den ganzen schicken Apps, mit denen man so täglich umgeht, sich auch noch etwas für Android selbst interessiert, dann wird man früher oder später schon mal ein Terminal aufgemacht haben, denn Android ist auch nur ein Linux.
Dieses Linux macht aber nicht gerade Spaß.

Neben dem Ärgernis, zumindest ohne Bluetooth Keyboard mit dieser (auf Smartphones viel zu kleinen) Tastatur arbeiten zu müssen, fehlen einfach zu viele Befehle.
Das Problem mit der Tastatur lässt sich recht schnell mit dem Hackers Keyboard beseitigen. Diese Tastatur hat, wenn man in den Landscape Modus wechselt, alle Tasten die man für ein Terminal benötigt. Es ist immer wieder ein Vergnügen einen Ping einfach mit einem CTRL+C abzubrechen, statt irgendwelche Verrenkungen mit Power und Lautstärke als Workaround zu machen.

Den Mangel an Linux Standardbefehlen kann man mit der BusyBox zwar angehen, aber auch mit ihr fehlt einfach noch zu viel.
Nun könnte man meinen, nachdem wir uns im letzten Artikel die Native Toolchain zusammen gebaut haben, wäre die doch Ideal, um die vermissten Tools einfach selbst zu bauen. Das Führt aber sehr schnell zu Frust.
Android ist eben kein Desktoplinux und so muss man schon für eine simple Bash (wenn man sie denn nicht dank Cyanogenmod schon hat) eine Menge Abhängigkeiten erfüllen. Ehe man sich versieht, hat man quasi eine Minimalinstalltion einer Linuxdistribution neben sein Adroid gebaut.
Das ist allerdings ziemlich unsinnig, weil es dafür diverse Apps gibt, die tatsächlich genau das leisten.

An dieser Stelle wird Go interessant. Was mit C, oder C++ ziemlich nervtötend ist, ist mit Go schnell gemacht. Es bietet sich also an, sich auf die kleinen Probleme zu fokussieren, für die gerade mal wieder die entsprechenden Befehle in der Shell fehlen, bzw. die in der Busybox einfach nicht alle Funktionen haben, die man gerne hätte.

2. An die Arbeit

Wer jetzt vielleicht ein Android in der Hand hat, welches vom Dritthersteller noch keine der neueren Versionen von Android 5 (Lollipop) bekommen hat, kann sich Ausnahmsweise vielleicht freuen: Die Go Version 1.5, die ich im letzten HowTo gebaut habe, erstellt Binaries, welche sich auf älteren Android versionen noch ohne Probleme im Terminal verwenden lassen.

Dazu sei noch einmal gesagt, dass man zum ausführen beliebiger Binaries auf Android immer ein Root Rechte braucht. Die meisten Pfade des Systems sind explizit mit noexec gemountet, Dateien die man ohne Root Rechte irgendwo ablegen kann, sind per se nicht ausführbar.

Deshalb lege ich Dateien für solche Spielereien am System gerne unter /data ab. Dort kann man als Root ohne weiteres schreiben, da es im gegensatz zu /system nicht als readonly eingehängt wird.

Vorrausgesetzt die Umgebungsvariablen sind noch passend gesetzt, können wir ein simples Hello World schnell bauen:

GOOS=android GOARCH=arm GOARM=7 go build hello.go

Die resultierende hello Binary ist auf einem Weg deiner Wahl auf das Android Gerät zu übertragen. Dort sollte sie in einem eigens dafür angelegten Verzeichnis unter /data liegen und natürlich mit chmod ausführbar gemacht werden.

Wer jetzt auf seinem Gerät die Binary in einem Terminal ausführen kann, hat Glück gehabt und ist bereit beliebigen anderen Code zu verwenden.

Mit einer aktuellen Version von Android sieht man leider nur noch:

error: only position independent executables (PIE) are supported.

Dabei handelt es sich um ein Sicherheitsfeature, welches in den letzten Versionen ohne großes Aufsehen Einzug erhalten hat. Solcherart Binaries können vom System beim Laden auf beliebige, nicht vorhersagbare Adressen gelegt werden.
Das hat den Vorteil, dass Attacken, die über einen Pufferüberlauf realisiert werden sollen quasi unmöglich werden, weil hinter dem überschriebenen Puffer bei jeder Ausführung anderer Code liegt.

Für meine Go Spielereien ist das aber schlecht. Derzeit gibt es keine Möglichkeit, PIE Binaries mit den Go tools zu bauen.

Dafür kann man aber mit Go eine Shared Library bauen, welche man aus einem winzigen C Programm einbindet. Für Shared Librarys gilt die PIE Einschränkung nämlich nicht, weil sie per Definition positionsunabhängig geladen werden.

Die Recherche dazu war nicht gerade einfach bzw. kurz, weshalb ich sie an dieser Steller gerne Teilen möchte.
Beim generellen Ablauf habe ich mich deutlich von diesem Tutorial inspirieren lassen.

Als Erstes brauchen wir eine leicht modifizierte hello.go.

package main

import "fmt"
import "C"

//export hello
func hello() {
    fmt.Printf("hello, world\n")
}

//empty stub to satisfy buildmode
func main() {}

Diese lässt sich mit einer etwa umständlichen Zeile als Shared Library bauen.

GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 \
go build -buildmode=c-shared -o libhello.so hello.go

Der buildmode shared, welcher hier eigentlich angebracht wäre, steht für Android leider nicht zur Verfügung. Infolgedessen benötigen wir eine leere main Methode.

Der Aufruf baut uns nicht nur die libhello.so, sondern erstellt auch eine passende libhello.h Header File.

Der C Code um die Library aufzurufen:

#include <stdio.h>
#include "libhello.h"

int main(void)
{
    puts("This is a shared library test...");
    hello();
    return 0;
}

So viel C dürfte gerade noch ohne Schmerzen und schlimme Fehler zu schreiben sein.

Mit der Native Toolchain, die wir zum Bauen von Android benötigt haben, ist auch das schnell gebaut:

$CC_FOR_TARGET -L. -Wl,-pie -Wall -o hello wrap.c -lhello

Jetzt haben wir eine hello Binary und eine libhello.so Shared Library. Beide kopieren wir wieder irgendwohin unter /data.

Wenn wir den Compiler mit -Wl,-rpath aufgerufen hätten und Android damit irgendwas anfangen könnte, wäre der Aufruf im Terminal auf Android jetzt fast schon trivial. Leider ist dem nicht so.

Wir müssen den Ladepfad des Libraries per Hand angeben, da Android rpath ignoriert.

root@deb:/data/exo # export LD_LIBRARY_PATH=/data/exo
root@deb:/data/exo # ./hello
WARNING: linker: libhello.so has text relocations. This is wasting memory and prevents security hardening. Please fix.
This is a shared library test...
hello, world

Naja immerhin – es geht.

Auch wenn Android von der internen Struktur der Library nicht sonderlich begeistert ist. Vermutlich steht diese Meldung aber auch irgendwo in den Logs, wenn man derzeit eine mit Go gebaute Native App ausführt. Die kommen auch als Shared Library daher.
Daraus kann man wohl schließen, dass es noch sehr lange dauern wird, bis jemand sich dafür interessiert, _echte _PIE Binaries mit Go für Android zu bauen.

Angetestet: Android Apps mit Go

Ein ausführliches How-To

Die nötigen Schritte, um Example Apps aus dem mobile Projekt auf GitHub zu bauen:
  1. Vorwort
  2. Go 1.4.x besorgen, oder haben
  3. Android NDK besorgen
  4. Standalone Toolchain aus dem NDK bauen
  5. Go 1.5 bauen (keine Binaries verfügbar)
  6. das mobile Projekt initialisieren
  7. eine Example Anwendung kompilieren
  8. die Anwendung auf ein kompatibles Gerät deployen
  9. vielleicht selbst etwas entwickeln?

1. Vorwort

Dieser Artikel ist für Windows Nutzer höchstens von informativem Gehalt. Die nötigen Tools des mobile Projekts funktionieren derzeit nicht auf Windows. Ob eine Portierung geplant ist, ist ungewiss.
Meines Wissens nach müsste das Setup in ähnlicher Form auf Apple Geräten durchzuführen sein, ich habe aber keine Solchen und kann daher auch keine Aussagen über eventuell auftretende Abweichungen treffen.
Ganz allgemein richtet sich dieses How-To an Fortgeschrittene User. Es sollte zwar auch möglich sein, nur die Kommandos zu kopieren, dabei wird aber vermutlich der gewünschte Wissenszuwachs ausbleiben.

Die Entwicklung für linux/arm Plattformen ist zwar auch schon mit Go 1.4.x möglich, das erzeugt aber “nur” Binaries, wie man sie z.B für den Raspberry PI und andere ARM basierte Plattformen verwenden kann. Android hat eine Linux Kernel, aber der Überbau weicht stark von den üblichen Linux Geschmacksrichtungen ab. Um eine kompilierte Binary auf einem (nicht gerooteten) Android verwenden zu können, muss diese in eine .apk Datei verpackt werden und sich über die gewöhnliche Installation aus Drittquellen, also nicht über den Play Store, aufs Gerät gebracht werden.
Die Zielplattform android/arm ist aber erst ab dem noch in der Entwicklung befindlichen (Stand Juni 2015) Android 1.5 verfügbar. Bis jetzt gibt es für Go 1.5 keine offiziellen Binaries, oder Pakete, daher muss man sich eine passende Umgebung erst selbst bauen.
Eine überraschende Neuerung an dieser Go Version ist es, dass man jetzt ein Go der Version 1.4.x benötigt, um Go 1.5 und vermutlich auch die folgenden Versionen selbst zu bauen.

2. Go 1.4.x besorgen

Wer Go 1.4.x hat braucht hier nichts zu tun. Wichtig ist nur, dass die Go Kommandos auch wirklich im Suchpfad sind.
Ubuntu 14.4 bringt z.B. nur Go in der Version 1.2 mit sich, falls man also ein aktuelles braucht, bekommt man das am besten direkt von der Downloadseite.

Ich habe die Version go1.4.2.linux-amd64.tar.gz genommen. Diese ist schnell als root zu installieren:

sudo tar -C /usr/local -xzf go1.4.2.linux-amd64.tar.gz

Danach befinden sich die Kommandos unter /usr/local/go/bin. Dieses Verzeichnis liegt höchstwahrscheinlich nicht im Suchpfad daher empfiehlt es sich, das Verzeichnis mit auf zu nehmen.

export PATH=$PATH:/usr/local/go/bin

Das gilt allerdings nur für die betroffene Shell. Zu beachten ist auch, dass diese Zeile, die schändlich aus der Dokumentation übernommen wurde, das Verzeichnis am Ende des Suchpfades anfügt. Wer also schon über seine Distribution Go installiert hatte, wird weiterhin die alte Version aufrufen. Dies ist ein gern gemachter Fehler.
Es ist eine Überlegung wert, ob man sich das Verzeichnis immer in den Suchpfad schreiben will. Benutzt man sehr viele von Extern installierte Tools, sollte man darüber nachdenken, ob man die wirklich alle ständig im Suchpfad mit sich rumschleppen will. Lautet die Antwort für Go trotzdem “Ja”, ist auch das schnell erledigt.

echo 'PATH=$PATH:/usr/local/go/bin' >> $HOME/.profile

Damit diese Zuweisung aus der .profile übernommen wird, muss man sich einmal abmelden und wieder anmelden.

3. Android NDK besorgen

Beim Bauen von Go 1.5 werden einige Bibliotheken und Tools für die Zielplattform gebaut. Wir brauchen also einen Compiler, der das auch kann. Ich rate an dieser stelle davon ab, einen anderen ARM Crosscompiler zu verwenden, als das Native Development Kit für Android bereitstellt. Diese sind möglicherweise mit ungünstigen Default Einstellungen kompiliert worden und könnten unnötige Probleme verursachen.
Nachdem Go für die Zielplattform gebaut wurde, kann man das NDK wieder entfernen, da das gomobile Kommando sich später selbst automatisch passende Compiler besorgt.
Das NDK bezieht man direkt von der Developer Seite von Android in meinem Fall war es die Version android-ndk-r10e-linux-x86_64.bin.

An der Endung erkennt man schon, dass es sich hier unnötigerweise nicht um ein reines Archiv handelt, sondern um ein selbst entpackendes Binary. Für die Basteleien mit dem NDK sollte ein eigenes Verzeichnis im $HOME Verzeichnis angelegt werden. Die .bin Datei muss für die weiteren Schritte dort abgelegt werden. Ich nenne das Verzeichnis der Einfachheit halber mal NDK. Das Anlegen des Verzeichnisses und ablegen des Downloads gebe ich jetzt nicht extra an.

cd $HOME/NDK
chmod a+x android-ndk-r10e-linux-x86_64.bin
./android-ndk-r10e-linux-x86_64.bin

Wer nicht die Version r10e genommen hat, muss natürlich Passendes ersetzen.

4. Standalone Toolchain aus dem NDK bauen

Damit ist es aber noch nicht getan. Das NDK kann für verschiedene Zwecke eingesetzt werden und der Native Compiler wird im Normalfall nicht direkt aufgerufen, sondern über diverse Skripte und Tools. Wer wie wir nur den gcc braucht, muss sich eine Standalone Toolchain bauen. Direkte Aufrufe des gcc schlagen sonst fehl, da er einige Bibliotheken nicht finden wird.

Praktischerweise kann man sich die nötige Toolchain mit einem Einzeiler vorbereiten lassen.

android-ndk-r10e/build/tools/make-standalone-toolchain.sh \
--platform=android-21 --arch=arm --install-dir=toolchain

Ja, das ist ein Einzeiler.

Jetzt sollte die Toolchain unter $HOME/NDK/toolchain einsatzbereit sein.

5. Go 1.5 bauen

Jetzt haben wir schon fast alle Vorraussetzungen zusammen um Go 1.5 zu bauen. Ich schreibe fast, weil ich der Vollständigkeit halber nicht unerwähnt lassen will, dass wir natürlich eine Buildumgebung für C(++) brauchen. Der Befehl go get wird später git benötigen, also hier noch eben die Abhängigkeiten exemplarisch für Debian.

sudo apt-get install build-essential
sudo apt-get install git

Kommen wir nun endlich zu Go. Um uns ein paar Umgebungsvariablen zu ersparen, wechseln wir zurück ins $HOME Verzeichnis und legen dort den symbolischen Link go1.4 an, der auf das bin Verzeichnis unserer Go 1.4.2 Installation zeigt. Wenn nichts Anderes definiert ist, erwartet der Buildprozess Go 1.4.x unter $HOME/go1.4.
Danach besorgen wir uns den Quellcode für Go 1.5 über git.

ln -s /usr/local/go/ $HOME/go1.4
git clone https://go.googlesource.com/go $HOME/gosrc

Wer möchte, darf sich den Quellcode natürlich in ein anderes Verzeichnis Klonen, hat dann aber im Folgenden kein so einfaches Copy & Paste mehr.

Es folgen die magischen Zeilen um ein Go für die Zielplattform android/arm zu bauenen

export CC_FOR_TARGET=$HOME/NDK/toolchain/arm-linux-androideabi\
/bin/gcc
cd $HOME/gosrc/src/
GOOS=android GOARCH=arm GOARM=7 ./make.bash

Vorsicht mit diesem Block! Wordpress bricht mir die erste Zeile ungünstig um, daher musste ich die erste Zeile verunstalten.

Es fliegen ein paar Fehler der Form

warning: unable to find runtime/cgo.a.

Das ist ein bekanntes Problem am aktuellen Stand und ist in unserem Fall nicht schlimm. Auf keinen Fall sollte dieses Verzeichnis aber verwendet werden, um Go1.5 für eine andere Plattform zu bauen, Go kann nicht fehlerfrei für verschiedene Ziele initialisiert werden.

Ebenso kann diese Installation von go1.5 derzeit nicht genutzt werden um einzelne lauffähige Programme zu erzeugen, die man auf einem Android Gerät mit root Access in der Shell verwenden könnte. Seit Android 5.0.1 haben die Programme dazu nicht mehr das nötige Format, weil der linker zwingend Position Independend Executables erfordert.

error: only position independent executables (PIE) are supported.

Man kann sich aber damit Shared Libraries bauen, gegen die man dann mit dem gcc aus einer PIE Binary linken kann. Dazu später mehr.

6. Das mobile Projekt initialisieren

Ab jetzt machen wir mit dem frisch gebauten Go weiter, also nehmen wir das neue Go in den Suchpfad auf, legen uns ein Unterverzeichnis für unsere Tests an und initialisieren gomobile. Das müssen wir dann auch noch in den Suchpfad aufnehmen. Für go get muss vorher noch die Variable GOPATH auf das aktuelle Verzeichnis gesetzt werden.

export PATH=$HOME/gosrc/bin:$PATH
mkdir $HOME/mobile
cd $HOME/mobile
export GOPATH=$PWD
go get golang.org/x/mobile/cmd/gomobile
export PATH=$PWD/bin:$PATH
gomobile init

7. Eine Example Anwendung kompilieren

(äh, naja zwei)

Die Beispielanwendungen können jetzt sehr einfach gebaut werden. Ich habe die Basic und die Sprite App gebaut

go get -d golang.org/x/mobile/example/basic
gomobile build golang.org/x/mobile/example/basic

go get -d golang.org/x/mobile/example/sprite
gomobile build golang.org/x/mobile/example/sprite

Das war’s schon. Für beide Beispiele liegt jetzt unter $HOME/mobile ein APK bereit.

8. Die Anwendung auf ein kompatibles Gerät deployen

Hier führen wirklich viele Wege nach Rom. Wer den ADB benutzt, kann das natürlich damit machen und braucht vermutlich keine genauere Anleitung.
Auch sehr bequem ist es, die Dateien einfach vom Computer per Bluetooth an das Gerät zu schicken. Wem gar nichts anderes einfällt, wie er die APKs so im Heimnetz, oder auch im Internet hinterlegen kann, dass er sie mit seinem Mobilgerät beziehen kann, dem empfehle ich einfach mal Google Drive zu benutzen. Das sollte ohne zusätzliche Software mit jedem Android Gerät trivial sein.
Sind die APKs einmal auf dem Gerät, können sie dort durch Antippen zur Installation gebracht werden. Hierfür muss, zumindest zeitweise, die Installation aus unbekannten Quellen im Menüpunkt Sicherheit in den Einstellungen des Gerätes aktiviert werden.
Für Diejenigen, die nur aus Interesse gelesen haben, aber sich die Arbeit nicht selbst machen wollen, habe ich die beiden APKs auch zum Download:

basic.apk 1ea3fbcca983a58dee0032a11f3d38d106a476c31efc1c99a0de511711ca8110

sprite.apk 99f2f86de61b64cee61bdc4882ee386276d7e9dc8f93a9b3bc90b5c9a85670a2

Es schadet sicher nicht, vorher die sha256 Summen zu überprüfen.

9. Vielleicht selbst etwas entwickeln?

Diese triviale Übung überlasse ich natürlich dem Leser für zu Hause. Wer allerdings wirklich neugierig geworden ist, kann (wenn er das How-To durchgearbeitet hat) unter $HOME/mobile/src/golang.org/x/mobile/example die Quellen durchsehen. Dabei merkt man schnell, dass zumindest einfache Anwendungen mit den kommenden Tools für Go schnell gemacht sind.
Besonders interessant dürfte der GLES Support sein. Wer ohnehin schon OpenGL kann, oder vielleicht auch mal WebGL gemacht hat, braucht hier nicht viel Beiwerk, um schnell einfache Demos, aber auch komplexere Grafik Apps zu bauen.
Ich persönlich kann mich mit Java einfach nicht so richtig anfreunden und mir war das SDK immer ein bisschen zu umständlich – Go als zu Binärcode kompilierende Hochsprache hat mir hingegen in letzter Zeit eine Menge Spaß gemacht. Ich bin gespannt, wie sich das Projekt in nächster Zeit weiter entwickeln wird.

Kompetenz durch Kauf?

Warum ich lieber Sachen auseinander nehme, als unreflektiert und ohne jedes Sachverständnis Sachen zu kaufen, die immer mehr darauf optimiert werden, den Nutzer zu bevormunden.

Die sollte ursprünglich nur ein kleiner Kommentar zu einem Interview mit Ranga Yogeshwar werden – kurz fassen war mal wieder nicht drin.

Natürlich kann man das ganze etwas mit Luxus und tollem Service ansprühen. Ich kann auch nicht von der Hand weisen, dass viele Menschen mit durchdachten Fertigprodukten deutlich bessere Resultate erzielen, als ihnen selbst sonst möglich wäre.
Das kann man selbst gut finden und sicher gibt es in User-$irgendwas Branche auch tolle Jobs.

Ich hingegen finde diesen Trend sehr schade. Wir verlernen es dadurch, überhaupt noch etwas verstehen zu wollen. Langsam aber sicher wird in den Köpfen vieler Menschen

ich habe sehr viel Geld für Produkt XY ausgegeben und dann auf einen Knopf gedrückt…

gleichbedeutend mit

das habe ich selbst gemacht

Der Besitz eines Produktes und das vernachlässigbare Wissen es richtig zu bedienen, wird heute schon ihn vielen Branchen als Kompetenz angesehen.
Wie weit fortgeschritten dieser Prozess schon ist, bemerkt man, wenn man einem Nutzer eines dieser Produkte erklärt, dass seine Resultate eigentlich nicht seine eigenen Werke sind, sondern nur das Resultat sequenziell angewendeter Voreinstellungen, auf die er eigentlich keinen Einfluss mehr hat. Wenig mehr, als “Malen nach Zahlen” mit Malerei zu tun hat.
Solche Produkte werden nicht selten als besonders professionell dargestellt und verkauft, dabei sind sie eigentlich nur die Inkarnation des kleinsten gemeinsamen Nenners.
Dadurch wird Kompetenz schleichend durch Finanzkraft ersetzt. Man ist professionell, weil man ein professionelles Produkt gekauft hat. Fähigkeiten bzw. Verständnis für die Sache werden nach und nach verdrängt.
Den Herstellen kommt dabei noch zu Gute, dass solche Produkte einen unglaublichen sozialen Druck aufbauen. Wer sie erworben hat, wird im Folgenden seine Entscheidung für dieses Produkt bis aufs Blut verteidigen, weil es zwar einerseits großes gesellschaftliches Ansehen mit sich bringt, viel Ressourcen in ein hochwertiges Produkt investiert zu haben, aber auf der anderen Seite einer Ächtung gleichkommt, seine Ressourcen für Minderwertiges zu verschwenden.
So wird der Käufer selbst zum flammenden Verfechter eher durchschnittlicher Produkte und Zutritt zu_Professionellen_ Kreisen nicht mehr aufgrund von Fähigkeiten, sondern von Besitz abhängig gemacht.

Diese sogenannten professionellen Produkte eint dabei allesamt eine Eigenschaft: Verbesserung in den Resultaten ist nur durch Zuerwerb weiterer Produkte möglich, nicht aber durch einen persönlichen Zuerwerb an Wissen und Fähigkeiten.

Die Produkte sind sozusagen durchschnittsoptimal d.h. sie bringen in den meisten Anwendungsfällen gute bis sehr gute Ergebnisse, greifen aber jeden Einzelfall gleich auf.

Professionell bedeutet für mich aber, dass man gerade für jeden Einzelfall selbst tatsächlich optimale Bedingungen herstellen kann. Hier kommt dann wieder die von mir geforderten Fähigkeiten und Sachkenntnisse ins Spiel.
Wer diese nicht hat, fährt mit der neuen Definition von_professionell_ sicher besser, da er durch Unkenntnis nichts schlechter machen kann, als die Produkte ihm erlauben.
Wenn ein Produkt uns aber derart bevormundet, so dass wir auch bei gegebener Kompetenz nicht besser sind, als jemand der das Produkt gerade so eben bedienen kann, hat das für mich nicht besonders viel mit Professionalität zu tun.

Für mich stellt sich mit ich muss das nicht verstehen, es funktioniert einfach keine Begeisterung ein.

Mein Bestreben ist es, zu Lernen, Wissen zu erlangen und dieses Wissen mit anderen zu teilen. Wissen an sich und die Erkenntnis neues Wissen erlangt zu haben, machen Spaß. Ebenso, wie dieses Wissen zu Teilen.
Schon alleine deshalb lehne ich Kompetenz definiert durch den Besitz professioneller Produkte ab. Dieser Ansatz ist wohl kaum geeignet in einer sich zunehmend globalisierenden Gesellschaft gleiche Bedingungen für Alle zu schaffen.
Im Gegenteil, er schafft nicht kritikfähige Eliten, die sich über Geld abschotten und hemmt jeglichen Fortschritt bzw. bindet ihn an die Produkte, da der Hersteller bei diesem Konzept der einige Akteur ist, der als Innovator auftreten kann.
Aller Wahrscheinlichkeit wird er das aber nicht. Kommerzielle Anbieter neigen eher dazu, sich auf ehemaligen Innovationen aus zu ruhen, wenn denn erst mal alle Kunden fest genug in ihrem Sandkasten eingesperrt sind.
Schade, dass wir zu träge sind, ab und zu einen Blick aus den Sandkästen zu werfen, weil wir zu bequem geworden sind, diesen Bereich zu verlassen, in dem alles so einfach funktioniert und wir uns deshalb einreden dürfen, irgendetwas zu können.

Was ist eigentlich Chrome?

Mal wieder ein neuer Chrome. „So what?“ werden sich die meisten sagen und genau das hat Methode. Wenn man sich die kleinen Änderungen und Erweiterungen mal ansieht, erkennt man unschwer wohin die Reise mal gehen soll, was allerdings spätestens seit den Chrome Books und ChromeOS wohl kein Geheimnis mehr sein sollte.

Mit Chrome unternimmt Google nichts Geringeres, als den Versuch einen Kompatibitäslayer zwischen Anwendung und System einzufügen, so dass Anwendungen völlig unabhängig von der Hardwarearchitektur und dem Betriebssystem ausgeführt werden können und Look&amp;Feel erhalten bleiben. Jetzt wird sich der ein oder Andere, sicher denken:

Das gab schon mal? Was ist mit Java?
Der Unterschied? Google macht es vermutlich diesmal richtig.

Das größte Kapital der Firma Microsoft ist z.B. die Trägheit und die Unbeweglichkeit ihrer Userbasis. Genau diese ist aber in den heutigen Zeiten des Wandels auch ihr größter Fluch. Keine Firma die einen Umbruch in der Technologie anstrebt, kann sich gleichzeitig einen Bruch in der User Experience leisten. Genau diesen Bruch hat es bisher jedes Mal gegeben, wenn versucht wurde, Plattformübergreifende Anwendungen zu ermöglichen. Ich denke da zum Beispiel an den unsäglichen JavaWebStart, der von mir beim ersten erscheinen des Icons auf dem (damals noch Windows) Desktop, sofort wieder deinstalliert wurde. Er brachte mir keinen Nutzen und wurde deshalb auch niemals beachtet. Dabei war das, was er hätte werden können, eigentlich exakt das Selbe, was der Chrome jetzt wird.

Wieso aber scheint Google mit exakt dem gleichen Ziel plötzlich Erfolg zu haben? Die Antwort ist verblüffend einfach:

Weil es niemand mitbekommt.

Chrome entwickelt sich einfach langsam aber stetig in diese Richtung weiter ohne dabei irgendjemandem etwas aufzwingen zu wollen. Dabei wird peinlichst genau darauf geachtet, die Entwicklercommunity mitzunehmen und einen Fokus auf die Funktionen zu legen, die zwar auch in die gewünschte Richtung gehen, aber von der Entwicklerbasis schon lange gefordert werden.
Da ist als Beispiel die File API zu nennen. Wer mal versucht hat mit minimalen Methoden, d.h. ohne PHP oder extra Tools einen Fileupload zu realisieren und damit meine ich zu Zeiten, als dies nur über Multipart MIME in einem Webformular möglich war, der dürfte diese API genauso lobpreisen, wie ich.

Sie ist natürlich keine Entwicklung ausschließlich aus dem Hause Google und in so ziemlich jedem halbwegs aktuellen Browser verbaut, aber dennoch einer der Pflastersteine in die gewünschte Richtung.
Google hat es auf diesem Weg auf fast unfaire Art und Weise einfacher als Microsoft, die gerade versuchen den Umgekehrten Weg vom Desktopsystem in die viel beschwohrene Cloud und die mobile Welt zu gehen.

Chrome kann eine bekannte Welt, das Lool&amp;Feel des Webs mitnehmen. Der heutige Webuser ist die kontinuierliche Weiterentwicklung der Dienste gewöhnt, die meist in kleinen Schritten unbemerkt, aber auch mal mit unschönen Stolpersteinen vorranschreitet. Diese Bewegung ist im Gegensatz zur Desktopsoftware unvermeidlich und nimmt so auch den konservativsten Gewohnheitsuser mit. Er kann einfach nicht mehr das Facebook von 2008 verwenden.

Hier liegen die großen Probleme mit denen sich Microsoft momentan auseinandersetzen muss. Sie waren es viel zu lange gewöhnt, Standards einfach brechen zu können und andere, durch schiere Macht auf dem Markt, auf ihren Weg zu zwingen. Heute ernten sie dafür nicht mal mehr ein müdes Lächeln. Das Web verabschiedet sich, nicht ohne Zwang, der diesmal allerdings von Apple kam, von Adobe Flash und setzt auf reines HTML5 – Microsoft entwickelt mit Silverlight einen Flashnachfolger, den niemand mehr braucht.

Auch der Versuch das mobile Parkett zu betreten, scheiterte bis jetzt im wesentlichen an zwei Fehlern die Google mit dem Chrome nicht macht.
Da wäre als erstes die Entwicklerbasis zu nennen. Es reicht eben nicht aus, ein Produkt auf den Markt zu werfen, ohne die Entwickler abzuholen. Mit Software die zum größten Teil aus Produkten des eigenen Hauses besteht, erreicht man heutzutage keine Breite mehr, die dem Endkunden ausreicht.
Beispielhaft dafür ist das fast nicht erwähnenswerte Scheitern des Surface Tablets. Ein von der Hardware her durchaus beachtliches Produkt, mit einem unverschämten Preis, der nur mit einer Breiten Softwarebasis und Service zu rechtfertigen wäre, wie sie von Apple geboten wird – und auch dort besteht ein großer Teil der Preisbildung nur aus der fiktiven Eintrittskarte in die High Society.
Welches Extra rechtfertigt das Surface und macht es attraktiv? Ich darf in Microsofts beengender Hauseigenen Sandkiste mit Niemandem spielen.

Ein vollwertig Desktopkompatibles Surface wird umgehend den zweiten Fehler machen und einen weiteren noch gratis dazu.

Der Desktopuser ist ein Gewohnheitstier. Er wünscht keine Änderungen und möchte gleiche Aufgaben immer nach dem gleichen Schema lösen. Selbst dann noch, wenn es für die Aufgabenstellung längst bessere Lösungen gibt. Nimmt man ihm seinen gewohnten Weg und ersetzt ihn durch einen viel effizienteren Weg, denn freiwillig würde er das nie versuchen, sieht er diese Verbesserung stattdessen als Verschlechterung.

So schleppt sich Windows mit Altlasten aus inzwischen zwei Jahrzehnten vor sich hin, bremst sich selbst und bringt mit einer Neuinstalltion schon über 10GB auf die Wage. Wo man Geschwindigkeit aber nicht unbegrenzt durch größere Hardware kaufen kann, weil dieser Mangel an Effizienz am Ende immer auch mehr Strom bedeutet, geht diese Altlast plötzlich auf Kosten der Laufzeit. Der Endanwender sieht den Fehler aber nicht in seiner eigenen Trägheit, sondern in einem angeblich schlechten Produkt, das seine Wünsche nicht erfüllt.
Wie aber soll sich ein mobiles Windows durchsetzen, wenn schon die erste Reaktion auf Windows8 eine Flut von „so bekommen sie ihren Startknopf / Desktop zurück“ Artikeln war.

Genau diese Trägheit hat letztendlich auch die gute Idee hinter Java kaputt gemacht. Das generische UI ließ sich nicht eins zu eins in native UIs übersetzen und es musste ein generisches Javasytle UI her. Wir erinnern uns an Swing und was darauf folgte. Wieder kam es zu einem Bruch in alltäglichen Aufgaben. Der Mehrwert von plattformunabhängigen Anwendungen konnte nicht vermittelt werden. So das der Nutzer keinen Sinn darin sah, seine Alltäglichen Gewohnheiten auf zu geben.

Es ist noch nicht lange her, da wurden Anbieter dafür verhöhnt, ihre Software erst beim Nutzer ausreichend zu Testen und fern zu warten, anstatt von Anfang an ein angeblich perfektes Produkt aus zu liefern.
Die Zeit zeigt uns aber eher, dass Nutzer durchaus ein paar kleine Probleme verzeiht, wenn er dadurch frühzeitig an deutlichen Verbesserungen teilhaben kann.

So verlockend es auch sein Mag den Nutzer durch Stagnation, auf einem ehemals guten Niveau, durch seine Gewohnheit zu binden, diese Strategie funktioniert nur für einen Monopolisten. In einer Konkurrenzsituation tut sich dadurch ein Graben auf, den man irgendwann selbst nicht mehr überbrücken kann, weil immer ein nicht zu vernachlässigender Teil der Nutzer nach diversen Kleinigkeiten verlangen wird, die man auf der „alten“ Seite hinter sich lassen müsste. Ist erst einmal ein Graben da, gibt es unweigerlich zwei Seiten.

Geht man stattdessen behutsam, in kleinen Schritten weiter, kann man einen Großteil der Nutzer mitnehmen und vermeidet unliebsame Altlasten, die man niemals entfernen darf, weil man sonst die an sie gebundenen Nutzer verlieren würde.
So hat Google beste Voraussetzungen dafür, zu ganz nebenbei, mit ihrer Variante von Javascript und einem Browser das zu schaffen, wofür schon Sprachen geplant, entwickelt und finanziert wurden und trotz allen Hypes doch wieder nur in einer Nische verschwanden.

Ob sie das schaffen werden – man darf gespannt sein.

Wenn sie es schaffen, dann werden künftige Betriebssysteme vermutlich – wieder – nur die Hardware verwalten und Schnittstellen für die Anwendungssoftware bereitstellen. Damit wären wir dann einem Punkt, wo wir schon vor zehn Jahren hätten sein können, wenn man vermieden hätte, sich abgeschottete, monopolistische Ökosysteme zu bauen. Diese dienten nur dem Zweck, den Innovationsdruck zu mindern. Niemand wechselt ein Betriebssystem, weil drei Programme besser sind und man dafür seine ganze gewohnte Arbeitsumgebung aufgibt.

Sind in einigen Jahren aber fast alle aktuellen Programme auf allen Systemen lauffähig, wird es die bisher gewohnte Marktverzerrung, dass es einige gute Programme nur für ein schlechtes Betriebssystem (oder wahlweise auch umgekehrt) gibt, nicht mehr geben.

Möge der bessere gewinnen.

tldr: Es ist nur ein Browser.

BT-NAP reloaded

Kurz nachdem ich meinen letzten Beitrag über BT-NAP veröffentlichte, brachte Google das Android 4.2 Update heraus, mit dem es dann unter Umständen nicht mehr funktionierte. Was passiert ist und wie man es dann doch wieder zum Laufen bekommt, erkläre ich dann mal eben hier.

Android 4.2 ist zugegebenermaßen nicht mehr sonderlich neu und den kleinen Fix, den ich im Folgenden zeige, benutze ich selbst nun auch schon seit ungefähr einem Monat nach dem Erscheinen.
Es sei somit an dieser Stelle nachgeholt, das jetzt auch einmal schriftlich fest zu halten.

Aber der Reihe nach. Was hat sich geändert, und wer ist betroffen? Betroffen dürften die wenigsten Nutzer sein, die überhaupt Ethernet über Bluetooth auf Android verwenden. Jedoch hat sich Google einen Patzer erlaubt, bei dem ich mir nicht ganz sicher bin, ob das jetzt ein Bug, oder ein Feature sein soll.
Schmählich sei zu erwähnen, dass Google im Zuge des Updates auf Android 4.2 einen Bluetooth Stack aus eigener Feder eingebaut hat, den sie in Zusammenarbeit mit Broadcom entwickelten.
Wie immer, wenn diese Firma ihre Finger mit im Spiel hat, kann man sich darauf verlassen, dass am Ende irgendwas nicht so funktioniert, wie es sollte. Geht es um Software, so liegt es meist daran, dass Standards nicht eingehalten wurden.

Auch diesmal enttäuschte Broadcom nicht und so funktionierte mein schönes Bluetooth Netzwerk nicht mehr, sobald Android 4.2 aufgespielt war.

Nutze ich hingegen ein anderes Smartphone als Bluetooth Access Point, ging alles wie bisher. Das legt ja zumindest erst mal die Vermutung nahe, dass ich bei meinem Setup irgendwas falsch gemacht hatte.
Von meinem Server bekam ich zwar noch eine IP Adresse, aber das war dann auch schon alles. Versuchte ich hingegen irgend eine Seite aufzurufen, oder auch nur nach Emails zu laden – nichts.
Ich überprüfte als nächstes die per DHCP übermittelte Netzwerkkonfiguration auf den Androiden. IP Adresse, DNS, Default Gateway und auch das restliche Routing waren völlig in Ordnung.
Von der Netzwerkkonfiguration auf IP Ebene her hätte es funktionieren müssen. Das tat es aber nicht. Ich bekam DNS Requests aufgelöst, aber schon ein Ping schlug fehl, sogar im eigenen Netzwerk. Der einzige Rechner, den ich völlig normal erreichen konnte, war der Server welcher als Endpunkt für die Bluetooth Verbindung diente.

Erst ein Dump der Bluetooth Schnittstelle auf dem Server brachte die traurige Wahrheit ans Licht:

Kein Einziges Paket, welches nicht die Ethernet MAC Adresse des Access Points als Zieladresse hatte, verließ überhaupt die Androiden!

Bis heute ist mir nicht klar, ob es sich dabei um Absicht (und damit wohl um eins der missglücktesten Sicherheitsfeatures, welche ich je gesehen habe) handelt, oder ob sich da wirklich ein unglaublich dämlicher Bug durch die Qualitätssicherung geschlichen hat.

IP Routing basiert unter anderem auf der Vorraussetzung, dass jeder Host im gleichen Subnetz direkt über seine MAC Adresse angesprochen werden kann.
Android 4.2 hingegen schickt zwar einen ARP (Adress Resolution Protocol) Request, wenn zu einer IP Adresse im Subnetz die MAC Adresse nicht bekannt ist, kommuniziert aber nur mit der MAC Adresse des Bluetooth Access Points, oder der Broadcastadresse (zum Glück).
Um es verständlicher auszudrücken: Es redet nur mit dem einen Host mit dem die Ethernetverbindung über Bluetooth hergestellt wurde, oder mit dem ganzen Subnetz.

Man könnte nun denken, dass dies ein gewaltiges Problem ist, welches doch schon etwas mehr Lärm im digitalen Raum hätte erzeugen müssen. Hier liegt auch der Grund, warum ich mir eben nicht sicher bin, ob es sich um Absicht handelt.

Zum Surfen im Internet reicht das aus!

Zumindest wenn eine Voraussetzung gegeben ist. Der Host, welcher als Bluetooth Endpunkt für die Verbindungen der Android Geräte dient, muss gleichzeitig Router des Subnetzwerkes, DNS und DHCP Server sein.
Verbindet man sich mit einem anderen Smartphone, ist genau das der Fall.
Auch wenn man noch ein altes Modem verwendet, welches keine Routerfunktion übernimmt, so kann dieses Setup funktionieren, wenn der Host der die Internetverbindung hält, genau alle oben genannten Voraussetzungen erfüllt.

Eine ähnliche Funktion gibt es auch für bessere WLAN Access Points. Sie garantiert, dass sich die Teilnehmer in einem WLAN nicht gegenseitig attackieren können, weil sie jegliche Kommunikation zwischen den Teilnehmern unterbindet. Diese Funktion wird gerne Client Isolation genannt.

Nimmt man nun einmal an, dass es sich hierbei um Absicht handelte, so drängt sich doch gleich die Frage auf: Welchen Nutzen sollte Client Isolation in einem Heimnetzwerk haben? Ist es nicht gerade Sinn und Zweck eines Heimnetzwerks, dass lokale Geräte auch untereinander kommunizieren können und nicht nur jedes einzelne Gerät mit dem Internet?
Eine Antwort auf diese Frage würde ich jedenfalls gerne mal von Google irgendwo lesen, allerdings bezweifle ich inzwischen, dass sich Google zu dem Problem jemals noch äußert.
Derzeit kann ein über Bluetooth eingebundenes Gerät keinen anderen Host erreichen, außer dem Bluetooth AP. Damit fallen sämtliche Verbindungen zu Anderen Teilnehmern, wie z.B. Netzwerkfreigaben aus.

Also was kann man jetzt tun, um ein Android 4.2 Gerät doch noch über Bluetooth in ein Heimnetzwerk einzubinden?

Da es nur in Custom ROMs möglich ist, an so tiefliegenden Teilen von Android etwas zu ändern, wie es nötig wäre, um das Problem direkt auf den Endgeräten zu lösen, muss man eben das Netzwerk so anpassen, dass es dem Androiden vorgaukelt, sich genau in Situation zu befinden, die erforderlich ist.

Um das zu erreichen, muss man sich ein bisschen mit dem ARP (Adress Resolution Protocol) beschäftigen. Heutzutage ist es kaum noch bekannt und das ist ziemlich verwunderlich, weil IP ohne ARP überhaupt nicht funktionieren würde. Offensichtlich funktioniert es zu Problemlos, als das sich jemand damit beschäftigen müsste.

Hier ein paar Minimalgrundlagen: Jeder Teilnehmer im IP führt eine Tabelle, in der die Ethernet MAC Adresse für eine IP Adresse im Subnetz gespeichert werden kann. Soll eine IP Adresse erreicht werden, die nicht im Subnetz liegt, wird das Paket einfach an den für das Zielsubnetz zuständigen Router übermittelt.
Für das Internet ist dies für gewöhnlich der sogenannte Default Gateway.
Was ist aber mit den Hosts, die sich im gleichen Subnetz befinden? Diese sollten im Normalfall direkt auf Ethernet Ebene erreichbar sein. Sei dies nun Netzwerkkabel, WLAN oder eben auch Ethernet über Bluetooth.
Ist einem Gerät im Subnetz die Ethernet MAC Adresse einer IP Zieladresse nicht bekannt, so fragt es über das ARP einfach nach.

Hier ist XYZ, wie ist die Ethernet Adresse zur IP Adresse ABC?

Da die Zieladresse nicht bekannt ist, wird diese Anfrage einfach über die Broadcastadresse an alle Teilnehmer im Subnetz gestellt. Jeder Teilnehmer, der die Antwort kennt, ist berechtigt, diese zu übermitteln. Dies geschieht normalerweise jetzt mit dem Fragestellenden als Zieladresse.
Nun wo diesem die MAC Adresse zur IP Adresse bekannt ist, kann der Teilnehmer seine eigentlichen IP Nutzdaten übermitteln.

Dieser Vorgang funktioniert nun durch Googles Verschlimmbesserung nur noch mit dem Bluetooth Access Point als Zielgerät.
Da ich daran nichts ändern kann, baue ich etwas ungewöhnliches: Einen Router für das eigene Subnetz!

Ähnliche Lösungen gibt es schon für komplett getrennte Teile des gleichen Subnetzes. Diese können durch einen sogenannten ARP Proxy verbunden werden. Der ARP Proxy antwortet dazu einfach auf alle Anfragen nach einem Host in einem anderen Teil des Subnetzes mit seiner eigenen MAC Adresse. Wird ihm dann ein IP Paket für diesen zugestellt, übermittelt er dieses dann stellvertretend für den Absender.
Ein ARP Proxy hilft aber nicht dabei Pakete zu vermitteln, die gar nicht über IP transportiert werden. So funktioniert z.B. DHCP nicht durch eine Verbindung über einen ARP Proxy hinweg, wenn dort nicht auch ein DHCP Relay installiert ist.

Diese Lösung lässt sich in diesem Fall aber nicht anwenden, weil das Netz in Richtung des Androiden völlig normal funktioniert. Jeder Teilnehmer im Subnetz kann dem Androiden ein IP Paket zustellen. Dieser Antwortet nur einfach nicht.

Damit haben wir ein halbes Problem, für das sich auch eine passende halbe Lösung finden lässt. Der Eingriff in das lokale Netz soll so gering wie nötig ausfallen.

Der Einfachheit halber erkläre ich die Lösung an den fünf kleinen Zeilen, die dafür nötig sind.

Zunächst brauchen wir das Paket ebtables. Es ähnelt dem viel besser bekannten Paket iptables in Bedienung und Funktion. Während iptables genutzt wird, um Pakete auf IP Ebene zu manipulieren und damit z.B. das Routing zu beeinflussen, verändert ebtables Ethernetpakete, die eine Bridge durchlaufen.

Die Installation beispielhaft für Debian und Ubuntu:

sudo apt-get install ebtables

Die erste Zeile:

sudo ebtables -t nat -A PREROUTING -i bnep+ -p arp -j dnat --to-destination 'FF:FF:FF:FF:FF:FF'

In jedem ARP Paket, welches die Bridge über eine Schnittstelle, deren Name mit bnep beginnt (dazu dient das +) erreicht, wird noch vor dem Routing die Zieladresse auf die Ethernet Broadcastadresse (FF:…) gesetzt.

Da die Anfragen des Androiden hinter bnepX ohnehin an die Broadcastadresse gehen, betrifft dies effektiv nur die Antworten auf ARP Anfragen (ARP Reply), die der Androide gibt. Wir erinnern uns: Die Antwort erfolgt normalerweise Zielgerichtet an den Fragestellenden.

Die zweite Zeile:

sudo ebtables -t nat -A POSTROUTING -p ARP -o bnep+ -j snat --to-src YO:UR:MA:C0:HE:RE --snat-arp --snat-target ACCEPT

Hier soll bei jedem ARP Paket, welches die Bridge über bnepX verlässt, der Absender auf die MAC Adresse des Bluetooth Interfaces in der Bridge gesetzt werden. YO:UR:MA:C0:HE:REist natürlich für die eigenen Bedürfnisse anzupassen. --snat-target ist ein Zusatz, der nicht nur den Absender des Ethernetpakets auf diese Adresse umschreibt, sondern auch das TARGET Feld der ARP Antwort.
Da ARP Anfragen stellvertretend für Andere Teilnehmer beantwortet werden dürfen, ist das TARGET nicht immer gleich dem Absender der Antwort und muss extra gesetzt werden.

Die dritte Zeile:

sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"

Dies beeinflusst, was die Kernel auf der Bridge mit IP Paketen machen soll, in der keine ihrer IP Adressen als Absender, oder Adressat vorkommt. Auf den meisten Systemen steht dieser Wert auf 0 was die Kernel dazu veranlasst, diese Pakete einfach zu verwerfen. Diese Änderung bewirkt, dass die Pakete stattdessen gemäß der eigenen Routingtabelle weitergeleitet werden.

Die vierte Zeile:

sudo sh -c "echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects"

Normalerweise sendet die Kernel automatisch einen ICMP Redirect, wenn sie der Meinung ist, dass der Absender eines IP Pakets den Adressaten auf einem günstigern Weg erreichen könnte. Da Android 4.2 aber keine Teilnehmer des eigenen Subnetztes mehr erreich kann, ist diese Annahme immer falsch und der Redirect muss abgestellt werden.

Und wie Spielt das jetzt zusammen?

Das erläutere ich jetzt mal anhand von zwei Beispielen:

1. Der Androide möchte selbst ein IP Paket verschicken.

Will der Androide einen Teilnehmer im Subnetz erreichen, wird er zunächst versuchen die MAC Adresse des Teilnehmers über einen ARP Request zu erfahren. Dieser geht ganz normal durch die Bridge und erreicht über die Broadcastadresse das komplette Subnetz.
Von irgendwo im Subnetz erreicht jetzt die dazu gehörige Antwort auch die Bridge. Diese setzt jetzt die MAC Adresse in Absender und TARGET Feld auf ihre eigene. Diese Änderung sieht niemand außer dem defekten Androiden selbst, so dass die anderen Teilnehmer nicht verwirrt werden.
Damit denkt der Androide, die IP Adresse würde der Bridge gehören und wird alle folgenden IP Pakete für diese IP Adresse der Bridge geben.
Die Bridge stellt aber in ihrem Routing Code fest, dass die Pakete gar nicht für sie sind und leitet sie an den tatsächlichen Empfänger weiter. Ein Redirect wurde manuell abgestellt und bleibt damit aus.
Für den Empfänger bleibt der Vorgang unbemerkt, der Absender auf IP Ebene ist weiterhin der Androide.

2. Ein anderer Teilnehmer im Subnetz möchte den Androiden erreichen.

Auch dieser versendet einen ARP Request. Der Request erreicht die Bridge und wird dort so geändert, als wäre die Anfrage von der Bridge selbst gekommen.
Der Androide Antwortet jetzt aber der Bridge direkt, so dass der ursprüngliche Teilnehmer die Antwort gar nicht erhalten würde – wenn wir nicht in der ersten Zeile befohlen hätten, dass alle über Bluetooth eingehenden Pakete, die die Bridge erhält, auf die Broadcastadresse umgelenkt werden sollen.
Damit erhält die Antwort also jeder Teilnehmer im Subnetz, das schließt auch denjenigen mit ein, der urpsrünglich den ARP Request gemacht hat.
Eine ARP Antwort an die Broadcastadresse zu schicken ist zwar unüblich, aber nach Standard zulässig und wird auch z.B. beim unsolicited ARP eingesetzt, um Änderungen aktiv durch das Netzwerk zu propagieren.
Auf diesem Umweg haben wir es jetzt geschafft, dass der Androide einen ARP Reply zu einem Teilnehmer schickt, mit dem er normalerweise gar nicht reden würde.
Zum Androiden hin ist der Weg im Netzwerk nicht gestört, die Pakete durchlaufen, nach Bekanntwerden seiner MAC Adresse, ganz normal die Bridge.

Logisch gesehen nehmen die Pakete jetzt zwei unterschiedliche Wege.

Vom Androiden ins restliche lokale Netzwerk werden sie auf der Bridge in Layer 3 gehievt und dort geroutet, auf dem Rückweg werden sie ganz normal auf Layer 2 zugestellt.
Eine Lösung auf Layer 3 (IP Routing) Basis hätte nicht funktioniert, da auf Layer 2 (Ethernet) nicht alle Teilnehmer in einem Subnetz ungehindert kommunizieren konnten, wie es für IP Voraussetzung gewesen wäre.
Diese Lösung hingegen behebt das Problem schon auf Layer 2, wo durch Manipulationen am ARP wieder eine für Layer 3 transparente Zustellung der Pakete erreicht werden konnte.

Bluetooth NAP was ist das - und wieso?

Wer heutzutage über Bluetooth Netzwerk schreibt, hat sich wohl als Erstes mal zu rechtfertigen.

Bluetooth heute?

Das in Zeiten wo WLAN in Standards ABGN und noch einigen weiteren Erweiterungen, in allen möglichen Frequenzen verfügbar ist. Ohne mich jetzt unnötig in technischen Details zu verlieren, die ich zugegebenermaßen ohnehin selbst nachschlagen müsste, stelle ich einfach mal die Behauptung in den Raum, dass Bluetooth sich teilweise für mobile Geräte einiges besser eignet als WLAN.

Obwohl beide Techniken ungefähr zur gleichen Zeit zum Endnutzer vordrangen und ursprünglich im gleichen Frequenzband liegen, wurden sie doch mit sehr unterschiedlichen Zielsetzungen entwickelt. Auch in den ersten WLAN Standards findet sich eine Menge zum Thema Powersaving. Aber:

In der Praxis hat es nie wirklich das Tageslicht erblickt. Sendeleistung ist nur in einigen Treibern überhaupt konfigurierbar, in noch weniger Fällen wird diese automatisch angepasst. Stattdessen verfolgte man beim WLAN hauptsächlich ein Standby Konzept. Wenn ein Client nichts zu senden hat, legt er sich für eine definierte Zeit schlafen, in der er nicht mehr erreicht werden kann. Im normalen Betrieb ergab sich daraus eine durchaus unangenehme Latenz, verbindungsorientierte Übertragungen können dadurch unterbrochen werden.

Das alles zusammen führte in letzter Konsequenz dazu, dass sich Powersaving im WLAN Bereich nur minimal und sehr defensiv durchsetzte. Für WLAN im Heimbereich war es nicht relevant, solange es nur darum ging Kabel zu sparen. Für größere Laptops ist der Stromverbrauch von WLAN im Vergleich zum Gesamtverbauch auch nicht wirklich kritisch.

Kritisch wurde der Stromverbrauch erst mit Geräten, bei denen das Halten einer WLAN Verbindung für den Standbybetrieb inakzeptabel wurde. Auf den meisten Mobilgeräten ist dies kaum möglich. Verwendet man eine App, die nicht nur zyklisch Daten abfragt, sondern dauerhaft eine Verbindung benötig, so wird diese höchstwahrscheinlich nach recht kurzer Zeit im Standby abbrechen. Sogar wenn man per Hand alle möglichen WLAN Einstellungen verdreht, ist man leider immer noch nicht vor Verbindungsabbrüchen im Standby sicher. Dies ist unter anderem auch von der verwendeten Netzwerkhardware abhängig. Eigentlich wollte ich ursprünglich noch ein How-To schreiben, aber so viel gibt es diesmal nicht zu tun. Erneut scheint der Textteil deutlich zu überwiegen.

Eine Garantie dafür, dass es funktioniert gibt es auch nicht. Bluetooth unter Linux ist seit Jahren ein Graus. Außer dem Projekt BlueZ gibt es nichts, was nennenswerte Bekanntheit erreicht hätte. BlueZ wiederum ist nicht gerade das, was ich als ein Linux Vorzeigeprojekt bezeichnen würde.

Ohne mich in die Tiefen der Quellcodes gegraben zu haben, schildere ich hier nur den Eindruck, den ich als langjähriger Nutzer gewonnen habe:

Die ersten Versionen hatten einen straight forward Ansatz, wie er im embedded Linux Umfeld üblich ist. Bestehend aus Kerneltreiber und ein paar Daemons, die sich jeweils um sehr eng gesteckte Aufgabengebiete kümmerten. Konfiguriert und gesteuert wurde diese Infrastruktur, von funktional gehaltenen kleinen Binärprogrammen, die direkt mit den Daemons kommunizierten.

Dann kam eine folgenschwere Entscheidung, von der sich Bluetooth auf Linux bis heute nicht ganz erholt hat. Statt das Projekt erwachsen werden zu lassen und erst einmal die Infrastruktur auf alle möglichen Bluetooth Funktionen (und Bluetooth kann bedeutend mehr, als nur Bilder versenden und FTP) zu erweitern, hat irgend jemand beschlossen, dass BlueZ in der alten Form nicht mehr zeitgemäß ist und für den Desktopbetrieb die Infrastruktur komplett umgebaut werden müsste. Anscheinend gefiel es den Entscheidungsträgern nicht, dass die Netzwerkverwaltungsapplets der Desktopdistributionen die Daemons nicht direkt umkonfigurieren konnten, sondern stattdessen dazu jene kleinen Binärprogramme aufgerufen werden mussten.

Das einzig hierfür gültige Argument wäre ein ernst zu nehmender Overhead. Ein Solcher ergibt sich aber realistisch wohl erst bei ein paar Tausend Vorgängen pro Sekunde. Dennoch wurde das Projekt in der Folgezeit funktional auf Eis gelegt und seitdem in Schneckentempo an der Infrastruktur gebastelt.

Die Entscheidung gegen eine Vielzahl kleinerer Daemons, die sich um sehr enge Bereiche kümmern, hin zu dem großen allzweck bluetoothd **Daemon, kann ich mit viel Wohlwollen noch nachvollziehen, auch wenn man sich damit eine deutlich größere Fehlerdomäne heranzüchtet, da nun schlimmstenfalls nicht mehr eine Bluetooth Funktion abstürzt, sondern gleich alles. Gerade, wenn man mit wackeligen exotischen Funktionen arbeitet, ist es nicht gerade ein Fortschritt, wenn beim experimentieren gleich immer Alles ausfällt.

Absolut nicht nachvollziehbar ist für mich aber die Entscheidung, die komplette Kommunikation über DBUS abzuwickeln. Ein derart komplexer Nachrichtenbus, sollte für Kommunikation auf Applikationslevel vorgesehen sein und zumindest nicht der einzige Weg sein, dem Bluetoothd irgendetwas mitzuteilen. Jede embedded Plattform wird im Zuge dieser Entwicklung DBUS implementieren müssen, um überhaupt die neueren BlueZ Versionen verwenden zu können.

Auch die Migration dahin verlief alles andere als sauber. Zeitweise liefen beide Ansätze quasi parallel, die kleinen Binärtools wurden umgeschrieben, den Bluetoothd zu nutzen, einige weitere Daemons wurden dennoch gebraucht und bis Heute fehlt ein halbwegs vernünftiges Desktop Applet, dass mehr kann als Filetransfer (wenn er denn mal funktioniert) und Eingabegeräte einbinden. Blueman geht da immerhin schon einmal in die richtige Richtung.

Das Wirrwar um die Bluetooth Funktionen lässt sich auf einen kurzen Blick erfassen, wenn man mal mit dem sdptool und seiner browse Funktion ein Gerät abscannt. Die, zugegebenermaßen schwer zu lesende, Auflistung der verfügbaren Dienste zeigt, was das Gerät glaubt zu können und mit welchen Protokollen man diese Funktionen erreichen könnte. Hier sollte einiges mehr stehen, als die GUIs einem gefiltert offerieren. Noch weniger davon wird das Gerät aber tatsächlich können, denn nicht mal diese Listen werden ordnungsgemäß geführt. Dieses Problem beschränkt sich aber nicht nur auf Linux.

Kommen wir nun also zu dem, worüber ich eigentlich schreiben wollte:

Ethernet über Bluetooth

Wie schon erwähnt, bietet Bluetooth einiges mehr, als nur Eingabegeräte, Filetransfer und FTP. Schon seit sehr langer Zeit gehört auch IP fähige Ethernetemulation zum Standard. Ethernetemulation heißt in diesem Zusammenhang übrigens PAN (Personal Area Network). Recht schnell findet man dazu auch ein How-To aus den besseren Tagen des BlueZ Projekts. Inzwischen funktioniert davon leider so ziemlich gar nichts mehr. Die Ankündigung, die entsprechenden Compat Pakete demnächst komplett zu entfernen, klingt in diesem Zusammenhang fast wie eine Drohung. Jedenfalls halte ich es deshalb nicht mehr für eine gute Idee, noch lange auf diese Tools zu setzen. Aber zunächst die Grundlagen.

PAN kann als Group Ad Hoc Network realisiert werden, einem eher losem Verbund mehrer Client Nodes (PANU) mit einem Verwaltenden Master Node (GN). Diese Betriebsart ist für nicht statische, isolierte lokale Netze gedacht.

Für den Ersatz bzw. die Ergänzung von WLAN eignet sich eher die Betriebsart mit einem Network Access Point (NAP). Dieser stellt dann die Verbindung vom LAN, WAN, oder auch diesem ominösen Internet bereit.

Wird auf einem Bluetooth Adapter mit einem aktuellen BlueZ Stack die NAP Funktionalität aktiviert, so braucht man zwingend eine virtuelle Ethernet Bridge. Das Starten des Dienstes erzeugt nicht sofort ein Ethernet Interface, welches verwaltet, oder konfiguriert werden könnte. Stattdessen wird das Interface dynamisch erzeugt, wenn ein Client sich verbindet. Es ist keine automatisierte Konfiguration des Interfaces vorgesehen, wie man sie in Form von Up- und Downscripts. ggf. von anderen Projekten kennt.
Dadurch wird die Bridge erforderlich. Das einzige was der Dienst macht, ist ein Interface erzeugen, es hochzufahren und dann automatisch in eine vorher per Kommandozeile angegebene Bridge zu hängen. Das funktioniert überraschend gut und ist, von dem bisschen extra Aufwand die Bridge zu erstellen, sehr einfach.

Wie man eine Bridge erstellt und konfiguriert habe ich schon an anderer Stelle beschrieben und gehe daher nicht mehr detailliert darauf ein.

Einen kleinen technischen Haken hat die Geschichte noch und dieser Haken hat mich mehrere Tage und eine Fehlinvestition gekostet. Hardwareseitig ist der NAP Dienst ist nicht in allen Bluetooth Dongles oder Laptopmodulen implementiert. Nicht mal dass er sich starten lässt, ist eine Garantie dafür, dass er dann auch richtig funktioniert. Mit meinen neusten beiden Dongles ging es z.B. nicht. Mit beiden ließ der Dienst sich starten und eine Verbindung mit Mobilgeräten konnte aufgebaut werden. Nach kurzer Verwendung flog die Verbindung dann ohne verwendbare Fehlerberichte raus. Ein Blick in die syslog gibt nur Auskunft über ein hohes Aufkommen von Fehlerhaften ACL Paketen, bevor die Verbindung abbricht.

Klar ACL Pakete. Was auch immer das nun sein soll. So nah wollte ich mich nun eigentlich auch nicht mit der Protokollebene beschäftigen. Etwa eine Stunde Recherche auf Google bringt zu der Fehlermeldung nur immer wieder die gleichen Fehlerberichte zu Tage, wo Nutzer nach einem Systemupdate Probleme damit hatten ihre Logitech Bluetooth Maus zu verwenden.

Bezüglich PAN gibt es keine Treffer nicht einmal irgendwelche Details, was das nun für Pakete sind, warum sie Defekt sein könnten und wie man es beheben könnte. Einige Stunden genervtes Gefrickel später, hatte ich dann raus, dass es sich wohl um ein Problem zwischen Treiber und Dongle handelt. Mit einem zehn Jahre alten Bluetooth V1.0 Class A Adapter ging es dann nämlich plötzlich tadellos.

Sollte dieses Problem bei Irgendjemandem auftreten, kann ich also leider auch überhaupt keine Hilfestellung geben. Abhilfe könnten da nur die Entwickler des BlueZ Stacks selbst schaffen.

Was ist zu tun?

Als Erstes braucht man die aktuellen Binärtools des BlueZ Projektes. Die sind zumindest bei einem Stock Ubuntu noch nicht installiert. Es gibt zwar ein paar Demo Tools mit den Namen bluez-test-*, aber die sind wohl eher Anschauungsmaterial und nicht für den Dauergebrauch gedacht. Es handelt sich um Python (!!!?) Skripte. Im Network Skript ist ein willkürlicher Timeout eingebaut, nachdem der Dienst einfach wieder runter fährt. Es kursieren zwar einige Hacks im Netz, die es für den Dauergebrauch flott machen sollen, aber die funktionierten bei mir nicht und dann ist da noch diese Hemmschwelle.

Einen Systemdienst über ein nicht terminierendes Python Skript konfigurieren, das dann mit samt dem Interpreter im Speicher rumgammelt, bis der Dienst beendet wird? Sonst geht’s Euch aber gut, oder?

Also, mal vorausgesetzt, der geneigte Leser möchte ebenso wie ich, den Dienst nicht von einem wackeligen Hochsprachenskript abhängig machen, dann empfiehlt sich stattdessen die Installation der bluez-tools. Vorausgesetzt das Paket ist auf Deiner Distribution verfügbar, sollte es mit dem Paketmanager deiner Wahl zu beschaffen sein.

Unter Ubuntu und vermutlich damit auch Debian geht es in einem Terminal folgendermaßen:

sudo apt-get install bluez-tools

Aber Vorsicht: Bei mir auf dem Desktop (mit XUbuntu) führt das geradewegs in einen Konflikt. Das Paket enthält ein paar OBEX Tools (das ist der Dienst mit dem Muttis Bilder von ihren Kindern tauschen), die gerne diejenigen ersetzen würden, von denen das Systemapplet Blueman abhängt.

Bei einer Serverinstallation sollte dies nicht weiter stören, denn wer hat schon eine grafische Oberfläche. Für meinen Laptop hieß das:

“tschüß Blueman!”

Ab jetzt wird Bluetooth eben über die Kommandozeile verwaltet. Genau das muss im Folgenden noch gemacht werden, damit der Dienst genutzt werden kann.

Eine PAN Verbindung kann nämlich erst aufgebaut werden, wenn die beteiligten Geräte gepaart sind und einander noch mal explizit vertrauen (Trust). Über das Letztere bin ich dann auch noch einmal gestolpert. Selbst wenn die Geräte gepaart sind, wird die Verbindung ohne Trust nicht aufgebaut. Im syslog findet sich dazu dann nur eine winzige security exception.

Je nach Gerätekombination kann das Pairing von beiden Geräten initiiert werden, oder nur von einer Seite.

Äh? Wieso das denn?

Weil die Praxis mal wieder anders aussieht, als die Theorie. Am Pairing sind softwareseitig einige Timeouts beteiligt, die auf meinem Nexus7 dazu führten, dass ich in etwa eine Sekunde Zeit hatte, einen vierstelligen Code einzugeben und mit Fertig zu bestätigen, bevor das Fenster einfach wieder verschwand. Da ich das in dieser Zeitspanne kein einziges Mal geschafft habe, weis ich jetzt nicht, ob es überhaupt funktioniert hätte.

Eine allgemeingültige Anleitung zum Pairing kann ich aus diesem Grund dafür nicht angeben. Aber ich kann die Tools nennen, die man dazu braucht.

Auf der Serverseite wird man ohne die MAC Adresse des Clients nicht weit kommen. Da wir alle es hassen, diese viel zu langen MAC Adressen abtippen zu müssen, bietet es sich hier an, den Client auf sichtbar zu stellen. Bitte dabei nicht vergessen, dass er sich im Regelfall nach recht kurzer Zeit von alleine wieder auf unsichtbar stellen wird.

Ab hier bauchen wir für jeden weiteren Befehl Administratorrechte, weshalb für die anstehende Bastellei auf eine Root Konsole gewechselt werden sollte.

sudo -s

Willkommen in der Root-Shell.

Das Scannen nach auffindbaren Bluetooth Geräten ist eine Funktion des Adapters. Jeder Bluetooth Adapter erhält vom BlueZ eine eigene Liste von Geräten mit denen er gepaart ist und denen er vertraut. Dies bitte nicht vergessen, falls Ihr Experimente mit mehreren Adaptern vor habt.

Ein Scan kann zwar weiterhin auch mit dem hcitool initiiert werden, aber wir sind ja up to date.

bt-adapter -d

Ich gehe jetzt mal davon aus, dass der gewünschte Client in der Liste ist. Die MAC Adresse sollte jetzt irgendwo hinterlegt werden, wo man sie beliebig oft wieder rauskopieren kann.

So. Jetzt hätte ich beim Schreiben beinahe einen Fehler gemacht, der mir auch beim Basteln passiert ist. Die meisten Geräte fragen nämlich nur genau ein mal ab, welche Dienste der Partner anbietet und das ist beim Pairing. Dabei kommt das weiter oben schon erwähnte Service Discovery Protokoll (SDP) zum Einsatz. Dabei wird eine kryptische Liste mit teils numerischen Identifiern und Zoix(tm) getauscht. Der NAP Dienst wird aber erst in der Liste des Servers geführt, wenn er auch aktiv ist. Irgendwie logisch, oder? Das machen wir jetzt also mal ganz schnell zwischendurch.

bt-network -s nap <BRIDGE> &

Das war’s auch schon. Der Dienst läuft und ist im SDP registriert. Ich bitte darum, das kaufmännische Und am Ende der Zeile nicht zu vergessen, da das Tool sich nicht selbst in den Hintergrund begibt, und ansonsten die Kommandozeile blockiert. Natürlich könnte man hier mit einem beherzten Strg + Z und dem darauffolgenden Befehl bg (Background) Abhilfe schaffen.

Der Dienst ist nun also da. War es das nicht schon?

Nein leider nicht. Man findet den Dienst jetzt zwar mit dem sdptool, aber verbinden können sich nur Geräte, die gepaart sind, einander vertrauen und vor allem überhaupt wissen, dass der Dienst verfügbar ist. Wenn die Geräte schon mal gepaart waren, sollte der Client in den meisten Fällen noch mal entfernt werden, damit er beim nächsten Mal eine aktuelle Liste der Dienste bezieht.

bt-device -r <CLIENT MAC>

Wird den Client bei Bedarf Serverseitig aus der Liste der bekannten Clients und auch der Trustliste entfernen.

Das Pairing kann jetzt aktiv oder passiv erfolgen. Aktiv geht des so:

bt-device -c <CLIENT MAC>

Dadurch wird automatisch bei Bedarf der bt-agent gestartet, der sich um den Rest des Parings kümmern wird. Je nachdem, welche Bluetooth Versionen beteiligt sind. Müssen jetzt Nummern getauscht werden, oder nur bestätigt, oder eine DNA Probe abgegeben werden.

Wenn die aktive Variante des Pairings nicht funktioniert, kann der Server das auch passiv. Dazu muss der bt-agent einfach manuell gestartet werden. Allerdings sollte der Server in diesem Zeitraum überhaupt sichtbar sein, sonst macht das herzlich wenig Sinn.

bt-adapter --set Discoverable True
bt-agent

Achtung: Der Kram legt Wert auf korrekte Groß- und Kleinschreibung (WTF!)

Ebenso wie der bt-network Dienst, blockiert auch der Agent die Kommandozeile. In diesem Fall ist das aber wünschenswert, weil wir sie für die nötigen Eingaben brauchen werden. Wie schon bei der aktiven Variante, sollte der Pairingprozess relativ selbsterklärend sein.
Da man anscheinend davon ausging, dass gleich mehrere hundert Clients angemeldet werden sollen, beendet sich der Agent nicht selbst, sondern muss via Strg + C terminiert werden (seufz).

Das war’s jetzt schon - fast!

Da wäre immer noch die Sache mit dem Vertrauen. Der NAP Dienst ist nämlich verdammt misstrauisch und lässt absolut niemanden rein, dem er nicht vertraut. Selbst wenn er in Form des Pairings eigentlich schon den Haustürschlüssel hat.

Du kommst hier vielleicht rein. Aber reden tu’ ich deshalb noch lange nicht mit dir!

Also gut, dann müssen wir halt für eine sanfte Annäherung sorgen:

bt-device --set <CLIENT MAC> Trusted True

Damit sollte der Weg jetzt frei sein! - Oder, was jetzt gehen sollte:

Der Server wird auf dem Client als Computer angezeigt. Je nach Betriebsystem, bei mir sind das diverse Androiden, kann man eine Liste der verfügbaren Dienste unter Details anzeigen. Dort gibt es dann auch einen Dienst Namens Internetfreigabe, oder so ähnlich.

Klickt man diese Freigabe an, baut der Client eine Verbindung zum Server auf. Der NAP Server erzeugt ein Ethernetinterface und fügt es der Ethernetbridge hinzu. Von der Bridge aus sollte ein DHCP Server zu erreichen sein, denn der Client wird als nächstes versuchen eine IP Adresse zu beziehen und DNS Server und Gateway zu konfigurieren. Im trivialsten Fall wird das alles der Router erledigen, der die Internetverbindung bereitstellt. Bei Problemen muss also nur überprüft werden, ob die Bridge richtig funktioniert. Wenn das Bridgeinterface selbst über DHCP keine Adresse bekommt und keine Verbindung zum Internet herstellen kann, dass wird dies auch keinem Interface gelingen, das der Bridge hinzugefügt wurde.

In meinem Fall habe ich durch dieses doch recht beschauliche Setup jetzt endlich eine stabile Verbindung mit meinen Mobilgeräten, selbst wenn diese sich im Standby befinden. Verbinde ich mich stattdessen z.B. über WLAN auf den SSH Server meines Tablets, erhalte ich ein Netzwerklag, welches sich in etwa wie eine gestörte GPRS Verbindung verhält, sobald der Bildschirm aus ist.

Bluetooth hingegen bleibt uneingeschränkt performant, hat aber zugegebenermaßen grundsätzlich eine deutlich geringere Durchsatzrate als WLAN und ist damit für größere Downloads und Internetvideos ungeeignet. Dafür hat man aber eine stabile Verbindung die auch ohne Probleme die ganze Nacht übersteht.

HowTo: Android in der Linux KVM

[nggallery id=5]

Vorwort:

[update: dieses HowTo ist alt. Derzeit habe ich kein passendes Image mehr zum Download]

Dieses kleine HowTo richtet sich prinzipiell an Jeden, der einfach mal auf einem PC mit Android rumspielen will, aber selbst nicht die Zeit und Motivation aufgebracht hat, es selbst zum laufen zu bringen. Gründe dies zu tun wären z.B. wenn man selbst kein Andoid Gerät hat, oder nur ein veraltetes, so wie ich und mal sehen möchte, was denn im Lager Google gerade der Stand ist. Auch für Entwickler ist ein Virtuelles System natürlich interessant, weil man bei Experimenten nichts beschädigen kann, was man gleichzeitig im täglichen Gebrauch hat.

Eigeninitiative ist kaum noch nötig, es wird ein Archiv verwendet, in dem ein fertig installiertes Image liegt und ein Shell Skript, welches die KVM mit den nötigen (und richtigen) Optionen startet.

Nachtrag: Obwohl nicht mehr sonderlich viel zu tun ist, gelang es mir nicht, mich kürzer zu fassen, ohne dabei diejenigen zu vernachlässigen, die ggf. etwas mehr Hilfe brauchen.

Warnung / Hinweis:

Dieses HowTo ist wirklich nur für die Linux KVM. Die verwendeten Befehle machen nur unter Linux Sinn und das verwendete Image hat absichtlich keinen Bootblock, da die KVM den Android Kernel selbst bootet.

Warum?

Ich teile hier meinen eigenen Wissensstand, einfach nur weil ich Spaß daran habe und diesen mit Anderen teilen will. Die Worte Windows, VMWare und Spaß kann ich mir nicht in einem positiven Zusammenhang vorstellen, ohne dass nicht mindestens eins davon negiert ist.
Selbstverständlich kann man Android auch virtualisiert unter Windows zum laufen bekommen, aber das interessiert mich nicht und ich werde mich nicht in meiner Freizeit damit beschäftigen.

Motivation:

Möglichkeiten der Virtualisierung gibt es sicher viele und wie es immer so ist, wenn man keine fertige Monokultur vorgesetzt bekommt, sollte man sich zunächst informieren, denn es gibt ebenso viele Möglichkeiten, etwas, sagen wir mal, weniger gut zu lösen.

Weniger gut ist imho die Lösung die Google selbst. Wer den hauseigenen Emulator nutzen will, kommt nicht darum, das Ganze SDK aufzuspielen, eine Zielplattform auszuwählen und diese auch noch zu konfigurieren. Schritte, die für Jemanden, der eher Nutzer als Entwickler ist, alles andere als trivial sind.
Auch die Art, wie Google den Emulator implementiert hat, ist … ungewöhnlich. Normalerweise werden Emulatoren so systemnah wie möglich entwickelt, da sie, als Herzstück der Virtualisierung, entscheidend für die Performanz des Gastsystems sind.
Google schien die Portabilität des Emulators wichtiger zu sein - sie verwendeten Java. Mehr müsste man eigentlich nicht sagen. Ich fasse dennoch zusammen:
Ein Emulator, der in Java geschrieben ist, emuliert ARM Hardware, auf der Java läuft.
WTF!!!
Zumindest auf meiner bescheidenden Hardware ist das Konzept unbenutzbar und produziert auch nach mehreren Minuten nur eine Menge warme Luft aus dem Gehäuse, bevor dann endlich eine elendig lahme Oberfläche kommt.

Ansatz:

Auf meiner Suche nach einer brauchbaren Alternative, stieß ich auf das Projekt
Android x86. Deren primäres Ziel ist es zwar, Android auf physikalisch existierende PC Hardware zu bringen, aber schließlich ist es auch primäres Ziel einer guten Virtualisierung, physikalisch existierende Hardware möglichst nah und performant abzubilden.
Tatsächlich finden sich auch einige, leider zu kurze und veraltete, Tutorials für die Virtual Box. Warum sie gerade die verwenden, wird nirgendwo erwähnt, aber ich gedenke ja auch nicht, mich für die Präferenz der KVM zu rechtfertigen.
Also Android auf einer x86 KVM. Nun kommt natürlich die Frage:

Andoid auf x86? Ist das nicht für ARM entwickelt? Funktioniert das?

Zumindest die letzte Frage kann ich direkt und präzise mit Ja *beantworten. Wäre dem nicht so, würde ich dazu kein HowTo schreiben. Bei der zweiten Frage, wird es schon schwieriger.
Generell wurde Android für die Dalvik VM entwickelt. Diese ist im Gegensatz zu z.B. der OpenJRE eine Stack orientierte Maschine und keine Registermaschine. - Hä? - Irrelevanzinformation.
Soll heißen: Das meiste von und für Android sollte Plattformunabhängig sein.
*
Sollte
.
Wäre dem 100%ig so, würde Google kein NDK (native development kit) bereitstellen. Zunächst ist natürlich ohnehin Alles erst mal bis zum Start der Dalvik VM native Linux. Das kann man in jeder brauchbaren Umgebung, für nahezu jede weiter verbreitete Hardware, kompilieren und so hat es das Android x86 dann auch gemacht.
Effektiv scheitern werden wir bei einigen Paketen also nicht an der Hardware, sondern am Paketmanagement von Android selbst. Dieses kennt nur komplette Zielgeräte und die Kompatibilitäten dazu einzustellen, ist den Entwicklern überlassen. So kommt es, dass es Pakete gibt, die angeblich überall funktionieren, dann aber doch ein paar entscheidende Brocken native ARM Code enthalten, der dann wortlos einfach nicht funktioniert.
Bei meinen ersten Versuchen, war das noch ein ärgerliches Problem. Die von mir jetzt eingesetzte Version enthält ein paar Librarys von Intel, die notfalls einspringen und den ARM Code, meist erfolgreich, laufen lassen. Wir erinnern uns: Es gibt jetzt auch Android Tablets mit Intel Atom Prozessoren.
Des Weiteren ist noch ein Ethernet Patch dabei, der für die nötige Unterstützung des Netzwerkinterfaces sorgt.
Leider ist die Dokumentation von Android x86 etwas veraltet, was die Virtualisierung angeht - fertige Images gibt es entweder undokumentiert generisch, oder ebenso undokumentiert für diverse Laptops. Welche Hardware die KVM nun verwenden soll, ist daher ein langweiliges ausprobieren, welches ich euch gerne ersparen würde. Die Virtuelle Soundkarte, welche funktioniert, hat zwischen den beiden Images, die ich jetzt verwendet habe, gewechselt und in beiden Fällen war es nicht die, die im Virtual Box HowTo des Projekts empfohlen wird.

Ja, Ja - Los jetzt! - Setup:

Benötigt wird:

  • Die KVM
  • Dieses Archiv mit dem Image
  • XZ um es zu entpacken (entschuldigt die Bandbreite schonende Unannehmlichkeit)
  • ein echtes Netzwerkkabel (am Netz, bitte)
  • eine virtuelle Ethernet Bridge
  • das Usermode Ethernet Interface tap0 für die KVM
  • das Paketmanagement deiner Wahl um evtl. hiervon fehlende Pakete zu installieren
    Die Anweisungen zur Paketinstallation beziehen sich im Folgenden auf Ubuntu. Die Pakete sollte aber auch auf anderen gängigen Distributionen verfügbar sein. Falls der Paketname nicht stimmt, nicht gleich entmutigen lassen, sondern einfach nach dem Befehl suchen.
    Ich verwende den simplen Befehl apt-get. Selbstverständlich kommt man auch mit aptitude und synapticzum Ziel. Anfängern empfehle ich synaptic. Das ist übersichtlich und grafisch, arbeitet aber langsamer, da es unter der Haube so einiges werkeln muss, um diesen Luxus zur Verfügung zu stellen.
    Für Distributionen die nicht von Debian abstammen, fallen mir noch emerge und yast ein, Letztes kenne ich nur noch rudimentär, Ersteres gar nicht. Normalerweise sollte ein grafischer Desktop irgendwo eine Paketverwaltung anbieten. Genug dazu.

KVM:

Die KVM sollte installiert sein. Wer noch nie damit gearbeitet hat, muss sich nicht fürchten, ein passendes Startskript ist dabei. Falls die KVM noch nicht installiert ist hilft hier:

sudo apt-get install kvm

das wars dazu auch schon.

Image:

Spätestens jetzt ist es an der Zeit, das Archiv zu laden. Bitte irgendwo speichern, wo Du es nachher wieder findest. Downloads ist nur eine beschränkt gute Idee, da das folgende Kommando es genau dort hin extrahieren wird.
Die ISO zur Installation habe ich übrigens von www.android-x86.info geladen. Die Installation habe ich Euch soweit erspart und bis zum ersten Boot selbst vorgenommen. In den Bootoptionen der KVM wird eine zweite Partition für eine SD-Karte übergeben. Einige Apps hätten gerne eine Solche.
Der Installer von Android x86 stellt sich dabei aber gerne quer, oder will unbedingt ein Fileimage dafür anlegen. Ein Fileimage in einem Fileimage ist schon fast ein bisschen wie Java auf ARM, dass von Java emuliert wird.
Ich würde gerne den Author der ISO, Ron M. dafür verlinken, finde ihn aber nicht.

Auspacken:

XZ ist der Nachfolger von LZMA, oder kurz, der meines Wissens nach der effizienteste momentan in der Open Source Welt verfügbare Packer. Er darf auch gerne nach dem Extrahieren wieder entfernt werden.
Falls du kein XZ hast:

sudo apt-get install xz-utils

Wenn Dein distributionseigenes tar xz unterstützung hat, reicht nun ein:

tar xvJf <Pfad zum Archiv>

ansonsten

xzcat <Pfad zum Archiv> | tar xv

Das Netzwerk:

Hier gab es jetzt zwei Möglichkeiten. Die KVM kann sich von Haus aus so verhalten, als wäre das Gastsystem in einen Router eingestöpselt.
Ich habe mich gegen diese Möglichkeit entschieden, weil damit Andoid in einem virtuellen Netzwerk eingesperrt wäre, aus dem es zwar raus kommt, weil die KVM die Internen IP Adressen übersetzt und weiterleitet - wie ein Router ins Internet weiterleitet (NAT) - aber man kommt aus dem lokalen Netz nicht rein. Mit meinem Setup erhält Android eine eigene IP Adresse aus dem selben Netz, welches auch der Host Rechner verwendet. Das ist für Debugging, Entwicklung und eigentlich überhaupt prinzipiell so ziemlich Alles besser.
Der Haken:
Das funktioniert nicht mit WLAN. Es sei denn man verwendet einen Router welcher WDS unterstützt und dafür richtig konfiguriert ist (was nur komische Leute wie ich machen). Dann müsste man die virtuelle Bridge und das WLAN Interface des Host Rechners (wenn es überhaupt WDS kann) aber auch noch dafür konfigurieren.
Muss nicht sein, oder?
Ohne WDS wird jedenfalls kein Paket vom WLAN-Router das Gastsystem erreichen, weil dieser immer direkt an den Zielrechner Adressiert. Die WLAN Schnittstelle gehört aber dem Host.
Nimmt man stattdessen ein Kabel, kommen Pakete für den Gast über die Bridge auch direkt ohne Umwege beim Gast an.
Da wir uns jetzt für ein Kabel entschieden haben, können wir ja weiter machen.

Die Bridge:

Die Ethernetbridge ist nun keine besondere Zauberei, sondern genau das, was heutzutage in so ziemlich jedem Router die Pakete zwischen Kabel und Kabellos verteilt. Sie verbindet physikalisch getrennte Netzwerke miteinander, indem sie auf allen Anschlüssen lauscht wer redet und dann ggf. Pakete von einer Seite auf die andere weiterreicht, wenn die Parteien hinter verschiedenen Netzwerkschnittstellen sind.
Ob dies nun wirkliche Netzwerke sind, oder nur ein virtuelles, wie bei der KVM, ist der Bridge dabei egal. Wie praktisch.

Wer die Ethernet Bridge nicht installiert hat, holt das mal eben schnell nach:

sudo apt-get install bridge-utils

Der Einfachheit halber erstellen wir auch gleich ein Interface und fahren es hoch.

sudo brctl addbr br0
sudo ip li se up br0

Den Syntax des ip Befehls lässt sich in der Regel auf zwei Buchstaben verkürzen und ist daher etwas gewöhnungsbedürftig. In älteren Distributionen gehört er noch nicht zur Standardausrüstung. Alternativ kann ifconfig verwendet werden.

ifconfig br0 up

Das ist in diesem Fall sogar kürzer, der Befehl ist aber nicht so universell einsetzbar und wird von mir daher nur noch selten verwendet. Falls Du ip nicht hast, kannst du jedes Auftreten mit ifconfig ersetzen. Für etwas Anderes, als zum Hochfahren von Interfaces, werden die Befehle in diesem HowTo nicht gebraucht.

Das TAP Interface:

Dieser Abschnitt könnte mehr oder weniger überflüssig sein, denn die KVM kann selbst ein TAP Interface richtig konfigurieren und verwenden. Das kann sie aber nur, wenn sie die nötigen Rechte dazu hat d.h. die KVM die ganze Zeit als ROOT läuft.
Da wir der KVM aber nur so viele Rechte wie eben nötig geben wollen, stellen wir dieses Interface selbst bereit. Dazu brauchen wir die uml-utilities.

 sudo apt-get install uml-utilities

Genauer gesagt, den Befehl tunctl.

sudo tunctl -u <dein Username>

Das System sollte Dir jetzt bestätigen, dass es das Interface tap0 für Dich angelegt hat. Das Besondere daran ist, dass es nun auch mit deinen Nutzerrechten verwaltet werden kann. Solltest du nicht tap0 bekommen haben, existiert es vermutlich schon, weil du selbst Etwas damit machst und ohnehin genau weist was du tust.
In dem Fall brauchst Du diesen Abschnitt wohl nicht. Vergiss dabei bitte nicht, dass ich davon ausgehe, dass wir mit tap0 arbeiten.
Das Hochfahren auch nicht vergessen.

sudo ip li se up tap0

Die Netzwerkkonfiguration:
Nun wird es etwas kniffeliger. Bis jetzt haben wir mit Netzwerkschnittstellen rumgefummelt, die der automatischen Netzwerkverwaltung relativ egal sind, solange Niemand etwas für sie angelegt hat. Das ändert sich nun.
Daher muss jegliche automatische Netzwerkverwaltung abgeschaltet werden. Dies kann und wird Deine Internetverbindung trennen, wenn auch nur temporär.

sudo stop network-manager

Dieser Befehl könnte unter Umständen sehr ubuntuspezifisch sein. Alternativen kann ich für andere Distributionen leider nicht anbieten, da ich nicht weis, wie die ihr Netzwerk konfigurieren.
Auch die Netzwerkschnittstelle eth0, mit der ich die KVM verwenden will, wurde hierdurch dekonfiguriert und heruntergefahren. Also muss sie zunächst wieder hochgefahren werden. Wenn Deine primäre Netzwerkschnittstelle für Kabel Ethernet nicht eth0 ist, gehe ich wieder mal davon aus, dass Du die erforderlichen Änderungen selbst nachvollziehen kannst.

sudo ip li se up eth0

Die Schnittstellen müssen nun genau in dieser Reihenfolge in die Bridge integriert werden, denn die Ethernetadresse der Bridge wird sich in den meisten Fällen nach dem Interface richten, welches als Erstes hinzugefügt wurde.

sudo brctl addif br0 eth0
sudo brctl addif br0 tap0

Das würde jetzt für die KVM ausreichen, um sich ins Netz zu integrieren, nur wäre es ja auch ganz schön, wenn das Host System auch wieder Netz hätte. Dazu fehlt nur noch eine IP Adresse. Wir benutzen jetzt aber nicht mehr die Netzwerkschnittstelle direkt, sondern die Bridge.

sudo dhclient -v br0

Dabei gehe ich natürlich davon aus, dass das Netz DHCP verwendet. Wenn das nicht der Fall ist, sollte Derjenige, der das abgeschaltet hat, auch wissen, was zu tun ist.

Der erste Start:

Hierfür reicht es, kvmstart.sh im Verzeichnis auszuführen, wo das Archiv extrahiert wurde.

. kvmstart.sh

Ja, richtig gesehen. Das beginnt mit einem Punkt. Alternativ wäre auch source möglich gewesen. Ich wollte nur vermeiden, für eine Zeile eine Shell in der Shell auszuführen, die die KVM ausführt. Muss ja nicht sein.
Das wäre es dann auch endlich von meiner Seite aus. Die KVM sollte starten und Android wird Dich nach Deinem Google Account usw. fragen. Vorher muss noch eben bestätigt werden, dass der Wizard für die Systemanmeldung verwendet werden soll. Durch die Anmeldung kann die KVM wie ein reguläres Android Device verwendet werden. Pakete können also bequem über den Play Store installiert werden, der allerdings bis zum ersten Update noch Google Market ist.

Hinweis:

Die KVM wird den Mauszeiger einfangen, da diese einfache Version der Konfiguration eine Maus emuliert. Den sog. Mausgrab verlässt man mit Strg + Alt.
Wer davon genervt ist, kann durch das Anfügen der Optionen -usb -usbdevice tablet an die KVM Kommandozeile in kvmstart.sh auf ein virtuelles usb Tablet wechseln. Die Maus verlässt dann das Fenster, sobald sie am Bildschirmrand ankommt.
Abschließend sei erwähnt, dass die Grafik geringfügig beschleunigt werden kann, wenn man die KVM stattdessen mit VNC Display Ausgabe arbeiten lässt. Dann braucht man natürlich auch ein VNC Viewer um die Anzeige sehen zu können. Mehr dazu, falls jemand danach fragt.

Zoix

Wenn ich mich gerade so in meinem Zimmer umsehe, fühle ich mich gezwungen, den Begriff Zoix an dieser Stelle zu definieren.

Zoix, exolenter Sprachgebrauch, ist abgeleitet vom deutschen Begriff Zeug. Ungleich dem Stammwort, hat Zoix eine stark negative Vorbelegung. Es wird vermutet, dass diese Bedeutungsdrift durch den aktiven Sprachgebrauch entstand. Besonders die abgewürgt hervorgebrachte Endung auf x, drückt starken Unwillen aus.

“Muss ich mich jetzt mit diesen Zoix auch noch beschäftigen?”

Zu beachten ist dabei, dass Zoix eine weniger deutlich und weniger gegenstandsbezogene Nutzung haben kann, als das Stammwort.

Der Begriff kann sowohl analog zum Stammbegriff verwendet werden,

“Woher kommt all das Zoix, was hier schon wieder rumliegt?”

als auch Handlungen

“Nicht heute, ich hab noch ‘ne Menge Zoix zu erledigen.”

und insbesondere geistiges Eigentum.

“Was schreibt der eXo denn da schon wieder für ein Zoix.”

Für den korrekten Wortgebrauch ist grundsätzlich die sog. scheinbare Überflüssigkeit Grundvoraussetzung.

Als Zoix werden typischerweise auch besonders Alltagsgegenstände bezeichnet, die während einer längeren Tätigkeit nur kurz erforderlich sind, aber die Abart besitzen, nach Gebrauch nicht selbstständig und sortiert an ihren Ursprungsort zurückzukehren.
(Sonderform: Werkzoix)
Diese Gegenstände sammeln sich am Ort des Wirkens in immer größeren Mengen an, obwohl sie nicht benötig werden.

Daher hat Zoix die Eigenschaft, ganz allgemein Fortschritt zu behindern. Das Auftreten von Zoix hat zur Folge, dass Ressourcen belegt werden, die ohne Zoix sinnvoller genutzt werden könnten. In diesem Sinne wird Zoix häufig als Abfallprodukt des menschlichen Wirkens gesehen, unterscheidet sich aber von gewöhnlichem Abfall dadurch, dass es generell nicht entsorgt werden darf, sondern durchaus noch einen nicht zu vernachlässigenden Wert hat.

Zoix erfordert stattdessen die Aufwendung weiterer Ressourcen (meist Zeit) um die, von ihm nur temporär belegten, Ressourcen wieder nutzbar zu machen. Seine blockierende Eigenschaft wird meist als grundlegend falsch empfunden und ruft deshalb den Unwillen hervor, sich überhaupt mit Zoix zu beschäftigen. Diese Eigenschaft wird dadurch noch verstärkt, dass Zoix grundsätzlich einen Handlungsablauf unterbricht (interruptive Eigenschaft).

Wissenschaftliche Untersuchungen erklären diese Eigenschaft dadurch, dass es unmöglich ist, Zoix parallel zu verarbeiten. Eine Serialisierung der wünschenswerten Handlung mit der notwendigen Handlung, zu Ungunsten der wünschenswerten Handlung, ist unumgänglich.

Die schlimmste Form von Zoix ist das sog. Hyperzoix. Es erfüllt die Kriterien des Zoix **in mehreren Ebenen und ist fachlich gesehen vielfach interruptiv.

Ein Beispiel hierfür wäre eine Tiefkühlpizza auf einem Toilettendeckel. Selbst nach Auflösung des ersten Interruptivs, verliert die Tiefkühlpizza den zoixigen Charakter nicht, da sie weiterhin nutzlos ist.

Erst nach der Zubereitung im Backofen steht sie zum Verzehr bereit und wird zum sinnvoll nutzbaren Gegenstand des täglichen Lebens. Schon die Zubereitung generiert aber schon wieder neues Zoix. Es ensteht leere Verpackung und Abwasch. Der angestrebte Zustand der Zoixfreiheit ist erst wieder hergestellt, wenn die Verpackung entsorgt wurde, das Geschirr abgewaschen und wieder in den Schrank geräumt wurde.

Die allgemeine Auflösung der von Zoix verursachten Ressourcenverklemmung bezeichnet man auch als Entzoixigung.

Das obige Beispiel wurde nicht willkürlich gewählt. Nahrung und Nahrungsaufnahme sind Gegenstände und Vorgänge, die von Natur aus ein sehr hohes Zoixniveau aufweisen.

Eine utopische Gesellschaft sollte, nach derzeitigem Stand der Wissenschaft, ihren Fokus auf die Entzoixigung jeglicher Prozesse richten. Paradoxerweise kann dies dadurch erfolgen, dass einzelne Individuen die Entzoixigung zu ihrem Beruf machen.
Es konnte bewiesen werden, dass die aktive Beschäftigung mit Zoix, in einem ununterbrochenen Prozess, zoixartige Ressourcenverklemmungen für Dritte Auflösen kann.

“Des Einen Zoix, des Anderen Freud.”

Als Beispielhaft für diesen Prozess sind Fastfoodketten hervorzuheben, die bereits in unserer heutigen, sehr z_oixlastigen_ Gesellschaft, einen großen Beitrag zur Entzoixigung leisten.

Charset Wars & 'fdupes'

Mein heutiger Tag stand ganz im Zeichen dessen, was ich in leicht ironischer weise Charset Wars getauft habe. Ursache des ganzen ist eine Fernstersfreigabe, auf die offensichtlich mit verschiedenen Fenstersversionen und auch Apfelgeräten zugegriffen wird. Das wäre ja auch alles ganz wunderbar (weil es überhaupt funktioniert), wenn all diese Geräte nicht der Meinung wären, mit ihrem lokalen Charset die Weltherrschaft anstreben zu müssen. UTF8 scheint hier noch nicht eingezogen zu sein.

Den Server interessiert das erst mal gar nicht. Er schreibt die Zeichenketten einfach so hin, wie er sie erhält und das ist dann eben der Dateiname. Wer das gleiche Charset hat, der hat halt Glück.

So war es nicht weiter verwunderlich, dass ich haufenweise Kopien der gleichen Dateien fand, die sich nur in unterschiedlich vermurksten Sonderzeichen in ihren Dateinamen unterschieden.

Für die Nutzer kam mit Fensters95 eine bisher nie da gewesene Freiheit. Plötzlich durften sie Dateinamen in gefühlt unbegrenzter Länge verwenden und sie sogar mit Leer- und Sonderzeichen durchsetzen.
In der Monokultur derer, mit denen man sporadisch Daten tauschte, fiel lange Zeit niemandem auf, dass die Hersteller heimlich nebenher, nach unterschiedlichen Rezepten, in vielen Töpfen kochten.

Der viel zu spät erfundene Einheitsbrei Namens UTF8 hat sich bis heute in vielen Küchen noch nicht durchgesetzt, oder man muss dem lokalen Koch per Hand die Rezepte vertauschen. So kommt es halt, dass ein Koch, der mit einem fremden Rezept kocht, aber die Zutaten nicht kennt, schon mal etwas den Geschmack verfehlt.

Genug der kulinarischen Analogien. Teilweise war es mir nicht möglich, herauszufinden, welche Charsets für die kryptischen Zeichen verantwortlich waren, die mein UTF8 mir da bot. Selbst wenn ich es gekonnt hätte, wäre nicht einmal das von Nutzen gewesen, da die Namen selbst in einzelnen Verzeichnissen unterschiedlichen Charsets entsprangen.
Keine Change, da mit skripten und Charsetkonvertern wie iconv oder recode etwas zu werden.

Letztendlich muss mich das auch nicht weiter stören. Die Mission, die Nutzer davon zu überzeugen, einfach keine Sonderzeichen zu verwenden, weil ihre lokalen Charsets dann irrelevant wären, habe ich seit langem aufgegeben.
Datenblätter sehen offensichtlich einfach viel schöner aus, wenn sie nicht Datenblaetter heißen.

Was mich als Admin aber stört, ist wenn verschiedene Nutzer die gleiche Datei mit lediglich unterschiedlichen Sonderzeichen in den Namen auf die Freigabe kopieren. Besonders, weil die Verlockung viel zu groß ist, an seiner eigenen Datei zu werkeln und sich dann bei mir zu beschweren, dass man die Änderungen der Kollegen nicht sehen kann.
Wie denn auch? Der Kollege hat eine andere Datei geÀndert!

Bei der Suche nach einem Programm, welches mir schnell und schmerzlos diese Dubletten identifiziert stieß ich auf fdups. Dieses nette kleine Programm ist nicht nur in der Lage, doppelte Dateien per Hash zu identifizieren, sondern auch wahlweise bei jedem Satz n-facher Kopien zu fragen, welche davon behalten werden soll.

Da ich keine Lust hatte, das für buchstäblich hunderte Dateien zu entscheiden (und damit womöglich jemanden wegen seines Charsets zu diskriminieren), entschied ich mich stattdessen für eine noch praktischere Variante: Alle Namen zu Hardlinks auf die selben Daten zu machen.
Dadurch verwenden jetzt alle Kopien den gleichen Speicherplatz, es wird also nichts mehr verschwendet, dennoch bleiben die Namen erhalten. Falls man sich später mal auf einen kompatiblen Namen einigt, können die Kopien einfach gelöscht werden. Der Festplattenspeicher wird erst freigeben, wenn der letzte Link gelöscht wird und es ist sicher gestellt, dass auch wirklich alle mit den gleichen Daten arbeiten.

Selbstverständlich habe ich eine Liste der Kopien bereitgestellt und über den Sachverhalt informiert und genauso selbstverständlich sind davon auch keine gewollten Sicherheitskopien betroffen.
Das wäre ja auch kontraproduktiv.