Sync Address List with DNS Cache - MikroTik Script RouterOS
This script will update an address list from a given DNS cache search. This address list can then be used for example in Firewall settings.
# Sync an address list with DNS cache
# Version: 1.0.0
# This script currently only works with type A and non-static DNS records.
# If no matching DNS records are found:
# the address list is removed.
# If matching DNS records are found:
# if an address list entry is NOT found in search result, it is removed.
# if an address list entry IS found in search result, is not modified.
# if a search result is NOT found in address list, it is added.
#
# Search string format:
# "(:|=|~)"
# : match string anywhere
# = match string exactly (case sensitive)
# ~ match string using regular expression (requires ROS >= v3.23)
#
# Example: To search all records containing 'google.com':
# :local search ":google.com"
#
# To search all records ending with 'microsoft.com':
# :local search "~microsoft\\.com\$"
:local search ":google.com"
# The prefix of address list ("" = none)
:local listprefix "DNSCache_"
# Internal processing...
:local IPs ""
:local Names ""
:local sop [:pick [:tostr $search] 0 1]
:set search [:pick [:tostr $search] 1 [:len [:tostr $search]]]
/ip dns cache all {
:local findex; :local property; :local value; :local name; :local type; :local data
:local sfound 0
:foreach rule in=[print detail as-value where static=no] do={
:set name ""; :set type ""; :set data ""
:foreach item in=$rule do={
:set findex [:find [:tostr $item] "="]
:set property [:pick [:tostr $item] 0 $findex]
:set value [:pick [:tostr $item] ($findex + 1) [:len [:tostr $item]]]
:if ($property = "name") do={ :set name $value }
:if ($property = "type") do={ :set type $value }
:if ($property = "data") do={ :set data $value }
}
# Search DNS cache name using specified operator
:set sfound 0
:if ($sop = ":") do={
:if ([:find [:tostr $name] [:tostr $search]] != "" && $type = "A") do={ :set sfound 1 }
}
:if ($sop = "=") do={
:if ([:tostr $name] = [:tostr $search] && $type = "A") do={ :set sfound 1 }
}
:if ($sop = "~") do={
:if ([:tostr $name] ~ [:tostr $search] && $type = "A") do={ :set sfound 1 }
}
:if ($sfound = 1) do={
# :put ("Found " . $name . " -> " . $data)
:set IPs ($IPs . $data . ",")
:set Names ($Names . $name . ",")
}
}
# /ip dns cache all
}
:put ("DNS cache search found " . [:len [:toarray $IPs]] . " match(es) for '" . $search . "'")
# Search through IPs and add to address list
/ip firewall address-list {
:local findex; :local listaddr; :local IPsFound ""
:put ("Searching address list '" . ($listprefix . [:tostr $search]) . "'...")
:foreach l in=[find list=($listprefix . [:tostr $search])] do={
:set listaddr [get $l address]
:if ([:len [:find [:toarray $IPs] [:toip $listaddr]]] = 0) do={
:put (" " . $listaddr . " not found in search, removing...")
remove $l
} else={
# :put ($listaddr . " found address in IPs")
:set IPsFound ($IPsFound . $listaddr . ",")
}
}
# Add remaining records to address list
:set findex 0
:foreach ip in=[:toarray $IPs] do={
:if ([:len [:find [:toarray $IPsFound] [:toip $ip]]] = 0) do={
:put (" Adding address " . $ip)
add list=($listprefix . $search) address=[:toip $ip] comment=([:pick [:toarray $Names] $findex]) disabled=no
}
:set findex ($findex + 1)
}
# /ip firewall address-list
}