Mikrotik: Lokale Domain mit Namensauflösung für Clients (FQDN)

Die Namensauflösung von Netzwerkteilnehmern ist bei Mikrotik nicht von Haus aus implementiert. Somit gibt es keine richtige lokale Domain, mit der sich Clients ansprechen lassen. Dennoch liefern die Router alles, was wir benötigen, um für jeden Netzwerkteilnehmer dynamisch einen FQDN (Fully Qualified Domain Name) anzulegen und sie darüber auch im Netzwerk erreichbar zu machen. Dafür nutzen wir ein Script, das zu jedem DHCP-Lease einen statischen DNS-Eintrag anlegt und diesen Eintrag auch von selbst wieder entfernt.

Ich setze in diesem Beitrag voraus, dass euer Router grundsätzlich läuft und mit dem Internet verbunden ist. Damit verbunden gehe ich auch davon aus, dass es einen DHCP-Server bei euch gibt, der seinen Job tut.

Inhalt

Meine Netzwerk-Struktur

Als Router verwende ich ein Mikrotik Routerboard RB2011UAS-RM. Darauf läuft ein DHCP-Server, der allen Netzwerkteilnehmern eine IP-Adresse und den DNS-Server zuweist. Der DNS-Server ist Pi-hole, installiert auf einer virtuellen Maschine mit Debian.

DNS-Anfragen nehmen folgenden Weg: Client -> Pi-hole -> Router -> 8.8.8.8

Als IP-Subnetz verwende ich 192.168.243.0/24, wobei der Router die IP-Adresse .1, und Pi-hole .2 besitzt. Meine lokale Domain soll home.local heißen, sodass mein ioBroker-Server unter dem FQDN srv-iobroker1.home.local erreichbar ist.

Die richtige Domain wählen:
Im Prinzip kann man jeden beliebigen Domain-Namen verwenden, den man möchte. Wenn man also eine private Domain besitzt, die im öffentlichen Internet auch erreichbar ist, z.B. domain.com, dann könnte man Zuhause auch die Domain home.domain.com verwenden. Allerdings ist das nicht ganz ohne, daher nehmen wir hier in diesem Beispiel eine Domain-Endung, die die meisten Systeme als nicht öffentlich klassifizieren: .local.

DNS-Settings

Wir beginnen mit den DNS-Settings im Router. In WinBox navigieren wir zu IP -> DNS und prüfen die Einstellungen.

Mikrotik: DNS-Settings

Mikrotik: DNS-Settings

Relevant sind hier zwei Einstellungen. Unter Servers werden die DNS-Server angegeben, die der Router verwenden soll. Das ist zum einen er selbst (für die lokale Domain) und 8.8.8.8, also der DNS-Server von Google, in dem alle öffentlichen Namen nachgeschlagen werden.

Mit Allow Remote Requests gestatten wir allen Netzwerkteilnehmern, DNS-Anfragen beim Router zu stellen. Das ist auch nötig, da der Router die FQDN aller Netzwerkteilnehmer verwaltet.

Über die Schaltfläche OK schließen wir den Dialog.

DHCP-Server

Im Nächsten Schritt passen wir die Konfiguration des DHCP-Servers an. Dazu navigieren wir in WinBox nach IP -> DHCP-Server -> Networks und öffnen die Einstellungen unseres DHCP-Netzwerks. Hier wird definiert, was die Clients per DHCP zugewiesen bekommen. Unter DNS-Servers tragen wir den Server ein, den die Clients nutzen sollen. In meinem Fall ist das der Pi-hole. Solltet ihr keinen separaten DNS-Server verwenden, sondern möchtet, dass die Clients ihre DNS-Anfragen direkt an den Router stellen, so tragt ihr hier die Router-IP ein. Bei mir wäre das 192.168.243.1.

Mit Domain legen wir die lokale Domain an, die viele Clients auch als Such-Domain anzeigen. Wir nennen sie home.local.

Mikrotik: DHCP-Netzwerk

Mikrotik: DHCP-Netzwerk

Nun gehen wir zu IP -> DHCP-Server -> DHCP und öffnen die Eigenschaften des DHCP-Servers. Im Feld Lease Script tragen wir den Namen des Scripts ein, das wir im nächsten Schritt anlegen werden. Der Name kann frei ausgedacht und gewählt werden.

Mikrotik: DHCP-Server

Mikrotik: DHCP-Server

Lease-Script

