Показаны сообщения с ярлыком Полезные наработки кода. Показать все сообщения
Показаны сообщения с ярлыком Полезные наработки кода. Показать все сообщения

среда, 21 сентября 2016 г.

Групповое удаление файлов по типу в Mikrotik.

  Используя скрипт-аналог Netwatch я столкнулся с проблемой, когда Mikrotik производит отправку сообщения в Telegram создается соответствующий файл, после каждой отправки. Когда отправляется много сообщений это выглядит так:


  Решить проблему достаточно просто, после каждой отправки можно удалять все файлы, которые имеют тип "file" командой
/file remove [find type=file]
  В скрипте это может выглядеть так:
/tool fetch url="https://api.telegram.org/bot123456789:AAyJyyZ_W67Vyst9wSGRWzcXqeFI5E85RVy/sendMessage\?chat_id=-123456789&text=$time BAIRAK $name3 off"; delay3; /file remove [find type=file]
  Так же приведу команду удаления файлов с нулевым размером:
/file remove [find where size=0]

суббота, 27 августа 2016 г.

Удаляем, переименовываем записи в address-list в Mikrotik.

  Удалить все записи в адрес-листах (удаляет ВСЕ адрес-листы):
/ip firewal address-list remove [find]
  Удалить списки в адрес-листах которые содержат в названии листа "la":
/ip firewal address-list remove [find list~"la"]
  Удалить списки в адрес-листах название которых начинается на "la":
/ip firewal address-list remove [find where list~"^la"]

вторник, 23 августа 2016 г.

Выводим значение переменной в название/значение другой переменной.

  Выведем значение переменной в название другой переменной:

способ 1:
#есть переменная A c значением 123
:global A 123;
#создадим переменную, взяв в название значение переменной А:
:execute ":global $A";
#создадим переменную, взяв в название значение переменной А, и просвоим ей значение 321:
:execute ":global $A 321";
способ 2(автор vqd):
{
:local tmp "str"
[:parse ":global $tmp"]
}

понедельник, 15 августа 2016 г.

Сохраняем глобальные переменные после перезагрузки.

  При перезагрузке роутера глобальные переменные удаляются. Иногда их нужно сохранить, для этого можно использовать, к примеру, комментарии к интерфейсам и т.д. Нужно к вашему скрипту добавить следующий код:
:global save;
:set save 6;
# после введения переменной сохраняем ее в коммент и создаем задание на выполнение при загрузке маршрутизатора
/interface ethernet set ether5 comment=$save;
/system scheduler add name=global_save on-event=":delay 3; :global save [/interface ethernet get ether5 comment]" start-time=startup;
  Глобальную переменную "save" мы вносим в коммент к интерфейсу ether5. Далее ставим задание, которое выполняется при загрузке роутера и извлекает нашу переменную из комментария интерфейса. 

воскресенье, 7 августа 2016 г.

Пару полезностей: получаем публичный IP в переменную, подсказка диапазона подсети.

  Иногда требуется получить публичный IP в переменную Mikrotik. Если роутер за натом, то на его интерфейсе внутренний IP. Для получения внешнего можно воспользоваться методом, о котором я писал ранее. Сервис opendns позволяет запросом получить свой внешний IP. Если сделать запрос на сервер 208.67.222.222 домена myip.opendns.com, сервер возвратит ваш IP, с которого сделан запрос. Таким образом скрипт возвратит реальный публичный IP, даже если вы за NAT-ом.
:global currentIP [:resolve myip.opendns.com server=208.67.222.222];
  Так же, если в окне IP/Address List навести на адрес, то Микротик выдаст подсказку, с дапазоном IP, которые входят в текущую маску. Пока такая фича пока доступна только в этом окне.

воскресенье, 12 июня 2016 г.

Цикл добавления маршрутов, сверяем шлюз провайдера с маршрутом, правим MSS при VPN.

  Пример скрипта - цикл для добавления 254 маршрута:
for x from=1 to=254 do={ /ip route add dst-address="192.168.$x.0/24" gateway=192.168.201.10 }
  Если мы получаем настройки по DHCP, а основной маршрут выставляем статический, неплохо было бы проверять изменился ли текущий шлюз у провайдера или нет:
:global ispgw [ip dhcp-client get [/ip dhcp-client find interface=ether1-gateway] gateway];
:global ispgwstat [ip route get [/ip route find comment="ISP1" ] gateway ];
#:log info ("$ispgw" )
#:log info ("$ispgwstat" )
:if ($ispgw = $ispgwstat ) do={ :log info ("ISP GW OK" ) } else={ ip route set [/ip route find comment="ISP1"] gateway=$ispgw; :log info ("ISP GW COMPLETE" )}
  Если через PPPOE соединение некоторые сайты не открываются
- сделать изменения в Firewall > Mangle, удалить динамические правила change MSS all ppp
PPP > Prifiles > Default > General > Change TCP MSS “no”
- прописать правило вручную
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 protocol=tcp tcp-flags=syn tcp-mss=1453-65535

понедельник, 6 июня 2016 г.

