Thread Dumps – auch für Python

Thread Dumps sind Momentaufnahmen des Aufruf-Stacks für jeden Thread einer laufenden multi-thread Anwendung. Dies ist in vielen Situationen zur Analyse hilfreich. Diese gestaltet sich gerade bei multi-thread Anwendung meist komplizierter.

Für Java gibt es das Programm jstack (u.a. mit jps im JRE enthalten) um Thread Dumps zu erzeugen.

Unter Python kann ein ähnliches Verhalten (getestet unter Linux) mit einem kleinen Umweg über einen Signal-Handler erreicht werden:

...
import faulthandler 
import signal
import os
...

def handler(signum, frame):
  file ='/tmp/threads'
  print('Writing thread dump to ', file)
  with open(file, 'w') as f:
    faulthandler.dump_traceback(file=f, all_threads=True)

...
if __name__ == '__main__':
  with open('/tmp/pid', 'w') as f:
    f.write(str(os.getpid()))
  signal.signal(signal.SIGUSR1, handler)
  ...

Nach dem Starten des Programms kann man über die PID aus /tmp/pid einen Thread Dump erzeugen:

kill -USR1 `cat/tmp/pid`

Dieser sieht exemplarisch so aus (extra in kleinerer Schriftart um die Zeilen ohne Umbrüche zu erhalten):

Thread 0xb3ccb460 (most recent call first):
 File "/home/jlusiardi/.local/lib/python3.4/site-packages/zeroconf.py", line 1102 in run
 File "/usr/lib/python3.4/threading.py", line 920 in _bootstrap_inner
 File "/usr/lib/python3.4/threading.py", line 888 in _bootstrap

Thread 0xb44ff460 (most recent call first):
 File "/usr/lib/python3.4/socketserver.py", line 154 in _eintr_retry
 File "/usr/lib/python3.4/socketserver.py", line 236 in serve_forever
 File "/home/jlusiardi/sources/smarthome/homekit_link/__init__.py", line 142 in run
 File "/usr/lib/python3.4/threading.py", line 920 in _bootstrap_inner
 File "/usr/lib/python3.4/threading.py", line 888 in _bootstrap

Thread 0xb4cff460 (most recent call first):
 File "/home/jlusiardi/sources/smarthome/influxdb/__init__.py", line 109 in run
 File "/usr/lib/python3.4/threading.py", line 920 in _bootstrap_inner
 File "/usr/lib/python3.4/threading.py", line 888 in _bootstrap

Thread 0xb6025460 (most recent call first):
 File "/usr/lib/python3.4/socketserver.py", line 154 in _eintr_retry
 File "/usr/lib/python3.4/socketserver.py", line 236 in serve_forever
 File "/home/jlusiardi/sources/smarthome/homematic/callback.py", line 42 in run
 File "/usr/lib/python3.4/threading.py", line 920 in _bootstrap_inner
 File "/usr/lib/python3.4/threading.py", line 888 in _bootstrap

Current thread 0xb6fb6300 (most recent call first):
 File "./main.py", line 19 in handler
 File "/usr/lib/python3.4/cmd.py", line 126 in cmdloop
 File "/home/jlusiardi/sources/smarthome/cli/__init__.py", line 32 in cmdloop
 File "./main.py", line 50 in <module>

Auch hier bieten sich verbesserte Analysemöglichkeiten analog zu Java.

Spielchen mit RSA-Schlüsseln

Als Einstiegshürde für ein CTF (Capture the Flag) dient gerne mal ein RSA Schlüsselpaar, von dem nur der öffentliche Teil bekannt ist. Also kein unrealistischer Ansatz, lediglich die Schlüssellängen sollten entsprechend klein sein.

Vorbereiten der Challenge

Diese Schritte werden vom Spielleitder durchgeführt. Wichtig ist eine geeignete, nicht zu lange Schlüssellänge zu wählen. Hier wählen wir 256 Bit als Schlüssellänge. Das sollte die Teilnehmer vor keine Probleme stellen.

Generieren des Schlüsselpaars

Der wesentliche Schritt bei der Erzeugung eines RSA-Schlüsselpaars ist die Wahl von 2 Primzahlen p und q, deren Produkt n (der RSA-Modulus) die gewünschte Schlüssellänge besitzt.

Dank OpenSSL ist es einfach ein RSA-Schlüsselpaar zu erzeugen:

openssl genrsa -des3 -out private.pem 256
openssl rsa -in private.pem -outform PEM -pubout -out public.pem