Das Lease-Script habe ich im Mikrotik-Forum gefunden und im Prinzip übernimmt es die ganze Arbeit. Unter System -> Scripts legen wir ein neues Script an, geben ihm den Namen, den wir uns gerade ausgedacht haben und kopieren folgenden Code in das Source-Feld:

:local DHCPtag
:set DHCPtag "#DHCP"

:if ( [ :len $leaseActIP ] <= 0 ) do={ :error "empty lease address" }

:if ( $leaseBound = 1 ) do=\
{
    :local ttl
    :local domain
    :local hostname
    :local fqdn
    :local leaseId
    :local comment

    /ip dhcp-server
    :set ttl [ get [ find name=$leaseServerName ] lease-time ]
    network 
    :set domain [ get [ find $leaseActIP in address ] domain ]

    .. lease
    :set leaseId [ find address=$leaseActIP ]

    # Check for multiple active leases for the same IP address. It's weird and it shouldn't be, but just in case.

    :if ( [ :len $leaseId ] != 1) do={
        :log info "DHCP2DNS: not registering domain name for address $leaseActIP because of multiple active leases for $leaseActIP"
        :error "multiple active leases for $leaseActIP"
    }  

    :set hostname [ get $leaseId host-name ]
    :set comment [ get $leaseId comment ]
    /

    :if ( [ :len $hostname ] <= 0 ) do={ :set hostname $comment }

    :if ( [ :len $hostname ] <= 0 ) do={
        :log error "DHCP2DNS: not registering domain name for address $leaseActIP because of empty lease host-name or comment"
        :error "empty lease host-name or comment"
    }
    :if ( [ :len $domain ] <= 0 ) do={
        :log error "DHCP2DNS: not registering domain name for address $leaseActIP because of empty network domain name"
        :error "empty network domain name"
    }

    :set fqdn "$hostname.$domain"

    /ip dns static
    :if ( [ :len [ find name=$fqdn and address=$leaseActIP and disabled=no ] ] = 0 ) do={
        :log info "DHCP2DNS: registering static domain name $fqdn for address $leaseActIP with ttl $ttl"
        add address=$leaseActIP name=$fqdn ttl=$ttl comment=$DHCPtag disabled=no
    } else={
        :log error "DHCP2DNS: not registering domain name $fqdn for address $leaseActIP because of existing active static DNS entry with this name or address"
    }
    /
} else={
    /ip dns static
    :local dnsDhcpId
    :set dnsDhcpId [ find address=$leaseActIP and comment=$DHCPtag ]
    :if ( [ :len $dnsDhcpId ] > 0 ) do={
        :log info "DHCP2DNS: removing static domain name(s) for address $leaseActIP"
        remove $dnsDhcpId
    }
    /
}

Funktionsweise des Scripts:

Das Script erzeugt einen statischen DNS-Eintrag mit dem FQDN, sobald ein DHCP-Lease vergeben wird und entfernt diesen Eintrag wieder, sobald das Lease abläuft. Der Eintrag setzt sich aus zwei Teilen zusammen:

  1. Der Host-Name des Netzwerkteilnehmers. Sollte der leer sein, dann wird der Kommentar des DHCP-Lease-Eintrages (IP -> DHCP-Server -> Leases) genutzt.
  2. Der festgelegten Domain. Bei uns ist das home.local.

Für meinen ioBroker-Server wäre das also srv-iobroker1.home.local.

Für ungültige FQDN wird kein Eintrag angelegt. Ebenso wird keiner angelegt, wenn es die IP-Adresse oder den FQDN schon gibt. Alle durch das Script angelegten Einträge erhalten den Kommentar #DHCP, damit man sie von den manuell angelegten unterscheiden kann. Die Gültigkeitsdauer der DNS-Träge entspricht der der DHCP-Leases (in Standardeinstellungen 1d). Das Script loggt verschiedene Fehler und Informationen mit dem Tag DHCP2DNS.

Mikrotik: Lease-Script

Mikrotik: Lease-Script

Mit OK speichern wir das Script und die Arbeit ist getan.

Ergebnis

Wenn wir alles korrekt eingestellt haben, dann sollten nun statische DNS-Einträge angelegt werden, sobald sich ein Gerät im Netzwerk anmeldet und seine IP-Adresse per DHCP bezieht. Zu sehen sind die Einträge unter IP -> DNS -> Static. Wenn euch das zu lange dauert, bis hier etwas passiert, könnt ihr ja auch mal das Netzwerkkabel eines Gerätes ziehen, oder das WLAN kurz ab- und wieder einschalten.

