Projekt: Fitlet-XA10 als Linux Router

0

Das Ziel war, einen Router für ein Kabelmodem auf Basis von Debian 8 mit mindestens drei, für Endgeräte nutzbaren, Gigabit LAN-Anschlüssen, sowie einer WLAN Karte für einen AccessPoint zu bauen. Bei der Auswahl der Hardware war wichtig, dass neben den Gigabit Netzwerkanschlüssen auch noch mindestens zwei USB 3.0 Anschlüsse vorhanden sind, um gegebenenfalls per USB weitere Gigabit LAN-Anschlüsse einrichten zu können. Die CPU sollte über genug Leistung verfügen, um das Routing, die Firewall mittels iptables, sowie einen VPN Tunnel stemmen zu können. Für den VPN-Tunnel ist es sinnvoll, dass die CPU über eine AES Erweiterung verfügt, um bei der Ver- und Entschlüsselung des Datenverkehrs keine zu großen Latenzen zu produzieren.

Softwaretechnisch waren die Anforderungen:

  • Der Betrieb eines DHCP-Servers sowie eines DNS-Servers mit DNS-Zone für das lokale Netzwerk (home.local), in der sich alle Geräte mit Hostnamen und IP registrieren sollen.
  • Das Aufspannen eines WLAN Netzwerkes
  • Der Aufbau einer VPN-Verbindung beim starten des Gerätes um den gesamten Netzwerkverkehr ausgenommen einiger Geräte über den VPN-Tunnel zu routen
  • Das zusammenschließen der drei Gigabit-Anschlüsse mit dem WLAN zu einer Bridge um die Kommunikation der Geräte untereinander zu ermöglichen.
  • Die Installation eines UPnP-Dienstes um die Firewallanpassung seitens der Endgeräte zu ermöglichen.

Letztendlich sollte das ganze System so robust sein, dass ein abruptes Trennen des Gerätes vom Strom nicht zu konsistenz Problemen auf dem Datenträger führt. Die nachfolgende Anleitung habe ich auf Basis meiner Notizen aus der Einrichtungsphase des Routers nachträglich erstellt. Sollten also kleine Zwischenschritte fehlen, wie das setzten von Rechten, so bitte ich das zu entschuldigen. Es kann gerne die Kommentarfunktion verwendet werden, um darauf hinzuweisen.

Router Komponenten

Hardware

Der Fitlet XA-10 ist ein lüfterloser Mini-PC, der technisch aus:

  • einem 4-Kern AMD A10 Micro-6700T Prozessor mit AES Erweiterung
  • 4x GbE LAN Anschlüsse
  • 2x USB 3.0 Anschlüsse
  • 3x USB 2.0 Anschlüsse
  • 2x HDMI Ausgängen (AMD Radeon R6 Graphics)
  • 1x Full-size mSATA Steckplatz
  • 1x SO-DIMM 204-pin DDR3 SDRAM Speicher Steckplatz, der bis zu 8 GB Ram unterstützt
  • 1x Audio (Realtek ALC886)
fitlet_x_-_two_pcs_1_1 fitlet_-_port_diagram

 

WLAN

Software

Als Software würde die nachfolgende in Debian 8 bereits enthaltene Standard-Software verwendet:

  • Bind9 (1.9) als DNS-Server
  • ISC-DHCP-Server (4.3) als DHCP-Server
  • OpenVPN (2.3) als VPN-Client
  • Linux-IGD (1.0) als UPnP-Daemon
  • Hostapd (1.2) als WLAN AccessPoint
  • SystemD als init-Daemon

Installation

Installation des Grundsystems

Bei der Installation des Fitlet habe ich die Erweiterungskarte für die Dauer der Installation entfernt, da ansonsten der einzelne LAN Anschluss auf der Rückseite nicht eth0 erkannt worden wäre, was ich jedoch wollte, um eth1-eth3 später als bridge verwenden zu können. Wer die Karte nicht ausbauen möchte, kann später in der Datei /etc/udev/rules.d/10-network.rules die Namen der Schnittstellen auch nachträglich ändern.

Partitionierung

Prinzipiell lässt sich mit ein paar kleinen Änderungen ein ganzes Linux System im read-only Modus betreiben. Die Ordner, welche zwingend beschreibbar sein müssen, können in eine Ramdisk ausgelagert werden. Dies hat den Vorteil, dass ein abrupter Stromverust die für den Betrieb wichtige Datenstruktur nicht beschädigen kann, jedoch das auch alle Log-Dateien oder Statistiken zur Schnittstellennutzung verloren. Da ich letztere jedoch behalten möchte, habe ich mich für folgende Partitionierung entschieden.