Спрашиваем пользователя в командной строке Mikrotik и обрабатываем его ответ.

  Процитирую вопрос на форуме forummikrotik.ru:
Возникла необходимость при выполнении скрипта через консоль (import file=) спросить пользователя, хочет он это делать или нет, например: "Install Extra Domain (Block Skype, Hotmain, Dr. Watson and/or Error Reporting) (Y\N) ? : " и пользователю нужно нажать нужную кнопку.
Полазив по wiki, я не нашёл как такое реализовать.
  Было предложено решение:
:put [terminal inkey ]
   И пример использования:
:put "Install Extra Domain (Block Skype, Hotmain, Dr. Watson and/or Error Reporting) (Y\\N):"
:local key [:terminal inkey]
  Сначала выводится вопрос в терминал и ожидание ввода клавиши. После нажатия клавиши Y или N сохраняется её ASCII представление в переменную key. И конструкцией if ($key = 121) do={} выполняется определенное действие в зависимости от нажатой клавиши.
  Пример реализации можно почитать тут: 

пятница, 22 апреля 2016 г.

Узнаем номер версии RouterOS скриптом.

  Сам скрипт:
:global sysversion
:set $sysversion [/system package get [/system package find name=system] version]

воскресенье, 27 декабря 2015 г.

Остановить выполнение скрипта.

  Прервать скрипт:
/system script job remove [find script=script25]
  Более правильный вариант, с обработчиком ошибок:

:do {/system script job remove [find script=script25]} on-error={}
log info 33
   Хотя первый скрипт срабатываем отлично, и не валится в ошибку если в "system script job" script25 нет,  я бы рекомендовал использовать второй вариант, особенно, если данная часть кода входит в длинный скрипт. В этом случае, работает или нет в данный момент скрипт с именем "script25", выполнения кода продолжится, и в лог напишет "33".

суббота, 10 октября 2015 г.

Поиск нужного address-list.

Скрипт найдет нужный адрес-лист и выведет его название:
:put [/ip firewall address-list get value-name=list [find address=192.168.x.x]] 

пятница, 9 октября 2015 г.

Таймер в скрипте.

   Таймера  в Микротике пока не придумали, можно воспользоваться шедуллером, и запускать скрипт с интервалом, но иногда нужно что-бы таймер обрабатывался в скрипте. Например, мне нужно было, что бы в скрипте на определенном моменте засекалось 60 минут, и в течении этого времени происходила пинг-проверка работоспособности сети wifi, когда это время истекало, скрипт должен был принудительно подключать роутер к другой wifi сети.
В итоге вышло такое:
:global nameADR23;
:global perviy23;
:do {:global nameADR23 [/ip firewall address-list get value-name=list [find address=12.12.12.12]]} on-error={:if ($perviy23=true) do={set $perviy23 ""; set $nameADR23 ""; log info 146} else={:set nameADR23 ""; /ip firewall address-list add dynamic=yes address=12.12.12.12 list=timer23 timeout=0:01:00; set $perviy23 true}};
Создаются две глобальные переменные. Потом проверяется наличие некого списка адресов в  address-list, если его нет, он создается с нужным вам таймаутом(в примере 1 минута). При следующем запуске скрипта, он проверит наличие этого адрес-листа, если он еще есть(время не прошло), просто запишет в переменную nameADR23 имя адрес-листа(timer23), но если время истечет, адрес-лист удалится, извлечь имя его мы не сможем, и если это будет не первый запуск(который непосредственно создает адрес лист) то мы считаем что 1 минута прошла, и выполняем действие log info 146, и очищаем наши переменные(set $perviy23 ""; set $nameADR23 ""). Вот такой работоспособный скрипт (версия 6.18).

пятница, 18 сентября 2015 г.

Функции.

Если в скрипте нужно использовать повторяющийся кусок кода можно использовать функцию:
#define function and run it
:global myFunc do={:put "hello from function"}
$myFunc
output:
hello from function
Таким образом можно сократить количество строк в коде. Например функцию можно использовать в таком куске кода:
:if ($lenPass = 8) do={:log warning "WiFi password s random.org: $newPassword"; $myFunc} 
Он выполнит запись в лог, а потом все команды которые записаны в функции $myFunc.

Еще пример с вики:
:global myFunc do={ :return ($a + $b)}
:put [$myFunc a=6 b=2]
output:
8
Так же можно передать существующий скрипт в функцию:

#add script
 /system script add name=myScript source=":put \"Hello $myVar !\"" 

:global myFunc [:parse [/system script get myScript source]]
$myFunc myVar=world
output:
Hello world !

Обработчик ошибок.

Есть такой скрипт:
/tool fetch url="https://www.random.org/passwords/\?num=1&len=8&format=plain&rnd=new" keep-result=yes dst-path="pass.txt";
log info 1;
Если по какой-то причине  www.random.org будет недоступен, то скрипт не продолжит работу, а завершится с ошибкой. Что-бы он продолжил работу нужно добавить обработчик:
:do {/tool fetch url="https://www.random.org/passwords/\?num=1&len=8&format=plain&rnd=new" keep-result=yes dst-path="pass.txt"} on-error={:log warning "random.org not generator"};
log info 1;
В таком случае скрипт продолжит работу.
Еще пример с вики:
:do {
      :put [:resolve www.example.com];
} on-error={ :put "resolver failed"};
:put "lala"
output:
resolver failed
lala 
http://wiki.mikrotik.com/wiki/Manual:Scripting 

