DoT und DoH mit unbound

Schon seit längerem unterstützt unbound DoT (DNS over TLS) und DoH (DNS over HTTPS) für eingehende Anfragen von Clients.

Die Konfiguration ist in der unbound Dokumentation gut beschrieben, aber es gibt ein paar Stolperfallen.

Um DoT und DoH zu aktiveren muss, laut Dokumentation, nur ein Schlüssel mit tls-service-key, ein dazu passendes Zertifikat mit tls-service-pem und eine interface Option mit passendem Port gesetzt werden. Der Standard Port für DoT ist 853 und für DoH 443. 

Kombiniert für alle IPv4 und IPv6 Adressen auf dem System, könnte die Konfiguration so aussehen:

server:
    interface: 0.0.0.0@853
    interface: ::0@853
    interface: 0.0.0.0@443
    interface: ::0@443
    tls-service-key: "/Pfad/zum/key.pem" 
    tls-service-pem: "/Pfad/zum/cert.pem"

Die Schlüssel/Zertifikat Kombination wird immer gemeinsam für DoH und DoT verwendet und die Dateien müssen im PEM Format vorliegen. Zertifikate im DER Format müssen vorher konvertiert werden.

Wenn auf dem gleichen System bereits ein Webserver läuft, ist der Port 443 ggf. belegt. Dann kann mit https-port ein anderer Port gewählt werden.

server:
    interface: 0.0.0.0@4343 
    interface: ::0@4343 
    https-port: 4343
    tls-service-key: "/Pfad/zum/key.pem"
    tls-service-pem: "/Pfad/zum/cert.pem"

Leider funktionierte bei meiner unbound Konfiguration diese Art über die interface Optionen nicht. Wenn interface-automatic verwendet wird, müssen mit interface-automatic-ports alle Ports angegeben werden.

Für DoT und DoH kann z.B. so aussehen:

server:    
    interface-automatic: yes
    interface-automatic-ports: "53 853 4343"

    https-port: 4343
    tls-service-key: "/Pfad/zum/key.pem"
    tls-service-pem: "/Pfad/zum/cert.pem"

Die interface Optionen müssen nicht mehr verwendet werden. Wenn für DoH ein anderer Port als 443 benutzt werden soll, muss es immer noch mit https-port definiert werden.

In Firefox  kann nun eine benutzerdefinierte DoH Adresse eingetragen werden. Firefox unterstützt von Port 443 abweichende benutzerdefinierte Ports.

Die URL für vom Standard abweichende Ports folgt diesem Muster:  https://example.org:4343/dns-query

Ein großer Nachteil von DoH und auch in Teilen von DoT ist die Geschwindigkeit. Wenn eine Adresse bereits im Cache von unbound ist, dauert eine Abfrage auf dem alten Weg per UDP in meinem lokalem Netzwerk im Durchschnitt etwa 2 ms. Mit DoH dauert es im Durchschnitt etwa 50 ms. Aus dem Internet heraus wird es etwas besser, da sich an den 50 ms für DoH nicht viel ändert, der Weg über unverschlüsseltes UDP aber auf etwa 25 ms  klettert.  Allerdings schwanken die Zugriffszeiten aus dem Internet stark und sind  sehr abhängig in welchen Netzen sich Server und Client gerade befinden.

Debian-Pakete – control und data mit xz anstatt zstd komprimieren

Wenn unter Ubuntu 22.04 LTS (Jammy Jellyfish) Pakete mit dpkg-deb erstellt werden, werden die im DEB-Paket enthaltenden control und data Archive mit Zstandard (zstd) komprimiert. In vorherigen LTS Versionen von Ubuntu, waren diese Archive mit xz komprimiert.

Grundsätzlich ist Zstandard ein sehr guter Datenkompressionsalgorithmus, aber um Abwärtskompatibilität zu erreichen, kann es gewollt sein den Default von Zstandard auf das alte xz zu verändern. Wenn dpkg-deb direkt aufgerufen wird, kann mit der Option -Zxz (ohne Leerzeichen zwischen -Z und dem Algorithmus) ein anderer Datenkompressionsalgorithmus für die control und data Archive verwendet werden. Es ginge neben xz, noch gzip oder zstd.