Mount Punkt Größe später RW/RO Kommentar
/ 5 GB RO Root Partition
/var/log 5 GB RW Log-Dateien
/var/lib 2,5 GB RW Schnittstellenstatistik und DHCP-Lease Informatonen
/root 5 GB RO Skripte etc.
       
/var/cache/apt/ dynamisch,  da Ramdisk RW Paketinformationen für
apt-get
/var/cache/bind/ dynamisch,  da Ramdisk RW Schreibbare DNS Zonendatei
/backup/ dynamisch,  da Ramdisk RW tägliches Backup welches per FTP gesichert wird.
 

 

Softwareauswahl

Die Installation des Grundsystems erfolgte anhand der aktuellen Debian Version 8.1.0 von CD. Es wurde im Experten-Modus nur das minimal-System installiert, also bei der Software-Auswahl alles abgewählt.

debinstsoftware

Während der Installation kann die Schnittstelle eth0, die sich auf der Rückseite des Gerätes befindet, einfach mit dem bereits vorhandenen LAN verbunden werden und im Verlaufe der Installation mittels DHCP eingerichtet werden. Wenn später das Kabel-Modem an eth0 angeschlossen wird (Crossover-Kabel notwendig), bekommt die Schnittstelle die öffentliche IP-Adresse ebenfalls per DHCP zugewiesen. Es muss später also nichts mehr an der Konfiguration von eth0 geändert werden.

Nach Abschluss der Installation habe ich noch einige Pakete nachinstalliert, welche zum späteren Betrieb beziehungsweise der Administration benötig werden.

apt-get install ssh htop ftp dnsutils screen vim cpufrequtils openvpn hostapd isc-dhcp-server bind9 linux-igd sudo apt-file locate iw firmware-ralink bridge-utils sysfsutils lsof vnstat iptraf nload firmware-linux-nonfree ncftp bash-completion unattended-upgrades psmisc openvpn whois lm-sensors linux-igd

Systemd Bild-Reset nach Boot verhindern

Sobald Debian 8 mit Systemd gebootet ist, wird der Bildschirminhalt resettet, so dass nur noch der Prompt zu sehen ist und alle vorherhigen Boot-Meldungen verschwinden. Mittels dmesg kann man sich zwar den Bootverlauf wieder anzeigen lassen, jedoch ist dies nicht die gleiche Darstellung wie im Boot-Bildschirm, was die Suche nach einer beim booten wahrgenommenen Meldung unnötig erschwert.

Um bei späteren Einrichtung Boot-Meldungen in Ruhe lesen zu können, wurde das Löschen der Meldungen nach dem Boot, wie hier gefunden, abgeschaltet.

mkdir -pv /etc/systemd/system/getty@tty1.service.d

cat > /etc/systemd/system/getty@tty1.service.d/noclear.conf << EOF
[Service]
TTYVTDisallocate=no
EOF

DNS-Server einrichten

Nach der Installation des Bind9 Paketes ist der DNS-Server selber schon Einsatzbereit. Damit der DHCP-Server die gleich anzulegende die DNS-Zone später auch aktualisieren kann, muss dafür eine key (rndc.key) erstellt werden.

rndc-confgen -a

Nun kann die DNS-Zone home.local sowie eine Reverse-Zone eingerichtet werden. Dazu werden einmal die nachfolgend verlinkten DNS-Zonen unter /etc/bind/ abgelegt und anschließend die /etc/bind/named.conf angepasst. Hierbei wird direkt der rndc.key mit eingebunden.

# /etc/bind/named.conf

include "/etc/bind/rndc.key";

zone "home.local" IN {
        type master;
        file "home.local.zone";
        allow-query { any; };
        allow-update { key rndc-key; };
};

zone "10.168.192.in-addr.arpa" IN {
        type master;
        file "10.168.192.in-addr.arpa";
        allow-query { any; };
        allow-update { key rndc-key; };

};

Abschließend den DNS-Dienst neustarten und dem Router mitteilen, dass von nun an der lokale DNS-Server verwenden soll (etc/resolv.conf). Zusätzlich wird die /etc/resolv.conf noch vor Veränderungen geschützt.

systemctl restart isc-dhcpserver

echo "nameserver 127.0.0.1" > /etc/resolv.conf

chattr +i /etc/resolv.conf

DHCP-Server einrichten

