Wireless Roaming: Ubiquiti UniFi AP AC Lite vs. UniFi AP vs. Apple Airport Extreme / Express

In meinem Haus gibt es überall Ethernet, aber nicht überall WLAN. Das ist ärgerlich, kein Router schafft es, das ganze Haus alleine auszuleuchten. Getestet bisher: FritzBox 7270, Telekom Speedport Hybrid, Apple Airport Extreme, Ubiquiti UniFi AP LR, TP-Link 741.

Ich möchte aber im ganzen Haus ordentliche Bits haben und handle mal kurz ab, wie ich versuche zu einer Entscheidung zu kommen.

Die naheliegende Lösung

fritzboxTL-WR841ND

Man rennt los und holt sich einen zweiten Access Point. Diese wird mit gleichen Einstellungen (ESSID, Kanal, Passwort) als Bridge zwischen LAN und WLAN betreiben. Das Problem an der Sache: die mobilen Clients „kleben“ an ihrem Access Point. Wenn man sich durch das Haus bewegt, wird die WLAN-Verbindung immer schlechter. Der Client hängt dann vielleicht mit 1MBit am Access Point in der oberen Etage und schafft kaum ein Paket zu empfangen, während man mit ihm neben dem Access Point in der unteren Etage steht. Schon fast reflexartig knipst man dann das WLAN am Mobiltelefon aus und wieder an, damit der nähere Access Point gewählt wird. Das ist nervig.

Die politisch inkorrekte Lösung

WLAN-Repeater kommen für mich prinzipbedingt nicht in Frage:

  • Die Daten sind doppelt in der Luft, die Bandbreite leidet (gute Repeater können auf zwei Bändern funken und werden beim repeaten wenigstens nicht langsamer).
  • Repeater machen „Magie“. Sie müssen tricksen und machen so eine Art NAT auf Layer 2, jeder Hersteller kocht da seine eigene Suppe. Disclaimer: dieser Punkt ist gefährliches Halbwissen, was ich nebenbei aufgeschnappt habe, in meinem Kopf blieb lediglich haften: Repeater sind grundsätzlich scheiße. Sie mögen funktionieren, sind aber immer noch der schlechteste Kompromiss.
  • Es wiederspricht meinem gesunden Menschenverstand: ich habe überall Gigabit LAN, Daten gehören ins Kabel, nicht in die Luft

Die teure Lösung

airport_extreme
airport_express

Weil ich beruflich bedingt, aber auch sonst Apple-Fanboy bin, habe ich mir eine Airport Extreme geklickt. Dazu gibt es noch eine Airport Express für die untere Etage. Die Hoffnung ist, dass hier Roaming funktioniert. Die Airports sind sehr teuer, haben wenig Optionen und wollen alles für einen regeln. Leider musste ich feststellen, dass es (in meinem Netzwerk) nicht möglich ist die beiden Geräte kabelgebunden zu betreiben. Sobald beide Geräte am LAN hängen, geht gar nichts mehr: die WLAN-Verbindung an meinem Notebook bricht ständig zusammen, Paketverluste ohne Ende und natürlich kein Log, keine Info, keine Fehlermeldung – Apple halt.

Ich habe die beiden Airports dann so betrieben, dass die Express benutzt wurde um das WLAN der Extreme zu vergrößern (das scheint eine Art WDS oder Repeater-Funktion zu sein). Diese „Range-extender“-Lösung funktioniert soweit ganz gut. Ich kann zumindest durchs Haus laufen und i.d.R. hängt mein Telefon am „richtigen“ Access Point und hat eine gute WLAN-Verbindung.

Es ist jedoch irgendwie unbefriedigend, weil die Daten der Airport Extreme immer zweimal durch die Luft gehen, obwohl in unmittelbarer Nähe eine LAN-Dose zur Verfügung steht.

Die „richtige“ Lösung

ubiquiti_uap_ac_liteubiquiti_uap_ac_lite

Natürlich gibt es auch eine „richtige“ Lösung: Managed WLAN mit einem WLAN-Controller. D.h. eine Instanz im LAN spricht mit allen Access Points und kann entscheiden, welcher Client an welchem Access Point hängen sollte. Das Roaming zwischen den Access Points ist die hohe Kunst.

Es gibt dafür sehr teure Lösungen und es gibt etwas von Ubiquiti. Also habe ich mir zwei UniFi AC Lite Ufos geklickt. Das Paket war noch nicht ausgepackt, da chattet mich Kollege S. an. Er hat das gleiche Problem (große Wohnung, viel LAN, wenig WLAN) und hat festgestellt, dass Zero-Handoff scheinbar nicht mit AC-Geräten von Ubiquiti funktioniert. Wenn man danach googelt ist man nicht schlauer, in den Foren des Herstellers gibt es seitenlange Threads aus denen hervor geht, dass Zero-Handoff mit AC-Geräten möglicherweise nie funktionieren wird. Gründe dafür findet man aber nicht.

Was tun? Genau: nachmessen.

Der große Showdown

Ich habe zu testzwecken noch zwei Ubiquiti UniFi APs geklickt. Die können „nur“ 802.11n auf 2.4GHz. Das ist für meine Anwendung aber ausreichend (Twitter muss auf dem Klo funktionieren). Große Datenmengen schiebe ich am LAN-Kabel durch die Gegend und in der Praxis ist dann 802.11ac auch nicht sooo viel schneller.

Mein Benchmark ist: welche Geräte schaffen sauberes WLAN-Roaming? Ich möchte also durchs Haus laufen und möglichst immer Netz haben.

Die gewählte Messmethode ist hochwissenschaftlich: ping. Ich pinge 10x pro Sekunde mein Telefon an und laufe damit immer wieder die gleiche Strecke durchs Haus. Wenn ich unten in der Küche angekommen bin, wechselt das Telefon zum unteren AP. Auf dem Weg nach oben erfolgt ebenfalls nochmal ein Wechsel des Access Points. Damit das ganze etwas aussagekräftiger wird, wiederhole ich die Messung drei Mal. Dann teste ich noch verschiedene Paketgrößen: 56, 504 und 1492 Bytes.

Nachdem ich also 36 Mal durch das Haus gewandert bin und unter den irritierten Blicken der Familie Zahlen murmelnd wieder verschwunden bin kann ich folgendes verkünden:

Size UniFi AP UniFi AP ZH UniFi AC Airport
56 0,48% 5,66% 5,40% 5,63%
504 2,40% 5,61% 2,63% 12,51%
1492 5,01% 11,28% 17,42% 28,18%

wlan_showdown

In Worten bedeutet es, dass die Airports am meisten Pakete verlieren, wenn ich durchs Haus gehe. Die UniFi APs verlieren am wenigsten und die UniFi AC sind irgendwo dazwischen. Interessanterweise performt der UniFi AP mit eingeschaltetem Zero-Handoff schlechter. Die besten Ergebnisse bringt der UniFi AP ohne Zero Handoff.

Damit ist Entscheidung nicht einfacher: Zero Handoff funktioniert scheinbar nicht wirklich, außerdem muss man sich auf einen Kanal festlegen und hat nur noch die halbe 802.11n Bandbreite (HT20). Nachdem ich die ganze Messung durchgeführt habe, grübel ich schon wieder, was wichtiger ist: nahtloses Roaming (was es so nicht gibt) oder gute Bandbreite an einem bestimmten Platz im Haus (die ich eigentlich nicht benötige).

Disclaimer

  • Das Ergebnis ist nur für meine Situation anwendbar. Jedes Haus, jede WLAN-Umgebung ist anders.
  • Es ist natürlich etwas unfair, weil die Airport Express nicht am LAN hängt. Die Datenmenge ist viel zu klein und das ganze Vorgehen ist höchst unwissenschaftlich. Ich bin halt Praktiker 😉
  • Jolly hat vor einem Jahr die Performance der UniFi APs viel genauer nachgemessen und festgestellt, dass es bei den Geräten Dropouts gibt. Das war nicht Teil meiner Untersuchung. Möglicherweise gibt es inzwischen einen Fix in der UniFi Firmware für das Problem. Ich konnte bisher keine Probleme feststellen. YMMV.

Telekom Speedport Hybrid: Logging mit rrdtool

Als internetsüchtiges Landei greift man ja jedem Strohhalm, den man zu fassen bekommt. Ich hatte vor gut zwei Jahren zusätzlich zu unserem „normalen“ DSL-Anschluss der (je nach Tagesform) 10-14MBit/s bring noch einen LTE-Anschluss geklickt.

Das Problem an der Sache: bei zwei Uplinks man muss den Traffic intelligent routen. Eigentlich soll alles über LTE abgewickelt werden, aber man definiert dann unzählige Ausnahmen um möglichst keinen teuren LTE-Traffic zu vergeuden. Manche Dienste lassen sich auch schwer anhand von IPs und Ports in Filter gießen. Selbst mit viel Gefummel und Gehirnschmalz reichen dann 30GB für zwei Werktätige im Homeoffice eigentlich nicht aus.

Zum LTE-Vertragende wurden Hybrid-Anschlüsse bundesweit verfügbar. Das ist genau was ich eigentlich will: höhere Geschwindigkeit ohne Volumenlimit und mehr Redundanz, das alles ohne Fummelorgie in pf bzw. iptables. Einzig der Rant von Clemens in der Freakshow hat mich davon abgehalten sofort zuzuschlagen. Sein Fazit: das Produkt ist gut, aber der Router ist scheiße.

Nun habe ich einen Speedport Hybrid im Haus und kann diese Meinung vollumfänglich bestätigen. Das Webinterface des Routers ist eine Beleidigung. Javascript-Foo ohne Ende, es nervt mit unwichtigen Dingen wie Telefonie und diversen „Sicherheitsfeatures“. Man kann zeitgesteuert WLAN und Internet abschalten (ein sehr deutsches Feature), dafür kommt man aber an wichtige Informationen wie verbrauchter Traffic oder CRC-Fehler nicht ran. Das Webinterface warnt den User, wenn von einem weiteren Client darauf zugegriffen wird und ist auch sonst in jeder Hinsicht ein Usability-Verbrechen.

Her mit Deinen Daten!

