IT security, FreeBSD, Linux, mail server hardening, post-quantum crypto, DNS, retro computing & hands-on hardware hacks. Privater Tech-Blog seit 2003.

Kategorie: Kernel-Error-Blog (Seite 8 von 46)

Persönlicher Tech-Blog von Sebastian van de Meer — Beiträge zu IT-Security, Netzwerken, FreeBSD, Linux, Elektronik und Maker-Projekten.

FreeBSD IPv6-Probleme bei Netcup beheben

Dinosaurier beißt ein Patchkabel durch, im Hintergrund das Buch IPv6 Workshop.

Als Kunde, der bei Netcup FreeBSD-Rootserver auf KVM/QEMU-Basis einsetzt, habe ich schnell gemerkt, dass meine IPv6-Verbindung nicht stabil ist.

Symptome

  • Direkt nach dem Boot funktioniert IPv6 wie gewünscht
  • Nach einiger Zeit brechen Verbindungen zusammen — sowohl eingehend als auch ausgehend
  • Verbindungen haben „Startprobleme“ — ein Ping läuft erst ein paar Mal ins Leere, dann funktioniert plötzlich alles wieder für einen Moment

Ein Ping auf die IPv6-Adresse des Netcup-Gateways stellt die Konnektivität kurzzeitig her. Das deutet sofort auf ein NDP-Problem (Neighbor Discovery Protocol) hin.

Diagnose

FreeBSD behandelt Neighbor Solicitations anders als Linux. Netcups Netzwerk-Setup kommt damit offenbar nicht klar — unter Linux funktioniert IPv6 problemfrei, unter FreeBSD (und NetBSD) nicht. Die ICMPv6-Statistiken zeigen das Problem deutlich:

netstat -s -picmp6 | grep -i neighbor
    neighbor solicitation: 29          # Output: wenige eigene Anfragen
    neighbor advertisement: 10         # Output: wenige eigene Antworten
    neighbor solicitation: 633         # Input: Flut eingehender Anfragen
    neighbor advertisement: 25         # Input: wenige Antworten zurück
    423 bad neighbor solicitation messages  # <-- das Problem

633 eingehende Neighbor Solicitations, davon 423 als „bad" verworfen. FreeBSD verwirft die Anfragen, weil sie nicht von einer On-Link-Adresse kommen — ein Verhalten, das FreeBSD aus Sicherheitsgründen seit einem Security Advisory von 2008 erzwingt.

Lösung

FreeBSD anweisen, Neighbor Discovery nach RFC 4861 zu machen — das akzeptiert auch Solicitations von Off-Link-Adressen, wie es Netcups Router sendet. Zum Testen:

sysctl net.inet6.icmp6.nd6_onlink_ns_rfc4861=1

Funktioniert es, den Eintrag in /etc/sysctl.conf permanent machen:

net.inet6.icmp6.nd6_onlink_ns_rfc4861=1

Wichtig: FreeBSD hat dieses Verhalten aus Sicherheitsgründen deaktiviert. Die strenge Prüfung schützt gegen NDP-Spoofing-Angriffe. Auf einem VPS bei einem vertrauenswürdigen Hoster ist das Risiko überschaubar — auf einem System in einem offenen Netzwerk sollte man abwägen.

Netcup-Support

Ich habe einige Zeit mit dem Support verbracht. Das Problem wurde mir bestätigt — es liege an den Core-Routern, ein Update sei geplant, aber ohne Termin. Mein System wurde auf verschiedene Hosts verschoben, ohne Besserung. Das Problem ist im Netcup-Forum bekannt und betrifft alle BSD-Systeme. Aus meiner Sicht lässt Netcups Setup keine einfache Lösung zu, daher bleibt der sysctl-Workaround.

Siehe auch: IPv6 ULA und Priorität

Fragen? Einfach melden.

MikroTik CRS305-1G-4S+IN: Der 10-Gbit-Switch für 130 Euro im Langzeittest

Den MikroTik CRS305-1G-4S+IN habe ich Ende 2020 in meinem Arbeitszimmer in Betrieb genommen. Workstation, Storage, Hauptswitch und Windows-PC hängen seitdem an seinen vier SFP+ Ports. Fünf Jahre später läuft das Teil immer noch ohne Ausfall und ich denke es ist Zeit für ein ehrliches Update.

Damals lag der Preis bei knapp über 100 Euro, aktuell zeigt mir Amazon 131,62 Euro an. Klingt nach Inflation, ist für einen managebaren 4-Port 10-Gbit-Switch trotzdem immer noch ein Witz.

Was bekommt man fürs Geld?

An der Hardware hat sich seit dem Erstkauf nichts geändert: Vier SFP+ Ports mit 10 Gbit/s, dazu ein Gigabit-Port für Out-of-Band-Management. Komplett lüfterlos, das Metallgehäuse dient als Kühlkörper. Stromversorgung wahlweise per Steckernetzteil, über den zweiten Netzteil-Anschluss redundant oder per PoE-In über den Management-Port. Wer es ernst meint mit Hochverfügbarkeit, packt drei verschiedene Quellen drauf.

Auf der Unterseite sind Bohrungen für die Wandmontage. Bei mir hängt der Switch seit Jahren an genau dieser Stelle.

RouterOS, jetzt in Version 7

Auf dem Gerät läuft echtes RouterOS, kein abgespecktes SwitchOS-Light. Vor ein paar Jahren bin ich von Version 6 auf 7 umgestiegen, der Sprung lief schmerzfreier als befürchtet. Container-Support, eine neue Routing-Engine, in-kernel WireGuard, ROSE-storage. Für den CRS305 in reiner Switch-Funktion ist das meiste davon Overkill, aber der gleiche Software-Stack läuft auf allen MikroTik-Geräten und das einmal gelernte Wissen ist übertragbar.

Wer den Switch wirklich nur als Switch braucht und das volle Routing-Featureset nicht will, kann alternativ SwOS einspielen. Ich bleibe bei RouterOS, weil ich VLANs, VRRP und gelegentlich mal eine kleine Bridge mit eigenen Regeln nutze.

Härtung: das was 2021 noch keiner gesagt hat