Für die Einrichtung des DHCP-Servers wird in der Datei /etc/dhcp/dhcpd.conf der DHCP-Bereich definiert, aus welchem die Clients später ihre IP-Adresse zugewiesen bekommen. An der markierten Stelle muss der Inhalt der Datei rndc.key eingefügt werden. Theoretisch kann der Key auch durch die Direktive include "/etc/bind/rndc.key"; eingebunden werden, jedoch funktionierte dies bei mir nicht.

log-facility local7;

option netbios-node-type 8;
option netbios-name-servers 192.168.10.1;
ddns-update-style interim;
ddns-updates on;
allow unknown-clients;
use-host-decl-names on;
ddns-domainname "home.local";
update-static-leases on;
key "rndc-key" {
 [...]
};

zone home.local. {
 primary 192.168.10.1;
 key rndc-key;
}

zone 10.168.192.in-addr.arpa. {
 primary 192.168.10.1;
 key rndc-key;
}

authoritative;
default-lease-time 600;
max-lease-time 7200;

subnet 192.168.10.0 netmask 255.255.255.0 {
 option domain-name-servers 192.168.10.1;
 option domain-name "home.local";
 ddns-domainname "home.local";
 ddns-rev-domainname "in-addr.arpa.";
 option broadcast-address 192.168.10.255;
 option routers 192.168.10.1;
 range 192.168.10.100 192.168.10.150;
}

Abschließend einmal den DHCP Dienst durchstarten.

systemctl restart isc-dhcp-server

Um sich die aktuelle vergebenen Leases anzeigen zu lassen, gibt es den Befehl dhcp-lease-list. Dieser funktioniert in der Konfiguration jedoch nicht, da er die Datei für die Leases (dhclient.leases) unter /var/db erwartet, die jedoch unter /var/lib/dhcpd liegt. Das lässt sich aber durch eine Verlinkung beheben.

mkdir /var/db
ln -s /var/lib/dhcp/dhclient.leases /var/db/dhcpd.leases

dhcp-lease-list

Bridge einrichten

Nachdem nun der DNS- sowie DHCP-Server laufen, kann die Bridge für die Netzwerkschnittstellen eth1 bis eth3 eingerichtet werden. Hierzu sind folgende Einträge in der /etc/network/interfaces notwendig. Die Paremter dazu können in der manpage nachgelesen werden.

Die wlan0 Schnittstelle wird später über hostapd automatisch hinzugefügt.

# /etc/network/interfaces


auto eth1
iface eth1 inet manual
        up ifconfig eth1 up promisc
        down ifconfig eth1 down -promisc

auto eth2
iface eth2 inet manual
        up ifconfig eth2 up promisc
        down ifconfig eth2 down -promisc

auto eth3
iface eth3 inet manual
        up ifconfig eth3 up promisc
        down ifconfig eth3 down -promisc

auto wlan0
iface wlan0 inet manual

# Bridge setup
auto br0
iface br0 inet static
        bridge_ports eth1 eth2 eth3 wlan0
        bridge_waitport 0
        bridge_fd 0
        bridge_hello 0
        address 192.168.10.1
        broadcast 192.168.10.255
        netmask 255.255.255.0
        gateway 192.168.10.1

Damit das Routing sauber funktioniert wird ipv6 deaktiviert, der Bridge erlaubt auf den entsprechenden Interfaces als Arp-Proxy zu fungieren, sowie die Weiterleitung der IP Pakete aktiviert.

echo "# Disable IPv6"
echo net.ipv6.conf.all.disable_ipv6 = 1 >> /etc/sysctl.conf
echo >> /etc/sysctl.conf

echo "# Allow Router to act as ARP Proxy"
echo net.ipv4.conf.all.proxy_arp=1 >> /etc/sysctl.conf
echo net.ipv4.conf.wlan0.proxy_arp=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth1.proxy_arp=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth2.proxy_arp=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth3.proxy_arp=1 >> /etc/sysctl.conf
echo >> /etc/sysctl.conf

echo "# Enable forwarding on all interfaces"
echo net.ipv4.ip_forward = 1 >> /etc/sysctl.conf
echo net.ipv4.conf.wlan0.forwarding=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth1.forwarding=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth2.forwarding=1 >> /etc/sysctl.conf
echo net.ipv4.conf.eth3.forwarding=1 >> /etc/sysctl.conf

Nun die Änderungen noch aktivieren:

sysctl -p

Damit der DHCP-Dienst nun auch auf der Bridge (br0) auf DHCP-Anfragen lauscht, muss in der Datei /etc/default/isc-dhcp-server noch eine Zuweisung an br0 erfolgen.

/etc/default/isc-dhcp-server
INTERFACES="br0"

