Community discussions

MikroTik App
 
yodamaker
just joined
Topic Author
Posts: 1
Joined: Fri Mar 19, 2021 9:09 pm

Update Mikrotik DNS Static Entries (Python Script)

Sat Apr 10, 2021 4:46 am

It is very handy to be able to use a mikrotik router to serve as a DNS server.
With a large wide area network of mikrotik routers it is also very nice to be able to distribute DNS server load so DNS client queries hit the closest DNS caching server.
No need to install a separate computer. Just turn turn DNS serving on.

Your local host table can be loaded onto your DNS servers so your static host entries can be resolved by any DNS client.
(e.g. /ip dns static add name=hostname1234 address=1.2.3.4)
So if you have your own private network with your own host table, private host names can be resolved before the query goes out to the Internet DNS servers.
Problems:
- How do you keep all of these DNS server static entries in sync?
- How do you update the DNS service static entries efficiently? (i.e. Not deleting everything and reloading everything in case you have hundreds or thousands of static hosts)
One Solution:
The following Python script will grab the latest copy of your host table and make incremental changes (add/delete/set) as needed to each mikrotik DNS server so they are synced with your host table.
Enjoy.
update_dns_gpl.py
 #! /usr/bin/python
#
# update_dns.py - Update DNS static entries on your Mikrotik Router(s) using this python script.
# Copyright (C) 2021 WILDERNETS LLC, Distributed under GPL-3.0, GNU General Public License v3.0 only
# 
# How it works:
# - Grab a copy of the master host table off the host table server.
# - Get existing DNS static entries from a list of Mikrotik routers.
# - Compare entries to the master host table
# - Issue add/set/remove commands as needed to update the Mikrotik DNS entries.
#
# Setup Notes:
# - Setup DNS server on your mikrotik router(s)
# - Run this on a trusted secure system so you don't have to trust the host master with access to your router(s).
# - OR just Comment out Step0 and run from the machine that has the host master file.
# - Setup password-less ssh to the host master machine.
# - Setup password-less ssh to your router(s).
# - Adv Topic: consider setting up a portable subnet/IP for your router so you can implement DNS server redundancy.
# (I use 10.10.10.10 on two routers and 10.10.10.1 on two routers and inject these as /32 into OSPF)
#
# Requirements:
# - Setup password-less SSH using keys to the machine that hosts the master copy of the host table
# - Setup password-less SSH using keys to the router that act as DNS servers
# - Change the Script vars listed below
# - Test on a non-production router
#
# Coding Notes:
# - Hosts file parsed into two master dictionaries.
# - For each router updated a working copy is made of these two masters.
# - As hosts are processed they are deleted from the dictionary copy.
# - Next router updated gets a brand new copy from the master.
#
import re               # strip comments
import sys              # system stuff
import subprocess       # Popen command
import os               # Execute scp command

# Script vars
HOSTMASTER = "nismaster:/var/yp/etc/hosts" 
HOSTSFILE  = "/home/myuserid/etc/hosts.iowt"
SSHCMD     = "/ip dns static export"
routerlist = ['mikrotik-dnsrouter1','mikrotik-dnsrouter2','mikrotik-dnsrouter3','mikrotik-dnsrouter4']
routeruser = "autoadmin"
debug      = 0

# Step0 Go Grab latest hosts file
print "# Getting hosts file: scp "+HOSTMASTER+" "+HOSTSFILE
os.system("scp "+HOSTMASTER+" "+HOSTSFILE)

# Step1 Open hosts file, parse and check for duplicates
if debug: print "# Verifying hostsfile: "+HOSTSFILE
error = 0
masteriphosts = {}
masterhostip  = {}
hosts = open(HOSTSFILE,'r')

for line in hosts:
    if not line.startswith('#') and line.strip():
        line=re.sub(r'#.*$', '', line).rstrip()
        data = line.split()
        i = data.pop(0)
        if debug > 1: print "checking ip "+i
        if (i in masteriphosts):
            print "ERROR: Duplicate ipaddress "+i+" for "+str(data)+" and "+str(masteriphosts[i])
            error += 1 
        else:
            masteriphosts[i] = data

        for h in data:
            if debug > 1: print "checking host "+h
            if (h in masterhostip):
                print "ERROR: Duplicate hostname "+h+" in hosts file for "+i+" and "+masterhostip[h]
                error += 1 
            else:
                masterhostip[h] = i
if error:
    exit(1)

for router in routerlist:
    USERHOST = routeruser+"@"+router
    iphosts  = masteriphosts.copy()
    hostip   = masterhostip.copy()
    addrname = {}
    nameaddr = {}

    # Step2 SSH to EACH DNS Router and Export the DNS static table and Parse
    print "# Getting router DNS entries: ssh",USERHOST, SSHCMD
    ssh = subprocess.Popen(["ssh", "%s" % USERHOST, SSHCMD],
                           shell=False,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
    result = ssh.stdout.readlines()
    if result == []:
        error = ssh.stderr.readlines()
        print >>sys.stderr, "ERROR: %s" % error
    else:
        if debug: print "# Parsing DNS Static Export"
        for line in result:
            if line.startswith('add address=') :
                line=re.sub(r'add address=', '', line).rstrip()
                line=re.sub(r'name=', '', line)
                a,n = line.split()
                # Check name is a Host 
                if (n in hostip):
                    i = hostip[n]
                    # Check for duplicate DNS names
                    if (n in nameaddr):
                        command = "ssh "+USERHOST+" /ip dns static remove [find name="+n+" address="+a+"]; # Delete Duplicate"
                        print command
                        os.system(command)
                    # Changed address for name
                    elif (a != i):
                        command = "ssh "+USERHOST+" /ip dns static set address="+i+" [find name="+n+" address="+a+"]; # Changed Address"
                        print command
                        os.system(command)
                    addrname[i] = n
                    nameaddr[n] = i 
                    # Delete key from hostip after used so they are gone before step3
                    del hostip[n]
                else:
                    # Delete it if not Host
                    command = "ssh "+USERHOST+" /ip dns static remove [find name="+n+" address="+a+"]; # Delete Entry"
                    print command
                    os.system(command)

    # Step3 Remaining keys in hostip need to be added.
    if debug: print "# Generate Add Commands"
    for h in hostip:
        i = hostip[h]
        command = "ssh "+USERHOST+" /ip dns static add address="+i+" name="+h+"; # Add Entry"
        print command
        os.system(command)

if debug: print "# Finished"
exit(0)

Who is online

Users browsing this forum: No registered users and 22 guests