Open vSwitch + SDN – aus dumm mach schlau

Verbindet man Open vSwitch mit einem SDN-Controller (z.B. OpenDaylight), ist das Netzwerk ersteinmal tot. Erst mit dem Hinzufügen von Regeln bekommt das Netz wieder in Gang. Für Basiskommunikation benötigt es Regeln, welche ARP- und IP-Traffic berücksichtigen. Dazu müssen folgende Fälle berücksichtigt werden:

  1. ARP-Traffic an die Broadcastdomain
  2. ARP-Traffic an einen bestimmten Host
  3. IP-Traffic an deinen bestimmten Host

Die Regel für den ersten Fall muss alle ARP-Pakete an die Broadcastdomain über alle Interfaces weiterleiten, damit es den Zielhost erreichen kann:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <flow-name>arp2broadcast</flow-name>
    <table_id>0</table_id>
    <id>0</id>
    <priority>100</priority>	
    <instructions>
        <instruction>
            <order>0</order>
	     <apply-actions>		
                <action>
                    <order>1</order>
                    <output-action>
                        <output-node-connector>ALL</output-node-connector>
                        <max-length>200</max-length>
                    </output-action>
                </action>    
	     </apply-actions>
        </instruction>
    </instructions>
    <match>
   <ethernet-match>
            <ethernet-type>
                <type>2054</type>
            </ethernet-type>
	   <ethernet-destination>
                <address>ff:ff:ff:ff:ff:ff</address>
            </ethernet-destination>
   </ethernet-match> 
  </match>
</flow>

Für Fall 2 muss die Ethernetzieladresse und der Output-Port angepasst werden. Jeder Host im Netzwerk benötigt einen solchen Eintrag, damit die Pakete entsprechend geroutet werden können:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <flow-name>arp2linuxadmin</flow-name>
    <table_id>0</table_id>
    <id>3</id>
    <priority>100</priority>	
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
                <action>
                    <order>1</order>
                    <output-action>
                        <output-node-connector>4</output-node-connector>
                        <max-length>200</max-length>
                    </output-action>
                </action>
            </apply-actions>
        </instruction>
    </instructions>
    <match>
   <ethernet-match>
            <ethernet-type>
                <type>2054</type>
            </ethernet-type>
	   <ethernet-destination>
                <address>52:54:00:34:85:00</address>
	   </ethernet-destination>
   </ethernet-match> 
  </match>
</flow>

Der Rechner mit der MAC-Adresse 52:54:00:34:85:00 ist über Port 4 erreichbar, der Ethernet-Type 2054 matcht ARP-Pakete. In diesem Fall wird das einfachste Szenario, die VMs sind direkt an den Switch angeschlossen, betrachtet. Sind VMs über einen weiteren Switch angeschlossen, muss der Output-Port der Regeln entsprechend angepasst werden.

Um IP-Pakete zu erfassen, wird der Ethernet-Type entsprechend angepasst:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <flow-name>linuxadmin</flow-name>
    <table_id>0</table_id>
    <id>102</id>
    <priority>100</priority>
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
            	<action>
		    <order>1</order>
                    <output-action>
                        <output-node-connector>4</output-node-connector>
                        <max-length>200</max-length>
                    </output-action>
                </action>
            </apply-actions>
        </instruction>
    </instructions>
    <match>
   <ethernet-match>
            <ethernet-type>
                <type>2048</type>
            </ethernet-type>
            <ethernet-destination>
                <address>52:54:00:34:85:00</address>
            </ethernet-destination>
   </ethernet-match>
   </match>
</flow>

Damit ist eine Grundkommunikation im Netzwerk hergestellt. Weitere, tiefer greifende Konfigurationsmöglichkeiten – wie das setzen von VLAN-Tags oder filtern von bestimmten Pakettypen – ist möglich: https://wiki.opendaylight.org/view/Editing_OpenDaylight_OpenFlow_Plugin:End_to_End_Flows:Example_Flows

HTTP-BASIC-AUTH nach Umleitung auf HTTPS