Nach den Änderungen besten einmal den Router neustarten.

AccessPoint einrichten

Um den AccessPoint zu betreiben wurde am Anfang schon das Treiberpaket firmware-ralink mit installiert. Über der /etc/network/interfaces wird die Schnittstelle wlan0 auch bereits aktiviert. Jetzt kommt noch hostapd als AccessPoint oben drauf. Dazu muss die Konfigurationsdatei /etc/hostapd/hostapd.conf angepasst werden. Die SSID, sowie das WLAN-PASSWORT müssen bitte individuell gesetzt werden. Der Parameter bridge= veranlasst hostapd beim starten wlan0 automatisch zur Bridge br0 hinzuzufügen.

/etc/hostapd/hostapd.conf

interface=wlan0
driver=nl80211
bridge=br0
ssid=<SSID>
auth_algs=1
channel=3

country_code=OB

#  yes, it says 802.11g, but the n-speeds get layered on top of it
hw_mode=g

#  this enables the 802.11n speeds and capabilities ...  You will also need to enable WMM for full HT functionality.
ieee80211n=1
wmm_enabled=1

eap_reauth_period=360000000

wpa=0
ignore_broadcast_ssid=0
wpa=3
wpa_passphrase=<WLAN-PASSWORT>
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP

Da hostapd leider keine Service-Unit für systemd mitliefert, muss diese manuell erstellt werden. Dazu wird die Datei /etc/systemd/system/hostapd.service mit folgendem Inhalt angelegt.

/etc/systemd/system/hostapd.service

[Unit]
Description=Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
Wants=network.target

BindsTo=sys-subsystem-net-devices-wlan0.device
After=sys-subsystem-net-devices-wlan0.device isc-dhcp-server.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/hostapd -B /etc/hostapd/hostapd.conf -P /var/run/hostapd.pid
ExecStart=/sbin/iptables --append FORWARD --in-interface wlan0 -j ACCEPT
ExecStop=/usr/bin/killall -9 hostapd

[Install]
WantedBy=multi-user.target

Anschließend hostapd systemd einmal die Konfiguration neu einlesen lassen, hotsapd als Start-Dienst aktivieren und den Dienst händisch starten.

systemctl daemon-reload
systemctl enable hostapd
systemctl restart hotsapd

Dateisystem durch Read-Only schützen

Eines vorweg: Man kann das Dateisystem später im laufenden Betrieb problemlos wieder als RW mounten. Also nicht nervös werden, wenn das System später startet und nichts mehr geschrieben werden kann. Der Befehl dazu lautet:

mount - / -oremount,rw

/etc/fstab anpassen

Um das Dateisystem zu schützen, müssen in der Datei /etc/fstab die read-only zu mountenden Partition einige Parameter ergänzt werden. Zusätzlich werden /var/log und /var/lib/ abgesichert, da diese beiden Ordner die einzigen beschreibbaren auf der Festplatte sind.

# <file system>    <mount point>     <type>    <options>                                        <dump>  <pass>
/dev/sda1          /                 ext4      defaults,ro,errors=remount-ro                    0       1
/dev/sda8          /root             ext4      defaults,ro,errors=remount-ro                    0       2
/dev/sda6          /var/log          ext4     defaults,nodiratime,noatime,nodev,nosuid,noexec   0       2
/dev/sda7          /var/lib          ext4     defaults,nodiratime,noatime,nodev,nosuid          0       2

/var/lib: Hier legen vnstat und der DHCP-Server Informationen über den Trafficverbrauch bzw. die aktuellen DHCP Leases ab. Ohne Schreibrechte wäre beides nicht möglich.

Darüber hinaus müssen einige Teile des Dateisystems beschreibbar sein und werden daher über eine Ramdisk eingebunden.

# <file system>    <mount point>     <type>    <options>                                        <dump>  <pass>
tmpfs              /var/cache/bind/  tmpfs     defaults,noexec,noatime,mode=0755                0       0
tmpfs              /backup/          tmpfs     defaults,noexec,noatime,mode=0755                0       0
tmpfs              /var/cache/apt/   tmpfs     defaults,noexec,noatime,mode=0755                0       0

/var/cache/bind/: Hintergrund ist, dass Bind9 nach der Vergabe einer IP Adresse mittels DHCP den neuen Host in die DNS-Zonendatei eintragen können muss. Die Original Zonen-Datei kann weiterhin unter /etc/bind/ liegen bleiben. Sie wird später beim Start nach /var/cache/bind/ umkopiert. Dieses Vorgehen hat für die DNS-Zonen den Vorteil, dass durch jeden Reboot wieder eine saubere Zone ohne jegliche Einträge geladen wird. Da nach einem Neustart der DHCP-Client die leases der Clients erneuert, werden auch automatisch alle eingeschalteten Clients wieder in der Zone registriert.

