Planet NoName e.V.

19. February 2015

RaumZeitLabor

Exkursion zum Grosskraftwerk Mannheim (GKM)

Das RaumZeitLabor geht mal wieder auf Tour. Dieses mal werden wir den aktiven Block 8 des Grosskraftwerks Mannheim (GKM) besichtigen.

19. February 2015 00:00:00

Exkursion zum Grosskraftwerk Mannheim (GKM)

Das RaumZeitLabor geht mal wieder auf Tour. Dieses mal werden wir den aktiven Block 8 des Grosskraftwerks Mannheim (GKM) besichtigen.

19. February 2015 00:00:00

15. February 2015

RaumZeitLabor

Aschermettwoch 2015

Am Anfang schuf der Vorstand Boden und Decke. Der Boden aber war wüst und wirr, Finsternis lag über dem Mett.

15. February 2015 12:37:23

08. February 2015

Raphael Michel

Erfahrungen mit Django

Der Patrick hat mich gebeten, Dinge zu Django aufzuschreiben, die über den grundlegenden Workshop, den ich neulich gehalten habe, hinausgehen. Ich weiß nicht so ganz, was ich dazu schreiben soll und wie viel davon tatsächlich interessant ist, aber ich habe einfach mal den Code meiner abgeschlossenen und laufenden Django-Projekte durchforstet, und dabei aufgeschrieben, was mir so schien, als könnte es anderen Entwicklern nützlich sein. Ich habe das ganze sehr lose in verschiedene Abschnitte gegliedert, aber ansonsten nicht weiter sortiert.

Generell

Benutzt Python 3. Bitte. Und Django 1.7+. Danke. Und lest mehr in der Doku, sie ist fast vollständig lesenswert. :-)

Projektstruktur

Django bietet die Möglichkeit, das Projekt in sogenannte Apps aufzuteilen. Die Idee dahinter ist hauptsächlich die der Wiederverwendbarkeit von Apps, die ich in der Realität bisher eher für unrealistisch halte, aber dennoch kann es sinnvoll sein, diese Möglichkeit zu nutzen. Ich habe in verschiedenen Projekten bisher verschiedene Ansätze ausprobiert, angefangen bei einem monolithischen Modell mit einer gigantischen App, sowie zusätzlichen, "kleinen" Apps für Meta-Funktionen wie Analyse und Statistik, bis hin zu einer Aufteilung in mehrere austauschbare Apps (z.B. eine für Backend und eine für Frontend), die nicht voneinander abhängen dürfen und einer App mit gemeinsamen Funktionen und Models, von der alle anderen abhängen. Verschiedene Apps für verschiedene Features sind sicher oft sinnvoll, bei mir aber meist nicht realistisch, da die Features zu stark zusammenhängen und ineinander integriert sind.

Welcher Ansatz sinnvoll ist, hängt wohl sehr vom Projekt ab, aber ich fahre bis jetzt mit letztere Aufbau am besten.

Standardmäßig legt Django pro App eine views.py, eine urls.py, ein eine tests.py und eine models.py an. Während man bei urls und models oft sehr lange mit einer Datei auskommt, ist es bei views und tests nützlich zu wissen, dass es Django nicht stört, wenn man daraus ein Subpackage macht und das in mehrere Dateien aufteilt.

Debugging

Zum Debugging empfehle ich die allseits bekannte Django Debug Toolbar, die mir nicht nur beim Debugging selbst sehr nützlich ist, sondern vor allem auch dafür, das ORM im Auge zu behalten: Wenn man unachtsam Code schreibt, passiert es einem leider leicht, dass man extrem viele Datenbankqueries produziert. Das Problem fällt meist in der Entwicklungsphase, wenn man mit kleinen Testdatensätzen arbeitet, oft nicht auf aber verursacht dann riesige Last, sobald man in Produktion geht. Faustregel: Jede Aktion sollte eine konstante (bzw. konstant nach oben beschränkte) Anzahl Datenbankqueries verursachen, die unabhängig von der Anzahl der Datensätze sein sollte.

In Produktion ist dann, wenn User sich beschweren, django-impersonate ein nützliches Tool, um Fehler nachzuvollziehen.

Statische Dateien

Bei jedem größeren Projekt wollt ihr wahrscheinlich statt CSS-Code lieber LESS oder SASS schreiben. Der django-compressor regelt das für euch genauso, wie er CSS und JavaScript komprimieren kann. Im Entwicklungsmodus tut er das live und transparent, in Produktion kann man ihn vorkompilieren lassen.

Models

Schaut euch die Dokumentation zu models.ForeignKey an und behaltet im Kopf, dass die Standardeinstellung für on_delete auf CASCADE steht: Wenn ihr ein referenziertes Objekt löscht, werden alle referenzierenden Objekte mitgelöscht. Das kann einem den Kopf kosten (für euch getestet) und man ist in fast allen fällen mit PROTECT oder SET_NULL besser beraten.

Authentifizierung

Seit einiger Zeit macht Django es recht einfach möglich, eigene User-Models statt dem mitgelieferten django.contrib.auth.models.User zu verwenden. Macht von dieser Möglichkeit früh Gebrauch – wenn der Bedarf erst später entsteht, ist eine Migration im Produktivbetrieb zwar möglich, aber ziemlich aufwändig1.

Signals

Das Signal-Framework von Django ist viel mächtiger als es auf den ersten Blick aussieht. Hierzu gibts wahrscheinlich irgendwann einen Vortrag oder Extra-Blogpost von mir.

Hintergrundprozesse

Es gibt fast keinen Fall, in dem es gerechtfertigt ist, den User auf eine Antwort warten zu lassen. Man sollte daher tunlichst vermeiden, irgendetwas, das länger dauern kann, in einem View zu tun. Ich verwende Celery als Task Queue für möglichst alles, was länger dauern kann oder von externen Erreichbarkeiten abhängt, sei es der Export vieler Daten oder das bloße Versenden von E-Mails.

Für Cronjob-artige Dinge verwendete ich früher django-cron, aber muss mich nach einer Alternative umsehen oder es auf Python 3 portieren.

Templates

Es ist eine Überlegung wert, Djangos Template Engine durch Jinja2 zu ersetzen. Ich habe dies in einem Projekt getan, weil ich Dinge abbilden musste, die in Djangos TE sehr umständlich gewesen wären und werde es wohl noch öfter tun, wenn Django 1.8 released ist, das bedeutend bessere Unterstützung für externe Template Engines bieten wird.

Views

Ich habe zu Beginn meiner Arbeiten mit Django vernachlässigt, wie mächtig Class-based views sind und sie viel zu wenig verwendet. Ich kann euch nur empfehlen, euch die ganz genau anzuschauen.

Unit Tests

Wenn ihr wirkliche Interface-Tests machen wollt, dann lässt sich Django mithilfe des StaticLiveServerTestcase recht gut mit Selenium verbinden2.

Lokalisierung

Auch wenn ich noch nicht in den zweifelhaften Genuss kam, ein mehrsprachiges Projekt in Produktion zu bringen, kann ich den Tipp geben, dass man das, wenn man es je tun möchte, gar nicht früh genug einplanen kann.


  1. Ja, ich habe auch das für euch getestet. 

  2. In der Dokumentation gibt es ein Beispiel. 

08. February 2015 23:00:00

05. February 2015

RaumZeitLabor

Neue Webseite

Seit einiger Zeit haben wir auf GitHub gemeinsam an einer neuen Webseite gebastelt und diese jetzt "deployed" wie man in der Welt der Web-Hipster sagt.

In erster Linie wollten wir die bisherige, auf Wordpress basierende Seite wegen all ihrer Probleme (PHP, security, updates, account management etc.) durch statisch generierte Seiten ersetzen. Bei einem solchen Neuanfang kann man sich auch gleich an aktuelle Gepflogenheiten der Web- und Softwareentwicklung halten.

Alles beginnt im GitHub Repository des RaumzeitLabors mit rzl-homepage, wo der gesamte Code und Inhalt der Seite liegt.

Abgesehen von den Blogbeiträgen bauen wir mit JavaScript und der Tumblr API eine "endlos" scrollende Seite mit Bildern aus unserem Log und eine kleine Übersicht über unsere Vortragsvideos. Für die Anreise zum RaumZeitLabor haben wir eine interaktive Beschreibung mit OpenStreetMap Karten gebaut.
Unser Eventkalender, der eines der größten Sorgenkinder der Wordpress Installation war, liegt jetzt auf einem CalDAV Server

Wenn jemand jetzt im GitHub einen Commit oder einen Pull-Request erstellt, kümmert sich Travis darum, die Seite zu bauen. Das ganze ähnelt dem Kompilieren von Software, weil aus allen rohen Blogtexten, Bildern, Events und Links ein statisches Konstrukt aus HTML, CSS und JavaScript erstellt werden muss. Im Gegensatz zu Wordpress werden also sämtliche Seiten nicht dynamisch beim Aufruf auf dem Server generiert und ausgeliefert (PHP) sondern sie liegen immer schon "fertig" auf dem Server.

Für den eigentlichen Bauvorgang nutzen wir Grunt, eine Art "Makefile fürs Web". Grunt führt diverse Arbeiten durch, um den JavaScript-Code und das CSS zu prüfen und zu verkleinern, kopiert alle Inhalte an passende Stellen und führt Jekyll aus. Jekyll überführt die einzelnen Texte der Blogposts zusammen mit Layout, Templates und CSS zu einer statischen Webseite mit Blogcharakter zusammen.
Zum Schluss werden noch alle HTML Seiten minimiert, damit die Webseite schnell lädt.

Travis protokolliert alle Builds, so dass ihr genau nachsehen könnt, wie der Prozess abläuft. Wenn die Webseite erfolgreich baut, wird dieser Zustand auf unseren Server kopiert und ist ab dann "live".

Um dem "mobile first" Gedanken zu genügen, nutzen wir das Bootstrap Framework, das sich um die passende Skalierung der Seite für alle Geräte kümmert. So schrumpft z.B. die Menüleiste auf den kleinen Smartphonebildschirmen automatisch zu einem Menübutton zusammen.

Ein GitHub Account ist jetzt also die einzige Hürde, um einen Blogpost zu schreiben.
Mehr über die neue Seite gibt es auch im Wiki. Wer mitentwickeln will, findet bei GitHub auch einen Docker Container zum Sofort-Loslegen.

Send Pull-Requests!

05. February 2015 12:30:00

25. January 2015

RaumZeitLabor

Stick-Wochenende

Das StickZeitLabor lädt zum Stick-Wochenende.

 rd-jump

Seit geraumer Zeit gibt es im RaumZeitLabor und seinen diversen Außenstellen Stickmaschinen und -begeisterte. Jetzt wollen wir uns zum ersten Mal zu einem Wochenende voller Vorträge, Erfahrungsaustausch und wilder Experimente treffen. Sattelt die Pferde und kommt mit euren Maschinen am 21.02./22.02 ab 10 Uhr ins StickZeitLabor zum ESWIRZL (Erstes Stickwochenende im RaumZeitLabor).
Am besten ihr schreibt uns vorher (info@raumzeitlabor.de), mit wie vielen Sticknerds ihr im RZL einreiten wollt, ob ihr Fahrtkostenerstattung oder einen Schlafplatz braucht, was ihr alles mitbringt, wieviel Platz ihr dafür voraussichtlich benötigt, und was euch sonst noch an nützlichen Informationen einfällt.
Sollte jemand planen eine Stickmaschine mit mehreren Köpfen mitzubringen, bitte auch kurz klären, ob wir sie durch die Tür bekommen!
Euer StickZeitLabor

by Alexander Brock at 25. January 2015 16:31:39

Stick-Wochenende

Das StickZeitLabor lädt zum Stick-Wochenende.

 rd-jump

Seit geraumer Zeit gibt es im RaumZeitLabor und seinen diversen Außenstellen Stickmaschinen und -begeisterte. Jetzt wollen wir uns zum ersten Mal zu einem Wochenende voller Vorträge, Erfahrungsaustausch und wilder Experimente treffen. Sattelt die Pferde und kommt mit euren Maschinen am 21.02./22.02 ab 10 Uhr ins StickZeitLabor zum ESWIRZL (Erstes Stickwochenende im RaumZeitLabor).
Am besten ihr schreibt uns vorher (info@raumzeitlabor.de), mit wie vielen Sticknerds ihr im RZL einreiten wollt, ob ihr Fahrtkostenerstattung oder einen Schlafplatz braucht, was ihr alles mitbringt, wieviel Platz ihr dafür voraussichtlich benötigt, und was euch sonst noch an nützlichen Informationen einfällt.
Sollte jemand planen eine Stickmaschine mit mehreren Köpfen mitzubringen, bitte auch kurz klären, ob wir sie durch die Tür bekommen!
Euer StickZeitLabor

25. January 2015 16:31:39

17. January 2015

Raphael Michel

31c3 Vortragsreviews

Ich habe auf und (vor allem) im Nachgang des 31. Chaos Communication Congress eine sehr große Menge Vorträge geschaut. Da ich immer mal wieder gefragt wurde, welche ich denn empfehlen kann, gibt es hier kurze Meinungsschnippsel zu vielen davon. Der Blogbeitrag wird möglicherweise auch noch still und heimlich erweitert.