In den allermeisten Fällen wird dpkg-deb aber nicht direkt aufgerufen. Sondern indirekt über debuild, das auch nur dh_builddeb aufruft, dass dann aber dpkg-deb verwendet um das Debian-Paket zu erstellen.

Die Option kann nicht auf der Befehlszeile mit debuild an dpkg-deb übergeben werden, sondern nur über die rules Datei im Debian Verzeichnis. In der rules Datei wird eine override_dh_builddeb Sektion eingefügt. Die Sektion kann einfach ans Ende der rules Datei angehängt werden. Dort wird dann angegeben welche Optionen oder Parameter dh_builddeb an dpkg-deb übergeben soll.

Das sieht zum Beispiel so aus:

override_dh_builddeb:
          dh_builddeb -- -Zxz

Damit wird dpkg-deb angewiesen die control und data Archive mit xz zu komprimieren.

Docker mit IPv6

IPv6 in Docker zu konfigurieren ist sehr einfach. Es gibt nur eine Voraussetzung, aber ein paar Punkte die man beachten sollte.

Das wichtigste zuerst, man benötigt einen festen IPv6 Präfix. Dieser muss konstant sein und darf sich nicht ändern. Das ist bei alle normalen Hosting Providern der Fall.

Die Docker Dokumention zu IPv6 ist leider für die meisten Anwender nicht richtig, den es fehlt ein entscheidender Punkt. Die IPv6 Option muss nicht nur auf „True“ gesetzt werden, es muss auch gleich für das Default Netzwerk (bridge) ein IPv6 Präfix gesetzt werden. Sonst wird der Docker Daemon nicht starten.

Die meisten Provider vergeben ein /64-Netz, daher kann man sehr gut ein /80-Netz für jedes Docker Netzwerk verwenden. In diesem Beispiel wurde dem Server dieser IPv6 Präfix zugeteilt 2001:DB81:12A:C343::/64  Um ein /80-Netz zu erhalten fügt man einfach 4 Weitere Zeichen dem Präfix Teil hinzu (z.B. 2001:DB81:12A:C343:1234::/80 ).

Wenn IPv6 aktiviert wurde, hat das Default Netz (bridge) IPv6. IPv6 kann in diesem Netz auch nicht deaktiviert werden. Es macht daher Sinn, für einzelne Container oder Gruppen von  Containern selbst definierte Netzwerke zu erstellen. Dann kann man ganz individuell entscheiden ob ein Container oder eine Gruppen von Containern Zugang zu einem IPv6 Netz haben soll oder nicht.

Um IPv6 in Docker zu aktiveren, fügt man der Datei /etc/docker/daemon.json folgen Inhalt hinzu. Fall es die Datei noch nicht gibt, muss man sie erstellen.

{
"ipv6": true,
"fixed-cidr-v6": "2001:DB81:12A:C343:1234::/80"
}

Wichtig ist das fixed-cidr-v6 mit einem /80-Netz. Dieser IPv6-Präfix wird für das Default Netz verwendet.

Wenn der Docker Daemon nun neu gestartet wird sollten die Container im Default Netzwerk eine IPv6 Adresse erhalten haben. Es gibt kein SLAAC, der Docker Daemon weist jedem Container eine IPv6 zu. 

Falls zwar eine IPv6 Adresse im Container vorhanden ist, aber keine IPv6 Verbindung ins Internet möglich ist, benötigt man wahrscheinlich ein Neighbor Discovery Proxy wie ndppd. Diesen muss man dann auf dem Docker Host laufen lassen.

Um ein eigenes Docker Netzwerk mit IPv6 zu erstellen kann man folgenden Befehl verwenden.

docker network create --ipv6 --subnet 2001:DB81:12A:C343:4321::/80 mein-netz

Es handelt sich hierbei um ein bridge Netzwerk und hat in diesem Beispiel den Namen „mein-netz“. Neben IPv6 wird vom Docker Daemon auch ein eigenes IPv4 Sub-Netz definiert. Es ist wichtig ein anders /80-Netz als beim Default Netz zu verwenden. Um das Netz zu verwenden muss man den --network mein-netz Parameter zum Docker Befehl hinzufügen.

docker run --network mein-netz hello-world

