Planet NoName e.V.

13. May 2015

RaumZeitLabor

Stick-Wochenende 2

Das StickZeitLabor lädt zum Stick-Wochenende am 25.-26.07.

Kleine Stickerei mit Steppstich-Kontur

Seit geraumer Zeit gibt es im RaumZeitLabor und seinen diversen Außenstellen Stickmaschinen und -begeisterte.

Im Februar fand deshalb das erste Stickwochenende im RaumZeitLabor (ESWIRZL) statt.

Jetzt wollen wir uns zum zweiten Mal zu einem Wochenende voller Vorträge, Erfahrungsaustausch und wilder Experimente treffen. Sattelt die Pferde und kommt mit oder ohne Maschinen am 25.-26.07. ab 10 Uhr ins StickZeitLabor zum ZSWIRZL (Zweites Stickwochenende im RaumZeitLabor).

Eine formelle Anmeldung mit Passierschein A38 und einem Antrag auf Erteilung eines Antragformulars zur Bestätigung der Nichtigkeit des Durchschriftexemplars, dessen Gültigkeitsvermerk von dem Bezugshackerspace stammt zum Behuf der Vorlage beim zuständigen Erteilungserfa ist nicht unbedingt notwendig, ihr könnt auch einfach spontan vorbeikommen.

Trotzdem wäre es nett wenn ihr uns vorher mitteilt, mit wie vielen Sticknerds ihr im RZL einreiten wollt, ob ihr 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

13. May 2015 22:41:41

06. May 2015

RaumZeitLabor

Bericht Texprocess

Bild 1

(Bild 1: Verzug rot markiert)

Vom vierten bis zum siebten Mai war in Frankfurt die Textilverarbeitungsmesse Texprocess. Ingo und ich waren am Mittwoch dort und haben unserem Stickmaschinenlieferanten und Stickzubehörlieferanten Löcher in den Bauch gefragt.

Tipps von ACE International:

Um dehnbare Träger zu stabilisieren kann man ein transparentes Reiß-Stickvlies vor dem Sticken auflegen. Nach dem Sticken überstehende Reste abreißen, das Vlies unter den Stichen bleibt dort und löst sich auch beim Waschen nicht auf. Bekommt man bei etc supplies.

Bei Plattstichen bzw. Satinstichen sollte man auf der Unterseite rechts und links jeweils 1/3 Oberfaden und in der Mitte 1/3 Unterfaden sehen.

Tipps von Gunold

Aus den eigenen Fehlern lernt man bekanntlich am besten, also habe ich zwei meiner Stickereien mitgebracht um die zugehörigen Probleme zu diskutieren, siehe Bild 1 und Bild 2.

Bild 2

(Bild 2: Zu hohe Stichdichte, dadurch Wellen im Motiv)

Für T-Shirts eignet sich das Vlies 2040, weil es dünn und weich ist, also einen hohen Tragekomfort bietet und trotzdem eine hohe Stich-Stabilität hat, also nicht so leicht zerstochen wird wie Vliese zum Abreißen.

Auf die Frage, warum sich die Stickerei in Bild 2 entlang der Hauptachsen der eingezeichneten Ellipsen so wellt und was man dagegen tun kann war die Antwort: Die Steppfläche ist zu dicht ausgestickt, da es blau auf blau ist (Ton in Ton) kann man problemlos die Stichdichte reduzieren. Außerdem sollte man immer mit Unterleger arbeiten, d.h. in der Sticksoftware die Option “Unternähen” einschalten, um das Textil zunächst bombenfest an dem Vlies zu befestigen. Wenn man dicht genug unternäht kommt man bei der anschließenden Steppfläche auch mit einer geringeren Dichte aus.

Bei den schwarz gestickten Wimpern (siehe Bild 1, grüne Ellipsen) sprachen wir über das Problem, dass der schwarze Plattstich die unterliegenden weißen und grauen Plattstiche nicht richtig verdeckt und deshalb zweimal gestickt werden muss, so dass die Stickerei an dieser Stelle sehr dick wird. Das lässt sich auf zwei Arten beheben: Entweder die schwarzen Flächen ebenfalls unternähen oder vor den schwarzen Flächen in die Stickdatei einen Maschinenstopp einfügen und Solvy (ein wasserlösliches Stickvlies) auflegen. Den Verzug am Rand der Stickerei (Bild 1, rote Kreise) wird man los, indem man da ebenfalls die Stichdichte reduziert.

Die Fadenspannung wird normalerweise nach Gefühl eingestellt und sollte bei Viskose (Sulky, unser Standardgarn besteht aus Viskose) etwas niedriger sein als bei Polyester. Bei Metall-Garn und nachleuchtenden Garnen noch etwas niedriger, bei letzeren ist die Spannung aber sowieso automatisch niedriger weil die aufgrund ihrer Beschichtung etwas besser gleiten. Die Unterfadenspannung sollte so hoch sein, dass man die Spulenkapsel mitsamt Spule am Unterfaden hochheben kann, aber gleichzeitig so niedrig dass ein bischen Unterfaden abgespult wird, wenn man dann am Unterfaden ruckartig zieht. Die Oberfadenspannung wird dann so eingestellt, dass bei Plattstichen auf der Unterseite 2/3 Oberfaden und 1/3 Unterfaden zu sehen ist.