Daraus ergibt sich als Public Key beispielsweise:

-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALRUOO0rvPEA282wqL4VF5GibnA1kcux
LHdIOcT807+DAgMBAAE=
-----END PUBLIC KEY-----

Den privaten Schlüssel private.pem können wir nun löschen, da wir diesen zum Einen nicht mehr benötigen und zum Anderen ja rekonstruieren wollen.

Verschlüsseln der Probedatei

Eine Probedatei lesbar.txt wird mit dem öffentlichen Schlüssel mit OpenSSL verschlüsselt:

openssl rsautl -encrypt -inkey public.pem -pubin -in lesbar.txt -out geheim.txt

Das Ergebnis der Verschlüsselung ist eine Datei, die nur unlesbare binäre Daten enthält. Sie kann hier heruntergeladen werden: geheim.txt. Diese Datei und der öffentliche Schlüssel gehen an die Teilnehmer.

Lösen der Challenge

Diese Schritte werden durch die Teilnehmer durchgeführt.

Knacken der Schlüssel

Zunächst müssen wir aus dem öffentlichen Schlüssel die beiden Parameter  n (Modulus) und e (Exponent) extrahieren:

from Crypto.PublicKey import RSA

public_key = RSA.importKey(open('public.pem', 'r').read())
print 'n =', public_key.n
print 'e =', public_key.e

Dazu verwenden wir die Bibliothek pycrypto (Debian: python-crypto). Ausgegeben werden die beiden oben genannten Werte, in unserem Beispiel also:

n = 815651207903382691105573612057017618852
    64115611526254943458542612275141001091
e = 65537

Nun muss der Modulus faktorisiert werden (n ist das Produkt der beiden Primzahlen p und q). Dazu kann das msieve von Jason Papadopoulos verwendet werden.

Für unsere Zahl n liefert msieve auf einem Core2Duo T7400 nach knapp 10 Minuten die beiden Primfaktoren:

p = 264446414907090989475638551039611206507
q = 308437234133027923039636551098640509513

Alternativ können wir auch factordb.com verwenden, wenn die Zahl dort bereits faktorisiert vorliegt.

Nun müssen wir aus p und q den privaten Exponenten d berechnen:

d = 1/e mod (p-1)*(q-1)

oder mit Python und dem Modul gmpy2:

import gmpy2

p = 264446414907090989475638551039611206507
q = 308437234133027923039636551098640509513
e = 65537
d = gmpy2.invert(e,(p-1)*(q-1))

Aus den Werten n,e und d wird nun der private Schlüssel erstellt und ausgegeben:

from Crypto.PublicKey import RSA
key = RSA.construct((n,e,d))
print key.exportKey()

In unserem Beispiel ergibt das:

-----BEGIN RSA PRIVATE KEY-----
MIGrAgEAAiEAtFQ47Su88QDbzbCovhUXkaJucDWRy7Esd0g5xPzTv4MCAwEAAQIh
ALFDhX4nG6FxbaChww6vnyzjasWei1L/rUg3aG/c6MaxAhEA6ArZu41/pzoKRlXH
MfYqSQIRAMbyhuPv26I/S0+zokene2sCEDxkfpDK3huHBp+RubtuJ0kCECAEWecG
6+7Rhto9y4kCkB8CEQCSSbMXMjOybMpz3gCOQYeS
-----END RSA PRIVATE KEY-----

Wir speichern den privaten Schlüssel wieder in der Datei private.pem ab.

Entschlüsseln der Probedatei

Wurde alles richtig durchgeführt, so kann man mit folgender OpenSSL Anweisung die Probedatei entschlüsseln:

openssl rsautl -decrypt -inkey private.pem -in geheim.txt -out lesbar.txt

Der genaue Inhalt von lesbar.txt wird hier jedoch nicht verraten.

Abschluss