Eine HTTP-BASIC-AUTH-Authentifizierung sollte man nicht unverschlüsselt durchs Netz jagen. Doof ist es, wenn die Umleitung per .htaccess erst nach der Authentifizierung greift, da die erste Anfrage über HTTP läuft, von der Authentifizierung abgefangen wird und erst danach umgeleitet wird.
Eine Möglichkeit dies zu umgehen sieht so aus:

SetEnvIf %{SERVER_PORT} ^80$ IS_NON_SSL

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

AuthUserFile /pfad/zur/.htpasswd
AuthName "HTTP-BASIC-AUTH über TLS"
AuthType Basic
require valid-user
Allow from env=IS_NON_SSL

via http://stackoverflow.com/questions/10267102/apache-htaccess-redirect-to-https-before-asking-for-user-authentication

Let’s encrypt!

Seit einiger Zeit bietet “Let’s encrypt” seine SSL-Zertifikate in einer geschlossenen Beta-Phase an.
Die CA möchte schnell und einfach Zertifikate für jeden anbieten. Dies geschieht über ein Tool, welches über die Shell ausgeführt wird. Es kümmert sich um die Erstellung des Private-Keys, des CSR, die Validierung der Domain und die Erzeugung des Zertifikates.
“Let’s encrypt” wird direkt aus den GIT-Repos heruntergeladen und ausgeführt. Dabei werden z.T. noch benötigte Pakete nachinstalliert.
Zertifikate werden anschließend über
systemctl stop httpd
cd letsencrypt
./letsencrypt-auto --agree-dev-preview --rsa-key-size 4096 --server https://acme-v01.api.letsencrypt
.org/directory certonly
systemctl start httpd

angefragt. Dabei wird über Port 80 des Servers kommuniziert, was ich etwas unschön finde, da man vorher einen laufenden Webserver beenden muss.
Die Zertifikate sind nur 90 Tage lang gültig, danach müssen sie erneuert werden. Dies kann automatisch über einen Cronjob geschehen, ein weiteres Eingreifen durch den Benutzer ist nicht mehr nötig.
./letsencrypt-auto --agree-dev-preview --renew-by-default --server https://acme-
v01.api.letsencrypt.org/directory -d johnassel.de -d www.johnassel.de certonly
erneuert schon vorhandene Zertifikate. Auch hier muss ein laufender Webserver für den Vorgang beendet werden.
Leider kann man “Let’s encrypt” nicht schon vorhandene CSRs signieren lassen. Diese Schritte übernimmt die Software. Mir wäre es lieber, wenn ich Key und CSR selbst generieren könnte, einen Einfluss kann man aktuell auf die Länge des Schlüssels wohl noch nicht haben.
Auch bietet “Let’s encrypt” die Möglichkeit, direkt die Konfiguration von Apache etc für die generierten Schlüssel und Zertifikate anzupassen. Irgendwie habe ich dabei Bauchschmerzen, wenn eine Software versucht meine Konfiguration anzupassen.
Mit entsprechenden Scripten sollte es aber kein Problem sein, den Vorgang der Zertifikaterstellung so zu scripten, dass “Let’s encrypt” nicht noch in der Konfiguration rumwurschteln muss.

OpenStack schnell und einfach auf einem Host installieren

OpenStack auf einem einzigen Host aufzusetzen kann viel Handarbeit bedeuten, muss aber nicht. Über packstack des RDO-Projekts lässt sich OpenStack schnell und einfach installieren und konfigurieren. Zwar bringt Ferdora 22 Packstack von Haus aus mit sich, das Skript scheint aber noch nicht angepasst zu sein. Auf CentOS 7 lief die Installation ohne Probleme durch – nach 30 Minuten war OpenStack installiert und einsatzbereit.

Fedora 21, KDE-NetworkManager, OpenVPN, tun0