In den letzten Jahren ist MikroTik mehrfach unangenehm aufgefallen. Botnetze auf nicht aktualisierten RouterOS-Geräten (Mēris, TrickBot, VPNFilter), mehrere Webfig-Authentifizierungs-Bypässe, dazu der Klassiker: Default-User „admin“ ohne Passwort. Wer so ein Gerät ohne Härtung ans Internet hängt oder auch nur ohne Trennung ins LAN, hat sich selbst beschenkt.

Mein Standardvorgehen direkt nach dem Auspacken sieht ungefähr so aus:

/user add name=adminneu group=full password=...
/user remove admin
/ip service disable telnet,ftp,www,api,api-ssl
/ip service set winbox address=192.168.X.0/24
/ip service set ssh address=192.168.X.0/24
/system clock set time-zone-name=Europe/Berlin
/system ntp client set enabled=yes servers=pool.ntp.org
/system package update check-for-updates
/system routerboard upgrade

Webfig und API mögen bequem sein, ich brauche beides nicht. Telnet und FTP haben auf einem Gerät von 2026 nichts mehr verloren. Wer trotzdem das Webinterface nutzen will, sollte zumindest auf HTTPS umstellen und die Zugriffe auf das Management-Subnetz beschränken.

Auto-Update gibt es bei MikroTik leider noch immer nicht out-of-the-box. Ich habe mir einen kleinen Cron-Job gebaut, der einmal im Monat anpingt ob ein Update da ist. Manuell einspielen muss ich es dann selbst, weil mir bei einem zentralen Netzwerkgerät ein automatisches Reboot mitten in der Nacht zu heikel ist.

SFP+ Module und DAC-Kabel

MikroTik ist da angenehm tolerant: vendor-locked Module von Cisco, Juniper oder HPE fliegen in der Regel ohne Murren rein. In meinen vier Ports stecken aktuell zwei FS.com-Module mit LWL, ein generisches Kupfer-DAC zur Workstation und ein 10GBASE-T-Adapter ans Storage. Alles funktioniert, kein Kabel oder Modul zickt.

Vorsicht bei 10GBASE-T-Adaptern: die werden warm. Sehr warm. Bei zwei oder mehr Stück im engen Gehäuse kann der Switch im Sommer am thermischen Limit kratzen. Wer kann, sollte LWL oder DAC bevorzugen, das ist effizienter und kühler. DACs sparen außerdem die Modul-Kosten und bringen Latenzen, die mit aktiven Modulen schlicht nicht zu erreichen sind.

Stromverbrauch

Bei mir liegt der Verbrauch im Mittel zwischen 8 und 12 Watt, je nach Bestückung. Mit zwei 10GBASE-T-Adaptern kann es Richtung 14 bis 16 Watt gehen. Für einen 24/7 laufenden Switch ist das vertretbar, in Zeiten von Stromrechnungen die jedes Jahr neue Höchststände erreichen sollte man es zumindest wissen.

Markt 2026: Alternativen

2021 war der CRS305 in seiner Preisklasse fast konkurrenzlos. 2026 sieht das anders aus. Ein paar Optionen, die ich heute mit auf die Liste setzen würde:

  • MikroTik CRS309-1G-8S+IN: Doppelte Portzahl, gleicher Aufbau, etwa 250 bis 300 Euro. Wenn vier Ports knapp werden, der logische Schritt nach oben.
  • MikroTik CRS310-1G-5S-4S+IN: Mischmasch aus 1G/2.5G und 4× SFP+, brauchbar wenn das eigene Netz nicht komplett auf 10G migriert ist.
  • TP-Link TL-SX3008F: 8× SFP+ JetStream-Smart-Switch, kein RouterOS aber gepflegtes Webinterface, etwa 250 Euro. Für reines Switchen oft entspannter als RouterOS.
  • QNAP QSW-M408S: 4× SFP+ plus 4× 1G, simples Web-UI, knapp 280 Euro. Gut für Leute, die kein RouterOS lernen wollen.
  • Ubiquiti USW-Aggregation: 8× SFP+ mit Web-Controller, etwa 280 Euro. Wer schon im UniFi-Ökosystem unterwegs ist, will sowieso nichts anderes.

Für den absoluten Einstieg in 10G zuhause, mit kleinem Budget und der Bereitschaft sich kurz mit RouterOS zu beschäftigen, ist der CRS305 weiterhin der beste Deal. Wer mehr Ports braucht oder das Routing-Featureset gar nicht erst anfassen will, sollte einen der oben genannten in die engere Wahl nehmen.

Fazit nach 5 Jahren

Das Gerät ist seit 2021 ohne einen einzigen Ausfall durchgelaufen, hat zwei Wohnungswechsel und mehrere RouterOS-Major-Updates überlebt. Bei aktuell 131,62 Euro auf Amazon oder direkt von MikroTik bleibt es eine klare Empfehlung. Mit der Einschränkung, dass man die paar Minuten in Härtung investieren sollte, sonst wird aus dem schönen kleinen Switch schnell ein Botnet-Knoten.

Ich mache ja eher selten Werbung für ein Produkt, aber dieser Switch hat sich nach fünf Jahren als die beste Empfehlung herausgestellt, die ich in dieser Preisklasse jemals geben konnte.

Siehe auch: IPv6 Prefix Delegation: FritzBox und MikroTik und Ist mein Netzwerk kompromittiert? Warum das kaum jemand merkt.

Fragen? Einfach melden.

Linux Mint mit verschlüsseltem ZFS-Root-Pool installieren

ZFS als Root-Dateisystem unter Linux — will man haben. Verschlüsselung auf der Festplatte — will man auch haben. Die Kombination aus beidem war unter Linux lange ein manueller Kraftakt. Seit Linux Mint 20 bringt der Installer aber fast alles mit. Man muss ihm nur an zwei Stellen unter die Arme greifen.

Linux Mint Boot-Bildschirm: ZFS-Pool-Passwortabfrage nach erfolgreicher Verschluesselung.

Hinweis: Diese Anleitung wurde mit Linux Mint 20.1 geschrieben, funktioniert aber genauso mit Mint 21.x und 22.x — der Installer nutzt das gleiche zsys-setup-Skript.

Pakete im Live-System nachinstallieren

Die gewünschte Linux Mint ISO herunterladen und davon booten. Im Live-System ein Terminal öffnen und die ZFS-Pakete installieren:

sudo aptitude -y install libzfs2linux zfs-initramfs zfsutils-linux zfs-zed

Wer nur ZFS ohne Verschlüsselung will, ist damit schon fertig. Einfach den Installer starten, bei der Festplattenauswahl auf Advanced features… klicken und EXPERIMENTAL: Erase disk and use ZFS wählen. Für Verschlüsselung weiter lesen.

Installer-Skript für Verschlüsselung anpassen

Der Installer fragt kein Passwort für die ZFS-Verschlüsselung ab — das muss man ihm vorher ins Skript schreiben. Im Terminal:

sudo vi /usr/share/ubiquity/zsys-setup

Nach zpool create suchen — es taucht zweimal auf. Beim rpool (nicht beim bpool) zwei Änderungen vornehmen:

1. Vor die zpool create-Zeile des rpool ein echo mit dem gewünschten Passwort setzen:

echo 'EUER-PASSWORT' | zpool create -f \

2. Vor die Zeile -O mountpoint=/ -R "${target}" rpool "${partrpool}" die Encryption-Optionen einfügen:

-O encryption=aes-256-gcm \
-O keylocation=prompt \
-O keyformat=passphrase \

Das fertige Ergebnis sieht dann so aus:

echo 'Kennwort!' | zpool create -f \
        -o ashift=12 \
        -O compression=lz4 \
        -O acltype=posixacl \
        -O xattr=sa \
        -O relatime=on \
        -O normalization=formD \
        -O mountpoint=/ \
        -O canmount=off \
        -O dnodesize=auto \
        -O sync=disabled \
        -O encryption=aes-256-gcm \
        -O keylocation=prompt \
        -O keyformat=passphrase \
        -O mountpoint=/ -R "${target}" rpool "${partrpool}"

Sicherheitshinweis: Das Passwort steht kurzzeitig im Klartext in der Datei und in der Bash-History. Im Live-System ist das unkritisch — nach dem Reboot ins installierte System ist das Live-System weg. Trotzdem nicht das Produktivpasswort in Screenshots posten.

Jetzt den Installer starten, ZFS als Dateisystem wählen — fertig. Funktioniert mit EFI und Legacy-Boot.

Verschlüsselung prüfen

Nach dem ersten Boot ins neue System — Terminal öffnen und prüfen, ob die ZFS-Verschlüsselung aktiv ist und sich durch den Pool bis zu den Benutzerdaten vererbt hat:

$ zpool get feature@encryption bpool rpool
NAME   PROPERTY            VALUE     SOURCE
bpool  feature@encryption  disabled  local
rpool  feature@encryption  active    local

$ zfs get encryption rpool/USERDATA/test_9d9i92
NAME                        PROPERTY    VALUE        SOURCE
rpool/USERDATA/test_9d9i92  encryption  aes-256-gcm  -

feature@encryption: active beim rpool und aes-256-gcm auf den Benutzerdaten — alles korrekt. Der bpool (Boot-Pool) bleibt unverschlüsselt — GRUB muss den Kernel lesen können, bevor das Passwort eingegeben wird.

Wer seine SSDs im ZFS-Pool auch gleich mit TRIM versorgen will — das ist in einem separaten Beitrag beschrieben.


Bilder von der Installation zum Durchklicken:

Siehe auch: ZFS Encryption

Fragen? Einfach melden.

Bose QuietComfort 35: Akku tauschen leicht gemacht

Der Akku in meinem Bose QC35 hat inzwischen ausgedient und muss ausgetauscht werden. Der verbaute Akku ist ein AHB110520CPS von Synergy. Leider konnte ich diesen nicht als Ersatzakku finden. Man kann ihn zwar aus China bestellen (ca. 35 €), aber er ist dann gebraucht, da er aus einem alten Kopfhörer ausgebaut wurde – natürlich „getestet“.

Alternativ gibt es die Möglichkeit, den Kopfhörer einzuschicken und den Akku dort tauschen zu lassen (ca. 70 €). Beides sind jedoch Lösungen, die mir nicht zusagen, denn im Grunde handelt es sich nur um einen einfachen 3,7V-Akku mit knapp 500 mAh.

Nach einiger Suche habe ich jedoch einen passenden Ersatz gefunden. Der Akku GSP072035 hat zwar etwas weniger mAh, was bedeutet, dass die Kopfhörer etwas früher leer sind – aber damit kann ich leben. Zumal die Standzeit des alten Akkus ohnehin schon stark eingeschränkt war. Bestellt habe den folgenden Ersatzakku bei Amazon: https://amzn.to/2JXwhJc

Der neue Akku passt zwar nicht exakt ins Akkufach des alten, ist jedoch klein genug, um problemlos im Kopfhörer Platz zu finden, ohne das Gewicht oder die Klangqualität zu beeinflussen. Man merkt den Unterschied also nicht!

Ein kleiner Tipp: Wenn man schon dabei ist, kann man auch gleich die Ohrpolster austauschen. Ich habe die folgenden Polster bereits zweimal erneuert und kann sie wärmstens empfehlen: https://amzn.to/2L4xcbo

Wie man den Akku selbst austauscht, zeigt eine erstklassige Anleitung von IFIXIT: https://de.ifixit.com/Anleitung/Bose+QuietComfort+35+Akku+tauschen/134337

Bild vom geöffnetem Bose QuietComfort 35 mit eingebautem Ersatzakku.

Sobald der alte Akku entfernt ist, klebt man den neuen mit einem kleinen Tropfen Heißkleber in die Ecke und lötet ihn wie den alten Akku an. Nach dem Zusammenbau sollte der Kopfhörer wieder wie gewohnt funktionieren – abgesehen von etwa 20–25 Minuten weniger Hörzeit.

Kleines Update! 😊

Inzwischen gibt es auf Amazon einen perfekt passenden Ersatzakku. Es war mal wieder Zeit für einen Austausch, und dieses Mal habe ich sogar ein Modell mit 600 mAh gefunden. Jetzt habe ich so viel Hörzeit wie noch nie zuvor mit meinen Kopfhörern! 🎧 https://amzn.to/3CsPQnv

Fragen? Dann fragt einfach!.