Bitte beachten: Diese sind sehr kurz und möglicherweise subjektiv, unreflektiert, falsch, unfair, etc. und geben nur meine Gedanken direkt nach dem Anschauen des Vortrags. Sie sind sehr grob von oben nach unten nach Empfehlung sortiert, aber wirklich nur sehr grob.

  • Reconstructing narratives von Jacob Appelbaum und Laura Poitras

    Für mich der Vortrag des Congress, der den größten Eindruck hinterlassen hat. Die Stimmung im Saal hätte für mehrere Keynotes gereicht. Sollte man auf jeden Fall anschauen.

  • Traue keinem Scan, den du nicht selbst gefälscht hast von David Kriesel über einen katastrophalen Fehler in Xerox-Scannern

    Hervorragender Vortrag, sehr unterhaltsam vorgetragen. Für mich der größte Lacher des Congress. Guckempfehlung!

  • Correcting copywrongs von Julia Reda über Copyright-Reformen in der EU

    Sehr empfehlenswerter Vortrag, aufschlussreich und gut zu gucken.

  • Ich sehe, also bin ich .. Du von starbug über Biometrie

    Auch wenn man die Pressemeldung gelesen hat, hält der Vortrag noch einige Überraschungen und Erklärungen bereit und ist in jedem Fall sehenswert.

  • Mit Kunst die Gesellschaft hacken von Stefan Pelzer und Philipp Ruch über das ZPS

    Eine Selbstvorstellung des Zentrums für politische Schönheit. Wer deren Aktivitäten bisher nicht verfolgt hat, sollte sich das wirklich anschauen, ich fand den Vortrag äußerst inspirierend.

  • Security Analysis of Estonia's Internet Voting System von J. Alex Halderman

    Unterhaltsam und aufschlussreich, ungefähr das, was mane rwarten würde.

  • State of the Onion von Jacob und arma über Tor

    Sehenswert wie jedes Jahr, leider aber nicht wie angekündigt mehr Q&A als sonst.

  • Why are computers so @#!*, and what can we do about it? von Peter Sewell

    Ein sehr unterhaltsamer Rant, der trotzdem noch die Kurve zu Lösungsvorschlägen kriegt. Sehenswert!

  • ECCHacks von Tanja Lange und djb über elliptische Kurven

    Eine sehr gute Einführung in elliptische Kurven, die man tatsächlich verstehen kann, wenn man vorher noch nie davon gehört hat. Man sollte durchaus ein bisschen in Mathematik geübt sein, braucht aber eigentlich nur Schulwissen, um es zu verstehen.

  • Let's build a quantum computer! von Andreas Dewes

    Andreas versucht, Quantencomputer einfach zu erklären und der Vortrag macht viel Spaß und war für mich sehr lehrreich, aber ich fürchte, dass man trotz aller Versuche einen gewissen Physik-Background braucht, um ihn zu verstehen.

  • What Ever Happened to Nuclear Weapons? von Michael Büker

    Eine hauptsächlich geschichtliche und politische Zusammenfassung zu allem rund um Atomwaffen – Vortrag ist gut gehalten und bleibt interessant.

  • Why is GPG „damn near unusable“? von Arne Padmos über Usability

    Lehrreicher Vortrag über Grundlagen von Usability, Probleme in aktueller Crypto-Software, etc..

  • Low Cost High Speed Photography von polygon

    Schöner Vortrag, macht Lust zum Nachbauen.

  • Rocket science – how hard can it be?

    Sehr schönes Projekt und unterhaltsam vorgetragen.

  • Security Analysis of a Full-Body X-Ray Scanner von Eric Wustrov und Hovav Schacham

    Schöne Story, schöner Vortrag, viel mehr kann man nicht sagen.

  • Thunderstrike EFI bootkits for Apple MacBooks von Trammell Hudson

    Ich glaube, der Vortrag ist sehr spannend, aber zu weit weg von allem, womit ich mich auskenne, als dass ich gut hätte folgen können.

  • Source Code and Cross-Domain Autorship Attribution

    Bei weitem nicht der erste Vortrag über Stylometry von diesem Team und wie immer beeindruckend, wie gut man aufgrund von Schreibstilen Autoren erkennen kann – dieses Jahr dann auch bei Source Code.

  • Tell no-one von James Bamford über die NSA

    Eine schöne Geschichtstunde über die Geschichte der NSA, in jedem Fall sehenswert und gut erzählt.

  • Reproducible Builds von Mike Perry, Seth Schoen und Hans Steiner

    Ein gutes Plädoyer, warum man reproduzierbare Builds umbedingt haben will; wird ein bisschen, aber nicht sehr technisch.

  • SS7: Locate. Track. Manipulate von Tobias Engel über Mobilfunk

    Konnte ich leider nur während einer Engelschicht mit halben Ohr genießen können, war aber sehr spannend und ist sicherheitstechnisch sicher eines der Highlights.

  • Let's Encrypt von Seth Schoen über eine automatisierte CA

    Ein hervorragendes Projekt der EFF, gut (und knapp) vorgestellt. Der eigentliche Vortrag geht nur eine halbe Stunde, danach viel Q&A.

  • Crypto Tales form the Trenshes über Kryptografie und Journalismus

    Ich bin kein Freund von Podiumsdiskussionen, aber diese kann man sich durchaus ansehen für einen Realitätsabgleich mit der Welt des Journalismus.

  • „Wir beteiligen uns aktiv an den Diskussionen“ von maha über die „Digitale Agenda“

    Habe ich leider bisher nur zur Hälfte gesehen. War sehr vergleichbar zu den vergangenen Congress-Vorträgen von maha und somit wie immer unterhaltsam.

  • The rise and fall of Internet voting in Norway von Tor Bjørstad

    Eine schöne Wahlcomputergeschichte

  • Inside Field Station Berlin Teufelsberg von Bill Scannell

    Durchaus eine unterhaltsame Geschichtsstunde, aber ich werde noch nicht ganz schlau daraus, was ich von dem Vortrag halte und was er uns eigentlich sagen wollte.

  • Krypto für die Zukunft von ruedi

    Kurz und knackig ein Statusupdate über Kryptographie. Nichts umwerfendes, aber eine gute Zusammenfassung.

  • Damn Vulnerable Chemical Process über industrielle Sicherheit

    Ein interessanter Ausflug in ein mir und den meisten anderen eher fern liegendes Gebiet der IT-Security.

  • Internet of toilets von tbsprs

    Eine Kuriosität unter den Congress-Vorträgen, die man sich nicht entgehen lassen sollte ;-)

  • The Matter of Heartbleed

    Hier verstecken sich gleich zwei Vorträge. Beide sind gut vorgetragen, boten mir inhaltlich nicht wahnsinnig viel neues, aber sind durch die Kürze von je 20 Minuten auch erfrischend anzuhören. Der erste ist von einem Forscher, der direkt nach der bekanntgabe von Heartbleed IPv4-Netz-weite Scans durchgeführt hat und der zweite vom Security-Chef von CloudFlare, die damals eine Belohnung ausgelobt hatten für das extrahieren privater Schlüssel via Heartbleed und dann mal getestet haben, wie viel die Zertifikats-Revoke-Infrastruktur so mitmacht.

  • IFG – Mit freundlichen Grüßen von Stefan Wehrmeyer

    Die ersten 20 Minuten sind ein interessanter Vortrag über ein wichtiges Projekt, danach lässt es etwas nach.

  • Freedom in your computer and in the net von Richard Stallman

    Solange man ihn nicht zu wörtlich und ernst nimmt, ein gut gehaltenear Vortrag. Wenig überraschend gibt es keine neuen Inhalte, aber der Vortrag hat durchaus einen Kuriositätswert.

  • Jahresrückblick des CCC

    Genau wie jedes Jahr :-)

  • Vor Windows 8 wird gewarnt von ruedi

    Hielt für mich inhaltlich keine großen Überraschungen bereit, aber eine schöne, kompakte Zusammenfassung bekannter Probleme.

  • Fnord News Show von Frank und Fefe

    Nicht ganz so lustig wie die letzten Jahre, aber kann man nachts durchaus anschauen :)

  • (In)security of Mobile Banking von Eric Filiol und Paul Irolla

    Durchaus interessant, aber inhaltlich keine extrem spannenden Erkenntnisse und sprachlich anstrengend zu folgen.

  • „Hard Drive Punch“ von Aram Bartholl

    bestand eigentlich nur aus YouTube-Videos und war daher nicht so spannend.

  • Beyond PNR: Exploring airline systems von saper

    Das Abstract klang spannend, aber der Vortrag konnte mich nicht lange fesseln.

  • 31C3 Keynote von Alec Empire über … was eigentlich?

    Kann leider nicht mit den Keynotes der letzten Jahre mithalten.

17. January 2015 23:00:00

06. January 2015

Moredreads Blog

03. January 2015

Raphael Michel

Replacing Skype with SIP

I use Skype a lot in my day-to-day communication but I am not happy with it, as it has poor privacy and a crappy client. The alternative for Voice over IP is, of course, the SIP protocol. SIP clients are also more or less crappy, but thanks to ZRTP we can have strong end-to-end-encryption and thanks to OPUS we can have sound quality at least as good as Skype. Furthermore, SIP is a decentralized protocol and, in a perfect world, does not need any servers at all, because it cann directly call other SIP clients based on their IP address.

In our real world, however, there are annoying things like NAT and dynamic IP addresses, so we'd rather have a SIP server (so one can reach me at a static address) and a proxy (so NAT does not hurt that much). There are of course SIP servers out there, even free ones, but I want to host my own one. The fun part is that people do not need an SIP account at all to call me, it just helps when you want to be called.

As a client, I chose Blink, which has pretty much all the features I need and is a quite nice piece of software (with quite bad packaging on most distributions1), the next-best choice would probably be the platform-independent client Jitsi which I also used for testing.

As a server, I chose Kamailio. Kamailio looks pretty complicated but in comparison to other SIP servers it is really simple as it only does registration and proxying (while the proxying itself is done by rtpproxy) and does not have advanced features like voicemail integrated, although it seems to be possible to integrate them. If you have more complex needs, take a look at Asterisk or FreeSWITCH.

In theory, setting up Kamailio on Debian is pretty simple, but in practice there were several pitfalls and I'm not sure I remember them all, so if you follow the instructions in this blogpost and you stumble over strange error messages, do not hesitate to contact me.

To get started, we install some packages. I did all of this on a relatively clean Debian testing (8.0) system.

apt-get install kamailio kamailio-mysql-modules kamailio-tls-modules mysql-server rtpproxy

This might prompt you to choose a mysql root password, if you did not have mysql-server before. Choose one and write it down. Next, we have to edit a bunch of configuration files, the first of which is /etc/default/kamailio, where we just enable the service:

RUN_KAMAILIO=yes

The next file is /etc/kamailio/kamailio.cfg. We add some flags directly after the first line:

#!define WITH_MYSQL
#!define WITH_AUTH 
#!define WITH_USRLOCDB 
#!define WITH_NAT 
#!define WITH_TLS 

Now we choose a mysql user password (we do not have to create the user) and configure it in the DBURL definition somewhere in the same file:

#!define DBURL "mysql://kamailio:firstpassword@localhost/kamailio"

Now look for the alias option and set it to the hostname you want to use as the server part of your SIP address (think of it like email hosts):

alias="sip.rami.io"

Also, look out for the line configuring rtpproxy's port number and change it to:

modparam("rtpproxy", "rtpproxy_sock", "unix:/var/run/rtpproxy/rtpproxy.sock")

The next file is /etc/kamailio/tls.cfg where you can configure your TLS certificates. You should definitively generate new certificates, but if you just want to get started with testing, you can use the ones provided by Kamailio for now:

private_key = /etc/kamailio/kamailio-selfsigned.key 
certificate = /etc/kamailio/kamailio-selfsigned.pem 

Now we successfully configured the kamailio daemon. However, to control this deamon, there is the kamctl command-line utility which has to be configured in /etc/kamailio/kamctlrc. It also needs the same mysql user and password as configured above as well as a second username/password tuple for a read-only mysql user. You still do not have to create those users or databases by yourself.

SIP_DOMAIN=sip.rami.io
DBENGINE=MYSQL
DBHOST=localhost 
DBNAME=kamailio
DBRWUSER="kamailio"  
DBRWPW="firstpassword"
DBROUSER="kamailioro"
DBROPW="secondpassword"
DBROOTUSER="root"

Now we can use this tool to create the mysql users and database tables:

kamdbctl create

This will ask you for your MySQL root password as well as whether to create one or two optional tables (answer both with yes).

Last but not least we configure rtpproxy in /etc/default/rtpproxy:

USER=kamailio
GROUP=kamailio
CONTROL_SOCK="unix:/var/run/rtpproxy/rtpproxy.sock" 

Yey! Except… there is a bug in the rtpproxy debian package. Open /etc/init.d/rtpproxy and change the line DAEMON=/usr/sbin/rtpproxy to DEAMON=/usr/bin/rtpproxy.

Now start and enable the services (for Debian 7.0 or older, use the init scripts directly):

systemctl enable rtpproxy
systemctl start rtpproxy
systemctl enable kamailio
systemctl start kamailio

Done! You can now setup your SIP client. In Blink, if you are behind the NAT, set up the account, then go to settings, select your account and go to the Server Settings tab. Then enter your hostname as Outpound proxy, select port 5061 and TLS transport. Also make sure to fill in user username and tick the Always use checkbox, if you want to.

Again, it might be that I missed to mention one or two pitfalls I came by, so please write me an email/xmpp message if you get stuck.


  1. The Arch User Repository package for example misses at least python2-eventlib, python2-xcaplib and python2-msrplib as dependencies. 

03. January 2015 23:00:00

21. November 2014

RaumZeitLabor

Letzte Chance: Anmeldung zur Trollcon 2014

Sie wollen bei der TROLLCON 2014 dabei sein? Nehmen Sie sich wenige Minuten Zeit für die unkomplizierte Anmeldung. Füllen Sie einfach das Anmeldeformular aus und faxen Sie es an folgende Nummer: 0621 / 86429843