Unter Fedora 21 und KDE hat der Netzwerk-Manager die Eigenart die von einer OpenVPN-Verbindung erstellten tun0-Adapter aus seiner Netzwerkliste nicht zu löschen, wenn die Verbindung getrennt wird. Man kann sie zwar per Hand löschen, eine dauerhafte Lösung ist dies aber nicht.
Ein Script mit
#!/bin/bash
[[ ${1::3} == tun ]] && [[ $2 == down ]] && /usr/bin/nmcli connection delete $1
exit 0

unter /etc/NetworkManager/dispatcher.d/tun löst das Problem temporär bis das Verhalten korrigiert wird.

via https://bbs.archlinux.org/viewtopic.php?id=191044

Kompletten Netzwerkverkehr per iptables umleiten

Um den kompletten Netzwerkverkehr per iptables zu einer anderen Adresse umzuleiten, muss zunächst die Weiterleitung von IP-Paketen im System aktiviert werden (sysctl -w net.ipv4.ip_forward=1).
Als nächstes aktiviert man die eigentliche Weiterleitung mit folgenden Regeln:
iptables -t nat -A PREROUTING -s 0.0.0.0/0 -p all -j DNAT --to-destination $ipdeszielsystems
iptables -t nat -A POSTROUTING -j MASQUERADE

Bei mir kommt die Umleitung immer dann zum Einsatz, wenn ich einen vServer migriert habe, sich die IP gewechselt hat und nur noch die neuen Einstellungen des DNS-Servers wirksam werden müssen. Dies kann 24h dauern, wodurch Zugriffe auf das alte und neue System erfolgen können. Damit dies nicht passiert, leitet das alte System auf das neue um.
Nachteil: Auch der SSH-Zugriff wird umgeleitet, sodass auf dem Altsystem nur noch per VNC-Konsole über den Host zugegriffen kann. Zudem erscheinen alle umgeleiteten Zugriffe auf dem neuen System mit der IP-Adresse des alten Systems.

pfSense – “Unable to check for updates”

pfSense auf einem Alix-Board ersetzt seit kurzem unseren Border-Router, was auch sehr gut funktioniert. Die Firewall-Distribution hat einen Auto-Updatemechanismus, welcher aber immer mit “Unable to check for updates” oder “Could not contact pfSense update server http://updates.pfsense.org/_updaters” ins Leere lief. Aus dem privaten Netzwerk war die Adresse aber ohne Probleme erreichbar. Die Lösung war schließlich die Aktivierung des DNS-Forwaders auch über das lokale Interface.

pfsense_dnsmask_localhost
Danach konnte der Update-Server problemlos gefunden werden.

Tethering und Cyanogenmod 10.1

Cyanogenmod (und wie es aussieht gibts den Bug auch unter Stock-Android) schleppt einen Bug mit sich sich rum, wodurch WLAN Thethering nicht wirklich möglich ist. Zwar können sich Geräte verbinden, bekommen dann aber keinen Internetzugriff. Die Lösung ist eine fehlende iptables-Regel.
“su -c “iptables -t nat -A natctrl_nat_POSTROUTING -s 192.168.0.0/16 -o rmnet_usb0 -j MASQUERADE”” (leicht abgewandelt für das Nexus 4, die Schnittstelle heißt hier anders, von hier: http://code.google.com/p/android/issues/detail?id=38563#c122)
im Terminal ausgeführt löst das Problem. Ich lasse den Befehl regelmäßig von Tasker aufführen, sonst vergesse ich das garantiert ;-).

Ich grabe einen Tunnel