Siehe auch: Bosch Geschirrspüler E-21

Fragen? Einfach melden.

Windows Server RRAS: L2TP/IPsec-VPN mit sicheren Cipher Suites

RRAS Routing und RAS Icon.

Wenn ich schon bei Microsoft-Themen bin: Warum nicht gleich noch RRAS (Routing und RAS) mit einem L2TP/IPsec-VPN absichern? Im Standard verbinden sich die Clients nämlich mit SHA-1, 3DES und DH Group 2 (modp1024, also 1024 Bit). SHA-1 ist grenzwertig, 3DES muss nicht sein und modp1024 will man definitiv nicht mehr.

Hinweis: Ursprünglich für Windows Server 2012 R2 geschrieben (inzwischen End of Life). Die Konfiguration über die Windows-Firewall funktioniert auf neueren Versionen identisch.

Wo man die Einstellung findet (Spoiler: nicht bei RRAS)

Ich habe einige Zeit gesucht. Man würde erwarten, dass die IPsec-Cipher irgendwo in der Nähe von Routing und RAS konfiguriert werden. Falsch gedacht. Die Einstellung steckt in der Windows-Firewall mit erweiterter Sicherheit. Irgendeinen Grund wird es haben, das dort zu verstecken. Ich hätte dort nie gesucht.

Der Klickpfad: Windows Firewall → Rechtsklick auf „Windows-Firewall mit erweiterter Sicherheit“ → Eigenschaften → IPsec-Einstellungen → IPsec-Standardeinstellungen → „Anpassen“ → Schlüsselaustausch.

Screenshot der Windows-Firewall mit erweiterter Sicherheit und angezeichnetem Klickpfad um die Sicherheitsmethoden zu konfigurieren.

Hier kann man die Sicherheitsmethoden und Datenschutzeinstellungen anpassen. Windows Firewall als Ort für VPN-Cipher-Konfiguration. Kopfschütteln.

Screenshot der Windows-Firewall mit erweiterter Sicherheit und angezeichnetem Klickpfad um die Datenschutzeinstellungen zu konfigurieren.

UDP Encapsulation hinter NAT

Steht der RRAS hinter einem NAT, muss man noch UDP Encapsulation per Registry aktivieren. Dafür habe ich ein Registry-File:

Registry-File für IPsec UDP Encapsulation

Nach allen Änderungen den Server neu starten. Microsoft halt.

Prüfen ob es geklappt hat

Auf einem Windows-Client per PowerShell (mit erweiterten Rechten) prüfen, welche Cipher die VPN-Verbindung tatsächlich nutzt:

Get-NetIPsecMainModeSA | Select-Object -First 1
Screenshot des Kommandos Get-NetIPsecMainModeSA inkl Konsolenausgabe.

Relevant sind CipherAlgorithm, HashAlgorithm und GroupId. Im Standard steht da 3DES, SHA-1 und DH Group 2 (1024 Bit). Nach den Änderungen:

Encryption:                AES256
Authentication/Integrity:  SHA-1
Key Size:                  DH Group 20 (384-bit ECC)

Immer noch SHA-1 für die Integrity, aber AES-256 und ECC sind ein großer Sprung. Über Gruppenrichtlinien ließe sich das Ganze auch zentral ausrollen, aber das ist nochmal ein eigenes Thema. Vor allem die Reihenfolge korrekt vorzugeben ist dort unerwartet fummelig.

Wer auch die TLS-Cipher für Exchange/OWA härten will: SSL Labs A+ mit Exchange. Fragen? Einfach melden.

WSUS-Bereinigung: Timeouts beheben und Speicherplatz freigeben

Pfffff… Einen dauerhaft richtig gut laufenden WSUS Server habe ich tatsächlich noch nie gesehen. Irgendwann werden die Dinger langsam, dann gibt es Timeouts, die Serverbereinigung läuft nicht mehr durch und die Platten laufen voll. WSUS ist kein Dienst, den man einmal konfiguriert und dann läuft er. WSUS möchte dauerhaft Aufmerksamkeit. Was mir dabei so aufgefallen ist, möchte ich hier teilen.

Keine Treiberupdates über WSUS

Screenshot der WSUS-Oberfläche: Produkte und Klassifizierungen konfigurieren.

Nie Treiberupdates über WSUS verteilen. Hier explodiert der Platzverbrauch. Falls aktiviert: Über Optionen → Produkte und Klassifizierungen → Klassifizierungen den Haken bei „Treiber“ entfernen. Dann unter Updates → Alle Updates die Dropdown-Menüs auf „Genehmigung: Genehmigt“ und „Status: Alle“ setzen, nach Klassifizierung sortieren und alle Treiberupdates ablehnen.

Abgelehnte Updates löschen

Abgelehnte Updates belegen weiterhin Plattenplatz, bis sie aktiv gelöscht werden. Dieses PowerShell-Script räumt sie weg — es läuft eine Weile, schafft aber viel Platz:

Screenshot der PowerShell ISE mit WSUS-Bereinigungsscript.
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
$wsus.GetUpdates() | Where {$_.IsDeclined -eq $true} | ForEach-Object {
    $wsus.DeleteUpdate($_.Id.UpdateId.ToString())
    Write-Host $_.Title removed
}

Serverbereinigung automatisieren

Der „Assistent für die Serverbereinigung“ löscht überflüssige Updates — abgelehnte, ersetzte und nicht mehr benötigte. Man sollte ihn regelmäßig laufen lassen, aber er lässt sich nicht direkt automatisieren. Dafür braucht man ein PowerShell-Script, das man per Aufgabenplanung täglich ausführt:

# Variablen
$DateFormat = Get-Date -format yyyyMMdd-HH-mm
$Logfile = "H:\Logs\wsus-bereinigung-$DateFormat.log"

# WSUS Bereinigung durchführen
Invoke-WsusServerCleanup -CleanupObsoleteUpdates `
    -CleanupUnneededContentFiles -CompressUpdates `
    -DeclineExpiredUpdates -DeclineSupersededUpdates `
    | Out-File $Logfile

# Status-Mail versenden
$MailBody = Get-Content $Logfile | Out-String
Send-MailMessage -SmtpServer "smtp.example.de" `
    -From "wsus@example.de" -To "admin@example.de" `
    -Subject "${env:COMPUTERNAME} Bereinigung $DateFormat" `
    -Body $MailBody -Encoding Unicode