Bei Hemden tritt unter Umstanden folgendes Problem auf: Man stickt, wäscht, bügelt und dann hat sich das Motiv verzogen und das Hemd hat Falten, die man nie wieder herausbekommt. Es gibt zwei Lösungsansätze: Entweder man nimmt als Vlies unter dem Stoff Thermofilm, stickt und entfernt das dann durch kreisförmige Bewegungen mit dem Bügeleisen. Oder man nimmt Solvy Fabric als Vlies unter dem Stoff und entfernt das dann durch Waschen.

Um die Wellen im Stoff zu reduzieren kann man das dünne Solvy (wir bekommen ein Muster geschickt) auch auf das Textil auflegen, das wirkt dann auch dem Treppen-Effekt (siehe Bild 3) entgegen.

Bild 3: Treppen-Effekt(Bild 3: Treppen-Effekt)

Tipps von ZSK

Am Ende haben wir dann noch mit René Gotolle von ZSK geredet, der mir Grundlagen der Stichdichte aufgeschrieben hat (Endlich mal Zahlen!):

Stepplinien

Eine Stepplinie (z.B. als Konturlinie, wenn die Linie dünner als 1mm sein soll) wird standardmäßig mit 2mm langen Stichen gestickt, wobei in Kurven bis auf 1mm reduziert wird, um die Kontur besser anzunähern. In der Regel wird das zweimal gestickt, also einmal vorwärts und einmal rückwärts.

Bild 4: Steppstich-Kontur

(Bild 4: Steppstich-Kontur)

Steppflächen

Eine Steppfläche wird mit 3,6mm langen Stichen ausgestickt, wobei die Stiche in den einzelnen Zeilen um 1/3 versetzt werden und die Zeilen 0,36mm voneinander entfernt sind (Siehe Bild 5). In der Sticksoftware bedeutet das 2,8 Stiche pro Millimeter. Der Flächenunterleger wird senkrecht zur Stichrichtung der Steppfläche gestickt, dabei reicht eine Linie alle 1,2mm und die Stiche kann man 4mm lang machen, das spart Stiche und damit Zeit. In der Software muss man dafür “Unternähen, dicht” auswählen, das ergibt aber nur eine Linie alle 1,5mm. Für einzelne große Flächen kann man sich mit einem Trick behelfen: Anstatt die Unternähen-Funktion zu benutzen dupliziert man die Fläche und stickt die untere Fläche mit 0,9 oder 0,8 Stichen pro Millimeter senkrecht zur eigentlichen Stichrichtung ohne Zugkompensation. Das sollte den selben Effekt haben, ist für viele kleine Flächen aber wahrscheinlich zu fummelig. Ein einfacher Unterleger reicht, man braucht keinen Kreuz-Unterleger.

Bild 5: Steppfläche

(Bild 5: Steppfläche. Die lila markierten Stiche in jeder zweiten Linie sind leicht versetzt, weil nicht um 1/3 sondern um 30% verschoben wird.)

Plattstiche

Die minimale Breite für Plattstiche beträgt 1mm, darunter funktioniert es nicht mehr zuverlässig, weil die Nadel u.U. zweimal die selbe Stelle im Stoff trifft. Bei so schmalen Steppstichen reichen 2 Stiche pro Millimeter für Deckung, bei höheren Dichten hat man wieder das Problem, dass mehrfach die selbe Stelle im Stoff getroffen wird, das führt zu Löchern und Fadenriss. In der Sticksoftware braucht man dafür nicht die Option Unternähen, es reicht den Ein- und Aussteigspunkt auf die selbe Seite der Linie zu legen (siehe Bild 6, oben).

Der Unterleger wird als einfacher Steppstich in der Mitte ausgeführt. Ab 2mm Breite des Plattstiches nimmt man wieder die übliche Stichdichte von 2,8 Stichen pro Millimeter und als Unterleger eine Naht entlang der Kontur (siehe Bild 6, unten).

Bild 6: Plattstiche

(Bild 6: Plattstiche)

Falten um das Motiv

Selbst mit zwei Lagen Stickvlies unter dem Stoff bilden sich um das Motiv außenherum teilweise Falten (in Bild 1 rot markiert, in Bild 7 offensichtlich).

In Bild 1 wird das Problem teilweise durch die zu hohe Stichdichte von 5,5 Stichen pro Millimeter bzw. ein Stich alle 0,18mm verursacht. In Bild 7 habe ich die Dichte nachgemessen, die Umrandung des Stickmotivs hat eine Breite von etwa 1,3mm und einen Stich alle 0,4mm bzw. 2,5 Stiche pro Millimeter. Die Steppfüllungen haben ungefähr 3 Linien pro Millimeter bzw. eine Linie alle 0,33mm.

