Обновление адрес листов из DNS

Все вы наверное знаете, что можно в адрес листах указывать доменные адреса, RouterOS для каждой такой записи сделает запрос DNS серверам, и в случае получения записи, IP адрес записи на время TTL будет добавлен в адрес лист.

Пример

[admin@MikroTik.Me] /ip firewall address-list print where list="testlist"
Flags: X - disabled, D - dynamic 
 #   LIST                 ADDRESS                                   CREATION-TIME       

Для начало убедимся, что адрес лист testlist пустой.

А теперь для примера создадим адрес запись в адрес листе указав адрес как vk.com

[admin@MikroTik.Me] /ip firewall address-list add list=testlist address=vk.com

И проверим, что в листе находятся динамические записи

[admin@MikroTik.Me] /ip firewall address-list print where list="testlist"     
Flags: X - disabled, D - dynamic 
 #   LIST                 ADDRESS                                   CREATION-TIME       
 0   testlist             vk.com                                    nov/18/2019 12:19:59
 1 D ;;; vk.com
     testlist             87.240.190.72                             nov/18/2019 12:19:59
 2 D ;;; vk.com
     testlist             87.240.190.78                             nov/18/2019 12:19:59
 3 D ;;; vk.com
     testlist             93.186.225.208                            nov/18/2019 12:19:59
 4 D ;;; vk.com
     testlist             87.240.139.194                            nov/18/2019 12:19:59
 5 D ;;; vk.com
     testlist             87.240.190.67                             nov/18/2019 12:19:59

Отлично, видно, что было найдено пять записей для доменного имени vk.com и все адреса были занесены в адрес лист.

Это было для примера.

Меня часто спрашивают, а можно как-то добавить в адрес лист запись c маской например *.microsoft.com.

Нет так делать нельзя, дело в том что любой ДНС сервера не чего не знает о субдоменах, а узнаёт о них только при непосредственном запросе. Доменных имен и подуровней может быть неограниченное количество, и значит о всех таких записей только NS сервер данной записи, но он тоже не вернёт все записи.

А что если подойти с другой стороны.

Если MikroTik выступает в роли dns сервера то в кэше DNS сервера RouterOS должны храниться все записи которые запрашивали наши пользователи.

Очистим наш тестовый лист

[admin@MikroTik.Me] /ip firewall address-list remove [find list="testlist"]

Для начало нам понадобится подготовить скрипт

Создадим его следующей командой

[admin@MikroTik.Me] /system script add name=addresslistfromcache

Приступим к редактированию

[admin@MikroTik.Me] /system script edit addresslistfromcache source

Далее скрипт по частям, в конце будет полный скрипт.

Объявим переменную значение которой будет regexp необходимый для поиска в кэше

:local findreg "microsoft\\.com\$"; - Обратите внимания, что все символы которые участвуют в выборке regexp должны быть экранированы слешем. Попробуем разобрать, то что мы написали, уберём экранирование для лучшего понимания microsoft\.com$

Символ $ доллара обозначает конец строки, а точка экранирована, значит данный символ будет искаться "как есть" в виде точки. В регулярных выражения не экранированная точка обозначает любой символ.

Другими словами мы будет искать все строки где имя записи заканчивается на microsoft.com.

Далее нам необходимо найти все записи и записать результат в переменную

:local records  [/ip dns cache find name~"$findreg"];

Обратите внимание используется символ тильды ~, для того чтобы можно было искать по сопоставлению с регулярным выражением.

Теперь в переменной находится массив со всеми записями, которые найдены с помощью регулярного выражения.

Объявим переменную с адрес листом

:local addrlist "testlist";

Объявим переменную содержащую время на сколько мы будет добавлять в адрес листы записи

:local timeout 3600;

Я указал 1 час в секундах это 3600, вы можете указать приемлемое время для вас.

Так как у нас массив записей, нам необходимо создать цикл\loop и пройтись по каждой записи.

:foreach i in $records do={

}

Внутри конструкции do={ } будет находится переменная $i которая будет соответствовать внутреннему указателю в базе RouterOS.

Далее я буду добавлять по строчно в в цикл значения.

Получим имя для найденной записи

:foreach i in $records do={
    :local r [/ip dns cache get $i name]

}

С этого момента переменная $r имеет значение имени в Кеше, именно её мы должны добавить в адрес лист.

Но чтобы не насиловать MikroTik и nand память если вы будете добавлять её навсегда, давайте лучше проверим, а нет ли такой записи в адрес листе и добавим её только в случае отсутствия.

:foreach i in $records do={
    :local r [/ip dns cache get $i name]
    :local pr [/ip firewall address-list print count-only where address=$r list=$addrlist];    
}

Теперь переменная $pr содержит количество записей в необходимом адрес листе.

Давайте её сократим, что строки были не очень длинными.

:foreach i in $records do={
    :local r [/ip dns cache get $i name]
    :local pr [/ip f a p count-only where address=$r list=$addrlist];    
}

Далее нам необходимо, просто сравнить результат поиска с нулём, если количество ровно нулю, то добавляем в адрес лист.

:if ($pr=0) do={
        /ip firewall address-list add list=$addrlist address=$r timeout=$timeout;
    }  

Естественно это должно быть внутри цикла.

Скрипт целиком

:local findreg "microsoft\\.com\$";
:local records [/ip dns cache find name~"$findreg"];
:local addrlist "testlist";
:local timeout 3600;
:foreach i in $records do={
    :local r [/ip dns cache get $i name];
    :local pr [/ip f a p count-only where address=$r list=$addrlist];
    :if ($pr=0) do={
        /ip firewall address-list add list=$addrlist address=$r timeout=$timeout;
        /log warning message=$r;
    }
}

В конце после добавления в адрес лист, я добавил вывод в лог, того домена который добавился, это чтобы вы могли видеть, что он действительно работает.

Рассказать друзьям