Als nächstes muss man sich nun Gedanken um die Sicherheit der Docker Container machen. Den diese haben nun eine öffentlich erreichbare IP Adresse. Es gibt ein NAT mehr. Eine Portweiterleitung ist nicht mehr nötig den alle offenen Ports sind für alle zu erreichen. Es ist daher dringend geboten ein paar Firewall Regel zu erstellen.

MariaDB 10.4 – Root Passwort ändern

Vor kurzem wollte ich das Root Passwort von einem MariaDB Server ändern. Bisher ging das mit einem Update Kommando.

UPDATE mysql.user SET Password=PASSWORD('neuessupercoolespasswort') WHERE User='root';

Doch der Befehl endete mit einer Fehlermeldung

ERROR 1348 (HY000): Column 'Password' is not updatable

Seit MariaDB Version 10.4 muss man nun einen neuen Befehl benutzen um das Root Passwort zu ändern. Dazu wie gehabt auf dem MariaDB Server einloggen und die mysql Datenbank auswählen. Dann mit dem folgenden Befehl das Root Passwort ändern

ALTER USER 'root'@'localhost' IDENTIFIED BY 'neuessupercoolespasswort';

und am Ende ein flush privileges; nicht vergessen.

Libvirt – per DHCP feste IP Adressen verteilen

Es kann helfen seinen virtuellen Maschinen mit Libvirt eine statische oder feste IP zu geben. Eine Möglichkeit ist die virtuelle Maschine so zu konfigurieren, dass sie sich selbst eine bestimmte IP gibt. Ich persönlich finde es aber besser, wenn der DHCP Server von Libvirt diese Aufgabe übernimmt. Damit können an einer Stelle die verschiedenen IP Adressen für die virtuellen Maschinen zentral verwaltet werden.

Um per DHCP feste IP Adressen zu verteilen, muss man seine Netzwerk Konfiguration in Libvirt anpassen. Das geht mit dem Befehl virsh net-edit <network> . Wobei <network> für den Namen der Netzwerk Konfiguration steht, standardmäßig ist das default.

<ip address='172.17.17.1' netmask='255.255.255.0'>
 <dhcp>
   <range start='172.17.17.200' end='172.17.17.254'/>
   <host mac='52:54:00:10:b1:ed' name='buildserver5.vir' ip='172.17.17.10'/>
   <host mac='52:54:00:02:b2:2f' name='centos7.vir' ip='172.17.17.11'/>
 </dhcp>
</ip>

Im Bereich dhcp kann unter der Zeile range start eine neue host Zeile angelegt werden. Über die MAC Adresse wird der Host identifiziert. Mit der IP Option wird die IPv4 Adresse für diesen Host zugewiesen. Der Name wird für die interen DNS Einträge verwendet und kann helfen den Überblick zu behalten.

Man kann auch schon vor dem Erstellen einer neuen virtuellen Maschine einen Host Eintrag anlegen. Dazu einfach die letzten drei Gruppen einer MAC Adresse leicht verändern und bei dem Erstellen einer neuen virtuellen Maschine darauf achten diese neue MAC Adresse zu verwenden.

Libvirt – Host Ordner in VM nutzen

Es gibt eine recht einfache Möglichkeit einen Ordner des Host Systems in einer VM zu nutzen. Einzige Bedingung ist, dass der Kernel in der VM das 9p Dateisystem unterstützt.  Bei den meisten Distributionen ist das der Fall. Nur leider nicht bei Rhel7/Centos7. Aber Debian, Ubuntu, Arch und auch Fedora mach dort keine Probleme.
Als erstes muss mit dem virsh Kommando die VM config angepasst werden.

<filesystem type='mount' accessmode='mapped'>
  <source dir='/srv/vmshare'/>
  <target dir='host'/>
</filesystem>

Das ganze kann man natürlich auch im Virt-Manager machen, wenn man die GUI bevorzugt.

Es gibt für den accessmode 3 verschiedene Optionen. Diese sind mapped , squash und passthrough.

Bei mapped wird die Datei auf dem Host System vom Qemu Benutzer angelegt. Der VM Benutzer wird in den extended Attributes gespeichert und auch in der VM angezeigt. Das bedeutet, dass Dateien die von einem normalen Benutzer angelegt werden auch diesem in der VM gehören, gleiches gilt für Dateien von Root. Auf dem Host gehören alle Dateien dem Qemu Benutzer.

