Mikrotik, вторые шаги
Mikrotik, вторые шагиПредисловие. Это можно не читать ))
Есть много хороших и не очень руководств по языку скриптов Mikrotik, но подробного описания как работать с функционалом(объектами) я не нашел. Пришлось собирать информацию по крупицам, разбираться по примерам. Как известно, что бы закрепить и систематизировать полученные знания, полезно их рассказать другим. Поэтому, рискну изложить то, что понял сам из разрозненных источников.
На первый взгляд может показаться, что очень много написанного не имеет отношения к написанию скриптов. Но это только на первый взгляд ;)
Подготовка
Хоть я и старался максимально подробно изложить материал, но перед началом работы имеет смысл ознакомиться с основами работы в терминале Mikrotik. Это и будут первые шаги. Вот достойный материал на эту тему: http://mikrotik.vetriks.ru/wiki/%D0%94%D0%BB%D1%8F_%D0%BD%D0%B0%D1%87%D…
Поехали
Для примера будем работать с DHCP сервером.
Открываем терминал, пункт меню «New Terminal» и вводим команду: /ip dhcp-server
и жмем кнопку табуляции(далее <TAB>). Получим такой вывод:
Здесь мы видим доступные для продолжения ввода команды значения. То что подсвечено «синим» цветом, это подразделы. В WinBox их можно увидеть в виде вкладок. Нас же, более всего интересуют «фиолетовые» команды. Пробуем набирать print и <ENTER>. На выводе получим список всех(в примере один) настроенных DHCP серверов:
Кстати, после print то же можно нажать <TAB>. Поиграйтесь с разными параметрами.
Усложняем задачу. Идем на вкладку Leases. В этом примере она выглядит так:
Отключим(не удалим(remove), а именно отключим(disable)) резервирование IP адреса для хоста, у которого текущий адрес 192.168.254.21. На скриншоте мы видим результат - команды, их вывод и отключенная запись резервирования. Разберем подробно.
Вводим: /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 ее-то мы и будем использовать.
Обратите внимание на эти команды:
В первой строке: От корня иерархии объектов микротика мы двигаемся в раздел 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
Если кто заметил, в тексте IP-адрес экранирован кавычками, а на скриншоте нет. Можно использовать кавычки, можно не использовать — работает всяко.
Что такое find и как оно так произошло?
Команду find следует разобрать отдельно. Это одна из самых часто используемых команд в скриптах RouterOS. Она возвращает внутренний(это не тот номер, что возвращает print, но указывает на тот же объект) номер/номера объектов удовлетворяющих условию.
Если ввести команду(как в первой строке):
/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 lease set [find address=192.168.254.21] disabled=yes
Что здесь происходит:
-
Устанавливается контекст /ip dhcp-server lease
-
Внутри контекста(пункт 1) выполняется find address=192.168.254.21 и возвращается значение *dbb, как если бы выполнили команду
/ip dhcp-server lease find address=192.168.254.21
-
Внутри контекста(пункт 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 сервера, отвечающих следующим условиям:
-
Зарезервированы, т.е. IP-адрес закреплен за MAC
-
В настоящее время в сети и имеют активную аренду адреса.
Полученные адреса поместить в список доступа(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={}
}
}
Разберем построчно, что здесь происходит.
Устанавливаем контекст /ip dhcp-server lease
В цикле перебираем все выделенные адреса.
Если в терминале выполнить :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? Об этом позже...". Я сам не знаю почему так :) Возможно когда-нибудь узнаю и здесь напишу.