Es gibt ein verstecktes „Engineer“-Menü, das viele Daten bereitstellt, die ich gerne hätte: Paket-Zähler der Interfaces; Dämpfung, SNR, CRC-Fehler und Bitrate auf der DSL-Leitung, Empfangsqualität des LTE-Signals ect.

Telekom Speedport Engineer Menu

Diese Daten wollte ich haben und mit rrdtool visualisieren. Dann hätte ich einen „DSL-Wetterbericht“ und weiß, wie es meinem Anschluss geht. Leider muss man sich jedes Mal auf dem Webinterface einloggen und dann die Engineer-URL in den Browser pasten.

Das ganze kann man schlecht automatisieren, solche Trümmer wie Selenium wollte ich nicht gleich auffahren. Ich habe mir deswegen zwei Sachen näher angeschaut:

  1. Die Firmware. Vielleicht gibt es noch einen einfachen Weg: es könnten durchaus Klartextscripte (lua?) in der Router-Firmware zu finden sein, die Rückschlüsse auf die Datenquellen zulassen.
  2. Die Kommunikation beim Login und das involvierte Javascript.

Die Firmware des Routers gibt es bei der Telekom zum Download. Mit Tools wie dem Firmware Modification Kit und binwalk kann man in das Image reinschauen und findet folgendes vor:

Target File: Firmware_Speedport_Hybrid_v050124.01.00.057.bin
MD5 Checksum: 086f589676e2cf108e755c2f0ad34649

DECIMAL HEX DESCRIPTION
----------------------------------------------------
132615 0x20607 JFFS2 filesystem, big endian
31098175 0x1DA853F PNG image, 488 x 2, 8-bit colormap, non-interlaced
31098375 0x1DA8607 JFFS2 filesystem, big endian
45205479 0x2B1C7E7 gzip compressed data
53720703 0x333B67F gzip compressed data
56458441 0x35D7CC9 gzip compressed data
56493219 0x35E04A3 gzip compressed data
66090195 0x3F074D3 gzip compressed data

Interessant: das Image enthält mehrere Firmware-Images: neben der für den „normalen“ Router gibt es noch ein vxworks-Image für den LTE-Teil des Routers. Die anderen Images konnte ich nicht genauer zuordnen, „mein“ Image ist mit 30MB das größte und lässt sich einfach mit dd rauskratzen. Das Image ist ein JFFS2 Image und ich konnte es auch mit viel googeln und fluchen nicht mounten. An der Stelle musste ich erstmal aufgeben und einen anderen Weg suchen.

well … SECURITY!

Zwischen Router und Browser wird http gesprochen, man kann also einfach mit Charles oder Wireshark den Traffic analysieren. Früher hatten andere Speedport Router ein HTTPS-Webinterface. Das hatte aber nicht nur Vorteile:

Es spricht viel dafür, dass das HTTP-only Webinterface ein Resultat der oben geschilderten Probleme ist.

Ab in das JavaScript-Schlammbad!

Also Augen zu und durch! Der interessante Code steckt in http://speedport.ip/js/pages/login.js. Als Beifang springen zwei Dinge sofort ins Auge:

if(getVar(data, "isEngineerPassword")) {
    document.location.href = "/engineer/html/dsl.html";
    log.info("Login successful.");
}

Offenbar gibt es ein Standardpasswort für Servicezwecke. Entweder ist das Passwort statisch oder es lässt sich aus der Telekom verfügbaren Daten ableitet (IMEI oder Seriennummer …).

[Update] Ich habe in einem meiner vielen Telefonate mit der Telekom Störungsstelle einem Mitarbeiter die Information abgerungen, dass es nur ein hart codiertes Engineer-Password gibt … 🙁 [/Update]

Die Statusseite unter http://speedport.ip/html/login/status.html?lang=de ist ohne Login zugänglich und könnte den notwendigen Input liefern.
Insgesamt ist das schon gruselig, dass mein Provider meinen Router umkonfigurieren kann und ich nicht in der Lage bin es zu verhindern.

Ein weiteres interessantes Fundstück findet sich hier:

if (showpass) {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
else {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}

Offensichtlich findet beim Hersteller der Firmware kein Code-Review statt.

Die Speedport Login Prozedur

Damit trotzdem niemand das Router-Passwort mitlesen kann, unternimmt das Webinterface einen unglaublichen Eiertanz. Das Vorgehen ist vermutlich aus einem Crypto-Playbook, so ähnlich funktioniert auch der Login bei einigen Musikstreamingdiensten.

Zuerst sendet der Browser das hier zum Router:

POST /data/Login.json?lang=en HTTP/1.1
Content-Type: application/x-www-form-urlencoded

csrf_token=nulltoken&showpw=0&challengev=null

Mit diesem Request wird challengev angefordert, der Router liefert darauf hin 52 zufällige Bytes zurück:

[{
	"vartype": "status",
	"varid": "status",
	"varvalue": "ok"
}, {
	"vartype": "value",
	"varid": "challengev",
	"varvalue": "0f875ca2feb96b8AbFFf9e2e39AD9fAdFC13e59aE19BCc8A7f67"
}]

challengev muss im weiteren Verlauf der Sitzung immer als Cookie mitgesendet werden. Das eigentliche Passwort wird dann mit challengev in eine Hashfunktion geworfen und das Resultat daraus in sjcl.codec.hex.fromBits().

challenge_val = getVar(rep.serverData, "challengev");
encryptpwd = challenge_val + ":";
var showpass = $("#showpw_router_password").attr("checked");

if (showpass) {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
else {
    encryptpwd = sjcl.hash.sha256.hash(encryptpwd + loginpwd);
}
encryptpwd = sjcl.codec.hex.fromBits(encryptpwd);

Sendet man das richtige Passwort…

POST /data/Login.json?lang=en HTTP/1.1
Content-Type: application/x-www-form-urlencoded

password=8c40880088c6fc2ee7fd47e38c02f2c794cf80dc41e60f677c256a796e5aca93&showpw=0&csrf_token=nulltoken

… bekommt man in der Antwort eine Session-ID:

HTTP/1.1 200 OK
Set-Cookie: SessionID_R3=332X22U33mY; path=/; HttpOnly;

[{
	"vartype":"status",
	"varid":"login",
	"varvalue":"success"
},
{
	"vartype":"status",
	"varid":"status",
	"varvalue":"ok"
},

]

Die Speedport-Firmware macht sich dann noch die Mühe mit den ersten 16 Zeichen von challengev sowie dem Passwort einen symmetrischen Schlüssel mittels PBKDF2 abzuleiten. Das alleine dauert in einer V8 Engine mehr als eine Sekunde und ist der Hauptgrund für die Verzögerung beim Login:

var mypbkdf2 = new PBKDF2(sha256loginpwd, loginsalt, 1000, 16);
mypbkdf2.deriveKey(function(percent_done){}, function(key){
		// ....
	    loginDK = key;
	    setCookie("challengev", challenge_val);
	    setCookie("derivedk", loginDK);
    });

Mit den insgesamt nur drei Cookies kann man dem Speedport endlich seine Daten abringen:

challengev=0f875ca2feb96b8AbFFf9e2e39AD9fAdFC13e59aE19BCc8A7f67; derivedk=28f3bdb0eafc8a6732b42d0bb3bd29ce; lang=en; SessionID_R3=332X22U33mY

Wie ich später bemerkt habe, ist derivedk für die Abfrage der JSON Statusdaten aus dem Engineer-Menu nicht notwendig.

l33tport

Ich habe das ganze in node.js nachgebaut und als „l33tport“ veröffentlicht. Das Script führt den Login durch und lädt die Statusdaten als JSON runter. Damit bin ich erstmal am Ziel: ich kann die Rohdaten selbst verarbeiten. Erstes Ergebnis ist der oben erwähnte „DSL-Wetterbericht“:

DSL Wetterbericht

Mit dem Script als Basis sind natürlich noch ganz andere Dinge vorstellbar: ein alternatives, benutzbares Web-UI für den Router, integration des Routers in Hausautomation, eine „richtige“ App… Wie immer sind der Phantasie keine Grenzen gesetzt.

Update (24.05.2015): rrdtool Beispiele

Das Github-Projekt enthält jetzt ein paar Beispiele, wie man die rrdtool-Datenbanken erstellt, dort via cron Daten reinpumpt und wie man daraus bunte Graphen erstellt.

How to use a Lightroom Catalog on multiple computers

I have one Lightroom database for my photographs, but multiple computers. Of course I want be able to edit my photos on every computer. The obvious solution is to put the catalog on a network share. But the catalog is a sqlite-Database which is build to be accessed by one process only. Because of this, Lightroom forbids to use a catalog that is located on a network share.

My solution is to rsync the catalog before Lightroom starts and sync it back, when the process terminates. To avoid conflicts, I create a lockfile during the runtime of Lightroom. Not very fancy, but this works well for me.

#!/bin/sh
 
if [ -f /Volumes/Pictures/Lightroom/lockfile ]; then
  echo "Catalog is locked by"
  cat /Volumes/Pictures/Lightroom/lockfile
  exit 1
fi 
 
echo `hostname` > /Volumes/Pictures/Lightroom/lockfile
 
rsync user@server.local:/zdata/Pictures/Lightroom/Lightroom-4-Catalog.lrcat /Users/$USER/Pictures/Lightroom/Lightroom-4-Catalog.lrcat && \
open -W -a "Adobe Photoshop Lightroom 4" --args /Users/$USER/Pictures/Lightroom/Lightroom-4-Catalog.lrcat && \
rsync /Users/$USER/Pictures/Lightroom/Lightroom-4-Catalog.lrcat user@server.local:/zdata/Pictures/Lightroom/Lightroom-4-Catalog.lrcat && \
rm /Volumes/Pictures/Lightroom/lockfile

Duplicity on Ubuntu 12.04: broken ssh backend

After setting up a new server with Ubuntu 12.04, I discovered that duplicity was unable to perform backups. The first problem was the missing ssh-backend. The package python-paramiko must be installed in order to use ssh-servers as backup target.

The second pitfall is a bit tricky, because of the confusing error message:

BackendException: ssh connection to server:22 failed: [Errno -2] Name or 
service not known

The bug is fixed in the Quantal-package. Simply download the .deb from the Quantal repository and install it:

dpkg -i duplicity_0.6.19-0ubuntu1_amd64.deb

Ubuntu auf einem Rootserver mit ZFS

Es ist mal wieder so weit: der alte Server ist zu klein, ein neuer muss her. Dieser Artikel ist ein Update zu meinem Update meiner alten Anleitung zum Setup des Rootservers.

Ein Serverumzug ist eine gute Gelegenheit, ein paar Dinge anders zu machen als bisher:

  • ZFS: die bisherige Lösung aus Raid + LVM + Dateisystem funktioniert zwar, aber das vergrößern / verkleinern der Partitionen ist doch immer eine recht spannende Angelegenheit und kann nicht immer online durchgeführt werden. Btrfs bietet noch nicht alle Features, die ich haben möchte (quotas auf FS-Ebene) und mit ZFS on Linux steht ZFS auch nativ als Kernelmodul zur Verfügung.
  • LXC statt OpenVZ: der Betrieb mit OpenVZ war nie ganz frei von Sorgen. Es ist super, dass man so viele Parameter hat und Resourcen flexibel zuweisen kann, aber speziell beim Webserver hatten wir das Gefühl, dass nie genug RAM vorhanden ist. Stößt der Server an das RAM-Limit, kommt es zu den seltsamsten Effekten, incl. Stillstand des Webserver. LXC ist im Mainline-Kernel und für unsere Zwecke gut genug, d.h. ich will Resourcen flexibel zuweisen und kann auf die höhere Sicherheit einer echten Virtualisierung verzichten.
  • nginx statt Apache: weil man es mal gemacht haben sollte 😉

Eine Sache, die sich hingegen bewährt hat, ist alle Dienste (PAM, Mail, sonstige Accounts) über LDAP abzuwickeln. Damit ist LDAP der „single point of administration and failure“, der sich besonders gut scripten lässt.

Hier also wieder die Copy & Paste Anleitung für das Setup von

Ubuntu auf einem Rootserver mit ZFS

Ich habe meinen Server bei Hetzner, aber das muss jeder selbst wissen. Als erstes bootet man ins Rescue-system und sichert den Inhalt der Datei /etc/network/interfaces:

### Hetzner Online AG - installimage
# Loopback device:
auto lo
iface lo inet loopback

# device: eth0
auto  eth0
iface eth0 inet static
  address   5.9.62.176
  broadcast 5.9.62.191
  netmask   255.255.255.224
  gateway   5.9.62.161

# default route to access subnet
up route add -net 5.9.62.160 netmask 255.255.255.224 gw 5.9.62.161 eth0

Festplatten einrichten

Dieses Mal soll der Server mit zfs betrieben werden. Es gibt zwar diverse Anleitungen, wie man Ubuntu in ein natives Root-ZFS-Dateisysten installiert, ich wähle aber bewusst einen anderen Weg.

Im Recovery-Fall komme ich nicht an den physikalischen Server. Ich kann nur ein Rescue-System booten, das kein ZFS-Kernelmodul hat, damit würde ich nicht an das root-Dateisystem kommen.
Deswegen installiere ich das Basissystem auf einer ext4-Partition. Hier läuft lediglich der LDAP-Server und ein SSH-Server. Alle anderen Dienste laufen in LX-Containern und diese können auf dem ZFS untergebracht werden.

Der Server ist mit 2×3 TB Festplatten ausgestattet, d.h. mit einem MBR kommt man nicht sehr weit, statt dessen wird eine GUID Partition Table (GPT) eingerichtet. Neben Root, Swap, ZFS wird auch eine „BIOS boot partition“ benötigt (ein EFI-Requirement).

gdisk /dev/sda

Der Rechner hat 32 GB Ram, also sollten 16 GB Swap genügen. Für das Root-System stelle ich 10GB bereit. Auf LVM verzichte ich bewusst um die Komplexität gering zu halten. Ich verliere damit die Möglichkeit das Basissystem über LVM-Snapshots zu sichern, den Kompromiss kann ich eingehen. Root und Swap werden aber in einem Raid-1 betrieben um einen Plattenausfall abzufangen. So sieht das gewünschte Layout aus:

Command (? for help): p
Disk /dev/sda: 5860533168 sectors, 2.7 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): 932661F7-1628-4107-A48F-8FDDC9DB29E4
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 5860533134
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            4095   1024.0 KiB  EF02  BIOS boot partition
   2            4096        33558527   16.0 GiB    FD00  Linux RAID
   3        33558528        54530047   10.0 GiB    FD00  Linux RAID
   4        54530048      5860533134   2.7 TiB     BF00  Solaris root

Die Platte /dev/sdb wird analog eingerichtet. Jetzt ist ein guter Zeitpunkt um das System zu rebooten (wir müssen nochmal das Rescue-System auswählen), damit die neue Partitionstabelle verwendet wird.

Dann können swap und / angelegt werden:

mdadm -v --create /dev/md0  --level=mirror  --metadata=0.90 --raid-devices=2 /dev/sda2 /dev/sdb2
mdadm -v --create /dev/md1  --level=mirror  --metadata=0.90 --raid-devices=2 /dev/sda3 /dev/sdb3

Wichtig: --metadata=0.90 sollte unbedingt gesetzt werden, sonst kann man große Probleme mit grub bekommen.

Swap aktivieren:

mkswap /dev/md0
swapon /dev/md0

Root-Dateisystem anlegen und mounten:

mkfs.ext4 /dev/md1
mkdir /mnt/install
mount /dev/md1 /mnt/install/

Jetzt können wir

Ubuntu installieren

Wir benötigen erstmal ein neueres debootstrap und installieren damit dann Ubuntu 12.04 LTS:

wget http://archive.ubuntu.com/ubuntu/pool/main/d/debootstrap/debootstrap_1.0.42_all.deb
dpkg -i debootstrap_1.0.42_all.deb 
debootstrap --arch amd64 precise /mnt/install http://archive.ubuntu.com/ubuntu

Die fstab muss angepasst werden:

vim /mnt/install/etc/fstab
proc                    /proc   proc    defaults 0 0
/dev/md0                none    swap    defaults,pri=1 0 0
/dev/md1                /       ext4    defaults 0 1

ausserdem muss die Netzwerk-Config, die wir vorhin gesichert haben wieder gesetzt werden:

vim /mnt/install/etc/network/interfaces
### Hetzner Online AG - installimage
# Loopback device:
auto lo
iface lo inet loopback

# device: eth0
auto  eth0
iface eth0 inet static
  address   5.9.62.176
  broadcast 5.9.62.191
  netmask   255.255.255.224
  gateway   5.9.62.161

# default route to access subnet
up route add -net 5.9.62.160 netmask 255.255.255.224 gw 5.9.62.161 eth0

Die Spezialmounts werden noch gemountet:

mount -t proc none /mnt/install/proc
mount --bind /sys /mnt/install/sys
mount --bind /dev /mnt/install/dev
mount -t devpts none /mnt/install/dev/pts

Dann können wir ins System chrooten…

chroot /mnt/install/ /bin/bash

… und ein paar Einstellungen vornehmen. Zuerst ein neues root-Passwort:

shadowconfig on
passwd

Wir brauchen das Universe-Repository

vim /etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu precise main universe

Dann werden ein paar grundsätzliche Tools installiert:

apt-get update
apt-get install aptitude
aptitude install man-db vim ssh

Ausserdem wird mdadm zur Raidverwaltung benötigt. Da in Ubuntu eine Abhängigkeit zu einem MTA existiert und der default Postfix ist, installieren wir das sehr schlanke Tool SSMTP mit:

aptitude install ssmtp mdadm

Dann brauchen wir noch einen Bootloader. Dieser wird als Abhängigkeit des Kernels installiert:

aptitude install linux-image-generic

Damit die Boot-Partitionen durch die initrd auch einwandfrei gemountet werden, sollte Änderung der Datei mdadm.conf noch die initrd neu angelegt werden, z.B. durch Ausführen von

dpkg-reconfigure mdadm

Sofern die entsprechenden Module, md bzw. raid0, raid1, noch nicht in der /etc/initramfs-tools/modules aktiviert wurden, muss dies noch erfolgen:

echo "raid0" >>/etc/initramfs-tools/modules
echo "raid1" >>/etc/initramfs-tools/modules
echo "md" >>/etc/initramfs-tools/modules

und anschließend das initramfs mit

update-initramfs -u -k all

aktualisiert werden.

Zum Schluss solle die Option „quiet splash“ aus /etc/default/grub entfernt werden. Die Remote-Konsole LARA bei Hetzner kommt sonst mit dem Bildschirmmodus nicht klar und man würde bei bootproblemen nichts sehen.

vim default/grub

Dann noch grub updaten, aus dem Chroot aussteigen und rebooten.

update-grub
exit
reboot

Wenn kein Fehler aufgetreten und der Server wieder hoch gekommen ist, können wir

ZFS installieren

Für Ubuntu ist die Installation sehr einfach. Wir brauchen erstmal das Paket python-software-properties, da sonst add-apt nicht funktioniert:

aptitude install python-software-properties

Dann kann nach der Installationsanleitung verfahren werden:

add-apt-repository ppa:zfs-native/stable
aptitude update
aptitude install ubuntu-zfs

Das Kernelmodul zfs.ko sollte jetzt gebaut und geladen sein. Jetzt können wir einen zpool auf dem verbleibenden Festplattenplatz anlegen.

zpool create -o ashift=12 tank mirror /dev/disk/by-id/ata-ST3000DM001-9YN166_W1F0W2EW-part4 /dev/disk/by-id/ata-ST3000DM001-9YN166_W1F0WNK2-part4

Die Option ashift=12 sort für ein passendes Alignment. Die Namen der Festplatten müssen natürlich angepasst werden.

Der Pool ist angelegt…

zfs list
NAME   USED  AVAIL  REFER  MOUNTPOINT
tank   472K  2.66T   136K  /tank

…und kann jetzt mit Filesystemen bestückt werden:

zfs create -o mountpoint=/home tank/home  
zfs create -o mountpoint=/var/vm tank/vm 
zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        864K  2.66T   136K  /tank
tank/home   136K  2.66T   136K  /home
tank/vm     136K  2.66T   136K  /var/vm

Ich habe zunächst nur ein Filesystem für /home und für die Linuxcontainer angelegt. Ab hier weiss sicherlich jeder selbst am besten, wie das System organisiert wird.

Credits: Das Setup des Basissystems mit GPT hätte ich ohne die Anleitung von Mattias nicht so schnell hinbekommen.

An one finger rotation gesture recognizer

Last year we developed the Raumfeld iPhone App. The goal was to build something that could replace our native controller completely. The main design feature of the native controller is the massive volume knob. Of course we wanted to have something similar in our App, so the designer created the volume screen with a big knob, as shown in the right picture.

To create a volume control, we needed a way to detect if the user performs a rotation gesture on the knob image. There is no default UIGestureRecognizer that detects such a gesture, so we had to implement a custom gesture recognizer. It was surprisingly easy – to be honest, the hardest part was to do the math right.

To track the finger movement, we need to check for every touch event, whether it is within the defined area. The gesture is rotating, so there is a center point m, the radius a which defines the minimum distance from m and the radius b which defines the maximum distance from m. Finally we need to calculate the angle ? between the startpoint and the current finger position (relative to m).

For the first check, we calculate the distance d from the center and make sure, that a < d < b is true.

/** Calculates the distance between point1 and point 2. */
CGFloat distanceBetweenPoints(CGPoint point1, CGPoint point2)
{
    CGFloat dx = point1.x - point2.x;
    CGFloat dy = point1.y - point2.y;
    return sqrt(dx*dx + dy*dy);
}

The rotation angle is the angle between the two lines a and b. The arc tangent function atan() is the key:

/** The method is a bit too generic - in our case both lines share the same start point. */
CGFloat angleBetweenLinesInDegrees(CGPoint beginLineA,
                                   CGPoint endLineA,
                                   CGPoint beginLineB,
                                   CGPoint endLineB)
{
    CGFloat a = endLineA.x - beginLineA.x;
    CGFloat b = endLineA.y - beginLineA.y;
    CGFloat c = endLineB.x - beginLineB.x;
    CGFloat d = endLineB.y - beginLineB.y;
 
    CGFloat atanA = atan2(a, b);
    CGFloat atanB = atan2(c, d);
 
    // convert radiants to degrees
    return (atanA - atanB) * 180 / M_PI;
}

Ok, that was the hard part 🙂 To implement a custom gesture recognizer, let’s have a look at the UIGestureRecognizer API docs, especially the subclassing notes. We just need to overwrite five methods

- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

The key is touchMoved:withEvent: This method checks the distance of the touch event from the center point. If the touch is within the valid area, the angle between the start point and the current touch position is calculated. The result is sent to the delegate object of our class.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
 
    if (self.state == UIGestureRecognizerStateFailed) return;
 
    CGPoint nowPoint  = [[touches anyObject] locationInView: self.view];
    CGPoint prevPoint = [[touches anyObject] previousLocationInView: self.view];
 
    // make sure the new point is within the area
    CGFloat distance = distanceBetweenPoints(midPoint, nowPoint);
    if (   innerRadius < = distance
        && distance    <= outerRadius)
    {
        // calculate rotation angle between two points
        CGFloat angle = angleBetweenLinesInDegrees(midPoint, prevPoint, midPoint, nowPoint);
 
        // fix value, if the 12 o'clock position is between prevPoint and nowPoint
        if (angle > 180)
        {
            angle -= 360;
        }
        else if (angle < -180)
        {
            angle += 360;
        }
 
        // sum up single steps
        cumulatedAngle += angle;
 
        // call delegate
        if ([target respondsToSelector: @selector(rotation:)])
        {
            [target rotation:angle];
        }
    }
    else
    {
        // finger moved outside the area
        self.state = UIGestureRecognizerStateFailed;
    }
}