/backup: Hier schreibe ich später meine täglichen Konfigurationsbackups hin, welche auch keinen Neustart überleben müssen, da es per FTP weg kopiert wird.

/var/cache/apt: Um später updates installieren zu können, wird dieser Ordner auch in eine Ramdisk ausgelagert. Hier legt apt-cache seine Repository Informationen ab. Wer jetzt denke "Read-Only und Updates, wie passt das zusammen?" … kommt noch 😉

Anschließend noch das Swapping verhindern:

echo >> /etc/sysctl.conf
echo "# Disable swapping"
echo vm.swappiness=0 >> /etc/sysctl.conf
echo >> /etc/sysctl.conf

sysctl -p

ramdisk.service anlegen

Jetzt wird ein systemd service angelegt, welcher bei einem starten des Systems einige Dateien in die Ramdisk Ordner kopiert.

/etc/systemd/system/ramdisk.service

[Unit]
Description=Copy necesarry files into ramdisk
Wants=tmp.mount
After=tmp.mount
Before=bind9.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/cp /etc/bind/managed-keys.bind /var/cache/bind/
ExecStart=/bin/cp /etc/bind/10.168.192.in-addr.arpa /var/cache/bind/
ExecStart=/bin/cp /etc/bind/home.local.zone /var/cache/bind/
ExecStart=/bin/chown bind:bind /var/cache/bind/ -R

[Install]
WantedBy=local-fs.target

Da die Anleitung aufeinander aufbaut, muss jetzt in der der Datei /etc/bind/named.conf der Pfad zu den DNS-Zonen home.local.zone sowie 10.168.192.in-addr.arpa vollqualifiziert angegeben werden. Abschließend noch den Dienst aktivieren.

systemctl enable ramdisk.service

.viminfo anpassen

Wird vim später auf einem read-only System verwendet, wodurch auch das Homeverzeichnis geschützt wird, wirft vim folgende Fehlermeldung

E886: Can't rename viminfo file to ~/.viminfo!

Dem kann entgegen gewirkt werden:

set viminfo="NONE"

.bashrc anpassen

Die bash kann, insofern konfiguriert, eine Historie der zuletzt verwendeten Befehle führen. Auf einem read-only geschützten Dateisystem wird dies schwierig und die bash wirft daher ebenfalls beim starten einen Fehler. Aus diesem Grund sollte die bash Historie deaktiviert werden.

~/.bashrc

export HISTFILE=/dev/null

apt-get read-only anpassen

Auch wenn das Root-Dateisystem beim starte read-only gemountet wird, kann apt-get dennoch so angepasst werden, dass es wie immer verwendet werden kann. Wie hier beschrieben muss dazu nur die Datei /etc/apt/apt.conf mit folgendem Inhalt angelegt werden:

/etc/apt/apt.conf

DPkg {
    // Auto re-mounting of a readonly /
    Pre-Invoke { "mount -o remount,rw /"; };
    Post-Invoke { "test ${NO_APT_REMOUNT:-no} = yes || mount -o remount,ro / || true"; };
};

Hinweis zum random-seed.service

Wie hier beschrieben ist die Generierung von qualitativer Entropie sehr schwierig und braucht seine Zeit. Entropie wird jedoch zum Beispiel bei VPN-Verbindungen oder der Schlüsselerstellung benötigt. Um beim starten eines Linux Systems nicht erst aufwendig Zufallszahlen generieren zu müssen, speichert der random-seed.service diese beim herunterfahren. Im read-only Modus wird dies jedoch scheitern. Beim nächsten starten kann der Dienst die Datei /var/lib/systemd/random-seed nicht laden und wirft den Fehler:

Failed to start Load/Save Random Seed

Leider ist es mir weder gelungen den Dienst zu deaktiviern, noch durch das umkopieren der Datei beim starten und herunterfahren den Dienst zufrieden zu stellen. Dies nur als Hinweis für die auftauchende Fehlermeldung.

# ln -s /var/log/random-seed /var/lib/systemd/random-seed
# systemctl disable systemd-random-seed

Ob die Installation des haveged sich positiv auf die Generierung von Entropie auswirkt, kann ich nicht sagen, da ich mir die Arbeitsweise von haveged im Detail nicht angeschaut habe. Es könnte jedoch eine Option sein.