Überweisungen müssen bis Dienstag eingegangen sein, ansonsten kann es sein, dass Sie ohne Konferenz-Shirt auskommen müssen.

Alle Informationen zur Trollcon finden Sie auch in der Cloud unter trollcon.de.

by Alexander Brock at 21. November 2014 18:20:44

Letzte Chance: Anmeldung zur Trollcon 2014

Sie wollen bei der TROLLCON 2014 dabei sein? Nehmen Sie sich wenige Minuten Zeit für die unkomplizierte Anmeldung. Füllen Sie einfach das Anmeldeformular aus und faxen Sie es an folgende Nummer: 0621 / 86429843

Überweisungen müssen bis Dienstag eingegangen sein, ansonsten kann es sein, dass Sie ohne Konferenz-Shirt auskommen müssen.

Alle Informationen zur Trollcon finden Sie auch in der Cloud unter trollcon.de.

21. November 2014 18:20:44

20. November 2014

RaumZeitLabor

Tatarroh – Mettwoch im RaumZeitLabor

Ta tar roh – Tatarroh – Ta tar roh – Tatarroh

Unser Nachbar Tatarroh ist ein freundliches Wesen, das nur von
Fleischessern gesehen wird. Als Hack- und Mettgeister verfügen Tatarrohs
über besondere Fähigkeiten. Sie können beispielsweise durch ein Ritual
langweilige Brötchen in ein zauberhaftes Abendessen verwandeln.

Reist zahlreich mit dem zwölfschaligen Zwiebelkatzenbus am nächsten
Mittwoch, den 26. November, ins RaumZeitLabor. Tatarroh wird uns ab 19.00
Uhr einen Besuch abstatten. Damit er weiß, wie oft er seinen Brötchentrick
anwenden soll, bittet er um vorherige Anmeldung bis Dienstag, 13.37Uhr.

Tatarroh_klein

by TabascoEye at 20. November 2014 22:59:43

Tatarroh - Mettwoch im RaumZeitLabor

Ta tar roh - Tatarroh - Ta tar roh - Tatarroh

Unser Nachbar Tatarroh ist ein freundliches Wesen, das nur von
Fleischessern gesehen wird. Als Hack- und Mettgeister verfügen Tatarrohs
über besondere Fähigkeiten. Sie können beispielsweise durch ein Ritual
langweilige Brötchen in ein zauberhaftes Abendessen verwandeln.

Reist zahlreich mit dem zwölfschaligen Zwiebelkatzenbus am nächsten
Mittwoch, den 26. November, ins RaumZeitLabor. Tatarroh wird uns ab 19.00
Uhr einen Besuch abstatten. Damit er weiß, wie oft er seinen Brötchentrick
anwenden soll, bittet er um vorherige Anmeldung bis Dienstag, 13.37Uhr.

Tatarroh_klein

20. November 2014 22:59:43

14. November 2014

xeens Blog

Remote control Bravia TVs that require authentication

While older Sony Bravia TVs don’t require authentication to receive commands via HTTP, mine does. If you try, it will complain with an “Action not authorized” error. Others [1] [2] have the same problem, but there were no solutions available as of writing.

Luckily the authentication scheme is very simple and can be implemented in a couple of cURL calls. Unfortunately the cURL commands get rather long, so I’ve put them into simple shell scripts. The code is available on GitHub.

Usage: Authentication

  1. Clone the repository: git clone https://github.com/breunigs/bravia-auth-and-remote
  2. Edit auth.sh and enter your TV’s IP address. Also specify your device name (most likely $HOST) and a “nick” for this authentication. It’s only used for identification purposes in the TV’s menu.
  3. Run ./auth.sh. It will make two requests to the TV that are almost identical. The first will fail due to missing authentication, but the TV will display a PIN. Enter that 4-digit code into the still running script and hit enter. The script will repeat the request, but this time with HTTP Basic Authentication without user name, using the password/PIN you just entered.
  4. The script will print an auth= line. This is the cookie that has to be passed to each further request to the TV. When you use cURL, just add --cookie 'auth=…' and your requests should work.

Commands found on other websites will usually work once you add the cookie parameter.

Usage: Basic Remote Control

The repository contains some helpers I found useful. They will automatically read the auth_cookie file that has been created when you ran auth.sh, so you don’t have to specify it each time.

  • ./print_ircc_codes.sh <TV-IP>: Prints list of IRCC (remote control commands) that your TV understands.
  • ./send_command.sh <TV-IP> <IRCC-Command>: Sends an actual command to the TV. Note that it will return immediately, i.e. it does not wait for the TV to actually finish the command. The TV will return an error if the given command is invalid. However, it will report success, even if the command does not make sense. Instead, it will display an OSD message.
  • ./example_goto_media_player.sh: An example which will (most likely) open the media player. Note the sleeps have to be adapted to the action executed.

Other Commands / More Details

You can find some unused commands I extracted from the TCP dump as cURL calls in the commands file.

If you want to reverse engineer some more, it’s obvious you need to intercept the connection between the “TV SideView Sony” app and the TV. A very convenient way is to install tPacketCapture on your Android. It works as a proxy that outputs a .pcap file you can easily inspect with Wireshark. tPacketCapture doesn’t require root.

Enjoy!

14. November 2014 21:30:00

03. October 2014

Raphael Michel

Deploying Django without downtime

One of my active projects is abiapp.net, a SaaS content management tool for the collaborative creation of yearbook contents, primarily targeted to German high scool students. While we currently have few enough users to run all of abiapp.net on a single machine, we have enough users that at any time of the day one of us is working on the project, a user is online. We have a philosophy of pushing new code in very small intervals, days with multiple updates on the same day are nothing uncommon.

However, I do not enjoy pushing new code if I know that all users currently using the website will be interrupted – pretty much everything in our application happens in real-time, so users will surely recognize a downtime of up to a minute. There would have been several possibilities to shorten this time frame but I have decided to work on a solution without any measurable downtime at all.

The general setup

Our application is implemented in Python using Django and runs on a Debian stable virtual machine. The Django application lives inside a gunicorn instance, which is a lightweight HTTP server on top of the WSGI protocol you should use if you do web stuff in Python. On top of all, there is a nginx webserver which servers static content and acts as a proxy for gunicorn. We use MySQL as our database backand and we have a background task queue for long-running tasks powered by Celery and RabbitMQ as a message broker. The gunicorn instance is being controlled by supervisord.

The old deployment setup

We currently deploy using git. We have a git remote on our production server which has a post-receive hook which executed the following tasks:

  • Load the new source code into the working direcotry
  • Make a database backup (we learned this the hard way)
  • Perform database migrations
  • Compile LESS to CSS
  • Compress static files
  • Execute unit tests, just to be sure
  • Reload gunicorn

However, this setup has some very huge problems. The biggest one is that in the moment we load our new code into the working directory, Django will use our new templates and static files even though we are still running on the old python code. This is already bad, but it gets way worse in the unlikely event that the unit tests fail and the new python code is not loaded – then we're stuck in this intermediate state of broken things.

The new deployment setup

We now have two completely independent instances of the application. We have have our git repository three times on the production server:

$ ls app.*
app.src/
app.run.A/
app.run.B/

app.src is the bare git repository we push our changes to and app.run.A and app.run.B are two copies of it used for running the application. The application always runs twice:

$ supervisorctl status
abiapp.A       RUNNING    pid 6184, uptime 0:00:02
abiapp.B       RUNNING    pid 6185, uptime 0:00:02

One of those processes runs with the code and templates from app.run.A, one with the other. They listen on different sockets and supervisord knows them as distinct services.

We also have two copies of our nginx webserver config, one of them pointing to the socket of process A and one to the socket of process B. Only one of them is enabled at the same time:

$ ls /etc/nginx/sites-available/
abiapp.net-A
abiapp.net-B
$ ls /etc/nginx/sites-enabled/
abiapp.net-A

The nginx config

The nginx configuration looks a bit like this:

upstream abiapp_app_server_A {
    server unix:/home/abiapp/run/gunicorn.A.sock fail_timeout=0;
}

server {
    listen 443;
    server_name .abiapp.net;

    # … SSL foo …

    location /static/ { # The static files directory
        alias /var/www/users/abiapp/www.abiapp.net/static.A/;
        access_log off;
        expires 7d;
        add_header Cache-Control public;
        add_header Pragma public;
        access_log off;
    }

    location /media/ {
        # …
    }

    location / { # The application proxy
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://abiapp_app_server_A;
            break;
        }
        root /var/www/users/abiapp/www.abiapp.net/;
    }

    # error pages …
}

The git hook

So our post-receive hook has to find out which of those two processes currently serves users and replace the other process with the new code. We'll now walk through this git hook pice by piece.

The first part determines which instance is running by looking into a text file containing the string A or B. We'll write the current instance name into this file later in our hook.

#!/bin/bash
if [[ "$(cat /home/abiapp/run/selected)" == "B" ]]; then
    RUNNING="B"
    STARTING="A"
else
    RUNNING="A"
    STARTING="B"
fi

We now activate the virtual python environment our application lives in and move to the application's source code.

unset GIT_DIR
source /home/abiapp/appenv/bin/activate
cd /home/abiapp/app.run.$RUNNING/src

First of all, we'll do a backup, just to be sure. You could also use mysqldump here.

echo "* Backup"
python manage.py dumpdata > ~/backup/dump_$(date +"%Y-%m-%d-%H-%M")_push.json

We now pull the new source code into our current directory.

echo "* Reset server repository"
git reset --hard
git pull /home/abiapp/app.src master || exit 1
cd src

Then, we perform database migrations and deploy our static files.

echo "* Perform database migrations"
python manage.py migrate || exit 1
echo "* Deploy static files"
python manage.py collectstatic --noinput || exit 1
echo "* Compress static files"
python manage.py compress || exit 1

Note: The two source code directories have slightly different Django configuration files: Their STATIC_ROOT settings point to different directories.

We now perform our unit tests on the production server:

echo "* Unit Tests"
python manage.py test app || exit 1;

And finally restart the gunicorn process.

echo "* Restart app"
sudo supervisorctl restart abiapp.$STARTING

Remember, we just restarted a process which was not visible to the Internet, we replaced the idling one of our instances. Now the time has come to reload our webserver:

echo "* Reload webserver"
sudo /usr/local/bin/abiapp-switch $STARTING

The abiapp-switch script does no more than replacing the link in /etc/nginx/sites-enabled by the other configuration file and then calling service nginx reload.

This is the moment our new code goes live. On the reload call, nginx spawns up new workers using the new configuration1. All old workers will finish their current requests and then shut down, so that there really is no measurable downtime. To have the hook complete, we restart celery (which waits for all running workers to finish their tasks, then restarts with the new code):

echo "* Restart task queue"
sudo service celeryd restart 

And finally we report success and store the name of the newly running instance.

echo "Done :-)"
echo "Instance $STARTING is running now"
echo $STARTING > /home/abiapp/run/selected

So we're done here. As you may have noticed, all early steps of the hook included an || exit 1. In case of a failed migration, unit test or compression, the whole process would just abort and leave us virtually unharmed, as the working instance keeps running.

A word on database migrations

As you may have noticed, we still have one flaw in our workflow: The database migrations are applied some time before the new code is running. The only really clean solution is to split each of your 'destructive' database migrations into multiple deployment iterations: If you for example remove a field from a model (a column from a table), you'd first push the new code with all usage of the field being removed and then, in a second push, you'd deploy the database migration which removes the column.

03. October 2014 22:00:00

12. September 2014

Mero’s Blog

The four things I miss about go

As people who know me know, my current favourite language is go. One of the best features of go is the lack of features. This is actually the reason I preferred C over most scripting languages for a long time – it does not overburden you with language-features that you first have to wrap your head around. You don't have to think for a while about what classes or modules or whatever you want to have, you just write your code down and the (more or less) entire language can easily fit inside your head. One of the best writeups of this (contrasting it with python) was done by Gustavo Niemeyer in a blogpost a few years back.

So when I say, there are a few things popping up I miss about go, this does not mean I wish them to be included. I subjectively miss them and it would definitely make me happy, if they existed. But I still very much like the go devs for prioritizing simplicity over making me happy.

So let's dig in.

  1. Generics
  2. Weak references
  3. Dynamic loading of go code
  4. Garbage-collected goroutines

Generics

So let's get this elephant out of the room first. I think this is the most named feature lacking from go. They are asked so often, they have their own entry in the go FAQ. The usual answers are anything from "maybe they will get in" to "I don't understand why people want generics, go has generic programming using interfaces". To illustrate one shortcoming of the (current) interface approach, consider writing a (simple) graph-algorithm:

type Graph [][]int

func DFS(g Graph, start int, visitor func(int)) {
    visited := make([]bool, len(g))

    var dfs func(int)
    dfs = func(i int) {
        if visited[i] {
            return
        }
        visitor(i)
        visited[i] = true
        for _, j := range g[i] {
            dfs(j)
        }
    }

    dfs(start)
}

This uses an adjacency list to represent the graph and does a recursive depth-first-search on it. Now imagine, you want to implement this algorithm generically (given, a DFS is not really hard enough to justify this, but you could just as easily have a more complex algorithm). This could be done like this:

type Node interface{}

type Graph interface {
    Neighbors(Node) []Node
}

func DFS(g Graph, start Node, visitor func(Node)) {
    visited := make(map[Node]bool)

    var dfs func(Node)
    dfs = func(n Node) {
        if visited[n] {
            return
        }
        visitor(n)
        visited[n] = true
        for _, n2 := range g.Neighbors(n) {
            dfs(n2)
        }
    }

    dfs(start)
}

This seems simple enough, but it has a lot of problems. For example, we loose type-safety: Even if we write Neighbors(Node) []Node there is no way to tell the compiler, that these instances of Node will actually always be the same. So an implementation of the graph interface would have to do type-assertions all over the place. Another problem is:

type AdjacencyList [][]int

func (l AdjacencyList) Neighbors(n Node) []Node {
    i := n.(int)
    var result []Node
    for _, j := range l[i] {
        result = append(result, j)
    }
    return result
}

An implementation of this interface as an adjacency-list actually performs pretty badly, because it can not return an []int, but must return a []Node, and even though int satisfies Node, []int is not assignable to []Node (for good reasons that lie in the implementation of interfaces, but still).

The way to solve this, is to always map your nodes to integers. This is what the standard library does in the sort-package. It is exactly the same problem. But it might not always be possible, let alone straightforward, to do this for Graphs, for example if they do not fit into memory (e.g. a web-crawler). The answer is to have the caller maintain this mapping via a map[Node]int or something similar, but… meh.

Weak references

I have to admit, that I am not sure, my use case here is really an important or even very nice one, but let's assume I want to have a database abstraction that transparently handles pointer-indirection. So let's say I have two tables T1 and T2 and T2 has a foreign key referencing T1. I think it would be pretty neat, if a database abstraction could automatically deserialize this into a pointer to a T1-value A. But to do this. we would a) need to be able to recognize A a later Put (so if the user changes A and later stores it, the database knows what row in T1 to update) and b) hand out the same pointer, if another row in T2 references the same id.

The only way I can think how to do this is to maintain a map[Id]*T1 (or similar), but this would prevent the handed out values to ever be garbage-collected. Even though there a hacks that would allow some use cases for weak references to be emulated, I don't see how they would work here.

So, as in the case of generics, this mainly means that some elegant APIs are not possible in go for library authors (and as I said, in this specific case it probably isn't a very good idea. For example you would have to think about what happens, if the user gets the same value in two different goroutines from the database).

Dynamic loading of go code

It would be useful to be able to dynamically load go code at runtime, to build plugins for go software. Specifically I want a good go replacement for jekyll because I went through some ruby-version-hell with it lately (for example jekyll serve -w still does not work for me with the version packaged in debian) and I think a statically linked go-binary would take a lot of possible pain-points out here. But plugins are a really important feature of jekyll for me, so I still want to be able to customize a page with plugins (how to avoid introducing the same version hell with this is another topic).

The currently recommended ways to do plugins are a) as go-packages and recompiling the whole binary for every change of a plugin and b) using sub-processes and net/rpc.

I don't feel a) being a good fit here, because it means maintaining a separate binary for every jekyll-site you have which just sounds like a smallish nightmare for binary distributions (plus I have use cases for plugins where even the relatively small compilation times of go would result in an intolerable increase in startup-time).

b) on the other hand results in a lot of runtime-penalty: For example I can not really pass interfaces between plugins, let alone use channels or something and every function call has to have its parameters and results serialized and deserialized. Where in the same process I can just define a transformation between different formats as a func(r io.Reader) io.Reader or something, in the RPC-context I first have to transmit the entire file over a socket, or have the plugin-author implement a net/rpc server himself and somehow pass a reference to it over the wire. This increases the burden on the plugin-authors too much, I think.

Luckily, it seems there seems to be some thought put forward recently on how to implement this, so maybe we see this in the nearish future.

Garbage-collected goroutines

Now, this is the only thing I really don't understand why it is not part of the language. Concurrency in go is a first-class citizen and garbage-collection is a feature emphasized all the time by the go-authors as an advantage. Yet, they both seem to not play entirely well together, making concurrency worse than it has to be.

Something like the standard example of how goroutines and channels work goes a little bit like this:

func Foo() {
    ch := make(chan int)
    go func() {
        i := 0
        for {
            ch <- i
            i++
        }
    }()

    for {
        fmt.Println(<-ch)
    }
}

Now, this is all well, but what if we want to exit the loop prematurely? We have to do something like this:

func Foo() {
    ch := make(chan int)
    done := make(chan bool)
    go func() {
        i := 0
        for {
            select {
                case ch <- i:
                    i++
                case <-done:
                    return
            }
        }
    }()
    for {
        i := <-ch
        if i > 1000 {
            break
        }
        fmt.Println(i)
    }
}

Because otherwise the goroutine would just stay around for all eternity, effectively being leaked memory. There are entire talks build around this and similar problems, where I don't really understand why. If we add a break to our first version, Foo returns and suddenly, all other references to ch, except the one the goroutine is blocking on writing to are gone and can be garbage-collected. The runtime can already detect if all goroutines are sleeping and we have a deadlock, the garbage-collector can accurately see what references there are to a given channel, why can we not combine the two to just see "there is absolutely no way, this channel-write can ever succeed, so let's just kill it and gc all it's memory"? This would have zero impact on existing programs (because as you can not get any references to goroutines, a deadlocked one can have no side-effect on the rest of the program), but it would make channels so much more fun to work with. It would make channels as iterators a truly elegant pattern, it would simplify pipelines and it would possibly allow a myriad other use cases for channels I can not think of right now. Heck, you could even think about (not sure if this is possible or desirable) running any deferred statements, when a goroutine is garbage-collected, so all other resources held by it will be correctly released.

This is the one thing I really wish to be added to the language. Really diving into channels and concurrency right now is very much spoiled for me because I always have to think about draining every channel, always think about what goroutine closes what channels, passing cancellation-channels…

12. September 2014 17:10:28

05. September 2014

sECuREs Webseite

Fiber7 performance

Ever since I moved to Zürich, I wanted to get a fiber internet connection. I’ve lived with a 6 Mbps DSL line at my parent’s place for about 10 years, so I was looking forward to a lot more Megabits and a lot less latency. For reasons that I won’t go into in this article, it took me about a year to get a fiber connection, and in the end I had to go with Swisscom (instead of init7 on top of EWZ).

But then fiber7 launched. They provide a 1 Gbps symmetrical connection (Swisscom provided a 1 Gbps/100 Mbps down/up connection) for a lot less money than Swisscom, and with native, static IPv6.

A couple of people are interested in how fiber7 performs, and after being connected for about 2 months, I think I can answer this question by now :-).

Latency

I started running smokeping to see how my internet connection performs back when I was with Swisscom, because they had some routing issues to certain networks. This would manifest itself with getting 50 KB/s transfer rates, which is unacceptable for image boards or any other demanding application.

So, here is the smokeping output for google.ch during the time period that covers both my Swisscom line, the temporary cablecom connection and finally fiber7:

smokeping latency to google.ch (annotated)

What you can see is that with Swisscom, I had a 6 ms ping time to google.ch. Interestingly, once I used the MikroTik RB2011 instead of the Swisscom-provided internet box, the latency improved to 5 ms.

Afterwards, latency changed twice. For the first change, I’m not sure what happened. It could be that Swisscom turned up a new, less loaded port to peer with Google. Or perhaps they configured their systems in a different way, or exchanged some hardware. The second change is relatively obvious: Swisscom enabled GGC, the Google Global Cache. GGC is a caching server provided by Google that is placed within the ISP’s own network, typically providing much better latencies (due to being placed very close to the customer) and reducing the traffic between the ISP and Google. I’m confident that Swisscom uses that because of the reverse pointer record of the IP address to which google.ch resolves to. So with that, latency is between 1 ms and 3 ms.

Because switching to Fiber7 involves recabling the physical fiber connection in the POP, there is a 2-day downtime involved. During that time I used UPC cablecom’s free offering, which is a 2 Mbps cable connection that you can use for free (as long as you pay for the cable connection itself, and after paying 50 CHF for the modem itself).

As you can see on the graph, the cable connection has a surprisingly good latency of around 8 ms to google.ch — until you start using it. Then it’s clear that 2 Mbps is not enough and the latency shoots through the roof.

The pleasant surprise is that fiber7’s ping time to google.ch is about 0.6 ms (!). They achieve such low latency with a dedicated 10 gig interconnect to Google at the Interxion in Glattbrugg.

Longer-term performance

smokeping latency measurements to google.ch over more than a week

Let me say that I’m very happy with the performance of my internet connection. Some of the measurements where packet loss is registered may be outside of fiber7’s control, or even caused by me, when recabling my equipment for example. Overall, the latency is fine and consistent, much more so than with Swisscom. I have never experienced an internet outage during the two months I’ve been with fiber7 now.

Also, while I am not continuously monitoring my bandwidth, rest assured that whenever I download something, I am able to utilize the full Gigabit, meaning I get an aggregate speed of 118 MB/s from servers that support it. Such servers are for example one-click hosters like uploaded, but also Debian mirrors (as soon as you download from multiple ones in parallel).

Conclusion

tl;dr: fiber7 delivers. Incredible latency, no outages (yet), full download speed.

by Michael Stapelberg at 05. September 2014 12:00:00

31. August 2014

sECuREs Webseite

Replicated PostgreSQL with pgpool2

I run multiple web services, mostly related to i3wm.org. All of them use PostgreSQL as their database, so the data that is stored in that PostgreSQL database is pretty important to me and the users of these services.

Since a while now, I have been thinking about storing that data in a more reliable way. Currently, it is stored on a single server, and is backed up to two different locations (one on-site, one off-site) every day. The server in question has a RAID-1 of course, but still: the setup implies that if that one server dies, the last backup may be about a day old in the worst case, and also it could take me significant time to get the services back up.

The areas in which I’d like to improve my setup are thus:

  1. Durability: In case the entire server dies, I want to have an up-to-date copy of all data.
  2. Fault tolerance: In case the entire server dies, I want to be able to quickly switch to a different server. A secondary machine should be ready to take over, albeit not fully automatically because fully automatic solutions typically are either fragile or require a higher number of servers than I’m willing to afford.

For PostgreSQL, there are various settings and additional programs that you can use which will provide you with some sort of clustering/replication. There is an overview in the PostgreSQL wiki (“Replication, Clustering, and Connection Pooling”). My solution of choice is pgpool2 because it seems robust and mature (yet under active development) to me, it is reasonably well documented and I think I roughly understand what it does under the covers.

The plan

I have two servers, located in different data centers, that I will use for this setup. The number of servers does not really matter, meaning you can easily add a third or fourth server (increasing latency with every server of course). However, the low number of servers places some restrictions on what we can do. As an example, solutions that involve global consistency based on paxos/raft quorums will not work with only two servers. As a consequence, master election is out of the question and a human will need to do the actual failover/recovery.

Each of the two servers will run PostgreSQL, but only one of them will run pgpool2 at a time. The DNS records for e.g. faq.i3wm.org will point to the server on which pgpool2 is running, so that server handles 100% of the traffic. Let’s call the server running pgpool2 the primary, and the other server the secondary. All queries that modify the database will still be sent to the secondary, but the secondary does not handle any user traffic. This could be accomplished by either not running the applications in question, or by having them connect to the pgpool2 on the primary.

When a catastrophe happens, the DNS records will be switched to point to the old-secondary server, and pgpool2 will be started there. Once the old-primary server is available again, it will become the secondary server, so that in case of another catastrophe, the same procedure can be executed again.

With a solution that involves only two servers, an often encountered problem are split-brain situations. This means both servers think they are primary, typically because there is a network partition, meaning the servers cannot talk to each other. In our case, it is important that user traffic is not handled by the secondary server. This could happen after failing over because DNS heavily relies on caching, so switching the record does not mean that suddenly all queries will go to the other server — this will only happen over time. A solution for that is to either kill pgpool2 manually if possible, or have a tool that kills pgpool2 when it cannot verify that the DNS record points to the server.

Configuration

I apologize for the overly long lines in some places, but there does not seem to be a way to use line continuations in the PostgreSQL configuration file.

Installing and configuring PostgreSQL

The following steps need to be done on each database server, whereas pgpool2 will only be installed on precisely one server.

Also note that a prerequisite for the configuration described below is that hostnames are configured properly on every involved server, i.e. hostname -f should return the fully qualified hostname of the server in question, and other servers must be able to connect to that hostname.

apt-get install postgresql postgresql-9.4-pgpool2 rsync ssh
cat >>/etc/postgresql/9.4/main/postgresql.conf <<'EOT'
listen_addresses = '*'

max_wal_senders = 1
wal_level = hot_standby
archive_mode = on
archive_command = 'test ! -f /var/lib/postgresql/9.4/main/archive_log/backup_in_progress || (test -f /var/lib/postgresql/9.4/main/archive_log/%f || cp %p /var/lib/postgresql/9.4/main/archive_log/%f)'
EOT
install -o postgres -g postgres -m 700 -d \
  /var/lib/postgresql/9.4/main/archive_log
systemctl restart postgresql.service

pgpool comes with an extension (implemented in C) that provides a couple of functions which are necessary for recovery. We need to “create” the extension in order to be able to use these functions. After running the following command, you can double-check with \dx that the extension was installed properly.

echo 'CREATE EXTENSION "pgpool_recovery"' | \
  su - postgres -c 'psql template1'

During recovery, pgpool needs to synchronize data between the PostgreSQL servers. This is done partly by running pg_basebackup on the recovery target via SSH and using rsync (which connects using SSH). Therefore, we need to create a passwordless SSH key for the postgres user. For simplicity, I am implying that you’ll copy the same id_rsa and authorized_keys files onto every database node. You’ll also need to connect to every other database server once in order to get the SSH host fingerprints into the known_hosts file.

su - postgres
ssh-keygen -f /var/lib/postgresql/.ssh/id_rsa -N ''
cat .ssh/id_rsa.pub >> .ssh/authorized_keys
exit

We’ll also need to access remote databases with pg_basebackup non-interactively, so we need a password file:

su - postgres
echo '*:*:*:postgres:wQgvBEusf1NWDRKVXS15Fc8' > .pgpass
chmod 0600 .pgpass
exit

