Mikrotik, вторые шаги

Mikrotik, вторые шаги admin вс, 09 апр 2017 - 23:51

Предисловие. Это можно не читать ))

Есть много хороших и не очень руководств по языку скриптов Mikrotik, но подробного описания как работать с функционалом(объектами) я не нашел. Пришлось собирать информацию по крупицам, разбираться по примерам. Как известно, что бы закрепить и систематизировать полученные знания, полезно их рассказать другим. Поэтому, рискну изложить то, что понял сам из разрозненных источников.

На первый взгляд может показаться, что очень много написанного не имеет отношения к написанию скриптов. Но это только на первый взгляд ;)

Подготовка

Хоть я и старался максимально подробно изложить материал, но перед началом работы имеет смысл ознакомиться с основами работы в терминале Mikrotik. Это и будут первые шаги. Вот достойный материал на эту тему: http://mikrotik.vetriks.ru/wiki/%D0%94%D0%BB%D1%8F_%D0%BD%D0%B0%D1%87%D…

Поехали

Для примера будем работать с DHCP сервером.

Окно выбора настроек DHCP сервера

Открываем терминал, пункт меню «New Terminal» и вводим команду: /ip dhcp-server  и жмем кнопку табуляции(далее <TAB>). Получим такой вывод:

/ip dhcp-server

Здесь мы видим доступные для продолжения ввода команды значения. То что подсвечено «синим» цветом, это подразделы. В WinBox их можно увидеть в виде вкладок. Нас же, более всего интересуют «фиолетовые» команды. Пробуем набирать print и <ENTER>. На выводе получим список всех(в примере один) настроенных DHCP серверов:

/ip dhcp-server print

Кстати, после print то же можно нажать <TAB>. Поиграйтесь с разными параметрами.

Усложняем задачу. Идем на вкладку Leases. В этом примере она выглядит так:

Окно настроек резервирования DHCP сервера

Отключим(не удалим(remove), а именно отключим(disable)) резервирование IP адреса для хоста, у которого текущий адрес 192.168.254.21. На скриншоте мы видим результат - команды, их вывод и отключенная запись резервирования. Разберем подробно.

Окно настроек резервирования DHCP сервера + терминал

Вводим: /ip dhcp-server lease <TAB> и наблюдаем список команд. По смыслу понимаем что нам подходит команда disable, но мы сделаем вид что ее нет, и в академических целях пойдем более сложным путем. Так же видна некая команда set, вероятно она устанавливает какие-то параметры. Посмотрим что она может.

Продолжаем вводить: set <TAB>. Теперь мы видим список «зеленых» параметров, которые мы можем использовать в команде set. Обратите внимание, что параметр numbers выделен жирным цветом — он обязательный. Следуя логике можно предположить, что это некий идентификатор(номер), однозначно указывающий на изменяемый командой set объект.

Так где же нам узнать этот номер? Например через команду print, вводим:
/ip dhcp-server lease print

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

Пробуем ввести: /ip dhcp-server lease set disabled=<TAB> и видим какие значения может принимать параметр, дописываем yes и <ENTER>. Упс, что за вопрос numbers? Да-да, тот самый номер, из первой колонки таблицы, команды print. В нашем случае вводим: 7<ENTER>.

Но все это можно сделать одной командой:
/ip dhcp-server lease set 7 disabled=yes

Забегая вперед, замечу, что при попытке получить значение disabled, командой:
:put [/ip dhcp-server lease get 7 disabled]
вы получите булево значение true или false. Это важно при использовании в скриптах, такая особенность вас может поджидать в самом неожиданном месте. О_о, а откуда взялся get, его ведь не было в списке доступных команд? Об этом то-же позже...

Чет какая-то фигня заметит пытливый читатель )) Верно, фигня. Теперь выполним задачу одной командой. Если помните, среди доступных команд есть find ее-то мы и будем использовать.

Обратите внимание на эти команды:

/ip dhcp-server lease

В первой строке: От корня иерархии объектов микротика мы двигаемся в раздел lease DHCP-сервера, где командой set изменяем значение параметра disabled у 7-го объекта.

Во второй и третьей строке проделывается то-же самое, только немного иначе. Сначала мы переходим в контекст - /ip dhcp-server lease, а затем в этом контексте выполняем команду с параметрами: set 7 disabled=yes

Теперь в нашей команде /ip dhcp-server lease set 7 disabled=yes сотрем цифру 7 и напишем [ find ]. После слова find нажмем <TAB> и увидим список параметров по которым мы можем выполнить поиск в списке объектов выделенных адресов.

Дописываем наш find, должно получиться так:
/ip dhcp-server lease set [find address=192.168.254.21] disabled=yes

Окно настроек резервирования DHCP сервера + терминал

Если кто заметил, в тексте IP-адрес экранирован кавычками, а на скриншоте нет. Можно использовать кавычки, можно не использовать — работает всяко.

Что такое find и как оно так произошло?

Команду find следует разобрать отдельно. Это одна из самых часто используемых команд в скриптах RouterOS. Она возвращает внутренний(это не тот номер, что возвращает print, но указывает на тот же объект) номер/номера объектов удовлетворяющих условию.

Окно настроек резервирования DHCP сервера + терминал