IIS-Einstellungen bei Timeouts

Wenn die WSUS-Konsole oder Bereinigung mit Timeouts abbricht, hilft es oft, dem WsusPool im IIS mehr Ressourcen zu geben:

IIS-Manager → Anwendungspools → WsusPool → Erweiterte Einstellungen

  • Limit für den privaten Speicher (KB): 6000000
  • Maximale Anzahl von Arbeitsprozessen: 0
  • Startmodus: AlwaysRunning

Danach den IIS neu starten — oder besser gleich den ganzen Server, es ist ja ein Windows.

SUSDB-Datenbank warten

Screenshot der Database Properties SUSDB: Compatibility Level auf SQL Server 2012 setzen.

Mit dem SQL Server Management Studio zur Windows Internal Database verbinden: \\.\pipe\MICROSOFT##WID\tsql\query

Compatibility Level anheben: Databases → SUSDB → Properties → Options → Compatibility level: SQL Server 2012 (110)

Screenshot SUSDB Shrink Database Dialog.

Datenbank verkleinern: Databases → SUSDB → Tasks → Shrink → Database

Synchronisierungshistorie aufräumen:

Screenshot SQL Server Management Studio mit Bereinigungsquery für WSUS-Synchronisierungen.
USE SUSDB
GO
DELETE FROM tbEventInstance
WHERE EventNamespaceID = '2'
  AND EVENTID IN ('381', '382', '384', '386', '387', '389')

Wenn die Bereinigung hängen bleibt

Manchmal bleibt die Serverbereinigung an einem bestimmten Update hängen. Dann hilft es, das erste Update in der „zu löschen“-Liste von Hand zu entfernen:

USE SUSDB
GO
-- Erste Update-ID ermitteln
exec spGetObsoleteUpdatesToCleanup
-- ID notieren und löschen
exec spDeleteUpdate @localUpdateID=HIER_UPDATE_ID

Wenn auch das nicht reicht, kann man alle obsoleten Updates in einer Schleife löschen — das läuft lange, räumt aber zuverlässig auf:

USE SUSDB
DECLARE @var1 INT, @curitem INT, @totaltodelete INT
CREATE TABLE #results (Col1 INT)
INSERT INTO #results(Col1) EXEC spGetObsoleteUpdatesToCleanup
SET @totaltodelete = (SELECT COUNT(*) FROM #results)
SELECT @curitem = 1

DECLARE WC Cursor FOR SELECT Col1 FROM #results
OPEN WC
FETCH NEXT FROM WC INTO @var1
WHILE (@@FETCH_STATUS > -1)
BEGIN
    RAISERROR('%d/%d: Deleting %d', 0, 1, @curitem, @totaltodelete, @var1) WITH NOWAIT
    EXEC spDeleteUpdate @localUpdateID=@var1
    SET @curitem = @curitem + 1
    FETCH NEXT FROM WC INTO @var1
END
CLOSE WC
DEALLOCATE WC
DROP TABLE #results

Abschließend die Indexe der SUSDB neu aufbauen — das beschleunigt danach alles spürbar. Microsoft hatte dafür ein Script in der TechNet Gallery veröffentlicht. Die Gallery ist inzwischen offline, aber das Script findet sich als WsusDBMaintenance.sql in diversen Microsoft-Docs-Artikeln. Im Kern macht es nichts anderes als fragmentierte Indexe zu erkennen und per ALTER INDEX REBUILD oder REORGANIZE zu reparieren, gefolgt von sp_updatestats.

Meist hilft eine Kombination aus mehreren dieser Maßnahmen. Bisher hat mir immer irgendetwas davon geholfen — auch wenn ich dafür einige Zeit in Suchmaschinen verschwenden musste. Fragen? Einfach melden.

Siehe auch: Windows Server Backup mit Nagios

Windows Server mit Exchange: SSL Labs A+ erreichen

Qualis A+ Icon.

Ich hatte hier einen Windows Server 2012 R2 mit Exchange 2016 stehen. Out of the Box sprach das Ding TLS 1.0, SSLv3 und RC4. Da gehen einem die Haare hoch. Kann man so ein System auf ein A+ bei Qualys SSL Labs bekommen und es funktioniert danach noch? Kleiner Spoiler: Ja, geht.

Ich muss zugeben, Microsoft-Produkte strengen mich in dieser Hinsicht immer an. Die haben ihre Daseinsberechtigung, keine Frage. Aber TLS-Hardening unter Windows fühlt sich an wie Zahnmedizin mit Handschuhen aus Pappe.

Hinweis: Windows Server 2012 R2 und Exchange 2016 sind inzwischen End of Life. Der Ansatz (Registry-Änderungen für TLS, HSTS im IIS) funktioniert auf Windows Server 2016/2019/2022 aber genauso.

HSTS im IIS setzen

Für ein A+ braucht man neben sauberen Ciphern und Protokollen auch HTTP Strict Transport Security (HSTS). Das ist im Grunde nur ein HTTP-Response-Header. Im IIS-Manager konfiguriert man ihn ganz oben auf Server-Ebene, damit er überall vererbt wird:

IIS-Manager → HTTP-Antwortheader → Hinzufügen:

Screenshot der Internetinformationsdienste (IIS)-Manager.
Name:  strict-transport-security
Wert:  max-age=31536000; includeSubdomains

TLS-Protokolle und Cipher härten

Jetzt der eigentlich spannende Teil. Man muss eine ganze Reihe von Registry-Änderungen vornehmen: MD5 und RC4 deaktivieren, SSLv3, TLS 1.0 und TLS 1.1 abschalten, TLS 1.2 aktivieren, schwache Cipher raus und eine sinnvolle Cipher-Reihenfolge vorgeben. Ich habe dafür ein Registry-File vorbereitet. Herunterladen, ausführen, Server neu starten (Microsoft halt).

Download: Registry-File Download

Ergebnis

Qualis A+ Wertung.
Qualis Wertung mit Blick auf Cipher Suites und Protocols.

A+ steht. Ich hätte gerne noch schönere Cipher gehabt, aber mehr war mit diesem Setup nicht drin. Immerhin: Kein RC4, kein 3DES, kein TLS unter 1.2. Und Exchange funktioniert danach noch, was bei Microsoft-Produkten ja nie selbstverständlich ist.

Wer auch die VPN-Cipher auf dem Windows Server härten will, findet die Anleitung im Beitrag RRAS mit sicheren Cipher Suites. Fragen? Einfach melden.

DIY Feinstaubsensor bauen: Luftqualität selbst messen mit ESP8266​

Bild vom DIY Feinstaubsen und Luftqualitätsensor beim Aufbau.

Es gibt ein ganz spannendes Projekt, welches sich mit dem Messen und Sammeln von Umweltdaten beschäftigt. So gibt es vom Projekt einige Bauanleitungen inkl. Software zum Messen der Luftqualität, Temperatur, Luftfeuchtigkeit, Lärm usw… Die Webseite findet ihr hier: https://luftdaten.info/

Im einfachsten Fall basiert so ein Sensor am Ende auf folgenden Komponenten:
NodeMCU ESP8266, CPU/WLAN
SDS011 Feinstaubsensor (früher PPD42NS)
DHT22, Temperatur & Luftfeuchtigkeit (optional)

Die Daten werden offen gesammelt und können auf verschiedene Weise eingesehen werden. So gibt es zum Beispiel:
– eine Karte:  https://maps.sensor.community
– Grafana: Temperatur / Feinstaub

Die Bauanleitung ist extrem einfach, die Teile bekommt jeder und kosten kaum Geld. Selbst der Softwareteil ist ohne jeden Aufwand. Man muss nicht mal löten! Fast jeder sollte in der Lage sein so einen Sensor zu bauen und ihn mit seinem WLAN zu verbinden. Vielleicht ein schönes Projekt mit seinen Kindern oder um sich im Unterricht mit so etwas zu beschäftigen?!?

Fragen? Dann fragen!

Siehe auch: DHT22 am Raspberry Pi

Fragen? Einfach melden.

Bash-Skript: Automatisiertes Erstellen von Abuse-E-Mails

Das Problem

Wer ein System mit öffentlicher IP betreibt, kennt das: Kaum ist der Server online, hämmern Bots und Script Kiddies auf SSH, Postfix und alles, was nach Dienst aussieht. Fail2Ban sperrt die Adressen, meldet sie an AbuseIPDB und verteilt die Sperren auf die anderen Kisten. So weit, so automatisch.

Screenshot der Konsolenausgabe vom Abuse Script.

Aber was ist mit dem Hoster oder ISP hinter der IP? Meistens steckt ein kompromittierter Root-Server oder VPS dahinter. Vielleicht weiß der Admin noch gar nichts davon. Im whois zur IP findet sich eine abuse-mailbox, an die man sich wenden kann.

➜  ~ whois 8.8.8.8|grep -i abuse
OrgAbuseEmail:  ipaddressing@level3.com
OrgAbuseEmail:  network-abuse@google.com

Ehrlich gesagt: Der Großteil dieser Abuse-Mails landet beim Empfänger in /dev/null. Rückmeldungen bekommt man fast nie, und oft hat es schlicht keinen Effekt. Hin und wieder hilft es aber jemandem. Deshalb schiebe ich ab und zu einen Abuse an, will dabei aber so wenig Arbeit wie moeglich reinstecken.

Abuse melden: Was gehört rein?

Damit der Empfänger etwas mit der Meldung anfangen kann, sollte sie folgende Informationen enthalten:

  • Die IP-Adresse des eigenen Systems.
  • Die IP-Adresse, von der die Angriffe kommen.
  • Ein paar Zeilen aus dem Logfile, die das Problem zeigen.
  • Die Zeitzone des eigenen Systems, damit die Zeitangaben im Log nutzbar sind.
  • Eine kurze Beschreibung des Problems.
  • Die Erlaubnis, die Kontaktdaten an den Kunden weiterzugeben.

Das Script

Da mich Fail2Ban direkt mit dem whois zur IP informiert, brauche ich nur noch etwas, das die restlichen Informationen einsammelt und die Mail generiert. Dafür habe ich folgendes Bash-Script geschrieben. Man übergibt die IP und die Abuse-Adresse, das Script validiert beides, sammelt die passenden Zeilen aus dem auth.log, baut die Mail zusammen und schickt sie nach einer Sichtkontrolle ab.

#!/usr/local/bin/bash

if [ "$1" == "-h" ] ; then
    printf "You can add abuse ip and mail on start or interactive by request."
    printf "Usage 1: abusemail.sh 1.2.3.4 example@example.org"
    printf "Usage 2: abusemail.sh"
    exit 0
fi

myip="1.2.3.4"
bcc="my@mail.com"


function validateMail()
 {
         local mail=$1
         local stat=1
         if [[ "$mail" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]]; then
                stat=0
        fi
        return $stat
}

function validateIP()
 {
         local ip=$1
         local stat=1
         if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
                OIFS=$IFS
                IFS='.'
                ip=($ip)
                IFS=$OIFS
                [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
                && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
                stat=$?
        fi
        return $stat
}
clear
printf "\x1b[31;1;4mCreate und send abuse e-mail!\x1b[0m\n\n"
printf "Enter IP Address"

if [ "$1" == "" ] ; then
    read ip
else
    ip=$1
fi

validateIP $ip

if [[ $? -ne 0 ]];then
  printf "Invalid IP Address ($ip)"
  exit 1
else
  printf "$ip ==> \x1b[32;1;4mOK\x1b[0m\n\n"
fi
printf "\n"
printf "Enter Abuse E-Mail Address"

if [ "$1" == "" ] ; then
    read mail
else
    mail=$2
fi

validateMail $mail

if [[ $? -ne 0 ]];then
  printf "Invalid Abuse E-Mail Address ($mail)"
  exit 1
else
  printf "$mail  ==> \x1b[32;1;4mOK\x1b[0m"
fi

printf "Dear abuse team,\n\nI got some SSH connections from one of your IPv4 addresses. It seems to\nbe a bot or something....\n\nYes, you can forward this E-Mail with contact informations to your \ncustomer to solve this case, if necessary.\n\nMy timezone: Europe/Berlin\nMy IPv4: $myip\nYour IPv4: $ip\n\nSome log snippets:\n" > /tmp/abusemail
grep $ip /var/log/auth.log >> /tmp/abusemail
printf "\nBest regards\nSebastian van de Meer\n" >> /tmp/abusemail


printf "\n\n\n\x1b[31;1;4mCheck e-mail before sending!\x1b[0m\n\n"
printf "\x1b[32;1;4mRecipient:\x1b[0m $mail\n\n"
printf "\x1b[32;1;4mSubject:\x1b[0m Abuse against: $ip - Brute Force\n\n"
cat /tmp/abusemail
printf "\n\n"

while true
do
 printf "\x1b[33;1;4mSend Abuse Mail? [Y/n]\x1b[0m\n"
 read -r input

 case $input in
     [yY][eE][sS]|[yY])
 cat /tmp/abusemail | /usr/local/bin/mailx -s "Abuse against: $ip - Brute Force" -r "My Name " -b $bcc $mail
 printf "Abuse Mail is on it's way..."
 break
 ;;
     [nN][oO]|[nN])
 printf "Abuse Mail aborted"
 break
        ;;
     *)
 printf "Invalid input..."
 ;;
 esac