Mikrotik: statische DNS-Einträge

Mikrotik: statische DNS-Einträge

Die Netzwerkteilnehmer, für die ein statischer DNS-Eintrag angelegt wurde, sind nun unter ihrem FQDN erreichbar. Prüfen kann man das beispielsweise mittels Ping:

Ping per FQDN oder Host-Name

Ping per FQDN oder Host-Name

Wenn euer Computer die Such-Domain richtig übernimmt, werden Hostnamen automatisch zu FQDNs aufgelöst, wie man im Screenshot beim zweiten Ping gut erkennen kann.

Angepasstes Lease-Script

Ich habe das Script nochmal ein wenig angepasst. Einige meiner Netzwerkgeräte haben einfach unmögliche Hostnamen, die sich auch nicht ändern lassen. Andere Hostnamen sind doppelt vorhanden, weil der gleiche China-WiFi-Chip eingebaut ist.

Dieses nun angepasste Script arbeitet genauso, wie das originale, jedoch wird zur Bildung des FQDN zuerst der Kommentar des Leases verwendet. Wenn der leer ist, dann wird der Hostname genutzt. Sollten Sonder- oder Leerzeichen im Kommentar vorhanden sein, so werden die nicht in den FQDN übernommen.

:local DHCPtag
:set DHCPtag "#DHCP"

:if ( [ :len $leaseActIP ] <= 0 ) do={ :error "empty lease address" }

:if ( $leaseBound = 1 ) do={
    :local ttl
    :local domain
    :local hostname
    :local dnsname
    :local fqdn
    :local leaseId
    :local comment
    :local devicename
    :local convert ({})
    :local validChars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-"

    /ip dhcp-server
    :set ttl [ get [ find name=$leaseServerName ] lease-time ]
    network 
    :set domain [ get [ find $leaseActIP in address ] domain ]

    .. lease
    :set leaseId [ find address=$leaseActIP ]

    # Check for multiple active leases for the same IP address. It's weird and it shouldn't be, but just in case.
    :if ( [ :len $leaseId ] != 1) do={
        :log info "DHCP2DNS: not registering domain name for address $leaseActIP because of multiple active leases for $leaseActIP"
        :error "multiple active leases for $leaseActIP"
    }

    :set hostname [ get $leaseId host-name ]
    :set comment [ get $leaseId comment ]
    /

    # Namen für Gerät ermittlen
    :set devicename $comment
    :if ( [ :len $devicename ] <= 0 ) do={
        :set devicename $hostname
    }

    # Gerätenamen auf ungültige Zeichen prüfen
    :for validCharsIndex from=0 to=([:len $validChars] - 1) do={
        :local validChar [:pick $validChars $validCharsIndex]
        :set ($convert->($validChar)) ($validChar)
    }
    :set ($convert->("_")) ("-")
    :set ($convert->(" ")) ("-")

    :for i from=0 to=([:len $devicename] - 1) do={
        :local char [:pick $devicename $i]
        :local converted ($convert->"$char")
        :local convertedType [:typeof $converted]

        :if ($convertedType = "str") do={
            :set $char $converted
        } else={
            :set $char ""
        }
        :set dnsname ($dnsname.$char)
    }

    # FQDN festlegen
    :if ( [ :len $dnsname ] <= 0 ) do={
        :log error "DHCP2DNS: not registering domain name for address $leaseActIP because of empty lease host-name or comment"
        :error "empty lease host-name or comment"
    }
    :if ( [ :len $domain ] <= 0 ) do={
        :log error "DHCP2DNS: not registering domain name for address $leaseActIP because of empty network domain name"
        :error "empty network domain name"
    }

    :set fqdn "$dnsname.$domain"

    /ip dns static
    :if ( [ :len [ find name=$fqdn and address=$leaseActIP and disabled=no ] ] = 0 ) do={
        :log info "DHCP2DNS: registering static domain name $fqdn for address $leaseActIP with ttl $ttl"
        add address=$leaseActIP name=$fqdn ttl=$ttl comment=$DHCPtag disabled=no
    } else={
        :log error "DHCP2DNS: not registering domain name $fqdn for address $leaseActIP because of existing active static DNS entry with this name or address"
    }
    /
} else={
    /ip dns static
    :local dnsDhcpId
    :set dnsDhcpId [ find address=$leaseActIP and comment=$DHCPtag ]

    :if ( [ :len $dnsDhcpId ] > 0 ) do={
        :log info "DHCP2DNS: removing static domain name(s) for address $leaseActIP"
        remove $dnsDhcpId
    }
    /
}
Sebastian

