Setting static DNS record for each DHCP lease

From MikroTik Wiki
Jump to navigation Jump to search

Run this in scheduler and it will add static dns entry for each DHCP lease.

NB: As this script may delete already added static DNS entries, bases on received hostname over DHCP, the script involves a security risk. Use a uniq domain, for example dhcp.yourdomain.com, dynamic.yourdomain.com or similar. If you have to mix static and dynamic DNS entries on exact same domain, see below.

# DNS record for DHCP lease
# Prepare variables in use
:local topdomain;
:local hostname;
:local hostip;

# Configure your domain
:set topdomain "dhcp.yourdomain.com";

/ip dhcp-server lease;
:foreach i in=[find] do={
  /ip dhcp-server lease;
  :if ([:len [get $i host-name]] > 0) do={
    :set hostname ([get $i host-name] . "." . $topdomain);
    :set hostip [get $i address];
    /ip dns static;
# Remove if DNS entry already exist
    :foreach di in [find] do={
      :if ([get $di name] = $hostname) do={
        :put ("Removing: " . $hostname . " : " . $hostip);
        remove $di;
      }
    }
# Add DNS entry
    :put ("Adding: " . $hostname . " : " . $hostip);
    /ip dns static add name=$hostname address=$hostip;
  }
}


This second script takes another approach. Using TTL as a way to distinguish dynamical added DNS entries and delete those before adding new. Adding hostnames that already exist is denied.

Also old DNS-entries will be removed, when not longer in DHCP-lease. This will prevent messed up DNS-static with a lot of entries.


# Domain to be added to your DHCP-clients hostname
:local topdomain;
:set topdomain "lan";

# Use ttl to distinguish dynamic added DNS records
:local ttl;
:set ttl "00:59:59";

# Set variables to use
:local hostname;
:local hostip;
:local free;

# Remove all dynamic records
/ip dns static;
:foreach a in=[find] do={
  :if ([get $a ttl] = $ttl) do={
    :put ("Removing: " . [get $a name] . " : " . [get $a address]);
    remove $a;
  }
}

/ip dhcp-server lease ;
:foreach i in=[find] do={
  /ip dhcp-server lease ;
  :if ([:len [get $i host-name]] > 0) do={
    :set free "true";
    :set hostname ([get $i host-name] . "." . $topdomain);
    :set hostip [get $i address];
    /ip dns static ;
# Check if entry already exist
    :foreach di in [find] do={
      :if ([get $di name] = $hostname) do={
        :set free "false";
        :put ("Not adding already existing entry: " . $hostname);
      }
    }
    :if ($free = true) do={
      :put ("Adding: " . $hostname . " : " . $hostip ) ;
      /ip dns static add name=$hostname address=$hostip ttl=$ttl;
    }
  }
}

Here's another example. This one will only change the DNS information when changes are necessary, and deletes old DNS entries when leases expire. You can also supply "static" hostnames for ethernet addresses. For example

:global shost001122334455 "hostname"

will assign the hostname "hostname" to the IP address of whatever the lease for mac 00:11:22:33:44:55 winds up being.

       :local zone "dhcp";
       :local ttl "00:05:00"
       :local hostname
       :local ip
       :local dnsip
       :local dhcpip
       :local dnsnode
       :local dhcpnode
       
       /ip dns static;
       :foreach i in=[find where name ~ (".*\\.".$zone) ] do={
         :set hostname [ get $i name ];
         :set hostname [ :pick $hostname 0 ( [ :len $hostname ] - ( [ :len $zone ] + 1 ) ) ];
         /ip dhcp-server lease;
         :set dhcpnode [ find where host-name=$hostname ];
         :if ( [ :len $dhcpnode ] > 0) do={
           :log debug ("Lease for ".$hostname." still exists. Not deleting.");
         } else={
       # there's no lease by that name. Maybe this mac has a static name.
           :local found false
           /system script environment
           :foreach n in=[ find where name ~ "shost[0-9A-F]+" ] do={
              :if ( [ get $n value ] = $hostname ) do={
                :set found true;
              }
           }
           :if ( found ) do={
             :log debug ("Hostname ".$hostname." is static");
           } else={
             :log info ("Lease expired for ".$hostname.", deleting DNS entry.");
             /ip dns static remove $i;
           }
         }
       }
       
       /ip dhcp-server lease;
       :foreach i in=[find] do={
         :set hostname ""
         :local mac
         :set dhcpip [ get $i address ];
         :set mac [ get $i mac-address ];
         :while ($mac ~ ":") do={
           :local pos [ :find $mac ":" ];
           :set mac ( [ :pick $mac 0 $pos ] . [ :pick $mac ($pos + 1) 999 ] );
         };
         :foreach n in=[ /system script environment find where name=("shost" . $mac) ] do={
           :set hostname [ /system script environment get $n value ];
         }
         :if ( [ :len $hostname ] = 0) do={
           :set hostname [ get $i host-name ];
         }
         :if ( [ :len $hostname ] > 0) do={
           :set hostname ( $hostname . "." . $zone );
           /ip dns static;
           :set dnsnode [ find where name=$hostname ];
           :if ( [ :len $dnsnode ] > 0 ) do={
       # it exists. Is its IP the same?
             :set dnsip [ get $dnsnode address ];
             :if ( $dnsip = $dhcpip ) do={
               :log debug ("DNS entry for " . $hostname . " does not need updating.");
             } else={
               :log info ("Replacing DNS entry for " . $hostname);
               /ip dns static remove $dnsnode;
               /ip dns static add name=$hostname address=$dhcpip ttl=$ttl;
             }
           } else={
       # it doesn't exist. Add it
             :log info ("Adding new DNS entry for " . $hostname);
             /ip dns static add name=$hostname address=$dhcpip ttl=$ttl;
           }
         }
       }