When pgpool recovers a node, it first makes sure the data directory is up to date, then it starts PostgreSQL and tries to connect repeatedly. Once the connection succeeded, the node is considered healthy. Therefore, we need to give the postgres user permission to control postgresql.service:

apt-get install sudo
cat >/etc/sudoers.d/pgpool-postgres <<'EOT'
postgres ALL=(ALL:ALL) NOPASSWD:/bin/systemctl start postgresql.service
postgres ALL=(ALL:ALL) NOPASSWD:/bin/systemctl stop postgresql.service
EOT

Now enable password-based authentication for all databases and replication traffic. In case your database nodes/clients don’t share a common hostname suffix, you may need to use multiple entries or replace the hostname suffix by “all”.

cat >>/etc/postgresql/9.4/main/pg_hba.conf <<'EOT'
host    all             all             .zekjur.net             md5     
host    replication     postgres        .zekjur.net             md5     
EOT

After enabling password-based authentication, we need to set a password for the postgres user which we’ll use for making the base backup:

echo "ALTER USER postgres WITH PASSWORD 'wQgvBEusf1NWDRKVXS15Fc8';" | \
  su postgres -c psql

Installing pgpool2

apt-get install pgpool2
cd /etc/pgpool2
gunzip -c /usr/share/doc/pgpool2/examples/\
pgpool.conf.sample-replication.gz > pgpool.conf

To interact with pgpool2, there are a few command-line utilities whose name starts with pcp_. In order for these to work, we must configure a username and password. For simplicity, I’ll re-use the password we set earlier for the postgres user, but you could chose to use an entirely different username/password:

echo "postgres:$(pg_md5 wQgvBEusf1NWDRKVXS15Fc8)" >> pcp.conf

In replication mode, when the client should authenticate towards the PostgreSQL database, we also need to tell pgpool2 that we are using password-based authentication:

sed -i 's/trust$/md5/g' pool_hba.conf
sed -i 's/\(enable_pool_hba =\) off/\1 on/g' pgpool.conf

Furthermore, we need to provide all the usernames and passwords that we are going to use to pgpool2:

touch pool_passwd
chown postgres.postgres pool_passwd
pg_md5 -m -u faq_i3wm_org secretpassword

For the use-case I am describing here, it is advisable to turn off load_balance_mode, otherwise queries will be sent to all healthy backends, which is slow because they are not in the same network. In addition, we’ll assign a higher weight to the backend which runs on the same machine as pgpool2, so read-only queries are sent to the local backend only.

sed -i 's/^load_balance_mode = on/load_balance_mode = off/g' \
    pgpool.conf

Now, we need to configure the backends.

sed -i 's/^\(backend_\)/# \1/g' pgpool.conf

cat >>pgpool.conf <<'EOT'
backend_hostname0 = 'midna.zekjur.net'
backend_port0 = 5432
backend_weight0 = 2
backend_data_directory0 = '/var/lib/postgresql/9.4/main'

backend_hostname1 = 'alp.zekjur.net'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/var/lib/postgresql/9.4/main'
EOT

Overview: How recovery works

Let’s assume that pgpool is running on midna.zekjur.net (so midna is handling all the traffic), and alp.zekjur.net crashed. pgpool will automatically degrade alp and continue operation. When you tell it to recover alp because the machine is available again, it will do three things:

  1. (“1st stage”) SSH into alp and run pg_basebackup to get a copy of midna’s database.
  2. (“2nd stage”) Disconnect all clients so that the database on midna will not be modified anymore. Flush all data to disk on midna, then rsync the data to alp. pg_basebackup from 1st stage will have copied almost all of it, so this is a small amount of data — typically on the order of 16 MB, because that’s how big one WAL file is.
  3. Try to start PostgreSQL on alp again. pgpool will wait for 90 seconds by default, and within that time PostgreSQL must start up in such a state that pgpool can connect to it.

So, during the 1st stage, which copies the entire database, traffic will still be handled normally, only during 2nd stage and until PostgreSQL started up no queries are served.

Configuring recovery

For recovery, we need to provide pgpool2 with a couple of shell scripts that handle the details of how the recovery is performed.

sed -i 's/^\(recovery_\|client_idle_limit_in_recovery\)/# \1/g' \
    pgpool.conf

cat >>pgpool.conf <<'EOT'
recovery_user = 'postgres'
recovery_password = 'wQgvBEusf1NWDRKVXS15Fc8'

# This script is being run by invoking the pgpool_recovery() function on
# the current master(primary) postgresql server. pgpool_recovery() is
# essentially a wrapper around system(), so it runs under your database
# UNIX user (typically "postgres").
# Both scripts are located in /var/lib/postgresql/9.4/main/
recovery_1st_stage_command = '1st_stage.sh'
recovery_2nd_stage_command = '2nd_stage.sh'

# Immediately disconnect all clients when entering the 2nd stage recovery
# instead of waiting for the clients to disconnect.
client_idle_limit_in_recovery = -1
EOT

The 1st_stage.sh script logs into the backend that should be recovered and uses pg_basebackup to copy a full backup from the master(primary) backend. It also sets up the recovery.conf which will be used by PostgreSQL when starting up.

cat >/var/lib/postgresql/9.4/main/1st_stage.sh <<'EOF'
#!/bin/sh
TS=$(date +%Y-%m-%d_%H-%M-%S)
MASTER_HOST=$(hostname -f)
MASTER_DATA=$1
RECOVERY_TARGET=$2
RECOVERY_DATA=$3

# Move the PostgreSQL data directory out of our way.
ssh -T $RECOVERY_TARGET \
    "[ -d $RECOVERY_DATA ] && mv $RECOVERY_DATA $RECOVERY_DATA.$TS"

# We only use archived WAL logs during recoveries, so delete all
# logs from the last recovery to limit the growth.
rm $MASTER_DATA/archive_log/*

# With this file present, our archive_command will actually
# archive WAL files.
touch $MASTER_DATA/archive_log/backup_in_progress

# Perform a backup of the database.
ssh -T $RECOVERY_TARGET \
    "pg_basebackup -h $MASTER_HOST -D $RECOVERY_DATA --xlog"

# Configure the restore_command to use the archive_log WALs we’ll copy
# over in 2nd_stage.sh.
echo "restore_command = 'cp $RECOVERY_DATA/archive_log/%f %p'" | \
    ssh -T $RECOVERY_TARGET "cat > $RECOVERY_DATA/recovery.conf"
EOF
cat >/var/lib/postgresql/9.4/main/2nd_stage.sh <<'EOF'
#! /bin/sh
MASTER_DATA=$1
RECOVERY_TARGET=$2
RECOVERY_DATA=$3
port=5432

# Force to flush current value of sequences to xlog
psql -p $port -t -c 'SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn' template1|
while read i
do
  if [ "$i" != "" ];then
    psql -p $port -c "SELECT setval(oid, nextval(oid)) FROM pg_class WHERE relkind = 'S'" $i
  fi
done

# Flush all transactions to disk. Since pgpool stopped all connections,
# there cannot be any data that does not reside on disk until the
# to-be-recovered host is back on line.
psql -p $port -c "SELECT pgpool_switch_xlog('$MASTER_DATA/archive_log')" template1

# Copy over all archive logs at once.
rsync -avx --delete $MASTER_DATA/archive_log/ \
    $RECOVERY_TARGET:$RECOVERY_DATA/archive_log/

# Delete the flag file to disable WAL archiving again.
rm $MASTER_DATA/archive_log/backup_in_progress
EOF
cat >/var/lib/postgresql/9.4/main/pgpool_remote_start <<'EOF'
#!/bin/sh
ssh $1 sudo systemctl start postgresql.service
EOF

chmod +x /var/lib/postgresql/9.4/main/1st_stage.sh
chmod +x /var/lib/postgresql/9.4/main/2nd_stage.sh
chmod +x /var/lib/postgresql/9.4/main/pgpool_remote_start

Now, let’s start pgpool2 and verify that it works and that we can access our first node. The pcp_node_count command should return an integer number like “2”. The psql command should be able to connect and you should see your database tables when using \d.

systemctl restart pgpool2.service
pcp_node_count 10 localhost 9898 postgres wQgvBEusf1NWDRKVXS15Fc8
psql -p 5433 -U faq_i3wm_org faq_i3wm_org

Monitoring

pgpool2 intercepts a couple of SHOW statements, so you can use the SQL command SHOW pool_nodes to see how many nodes are there:

> SHOW pool_nodes;
 node_id |     hostname     | port | status | lb_weight |  role  
---------+------------------+------+--------+-----------+--------
 0       | midna.zekjur.net | 5432 | 2      | 0.666667  | master
 1       | alp.zekjur.net   | 5432 | 2      | 0.333333  | slave
(2 rows)

You could export a cgi-script over HTTP, which just always runs this command, and then configure your monitoring software to watch for certain strings in the output. Note that you’ll also need to configure a ~/.pgpass file for the www-data user. As an example, to monitor whether alp is still a healthy backend, match for “alp.zekjur.net,5432,2” in the output of this script:

#!/bin/sh
cat <<'EOT'
Content-type: text/plain

EOT
exec echo 'SHOW pool_nodes;' | psql -t -A -F, --host localhost \
  -U faq_i3wm_org faq_i3wm_org

Performing/Debugging a recovery

In order to recover node 1 (alp in this case), use:

pcp_recovery_node 300 localhost 9898 postgres wQgvBEusf1NWDRKVXS15Fc8 1

The “300” used to be a timeout, but these days it’s only supported for backwards compatibility and has no effect.

In case the recovery fails, the only thing you’ll get back from pcp_recovery_node is the text “BackendError”, which is not very helpful. The logfile of pgpool2 contains a bit more information, but to debug recovery problems, I typically strace all PostgreSQL processes and see what the scripts are doing/where they are failing.

pgpool2 behavior during recovery

In order to see how pgpool2 performs during recovery/degradation, you can use this little Go program that tries to do three things every 0.25 seconds: check that the database is healthy (SELECT 1;), run a meaningful SELECT, run an UPDATE.

When a database node goes down, a single query may fail until pgpool2 realizes that the node needs to be degraded. If your database load is light, chances are that pgpool2 will realize the database is down without even failing a single query, though.

2014-08-13 23:15:27.638 health: ✓  select: ✓  update: ✓
2014-08-13 23:15:28.700 insert failed: driver: bad connection
2014-08-13 23:15:28.707 health: ✓  select: ✓  update: x

During recovery, there is a time when pgpool2 will just disconnect all clients and not answer any queries any more (2nd stage). In this case, the state lasted for about 20 seconds:

…
2014-08-13 23:16:01.900 health: ✓  select: ✓  update: ✓
2014-08-13 23:16:02.161 health: ✓  select: ✓  update: ✓
# no queries answered here
2014-08-13 23:16:23.625 health: ✓  select: ✓  update: ✓
2014-08-13 23:16:24.308 health: ✓  select: ✓  update: ✓
…

Conclusion

Setting up a PostgreSQL setup that involves pgpool2 is definitely a lot of work. It could be a bit easier if the documentation was more specific on the details of how recovery is supposed to work and would include the configuration that I came up with above. Ideally, something like pgpool2 would be part of PostgreSQL itself.

I am not yet sure how much software I’ll need to touch in order to make it gracefully deal with the PostgreSQL connection dying and coming back up. I know of at least one program I use (buildbot) which does not handle this situation well at all — it needs a complete restart to work again.

Time will tell if the setup is stable and easy to maintain. In case I make negative experiences, I’ll update this article :).

by Michael Stapelberg at 31. August 2014 16:00:00

26. August 2014

Raphael Michel

SSL-enabled web servers on Android devices

Scenario

I am currently working on a software for a client, in which there are multiple Android devices involved. One of them works as a server while the other devices work as clients, fetching and pushing data from and to the server to keep all the data in sync. The software is supposed to be deployed on trusted devices in a trusted wireless network specifically set up for this application. Nevertheless, experience tells that in reality, it probably will be used in wireless networks which are not isolated.

The software is to be used at event locations and may not require internet connection at any time. It should work with any set of Android (4.0+) devices with having the app installed being the only prerequisite, wheras the same app should work as both client and server. The software should assume that the connection between the devices might be broken at any time and configuration should be simple for non-technical people.

As I'm pretty sure I'm not the only one having this requirements for an Android app project, I'm gonna talk a bit about how I've done it.

Implementation idea

The protocol used between the Android devices is HTTP. As I must assume that the app is being used in unisolated WiFi networks, the communication has to be SSL encrypted.

It is quite easy to run a Jetty server inside an Android app1, and it is also possible to use SSL encryption with Jetty. However, all documentation and examples on this I managed to find, were suggesting creating a SSL cert with keytool on your computer, storing it in a BKS keystore and shipping it with your application, or, having your users do this and letting them specify a path on the SD card to the keystore.

Neither of those is a real option for me: I cannot assume any of my users ever will create his own certificate with keytool and I also cannot ship a hard-coded private key with my application, as the app itself might not be considered a secret and using SSL with known keys is not even slightly better than not using encryption at all. Therefore, I must generate the SSL key and certificate on each device seperately on the first use of the app. I will present my code for this in the next section.

After the certificate is generated, the clients need to know the certificate's fingerprint: If the client would just accept any certificate, I could have avoided all the key generation work above, because a client accepting all certificates is nearly as bad as shipping the same keys on every device. As the system has to work offline and ad-hoc, there is no way to use something like a CA infrastructure.

Luckily, there is an elegant way to solve both the certificate and the configuration problem at once: The server device shows a QR code containing ip address, port and SSL fingerprint of the server as well as an authentication token (being in a public network, we want both encryption and authentication). The client just has to scan this QR code and gets all informaction necessary for etablishing a secure connection.

Implementation details

Dependencies

This effort has introduced a bunch of new dependencies to my application

  • My webserver component is built on Jetty 8.1.15, of which I created my own jar bundle (using jar xf and jar cf) containing:
    • jetty-continuation-8.1.15.v20140411.jar
    • jetty-http-8.1.15.v20140411.jar
    • jetty-io-8.1.15.v20140411.jar
    • jetty-security-8.1.15.v20140411.jar
    • jetty-server-8.1.15.v20140411.jar
    • jetty-servlet-8.1.15.v20140411.jar
    • jetty-util-8.1.15.v20140411.jar
    • jetty-webapp-8.1.15.v20140411.jar
    • jetty-xml-8.1.15.v20140411.jar
    • servlet-api-3.0.jar
  • Bouncycastle's bcprov-jdk15on-146.jar for keystore handling
  • Apache Commons Codec for fingerprinting keys
  • ZXing's core.jar for QR code generation or David Lazaro's wonderful QRCodeReaderView for easy QR code scanning (already includes core.jar)

Key generation

The hardest part was generating the keypair and certificate. I've got2 some3 inspiration4 from the web, but as I did not find an example ready to work on Android, here's mine:

/**
 * Creates a new SSL key and certificate and stores them in the app's
 * internal data directory.
 * 
 * @param ctx
 *            An Android application context
 * @param keystorePassword
 *            The password to be used for the keystore
 * @return boolean indicating success or failure
 */