Befindet man sich in unsicheren Netzwerken (öffentliche Netzwerke, z.B. an einer Uni, öffentliche WLANs…) so muss man ziemlich aufpassen, da man nie wirklich weiß, ob sich nicht doch jemand mit bösen Absichten im Netz befindet. So ein Man-in-the-middle Angriff mit ARP-Spoofing ist mit den richtigen Tools schnell und unbemerkt durchgeführt. So kann man den Traffic von allen Rechnern im Netz scannen und interessantes wie Passwörter herausfiltern. Selbst SSL-Verbindungen sind angreifbar. Zwar gibt es deutliche Anzeichen für Angriffe, wie z.B. gemeldete, fehlerhafte Zertifikate durch den Browser o.ä., allerdings werden diese von den meisten Nutzern blind abgenickt. Ein schwerer Fehler, denn dann ist auch die eigentlich sichere SSL-Verbindung gekapert und kann mitgelesen werden. Oder die SSL-Verbindung wird auf dem Weg zum Zielrechner einfach komplett entfernt, die Warnung wegen eines falschen Zertifikats entfällt. Nur wer aufmerksam ist wird vielleicht merken, dass er die eigentlich per SSL geschützte Seite über eine normale HTTP-Verbindung aufruft.
Ein relativ wirksames Mittel gegen solche Manipulationen ist die Tunnelung des Traffics zu einem vertrauenswürdigen Netz. Dies kann beispielsweise ein Server im Internet oder gar das eigene Heimnetzwerk sein. Doch wie bekommt man seine Daten sicher aus dem unsicheren Netz heraus? Dafür bietet sich ein VPN-Tunnel an, welcher Datenverbindungen verschlüsseln und auch umleiten kann. Im Prinzip kann man sich ein VPN wie ein eigenes, kleines sicheres Netzwerk vorstellen, welches über andere, unsichere, Netzwerke aufgespannt ist. Gut, die Konstellation heißt vielleicht nicht umsonst Virtual Private Network ;-) Mitglieder in diesem virtuellen Netzwerk können sich untereinander sehen, als würden sie sich in einem physikalischen Netzwerk befinden.
Um ein VPN als sicheren Tunnel gegen dubiose Netzwerke zu nutzen, muss zunächst ein Endpunkt (also da, über welche Internetverbindung man schließlich ins Internet gehen will, z.B. im Heimnetzwerk) mit VPN-Server verfügbar sein. Hierfür bietet sich OpenVPN an, da es relativ einfach zu konfigurieren ist (als beispielsweise IPSec) und eine hohe Sicherheit bietet (von einem PPTP-VPN sieht man besser ab).
Ist OpenVPN installiert geht es an die Konfiguration. Dazu stellt man im Ordner /etc/openvpn/ (Unter Linux, unter Windows sind die Pfade anders) eine Konfigurationsdatei server.conf o.ä..
Diese sieht wie folgt aus:

mode server #Starte OpenVPN als Server
tls-server
script-security 2
server 192.168.23.0 255.255.255.0 #Definiert VPN-Adressbereich
persist-key
persist-tun
user openvpn
group openvpn
push "route 192.168.23.0 255.255.255.0" #Setzt Route zum angegeben Netz am Client
route 192.168.23.0 255.255.255.0
push "redirect gateway def1" #Leitet Traffic zum Server
client-to-client #Clients im VPN-Netzwerk können sich untereinander sehen
float
dev tun
proto udp
port 1194
keepalive 10 300
dh /etc/openvpn/easy-rsa/keys/dh1024.pem 
ca /etc/openvpn/easy-rsa/keys/ca.crt #Pfade zu den TLS-Zertifikaten
cert /etc/openvpn/easy-rsa/keys/server.crt
key /etc/openvpn/easy-rsa/keys/server.key
verb 4

Als nächstes müssen Zertifikate erzeugt werden – wie das geht steht hier: http://wiki.openvpn.eu/index.php/Erzeugen_einer_PKI_mit_EasyRSA

Damit der Server den ankommenden Traffic auch weiterleiten kann, muss noch ein bisschen am System geschraubt werden. Zunächst muss über eine iptables-Regel die Weiterleitung aus dem VPN-Netz an das Standardinterface erlaubt werden:
iptables -t nat -A POSTROUTING -s 192.168.23.0/24 -o eth0 -j MASQUERADE
Als nächstes wird die Weiterleitung von Datenpaketen mit echo "1" > /proc/sys/net/ipv4/ip_forward aktiviert. Diese Einstellunen sind allerdings nicht persistent, bei einem Neustart werden die Einträge wieder zurückgesetzt. Damit ein Reboot überlebt wird, muss net.ipv4.ip_forward=1 in der Datei /etc/sysctl.conf gesetzt sein. Alternativ können die Befehle auch in bei Systemstart z.b. über rc.local aktiviert werden (das ist aber irgendwie nicht so schön ;-)).
Wann nach oben verlinkter Anleitung alle Zertifikate generiert wurden, können diese an den Clients eingerichtet werden. Unter Linux geht dies bequem über den Netzwerkmanager, wie es unter Windows aussieht, keine Ahnung – das habe ich noch nicht probiert ;-)
Unter Android kann die Verbindung auch genutzt werden.
Dazu ist eine Konfigurationsdatei erforderlich, bei mir sieht sie wie folgt aus:

remote $Adresse-zum-VPN-Server 1194
client 
dev tun
proto udp
resolv-retry infinite 
nobind 
persist-key 
persist-tun 
float 
tls-client
ca $Zertifikat-der-CA
cert $Zertifikat
key $Key
Screenshot_2013-07-14-10-22-17
OpenVPN für Android, Routing

Diese wird in “OpenVPN für Android” importiert. Unter “Routing” muss dann noch das Häkchen zur Weiterleitung des Traffics über die VPN-Verbindung gesetzt werden (siehe Screenshot links).
Ob der Tunnel funktioniert kann über Webseiten wie http://browserspy.dk/ip.php überprüft werden. Dazu besucht man die Webseite einmal mit aktivierten und einmal mit deaktiviertem VPN. Sind beide IPs unterschiedlich, so funktioniert der Tunnel und der Traffic wird darüber weitergeleitet. Angriffe von den darunter liegenden Netzwerken sind somit nicht mehr möglich. Als nettes Nebenfeature ist dort auch nur noch die VPN-Verbindung sichtbar, alles andere ist unsichtbar.

Bastelstunde: Der eigene DynDNS-Dienst

Seit, ich glaube 2007, war ich Nutzer des DynDNS-Dienstes des gleichnamigen Anbieters. Auf die Arbeitsweise von DynDNS will ich hier nicht genauer eingehen, da verweise ich lieber auf den entsprechenden Wikipedia-Eintrag: http://de.wikipedia.org/wiki/Dynamisches_DNS
In Kürze: wie bei statischem DNS wird hier ein Hostname einer IP zugeordnet, nur mit dem Unterschied, dass die IP dynamisch ist und sich jederzeit ändern kann.
Bis vor kurzem musste sich die IP-Adresse zu einem Hostnamen mindestens einmal im Monat ändern, damit der Eintrag aktiv blieb. Seit neustem reicht dies aber nicht mehr: Nun muss man sich mindestens einmal im Monat über die Webseite einloggen, sonst wird der komplette Account gelöscht. Alternativ hat man die Möglichkeit auf “Dyn Pro” umzusteigen, für 10 USD im ersten Jahr, danach 25 USD – für mich also keine wirkliche Option. Also mussten weitere Alternativen her.
Möglichkeit 1: no-ip.com – hier muss im Moment nur die IP mindestens 1x alle 30 Tage aktualisiert werden, aber wer weiß wann man auch hier sich 1x aktive einloggen muss.
Möglichkeit 2: Die Do-It-Yourself Methode. Etwas umständlich, aber dafür hat man den Kram komplett unter der eigenen Kontrolle.
Und um Möglichkeit 2 geht es jetzt hier.
Was man benötigt:
– Linux-Kenntnisse
– einen vServer/root-Server
– eine Domain
– einen Nameserver, dem man neue Tricks beibringen kann ;-)

Grundlage meiner Basteleien war folgende Anleitung, welche ich zum Teil abgewandelt habe: http://andrwe.org/linux/own-ddns.
Umgesetzt habe ich sie unter Debian 7 mit Bind9.
Zuerst habe ich den TSIG-Key über
dnssec-keygen -a hmac-sha256 -b 256 -n HOST dyndns.johnassel.de
generiert und unter /etc/bind abgelegt. Der wichtige Teil liegt in der erzeugten .private Datei: Über den dort hinterlegten Key wird es später möglich sein, die DNS-Einträge zu aktualisieren. Dafür habe ich in /etc/bind/named.conf.default-zones die folgenden beiden Einträge hinzugefügt:

key dyndns.johnassel.de. {
algorithm HMAC-SHA256;
secret "generierterganzgeheimerKey";
//Festlegung des Schlüssel, über welchen man sich authentifiziert um die Einträge für die Subdomain ändern zu können
};
zone "dyndns.johnassel.de" {
type master;
file "/var/cache/bind/zones/johnassel.de.zone"; //Definition der Zonen-Datei
allow-update {
key dyndns.johnassel.de.; //Verweis auf den Key
};
};

Jetzt weiß der Nameserver, dass er für die Zone “dyndns.johnassel.de” zuständig ist.
Damit Hostnamen auch IP-Adressen zugeordnet werden können, muss die oben definierte Zonendatei angelegt werden:

$ORIGIN .
$TTL 300 ; 5 minutes
dyndns.johnassel.de IN SOA ns.johnassel.de. root.johnassel.de. (
2013051307 ; serial
3600 ; refresh (1 hour)
1800 ; retry (30 minutes)
604800 ; expire (1 week)
1800 ; minimum (30 minutes)
)
NS ns.johnassel.de.
$ORIGIN dyndns.johnassel.de.

Da es sich hier um dynamische DNS-Einträge handeln wird, habe ich die TTL-auf 5 Minuten gesetzt. Bei den üblichen 24 Stunden müsste man im schlechtesten Fall einen Tag warten, bis IP-Änderungen der dynamischen Hosts wirksam werden – was doch sehr unpraktisch ist ;-)
Theoretisch wäre es möglich, die Zone-File schon mit Einträgen zu füllen. Allerdings wären diese dann statisch und würden bei einer Änderung der IP-Adresse des DynDNS-Clients ins Leer führen.
Also muss noch etwas Dynamik in die Sache gebracht werden.
Dafür kommt folgendes PHP-Script zum Einsatz:


<?php
$ip = $_SERVER['REMOTE_ADDR'];
shell_exec("/usr/bin/nsupdate -k /etc/bind/Kdyndns.johnassel.de.*.private <<EOF
server localhost
zone dyndns.johnassel.de
update delete home.dyndns.johnassel.de A
update add home.dyndns.johnassel.de 300 A $ip
send
EOF
");
shell_exec("/usr/sbin/rndc reload");
print("updated home.dyndns.johnassel.de to $ip" . PHP_EOL);
?>

Dieses wird irgendwo auf dem Webserver (welcher auf der gleichen Maschine laufen muss, auf welchem der DNS-Server läuft) abgelegt. Wird das Script nun abgerufen, so wird für den Eintrag “home.dyndns.johnassel.de” die aufrufende IP gesetzt. Damit der Vorgang auch automagisch abläuft, habe ich auf meinem Homeserver einen cronjob eingerichtet, welcher das Scipt jede Minute abruft.

*/1 * * * * wget --http-user="home" --http-passwd="geheimsageichnicht" http://url/zum/php/script > /dev/null

Damit nicht jeder die IP-Adresse ändern kann, empfiehlt es sich das Script per .htaccess und .htpasswd zu schützen, optimalerweise über eine SSL-gesicherte Verbindung, da sonst das Passwort im Klartext übertragen wird (unschön, macht man nicht ;-))

Jetzt fehlt nur noch eine Sache: Die Delegation der Namensauflösung der Subdomain auf den gerade konfigurierten DNS-Server.
Dies muss am Nameserver geschehen, der die Domain (in meinem Fall johnassel.de) verwaltet. Über die Einträge
dyndns 300 IN NS ns.johnassel.de.
und
ns A 46.38.242.191
wird die Delegation realisiert.
Anschließend sollten die DynDNS-Clients über ihre Adresse erreichbar sein.
Möchte man weitere Clients hinzufügen, so reicht es das obige PHP-Script zu kopieren und entsprechend anzupassen.
Im Prinzip ganz einfach, oder? ;-)