done

Das Script ist alt, stumpf und einfach. Es tut genau das, was es soll: Arbeit abnehmen bei einer Aufgabe, die sich meistens sowieso nicht lohnt. Wer das Thema automatisierter weitertreiben will, kann sich mal SSH-Bruteforce und AbuseIPDB anschauen. Dort geht es darum, wie Fail2Ban und AbuseIPDB zusammenspielen.

Fazit

Abuse-Mails sind undankbar. Die meisten verpuffen, manche helfen. Wer trotzdem ab und zu eine rausschicken will, ohne jedes Mal alles von Hand zusammenzusuchen, hat mit so einem Script zumindest den Aufwand minimiert.

Fragen? Einfach melden.

Rspamd: Automatisches Spam/Ham-Lernen mit Dovecot und IMAPSieve

Rspamd hat ein Webinterface. Da kann man E-Mails reinkopieren und als Spam oder Ham markieren. Klingt erstmal praktisch. Ist es aber nicht. Niemand kopiert ernsthaft den Quellcode jeder fehlklassifizierten Mail in ein Webformular. Das macht man einmal zum Testen und dann nie wieder.

Automatisches Spam-Training mit Rspamd über Dovecot IMAPSieve – Mail wird zwischen Inbox und Junk verschoben

Was man eigentlich will: Wenn ein Benutzer eine Mail in den Junk-Ordner verschiebt, soll rspamd das automatisch als Spam lernen. Und wenn eine Mail aus dem Junk-Ordner rausgeholt wird, soll rspamd sie als Ham lernen. Kein Webinterface, kein manueller Eingriff. Der Benutzer sortiert einfach seine Mails — und rspamd lernt mit.

Genau das geht mit Dovecot und IMAPSieve. Hier beschreibe ich, wie ich das bei mir eingerichtet habe. Die Konfiguration läuft seit Mai 2020 unverändert — über sechs Jahre, ohne eine einzige Anpassung. Das darf man ruhig als stabil bezeichnen.

Was passiert da eigentlich

Der Datenfluss ist simpel:

  • Benutzer verschiebt eine Mail in den Ordner „Junk“
  • Dovecot erkennt die Verschiebung per IMAPSieve
  • IMAPSieve startet ein Sieve-Script
  • Das Sieve-Script ruft ein Shell-Script auf
  • Das Shell-Script übergibt die Mail per rspamc an rspamd
  • Rspamd lernt die Mail als Spam (Bayes-Klassifikator)

In die andere Richtung genauso: Mail raus aus Junk, Dovecot erkennt es, rspamd lernt Ham. Egal ob der Benutzer über Thunderbird, Roundcube, ein Smartphone oder was auch immer sortiert — solange es IMAP ist, greift das.

Voraussetzungen

  • Dovecot mit Sieve-Support (dovecot-pigeonhole unter FreeBSD, dovecot-sieve unter Debian/Ubuntu)
  • Rspamd mit laufendem Controller-Worker
  • rspamc CLI-Tool (kommt mit rspamd mit)

Mein Setup läuft auf FreeBSD. Die Pfade beginnen daher mit /usr/local/. Unter Linux ist es /etc/dovecot/ statt /usr/local/etc/dovecot/ und /usr/lib/dovecot/ statt /usr/local/libexec/dovecot/. Ansonsten ist alles identisch.

Mein rspamd läuft in einer eigenen Jail und lauscht auf 127.0.0.3:11334. Wer rspamd lokal auf dem gleichen System hat, nimmt stattdessen 127.0.0.1:11334 oder den Unix-Socket.

Dovecot konfigurieren

Zuerst muss das Sieve-Plugin für IMAP aktiviert werden.

20-imap.conf:

protocol imap {
  mail_plugins = $mail_plugins sieve
}

Dann die IMAPSieve-Konfiguration. Hier wird festgelegt, welche Ordner-Aktionen welches Sieve-Script auslösen.

90-plugin.conf:

plugin {
  sieve_plugins = sieve_imapsieve sieve_extprograms

  # Wenn eine Mail in den Junk-Ordner kopiert oder dort ein Flag geaendert wird
  imapsieve_mailbox1_name = Junk
  imapsieve_mailbox1_causes = COPY FLAG
  imapsieve_mailbox1_before = file:/usr/local/etc/dovecot/sieve/report-spam.sieve

  # Wenn eine Mail AUS dem Junk-Ordner woanders hin verschoben wird
  imapsieve_mailbox2_name = *
  imapsieve_mailbox2_from = Junk
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_before = file:/usr/local/etc/dovecot/sieve/report-ham.sieve

  sieve_pipe_bin_dir = /usr/local/libexec/dovecot

  sieve_global_extensions = +vnd.dovecot.pipe
}

Zwei Trigger: Einer für „Mail landet im Junk“ (→ Spam lernen), einer für „Mail verlässt Junk“ (→ Ham lernen). COPY deckt Verschieben ab, FLAG fängt den Fall ab, dass ein Mail-Client den Junk-Status per Flag statt per Verschieben setzt.

Sieve-Scripts