target needs to implement some kind of protocol to allow the gesture recognizer notification of movements:

@protocol OneFingerRotationGestureRecognizerDelegate <nsobject>
@optional
/** A rotation gesture is in progress, the frist argument is the rotation-angle in degrees. */
- (void) rotation: (CGFloat) angle;
/** The gesture is finished, the first argument is the total rotation-angle. */
- (void) finalAngle: (CGFloat) angle;
@end
</nsobject>

And that’s the whole magic. To use the gesture recognizer, create an image of a rotating control and add a gesture recognizer to your view:

// calculate center and radius of the control
CGPoint midPoint = CGPointMake(image.frame.origin.x + image.frame.size.width / 2,
                               image.frame.origin.y + image.frame.size.height / 2);
CGFloat outRadius = image.frame.size.width / 2;
 
// outRadius / 3 is arbitrary, just choose something >> 0 to avoid strange 
// effects when touching the control near of it's center
gestureRecognizer = [[OneFingerRotationGestureRecognizer alloc] initWithMidPoint: midPoint
                                                            innerRadius: outRadius / 3 
                                                            outerRadius: outRadius
                                                                 target: self];
[someView addGestureRecognizer: gestureRecognizer];

As soon as a gesture is detected, the delegate method is called and you can rotate the image according to the angle:

- (void) rotation: (CGFloat) angle
{
    // calculate rotation angle
    imageAngle += angle;
    if (imageAngle > 360)
        imageAngle -= 360;
    else if (imageAngle < -360)
        imageAngle += 360;
 
    // rotate image and update text field
    image.transform = CGAffineTransformMakeRotation(imageAngle *  M_PI / 180);
    textDisplay.text = [NSString stringWithFormat: @"\u03b1 = %.2f", imageAngle];
}

I’ve created a sample project on github, feel free to play with. Also make sure to read Ole Begemanns article about the UX details on gesture recognition.

Huch, schon August?

Oh, es ist ja Camp. Und gutes Wetter… Wir haben erstmal einen Graben gezogen, in der Hoffnung, dass das Zelt nicht absäuft.
Sehr cool: schon mit Kind 1 ein Throwie (LED + Batterie + Magnet) gebastelt und morgen für den Raketenworkshop angemeldet. Noch keinen Vortrag gesehen, aber dabei sein ist alles 🙂

Objective C: KVC und KVO

Ich empfinde das Eintauchen in die Welt von Objective C und Cocoa als sehr erfrischend, jeden Tag gibt es etwas neues zu entdecken. Wenn man sich mit anderen Entwicklern, die Objective C nicht kennen, unterhält, kommt aus der C++ Ecke garantiert die Frage: „Kann man dort Operatoren überladen?„.

Nein kann man nicht. Braucht man auch gar nicht. Operatoren zu überladen ist zweifelsohne cool, aber ich multipliziere nicht den ganzen Tag Matrizen, sondern baue Dinge für Endanwender. Das angenehme an Objective C ist, dass es bestimmte Real World Probleme sehr schön löst.

Key Value Observing ist so eine Lösung und es ist ein so verdammt einfaches Konzept, dass ich mich wundere, wie die Welt bisher ohne leben konnte… (Um es vorweg zu nehmen: GObject hat ein ähnliches Konzept und es gibt bestimmt noch mehr Implementierungen dieses Patterns).

Das Real World Problem kommt bestimmt jedem bekannt vor: man hat eine Klasse A gebaut und eine andere Klasse B muss benachrichtigt werden, wenn sich in A irgendetwas interessantes ändert. Bisher wäre das Herangehen, dass A eine Referenz auf B mitschleifen muss, damit Klasse A die Klasse B benachrichtigen kann. Das bringt natürlich das schöne Klassendesign durcheinander, eigentlich hat A mit B nichts zu tun und die Referenz auf B zu handhaben ist auch nervig.

In Objective C gibt es Properties, die Membervariablen und deren Getter und Setter erzeugen können:

// foo.h
@interface Foo
@property(nonatomic, copy) NSString* bar;
@end
 
// foo.m
@implementation Foo 
@synthesize bar;
@end

Im obrigen Beispiel hat die Klasse „Foo“ ein Member „bar“ und @synthesize generiert die Getter und Setter, die dann so verwendet werden können:

Foo *fooInstance = [Foo new]; // oder [[Foo alloc] init]
fooInstance.bar = @"Value";
NSLog(@"foo.bar=%@", fooInstance.bar); // "foo.bar=Value"
 
[fooInstance setBar:@"eulaV"]; // geht auch
NSLog("@foo.bar=%@", [fooInstance bar]); // "foo.bar=eulaV"
 
[fooInstance release];

Soweit, so trivial. Mit Key Value Coding kann man auf Properties programmatisch zugreifen. Das bedeutet, ich baue mir einen String zusammen, dessen Inhalt der Name einer Property ist und ich kann auf die Property zugreifen:

NSString* dings = [fooInstance valueForKey:@"bar"]; // "getter"
[fooInstance setValue:@"Hi there!" forKey:@"bar"]; // "setter"

Das wird unheimlich praktisch, wenn man z.B. XML parsen muss und die geparsten Key/Value-Paare direkt via KVC in den Properties einer Klasse speichern kann.

Key Value Observing ist nun die Lösung o.g. Problems: man kann sich einfach von außen als Observer für bestimmte Properties einer Klasse registrieren und wird benachrichtigt, falls sich ein Wert ändert.

Das spart eine Menge Code und die beobachtete Klasse A braucht sich um Klasse B nicht kümmern und muss keine Referenz auf B mitschleifen.

// als Observer registrieren ist einfach:
[fooInstance addObserver:self   // sag mir bescheid,
              forKeyPath:@"bar" // wenn sich bar ändert
               options:NSKeyValueObservingOptionNew
               context:NULL];
 
// der Observer muss diese methode implementieren, 
// um benachrichtigt zu werden:
- (void) observeValueForKeyPath:(NSString *)keyPath
		     ofObject:(id)object
		       change:(NSDictionary *)change
		      context:(void *)context 
{
    if ([keyPath isEqualToString:@"bar"])
        NSLog(@"new value for bar: %@", object);
}
 
// wenn man genug hat, meldet man sich wieder ab
[fooinstance removeObserver:self forKeyPath:@"bar"];

Ich finde das ziemlich elegant. Das Klassendesign bleibt sauber und trotzdem ist es möglich, sich kreuz und quer durch alle Schichten der Anwendung über Zustandsänderungen benachrichtigen zu lassen.