OpenVPN Einrichten

Ich möchte hier nicht beschreiben, wie OpenVPN in gänze einzurichten ist, sondern beschränke mich auf einige Anpassungen, welche ich an der OpenVPN Konfiguration gemacht habe.

DNS-Server nicht per DHCP beziehen

Per DHCP wird der Schnittstelle eth0 nicht nur eine IP Adressen, sondern auch der DNS-Server des Modems mitgeteilt. Dieses Verhalten wird deaktiviert, da auf dem Router ein eigene DNS-Server läuft, welcher verwendet werden soll.

/etc/dhcp/dhclient-enter-hooks.d/nodnsupdate
make_resolv_conf() {
        true
}

Systemd Service anlegen

Die erste Änderung ist, dass ich für Systemd eine eigene OpenVPN Service-Datei angelegt habe. OpenVPN startet sobald das Netzwerk als auch der DHCP-Dienst am Router Einsatzbereit sind.
Über die Parameter Restart und RestartSec wird sichergestellt, dass der Dienst automatisch neustartet, sollte er unerwartet beendet werden. –script-security ermöglicht das ausführen von Skripten beim Auf- und Abbau der VPN-Verbindung.

[Unit]
Description=OpenVPN
After=network.target bind9.service
Requires=networking.service bind9.service

[Service]
Type=forking
PIDFile=/var/run/openvpn.pid
ExecStart=/usr/sbin/openvpn --daemon --writepid /var/run/openvpn.pid --log-append /var/log/openvpn.log --script-security 2 --up /etc/openvpn/tun0-up.sh --down /etc/openvpn/tun0-down.sh --cd /etc/openvpn/vpn-config-folger --config /etc/openvpn/vpn-config-colder/vpn-config.ovpn
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=always
RestartSec=30
KillSignal=SIGINT

[Install]
WantedBy=multi-user.target

Die Service-Datei muss anschließend eingelesen und OpenVPN aktiviert werden.

systemctl daemon-reload
systemctl enable openvpn

Routing nach Quell-IP

Da der gesamte Netzwerkverkehr, über den VPN-Tunnel geroutet wird, kann es bei der Verwendung von Online-Video-Diensten wie Amazon Prime zu Probleme kommen. Endet der VPN-Tunnel außerhalb von Deutschland erkennt das Amazon Prime und verweigert das Abspielen von Videos. Hier kann man entweder die Verwendung eines lokalen DNS-Servers erzwingen oder aber, was mehr Sinn macht, den gesamten Verkehr von zum Beispiel einem Amazon FireTV am VPN vorbei routen. Dazu ist ein Routing auf Basis der Quell-IP Notwendig, welche über den DHCP Server anhand einer Reservierung fixiert werden kann.

Um Quell-IP Adressen anders zu routen, als den restlichen Netzwerkverkehr muss eine eigene Routingtabelle angelegt werden, in welcher das Zielgateway angegeben werden muss. Da ein Quell-IP basiertes Routing erst durch den Aufbau einer VPN-Verbindung notwendig wird, sorgt das Skript /etc/openvpn/tun0-up.sh für deren Ausführung. Das Skript legt die Routingtabelle 1000 mit dem aktuellen Gateway (eth0) als Routingadresse an und nimmt anschließend die IP Adressen 192.168.10.251 bis 253 in die Routingliste auf. Diese Quelladresse können also trotz aktiver VPN-Verbindung direkt über den Unitymedia Anschluss raus.

#!/bin/bash

addSourceRouting() {
        if [ $(ip rule list |grep $1 -c) = 0 ]; then
                ip rule add from $1/32 table 1000
        fi
}

gateway=$(ip addr show eth0 |grep -v "eth0:"| grep "inet " | cut -d / -f 1 | awk '{print $2}')
if [ ! -z "$gateway" ]; then
        ip route del default table 1000
        ip route add default via $gateway dev eth0 table 1000
        logger "Openvpn Table 1000: new gateway $gateway"
fi

addSourceRouting 192.168.10.251
addSourceRouting 192.168.10.252
addSourceRouting 192.168.10.253

Um sich die das Source-Routing anzuschauen, können folgende Befehle verwendet werden:

# Show table informationen
ip rule list
ip route list table 1000

Routing-Anpassung bei Änderung der öffentlichen IP-Adresse

Wird nach 24 Stunden über das Unitymedia Modem dem Router eine neue IP Adresse zugewiesen, macht dies die Routingtabelle 1000 unbrauchbar. Das Problem kann gelöst werden, indem automatisch bei einer Aktualisierung der eth0 IP-Adresse durch den DHCP Client ein entsprechendes Skript ausgeführt wird. Die Lösung dazu habe ich hier gefunden.

