UDM Pro 1.x: Netzwerktrennung - Teil 2
Alle Aussagen in diesem Artikel beziehen sich auf die UnifiOS Version 1.10.0 für die UDM Pro und die Unifi Network in Version 6.2.26. Mit jedem Update sowohl von UnifiOS als auch der Network App kann sich das Netzwerk-Setup und die Firewall-Einstellungen grundlegend ändern.
Es gibt eine aktualisierte Version des Artikels in dem eine angepasste Version des Scripts, die mit UnifiOS 3.2.7 kompatibel ist beschrieben wird: UDM Pro 3: Netzwerktrennung - Teil 2.
Da die einzelnen LAN- und Guest-Netzwerke von der Unifi Dream Machine Pro leider nicht konsequent voneinander getrennt werden (siehe Artikel UDM Pro: Netzwerktrennung - Teil 1) muss das Firewall-Regelwerk wohl oder übel etwas angepasst werden, wenn eine Trennung zwischen den einzelnen VLANs umgesetzt werden soll.
01| Voraussetzungen
Da eine Filterung für IPv6 bei dynamischen Prefix über die GUI aktuell nicht zu realisieren ist (siehe UDM Pro: Netzwerktrennung - Teil 1), muss das Firewall-Regelwerk per Script aktualisiert werden. Es muss also sichergestellt werden, dass das Script beim Boot der Unifi Dream Machine automatisch ausgeführt wird. Dies lässt sich mit dem dem UDM / UDMPro Boot Script von boostchicken realisieren. Daher muss dieses Tool zunächst installiert werden. Die Installationsanleitung findet sich auf der Github-Seite oder in meinem Artikel UDM Pro: NAT auf dem WAN Interface deaktivieren.
Aber die Ausführung beim Boot alleine ist nicht ausreichend, da mit jeder Änderung am Firewall-Regelwerk per GUI die alten Regeln gelöscht werden. Daher erzeugt das Script zusätzlich einen Cron-Job, der alle zwei Minuten das Script erneut ausführt, so dass die Regeln wieder eingefügt werden, wenn sie fehlen.
02| Script installieren und ausführen
Ist sichergestellt, dass das UDM / UDMPro Boot Script von boostchicken korrekt installiert ist und un funktioniert, so muss nur noch das Script 21-separate-vlans.sh von https://github.com/nerdiges/udmp-seperate-vlans im on_boot
-Verzeichnis abgelegt und initial ausgeführt werden. Die Installation des SCriptes ist daher mit wenigen Befehlen umgesetzt:
# 1. download file to directory /mnt/data/on_boot.d
curl -o /mnt/data/on_boot.d/21-separate-vlans.sh https://raw.githubusercontent.com/nerdiges/udmp-seperate-vlans/main/21-separate-vlans.sh
# 2. make script executable
chmod +x /mnt/data/on_boot.d/21-separate-vlans.sh
# 3. run script to add missing firewall rules and to create cron job
/mnt/data/on_boot.d/21-separate-vlans.sh
03| Hinweise zum Script
Das Script 21-separate-vlans.sh enthält einige Kommentare, die die Funktionsweise grundsätzlich erklären. Ergänzend dazu hier noch ein paar Hinweise zum Aufbau des Scriptes:
03.1| Erzeugte iptables Chains
Damit die Firewall-Regeln des Scripts sauber von den internen Regeln getrennt werden legt das Script zwei neue iptables-Chains an:
Chain | Beschreibung |
lan_separation | In dieser Chain werden die REJECT-Regeln zur Separierung der guest-Netzwerke hinterlegt. |
guest_separation | In dieser Chain werden die REJECT-Regeln zur Separierung der guest-Netzwerke hinterlegt. |
03.2| Erzeugte Firewall-Regeln
Das Script erzeugt insgesamt fünf unterschiedliche Typen von Firewall-Regeln:
03.1.1| Allow Established & Related
Damit später gezielte Verbindungen zwischen den einzelnen VLANs freigegeben werden können, sollten alle eingehenden Pakete zugelassen werden, die einer bestehenden Verbindung zugeordnet werden können. Daher sollten alle Pakete mit dem Status Established oder Related an den LAN und Guest Interfaces zugelassen werden. Dies kann entweder manuell in der GUI eingetragen werden oder automatisch vom Script eingefügt werden. Da in der Regel die meisten Pakete einer bereits bestehenden Verbindung zugeordnet werden können, sollten die entsprechenden Regeln möglichst weit vorne im iptables
Regelwerk eingetragen werden, um die Firewall-Performance zu verbessern. Mit dem folgenden Code wird daher im Script sichergestellt, dass die Regeln für die LAN-Interfaces in der Standard-Chain UBIOS_LAN_IN_USER
an erster Stelle eingetragen werden:
# add allow related/established to UBIOS_LAN_IN_USER if requested
if [ $allow_related_lan == "true" ]; then
rule="-A UBIOS_LAN_IN_USER -m conntrack --ctstate RELATED,ESTABLISHED.*-j RETURN"
iptables --list-rules | grep -e "$rule" &> /dev/null ||
iptables -I UBIOS_LAN_IN_USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
ip6tables --list-rules | grep -e "$rule" &> /dev/null ||
ip6tables -I UBIOS_LAN_IN_USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
fi
Hinweis: Ob die Established & Related-Regeln vom Script automatisch erzeugt werden, kann über die Variablen allow_related_lan
und allow_related_guest
festgelegt werden. Per Default sind diese aktiviert, so dass das Script sicherstellt, dass entsprechende Regeln vorhanden sind. Um doppelte Regeln zu vermeiden, fügt das Script nur dann eine entsprechende Regel ein, wenn nicht bereits über die GUI eine Regel hinzugefügt wurde.
03.1.2| LAN > LAN Reject
Für jedes LAN-Interface werden Regeln erzeugt, die eine Kommunikation zu anderen LAN-Interfaces unterbinden (REJECT-Regeln). Ausgenommen werden allerdings die Interfaces, die in der Variable $exclude
aufgelistet sind. Zusammen mit der Regel Allow Established & Related
(s.o.) führt das dazu, dass aus diesen Netzwerk-Segmenten auf alle anderen LAN-Netzwerke ungefiltert zugegriffen werden kann. Die entsprechenden Regeln werden in einer For-Schleife automatisch erzeugt:
# Add rules to separate LAN-VLANs to chain lan_separation
for i in $lan_if; do
case "$exclude " in
*"$i "*)
logger "$me: Excluding $i from VLAN separation as requested in config."
;;
*)
for o in $lan_if; do
if ! [ "$i" == "$o" ]; then
rule="-A lan_separation -i $i -o $o -j REJECT"
iptables --list-rules | grep -e "$rule" &> /dev/null || iptables $rule
ip6tables --list-rules | grep -e "$rule" &> /dev/null || ip6tables $rule
fi
done
;;
esac
done
Existieren beispielsweise vier Corporate-Networks mit den VLANs 0-3 und soll die Kommunikation aus VLAN 1 in alle anderen Netzwerke ermöglicht werden, so muss lediglich das zugehörige Interface br1
in der Exclude-Variablen aufgenommen werden (exclude="br1"
). Die erzeugten VLAN-Regeln sollten danach so aussehen:
-A lan_separation -i br0 -o br1 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br0 -o br2 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br0 -o br3 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br2 -o br0 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br2 -o br1 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br2 -o br3 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br3 -o br0 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br3 -o br1 -j REJECT --reject-with icmp-port-unreachable
-A lan_separation -i br3 -o br2 -j REJECT --reject-with icmp-port-unreachable
03.1.3| Guest > Guest Reject
Vergleichbar zur Trennung der LAN-Segmente, werden auch die Guest-Netzwerke voneinander getrennt. Diese Regeln werden allerdings in der Chain guest_separation
eingetragen. Auch für die Guest-Netzwerke gilt: Wird ein Guest-Interface in die Exclude Liste aufgenommen, so wird es von der Filterung ausgenommen.
03.1.4| LAN > Guest Reject
Bei der Analyse der Firewall-Regeln im ersten Teil der Artikelserie habe ich festgestellt, dass einzelne Pakete aus dem LAN-Netzwerk in das Guest-Netzwerk gelangen können, da die Standard Firewall-Regeln zwar den Datenverkehr aus dem Guest-Netzwerk in Richtung LAN-Netzwerk blockieren, aber eben nicht umgekehrt. TCP-SYN, UDP oder ICMP-Pakete die aus dem LAN-Netzwerk in Richtung Guest gesendet werden, kommen jedoch durch. Um das zu verhindern werden entsprechende REJECT-Regeln in der Chain lan_separation
hinterlegt:
# add rules to fix packet leakage from LAN > guest
for i in $lan_if; do
for o in $guest_if; do
rule="-A lan_separation -i $i -o $o -j REJECT"
iptables --list-rules | grep -e "$rule" &> /dev/null || iptables $rule
ip6tables --list-rules | grep -e "$rule" &> /dev/null || ip6tables $rule
done
done
03.1.5| Regeln zur Einbindung der Custom-Chains
Nachdem die Firewall-Regeln zur VLAN-Trennung in den Chains lan_spearation
und guest_separation
eingefügt wurden, werden entsprechende JUMP-Regeln in die Chains UBIOS_LAN_IN_USER
und UBIOS_GUEST_IN_USER
eingefügt. Dabei wird vom Script automatisch die richtige Position für die JUMP-Regeln ermittelt, so dass die Regeln direkt vor den jeweiligen ALLOW-Regeln des Standard-Regelwerks eingefügt werden. Für die IPv4-Regeln zur LAN-Trennung sieht das im Script so aus:
# add IPv4 rule to include rules in chain lan_separation
if ! iptables --list-rules | grep -e "-A UBIOS_LAN_IN_USER -j lan_separation" &> /dev/null; then
rules=$(iptables -L UBIOS_LAN_IN_USER --line-numbers | awk 'END { print $1 }')
v4_idx=$(expr $rules - $lan_if_count)
iptables -I UBIOS_LAN_IN_USER $v4_idx -j lan_separation
fi
03.3| Keine Kommentare für Firewall-Regeln
Auf der UDM Pro werden die Kommentare der Firewall-Regeln für die Verwaltung genutzt und scheinbar mit einer internen Datenbank abgeglichen. Alle Regeln, die einen unbekannten Kommentar enthalten (iptables
Paramter -m comment
) werden in /var/log/messages
im Sekundentakt Warnmeldungen ausgegeben:
Aug 1 00:19:41 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:42 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:43 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:44 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:46 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:47 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:47 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:49 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Aug 1 00:19:50 udmp user.notice ubios-udapi-server: ubios-udapi-server: Found unexpected rule --comment '0815'
Das führt dazu, dass das Syslog sehr schnell sehr umfangreich wird. Um das zu vermeiden sollte sichergestellt werden, dass alle Firewall-Regeln, die per Script oder manuell per Kommandozeile manuell hinzugefügt werden keinen Kommentar beinhalten.
04| Separierung dauerhaft sicherstellen
Da das Script und der on_boot
-Mechanismus von Unifi offiziell nicht unterstützt werden, besteht mit jedem Firmware-Update das Risiko, dass das Script nach einem Update nicht mehr korrekt funktioniert. Das kann dazu führen, dass nach einem Update die Regeln nicht mehr greifen. Im schlimmsten Falle wird die VLAN-Separierung dann unbemerkt wieder aufgehoben und es kann wieder frei zwischen den VLANs kommuniziert werden. Um das zu unterbinden, verschiedenen Maßnahmen ergriffen werden:
04.1| Ergänzende Firewall-Regeln über die GUI
Die vom Script erzeugten Regeln sollten, so weit möglich, auch in der GUI konfiguriert werden. Zumindest für den IPv4-Datenverkehr kann dies beispielsweise einfach über die jeweiligen IP-Adressbereiche der unterschiedlichen VLANs erfolgen. Werden die Firewall-Regeln vom Script nach einem Update nicht mehr korrekt gesetzt, so wird wenigstens für IPv4 die Trennung weiterhin aufrecht erhalten. Wie aber bereits im ersten Teil beschrieben ist das bei dynamischen IPv6-Prefixen für den IPv6-basierten Datenverkehr leider aktuell nicht möglich.
04.2| Monitoring der Filterung
Ist eine Hausautomatisierung im Einsatz, so kann auch durch VLAN-übergreifende Netzwerktest z.B. per ping
oder nmap
(siehe [04]) regelmäßig überprüft werden, ob die VLAN-Trennung noch aktiv ist. Sind bei einem solchen Test interne Systeme erreichbar, obwohl die Kommunikationsbeziehung nicht explizit freigegeben ist, dann könnte beispielsweise eine Alarmierung per Mail erfolgen.
05| Quelle:
[01] UDM Pro: Netzwerktrennung - Teil 1
[02] https://github.com/nerdiges/udmp-seperate-vlans
[03] UDM / UDMPro Boot Script von boostchicken
[04] https://nmap.org/
[05]
Kommentare