public static boolean genSSLKey(Context ctx, String keystorePassword) {
    try {
        // Create a new pair of RSA keys using BouncyCastle classes
        RSAKeyPairGenerator gen = new RSAKeyPairGenerator();
        gen.init(new RSAKeyGenerationParameters(BigInteger.valueOf(3),
                new SecureRandom(), 1024, 80));
        AsymmetricCipherKeyPair keypair = gen.generateKeyPair();
        RSAKeyParameters publicKey = (RSAKeyParameters) keypair.getPublic();
        RSAPrivateCrtKeyParameters privateKey = (RSAPrivateCrtKeyParameters) keypair
                .getPrivate();

        // We also need our pair of keys in another format, so we'll convert
        // them using java.security classes
        PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(
                new RSAPublicKeySpec(publicKey.getModulus(), publicKey
                        .getExponent()));
        PrivateKey privKey = KeyFactory.getInstance("RSA").generatePrivate(
                new RSAPrivateCrtKeySpec(publicKey.getModulus(), publicKey
                        .getExponent(), privateKey.getExponent(),
                        privateKey.getP(), privateKey.getQ(), privateKey
                                .getDP(), privateKey.getDQ(), privateKey
                                .getQInv()));

        // CName or other certificate details do not really matter here
        X509Name x509Name = new X509Name("CN=" + CNAME);

        // We have to sign our public key now. As we do not need or have
        // some kind of CA infrastructure, we are using our new keys
        // to sign themselves

        // Set certificate meta information
        V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator();
        certGen.setSerialNumber(new DERInteger(BigInteger.valueOf(System
                .currentTimeMillis())));
        certGen.setIssuer(new X509Name("CN=" + CNAME));
        certGen.setSubject(x509Name);
        DERObjectIdentifier sigOID = PKCSObjectIdentifiers.sha1WithRSAEncryption;
        AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(sigOID,
                new DERNull());
        certGen.setSignature(sigAlgId);
        ByteArrayInputStream bai = new ByteArrayInputStream(
                pubKey.getEncoded());
        ASN1InputStream ais = new ASN1InputStream(bai);
        certGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo(
                (ASN1Sequence) ais.readObject()));
        bai.close();
        ais.close();

        // We want our keys to live long
        Calendar expiry = Calendar.getInstance();
        expiry.add(Calendar.DAY_OF_YEAR, 365 * 30);

        certGen.setStartDate(new Time(new Date(System.currentTimeMillis())));
        certGen.setEndDate(new Time(expiry.getTime()));
        TBSCertificateStructure tbsCert = certGen.generateTBSCertificate();

        // The signing: We first build a hash of our certificate, than sign
        // it with our private key
        SHA1Digest digester = new SHA1Digest();
        AsymmetricBlockCipher rsa = new PKCS1Encoding(new RSAEngine());
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        DEROutputStream dOut = new DEROutputStream(bOut);
        dOut.writeObject(tbsCert);
        byte[] signature;
        byte[] certBlock = bOut.toByteArray();
        // first create digest
        digester.update(certBlock, 0, certBlock.length);
        byte[] hash = new byte[digester.getDigestSize()];
        digester.doFinal(hash, 0);
        // and sign that
        rsa.init(true, privateKey);
        DigestInfo dInfo = new DigestInfo(new AlgorithmIdentifier(
                X509ObjectIdentifiers.id_SHA1, null), hash);
        byte[] digest = dInfo.getEncoded(ASN1Encodable.DER);
        signature = rsa.processBlock(digest, 0, digest.length);
        dOut.close();
        
        // We build a certificate chain containing only one certificate
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(tbsCert);
        v.add(sigAlgId);
        v.add(new DERBitString(signature));
        X509CertificateObject clientCert = new X509CertificateObject(
                new X509CertificateStructure(new DERSequence(v)));
        X509Certificate[] chain = new X509Certificate[1];
        chain[0] = clientCert;

        // We add our certificate to a new keystore
        KeyStore keyStore = KeyStore.getInstance("BKS");
        keyStore.load(null);
        keyStore.setKeyEntry(KEY_ALIAS, (Key) privKey,
                keystorePassword.toCharArray(), chain);
        
        // We write this keystore to a file
        OutputStream out = ctx.openFileOutput(FILE_NAME,
                Context.MODE_PRIVATE);
        keyStore.store(out, keystorePassword.toCharArray());
        out.close();
        return true;
    } catch (Exception e) {
        // Do your exception handling here
        // There is a lot which might go wrong
        e.printStackTrace();
    }
    return false;
}

The key generation takes roughly fifteen seconds on my Motorola Moto G, so it is strongly discouraged to do this in the UI thread – do it in your Service (you should have one for your server!) or in an AsyncTask.

FILE_NAME is the name of your key store (I use keystore.bks) and KEY_ALIAS the alias of the new key inside the keystore (I use ssl).

Jetty initialization

In the initialization code of our jetty servlet, we have to load our newly created keystore into a SslContextFactory, which is quite easy:

SslContextFactory sslContextFactory = new SslContextFactory();
InputStream in = openFileInput(SSLUtils.FILE_NAME);
KeyStore keyStore = KeyStore.getInstance("BKS");
try {
    keyStore.load(in, KEYSTORE_PASSWORD.toCharArray());
} finally {
    in.close();
}
sslContextFactory.setKeyStore(keyStore);
sslContextFactory.setKeyStorePassword(KEYSTORE_PASSWORD);
sslContextFactory.setKeyManagerPassword(KEYSTORE_PASSWORD);
sslContextFactory.setCertAlias(SSLUtils.KEY_ALIAS);
sslContextFactory.setKeyStoreType("bks");
// We do not want to speak old SSL and we only want to use strong ciphers
sslContextFactory.setIncludeProtocols("TLS");
sslContextFactory.setIncludeCipherSuites("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");

Server server = new Server();
SslSelectChannelConnector sslConnector = new SslSelectChannelConnector(
        sslContextFactory);
sslConnector.setPort(PORT);
server.addConnector(sslConnector);

// As before:
server.setHandler(handler); // where handler is an ``AbstractHandler`` instance
server.start();

QR Code generation

In order to display the QR code, we first need to create a SHA1 hash of our certificate:

public static String getSHA1Hash(Context ctx, String keystorePassword) {
    InputStream in = null;
    KeyStore keyStore;
    try {
        in = ctx.openFileInput(FILE_NAME);
        keyStore = KeyStore.getInstance("BKS");
        keyStore.load(in, keystorePassword.toCharArray());
        return new String(Hex.encodeHex(DigestUtils.sha1(keyStore
                .getCertificate(KEY_ALIAS).getEncoded())));
    } catch (Exception e) {
        // Should not go wrong on standard Android devices
        // except possible IO errors on reading the keystore file
        e.printStackTrace();
    } finally {
        try {
            if (in != null)
                in.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    return null;
}

Using this method, we can generate a QR code containing ip, port and certificate information and draw it onto an ImageView:

protected void genQrCode(ImageView view) {
    QRCodeWriter writer = new QRCodeWriter();
    try {
        WifiManager wifiManager = (WifiManager) getActivity()
                .getSystemService(WIFI_SERVICE);
        int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
        final String formatedIpAddress = String.format(Locale.GERMAN,
                "%d.%d.%d.%d", (ipAddress & 0xff),
                (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff),
                (ipAddress >> 24 & 0xff));

        JSONObject qrdata = new JSONObject();
        qrdata.put("server", formatedIpAddress);
        qrdata.put("port", ServerService.PORT);
        qrdata.put("cert", getSHA1Hash(getActivity(), KEYSTORE_PASSWORD));
        qrdata.put("secret", SECRET); // for authentitication. Generate yourself ;)

        BitMatrix bitMatrix = writer.encode(qrdata.toString(),
                BarcodeFormat.QR_CODE, 500, 500);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        Bitmap bmp = Bitmap.createBitmap(width, height,
                Bitmap.Config.RGB_565);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                bmp.setPixel(x, y, bitMatrix.get(x, y) ? Color.BLACK
                        : Color.WHITE);
            }
        }
        view.setImageBitmap(bmp);

    } catch (WriterException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

Client side

On the client side, HttpsURLConnection is being used for the connection. This works roughly like this:

// My application saves server address, port and certificate
// in a SharedPreferences store
SharedPreferences sp = getSharedPreferences("server",
        Context.MODE_PRIVATE);

X509PinningTrustManager trustManager = new X509PinningTrustManager(
        sp.getString("cert", ""));

SSLContext sc = null;
DataSource data = getDataSource();
HttpsURLConnection urlConnection = null;
try {
    data.open();

    URL url = new URL("https://" + sp.getString("server", "") + ":"
            + sp.getInt("port", ServerService.PORT) + "/path");
    urlConnection = (HttpsURLConnection) url.openConnection();

    // Set our SSL settings settings
    urlConnection
            .setHostnameVerifier(trustManager.new HostnameVerifier());
    try {
        sc = SSLContext.getInstance("TLS");
        sc.init(null, new TrustManager[] { trustManager },
                new java.security.SecureRandom());
        urlConnection.setSSLSocketFactory(sc.getSocketFactory());
    } catch (NoSuchAlgorithmException e1) {
        // Should not happen...
        e1.printStackTrace();
    } catch (KeyManagementException e1) {
        // Should not happen...
        e1.printStackTrace();
    }

    // do HTTP POST or authentication stuff here...
    InputStream in = new BufferedInputStream(
            urlConnection.getInputStream());
    // process the response...
} catch (javax.net.ssl.SSLHandshakeException e) {
    // We got the wrong certificate
    // (or handshake was interrupted, we can't tell here)
    e.printStackTrace();
} catch (IOException e) {
    // other IO errors
    e.printStackTrace();
} finally {
    if (urlConnection != null)
        urlConnection.disconnect();
    try {
        data.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

If you /only/ connect to this server in your whole application, you can use the HttpsUrlConnection.setDefault* methods instead of specifying it with every request. With writing a clever HostnameVerifier and TrustManager you could also achieve that the pinning is only enforced for your server but the system defaults are used for other servers.

The above code example makes use of a TrustManager class I implemented myself. It only accepts exactly one certificate:

/**
 * This class provides an X509 Trust Manager trusting only one certificate.
 */
public class X509PinningTrustManager implements X509TrustManager {

    String pinned = null;

    /**
    * Creates the Trust Manager.
    * 
    * @param pinnedFingerprint
    *            The certificate to be pinned. Expecting a SHA1 fingerprint in
    *            lowercase without colons.
    */
    public X509PinningTrustManager(String pinnedFingerprint) {
        pinned = pinnedFingerprint;
    }

    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[] {};
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType)
            throws CertificateException {
        checkServerTrusted(certs, authType);
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType)
            throws CertificateException {
        for (X509Certificate cert : certs) {
            try {
                String fingerprint = new String(Hex.encodeHex(DigestUtils
                        .sha1(cert.getEncoded())));
                if (pinned.equals(fingerprint))
                    return;
            } catch (CertificateEncodingException e) {
                e.printStackTrace();
            }
        }
        throw new CertificateException("Certificate did not match, pinned to "
                + pinned);
    }

    /**
    * This hostname verifier does not verify hostnames. This is not necessary,
    * though, as we only accept one single certificate.
    *
    */
    public class HostnameVerifier implements javax.net.ssl.HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}

Security considerations

This approach should be very secure against most attackers, as all network traffic is encrypted and traditional man-in-the-middle is not possible, as the client exactly know which certificate it expects and does not accept others. We even have Perfect Forward Secrecy! The fact that this information is not being transferred via network but via a QR code adds additional security.

However, there are some security problems left:

  • Most important: We only have TLS 1.0 available. I did not find a possibility to enable TLS 1.2. This is sad. I suspect the reason is that Android is still based on Java 6 and TLS 1.2 was introduced with Java 7. There is a possibility of running Java 7 code starting with Android KitKat, but this did not help in my quick test.
  • The keystore password is hardcoded. The only other option would be to prompt the user for the password on every application startup, which is not desirable. This, however, is only important if someone gains access to the keystore file, which is only readable for the app itself and root. And if our potential attacker is root on your phone, I guess you've got bigger problems than this keystore… Remember, my application is supposed to run on phones dedicated to run this application (with not many 3rd-party applications introducing vulnerabilities being installed).
  • SecureRandom is not cryptographically secure in Android 4.3 or older, as Android Lint points out. This official blog post5 has some more details and a workaround, but if you care about security, you should not run an old operating system anyway ;)

26. August 2014 22:00:00

24. August 2014

Moredreads Blog

Atsutane's blog

FrOSCon 2014 Summary

This year’s FrOSCon’s over, we had an unused booth (later used by someone for presenting emacs) and our own room, including some talks and a workshop. The talks were surprisingly well visited, we did not expect so many people to come. The original expectation was that we might be 15 people, but we got a larger room, probably a good decision by the organization team.

There are some things we can and should do better with future events, this years organization was – as always – really chaotic.

There are few things we did well and others we learned that we handled them… well bad is the proper term.

  • We need to give talks on each day we get a room. This year we only gave these on the first day and the second day the room was quiet. (Positive effect is the reogarnization of the SSL certificates.)

  • We have to give the talks in a better prepared way and not come up with the topics the weekend before the event and create the slides last-minute.

  • We used an Etherpad for organization of a todo list this was from my point of view well handled.

  • When we want to get a room skip a booth. We did not use the booth as we had no hardware to present something down there.

  • Merchandising, it’s every year the same, users want to get some merchandising. If I saw it correctly Debian sells T-Shirts, with german law we probably can’t do something like that to get a bit profit invested into our servers. To give away free stickers to actual users (not arrogant Fedora folks) might be an option, yet we would have to get them on our own costs. Another option would be to talk with the people from the merchandising booth at the entry.

  • When we give workshops we need a better organization, especially with installation stuff. I haven’t done an installation with the pacstrap script yet, leaving me in the same situation as someone new: How the heck do I initialize an installation.

24. August 2014 17:34:38

19. August 2014

Atsutane's blog

FrOSCon 2014

For those who may miss to see us people downstairs next to some other distro/BSD: This year Arch Linux has its own room at FrOSCon, you’ll find us people in C125.

19. August 2014 05:42:49

12. August 2014

Mero’s Blog

Applying permutation in constant space (and linear time)

I stumbled upon a mildly interesting problem yesterday: Given an Array a and a permutation p, apply the permutation (in place) to the Array, using only O(1) extra space. So, if b is the array after the algorithm, we want that a[i] == b[p[i]].

Naively, we would solve our problem by doing something like this (I'm using go here):

func Naive(vals, perm []int) {
    n := len(vals)
    res := make([]int, n)
    for i := range vals {
        res[perm[i]] = vals[i]
    }
    copy(vals, res)
}

This solves the problem in O(n) time, but it uses of course O(n) extra space for the result array. Note also, that it does not really work in place, we have to copy the result back.

The simplest iteration of this, would be to simply use a sorting-algorithm of our choice, but use as a sorting key not the value of the elements, but the position of the corresponding field in the permutation array:

import "sort"

type PermSorter struct {
    vals []int
    perm []int
}

func (p PermSorter) Len() int {
    return len(p.vals)
}

func (p PermSorter) Less(i, j int) bool {
    return p.perm[i] < p.perm[j]
}

func (p PermSorter) Swap(i, j int) {
    p.vals[i], p.vals[j] = p.vals[j], p.vals[i]
    p.perm[i], p.perm[j] = p.perm[j], p.perm[i]
}

func Sort(vals, perm []int) {
    sort.Sort(PermSorter{vals, perm})
}

This appears a promising idea at first, but as it turns out, this doesn't really use constant space after all (at least not generally). The go sort package uses introsort internally, which is a combination of quick- and heapsort, the latter being chosen if the recursion-depth of quicksort exceeds a limit in O(log(n)). Thus it uses actually O(log(n)) auxiliary space. Also, the running time of sorting is O(n log(n)) and while time complexity wasn't part of the initially posed problem, it would actually nice to have linear running time, if possible.

Note also another point: The above implementation sorts perm, thus destroying the permutation array. Also not part of the original problem, this might pose problems if we want to apply the same permutation to multiple arrays. We can rectify that in this case by doing the following:

type NDPermSorter struct {
    vals []int
    perm []int
}

func (p NDPermSorter) Len() int {
    return len(p.vals)
}

func (p NDPermSorter) Less(i, j int) bool {
    return p.perm[p.vals[i]] < p.perm[p.vals[j]]
}

func (p NDPermSorter) Swap(i, j int) {
    p.vals[i], p.vals[j] = p.vals[j], p.vals[i]
}

func NDSort(vals, perm []int) {
    sort.Sort(NDPermSorter{vals, perm})
}

But note, that this only works, because we want to sort an array of consecutive integers. In general, we don't want to do that. And I am unaware of a solution that doesn't have this problem (though I also didn't think about it a lot).

The solution of solving this problem in linear time lies in a simple observation: If we start at any index and iteratively jump to the target index of the current one, we will trace out a cycle. If any index is not in the cycle, it will create another cycle and both cycles will be disjoint. For example the permutation

i    0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19
p[i] 2  13 1  5  3  15 14 12 8  10 4  19 16 11 9  7  18 6  17 0

will create the following set of cycles:

So the idea is to resolve every cycle separately, by iterating over the indices and moving every element to the place it belongs:

func Cycles(vals, perm []int) {
    for i := 0; i < len(vals); i++ {
        v, j := vals[i], perm[i]
        for j != i {
            vals[j], v = v, vals[j]
            perm[j], j = j, perm[j]
        }
        vals[i], perm[i] = v, i
    }
}

This obviously only needs O(1) space. The secret, why it also only uses O(n) time lies in the fact, that the inner loop will not be entered for elements, that are already at the correct position. Thus this is (from a complexity standpoint at least) the optimal solution to the problem, as it is impossible to use less than linear time for applying a permutation.

There is still one small problem with this solution: It also sorts the permutation array. We need this, to know when a position is already occupied by it's final element. In our algorithm this is represented by the fact, that the permutation is equal to it's index at that point. But really, it would be nice if we could mark the index without losing the order of the permutation. But that is not hard either - because every index is non-negative, we can simply negate every index we are done with. This will make a negative index out of it and we can check for that if we encounter it later and skip it in this case. After we are done, we only need to take care to flip everything back and all should be fine:

func NDCycles(vals, perm []int) {
    for i := 0; i < len(vals); i++ {
        if perm[i] < 0 {
            // already correct - unmark and go on
            // (note that ^a is the bitwise negation
            perm[i] = ^perm[i]
            continue
        }

        v, j := vals[i], perm[i]
        for j != i {
            vals[j], v = v, vals[j]
            // When we find this element in the future, we must not swap it any
            // further, so we mark it here
            perm[j], j = ^perm[j], perm[j]
        }
        vals[i] = v
    }
}

Here we only mark the elements we will again encounter in the future. The current index will always be unmarked, once we are done with the outer loop.

I am aware, that this is technically cheating; This solution relies on the fact, that the upper-most bit of the permutation elements won't ever be set. Thus, we actually do have O(n) auxiliary space (as in n bit), because these bits are not necessary for the algorithm. However, since it is pretty unlikely, that we will find an architecture where this is not possible (and go guarantees us that it actually is, because len(vals) is always signed, so we cant have arrays that are big enough for the msb being set anyway), I think I am okay with it ;)

I ran sum Benchmarks on this an these are the figures I came up with:

n 10 100 1000 10000
Naive 332 ns 883 ns 15046 ns 81800 ns
NDCycle 130 ns 1019 ns 17978 ns 242121 ns
NDSort 1499 ns 27187 ns 473078 ns 4659433 ns

I did not measure space-use. The time of NDCycle for 10000 elements seems suspicious - while it is not surprising, that in general it takes more time than the naive approach, due to it's complexity, this jump is unexpected. Maybe if I have the time I will investigate this and also measure memory use. In the meantime, I uploaded all the code used here, so you can try it out yourself. You can run it with go run perm.go and run the benchmarks with go test -bench Benchmark.*.

12. August 2014 11:10:21

11. August 2014

Moredreads Blog

Werbungskritik

Normalerweise kommentiere ich wenig im Netz, da die Diskussionskultur durch Trolle und anderes ziemlich schlecht ist. Und so sicher bin ich mir nicht mit dem was ich denke, dass ich das anderen aufbürden wollte. :p

Aber trotzdem habe ich mal zu “Das Experiment”, einem Gastbeitrag auf zu der Stimmungsmanipulationsstudie von Facebook, einen Kommentar (sogar mit Klarnamen oO) verfasst, und damit meine lange Abstinenz von öffentlichen Diskussionen abseits Twitter etc. gebrochen. Vielleicht liest’s ja jemand und findet es nachdenkenswert. :p

Um diesen Beitrag ein wenig mit Inhalt zu füllen, vielleicht noch eine Ergänzung.

Ich finde es sehr bemerkenswert wie normal Werbung wahrgenommen wird, als sei es ein Gott-gegebenes Recht von Unternehmen zu “Käufern” degradierte Bürger zum Kauf ihrer Waren zu bewegen, wobei nur in Grenzfällen gesetzliche Hürden gesetzt werden (i. B. bei an Kinder gerichtete Werbung und ironischer Weise, wenn Sie andere Unternehmen zu stark betrifft (Unlauterer Wettbewerb)).

Im Gegensatz zu Kindern, von denen angenommen wird, dass sie nicht fähig sind, den “Wahrheitsgehalt” von Werbung zu durchschauen, wird dem/der Erwachsenen eine “Mündigkeit” als Verbraucher zugeschrieben, bewusst und mit Bedacht das Warenangebot zu betrachten, bevor er/sie eine Entscheidung trifft. Von einem logischen und rationalem Marktteilnehmer/-Innen gehen auch “der” Neoliberalismus aus, dessen Ideologie seit Jahrzehnten immer mehr die Wirtschaftspolitik geprägt hat.

Alleine die Existenz von Werbung müsste dieses Weltbild ins Wanken bringen, denn es ist vielerlei in Studien (sorry, müsst selber suchen :p) gezeigt worden, dass auch darauf achtende Menschen leicht von ihr beeinflussbar sind, und insbesondere in der Überflutung von verschiedensten Informationen nicht alle in den Entscheidungsprozess einfließen lassen können. Aber Marketing, public relations, Lobbying etc. wird auch gerade von Anhängern des Marktliberalismus betrieben, wobei die “Initiative Neue Soziale Marktwirtschaft” und die Bertelsmann-Stiftung nur zwei prominente Akteure sind. Kritik an nicht rein informatinsbasierter “Öffentlichkeitsarbeit”, sei es durch Unternehmen, Lobbyisten, oder anderen “Marktteilnehmern”, kenne ich von Markt-liberalen nicht. Das das keine signifikante kognitive Dissonanz auslöst…

Auch ist Werbung in meinen Augen ein signifikantes Volkswirtschaftliches Problem. Alleine die direkte Investition in Werbung beträgt ca. 1% des Bruttoinlandprodukts in Deutschland, oder ca. 30 Milliarden Euro; vermutlich sind darin indirekte Investitionen, wie interne Produktoptimierungen nicht enthalten. Dies ist Produktivkraft, die verschwendet wird, um alleine das Konsumverhalten zu lenken.

Gerade sozial wichtige Bereiche sind hiervon Betroffen, z.B. fließen bei Pharma-Konzernen große Mengen in Werbung, teils mehr als in Forschung und Entwicklung (siehe z.B. diesen Spiegel Artikel). Dabei ist noch nicht berücksichtigt, dass die Grundlagenforschung die Innovationen erst ermöglicht, größtenteils aus öffentlichen Mitteln finanziert wird. Des weiteren wird durch Lobbying versucht besonderer Schutz fuer Pharma-Unternehmen durch internationale Abkommen zu erreichen, um z.B. den großen Generika Markt in Indien, von dem u. A. Staaten in Afrika stark profitieren, zu sabotieren. (Eine humorige Entgleisung eines Pharmavertreters ist hier ein Interview geführt von Martin Sonneborn)

Dies nur so als ein Paar Beispiele warum ich es, wie Eingangs erwähnt, bemerkenswert finde, dass Werbung eine so prominente Stellung in unserer Gesellschaft einnehmen kann. Andere kritische Beispiele finden sich z. B. in den Werken von Noam Chomsky, aber auch Systemtragende sollten Grund haben da sich zu wundern.

11. August 2014 19:15:00

sECuREs Webseite

Configuring a Ubiquiti EdgeRouter Lite (Erlite-3) for Fiber7

I immediately ordered a fiber7 internet connection once it became available, and I’ve been connected since a few weeks. They offer a 1 Gbps symmetrical fiber connection, with native (static) IPv6 and no traffic limit — for 65 CHF per month (about 54 €).

In the order form, they let you choose whether you want to order a pre-configured MikroTik RB2011UiAS-2HnD including fiber optic and fiber patch cable. I assumed this would be an excellent choice, so I ordered it.

I really like the MikroTik device. Its CLI and web interface are well thought-out and easy to use once you understand their way of thinking. It’s small, absolutely silent and just works. However, there’s one shortcoming: it doesn’t do IPv4 hardware acceleration (they call it “fast path”) when you enable NAT, which you need for a fiber7 connection. Thus, the top bandwidth maxes out at 500 to 600 Mbps, so effectively you only use half of your available bandwidth.

Therefore, I looked around for other routers which can do a full Gigabit WAN-to-LAN, i.e. with IPv4-NAT enabled. The selection of routers that can do that is very small, see for example the smallnetbuilder WAN-to-LAN router charts.

In my first try, I went with the Netgear R7000 (“Nighthawk”) which is the highest-performing router with regards to WAN-to-LAN bandwidth on smallnetbuilder. It indeed does hardware acceleration for IPv4-NAT, so you can reach the full 118 MB/s TCP bandwidth that a Gigabit line offers. However, the firmware does not do DHCPv6-PD (Prefix Delegation), even though it’s certified as IPv6-ready. There are alternative firmwares, e.g. Tomato and DD-WRT. Tomato (v121 as of writing) comes with the kernel module that enables IPv4-NAT hardware acceleration, but has a nasty bug: the latency jumps up to 500ms for most of your packets, which is clearly not acceptable. DD-WRT does not come with such a kernel module because they use a newer kernel, so the speed maxes out at 400 Mbps (that’s what they claim, I didn’t even bother testing it).

Ubiquiti EdgeRouter Lite (Erlite-3)

So, as a second try, I ordered what everyone recommended me in the first place: the Ubiquiti EdgeRouter Lite (Erlite-3).

The EdgeRouter Lite (tested with firmware v1.5.0 and v1.6.0) offers IPv4 and IPv6 offloading, and in fact reaches Gigabit line rate (118 MB/s measured TCP performance). An unwelcome surprise is that hardware acceleration only works when not using bridging at all, so if you want to connect two devices to your router in the same subnet, like a computer and a switch, you cannot do that. Effectively, the EdgeRouter needs to sit between the internet connection and a switch.

With regards to the web interface of EdgeOS: the web interface feels very polished and modern, but it seems to lack a number of features that are only accessible in the CLI interface. The MikroTik web interface had a much higher coverage of features. In general, I like how Ubiquiti does many things right, though: firmware updates are quick and painless, the model selection and download on their website is very simple to find and use, and you even get a link to the relevant GPL tarball without asking :).

Properly disconnecting your old router

First of all, you should disconnect the MikroTik (or your current router) from the network. I recommend doing that by explicitly disabling both DHCP clients, so that the fiber7 router knows you are not using the old device any more. This is important because fiber7 uses a Cisco feature called “IP source guard”, which will disable any MAC address on your port that does not have a DHCP lease. Therefore, if you just switch routers, you need to wait for the old lease to expire before you get a new lease. In my first tests, this worked relatively well, but then a lease got stuck for some reason and I had to escalate the problem to their NOC. So, better disable the DHCP:

/ip dhcp-client set disabled=yes numbers=0
/ipv6 dhcp-client set disabled=yes numbers=0

Configuring the EdgeRouter Lite for fiber7

In my configuration, I connect a switch to eth0 and a media converter (the TP-LINK MC220L) to eth1. As a general tip: if you mess up your configuration, you can always use the link-local address of the EdgeRouter and SSH into that. Find the link-local address using ping6 ff02::1%eth0.

After logging into the web interface, set the eth1 address to DHCP and it should get a public IPv4 address from fiber7. Afterwards, enable NAT by clicking on NAT → Add Source NAT Rule. Set the outbound interface to eth1 and select the “masquerade” radio button. You’ll also need to switch to the “services” tab and enable a DHCP and DNS server. This should give you IPv4 connectivity to the internet.

Now on to IPv6. Since EdgeOS version 1.6.0, DHCPv6-PD is an easily usable feature. Log into the router using ssh ubnt@192.168.1.1, then run the following commands:

configure
set interfaces ethernet eth1 dhcpv6-pd pd 0 prefix-length /48
set interfaces ethernet eth1 dhcpv6-pd pd 0 interface eth0 service slaac
set interfaces ethernet eth1 dhcpv6-pd pd 0 interface eth0 prefix-id :0
set interfaces ethernet eth0 ipv6 router-advert prefix ::/64
set interfaces ethernet eth0 ipv6 router-advert radvd-options
  "RDNSS 2001:4860:4860::8888 {};"
commit
save
exit
reboot

The prefix-length specifies how big the prefix is that the ISP is giving us; a /48 in the case of fiber7. The next lines specify that we want to use SLAAC to hand out addresses of the delegated prefix on eth0. The prefix-id is used for the part after the /48, so if you set it to e.g. ff23, and your prefix is 2a02:168:4a09::/48, the EdgeRouter will announce 2a02:168:4a09:ff23::/64 on eth0.

For me, the reboot was necessary after changing settings, so try rebooting if things don’t work as they should.

When running ip -6 address show dev eth0 you should see that the router added an IPv6 address like 2a02:168:4a09:0:de9f:dbff:fe81:a905/64 to eth0.

That’s it! On clients you should be able to ping6 google.ch now and get replies.

Bonus: Configuring a DHCPv6-DUID

fiber7 wants to hand out static IPv6 prefixes based on the DHCPv6 option 37, but that’s not ready yet. Until then, they offer you to set a static prefix based on your DUID (a device identifier based on the MAC address of your router). Since I switched from the MikroTik, I needed to port its DUID to the EdgeRouter to keep my static prefix.

Luckily, wide-dhcpv6 reads a file called dhcp6c_duid that you can create with the proper DUID. The file starts with a 16-bit integer containing the length of the DUID, followed by the raw DUID:

echo -en '\x00\x0a\x00\x03\x00\x01\x4c\x5e\x0c\x43\xbf\x39' > /var/lib/dhcpv6/dhcp6c_duid

Conclusion

I can see why fiber7 went with the MikroTik as their offer for customers: it combines a media converter (for fiber to ethernet), a router, a switch and a wifi router. In my configuration, those are now all separate devices: the TP-LINK MC220L (27 CHF), the Ubiquiti EdgeRouter Lite Erlite-3 (170 CHF) and the TP-LINK WDR4300 (57 CHF). The ping latency to google.ch has gone up from 0.6ms to 0.7ms due to the additional device, but the download rate is about twice as high, so I think this is the setup that I’ll keep for a while — until somebody comes up with an all-in-one device that provides the same features and achieves the same rates :-).

Appendix: IPv6 with EdgeOS < 1.6.0

IPv6 is a bit harder, since EdgeOS in its current version (1.5.0) does not support DHCPv6-PD via its Web or CLI interface. The necessary software (wide-dhcpv6) is included, though, so we can configure it manually.

For the next steps, you need to know the transfer network IP range, which seems to be different for every fiber7 POP (location). You can get it by either using DHCPv6 and looking at the address you get, by checking your MikroTik configuration (if you have one) or by asking fiber7. In my case, the range is 2a02:168:2000:5::/64, but I’ve heard from others that they have 2a02:168:2000:9::/64.

Use ssh ubnt@192.168.1.1 to log into the CLI. In order to set the proper IPv6 address on the transfer network, run ip -6 address show dev eth1 and look for a line that says inet6 fe80::de9f:dbff:fe81:a906/64 scope link. Copy everything after the :: and prefix it with 2a02:168:2000:5: (your fiber7 transfer network range), then configure that as static IPv6 address on eth1 and set the default route (and enable IPv6 offloading):

configure
set system offload ipv6 forwarding enable
set interfaces ethernet eth1 address 2a02:168:2000:5:de9f:dbff:fe81:a906/64
set protocols static route6 ::/0 next-hop 2a02:168:2000:5::1 interface eth1
commit
save
exit

Now you should be able to run ping6 google.ch and get a reply. We still need to enable DHCPv6 though so that the router gets a prefix and hands that out to its clients. Run sudo -s to get a root shell and configure DHCPv6:

cat >/etc/wide-dhcpv6/dhcp6c-script-zkj <<'EOT'
#!/bin/sh
# wide-dhcpv6-client 20080615-12 does not properly close
# file descriptors when starting the script.
# https://bugs.debian.org/757848
exec 4>&- 5>&- 6>&- 7>&-
# To prevent radvd from sending the final router advertisment
# that unconfigures the prefixes.
killall -KILL radvd
/etc/init.d/radvd restart
exit 0
EOT
chmod +x /etc/wide-dhcpv6/dhcp6c-script-zkj

cat >/etc/wide-dhcpv6/dhcp6c.conf <<'EOT'
interface eth1 {
        send ia-pd 0;
        request domain-name-servers;
        script "/etc/wide-dhcpv6/dhcp6c-script-zkj";
};

id-assoc pd 0 {
        prefix-interface eth0 {
                sla-id 1;
                sla-len 0;
        };
};
EOT

sed -i 's/eth0/eth1/g' /etc/default/wide-dhcpv6-client

cat >/config/scripts/post-config.d/dhcpv6.sh <<'EOT'
#!/bin/sh
/etc/init.d/wide-dhcpv6-client start
EOT
chmod +x /config/scripts/post-config.d/dhcpv6.sh

/config/scripts/post-config.d/dhcpv6.sh

Now, when running ip -6 address show dev eth0 you should see that the router added an IPv6 address like 2a02:168:4a09:0:de9f:dbff:fe81:a905/48 to eth0. Let’s enable router advertisments so that clients get an IPv6 address, route and DNS server:

configure
set interfaces ethernet eth0 ipv6 router-advert prefix ::/64
set interfaces ethernet eth0 ipv6 router-advert radvd-options
  "RDNSS 2001:4860:4860::8888 {};"
commit
save
exit

That’s it! On clients you should be able to ping6 google.ch now and get replies.

by Michael Stapelberg at 11. August 2014 09:55:00

04. August 2014

Raphael Michel

Monitoring email

I most recently moved my mails from the great guys at Uberspace to an own server, because I like owning things and running them by myself. This is no problem at all with hosting my own sync server for contacts, calendar and photos, but it is a problem with mail, because mail is critical infrastructure to me. So, although I like the thought of having my mail on a machine I own, I do not like the thought of my mailserver going broken without me noticing it.

As I run a bunch of online services for myself and for others, I already had an Icinga instance running to notify me if one of my services happens to go down. This Icinga instance already was configured to check whether my mailserver correctly responds on the SMTP and IMAP ports but this is not enough. This does not fire alarm, if there is a configuration mistake anywhere in the local mail transport (postfix), the spam filter (SpamAssassin), other filters (sieve), or the authentication system.

The only solution to this problem is to set up End to End monitoring for email. Most surprisingly, I failed to find a ready-to-use Icinga plugin for doing this. So this is what I came up with by myself.

For testing all of the steps in the flow of an email, you need a second mailserver you can regularly exchange mails with. You can use any mail account at one of the big mail hosters, but there is a chance they'll consider your testing mails as spam, so I just paired up with Ben, a friend of mine, to monitor each other's mailserver.

The basic idea is very simple: You have your mailserver (A) and your friend's mailserver (B) and on every run, the Icinga check script connects of the SMTP servers and sends one email each from A to B and from B to A, containing a timestamp. On the next run, it connects to both servers via IMAP, checks whether both mails arrived, deletes them and sends out new ones once again.

The check script is written in Python and requires at least Python 3.2 and the Python nagiosplugin. On Debian stable, just do a quick

apt-get install python3 python3-pip
pip-3.2 install nagiosplugin

Then, grab my script from Github:

wget https://raw.githubusercontent.com/raphaelm/monitoring/master/mail/check_mail_twoway
chmod +x check_mail_twoway
mv check_mail_twoway /usr/lib/nagios/plugins/

You can execute ./check_mail_twoway -h to get an overview of the command-line options and play around with them.

My Icinga configuration looks as follows:

define command {
    command_name    check_mail_twoway
    command_line    /usr/lib/nagios/plugins/check_mail_twoway $ARG1$ 
}
define service {
    use                 generic-service
    host_name           dannyl
    service_description Mail E2E
    check_command       check_mail_twoway!-s1 serverA \
        -a1 userA@serverA -i1 serverA -u1 userA \
        -p1 passwordA -s2 serverB -i2 serverB \
        -a2 userB@serverB -u2 userB -p2 passwordB
}

On the first run, the script will always report a failure, as it can not find any emails (as none have been sent out yet). I do not think there is a simple and perfect way to prevent this, please correct me if I'm wrong.

I'd love to hear if this works for you or to see any pull requests!

(And of course, my Icinga does not try to notify me via email if my email fails, but via SMS.)

04. August 2014 22:35:00

28. July 2014

sECuREs Webseite

Don’t type WiFi passwords again: use a yubikey

In my flat, I have a printed QR code which contains the WiFi credentials. You can scan it with your Smartphone (provided you have a barcode scanner installed) and then connect to the WiFi network.

For notebook computers, this doesn’t work so well. Sometimes they don’t have a usable camera, and even if they have one, people don’t typically have a barcode scanner installed.

Therefore, you typically end up typing in the (long) password, which is annoying. I thought there should be a better way, perhaps by faking a USB Human Interface Device (like a keyboard). Then I saw a YubiKey lying around and a couple minutes later I had my solution working :-).

YubiKey

YubiKey

The YubiKey is a small USB device (about as big as a USB memory stick) that is typically used for two-factor authentication. You may be familiar with this concept from Gmail, where you log in with a password and then provide a number generated by the Google Authenticator on your phone as a second factor. The YubiKey does this by simulating you typing in the number after you touch it.

Luckily, the device’s firmware also supports a mode where it essentially just types a static password when being touched. Unfortunately, this feature is a bit hard to use, so I wrote pw-to-yubi, a little script which translates a (WiFi) password into a command line to program your YubiKey.

$ sudo apt-get install yubikey-personalization
$ git clone https://github.com/stapelberg/pw-to-yubi.git
$ cd pw-to-yubi
$ ./pw-to-yubi.pl mywifipassword
ykpersonalize -1 -o-append-cr -o-static-ticket -oshort-ticket \
  -o-strong-pw1 -o-strong-pw2 -oman-update \
  -ofixed=h:101c1a0c090c130416161a1215070000 -ouid=000000000000 \
  -a00000000000000000000000000000000

Run the command and any further touches of the YubiKey that is currently plugged into your computer will result in the key typing your WiFi password.

pw-to-yubi in a terminal emulator

by Michael Stapelberg at 28. July 2014 19:15:00

26. July 2014

Moredreads Blog

19. July 2014

Moredreads Blog