Update: Es gibt einen sehr schönen Wrapper von Andy Matuschak: Block Callbacks for Cocoa Observers (via Ole Bergmanns hoch interessantem Twitterstream)

Der Einstieg in die iPhone / iPad Programmierung

Ich lese mich gerade in die Welt der iOS-Programmierung ein, „for fun and profit“ sozusagen. Die Hürde bei der Plattform ist etwas höher, weil man erstmal eine neue Programmiersprache (Objective C) lernen muss und zusätzlich die ganze Cocoa-API verstehen muss. Ich mache Dinge gerne gründlich, deswegen habe ich mir erstmal die Sprache an sich zu Brust genommen um dann in die iPhone-Programmierung einzusteigen.

Objective C macht auf mich erstmal einen sehr aufgeräumten Eindruck. Ich habe vorher C, Java und etwas C++ programmiert und von den Sprachen findet man einen guten Mix in Objective C wieder. Die umfangreiche Foundation- API ist vergleichbar mit dem, was man in Java vorfindet, trotzdem kann man bis auf C-Ebene hinunter. Die Objektorientierung ist angenehm gelöst, es heisst alles nur ein bisschen anders. So sind Protokolle z.B. das was man in Java Interfaces nennt.

Die Syntax ist etwas anstrengend, man merkt der Sprache deutlich an, dass die ersten Versionen vermutlich im C-Präprozessor implementiert wurden. Die vielen eckigen Klammern sind zwar erstmal ungewohnt, aber damit kommt man relativ schnell klar. Schlimmer ist, dass mit Objective C 2.0 ein Bruch erfolgte und Setter/Getter jetzt mit einem Punkt angesprochen werden können. Das spart zwei eckige Klammern ein, wirkt aber ziemlich inkonsistent.

Insgesamt ist die Sprache sehr mächtig, es gibt schöne dynamische Features. So kann man einer Klasse nachträglich Methoden hinzufügen (Categories), es gibt Dictionaries, wie man sie aus Python kennt und man kann auch mit dem for x in y Konstrukt durch solche assoziativen Speicher durchiterieren:

for (NSString *key in dictionary )
  NSLog (@”%@: %@”, key, [glossary objectForKey: key]);

Als Buch kann ich Programming in Objective-C 2.0* von Stephen Kochan empfehlen. Das Buch hat den Anspruch auch für Menschen geeignet zu sein, die bisher noch nicht in C programmiert haben. Trotzdem vermittelt es alle wichtigen Aspekte in der zu erwartenden Tiefe.

Was die Literatur zur „richtigen“ Programmierung unter iOS angeht: der Markt ist erstmal sehr unübersichtlich. Es gibt viele Bücher, aber welches davon ist gut? Ziemlich hoch gelobt wurde in letzter Zeit IPhone Programming: The Big Nerd Ranch Guide*. Wer sich die 3500 Euro für ein 7-Tage Training auf der Big Nerd Ranch nicht leisten kann, ist mit dem Buch gut beraten.
Man merkt deutlich, dass es aus Schulungsunterlagen hervorgegangen ist, aber das ist kein Manko, im Gegenteil. Man hat sofort Erfolgserlebnisse und muss nicht erst 200 Seiten Urschleim wälzen, bevor man einen Button programmieren darf. Ich kann das Buch fast uneingeschränkt empfehlen. Einziger Kritikpunkt ist, dass es für meinen Geschmack etwas Tiefgang missen lässt. Ich habe das Buch zur Hälfte durch und bis jetzt wurde das Thema Speicherverwaltung, das allen iOS-Anfängern das Genick bricht, sträflich vernachlässigt.

Zur iOS-Umgebung selbst kann ich noch nicht so viel sagen. Es wirkt alles sehr durchdacht, allerdings muss man sich das lineare Denken abgewöhnen. Jeder Pups wird über einen Callback erledigt (er heisst nur Delegate), was einfache Probleme ein bisschen verkompliziert. Aber ich denke das ist nur Übungssache.

Die Dokumentation ist mindestens auf dem Niveau der MSDN, wenn nicht sogar besser. Man kann Beispiele mit einem Knopfdruck direkt in Xcode öffnen. Die IDE ist allerdings eine Zumutung, Xcode 3 ist ein Wirrwar von Fenstern, die man ständig zur Seite schieben muss. Ich frage mich welcher ADS-Patient für das Interface-Design verantwortlich ist.
Xcode 4 dürfte die nächsten Wochen das Licht der Welt erblicken, hier findet sich alles in einem iTunes-Artigen Fenster wieder, was sich wesentlich angenehmer anfühlt. Allerdings haben die Previews von Xcode 4 noch ein paar hässliche Bugs, so lange die Final noch nicht draußen ist, würde ich Anfängern raten, bei Xcode 3 zu bleiben.

Was braucht man, um erstmal loszulegen? Ein gutes Buch, einen intel-Mac / Hackintosh und früher oder später ein „richtiges“ iOS-Gerät. Es genügt ein alter iPod-Touch, aber ohne geht es kaum. Der Simulator kann bestimmte Dinge nicht (Gravitationssensor, Kamera) und verhält sich auch manchmal ein klein bisschen anders (ich hatte speziell bei der Maps-API Probleme). Danke an Semmi, der mir so selbstlos seinen iPod Touch zur Verfügung gestellt hat. Ich verspreche, Du bekommst ihn noch in diesem Leben zurück 😉

Als Entwickler kann man kann nur Anwendungen auf iOS Geräten installieren, wenn man ein Entwicklerzertifikat hat, das kostet pro Jahr 79 Euro. Das ist die einzige Kröte, die man schlucken muss. Ob das gerechtfertigt ist, vermag ich nicht zu sagen, aber man kann sich so ein Zertifikat auch teilen und dann bis zu 100 iOS-Geräte bestücken. Das klappt natürlich nur mit Leuten, denen man halbwegs vertrauen kann.

*=affiliate Link

27c3: Tag 4

OMG WTF PDF war ein prima Einstieg in den letzten Kongresstag. Julia Wolf hat vorgeführt, was mit PDF alles möglich ist. Leider ist sie so rasend zwischen den Folien hin- und her gesprungen, dass man beim Konsum der Aufzeichnung die Folien zur Hand haben sollte. Sie hat u.A. vorgeführt, wie man Dateien aufbauen muss, die gleichzeitig ZIP und PDF Dateien sind. Highlight war ein Executable vom Windows-Taschenrechner, das sie auch mit dem Acrobat Reader öffnen konnte und dieser den Inhalt korrekt dargestellt hat.

Es gab dann noch ein paar Überlegungen, was man noch machen könnte – u.A. die PDF-Engine von Druckern nutzen, um Portscans durchzuführen. Heise hat das so dargestellt, als ob das schon möglich ist, aber Julia hat lediglich gesagt „man könnte mal“. Ich bezweifle jedoch, das es so einfach möglich ist. In dem Druckern ist ja kein Acrobat Reader eingebaut, der für Sicherheitslücken und Parserfoo bekannt ist. Vielmehr nehmen Drucker das PDF nur an und wandeln es dann in ein Format, das sie nativ verstehen, also PCL i.d.R. Es würde mich stark wundern, wenn da nicht-grafische Elemente berücksichtigt werden (Javascript ect.).

Insgesamt jedoch schein PDF ein weites Feld für Experimente sein. Julia hat sich hauptsächlich den Acrobat Reader angeschaut, aber es gibt ja noch mehr PDF Interpreter auf diesem Planeten – nicht nur in Druckern 😉

Bizarr war „Cybernetics for the Masses„. Eine quirlige Dame anfang zwanzig hüpft nervös über die Bühne und erklärt, wie man sich in der eigenen Küche Implantate unter die Haut jagt. Die Materialwahl schein extrem schwierig zu sein, Rost ist ein großes Problem. Dazu gab es noch hilfreiche Tipps wie „kein Skalpell verwenden, lieber eine große Kanüle“, „Venen in den Fingern kann man prima mit einer Lampe finden“ und „nie alleine arbeiten, falls man mal das Bewusstsein verliert“.
L. hat diverse Implantate unter der Haut, z.B. Sensoren für elektromagnetische Felder. Wenn man so einen Sensor ein paar Wochen trägt, trainiert man das Gehirn so sehr an die Signale, dass der Sensor zu einem weiteren Sinnensorgan wird. Ich hatte von diesem Effekt schon mal vor 2 (?) Jahren in einem Biohacking-Talk auf dem Kongress gehört. Mir ist allerdings nicht ganz klar, was der Nutzwert so einer zusätzlichen Wahrnehmung ist.
Interessanter klang L.s aktuelles Projekt, sich einen elektrischen Kompass ins Bein zu implantieren. Gerade für solche orientierungslosen Menschen wie mich, wäre das ein prima Addon 🙂

27c3: Tag 3

Der Jahresrückblick ist für mich Pflichtveranstaltung, er bestätigt mich regelmäßig darin, dass der Mitgliedsbeitrag richtig investiert ist. Nirgends bekommt man mehr Verfassungsklagen und Lobbying für’s Geld als beim CCC 😉
Parallel dazu lief „A Critical Overview of 10 years of Privacy Enhancing Technologies“ und soweit ich das mitbekommen habe, war der Talk auch sehr gut, ich werde mir auf jeden Fall die Aufzeichnungen anschauen.

Danach wurde mit dem Deutschlandfunk „Was kommt nach dem analogen Radio?“ besprochen, was mich aber nicht sonderlich angesprochen hat. Es hat auf mich gewirkt, als ob der Deutschlandfunkt denk, er ist im digitalen 21. Jahrhundert angekommen und das Publikum ist der Meinung, Der DLF hat noch gar nichts verstanden, weil von „Sendezeit“ gesprochen wird.

Ich habe mich dann zu „SIP home gateways under fire“ verkrümelt. Der Vortrag von Wolfgang Beck war etwas wirr, letztendlich wurden diverse Möglichkeiten für Source Routing Angriffe aufgezählt. Wolfgang hätte den Vortrag ruhig etwas ausschmücken können, denn nur mit blanken SIP-Schnipseln ohne weiterführende Grafiken, hing das Verständnis der Zuhörer stark von deren Fähigkeiten ab, SIP in Echtzeit von den Folien zu parsen.

