Mikrotik: mDNS Repeater als Docker-Container auf dem Router (ARM,ARM64,X86)
![Mikrotik: mDNS Repeater als Docker-Container auf dem Router (ARM,ARM64,X86) article-picture](/images/c/2023/03/24/81317105046_article.jpg)
Inhaltsverzeichnis
Einleitung
mDNS Repeating (Multicast DNS) auf Mikrotik Routern, ein hier oft nachgefragtes Feature, ist zur Zeit der Anleitung noch kein Bestandteil von RouterOS (Mikrotik arbeitet aber offensichtlich bereits daran). Da aber seit einiger Zeit für einige CPU-Architekturen ein Docker-Paket für RouterOS 7 existiert, habe ich ein Docker Image basierend auf der Vorlage dieses Github Repos für den Betrieb direkt auf dem Router gebaut welches mDNS Multicast-Pakete zwischen zwei oder mehr VLANs vermittelt. Damit wird das VLAN übergreifende Bekanntmachen vieler Gerätschaften ermöglicht welche sich normalerweise per mDNS über die Link Local Multicast-Adresse 224.0.0.251 via UDP Port 5353 nur in ihrer eigenen Layer-2 Broadcast-Domain zu erkennen geben. Der Container basiert auf einem sehr Ressourcen sparenden Alpine Linux und das Repeating übernimmt ein mit C programmierter Daemon von Darell Tan.
Ich habe das ganze dann noch in dem Sinne erweitert, dass sich die VLANs über eine Umgebungsvariable des Mikrotik leichter ändern lassen. Zudem stelle ich ein Mikrotik-Script bereit welches die komplette Interface-Einrichtung und das Anlegen des Containers für den Laien automatisiert.
In der Anleitung und im weiter unten bereitgestellten Mikrotik-Skript für die Einrichtung gehe ich davon aus, dass man ein aktuelles VLAN-Setup per "VLAN-Filtering" in einer VLAN-Bridge betreibt, so wie es auch @aqui in seiner Anleitung Mikrotik VLAN Konfiguration ab RouterOS Version 6.41 hier im Forum zeigt.
Kompatibilität/Verfügbarkeit von Docker-Containern auf Mikrotik Routern
Zur Zeit kommen für den Betrieb von Docker-Containern auf RouterOS nur drei Architekturen in Frage
- ARM
- ARM64
- x86 (z.B. CHR)
Das wären zum Zeitpunkt der Anleitung folgende Modelle (Auszug, ohne Anspruch auf Vollständigkeit)
- RB3011UiAS-RM
- RB4011iGS+RM
- RB5009UG+S+IN /RB5009UPr+S+IN
- RB1100AHx4
- CCR2004-16G-2S+PC / CCR2004-16G-2S+ / CCR2004-1G-12S+2XS / CCR2116-12G-4S+ / CCR2216-1G-12XS-2XQ / CCR2004-1G-2XS-PCIe
- CRS305-1G-4S+IN / CRS310-1G-5S-4S+IN / CRS326-24G-2S+IN / CRS309-1G-8S+IN / CRS328-4C-20S-4S+RM / CRS317-1G-16S+RM
- netPower 15FR / netPower 16P / FiberBox Plus / netFiber 9
- und sämtliche Hardware auf die sich die x86-Variante von RouterOS installieren lässt.
Benötigte Hardware-Ressourcen
RAM: Zum vernünftigen Betrieb empfiehlt sich ein Router mit mindestens 128MB RAM
Festplatten-Speicher: Der Container selbst begnügt sich je nach Architektur entpackt mit ca. 10 - 15MB.
Sollte das eigene Gerät bspw. nur über 16MB Flash verfügen aber einen USB Port lässt sich das Rootverzeichnis des Containers auch drauf ablegen. Des weiteren hat man ab RouterOS 7.7 auch die Möglichkeit eine RAM-Disk zu erstellen mit der sich ein Teil des Hauptspeichers als Datenablage nutzen lässt.
https://help.mikrotik.com/docs/display/ROS/Disks#Disks-AllocateRAMtofold ...
/disk add type=tmpfs tmpfs-max-size=50M slot=myRamDisk
Container Package auf dem Router installieren
Verfügbar ist das Container-Package seit RouterOS v7.4beta4. Es wird in den Mikrotik-Downloads unter dem Topic Extra Package für eine der oben genannten Architekturen zum Download bereitgestellt.
Aus dem heruntergeladenen ZIP-File extrahiert man nun die Datei container-7.x.npk (das "x" steht für die aktuell verfügbare Version) und schiebt diese nun entweder per Drag n' Drop in die Winbox-Oberfläche oder überträgt die Datei per FTP/SFTP in das Hauptverzeichnis des Routers.
Zum Abschließen der Installation muss der Router zwingend einmal neu gestartet werden. Danach ist das Feature in Winbox unter dem Punkt Container in der linken Navigation verfügbar.
![screenshot - 92862f9a314418e0e558be406766c9e2 screenshot](/images/c/2023/03/24/92862f9a314418e0e558be406766c9e2.jpg)
Container installieren
Für all diejenigen die sich den Container nicht selbst bauen können/möchten habe ich drei fertige Docker-Images vorbereitet die ihr euch hier herunterladen könnt:
(Build-Datum 03-2023)
Wer sich die Container aus den Sourcen selbst bauen möchte findet weiter unten die Sourcen und Anweisungen zum Build-Vorgang.
Das für eure Architektur passende Image kopiert ihr euch nun in das Hauptverzeichnis auf den Router (wieder per Drag n' Drop in die Winbox oder per FTP/SFTP).
Variante A : Automatische Einrichtung über ein Mikrotik-Skript
Für die Einrichtung inkl. der nötigen Interfaces und Zuweisung zur VLAN-Bridge habe ich ein Mikrotik-Skript geschrieben welches euch die Arbeit dafür abnimmt. Es ist einmalig nach dem Kopieren des Images auf dem Router in einem Terminal auszuführen. Wer lieber alle Einstellungen selbst vornehmen möchte, kann sich nach der Variante B im nächsten Punkt richten und diesen Schritt überspringen.
Im Skript anzupassen sind die nachfolgend genannten Variablen im Kopf des Skriptes:
Variable | Beschreibung |
---|---|
BRIDGENAME | Name der verwendeten VLAN-Bridge in der die VLANs Interfaces Member sind |
VETHNAME | Diesen Namen bekommt das neue virtuelle Netzwerk-Interface zum Container |
HOSTNAME | Hostname des Containers |
VLANS | Ein Array aus VLAN-IDs in die man die mDNS Paktete fluten möchte (Semikolon getrennt) |
IMAGENAME | Dateiname des Docker-Images mit dem man diesen auf dem Router kopiert hat |
CONTAINERROOT | Ordner in dem die Daten des Containers auf dem Router abgelegt werden |
Für das virtuelle Netzwerk-Interface des Containers verwende ich im Skript ein auf dem Router nicht genutztes Subnetz (172.19.19.0/24), da dieses für den Container nicht benötigt wird, sollte das genutzte Subnetz bei euch schon zum Einsatz kommen ändert es und die GW Adresse auf ein bei euch nicht benutztes Subnetz in folgender Zeile des Skriptes ab:
/interface veth add address=172.19.19.2/24 gateway=172.19.19.1 name=mDNSTrunk
{
# name of bridge to add veth interface to
:local BRIDGENAME "bridgeLocal"
# name the veth interface will get
:local VETHNAME "mDNSTrunk"
# set hostname of container
:local HOSTNAME "mDNS"
# set vlan-ids to reflect traffic between
:local VLANS {100;200}
# define image filename
:local IMAGENAME "mdns_x86.tar"
# path to data root for the container
:local CONTAINERROOT "docker/container/mdns_repeater"
# -------------------------------
# variable holds all vlans seperated by spaces
:local ALLVLANS ""
# check bridge existance
:if ([:len [/interface bridge find name="$BRIDGENAME"]] = 0) do={
:put "Could not find a bridge with name '$BRIDGENAME' !"
:quit
}
# add veth interface
:if ([:len [/interface veth find name="$VETHNAME"]] = 0) do={
# add veth interface
/interface veth add address=172.19.19.2/24 gateway=172.19.19.1 name=$VETHNAME
}
# add veth interface to bridge
:if ([:len [/interface bridge port find interface=$VETHNAME]] = 0) do={
/interface bridge port add interface=$VETHNAME bridge=$BRIDGENAME
}
# for each vlan id
:foreach id in=$VLANS do={
# find existing vlan entry
:local vlanentry [/interface bridge vlan find vlan-ids ~ "(^|;)$id(;|\$)" and bridge=$BRIDGENAME]
:if ([:len $vlanentry] = 0) do={
# if entry does not exist add it to vlan list
/interface bridge vlan add bridge=$BRIDGENAME tagged="$BRIDGENAME,$VETHNAME" vlan-ids=$id
} else={
# if entry exists and veth interface is not a tagged member append veth interface to vlan as tagged interface
:if ([:len [/interface bridge vlan find vlan-ids=$id and current-tagged ~ "$VETHNAME"]] = 0) do={
/interface bridge vlan set $vlanentry tagged=([get $vlanentry tagged],"$VETHNAME")
}
}
# build ALLVLAN variable
:if ($ALLVLANS != "") do={
:set ALLVLANS ($ALLVLANS . " " . $id)
} else={
:set ALLVLANS $id
}
}
# add container environment variable wich defines the vlans used
:if ([:len [/container envs find name=mdns key=VLANS]] = 0) do={
/container envs add name=mdns key=VLANS value=$ALLVLANS
}
# finally add container
:if ([:len [/container find root-dir="$CONTAINERROOT"]] = 0) do={
/container add file=$IMAGENAME envlist=mdns logging=yes start-on-boot=yes root-dir="$CONTAINERROOT" interface=$VETHNAME hostname=$HOSTNAME
} else={
:put "Container already exists, please delete it beforehand and run again!"
}
}
Über Winbox:
Oder über die Konsole:
/container print
Des weiteren sollte nun eine Docker-Umgebungsvariable mit dem Namen VLANS angelegt sein in welcher die oben angegebenen VLAN-IDs mit Leerzeichen von einander getrennt stehen:
Diese Variable bestimmt am Ende die VLAN-IDs welche nach dem Start des Containers per mDNS zusammengeschaltet werden, möchte man also nachträglich die beteiligten VLANs ändern tut man dies hier (Ändert man hier die Interfaces muss das VETH Interface natürlich manuell unter
/interface bridge vlan
tagged in dem jeweiligen VLAN hinzugefügt werden. Der Container muss danach ebenfalls gestoppt und neu gestartet werden).
Variante B : Manuelle Einrichtung
Die nötigen Schritte für eine manuelle Einrichtung des Containers ohne die Nutzung des Skriptes, zeige ich hier anhand von Screenshots in der Winbox.
Als erstes benötigen wir eine neues virtuelles Netzwerkinterface für dem Container (VETH)
Das hier angegebene Subnetz (172.19.19.0/24) muss ein nicht genutzter Adressbereich auf dem Router sein. Effektiv wird dieses Netz im Container nicht genutzt da die Kommunikation ausschließlich über die VLAN getaggten Verbindungen stattfindet, es kann also frei gewählt werden.
Nun fügen wir dieses VETH-Interface unter Bridge > Ports der genutzten Bridge hinzu
Anschließend unter Bridge >VLANs in den VLAN-IDs das VETH-Interface als tagged eintragen
Nun gehen wir in der Winbox in den Abschnitt Container > Envs und fügen eine Container-Umgebungsvariable für die VLANs hinzu. Die VLANs sind dabei mit Leerzeichen voneinander zu trennen.
Abschließend erstellen wir den Container selbst, mit Angabe des vorher auf den Router kopierten Images, des VETH-Interfaces, der angelegten Umgebungsvariablen und einem Ordner in den das Image des Containers entpackt wird.
Container starten
Nun sind wir bereits soweit den Containers zu starten. Dazu den Container in der Winbox auswählen und auf den Start Button klicken:
Über die Konsole (die 0 durch die angezeigte Nummer vor dem Eintrag ersetzen)
/container print
start 0
Am besten man öffnet sich das Log-Fenster und beobachtet dabei die Debug Ausgabe des Containers. Das sollte bei Erfolg dann so aussehen. Im Beispiel werden die VLANs 100 und 200 an den Container angebunden.
Man erkennt das für jede VLAN-ID im Container ein VLAN-Interface angelegt wird über die der getaggte Traffic an den Container übertragen werden. uDHCP holt sich dann aus jedem VLAN per DHCP eine IP und am Ende wird der Repeater-Prozess gestartet.
Shell auf dem Container öffnen
Zum Debugging lässt sich über ein Terminal eine Shell innerhalb des Containers starten. Dazu öffnen wir einen Terminal, lassen uns die Container auflisten, und starten anschließend die Shell
/container print
shell 0
Hier sieht man auch die aktiven Prozesse (Repeater-Prozess und DHCP-Daemons) und die mDNS Listener auf den VLAN-Interfaces innerhalb des Containers
Um die Container-Shell wieder zu verlassen drücke man
STRG+D
.
Firewall
Wurde das Setup oben erfolgreich durchlaufen und geprüft das sich die Geräte aus den VLANs übergreifend bekannt machen, war das nur der erste Schritt, da ja erst einmal nur die mDNS-Pakete in die beteiligten VLANs geflutet werden. Da die meisten Benutzer für die Trennung der VLANs natürlich die Firewall nutzen, muss der Traffic zwischen den gewünschten Geräten erst zugelassen werden, sofern er per Default in eurer Firewall-Config blockiert wird.Da das Firewall-Regelwerk bei jedem anders aufgebaut ist, kann ich hier nur Rezepte an die Hand geben, die ihr an eure Anforderungen anpassen könnt. Wenn Ihr, wovon ich ausgehe, eine Statefull Firewall Konfiguration mit "related/established" Regelwerk einsetzt muss die Regel auch immer nur in eine Richtung angelegt werden, die Rückroute für eine Verbindung ist dann automatisch durchgängig.
Beispiel: Zulassen von User mit IP 192.168.100.50 in VLAN100 auf Port 80 eines Gerätes mit der IP 192.168.200.60 in VLAN200
/ip firewall filter add chain=forward place-before=0 src-address=192.168.100.50 dst-address=192.168.200.60 in-interface=vlan100 out-interface=vlan200 protocol=tcp dst-port=80 action=accept
/ip firewall filter add chain=forward place-before=0 src-address=192.168.100.50 dst-address=192.168.200.0/24 in-interface=vlan100 out-interface=vlan200 action=accept
Docker Images selbst bauen
Wer sich den Container selbst bauen möchte, für den habe ich hier ein tar-Archiv vorbereitet.
Download mDNS Container Sourcen
Zum Bauen der Container ist ein installiertes Docker mit "dockerx" Erweiterung Voraussetzung.
Das Archiv enthält ein Skript mit welchem man die gewünschte Architektur bauen kann. Die Architektur wird dem Skript als erster Parameter mitgegeben:
sudo ./build_image.sh x86
sudo docker run --privileged --rm docker/binfmt:a7996909642ee92942dcd6cff44b9b95f08dad64
Nun viel Erfolg und Spaß beim Nachmachen.
Gruß @colinardo
Please also mark the comments that contributed to the solution of the article
Content-ID: 6478580736
Url: https://administrator.de/contentid/6478580736
Printed on: September 1, 2024 at 01:09 o'clock
16 Comments
Latest comment
Die meisten Netzdienste wie Drucker, NAS, Medienserver usw. announcen ihre Dienste fast ausnahmslos über mDNS damit Endgeräte diese automatisiert finden. mDNS nutzt eine Link local Multicast Adresse 224.0.0.251 mit UDP Port 5353 und einem festen TTL von 1 und ist damit unroutebar. Sprich es kann ohne Weiteres nicht in andere Netzwerk Segmente übertragen werden.
Das ist insofern fatal in segmentierten Netzen (VLANs) oder auch in einem VPN Umfeld, da Clients diese Dienste in anderen IP Netzen dann gar nicht oder nur schwer erreichen können. Professionelle Geräte haben für sowas oftmals einen mDNS Proxy an Bord. Nichts anderes ist die o.a. Lösung auch. SoHo Hardware hat solch ein Feature eher weniger.
Übel und unsicher ist das keineswegs, denn es sind ja nur UDP Multicast Frames die die IP Adressen dieser Dienste bekannt geben. Nicht mehr und nicht weniger. Microsoft ist da mit seinem SSDP Protokoll deutlich geschwätziger und nutzt ähnliche Mechanismen.
Ein immer wieder nachgefragtes Feature im Forum und Dank an @colinardo für diese elegante Lösung mit Mikrotik Hardware!
Das ist insofern fatal in segmentierten Netzen (VLANs) oder auch in einem VPN Umfeld, da Clients diese Dienste in anderen IP Netzen dann gar nicht oder nur schwer erreichen können. Professionelle Geräte haben für sowas oftmals einen mDNS Proxy an Bord. Nichts anderes ist die o.a. Lösung auch. SoHo Hardware hat solch ein Feature eher weniger.
Übel und unsicher ist das keineswegs, denn es sind ja nur UDP Multicast Frames die die IP Adressen dieser Dienste bekannt geben. Nicht mehr und nicht weniger. Microsoft ist da mit seinem SSDP Protokoll deutlich geschwätziger und nutzt ähnliche Mechanismen.
Ein immer wieder nachgefragtes Feature im Forum und Dank an @colinardo für diese elegante Lösung mit Mikrotik Hardware!
Danke für diese vorzügliche Arbeit. Wird demnächst sicher umgesetzt.
Insbesondere die Apple-Jünger-Kunden werden sich darüber freuen! Wenn man kein mDNS hat, merkt man erst, wie "dumm" die doch sonst so smarten Apple-Geräte sind![face-big-smile face-big-smile](/images/icons/fa/light/face-laugh.svg)
Spart einen Raspberry Pi ein, dient also auch der Nachhaltigkeit![face-smile face-smile](/images/icons/fa/light/face-smile.svg)
Viele Grüße, commodity
P.S.: @colinardo, packst Du das auch ins Mikrotik-Forum? Da würden sich sicher einige drüber freuen.
Insbesondere die Apple-Jünger-Kunden werden sich darüber freuen! Wenn man kein mDNS hat, merkt man erst, wie "dumm" die doch sonst so smarten Apple-Geräte sind
Spart einen Raspberry Pi ein, dient also auch der Nachhaltigkeit
Viele Grüße, commodity
P.S.: @colinardo, packst Du das auch ins Mikrotik-Forum? Da würden sich sicher einige drüber freuen.
genialer Artikel - hat mir sehr weitergeholfen.
Dummer Weise war das Problem aber nicht mDNS, sondern DLNA (also SSDP) - das repeatet der Container nicht. Ich habe bei Github aber einen anderen Container gefunden:
bonjour-reflector
Das klingt zwar erst mal nach Apple, aber dieser "Reflektor" kann wirklich auch SSDP - auch wenn in der Beschreibung ständig nur die Rede von mDNS ist.
Bitte schlagt mich jetzt nicht, von wegen "SSDP wäre geschwätzig" o.ä. - ich kann auch nix dafür, dass manche (viele) Hersteller das benutzen.
Dummer Weise war das Problem aber nicht mDNS, sondern DLNA (also SSDP) - das repeatet der Container nicht. Ich habe bei Github aber einen anderen Container gefunden:
bonjour-reflector
Das klingt zwar erst mal nach Apple, aber dieser "Reflektor" kann wirklich auch SSDP - auch wenn in der Beschreibung ständig nur die Rede von mDNS ist.
Bitte schlagt mich jetzt nicht, von wegen "SSDP wäre geschwätzig" o.ä. - ich kann auch nix dafür, dass manche (viele) Hersteller das benutzen.
Das klingt zwar erst mal nach Apple
Ist Unsinn, denn Bonjour basiert auf dem bekannten mDNS Standard und ist wie SSDP Multicast basierend. Beide nutzen eine Link Local Multicast Adresse mit einem vorgeschriebenen TTL von 1 was sie dann unroutebar macht.AVAHI Proxy oder solche Reflektoren sind dann das Mittel der Wahl.
Series: Mikrotik Docker Container
NPS 802.1x Radius Authentication with EAP-TLS and strong certificate mapping for non domain joined devices1Mikrotik: mDNS Repeater as Docker-Container on the Router (ARM,ARM64,X86)1Mikrotik: mDNS Repeater als Docker-Container auf dem Router (ARM,ARM64,X86) (german)16