Das Skript löscht bei einer Erneuerung der DHCP Adresse für eth0 die alte Route und definiert diese mit der neuen öffentlichen IP Adresse neu.

Es wird dazu die Datei /etc/dhcp/dhclient-exit-hooks.d/routing mit nachfolgendem Inhalt angelegt:

# /etc/dhcp/dhclient-exit-hooks.d/routing

set_routing() {
    case $reason in
        BOUND|RENEW|REBIND|REBOOT)
                gateway=$(ip addr show eth0 | grep -v "eth0:" | grep "inet " | cut -d / -f 1 | awk '{print $2}')
                if [ ! -z "$gateway" ]; then
                        ip route del default table 1000
                        ip route add default via $gateway dev eth0 table 1000
                        logger "dhclient: Table 1000 new gateway $gateway"
                fi
            ;;
        EXPIRE|FAIL|RELEASE|STOP)
                gateway=$(ip addr show eth0 | grep -v "eth0:" | grep "inet " | cut -d / -f 1 | awk '{print $2}')
                if [ ! -z "$gateway" ]; then
                        ip route del default table 1000
                        ip route add default via $gateway dev eth0 table 1000
                        logger "dhclient: Table 1000 new gateway $gateway"
                fi

            ;;
    esac
}

Massenhaft DHCPRequests

Nach der Einrichtung füllte sich das log (/var/log/syslog) nach und nach mit jeder Menge DHCPREQUEST Einträgen, welche alle vom Kabel-Modem von UnityMedia stammen.

Aug 14 15:54:47 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:55:03 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:55:12 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:55:24 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:55:35 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:55:49 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:56:10 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:56:22 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67
Aug 14 15:56:42 router dhclient: DHCPREQUEST on eth0 to 10.145.20.1 port 67

Bei der Suche nach der Ursache gab es zwei potentielle Lösungen.

  1. Das Modem schickt mit dem DHCPRequest einen Identifier, welcher fehlerhaft ist und somit eine Antwort nichz erfolgreich zugestellt werden kann (Quelle)
  2. Das Modem hat Probleme bei der Verarbeitung von Unicast Paketen (Gleiche quelle wie 1)

Es traf jedoch beides nicht zu. Die tatsächliche Ursache war, dass der UDP DHCPRequest auf dem Interface eth0 ankommt und der Router ihn aufgrund seiner Routintabelle über tun0 beantwortet. Somit erhält das Modem nie eine Antwort und stellt die Anfrage nach kurzer Zeit erneut. Die Lösung ist daher denkbar einfach. Es muss für das Modem eine dedizierte Router definiert werden. Diese kann man z.B. in der /etc/rc.local eintragen da es kein Problem darstellt, wenn die Route auch ohne VPN Verbindung gesetzt wird.

route add 10.145.20.1/32 dev eth0

Hinweis zur Wärmeentwicklung

Das Gerät wird im Betrieb sehr warm (Gehäuse 40-50° C im Normalbetrieb, CPU 65-68° C, bei 24° C Raumtemperatur), was der Hersteller aber auch in seinen FAQs erwähnt. Auch wenn sich die Anzahl der zu verwendenden Prozessoren sowie die maximale Leistungsaufnahme (1-25.000 mW) im Bios einstellen lassen, wirkt sich dies kaum auf die die Temperatur  aus.

Die CPU Temperatur kann ab Kernel 3.1.6 ausgelesen werden, dazu muss jedich lm-sensors installiert werden.

apt-get install lm-sensors

Anschließend das Modul laden und die Temperatur auslesen

$ modprobe k10temp
$ sensors
k10temp-pci-00c3
Adapter: PCI adapter
temp1:        +65.2°C  (high = +70.0°C)
                       (crit = +105.0°C, hyst = +104.0°C)

Wer möchte, dass dieses Modul beim booten direkt geladen wird, kann es unter Debian in die /etc/modules eintragen:

echo k10temp >> /etc/modules

Links

Wie im Artikel Kernel: Kernel für einzelnes System optimieren beschrieben, kann man einen Kernel für ein System individuell anpassen. Die minmal Konfiguration für Kernel 4.2.6 mit GrSecurity Erweiterung sowie Unterstützung des Logitech Unify Empfängers als des  RT5370 USB Wlan Stick auch kann hier heruntergeladen werden.

Nachtrag vom 21.09.2015: Update auf Kernel 4.1