Bei squash wird die Datei auf dem Host System vom Qemu Benutzer angelegt und gehört auch in VM System diesem User, aber alle haben Zugriff auf die Dateien. Das führt dazu, dass von Root angelegt Dateien plötzlich einem normalen Benutzer gehören können. Aber es ist bei Problem die einfachst Lösung, wenn einfach Zugriff benötigt wird.

Bei passthrough wird die Datei auf dem Host mit dem VM Benutzer angelegt. Das geht oft schief. Besonders wenn Qemu nicht als Root läuft. Ich würde diese Option nicht verwenden.

Das source dir ist der komplette Pfad des Ordners im Host System, der zugänglich gemacht werden soll.

Das target dir ist kein Pfad. Sondern einfach nur ein Name, der beim mounten in der VM wichtig ist. Am besten einen simplen, einfachen Namen wählen.

 

Nach dem Start der VM kann man mit dem mount Befehl überprüfen ob alles richtig konfiguriert wurde.

mkdir /media/host
mount -t 9p -o trans=virtio,version=9p2000.L host /media/host

Die Dateisystem Quelle bei dem mount befehl ist der Name des „target dir“ .

Wenn alles klappt kann man einen fstab Eintrag anlegen.

host /media/host 9p trans=virtio,version=9p2000.L,_netdev  0  0

 

 

In der Windows Firewall ping Antworten freischalten

Ein neuer Windows 10 Computer antwortet nicht immer auf ICMP ping Pakete. Die Firewall Einstellungen sind auf ein Privates Netz eingestellt. Im Lokalen Netzwerk antwortet der Windows Computer auch ohne Problem auf ping Anfragen.

Kommen die ping Pakete aber nicht aus dem eigenen Lokalen Sub Netzwerk, gibt der PC einfach keine Antwort. Das kann recht nervig sein wenn man mehrere Lokale Sub Netzwerke gekoppelt hat.

Zum Glück gibt es zwei einfache Befehle um dieses Fehlverhalten zu korrigieren. Zuerst öffnet man eine Eingabeaufforderung als Administrator. Dann gibt man folgenden Befehl für IPv4 und IPv6 ein.

 

netsh advfirewall firewall add rule name="ICMP erlaube v4 ping Anfragen" protocol=icmpv4:8,any dir=in action=allow

und

netsh advfirewall firewall add rule name="ICMP erlaube v6 ping Anfragen" protocol=icmpv6:8,any dir=in action=allow

Diese zwei Regeln schalten für alle Situationen ICMP ping Anfragen frei. Die zwei Befehle sind ziemlich selbst erklärend. Im ICMP Protokoll ist die ping Anfrage Option 8. Auf diese Option wird das Protokoll der Regeln beschränkt.

Bei Bedarf kann man auch nur einen der beiden Befehle verwenden, um so gezielt IPv4 oder IPv6 freizuschalten.

Munin Graphen vergrößern

Ich verwende Munin um von einzelnen Servern Kenndaten wie zum Beispiel CPU- und Arbeitsspeicher-Auslastung in Graphen darzustellen. Da klappt auch sehr gut und man kann über einen längeren Zeitraum Trends erkennen. Munin ist nicht wirklich mit Nagios zu vergleichen. Bei Munin geht es wirklich nur um die Erfassung von Leistungsdaten und das visualisieren in Graphen. Natürlich kann Munin auch Warnungen aufgrund dieser Daten verschicken, aber das ist nicht zu vergleichen mit den Möglichkeiten von Nagios.

Es gibt bei Munin zwei verschiedene Möglichkeiten wie die Graphen generiert werden können. Entweder über eine cgi Schnittstelle beim aufrufen der Munin Seite oder per cron/systemd-timer. Ich verwende einen systemd-timer. Dadurch werden alle 5 Minuten png Bilder der Graphen durch das RRDtool generiert. Das hat in der Vergangenheit sehr viel zuverlässiger funktioniert als per cgi.

Leider sind die generierten png Dateien für heutige Monitor Auflösungen recht kein. Die gesamte png Datei ist etwa 500×320 Pixel groß. Die gesamt Höhe ist natürlich abhängig von der Legende. Der eigentliche Graph nur etwa 400×180 Pixel groß. Das ist leider sehr klein. Es gibt natürlich auch noch die Zoom Funktion. Bei Munin dynazoom genannt. Mir geht es aber um die routinemäßig generierten png Bilder die in den Übersichten angezeigt werden.