Man erkennt hier am Zeitaufwand zur Faktorisierung eines 256 Bit Schlüssels bereits, dass die Sicherheit von RSA auf genau dieser Schwierigkeit basiert. In der Praxis verwendet man daher Schlüssellängen von mindestens 2000 Bit (siehe dazu die Technische Richtilinie des BSI: Kryptographische Verfahren: Empfehlungen und Schlüssellängen (Seite 39, Kapitel 3.5 – RSA).

UML mit PlantUML

PlantUML ist ein ein GPL Tool zur Erstellung von folgenden UMLDiagramm Typen aus reinen Text-Dateien:

  • Klassendiagramm (class diagram)
  • Sequenzdiagramm (sequence diagram)
  • Objektdiagramm (object diagram)
  • Anwendungsfalldiagramm (use case diagram)
  • Aktivitätsdiagramm (activity diagram)
  • Komponentendiagramm (component diagram)
  • Zustandsdiagramm (state diagram)
  • Deploymentdiagramm (deployment diagram) BETA (Stand 1. April 2017)
  • Zeitverlaufsdiagramm (timing diagram) BETA (Stand 1. April 2017)

Verwendbar ist PlantUML entweder online über einen Demo-Bereich oder lokal über eine JAR-Datei. Für ein lokales Ausführen braucht man Java und die Graphviz-Software.

Zusätzlich bietet das Plugin PlantUML integration von Eugene Steinberg (erhältlich für alle IntelliJ IDEA basierenden Produkte) eine Integration in meine Lieblings-IDE. Features sind unter anderem:

  • Syntax Highlighting
  • Autocompletion bereits definierter Elemente
  • Parallele Darstellung von Definition und Ergebnisgrafik

Kleines Beispiel aus meinem aktuellen Projekt:

@startuml

package modes {
    interface Mode {
     + handle_input(code): Mode
     + display(device)
     + handle_mpd(data)
     + activate()
    }

    class ModeProxy {
      current_mode
     + handle_input(code): Mode
     + display(device)
     + handle_mpd(data)
    }

    class MenuMode <<Singleton>> {

    }

    ModeProxy ..|> Mode

    MenuMode ..|> Mode
    MenuMode -->"*" Mode : "topics"
}
@enduml

und das zugehörige Bild:

Ergebnis der Demo Datei
Ergebnis der Demo Datei

Fazit: Ein gutes Tool mit einigen Vorteilen (z.B. einfache Versionierung der Eingabedateien) unter einer der richtigen Lizenzen, welches nicht nur in IntelliJ und Co verwendet werden kann sondern in einer Vielzahl weiterer Tools.

Open Source Hausautomatisierung im Vergleich

Inzwischen sind alle Heizkörper und auch fast alle Lichter in der heimischen Wohnung über die Weboberfläche der eQ-3 CCU2 fernbedienbar und auch die @Home App funktioniert soweit gut. Die Produktpflege und Dokumentation von eQ3 würde ich vorbildlich nennen: auf der Downloads-Seite findet man sowohl die jeweils aktuelle CCU2 Firmware (inklusive Change Log) als auch die Dokumentation der Schnittstellen (HomeMatic XML-RPC).

Vorhandene Komponenten

Folgende Homematic und Homematic  IP Produkte sind aktuell im Einsatz:

  • HM-CC-RT-DN – Funk-Heizkörperthermostat
  • HM-LC-SW1-FM – Schalt-Aktor 1-fach Unterputz (ohne Taster)
  • HM-LC-SW2-FM – Schalt-Aktor 2-fach Unterputz (ohne Taster)
  • HM-LC-Sw1PBU-FM – Schalt-Aktor 1-fach Unterputz (für Markenschalter)
  • HM-PB-2-WM55 – 2-fach-Funk-Wandtaster
  • HmIP-BSM – Schalt-Aktor 1-fach Unterputz (Homematic IP, für Markenschalter)
  • HMIP-PSM – Schalt- und Messsteckdose (Homematic IP)

Allerdings kann man (ohne Kritik an eQ-3 zu üben) naturgegeben nur deren Produkte verknüpfen und steuern. Weitere bereits vorhandene Geräte sollten ebenso angesprochen werden können:

Zum Glück gibt es ausreichend Softwarelösungen für dieses Problem. Vor dem Aufzählen der Kandidaten sollen allerdings Vergleichskriterien festgelegt werden.

Vergleichskriterien

  1. Die Software muss quell-offen und frei sein (OpenSource)
  2. Dokumentation auf Englisch bzw. Deutsch und in ausreichenden Qualität und Detailtiefe vorhanden (Dokumentation)
  3. Größe der Community
  4. Support für Komponenten von eQ-3 für Homematic und Homematic IP (Hardware-Unterstützung), da diese bereits vorhanden ist.
  5. Apps für iOS bzw. Android (Apps)
  6. Verwendete Programmiersprachen & Technologien (Technologie)
  7. Die Software muss Graphen zur historischen Analyse von Messwerten bieten (Graphen)
  8. Die Software muss über Regeln erweiterbar sein, z.B. Verknüpfung von Schalter, Reaktion aufs Verlassen der Wohnung (Regeln)

openHAB

openHAB basiert auf Java und OSGi (Equinox) und ist somit auf allen Plattformen lauffähig, auf denen Java angeboten wird (Linux, Windows, OS X,…). Laut Wiki sind auch ARM SBCs ausreichend.

openHAB verwendet intern einen Event Bus, um alle anderen Komponenten zu verbinden. Weitere wichtige Komponenten sind das openHAB Repository, welches den aktuell bekannten Zustand aller bekannten Items vorhält, und die Bindings, die als Abstraktionsschicht zwischen openHAB und den anzubindenden Geräten fungiert.

Über das openHAB Repository werden sowohl die diversen User Interfaces (WebUI, Apps für iOS, Android, Windows Phone, …) als auch die Verarbeitung der Automatisierungsregeln angebunden.

URLhttp://www.openhab.org/
OpenSourcehttps://github.com/openhab/openhab (EPL)
Dokumentationhttps://github.com/openhab/openhab/wiki
Dokumentation ausführlich für alle Module auf Englisch vorhanden, über github Wiki gut erweiterbar.
CommunityHohe Aktivität
Hardware-
Unterstützung
Breite Unterstützung für diverse Hardware und externe Software
Appsverfügbar für iOS, Android, Windows Phone und sogar Pebble
TechnologieJava / OSGi
GraphenCharts sind über Persistenzen für fast alle messbaren Größen möglich.
RegelnopenHAB ist über Regeln steuerbar. Diese sind in einer DSL zu erstellen und integrieren Java.

Home Assistant

Python 3 bildet die Basis für Home Assistant. Entsprechend bietet auch Home Assistant einen breiten Support für die gängigsten Betriebssysteme (Video-Tutorials existieren für Windows 10, OS X und Ubuntu). Auch Hinweise zum Durchführen einer Aktualisierung sind vorhanden. Installationshinweise für Raspberry Pi, Docker, Vagrant und auch Synology NAS sind vorhanden.

Auch Home Assistent nutzt architektonisch einen Bus, um die einzelnen Komponenten zu verbinden, eine Service Registry und eine State Machine zum Verwalten der Zustände der einzelnen Komponenten.

URLhttps://home-assistant.io/
OpenSourcehttps://github.com/home-assistant/home-assistant (MIT)
DokumentationCookbook für Anwender und Dokumentation für Entwickler
CommunitySehr hohe Aktivität
Hardware-Unterstützungüber 470 (Stand Version 0.33.0) verschiedene Komponenten (Hard- und Software), Homematic ist unterstützt, Homematic IP jedoch nicht
Appskeine, iOS App in Vorbereitung
TechnologiePython
GraphenGraphen sind an messenden Objekten vorhanden
Regelnmöglich, können in YAML definiert werden

fhem

fhem wird in Perl entwickelt und schont daher die benötigten Ressourcen  (sogar auf Fritz!Boxen ist ein Betrieb möglich). Eine Installation ist auch hier wieder auf den 3 großen Betriebssystemen möglich.

Für die Freunde eines Handbuchs hält die Community eine ausführliche Einführung bereit.

URLhttp://fhem.de//
OpenSourcehttps://sourceforge.net/p/fhem/code/HEAD/tree/trunk/fhem/ (GPL v2)
DokumentationAusführliches deutschsprachiges PDF, ausführliches gemischtsprachiges Wiki
CommunitySehr hohe Aktivität
Hardware-UnterstützungÜbersicht über unterstützte Hardware HmIP-Geräte noch nicht offiziell gelistet aber laut Forum möglich
Appsu.a. FHEMobile für iOS und andFHEM für Android
TechnologiePerl
GraphenGraphen sind über gnuplot möglich
RegelnRegeln in Perl geschrieben möglich

calaos

calaos ist ein französisches Projekt und setzt für die Steuerung auf KNX und DMX. Als Hardware wird hauptsächlich Wago unterstützt. Leider ist die Dokumentation hauptsächlich in Französisch und auch das Datum des letzten Eintrags aus dem Entwickler-Blog aus dem Februar 2015 lässt nichts gutes hoffen.

URLhttps://calaos.fr
OpenSourcehttps://github.com/calaos (GPL v3)
Dokumentationfranzösischsprachiges Forum, Wiki in Französisch und Englisch
Communitymoderate Aktivität
Hardware-UnterstützungEingeschränkt, lediglich WAGO, OneWire Komponenten, Zibase, GPIO und IoT Devices werden unterstützt (Quelle)
AppsCalaos Mobile für iOS, Calaos Home für Android
TechnologieC/C++
Graphenunbekannt
Regelnintegrierter LUA Support

domoticz

domoticz ist in C/C++ geschrieben und nativ verfügbar für Raspberry Pis, Windows, Linux, OS X und für einige NAS-Syteme. Als Scripting-Engine wird Lua verwendet, über die mit Blockly die Automatisierung vorgenommen wird. Leider Homematic nicht unterstützt, jedoch ist die Liste an unterstützter Hardware recht umfangreich.

URLhttps://domoticz.com/
OpenSourcehttps://github.com/domoticz/domoticz (GPL v3)
Dokumentationenglischsprachiges Handbuch und Wiki
Communityhohe Aktivität
Hardware-UnterstützungModerat, leider kein Homematic (Quelle)
AppsImperiHome für iOS und Android
TechnologieC/C++
GraphenJa, als Log in der UI
Regelnintegrierter Support für LUA, Bash, Perl, PHP und Python, Support für Blockly

openmotics

openmotics vereint ein Angebot von Soft- und Hardware, die unter eine OpenSource Lizenz gestellt wurde. Die Hardware wird auch im Shop verkauft. Allerdings existieren nur Module zum Einbau in Schaltschränke auf Hutschienen. openmotics eignet sich somit kaum zum nachträglichen Einbau sondern eher für Neubauten. Aber auch dann ist keine Integration weitere, fremder Komponenten vorgesehen.

URLhttps://www.openmotics.com/
OpenSourcehttps://github.com/openmotics (MIT)
Dokumentationenglischsprachiges Wiki
Communitykeine Aktivität (Quelle)
Hardware-Unterstützungnur spezielle openmotics Hardware (siehe Shop)
Appskeine bekannt
TechnologiePython
GraphenJa
RegelnJa

freedomotic

freedomotic bezeichnet sich als Open Iot Framework, versteht sich also nicht nur zur Heimautomatisierung, sondern versucht weiter zu gehen. Technologisch ist wie bei openHAB in Java Grundlage, es wird aber wohl auf OSGi verzichtet. Die verfügbaren Plugins sind im Marketplace verzeichnet.

Installationsanleitungen sind leider bisher nicht wirklich vorhanden, lediglich eine kurze Seite zum Raspberry Pi und Docker (Zugang über guest/guest, nur REST API) enthalten Text.

Der Einsatz von 2 getrennten Messaging Bussen ermöglicht hier zusätzlich noch das Clustering mehrerer freedomotic-Instanzen. Die verschiedenen Hardwaretypen und externen Services werden über Module angebunden.

URLhttp://freedomotic.com/
OpenSourcehttps://github.com/freedomotic/freedomotic (GPL v2)
Dokumentationenglischsprachiges Benutzerhandbuch
Communityunbekannt (Quelle)
Hardware-Unterstützungdiverse Hardware (siehe Shop), keine Hinweise auf Homematic
Appsunbekannt
TechnologieJava
Graphenunbekannt
RegelnÜber XML möglich

Bewertung

Eine abschließende Bewertung fällt schwer, jedoch werde ich freedomotic (fehlende Unterstützung für Homematic), openmotics (nur spezielle Hardware), domoticz (fehlende Unterstützung für Homematic, verwendete Programmiersprache) und calaos (stark eingeschränkte Hardwareunterstützung) aus den jeweilig genannten Gründen nicht weiter verfolgen.

Für

  • openHAB,
  • Home Assistant und
  • fhem

wird es weitere Artikel geben. Diese werden dann von hier verlinkt.

Ergänzung 7. Januar

Inhaltsverzeichnis eingefügt.

Python 3.3.0 auf Pogoplug: Watcher.py portiert

Watcher ist ein Dienstprogramm, welche analog zu incrond auf Änderungen in Verzeichnissen reagieren kann. Im Gegensatz zu incrond kann Watcher (im Original von Greggory Hernandez, geforked von Andreas Gohr) jedoch auch Verzeichnisse rekursiv betrachten.

Auf meinem Pogoplug die neuste Version von github per zip-Datei geladen, aber es funktionierte nicht. Grund: Python 2.7.x vs. Python 3.3.0.

Nach einigen Anpassungen funktioniert das Skript nun, und ich habe einen weiteren Fork angelegt, der diese Änderungen beinhaltet. Dank der github-OS X-Software war es auf für git Neulinge einfach, die Änderungen hoch zu laden.

Weitere Verbesserungen könnten eventuell folgen.