Wer übrigens auf Debian Jessie auf den Kernel 4.1 (Neuerungen des Kernels) der Backports upgraden möchte, kann dies relativ einfach. Dazu müssen die Quelle angepasst werden und anschließend der Kernel expliziet aus der Quelle installiert werden.

/etc/apt/sources.list
deb http://ftp2.de.debian.org/debian/ jessie-backports main contrib non-free
deb-src http://ftp2.de.debian.org/debian/ jessie-backports main contrib non-free

 

apt-get update
apt-get -t jessie-backports install linux-image-amd64 -y

Die anschließende Kontrolle der sensoren fördert einen neuen Eintrag zutage, der leider nicht so aussagekräftig ist.

fam15h_power-pci-00c4
Adapter: PCI adapter
power1:           N/A  (crit =   4.54 W)

Nachtrag vom 25.11.2015: Kühlkörper

Es gibt seit kurzem Austauschgehäuse mit besseren Kühlrippen. Dies kann etwender direkt beim Hersteller oder mittlerweile auch bei Amazon bestellt werden. Der Händle CompuLab bietet dort auch die restliche verfügbare Zubehör zu Kaufe an.

In der Praxis zeigt sich, dass durch die tieferen Külrippen der Wärmeaustausch verbessert wird, so dass die Temperatur um 15-20° C auf 45-48° C im Normalbetrieb fällt.

Nachtrag vom 08.12.2015: Kernel 4.2.6 GrSecuriy

Wie im Artikel Kernel: Kernel für einzelnes System optimieren beschrieben, kann man einen Kernel für ein System individuell anpassen. Die minmal Konfiguration für Kernel 4.2.6 mit GrSecurity Erweiterung sowie Unterstützung des Logitech Unify Empfängers als des  RT5370 USB Wlan Stick auch kann hier heruntergeladen werden.

Nachtrag vom 06.12.2015: geblockte Popups automatisch schließend

Eine Änderung habe ich heute nich implementiert. Popups die per DNS geblockt sind, gehen auf, zeigen aber aufgrund des blacklistings keinen Inhalt an.
Das ganze kann man noch etwas schöner lösen. Der Trick ist, geblockte Anfrage auf den Router umzuleiten. Der Router liefert dann eine Webseite aus, die sich sofort schließt.

Ursprünglich hatte ich mich gegen eine Umleitung der geblockten Anfragen zurück auf den Router entschieden, um den Traffic zu vermeiden.

Um die Konfiguration dementsprechend anzupassen sind 5 Schritte notwendig.

Webserver installieren

apt-get install lighttpd

DNS Zone anpassen

Der DNS Server muss für jede geblocke Domain sowie alle Subdomains (*) einen A record bereitstellen, der auf ihn verweist.

/etc/bind/blacklisted.zones

     IN    A       192.168.10.1
*    IN    A       192.168.10.1
     IN    AAAA    ::1
*    IN    AAAA    ::1

 

Blockpage erstellen

Die durch die Umleitung aufgerufene Webseite soll sich sofort wieder schließen.

# /var/www/html/index.lighttpd.html

<html>
<head>
<script language="javascript" type="text/javascript">
  function closeWindow() {
  window.open('','_parent','');
  window.close();
  }
closeWindow();
</script>
</head>
<body>
</body>
</html>

Einige Firefox Versionen erlauben das automatische Schließend von Fenstern nicht. Zu Beispiel unter OpenSUSE.
Um dies zu aktivieren, muss der Wert dom.allow_scripts_to_close_windows in der about:config auf true gesetzt werden.

Webseiten Umleitung

Nun noch lighttpd mitteilen, dass alle Anfragen auf die Standard Seite umgeleitet werden sollen.

# /etc/lighttpd/lighttpd.conf

server.error-handler-404   = "/index.lighttpd.html"
url.rewrite-once = ( "^/(.*)" => "/index.html" )

 

/etc/init.d/lighttpd restart

 

Teilen.

Über den Autor

Seit der Ausbildung zum Fachinformatiker Systemintegration (2002-2005) bei der DaimlerChrysler AG, beruflich im Bereich der E-Mail Kommunikation (Exchange, Linux) sowie des ActiveDirectory, mit entsprechenden Zertifizierungen (MCSE 2003, MCITP Ent.-Admin 2008, MCSE 2012, LPIC 1-3) tätig. Abgeschlossenes Studium zum Master of Science der IT-Management an der FOM sowie zertifizierter Datenschutzbeauftragter. Aktuell im Projektmanagement tätig.

Antworten