Den „PS3 Epic Fail“ wollte ich natürlich nicht verpassen. Im Vortrag wurde die These aufgestellt, dass die Play Station erst das Interesse der Hacker auf sich gezogen hat, als der Linux-Support offiziell eingestellt wurde. Erst als sich Hacker den Weg zurück zur Playstation (Slim) „erkämpfen“ mussten, haben als Nebeneffekt auch illegetim kopierte Spiele auf der Plattform Verbreitung gefunden.

Den Vortrag solltet Ihr Euch anschauen, es wird ein Sicherheitsmechanismus nach dem anderen zerlegt und das Highlight ist, dass das Team soweit gekommen ist, den Private Key (der Konsole?) zu berechnen, weil die Crypto-Funktionen eine Konstante verwenden, die eigentlich eine Zufallszahl sein soll. Sie haben sich dann in der Q&A-Session etwas gewunden und meinten sie zeigen nur wie es gehen könnte, aber ich hatte den starken Eindruck, dass sie im Besitz des Keys sind (so hat es fefe auch aufgefasst). Es ist unklar, ob das der generische Signing-Key ist oder ein Key der individuell pro Konsole ist. Wenn man den Signing-Key veröffentlichen würde, hätte das natürlich erhebliche Auswirkungen: jeder könnte Software für die Playstation signieren, finanziell würden Raubkopierer natürlich davon profitieren. Es ist auch nicht klar, ob Sony das Problem jemals beheben kann, denn es wurden Wege gezeigt, wie man die Playstation auf beliebige älte Firmware-Revisionen downgraden kann, da ist es irrelevant, wie viele Updates Sony hinterherschiebt.

Der Talk „IMMI, from concept to reality“ war etwas bizarr, Daniel Domscheit-Berg stand auf der Bühne um den Talk für seine verhinderte isländische Partnerin zu halten. Nach dem Talk drifteten die Fragen jedoch relativ schnell zu Wikileaks und Daniels neuem Projekt Openleaks.org. Ganz interessant war, dass er aus ähnlichen Motiven wie Julian ein Buch schreibt: damit er von dem Geld eine gewisse Zeit leben kann und diese Zeit in Openleaks investieren kann (Julian schreibt ein Buch um seine Anwaltskosten bezahlen zu könnnen).
Es scheint mit Openleaks noch bis in den Januar zu dauern, dann soll die Webseite zumindest mit einer detaillierten Erklärung zum Projekt online gehen. Laut Daniel wird es auch Support-Formulare geben, falls man die Platform in der einen oder anderen Art unterstützen möchte. Ich denke da an Bandbreiten- und Storage spenden, ähnlich wie beim Wikileaks Mass Mirroring Projekt.

Running your own GSM stack on a phone“ schaut ihr Euch am besten selbst an. Harald Welte hat das Thema (wie immer) ziemlich gründlich durchgearbeitet. Herausgekommen ist eine „Ethernet-Karte für das GSM-Netzwerk“, also eine Möglichkeit, nur mittels eines geeigneten GSM-Telefons direkt mit dem Netzwerk zu reden. Also bis auf Layer1 (also die ganze HF-Technik) wird alles auf einem normalen PC implementiert.
Es existiert mit OsmocomBB ein ganzes Toolset, mit dem man GSM erforschen kann. „Make interesting stuff“ ist Haralds Aufruf an die Community. Das ist natürlich hoch interessant – eine Basisstation kauft man sich nicht mal eben um mit OpenBSC herumzuspielen, aber ein 20 Euro Handy um GSM besser zu verstehen, finde ich schon ein geeigneteres Spielzeug.

27c3: Tag 2


(The internet is for porn.)

Ich habe den Tag mit Felix Domkes Vortrag „Distributed FPGA Number Crunching for the masses“ begonnen. Felix will DES (56bit) knacken und das möglichst preisgünstig. Nach Evaluierung aller Optionen (CPU, GPU, Cell Processor, FPGA) hat er sich für FPGAs entschieden. Leider sind die mitunter recht teuer, daher hat er auf ebay gebrauche Hardware ersteigert auf der FGPAs verbaut sind. Die Methode ist echt abenteuerlich, man muss bei einem unbekannten Board erstmal herausbekommen, welche Spannungsversorgung notwendig ist und wo die JTAG-Pins sitzen. Jedoch hat er pro FPGA nur $50 ausgegeben, statt $2000 (Listenpreis 2006). Sein Prototyp hat drei Boards á drei FPGAs, die einen 56bit Key in einer Woche berechnen können. Der Protyp verbraucht etwa 80 Watt, das ist weit mehr, als im „Normalbetrieb“.

Interessant finde ich, dass so ein Projekt mit ein paar Mannmonaten Arbeit möglich ist. Was wird möglich sein, wenn man extrem hohe finanzielle Resourcen zur Verfügung hat? Brute-Force Angriffe skalieren linear, je mehr Geld man auf das Problem wirft, desto größere Schlüssel können in zumutbarer Zeit geknackt werden. Welche Schlüssellängen kann man noch als sicher ansehen?

Die weiterführende Idee von Felix ist es, brach liegender FPGA-Power in einem verteilten Community Netz verfügbar zu machen, also ein distributed.net für FPGAs. Viel mehr als die Idee und ein paar Sourcecodefragmente existieren (noch) nicht, aber irgendwo muss man ja anfangen und ich bin gespannt, was wir auf dem nächsten Kongress von dem Projekt hören werden.

Ich habe dann ein paar Vorträge geskipt um mich in „Is the SSLiverse a safe place?“ zu setzen. Jesse und Peter von der EFF haben in drei Monaten das gesamte IPv4 Internet auf https-Server gescannt und die Zertifikate in eine Datenbank heruntergeladen. Die Datenbank gibt es per BitTorrent und man kann die Ergebnisse selbst auswerten – sofern man die Monster SQL-Queries entsprechend formulieren kann 😉
Soweit sind die Erkenntnisse aber nicht neu, EV-Zertifikate sind Geldschneiderei, die Browser vertrauen automatisch 1400 CAs, viele davon machen Fehler und dass das ssh-Security Modell „tofu“ (trust on first usage) im Browser implementiert werden soll, fordert fefe schon lange…
Trotzdem ein ganz interessanter Talk, Respekt vor der Leistung „das Internet“ zu scannen. Es gab auch gleich den Hinweis, dass es in Zukunft schwieriger werden wird. Etwa, weil dank SNI jetzt hinter einer IP mehrere SSL-Zertifikate lauern können. Und mit IPv6 werden es nicht weniger Hosts, die man scannen muss. Die EFF arbeitet an einem verteilten Ansatz, damit künftig User am Scan mitwirken können und so ein regelmäßiges Update der Datenbank möglich ist. Das impliziert natürlich auch eine zeitliche Nachverfolgung der Änderungen in der Zertifikatslandschaft.

Die Techniken zur Identifizierung von Netzwerk-Protokollen sind ein statistischer Ansatz um Netzwerkverkehr zu klassifizieren. Florian hat den SPID-Algorithmus in C++ re-implementiert – die Referenzimplementierung ist in C# realisiert – und schafft es damit auf einem Plastikrouter Traffic in Echtzeit zu klassifizieren. Der Ansatz ist von daher interessant, weil er ohne die sonst üblichen Deep Packet Inspection Techniken auskommt, die Paketweises Pattern Matching betreiben. Er schaut eher auf der Metaebene (Paketgröße, Richtungswechsel, Hash der ersten 4 Bytes des Paketes) und erlangt damit für die 17 untersuchten Netzwerkprotokolle eine sehr hohe Trefferrate – auch auf einem 40 Euro Plastikrouter.

Den Rest des Tages habe ich mir gesundheitsbedingt zu hause als Stream angeschaut. Klares Highlight war Daniel J. Bernstein Vortrag „High-speed high-security cryptography: encrypting and authenticating the whole Internet„. Der Vortrag ist sehr unterhaltsam, schaut Euch die Aufzeichnung an.

Im Prinzip mixt DJB ein paar bekannte und erprobte Elemtente um eine Art VPN aufzubauen. Er will HTTP-Traffic in UDP kapseln. DIe UDP-Pakete sollen einzeln verschlüsselt und signiert sein. Dank elliptischer Kurven mit vertretbaren Aufwand. Beim Client wird im Browser ein Proxy eingestellt, der Webserver nimmt die UDP-Pakete auf Port 53 an und leiten den entschlüsselten Verkehr an den richtigen Webserver weiter. Die Public-Key infrastruktur soll über DNS realisiert werden, nur dass die Public Keys im CNAME-Feld einer Domain untergebracht werden und nicht als TXT-Records wie bei DNSSEC (über das er ziemlich hergezogen ist, mangels Fachwissen kann ich nicht beurteilen, wie viel davon FUD und wieviel davon fundierte Kritik ist).
Mein Eindruck von seiner Lösung ist, dass er sich wirklich Gedanken gemacht hat. Er möchte gerne eine Art IPSEC möglichst simpel implementieren. Allerdings ist die Vorgestellte Lösung erstmal „nur“ für HTTP tauglich. Sicher lassen sich auch andere TCP-Protokolle tunneln, aber das steigert den Aufwand auf Clientseite (installation zusätzlicher Proxies), obwohl ich mir vorstellen kann, dass ein Browser diese Verschlüsselung nativ implementieren könnte.
Nachtrag: Siehe auch fefes Artikel dazu, heise berichtet ebenfalls.

27c3: Tag 1

Day0
Foto (cc) anders_hh

Verpeilung seitens der Bahn (Schnee) und meinerseits (müde) bin ich etwas spät im BCC angekommen und habe nur die Hälfte der Keynote von Rop mitbekommen.

Das Anzug-Anziehen hat sich gelohnt, gleich nach der Keynote wurde Nick auf die Bühne geholt, er war tatsächlich stilecht als Hacker gekleidet: Kapuzenpulli, Cargohosen, Turnschuhe… als Krönung gab es noch eine „goldene Uhr“, die sich als Mega-Bandwidth-Meter herausstellte („Porn“). Hier der Videobeweis (leider ohne Ton):