Zum Glück kann man sehr einfach die eigentliche Graphen Fläche vergrößern. Dazu fügt man der munin.conf die Optionen

graph_width 600
graph_height 300

hinzu. Jetzt ist der Graph mit 600×300 erheblich größer, wodurch die Gesamtgröße der png Datei auf 697×465 wächst. Bei einer größeren Legende wird sich die Höhe natürlich auch weiter vergrößern. Zwei Grafen nebeneinander füllen jetzt viel besser einen modern Bildschirm aus.

Es gibt Plugins die selbständig z.B. die Breite von den generierten png Bilder festlegen. Das diskstats Plugins gehört unter anderem dazu. Diese Plugins müssen angepasst werden damit sie auf die gleiche Größe kommen.

IPv6 Adresse für ausgehenden Verbindungen definieren

Server haben üblicherweise mehr als eine IPv6 Adresse. Diese Adressen sind meist gleichwertig. Daher ist es nicht immer offensichtlich welche IPv6 Adresse für ausgehenden Verbindungen verwendet wird. In diesem Artikel geht es um statisch hinzugefügte IPv6 Adressen. Bei Desktop Systemen ist es anders, dort gibt es diese Art von IPv6  Adressen normalerweise nicht.

Linux verwendet zur Auswahl einer IPv6 Adresse die Regeln in RFC 3484. Doch leider helfen die Regeln bei sehr ähnlichen Adressen nicht. Daher wird in letzer Instanz die zuletzt hinzugefügt IPv6 Adresse verwendet. Das kann dazu führen, dass die Ausgangs Adresse sich nach jedem Neustart ändert und manchmal auch zwischen durch.

Es gibt eine einfache Möglichkeit die default IPv6 Adresse für ausgehenden Verbindungen zu definieren. Dazu wird bei allen nicht default IPv6 Adressen die bevorzugte Lebensdauer (Preferred Lifetime) auf 0 gesetzt. Es sollte dann nur noch eine IPv6 Adresse mit einer unendlichen Lebensdauer geben. Die übrigen Adressen sind dann für den Kernel veraltet (deprecated) und werden nicht für ausgehende Verbindungen verwendet.

Der Kernel wird eingehende Verbindung auf diesen veralteten IP Adressen trotzdem noch bearbeiten. Auch können Programme diese Adressen noch für ausgehende Verbindungen nutzen. Nur es muss explizit konfiguriert werden. Viele Programme (Nginx, Postfix, Dovecot, …) haben Optionen dafür. Zum Beispiel bei Postfix die „smtp_bind_address6“ Option. Oder curl kann mit der Option --interface 'IPv6_Adresse' gestartet werden. So sind die weiteren Adressen noch zu verwenden, aber es ist eine default IPv6 Adresse für ausgehenden Verbindungen definiert auf die man sich verlassen kann.

Auf neueren Systemen wird oft systemd-networkd verwendet. Eine Beispiel Konfigurationen mit einer IPv4 und 3 gleichwertigen IPv6 Adressen

[Match]
Name=eno1

[Network]
Address=198.51.100.5/24
Address=2001:db8::5/32
Address=2001:db8::6/32
Address=2001:db8::7/32

Gateway=198.51.100.1
Gateway=2001:db8::1
DNS=198.51.100.3
DNS=2001:db8::4

Bei den Adressen 2001:db8::6 und 2001:db8::7 soll nun eine bevorzugte Lebensdauer von 0 eingestellt werden. 2001:db8::5 soll die default IPv6 Adresse sein. Die Konfiguration müsste so angepasst werden.

[Match]
Name=eno1

[Network]
Address=198.51.100.5/24
Address=2001:db8::5/32

Gateway=198.51.100.1
Gateway=2001:db8::1
DNS=198.51.100.3
DNS=2001:db8::3

[Address]
Address=2001:db8::6/32
PreferredLifetime=0

[Address]
Address=2001:db8::7/32
PreferredLifetime=0

Zu beachten ist, dass in einem [Address] Bereich immer nur eine Address= definiert werden kann. Es kann aber beliebig viele [Address] Bereiche geben. Es kann auch Sinn machen die IPv6 Router Advertisement auszuschalten um eine Autokonfiguration zu vermeiden.