Jetzt die beiden Sieve-Scripts, die von IMAPSieve aufgerufen werden.

report-spam.sieve — wird ausgelöst, wenn eine Mail im Junk-Ordner landet:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "imap4flags"];

if environment :is "imap.cause" "COPY" {
    pipe :copy "sa-learn-spam.sh";
}

# Beantworteten oder weitergeleiteten Spam ebenfalls lernen
elsif anyof (allof (hasflag "\\Answered",
                    environment :contains "imap.changedflags" "\\Answered"),
             allof (hasflag "$Forwarded",
                    environment :contains "imap.changedflags" "$Forwarded")) {
    pipe :copy "sa-learn-spam.sh";
}

Der erste Block fängt das normale Verschieben ab. Der zweite Block ist für einen Sonderfall: Wenn jemand auf eine Mail im Junk-Ordner antwortet oder sie weiterleitet, ändert sich das Flag — und auch das sollte als Spam gelernt werden.

report-ham.sieve — wird ausgelöst, wenn eine Mail den Junk-Ordner verlässt:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

if environment :matches "imap.mailbox" "*" {
  set "mailbox" "${1}";
}

if string "${mailbox}" [ "Trash", "train_ham", "train_prob", "train_spam" ] {
  stop;
}

pipe :copy "sa-learn-ham.sh";

Hier passiert etwas Wichtiges: Bevor die Mail als Ham gelernt wird, prüfen wir wohin sie verschoben wurde. Wenn sie im Papierkorb landet, war das vermutlich kein „Das ist kein Spam“ sondern ein „Ich lösche den Spam“. Deshalb: stop; für Trash und die Trainingsordner. Nur wenn die Mail in einen echten Ordner verschoben wird, ist es ein Ham-Signal.

Beide Scripts müssen kompiliert werden:

sievec /usr/local/etc/dovecot/sieve/report-spam.sieve
sievec /usr/local/etc/dovecot/sieve/report-ham.sieve

Shell-Scripts für rspamc

Die Sieve-Scripts rufen Shell-Scripts auf, die die Mail per rspamc an rspamd übergeben. Simpel — jeweils ein Einzeiler.

/usr/local/libexec/dovecot/sa-learn-spam.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_spam

/usr/local/libexec/dovecot/sa-learn-ham.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_ham

Die Dateinamen sa-learn-* kommen historisch von SpamAssassin. Verwirrend, wenn man rspamd nutzt. Man könnte sie auch rspamd-learn-spam.sh nennen — funktional ist es egal. Ich habe sie so gelassen, weil man funktionierende Dinge nicht anfasst.

Beide ausführbar machen:

chmod +x /usr/local/libexec/dovecot/sa-learn-spam.sh /usr/local/libexec/dovecot/sa-learn-ham.sh

Wer rspamd lokal laufen hat, ersetzt 127.0.0.3 durch 127.0.0.1 oder nutzt den Unix-Socket (-h /var/run/rspamd/rspamd.sock). Unter Linux liegen die Scripts in /usr/lib/dovecot/ statt /usr/local/libexec/dovecot/. Der Pfad in sieve_pipe_bin_dir muss natürlich dazu passen.

Wichtig: Damit rspamc ohne Passwort trainieren darf, muss die IP im rspamd Controller-Worker als vertrauenswürdig eingetragen sein. In /usr/local/etc/rspamd/local.d/worker-controller.inc (FreeBSD) bzw. /etc/rspamd/local.d/worker-controller.inc (Linux):

secure_ip = "127.0.0.0/8";
secure_ip = "::1";

Ohne das schlägt rspamc learn_spam mit einem Authentifizierungsfehler fehl. Bei Jail-Setups wie meinem muss die Jail-IP (127.0.0.3) in der Liste stehen.

Testen

Dovecot neu laden:

service dovecot reload

Dann eine beliebige Mail in den Junk-Ordner verschieben und im rspamd-Log nachschauen:

rspamd_controller_learn_fin_task: <127.0.0.3> learned message as spam: MESSAGE-ID

Mail wieder raus aus Junk in den Posteingang:

rspamd_controller_learn_fin_task: <127.0.0.3> learned message as ham: MESSAGE-ID

Wenn das im Log steht, funktioniert alles. Kein Neustart nötig, kein Cache-Flush, kein Warten.

Wie viel Training braucht rspamd

Rspamd nutzt einen Bayes-Klassifikator. Der braucht eine Mindestmenge an gelernten Nachrichten, bevor er aktiv wird. Die Standardeinstellung ist 200 — also mindestens 200 Spam-Mails und 200 Ham-Mails. Vorher ignoriert rspamd die Bayes-Ergebnisse komplett.

Das klingt nach viel, geht aber schneller als man denkt. Wer ein paar Dutzend Benutzer auf dem Server hat, kommt da in wenigen Wochen hin. Und danach wird rspamd mit jeder sortierten Mail ein bisschen besser.

Den aktuellen Stand kann man jederzeit prüfen:

rspamc stat

Unter Statfile sieht man wie viele Nachrichten rspamd bereits gelernt hat.

Rspamd trainiert standardmäßig einen globalen Bayes-Klassifikator — alle Benutzer lernen in denselben Pool. Wer das pro Benutzer trennen will, setzt in der classifier-bayes.conf:

per_user = true;

Für die meisten Setups mit einer Handvoll Domains ist der globale Pool sinnvoller — mehr Trainingsdaten, schneller gute Ergebnisse.

Hinweise

Die Konfiguration ist stabil — Dovecot-Updates, rspamd-Updates, FreeBSD-Upgrades, alles durchgelaufen ohne Anpassung.

Wer rspamd danach noch eine Stufe weiter bringen will: Ich habe einen eigenen Beitrag geschrieben, wie man GPT-basierte Spam-Erkennung in rspamd integriert. Das läuft zusätzlich zum Bayes-Klassifikator und fängt die Mails ab, die durch das statistische Netz rutschen.

Siehe auch: Postfix und AMaViS: content_filter oder smtpd_proxy_filter?, DMARC-Prüfung in Postfix: OpenDMARC und rspamd im Vergleich

Fragen? Schreib mir über die Kontaktseite.

« Ältere Beiträge Neuere Beiträge »

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