Bild 7: Stickerei auf Hemdtasche

(Bild 7: Stickerei auf Hemdtasche)

Die Falten bekommt man auch mit einem Dampfbügeleisen nur teilweise weg (BTDTNT).

Die ganzen Tipps werde ich sobald ich Zeit habe™ alle ausprobieren und dann natürlich berichten.

06. May 2015 00:00:00

02. May 2015

koebi

Setting Trackpoint speed via systemd

Disclaimer This post does not offer the truth in how trackpoint speed and sensitivity should be set. It just shows how I am doing it at the moment. Since this is the first time I wrote a systemd-service-file, or anything like this, I am very happy to receive any feedback on mistakes I may have made or anything else. Why trackpoint speed/sensitivity matters (to me) I am currently using a Thinkpad X220i with a heavily keyboard-based setup.

02. May 2015 00:00:00

28. April 2015

RaumZeitLabor

MRMCD 2015: Call for Participation

MRMCD 2015 Plakat

Für die diesjährigen MRMCD suchen wir wieder interessante Beiträge. Themen die auf den MRMCD häufig vertreten sind sind z.B. Open Source, Kryptographie, Soziale Netzwerke, Eingebettete Systeme, Programmiersprachen, Anonymität und daraus resultierende gesellschaftliche Fragen.

Entsprechend dem Motto dieses Jahr freuen wir uns auch auf Themen an der Schnittstelle zwischen Körper und Technik, sei es Forschungen und Entwicklungen unter dem Stichwort Quantified Self oder interessanten Technologien aus dem Sportbereich.

Diese Liste ist aber keinesfalls abschließend. Die MRMCD sind bekannt dafür, ein breites, interessantes Themenspektrum zu besitzen. Unsere Besucher sind stets daran interessiert auch scheinbar fachfremdes Wissen kennen und beherrschen zu lernen.

Entsprechend dem diesjährigen Thema planen wir Wettbewerbe für die Gäste auf der Veranstaltung. Solltest du eine Idee für einen Wettbewerb haben und vielleicht sogar Interesse besitzen, einen Wettbewerb zu organisieren, freuen wir uns über eine E-Mail.

Du hast eine Idee für einen Vortrag auf den MRMCD15?

Wir freuen uns, von dir zu hören! Ihr könnt euch auch gerne mit Themenideen melden. Wir schauen dann ob wir einen interessanten Speaker finden können.

Übrigens: Speaker auf den MRMCD15 sind die besten Menschen der Welt und wir kümmern uns natürlich ganz besonders um sie. Speaker sind automatisch zutrittsberechtigt zur VIP-Lounge.

Einreichungen zu Workshops und Vorträgen nehmen wir über unser Konferenzorganisationstool frab entgegen. Auf media.ccc.de findet ihr die Video-Aufzeichnungen vergangener MRMCDs.

Wir freuen uns, wenn du dabei bist.

Mit sportlichen Grüßen,

die Wettkampfleitung der MRMCD15

28. April 2015 00:00:00

13. April 2015

Mero’s Blog

Difficulties making SQL based authentication resilient against timing attacks

I've been thinking about how to do an authentication scheme, that uses some kind of relational database (it doesn't matter specifically, that the database is relational, the concerns should pretty much apply to all databases) as a backing store, in a way that is resilient against timing side-channel attacks and doesn't leak any data about which usernames exist in the system and which don't.