Wer noch ältere Debian Systeme verwendet, muss die Konfiguration in /etc/network/interfaces oder in /etc/network/interfaces.d vornehmen.  Dort ist die Idee den up Befehl zu verwenden. Eine Konfiguration würde so aussehen.

iface eno1 inet6 static
   address 2001:db8::5
   netmask 32
   gateway 2001:db8::1
   accept_ra 0
   autoconf 0
   privext 0
   up ip -6 addr add 2001:db8::6/32 dev eno1 preferred_lft 0
   up ip -6 addr add 2001:db8::7/32 dev eno1 preferred_lft 0

Nginx sub Modul bei einem Reverse Proxy

Wie auch der Apache Server gibt es bei Nginx ein Substitutionsmodul. Leider ist das Modul ein wenig schlichter und bietet nicht so viele Optionen. Das Modul wird nicht per Default mit gebaut. Es muss explizit aktiviert werden. Viele Distributionen bauen das Modul aber gleich mit. Dieses Modul sollte aber nicht mit dem „subs_filter“ Modul verwechselt werden, welches auch von vielen Distributionen mit angeboten wird. Das „subs_filter“ Modul ähnelt sehr stark dem Apache Mod Substitute.

Wie auch bei Apache funktioniert es nur wenn der Inhalt nicht komprimiert ist. Dazu setzt man am einfachsten die Option

proxy_set_header Accept-Encoding "";

im „location“ Bereich für den Proxy Eintrag. Dadurch wird der Inhalt bei der Übertragung zwischen Proxy und Quelle nicht komprimiert und kann mit dem sub Modul verändert werden. Der Inhalt vom Proxy zum Client (Browser) kann aber wieder komprimiert werden.

sub_filter_types application/xml;
sub_filter_last_modified on;
sub_filter_once off;
sub_filter 'https://problempodcast.de/wp-content/cache/' 'https://URL/podcast-ssl-problem/cache/';

Die „sub_filter_types“ Option bestimmt welche MIME Typen verändert werden dürfen. Der Standard ist nur „text/html“, mit einem Asterisk (*) kann man auf alle MIME Typen den Filter anwenden. Man sollte immer versuchen den MIME Type so genau wie Möglich setzen, um Fehler bei der Veränderung mit dem Modul auszuschließen.

Die „sub_filter_last_modified“ Option kann hilfreich sein wenn man nicht möchte, dass der „Last Modified“ Eintrag geändert wird. Den eine Veränderung mit dem Modul würde normalerweise einen neuen „Last Modified“ Eintrag erzeugen.

Mit „sub_filter_once“ kann bestimmt werden, ob alle „sub_filter“ im selben Bereich nur auf die erste passende Stelle angewendet werden oder auf jede im Dokument passende Stelle.  Leider kann man dieses nicht für jeden „sub_filter“ eigenständig konfigurieren. Man muss sich also entscheiden und dann ggf. die „sub_filter“ so anpassen das es nur eine mögliche Übereinstimmung gibt.

Nun zur wichtigsten Option, der “ sub_filter“ Funktion. Nach der ersten Zeichenfolge wird im Dokument gesucht und mit der zweiten Zeichenfolge ersetzt. Die Suche ignoriert immer die groß und klein Schreibung. Es macht also keinen Unterschied ob im original Dokument ein kleiner oder großer Buchstabe ist. Das lässt sich nicht abschalten. Die Zeichenfolgen müssen in einfache Anführungszeichen gesetzt werden. In einem „location“ Bereich kann es mehrer “ sub_filter“ Optionen geben. Sie werden der Reihe nach immer auf dem veränderten Dokument durchgeführt.

In “ sub_filter“ sind keine regulären Ausdrücke möglich. Das schränkt die Muster Erkennung erheblich ein. Es kann wirklich nur nach einem normalen String gesucht und dieser dann ersetzt werden. Zusätzlich können aber normale Nginx Variablen eingebaut werden.

Falls mehr Optionen gewünscht sind, besonders im hinblick auf reguläre Ausdrücke, hilft ein Blick auf das „subs_filter“ Modul. Viele Distributionen stellen das Modul als normales Pakte bereit.