Если ввести команду(как в первой строке):
/ip dhcp-server lease find address=192.168.254.21
в надежде увидеть номер, то ничего не произойдет. Это как вызвать функцию, а возвращаемый ей результат не обработать.

Поэтому, используем :put для вывода возвращаемого значения(вторая строка). На выходе получаем шестнадцатеричное число DBB. Его можно использовать в качестве значения numbers(раньше мы брали номер из команды print).

Если вы внимательно посмотрите, то заметите что во второй строке :put [ip dhcp-server lease find address=192.168.254.21] перед ip нет символа /

Эта команда выполнится, так как мы и так находимся в корне иерархии объектов. Но если нам перейти в другой контекст, то тут-же получим ошибку.

/ip dhcp-server

 

Не много отвлеклись, но вернемся к нашей команде
/ip dhcp-server lease set [find address=192.168.254.21] disabled=yes

Что здесь происходит:

  1. Устанавливается контекст /ip dhcp-server lease

  2. Внутри контекста(пункт 1) выполняется find address=192.168.254.21 и возвращается значение *dbb, как если бы выполнили команду /ip dhcp-server lease find address=192.168.254.21

  3. Внутри контекста(пункт 1) выполняется set(со значением numbers равным *dbb), который присваевает параметру disabled значение yes

В развернутом виде это аналогично:

/ip dhcp-server lease set [/ip dhcp-server lease find address=192.168.254.21] disabled=yes

Таким образом мы видим, что квадратные скобки позволяют выполнять команды во время выполнения других команд и передавать результат «на верх».

Скрипт

На основе вышесказанного напишем скрипт получающий IP адреса клиентов DHCP сервера, отвечающих следующим условиям:

  1. Зарезервированы, т.е. IP-адрес закреплен за MAC

  2. В настоящее время в сети и имеют активную аренду адреса.

Полученные адреса поместить в список доступа(aclGrantIPs). Если клиент отключился, то удалить его IP из этого списка.

Скопируем скрипт и вставим его в терминал:

/ip dhcp-server lease
:foreach i in=[find] do={
    :local addrTMP [get $i address]
    :if ([get $i status]="bound" && ![get $i dynamic]) do={
        :do {/ip firewall address-list add address=$addrTMP list=aclGrantIPs} on-error={}
    } else={
        :do {/ip firewall address-list remove [find address=$addrTMP list=aclGrantIPs]} on-error={}
    }
}

Окно настроек резервирования DHCP сервера + терминал

Разберем построчно, что здесь происходит.

Устанавливаем контекст /ip dhcp-server lease

В цикле перебираем все выделенные адреса.

Если в терминале выполнить :put [/ip dhcp-server lease find] то будет выведен массив внутренних идентификаторов объектов/записей аренды адресов.

:put [/ip dhcp-server lease find]

Это и проделывается в строке

:foreach i in=[find] do={

что эквивалентно

:foreach i in=[/ip dhcp-server lease find] do={

или в рассматриваемом случае(со значениями)

:foreach i in=[*d;*26;*86;*141;*143;*1db;*1f3;*dbb;*dc1] do={

Создаем и инициализуем локальную переменную addrTMP значением содержащим IP адрес клиента. Обратите внимание, при создании переменной знак $ в начале не ставится, а при использовании ставится.

:local addrTMP [get $i address]

что эквивалентно

:local addrTMP [/ip dhcp-server lease get $i address]

где $i по порядку подставляется из массива [*d;*26;*86;*141;*143;*1db;*1f3;*dbb;*dc1] циклом :foreach

Аналогично предыдущему шагу, проверим значение параметров status и dynamic.

:if ([get $i status]="bound" && ![get $i dynamic]) do={

Наблюдая за поведением DHCP сервера, на вкладке Leases, можно предположить, что:

  • параметр status со значением bound говорит нам о том, что клиент недавно запросил/подтвердил свой адрес.
  • параметр dynamic определяет, что адрес динамический и возвращает булево значение true или false соответственно.

Если выполняются условия, что это DHCP клиент, со статической привязкой адресов и активен в настоящее время, то добавляем его в список доступа командой:
/ip firewall address-list add address=$addrTMP list=aclGrantIPs

Причем заметьте, что команда обернута в обработчик ошибок:
:do {} on-error={}

Это сделано, что-бы скрипт не останавливался «в тихую» с ошибкой, в случае если адрес уже есть в списке.

Если условие не выполняется, то удаляем запись с этим IP из списка. Например, наш клиент отключился, или у него администратор снял статическое резервирование адреса.

/ip firewall address-list remove [find address=$addrTMP list=aclGrantIPs]

Для удаления записи используется команда remove. Которая как get, set и еще некоторые другие команды, использует в качестве параметра numbers внутренний номер объекта. В этом случае, объект - это запись в IP - Firewall - Address List.

Команда find может искать по нескольким параметрам в одном запросе.

PS Теперь, когда многие вещи прояснились, можно ознакомиться с официальным описанием скриптового языка RouterOS или его переводом.

PSS Помнится я писал - "О_о, а откуда взялся get? Об этом позже...". Я сам не знаю почему так :) Возможно когда-нибудь узнаю и здесь напишу.