The first obvious thing is, that you need to do a constant time comparison of password-hashes. Luckily, most modern crypto libraries should include something like that (at least go's bcrypt implementation comes with that).

But now the question is, how you prevent enumerating users (or checking for existence). A naive query will return an empty result set if the user does not exists, so again, obviously, you need to compare against some password, even if the user isn't found. But just doing, for example

if result.Empty {
    // Compare against a prepared hash of an empty password, to have constant
    // time check.
    bcrypt.CompareHashAndPassword(HashOfEmptyPassword, enteredPassword)
} else {
    bcrypt.CompareHashAndPassword(result.PasswordHash, enteredPassword)
}

won't get you very far. Because (for example) the CPU will predict either of the two branches (and the compiler might or might not decide to "help" with that), so again an attacker might be able to distinguish between the two cases. The best way, to achieve resilience against timing side-channels is to make sure, that your control flow does not depend on input data at all. Meaning no branch or loop should ever take in any way into account, what is actually input into your code (including the username and the result of the database query).

So my next thought was to modify the query to return the hash of an empty password as a default, if no user is found. That way, your code is guaranteed to always get a well-defined bcrypt-hash from the database and your control flow does not depend on whether or not the user exists (and an empty password can be safely excluded in advance, as returning early for that does not give any new data to the attacker).

Which sounds well, but now the question is, if maybe the timing of your database query tells the attacker something. And this is where I hit a roadblock: If the attacker knows enough about your code (i.e. what database engine you are using, what machine you are running on and what kind of indices your database uses) they can potentially enumerate users by timing your database queries. To illustrate: If you would use a simple linear list as an index, a failed search has to traverse the whole list, whereas a successfull search will abort early. The same issue exists with balanced trees. An attacker could potentially hammer your application with unlikely usernames and measure the mean time to answer. They can then test individual usernames and measure if the time to answer is significantly below the mean for failures, thus enumerating usernames.

Now, I haven't tested this for practicality yet (might be fun) and it is pretty likely that this can't be exploited in reality. Also, the possibility of enumerating users isn't particularly desirable, but it is also far from a security meltdown of your authentication-system. Nevertheless, the idea that this theoretical problem exists makes me uneasy.

An obvious fix would be to make sure, that every query always has to search the complete table on every lookup. I don't know if that is possible, it might be just trivial by not giving a limit and not marking the username column as unique, but it might also be hard and database-dependent because there will still be an index over this username column which might still create the same kind of issues. There will also likely still be a variance, because we basically just shifted the condition from our own code into the DBMS. I have simply no idea.

So there you have it. I am happy to be corrected and pointed to some trivial design. I will likely accept the possibity of being vulnerable here, as the systems I am currently building aren't that critical. But I will probably still have a look at how other projects are handling this. And maybe if there really is a problem in practice.

13. April 2015 02:49:53

10. April 2015

koebi

Connecting an iPod Shuffle

Backstory A few years ago, driving home from a night drinking in the old town of Heidelberg, I stumbled upon an iPod shuffle of the 4th generation. Being the drunk and stupid guy I was back then, I didn’t think much, and just took it home - just to wake up the other day recognizing I was now the proud owner of an iPod. Yay. Of course, now, that I had that thing, I wanted to use it.

10. April 2015 00:00:00

01. April 2015

RaumZeitLabor

GPN 2015

Offizielles GPN 2015 Plakat

Auch dieses Jahr gibt es wieder eine GulaschProgrammierNacht, dieses Mal von Donnerstag, den 04.06.15, bis Sonntag, den 07.06.15 in den Räumen der Hochschule für Gestaltung (HfG) und dem Zentrum für Kunst und Medientechnologie (ZKM) in Karlsruhe.

Das RaumZeitLabor wird wohl wieder mit Stickmaschine, Slush-Maschinen, Lasercutter, Shirtpresse, Kompressor und natürlich der neuen Tauchkreissäge antanzen.

Ich freue mich jedenfalls jetzt schon darauf, das kann man sich ungefähr so vorstellen:

Rainbow Dash (Quelle)

01. April 2015 00:00:00

30. March 2015

RaumZeitLabor

Bericht Troopers 2015

Finales Stickergebnis mit der Husqvarna

Auch dieses Jahr gab es wieder eine Troopers, dieses Mal von Montag den 16.03. bis Freitag den 20.03. Das RaumZeitLabor war wie gewohnt am Donnerstag und Freitag vor Ort, mitgebracht haben wir die Slushmaschine, den Laser und natürlich die Stickmaschine, leider nur die kleine.

Da ich eine gefühlte Ewigkeit nicht mit der Husqvarna gestickt hatte habe ich nach dem Aufbau erstmal ein Testmuster auf ein T-Shirt gestickt. Dazu habe ich zum ersten Mal die Kombination aus Stiffy 2040 und Stiffy 1860B benutzt, letzeres wird aufgebügelt und kann am Ende abgerissen werden, ersteres wird untergelegt und muss am Ende abgeschnitten werden. Das ist mehr Aufwand, führt aber angeblich zu weniger Verzug, da das Vlies nicht wie die Varianten zum Abreißen an den Rändern zerstochen wird.

Das Ergebnis lässt leider zu wünschen übrig, sowohl das T-Shirt um das Motiv herum als auch das Motiv an sich ist verzogen, man sieht das z.B. an der schwarzen Linie zwischen Ohr und Auge:

Verzogenes Stickergebnis mit leichtem Vlies

Der Verzug lässt sich zwar auch mit Nadelfilz in den Griff bekommen, aber das ist eine andere Geschichte und soll ein andermal erzählt werden.

Zu Beginn der Troopers hatte ich befürchtet, ähnlich wie auf dem Kongress die ganze Veranstaltung über gefragt zu werden, ob ich das Logo o.ä. langweiliges Zeug sticken kann. Diese Bedenken haben sich prompt zerstreut, als der erste Besucher eine Biene gestickt haben wollte.

Angesichts des filigranen Motivs und der begrenzten Zeit habe ich dann versucht, die Konturen mit Geradstichen anstelle der üblichen Satinstiche anzudeuten, was auch ganz gut geklappt hat bis auf die Tatsache, dass teilweise die Füllstiche aus der Kontur herausragen:

Stickmotiv Biene mit Geradstichen für die Konturen

In diesem Fall hätte ich entweder die Zugkompensation der Flächen auf 0 setzen oder die Konturstiche von Hand anpassen müssen.

Weiter ging es mit einem Fuchs, der weniger filigran war, so dass ich wieder auf Satinstiche als Randbegrenzung zurückgreifen konnte. Hier hätte die Randnaht etwas breiter sein können und an den Ohren sind Lücken, da hätte mehr Zugkompensation wahrscheinlich geholfen:

Stickmotiv Biene mit Geradstichen für die Konturen

Später habe ich mit zwei weißen Garnen, von denen genau eines unter Sonnenlicht orange wird ein Sonnenmotiv gestickt, bei dem das eigentliche Motiv erst im Sonnenlicht sichtbar werden sollte. Leider hatte ich die Zugkompensation mit 0,2mm viel zu niedrig eingestellt und zusätzlich gab es relativ viel Verzug, so dass das Motiv auch so klar erkennbar ist:

Stickmotiv Sonne mit Spezialgarn, das unter Sonnenlicht orange wird

Da wäre vielleicht mal eine Testreihe mit weißem Nadelfilz notwendig, das haben wir aber leider nicht im RZL.

Zum Schluss durfte ich dann nochmal eines meiner Lieblingsmotive sticken:

Stickergebnis mit schwerem Schneide-Vlies

Dabei habe ich das Bügelvlies Stiffy 1860B aufgebügelt und Stiffy 1950 untergelegt. Letzteres muss genau wie Stiffy 2040 abgeschnitten werden, ist aber mit 80g/m² 60% schwerer als Stiffy 2040.

Obwohl diese Version des Motivs etwas größer ist als der Teststich vom Anfang der Veranstaltung gab es fast keinen Verzug

Fazit

Ob sich der Einsatz der arbeitsaufwändigeren Schneidevliese lohnt müsste mal jemand ermitteln, in dem er die gleiche Datei mit verschiedenen Vlies-Kombinationen auf gleiche Textilien stickt. Noch ist nämlich unklar, an welcher Variablen es nun hängt, Stickdatei, Maschine, Vlies, Textil oder Maschinen-Einstellungen.

30. March 2015 00:00:00

15. March 2015

RaumZeitLabor

Applikationen sticken

Ziel

Wir wollen ein Motiv auf Baumwollköper sticken und daraus einen Kopfkissenbezug nähen.

Voraussetzung für das beschriebene Verfahren ist eine SVG-Datei, in der alle Konturen in Flächen umgewandelt und alle Überlappungen mit Hilfe der Mengenoperationen entfernt wurden. Wir nehmen das folgende Motiv:

Dornröschen

Wir wollen selbstverständlich den größten verfügbaren Rahmen voll ausreizen, das Motiv wird also 492mm breit und 330mm hoch. Dabei kommt uns entgegen, dass das Motiv zufälligerweise™ ziemlich genau in den Rahmen passt, u.a. weil es Rundungen anstelle von Ecken hat.

Wir könnten nun die Konturen mit Satinstichen und die großen Füllflächen mit Füllstichen füllen, aber alleine die Füllflächen haben bei moderaten 5 Stichen pro Millimeter ohne Unternähen bereits 113k Stiche, insgesamt sind es ohne weitere Optimierung 210k Stiche.

Große Flächen kann man mit Applikationsstoffen realisieren anstatt sie auszusticken. In diesem Motiv sind es die weiße Füllung der Wolken und die hellblaue Füllung des Körpers.

Vorbereitung des Motivs in Inkscape

Um die Applikationen mit der Stickmaschine zu realisieren sind einige einfache Vorbereitungen notwendig.

Wir duplizieren zunächst die Ebene, auf der die Füllfläche der Wolken liegen, diese werden später mit weißem Baumwollstoff dargestellt. Die Ebene schieben wir ganz nach oben, wählen alle Objekte der Ebene, entfernen die Flächenfüllung und fügen eine knallrote Konturlinie hinzu.

Wolken-Kontur

Wir vereinfachen die auszustickende Konturlinie, indem wir z.B. Knoten löschen oder kleine Inseln zu größeren Objekten verbinden (+). Dabei müssen wir lediglich darauf achten, dass keine Teilobjekte in dem Bereich anderer Füllflächen landen, in diesem Fall Körper oder Gesicht.

Wolken-Kontur vereinfacht

Der nächste Schritt ist dann, die Ebene mit den Körper- und Gesichts-Füllflächen zu duplizieren, das Duplikat ganz nach oben zu bringen und wieder die Flächenfüllung durch eine Konturlinie zu ersetzen, z.B. knallgelb zur Unterscheidung von der bereits vorhandenen Kontur der Wolken.

Körper- / Gesichts-Kontur

Auch bei diesen Flächen vereinfachen wir, insbesondere löschen wir die Spitzen der Mähne und fügen angrenzende Flächen zu größeren Flächen zusammen.

Körper- / Gesichts-Kontur vereinfacht

Je nach Wahl der Applikations- und Trägerstoffe kann es passieren, dass sich der Träger verzieht oder die Applikationen ausfransen so dass die Ränder der Applikationen sichtbar werden.

Um das zu vermeiden sorgen wir für mehr Überlappungen, indem wir die Konturlinien auswählen und mit Hilfe von “Path -> Dynamic Offset” um etwa 2mm vergrößern. Dabei muss man darauf achten, dass Ränder trotzdem von den angrenzenden Satinstichen verdeckt werden.

Körper- / Gesichts-Kontur hinreichend vergrößert

Damit kommen wir auch schon zu dem letzten Schritt, der in Inkscape durchgeführt wird: Die Ebenen mit den Füllflächen, die nicht gestickt sondern als Applikation aufgebracht werden sollen, ausblenden und die Datei als WMF-Datei speichern. Wenn WMF-Export nicht funktioniert liegt das wahrscheinlich an einer veralteten Inkscape-Installation, die aktuelle Version bekommt man auf der Inkscape-Download-Seite

Alle weiteren Schritte werden in PE-Design durchgeführt. Die WMF-Datei wird über “Muster Importieren -> von Vektorbild” in PE-Design importiert. Das führt erstmal zu 97k Stichen, die wir aber noch erheblich reduzieren können, indem wir alle Flächen nicht mit Füll- sondern mit Satin-Stichen realisieren. Dadurch wird die Stichzahl auf 61k reduziert, ein niedriger Wert für so ein großes Motiv. Mit weiteren kleinen Optimierungen kommen wir auf 59k Stiche, die Umstellung von 5 auf 7 Stiche pro Millimeter bringt aber 21k Stiche, damit sind es 80k.

Um zu vermeiden, dass man am Ende die Naht sieht, die den Applikationsstoff befestigt und um Überlappungen zu vermeiden erhöhen wir die Zugkompensation von dem Standardwert (0,2mm) auf 0,6mm. Dadurch werden alle Linien 0,8mm dicker, das merkt aber niemand.

Dann schalten wir von der soliden Ansicht auf die Stichansicht (F9) und überprüfen alle Teile auf Stellen, an denen viel zu viele Stiche auf eine Stelle konzentriert werden, z.B. so:

Schlechter Satin-Stich, zu viele Stiche auf einer Stelle

Mit dem Knoten-Editor (Wählen -> Punkt wählen) spielen wir so lange an den Punkten herum, bis die Stiche halbwegs gleichmäßig verteilt sind:

Besserer Satin-Stich, Stiche gleichmäßig verteilt

Wenn eine Fläche keine signifikante Krümmung aufweist kann man auch die Stichrichtung auf konstant setzen, z.B. bei der blauen Fläche in der Mitte:

Variable (oben) vs. konstante (unten) Stich-Richtung

Bei ausgeprägten Spitzen hilft es in der Regel, die Spitze nicht ganz so dünn auslaufen zu lassen:

Dünne Spitze (links) vs. dicke Spitze (rechts)

Wenn das Ende eines Satin-Stiches (orange) später unter einem anderen Stich (blau) verschwindet kann man hemmungslos korrigieren und dabei die Form ändern, sieht man später ja sowieso nicht.

Schlechter Satinstich (links) vs. guter Satinstich (rechts), der am Ende unter nachfolgenden Stichen versteckt wird

Jetzt kann man natürlich noch jede Menge weitere Optimierungen vornehmen, aber das ist eine andere Geschichte und soll ein andermal erzählt werden.

Wir exportieren das Motiv als .dst-Datei, speichern es auf einem USB-Stick und kopieren es damit auf die Maschine.

Handarbeit

Erstmal wird der ganze Stoff gewaschen, um zu vermeiden dass er später beim Waschen nochmal schrumpft. Dann muss gebügelt werden, dabei muss man (zumindest im RZL) darauf achten, dass man nicht erfriert.

Trägerstoff wird gebügelt

Da wir einen Bezug für ein 80x80cm²-Kissen herstellen wollen zeichnen wir auf die linke Seite des Stoffes mit Schneiderkreide ein 80x160cm²-Rechteck an und schneiden es mit etwa 5cm Nahtzugabe aus.

Ausgeschnittener Trägerstoff

Möglicherweise verzieht sich der Stoff während dem Besticken. Um zu vermeiden, dass man am Ende die Stiche sieht mit denen die Applikationsstoffe festgenäht werden wählen wir zum befestigen das selbe Garn wie für den Satinstich, der am Ende die Schnittkante verdecken soll.

Wir stellen die Maschine auf automatischen Farbwechsel ohne automatisches Weitersticken (Handbuch, PDF-Seite 25), so können wir nach dem Befestigen der Applikationsstoffe jeweils in aller Ruhe die überstehenden Ränder abschneiden und den nächsten Applikationsstoff auflegen.

Um das Motiv aussticken zu können schrauben wir die Rahmenhalterungen an die äußersten Positionen, bügeln den Grundstoff und die Applikationsstoffe und bügeln ein Stickvlies (1860B) auf die Rückseite des Grundstoffes auf.

Stickvlies wird aufgebügelt

Der Grundstoff wird zusammen mit einem weiteren nicht-klebenden Vlies in den großen Rahmen eingespannt und der Rahmen in die Rahmenhalterung eingespannt. Auf den Grundstoff wird der erste Applikationsstoff aufgelegt, die erste Kontur gestickt und der überstehende Rest mit einer kleinen Stoffschere abgeschnitten. Dabei sollte man vermeiden, viel Kraft auf den Stoff auszuüben, ansonsten kann sich der Grundstoff verziehen oder wellen.

Wolken-Kontur wird ausgeschnitten

Ich habe beim ersten Versuch nur die äußere Kontur der Wolke ausgeschnitten und zwei Lagen weißen Stoff für die Wolke benutzt. Dadurch hat der Bezug am Ende teilweise vier Lagen Stoff und ist ziemlich unflexibel, weicher wird es wenn man nur eine Lage nimmt und tatsächlich entlang aller Konturen schneidet.

Wenn die erste Kontur ausgeschnitten ist wird ein großzügiges Stück blauer Stoff ausgeschnitten, gebügelt und auf den Trägerstoff aufgelegt.

Stoff für Körper-Kontur auf Trägerstoff aufgelegt

Auch hier wird wieder die Kontur gestickt und die Reste ausgeschnitten.

Körper-Kontur gestickt und ausgeschnitten

Jetzt können wir die Stickmaschine wieder auf vollautomatisch stellen und den Rest des Motivs aussticken. In der Zwischenzeit üben wir mit der Husqvarna das nähen perfekt gerader Nähte an Stoffresten.

Nähübungen

Klappt schonmal super.

Nachdem das Motiv ausgestickt ist müssen wir es auf dem Rahmen entfernen, die Rahmenabdrücke glattbügeln, das Stickvlies abziehen und das ganze zu einem Kopfkissenbezug zusammennähen. Für den letzten Schritt siehe diese Anleitung.

Das fertig gestickte Motiv sieht dann ungefähr so aus:

Fertig gesticktes Motiv

Alle verwendeten Garne sind nachleuchtend und es wurden alle verfügbaren nachleuchtenden Garne verwendet, leider leuchten alle diese Garne sehr grünlich, die unterschiedlichen Farben sind eher ein Artefakt des automatischen Weißabgleichs:

Fertig gesticktes Motiv im Dunkeln

Alle relevanten Dateien findet ihr in dieser ZIP-Datei.

Es bleibt die Frage, wie man möglichst ohne Handarbeit von einer beliebigen SVG-Datei zu einer geeigneten kommt, aber das ist eine andere Geschichte und soll ein andermal erzählt werden.

15. March 2015 00:00:00

13. March 2015

RaumZeitLabor

RaumZeitLabor App für iOS

Das ändert alles. Wieder einmal.

Seit wenigen Tagen lässt sich das Angebot des RaumZeitLabors auch vom iPhone aus genießen.

Mit unserer neuen App kannst Du aktuelle Informationen wie die anwesenden Laborant*innen oder die Raumtemperatur abrufen. Außerdem hast du Zugriff auf die Lichtsteuerung.

One more thing: Du kannst deine Snacks auch durch Scannen des Barcodes bezahlen.

Den Code findet ihr auf Github. Dort könnt ihr auch Verbesserungsvorschläge und Pull-Requests erstellen.

13. March 2015 12:37:23

22. February 2015

RaumZeitLabor

Bericht Stickwochenende

Wiiilmaa eröffnete das Stick-Wochenende am Samstag um 4:23 Uhr mit einem irischen Wolfshund, bei dem leider das graue Garn ausging.

Wenige Stunden später kam habo und brachte seine selbstgeschriebene Sticksoftware mit, die diverse Fraktale erzeugen kann, darunter die Drachenkurve. Die wurde erstmal RaumZeitLabor-kompatibel auf 15 Iterationen aufgebohrt und mit 32.771 Stichen auf ein T-Shirt gestickt:

Drachenkurve

Ein Versuch, mit einem Dreifachstich und 98.307 Stichen ein dichteres Ergebnis zu erreichen endete mit einem akzeptablen Stichbild, aber leider auch damit, dass Brust und Rücken mit über neuntausend Stichen aneinander festgenäht wurden.

Am Tag zwei tauchte dann zur großen Überraschung von niemandem ein wildes Effektgarn auf, das alle zwei Meter von blau auf weiß und zurück wechselt. Es zeigt sehr effektiv die fraktale Struktur der Drachenkurve im Inneren der großen Flächen:

Drachenkurve mit Effektgarn ausgestickt

Drachenkurve mit Effektgarn ausgestickt, Teilansicht

Wer mehr über die Sticksoftware erfahren möchte, die dieses Motiv erzeugt hat kann sich an habo wenden.

Zu Gast war auch eine Familie mit knapp 2-jähriger Tochter, daher gab es diverse denkwürdige Gespräche, etwa folgendes:

Was möchtest du haben?

Ja.

Möchtest du den Hasen haben?

Ja.

Möchtest du das Malzbier haben?

Ja.

Möchtest du einen Schuss Katzenblut dazu?

Ja.

Du hast aber einen merkwürdigen Geschmack

Für die Kleine mussten es dann natürlich Ponies sein:

Kind mit Pony-T-Shirt Pony-Stickerei 1 Pony-Stickerei 2

Insgesamt haben wir 444.443 Stiche gemacht und dabei jede Menge Spaß gehabt. Vielen Dank auch den Besuchern, die tolle Ideen mitgebacht haben und mit denen wir uns über Sticktechniken austauschen konnten.

Spätestens nächstes Jahr werden wir die Veranstaltung wiederholen, bis dahin wünschen wir unseren Gästen wenig Fadenbrüche und immer genug Unterfaden in der Maschine.

Euer StickZeitLabor

22. February 2015 22:42:23

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.

GKM Mannheim Panorama

Das GKM sagt über diese Besichtigung:

Entdecken und erleben Sie das Innenleben eines modernen Steinkohleblocks – von der Kohlemühle über den Dampferzeuger bis hin zur Rauchgasreinigungsanlage. Bei der Besichtigung von Block 8 lernen Sie alle Arbeitsschritte kennen, die für eine umwelt- und klimafreundliche Strom- und Fernwärmeerzeugung notwendig sind.

Die Veranstaltung beginnt am Mittwoch, den 25. März, um 14:00 Uhr an der Verwaltungspforte des GKM (Marguerrestr. 1, 68199 Mannheim-Neckarau). Nachdem wir mit einem Informationsfilm über das GKM entsprechend eingestimmt wurden, beginnen wir den geführten Rundgang durch den Block 8. Einer der Höhepunkte der Führung wird ein Besuch auf der Kesseldecke sein. Aus 120m Höhe hat man eine wunderbare Aussicht über das Kraftwerksgelände und die Metropolregion Rhein-Neckar. Das Ganze wird ungefähr 2,5 Stunden dauern.

Voraussetzungen für die Teilnahme sind ein Mindestalter von 14 Jahren. Aus Sicherheitsgründen können leider nur Personen ohne körperliche Einschränkungen, sowie ohne Höhenangst oder Herzschrittmacher, teilnehmen. Wie üblich ist die Mitgliedschaft im RaumZeitLabor e.V. keine Voraussetzung um an der Veranstaltung teilnehmen zu können.

Die maximale Teilnehmerzahl ist beschränkt, daher ist eine verbindliche Anmeldung erforderlich. Um euch anzumelden sprecht entweder blabber direkt an oder schreibt eine Mail mit dem Betreff “GKM Exkursion” an info@raumzeitlabor.de. Die Anmeldung muss die bürgerlichen Namen, Adressen und Geburtsdaten der Teilnehmer enthalten, da das GKM nur Personen reinlässt die vorher über eine entsprechende Teilnehmerliste gemeldet werden. Die Anmeldungen müssen bis zum 17. März eingegangen sein.

Die Teilnehmer an der Exkursion sollten sich, wie immer, untereinander abstimmen und möglichst Fahrgemeinschaften o.Ä. bilden. Weitere Informationen zur Exkursion gehen zu gegebener Zeit per Mail an die angemeldeten Teilnehmer.

Bildquelle: GKM Mannheim Panorama, by-nc-sa, matthiashn

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

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

30. January 2015

koebi

Ein kleiner Trick für Copy-Paste

Hin und wieder stolpere ich über das Problem, Output von der Kommandozeile irgendwo einfügen zu wollen, sei es nun weil ich einen komplizierten Pfad nicht noch mal eingeben will, weil ich irgendwas cat-en und irgendwo einfügen will oder aus irgendeinem anderen Grund. Dann könnte man natürlich irgendwie (“copying the linux way”) die mittlere Maustaste nutzen, aber das ist manchmal fummelig, oder irgendwas anderes. Ich habe als Lösung hierfür vor kurzem das wunderschöne Tool xclip entdeckt.

30. January 2015 00:00:00

A first post/Ein erster Post

A first sign of life… …is exactly what this blog post is. Since I haven’t decided whether to write german or english in this blog, this post exists in both languages. Ein erstes Lebenszeichen… …ist genau das, was dieser Blogpost ist. Da ich mich noch nicht entschieden habe, ob ich in diesem Blog auf Deutsch oder Englisch schreiben werde, existiert dieser Post in beiden Sprachen.

30. January 2015 00:00:00

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

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