14 Comments

  1. Antworten Christia

    Hi Sebastian!
    Vielen Dank für die Anleitung, nach einigen Schwierigkeiten habe ich das nun auch hingekriegt 😀

    Dazu hab ich noch eine Frage:
    Kann ich das Script dahingehend anpassen, dass auch ein Static-Eintrag für nur den Hostnamen anlegen kann? An welchen Stellen müsste ich dein angepasstes Lease-Script ändern?

    Vielen Dank und Grüße!
    Christian

    • Antworten Sebastian

      Ja, das geht. Aber ob das Ergebnis brauchbar sein wird, weiß ich nicht.

      Im originalen Script musst du:
      – Zeile 9 löschen
      – Zeilen 17 & 18 löschen
      – Zeilen 40-43 löschen
      – auf Zeile 45 .$domain entfernen

      Im zweiten Script sind es die gleichen Einträge, die bearbeitet werden müssen, nur die Zeilennummern sind andere.

      Das ganze habe ich allerdings nicht getestet, weil ja die Suchdomain der Betriebssysteme dafür sorgt, dass ich jedes Gerät auch nur mit dem Hostnamen ansprechen kann und die Domain nicht hinschreiben muss.

  2. Antworten Ardian

    Servus.
    Sauber arbeit Respekt. Eine Frage wie kann ich Mikrotik in Windows Domain Controller Einbinden?
    Danke Voraus.
    Viele Grüße
    Ardian

  3. Antworten sprinkle

    Hi,

    Thanks for this great script!

    I installed it on a new router and it looks like this is not longer working in 6.47. Do you have an update?

    • Antworten Sebastian

      Hi. I’m still on 6.44.3, so I didn’t recognize any misfunction yet. Maybe next week I have some time to check it – depends on the weather 😉

  4. Antworten Bernd

    Habe es gerade mal probiert das Script und unter 7.0.5 funktioniert es bei mir problemlos (zumindest bisher 😉 )

    Danke für die Veröffentlichung!

  5. Antworten Christian

    Danke für die gute Arbeit. Frohe Weihnachten.
    Trotz allem eine Frage, wenn ich auf dem Mikrotik mehrere VLAN mit verschiedenen Netzen, welche sich nicht alle sehen dürfen, betreibe, muss ich das script dann in jedem DHCP-Server einarbeiten?

    Oder bietet es sich an, extra ein Netzwerk zu erstellen, auf welches alle VLANs zugreifen dürfen und dort das script einarbeiten und eine feste Adresse aus diesem Netzwerk als internen DNS bestimmen?

  6. Antworten PeterB

    Hallo Sebastian,

    danke für das Script und die Anleitung. Bei mir war das ganze bisher über ein Script für static-dhcp to dns gelöst. Da ich mit deinem Script aber nur single-hostname ODER fqdn schaffe, sehe ich 2 Optionen:
    1. Anpassung deines Scriptes, dass sowohl der Hostname, als auch der fqdn angelegt werden
    2. Rollout der Searchdomain via DHCP – dazu gibt es ein tolles Tool https://jjjordan.github.io/dhcp119/ und ein paar guten Foreneinträge: https://forum.mikrotik.com/viewtopic.php?t=166875

    Die Variante 2 konnte ich auf Windows 10+11; Linux mit resolv.conf und Ubuntu20 mit systemd-resolved erfolgreich testen.
    Leider scheitere ich bei meinem Printer und einem aktuellen Android13 Gerät. Wäre Variante 1 – also SOWOHL shortname, als auch fqdn als static einzutragen nicht sinnvoller? Ich habe das testweise für einen Eintrag durchgeführt – Windows nutzt trotzdem brav den fqdn Eintrag und Android den shortname.
    Wie löst du das bisher?

    Falls du keine Lust auf v1 hast – darf ich mit deinem Script (mit Verweis auf diesen Blogpost) im Mikrotik-Forum nachfragen?

    Danke und viele Grüße, Peter
    (Tests aktuell mit RouterOS v7.7 stable)

    • Antworten Sebastian

      Hi Peter,
      Natürlich kannst du das Script im Forum posten. Vielleicht magst du dich ja nochmal melden und das angepasste Script hier posten. So hätten auch andere Leser etwas davon.

      Gruß, Sebastian

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht.

WordPress Cookie Hinweis von Real Cookie Banner