Nick hat sich gerächt und in den Pausen zwischen den Vorträgen die anderen Anzugträger #0daysuits ermahnt, wie man einen Anzug korrekt trägt: „Keine Krawatte? FAIL!“, „hey, den untersten Knopf lässt man offen…“.

Ich habe mich zunächst in den Vortrag von Branko Spasojevic gesetzt und mir etwas über „code deobfuscation by optimization“ angehört. Der Ansatz ist, verschleierten Code durch Optimierung wieder lesbar zu machen und so Malware leichter auf die Spur zu kommen. Branko hat ein Plugin für IDA veröffentlicht, das die Arbeit wesentlich erleichtert, in dem durch feste bzw. fälschlich konditionale Sprünge verteilte Codeblöcke zusammengefügt werden man so Funktionen wieder rekonstruieren kann. Allerdings habe ich zum letzten Mal im Studium Assembler programmiert (dazu noch auf Microcontrollern und nicht x86), so dass ich bei einigen Folien nur verwirrt lächeln konnte.

Darauf brauchte ich erstmal etwas leicht verdauliches und habe mir Alvar Freudes Zensursula-Rückblick angeschaut. Er hat das schwierige politische Thema echt unterhaltsam rübergebracht und daran erinnert, wie wichtig es ist, dass Nerds auf politscher Ebene mitwirken.

In der Pause habe ich mich mit S. unterhalten, der an sehr interessanten Sachen arbeitet und unter anderem einen TCP Port-Scanner geschrieben hat. Das besondere ist, dass der Scanner single threaded ist und dank einer kniffligen State-Machine 10.000 SSH-Handshakes pro Sekunde ausführen kann. Damit kann man dann tatsächlich „das Internet“ scannen, was aber in der Praxis schwieriger ist, als man denken sollte. Es gibt keinen Provider der solche Aktionen genehmigt, weil bei dieser großen Anzahl von Verbindungen Netzwerküberwachungsmechanismen Alarm schlagen. Das kann so weit führen, dass plötzlich das Routing zum Provider wegen bösartigem Traffic eingestellt wird, das will natürlich kein kommerzieller Provider. Bei einem normalen Portscan mit nmap ist das natürlich nicht der Fall.

Ein ganz netter Nebeneffekt von großen Portscans auf SSH ist, dass man Hosts anhand der Schlüssel wiedererkennen und nachverfolgen kann. Selbst wenn ein Host in ein anderes Rechenzentrum umzieht, kann man ihn wiederfinden. Oder man findet hosts hinter gateways wieder, d.h. der gleiche Key ist auf mehreren IPs zu finden. Oder man identifiziert Notebooks auf einer großen Hackerkonferenz, die per DHCP eine Adresse bekommen… eine schöne Spielwiese 🙂

Dann ging es zum Vortrag des Wistleblower-Netzwerk e.V. Ein ganz interessanter Einblick in die jüngere Geschichte des Whistleblowings und gleichzeitig die deprimierende Erkenntnis, dass man als Whistleblower immer anonym handeln sollte – was schwierig ist, sobald die Information, die man publizieren möchte, nur sehr wenigen Menschen zugänglich ist und man automatisch in den Kreis der Verdächtigen gerät. Wer sich als Whistleblower outet, ist eigentlich immer Repressionen ausgesetzt.

Super Interessant war der darauf folgende Vortrag „sms-o-death“ von Collin Mulliner und Nico Golde. Die beiden haben eine marktübliche Auswahl von 10 Telefonen von der Seite des GSM-Netzwerkes angegriffen. Das mag jetzt wie ein theoretischer Angriff klingen, man bedenke aber, dass man gebrauchte GSM-Basisstationen auf ebay kaufen kann und dass inzwischen Open Source Software wie OpenBSC frei verfügbar ist. Genau das haben Collin und Nico gemacht – natürlich in einem abgeschirmten Raum der TU-Berlin um nicht extra eine GSM-Testlizenz erwerben zu müssen. Sie haben sich in ihrem Angriffsszenario auf SMS beschränkt (geht auf jedem Telefon) und durch Fuzzing alle möglichen Felder auf ungültige Werte gesetzt. Insgesamt wurden 120.000 SMS an die Telefone gesendet, was nur eine kleine Auswahl der theoretisch möglichen Anzahl von Variationen ist.

Das große Problem bei diesem Angriff ist, automatisch herauszufinden ob das Telefon nach Empfang der manipulierten SMS abgestürtzt ist. Die Basisstation kann feststellen, dass das Telefon sich vom Netzwerk getrennt hat (spontaner Reboot). Weil manchmal Telefon die SMS stillschweigend „verschlucken“ wurde noch ein kleines J2ME Programm entwickelt, dass als SMS-Echo-Server fungiert und das nach dem Angriff noch antworten musste.

Die Ergebnisse waren ziemlich ernüchternd: alle Telefone sind angreifbar. Die Symptome sind meist ein Komplettabsturz des Telefons, mitunter ein Reboot. Nokia S40 Telefone kann man so aus der Ferne abschalten. Sie haben einen Watchdog, der nach drei aufeinander folgenden Reboots das Telefon automatisch runterfährt und ausschaltet.

Noch spanndender war allerdings, dass es bei drei von fünf untersuchten Herstellern überhaupt keine Kontaktmöglichkeit für Sicherheitsexperten gibt und entsprechend lang die Reaktionszeiten sind. Wie das Problem der Softwareupdates für billige Featurephones aussieht, haben wir ja schon beim „Curse of Silence“ gelernt.

Ich habe dann erstmal versucht nach hause zu kommen, auf ein Winderabenteuer mit der Deutschen Bahn nach ?itternacht hatte ich keine Lust. Den Netzneutralitätstalk habe ich sausen lassen, er wurde vom Deutschlandradio übertragen und hinterher kontrovers diskutiert. Ich muss mir erstmal die Aufzeichnung ansehen, bevor ich dazu eine eigene Meinung habe.
Via Stream habe ich mir noch die Vorträge „Desktop on the Linux“ (Rant eines gefrusteten Sysadmins…) und „Hacking iButtons“ (sehr interessant) angeschaut.

Klares Highlight zum Abschluss des Tages war jedoch „Adventures in analyzing Stuxnet“ von Bruce Dang. Bruce arbeitet bei Microsoft von daher war seine Perspektive besonders interssant. Der Vortrag drehte sich hauptsächlich um die Analyse der 0day-Lücken, die Stuxnet ausgenutzt hat um sich auf einer ganzen Bandbreite von Windowsversionen zuverlässig zu verbreiten.
Das interessante war, dass Stuxnet sich nur über Lücken verbreitet, die 100%ig funktionieren, weil sie ohne Speichermanipulation auskommen. Es gibt also keine Abstürze, weil der Buffer Overflow manchmal nicht funktioniert oder sonstige Nebeneffekte, die man sonst oft bei Malware findet. Der Vortrag war sehr unterhaltsam („so I was tired and watched porn“), schaut Euch auf jeden Fall die Aufzeichnung an.

27c3, Tag 0: Vorbereitungen

Morgen ist wieder Chaos Communication Congress, der 27. um genau zu sein. Ich habe gerade versucht zu rekonstruieren, seit wann ich dort hin fahre, was gar nicht so einfach war. Es waren mindestens zwei Veranstaltungen im Haus am Köllnischen Park dabei, dann wird wohl der 16C3 mein erster gewesen sein.

Ich schreibe das nicht, weil ich so ein cooler Tüp bin, der schon eeeewig dabei ist und ganz locker mit Wau gefachsimpelt hat (ich war zu schüchtern ihn anzusprechen…). Nein, ich will damit nur sagen, dass es mir ziemlich wichtig ist dort hin zufahren. Meine Familie muss in der Nachweihnachtszeit ziemlich zurückstecken während ich im BCC staunend zuhöre und zu verstehen versuche, was mir in vier Tagen ins Gehirn geprügelt wird.

Wenn man in den Fahrplan schaut, ist für jeden etwas dabei. Auf Twitter und im Wiki bahnen sich auch diverse Interessante Themen an. Ausgelöst durch einen Tweet von Joern, ist davon auszugehen, dass morgen diverse Nerds im Anzug auftauchen. Das ist eine schöne Idee, sonst sieht man auf dem Congress eher die Mehrheit im Kapuzenpulli rumschlumpfen. Der einzige Nerd, der grundsätzlich im Anzug auftaucht, ist Nick Farr 🙂 Natürlich mache ich ebenfalls mit, obwohl ich mit 0days wenig am Hut habe und ein Krawattenknoten mich in die Verzweiflung treiben kann.

Ein ganz interessanter Bug in MacOS X ist heute Abend bekannt geworden: Scheinbar crasht die Cisco WLAN Hardware alle Macs, die sich mit dem WLAN verbinden wollen.

(Foto von @robotviki)

Gerüchteweise klappt das sogar mit iOS-Geräten (ipad, ipod, iphone). Es wird schon fleissig nach dem magischen WLAN-Paket gesucht, das die Ursache ist. Da der Kongress traditionell eine recht hoche Dichte an Macs aufweist, wird es dieses Mal echt interessant. Man stelle sich das mal vor: ein WLAN-Paket und der ganze Saal 1 schreit entnervt auf 😉 Interessanter ist natürlich die Ausführung von Code auf dem angegriffenen Mac, aber ein reproduzierbarer Crash ist schon die halbe Miete. Bei Interesse an der Thematik kann man die Twitter-Hashtags #0day #27c3 verfolgen.

Ansonsten fühle ich mich ganz gut präpariert, das für den Kongress unverzichtbare VPN läuft, auf dem Smartphone ist die sehr empfehlenswerte 27c3 Anwendung von Simon Schoar installiert und der Rucksack fasst alle Weihnachtsschokolade, die ich den Kindern unter dem Vorwand „gesunde Ernährung ist wichtig“ geklaut habe. Möge der Kongress beginnen.

Portable __VA_ARGS__ macros for Linux, HP-UX, Solaris and AIX

I recently needed a macro with variable arguments that work on all mainstream compilers. I use gcc only on Linux, on the other platforms I want to use the „native“ compiler that belongs to the OS. Let’s start with Linux.

Linux

If you’re inside the gnu/gcc world, things are easy. This is what everybody tries first:

1
2
3
4
5
6
7
8
9
10
11
#include "stdio.h"
/* I use "stdio.h" because my blog software cant't handle
   angle brackets inside a preformated text blog ... :( */
 
#define PRINTERROR(x, ...) fprintf(stderr, "ERRORMESSAGE = "  f "\n" , __VA_ARGS__);
 
int main(void)
{
    PRINTERROR("Hello %s!", "world");
    return 0;
}

The problems start, if you want to use the macro without variable arguments.

9
    PRINTERROR("Hello world!");

gcc will not accept the code, because it resolves the macro to

9
    fprintf(stderr, "ERRORMESSAGE = "  "Hello world!" "\n" ,);

(note the comma)

test.c: In function ‘main’:
test.c:9: error: expected expression before ‘)’ token

The gcc workaround for this kind of a situation is:

5
#define PRINTERROR(x, s...) fprintf(stderr, "ERRORMESSAGE = "  f "\n" , ## s);

If „s“ is null, this erases the comma to the left of the „##“ in the macro definition. The resulting expansion is:

9
    fprintf(stderr, "ERRORMESSAGE = "  "Hello world!" "\n" );

The comma is gone, the code compiles. Great.

HP-UX

However, this approach fails on HP-UX

cc -o test test.c
cc: "test.c", line 9: error 1000: Unexpected symbol: ")".

I found the solution for this problem in the HP-docs:

you must insert a space to the left of the comma to make it clear to the preprocessor that the comma is the left operand of the „##“ operator.

Yes. A space. Left of the comma. Sigh….

The definition that works on Linux and HP’s cc -AC99 compiler looks like this:

5
#define PRINTERROR(x, s...) fprintf(stderr, "ERRORMESSAGE = "  x "\n" , ## s);

Solaris

Solaris c89 compiles the above definition with a warning:

"test.c", line 9: warning: argument mismatch

Solaris c99 compiler is very strict and allows

5
#define FOO(...) printf(__VA_ARGS__)

only. The documentation points out, that it is possible to use #__VA_ARGS__ which seems to be similar to GNU’s/HP’s ## Operator:

5
#define PRINTERROR(x, ...) fprintf(stderr, "ERRORMESSAGE = "  x "\n" , # __VA_ARGS__ );

Ok, the code compiles, but calling PRINTERROR results in a „argument mismatch“-warning. I found no other solution than disabling the warning. Dirty but it works:

5
6
7
#define PRINTERROR(x, ...) printf(stderr, "ERRORMESSAGE = "  x "\n" , # __VA_ARGS__ );
/* optional: disables "warning: argument mismatch" */
#pragma error_messages (off, E_ARGUEMENT_MISMATCH)

If course it is bad to hide warnings, but if your code is multi-platform, you can use very strict compiler settings on another platform to make the warnings visible at least there.

AIX

The original AIX-compiler (cc) does not complain, but c89 fails with

"test.c", line 3.16: 1506-1128 (S) The GNU variable argument identifier "s" of macro "FOO" is not permitted in the current langlvl mode.
"test.c", line 7.29: 1506-041 (E) The invocation of macro FOO contains fewer arguments than are required by the macro definition.

There is a langlvl #pragma to switch the compiler language level. All levels that allow implementation-specific language extensions are sufficient. I used extc99 which allows to use the c99 compiler. Simply add this to the beginning of your sourcefile:

#pragma langlvl (extc99)

The final result

This is the result of some hours browsing the compiler docs. The macro works on all c99-compilers mentioned above and allows zero arguments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifdef _AIX
#pragma langlvl (extc99)
#endif
 
#include "stdio.h"
 
#ifdef _SOLARIS
  #define PRINTERROR(x, ...) fprintf(stderr, "ERRORMESSAGE = "  x "\n" , # __VA_ARGS__ );
  /* optional: disables "warning: argument mismatch" */
  #pragma error_messages (off, E_ARGUEMENT_MISMATCH)
#else
  #define PRINTERROR(x, s...) fprintf(stderr, "ERRORMESSAGE = "  x "\n" , ## s);
#endif
 
int main(void)
{
        PRINTERROR("NO PARAM");
        PRINTERROR("Param: %s", "foo");
 
        return 0;
}

Of course you have to use the compiler switch -D_AIX, -D_SOLARIS or -D_HPUX on the apropriate platform. Let me know what do you think and how it could be done better.

Update: André suggests this solution (see his comment):

void PRINTERROR_verbose(const char * file, int line, int level, char *format, ...) {
	int size;
	char *cp;
    va_list args;
 
	if (level < = 2) {
 
	    va_start(args, format);
    	size = vsnprintf(NULL, 0, format, args) + 1;
    	va_end(args);
 
    	va_start(args, format);
		cp = (char *)calloc(size, sizeof(char));
		if (cp != NULL && vsnprintf(cp, size, format, args) > 0) {
			/* Ausgabe von cp hier via syslog, stderr, stdout, etc. */
			/* oder cp noch mal umformatieren fuer Sonderzeichen und/oder */
			/* zusaetzliche Zeitangabe */
 
			/* bei Debuglevel 1 (z.B. ERROR) wird dann noch etwas mehr angezeigt */
			if (level < = 1) {
				fprintf(stderr, "\tFile '%s' in line %i\n", file, line);
			}
		}
	    va_end(args);
		free(cp);
	}
}
 
#define PRINTERROR(...) PRINTERROR_verbose(__FILE__, __LINE__, __VA_ARGS__)

Ohrenfutter

Ich habe früher Podcasts ignoriert. Meine Einstellung dazu war etwa

Warum soll ich mir das Gequatsche von anderen Leuten anhören, schliesslich kann ich geschriebenen Text viel schneller parsen.

Irgendwann ist mir mal aufgegangen, dass ich in vielen Situationen nichts lesen kann oder will. Etwa beim Autofahren. Beim Einkaufen. Nach 10 Stunden im Büro. Beim Saubermachen – mein neues Hobby seit ich Kinder habe 😉 Mein ADS-versautes Gehirn verlangt nach einem kontinuierlichem Informationsbombardement.
Also Stöpsel ich mir einen Podcase in die Ohren. Und bin begeistert. Weil ich mich so drüber freue, dass ich Podcasts nun doch gut finde, gebe ich hier gerne meine derzeit liebsten Abonnements zum besten:

  • Chaosradio Express. Ok, wer Podcasts hört, hört sehr wahrscheinlich diesen Podcast. Wer keine Ahnung hat, was Podcasts sind: hört Euch eine beliebige Folge zum Thema Eurer Wahl an. Es ist für alle etwas dabei. Highlight für mich war Folge 147: Mikrokosmos, Makrokosmos.
  • Mobile Macs. Der chaotische Podcast für Apple-Fanboys. Ich habe zwar nur einen recht immobilen 25kg-Mac, verpasse aber trotzdem keine Folge. Gegenüber Bits und So erheblich mehr Nerd- aber auch mehr Quatschfaktor. Das Leiden lohnt sich aber für die 5% Informationsgehalt. Unglücklicherweise sind die interessanten Infos immer an einer anderen Stelle versteckt, so dass man gezwungen ist, sich den ganzen Podcast anzuhören.
  • Bits und So. Der „vernünftige“ Podcast für Apple Fanboys. Eigentlich ziemlich langweilig, aber es gibt mitunter gute Tipps für hilfreiche Applikationen. Seit Leo Becker vom fscklog mit dabei ist, gesteigerter Informationsgehalt. Höre ich trotzdem nur, wenn gerade alle anderen Podcasts alle sind.
  • Küchenradio. Ganz toll, ganz anders. Sehr viele gesellschaftliche Themen, je nach Besetzung stark schwankende Qualität. Zum Reinhören empfehle ich: NR. 268: Gentrifizierung.
  • Alternativlos. Die Fnord News Show für die Hosentasche. Hoher Unterhaltungs- und Geekfaktor. Kann man nicht beschreiben, einfach mal reinhören. Anspieltipp: die Folge zur Polizeigewalt.
  • Netzpolitik Podcast. Höre ich nur, wenn mich das Thema interessiert. Hauptsächlich macht die entspannte Art von Markus Beckedahl den Charme des Podcasts aus.
  • Elementarfragen. Leider im Moment inaktiver Podcast, der hautpsächlich für seine großartige Sendung zu Tschernobyl extrem viel positives Feedback erhalten hat. Hört Euch wenigstens diese Folge an. Es lohnt sich. Ich drücke die Daumen, dass die Sommerpause bei den Elementarfragen bald vorbei ist.
  • Pandroid Podcast. Ich war vor einer Weile mal auf der Suche nach einem vernünftigen Podcast zu Android. Aber das was man üblicherweise findet, sind Gadget-lastige Labersendungen („Oh wow, das neue Samsung Bla bla bla mit 12 Megabupsel Kamera…muss ich haben…“). Speziell die US-amerikanische Podcastlandschaft ist in der Beziehung unerträglich.

    Um so erfreuter war ich gestern, als ich gelesen habe, dass Yan Minagawa und Dirk Jäckel mit dem Pandroid Podcast gestartet sind und sich explizit mit der Softwareentwicklung für Android beschäftigen wollen. Sendung 01 ist nur 15 Minuten lang, aber schon sehr vielversprechend. Was dem Podcast noch fehlt, ist lediglich ein flattr-Button.

Ich bin immer noch auf der Suche nach guten Podcasts zur Softwareentwicklung. Es gibt zwar den heise developer Podcast, aber so richtig umhauen tut mich das nicht. Speziell Systemnahe Entwicklung unter Unix scheint ein unbesetztes Nischenthema zu sein. Über Empfehlungen freue ich mich in den Kommentaren.

gdb attach fails with ptrace: Operation not permitted

Today I ran into a weird problem. I could not attach to my own process with gdb. The process ran under my UID, but gdb refused to attach. This is a problem of wrong permissions, although /proc/[pid]/status looked ok:

...
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
...

I am the owner but cannot attach? Well, I launched gdb as root and could attach. Strange. Without digging deeper into this, my dirty workaround was this:

sudo chmod +s /usr/bin/gdb

Update: Thanks to Mario, who pointed out, that the reason is the Kernel hardening stuff build into the Ubuntu kernel. See his comment how to fix the problem permanently.