вторник, 15 сентября 2015 г.

Удаляем с DHCP-сервера клиентов у которых поле host-name пустое.

foreach i in=[/ip dhcp-server lease find] do={
   :if ([:len [/ip dhcp-server lease get $i host-name]] = 0) do={
      /ip dhcp-server lease remove $i;
   }
}

Генерируем пароли через сервис random.org.

Предыдущий генератор не совершенен. А генерации случайных чисел в Mikrotik пока нет, но можно использовать сторонний сервис: random.org.
:global RandomOrg "";
/tool fetch url="https://www.random.org/passwords/\?num=1&len=8&format=plain&rnd=new" keep-result=yes dst-path="pass.txt";
delay 3;
:global RandomOrg [/file get pass.txt contents];
/file remove pass.txt;
Данный скрипт записывает сгенерированный пароль и 8 символов в переменную, если сервис не доступен - переменная будет пустая. 

воскресенье, 13 сентября 2015 г.

Создание папки.

Напрямую папку создать нельзя. Делаем небольшую уловку:
/tool fetch address=127.0.0.1 src-path=someDummyFile user=admin password=admin mode=ftp dst-path=newDir/newFileName;
Для того что-бы это работало нужно что б сервис ftp работал, если в скрипте не указывать порт, то он должен быть стандартным. Пользователь должен иметь доступ к ftp. newDir - название новой пустой диретории.

Отрезать маску IP-адреса.

:local $ip "1.1.1.1/32"
 :for i from=([:len $ip] - 1) to=0 do={
     :if ([:pick $ip $i] = "/" ) do={
         :set ip [:pick $ip 0 $i]
         }
     }
и покороче
:local s "1.1.1.1/24";
:put [:pick $s 0 [:find $s "/"]] 

вторник, 8 сентября 2015 г.

Проверить выполняется ли скрипт в данный момент или нет.

:if ([:len [system script job find script ="script23"]] > 1) do={} else={log info svoboden}
Этот скрипт называется  "script23". При запуске он проверяет выполняется ли он в данный момент(проверяет по своему имени). Если выполняется-то он ничего не делает и завершается, если не выполняется, то выполняет действие "log info svoboden". Этот оборот используется например в данном скрипте.  Для чего это нужно. Например скрипт может входить в бесконечный цикл(например пока не подключится к нужной сети wifi), но запускается он по шедуллеру, что б не было дубликатов нужна такая проверка. В таком случае ставим время повторения в шедуллере 1 минута, и пока не завершится скрипт, он заново не стартанет.

Определяем последний день текущего месяца.

  Иногда, например для отчетов с Mikrotik, нужно знать последний день текущего месяца -30, 31 или 28, 29( в феврале). Для этого нам поможет скрипт:
:global date
:global day
:global month
:global year
:global yeardiv
:global yearmult
:global leapyear
:global lastday
:global found
 
 :set date [system clock get date]
 :set month [:pick $date 0 3]
 :set day [:pick $date 4 6]
 :set year [:pick $date 7 11]

 :set yeardiv ($year / 4)
 :set yearmult ($yeardiv * 4)

 :if ([$yearmult] = $year) do={ :set leapyear true } else={ :set leapyear false }
 :if ([$month] = "jan") do={ :set lastday 31 }
 :if ([$month] = "feb") do={
        :if ($leapyear = true) do={ :set lastday 29 }
        :if ($leapyear = false) do={ :set lastday 28 } }
 :if ([$month] = "mar") do={ :set lastday 31 }
 :if ([$month] = "apr") do={ :set lastday 30 }
 :if ([$month] = "may") do={ :set lastday 31 }
 :if ([$month] = "jun") do={ :set lastday 30 }
 :if ([$month] = "jul") do={ :set lastday 31 }
 :if ([$month] = "aug") do={ :set lastday 31 }
 :if ([$month] = "sep") do={ :set lastday 30 }
 :if ([$month] = "oct") do={ :set lastday 31 }
 :if ([$month] = "nov") do={ :set lastday 30 }
 :if ([$month] = "dec") do={ :set lastday 31 }
 :if ([$lastday] = $day) do={log info 1} else={log info 2}
Скрипт выполняется каждый день. Если сегодня последний день месяца пишем в лог "1", если нет - пишем в лог "2". Естественно тут можно выполнять нужные именно вам команды. Так же глобальные переменные в начале можно заменить на локальные.

четверг, 14 мая 2015 г.

Очистить лог-журнал.

Иногда нужно очистить лог  Mikrotik. Напрямую это сделать нельзя, но можно выполнить команду очистки:
/system logging action set memory memory-lines=1;
/system logging action set memory memory-lines=1000;
Данные в скрипте подправить в зависимости куда пишется журнал (в оперативку или на диск), и какое количество строк в журнале.