MikroTik Скрипт: Уведомление о входе на устройство

Скрипт отправит уведомление о успешном входе и завершении сеанса пользователя на устройстве MikroTik. Уведомление отправляется на электронную почту или Telegram.

В интернете много скриптов позволяющих парсить лог устройства MikroTik, но все они огромные и сложные для понимания. Я [Yun Sergey] написал простой скрипт решающий эту задачу.

Скрипт ищет события «account» в журнале устройства MikroTik, с момента своего последнего запуска. Создает сообщение со списком всех событий произошедших с момента последнего запуска.

Скрипт создает и использует глобальную переменную ParseLogAccountEndArrayID, хранит ID последнего элемента из массива записей с темой «account».

Для отправки уведомлений используются функции:

Пример сообщений:

  • user USER logged in from E4:6F:13:AA:58:2D via winbox — пользователь выполнил вход на устройство используя WinBox;
  • user USER logged in via local — пользователь выполнил вход на устройство используя MAC адрес устройства;
  • user USER logged in from 192.168.1.9 via telnet — user launched MikroTik internal terminal.

Пример сообщения на электронную почту:

Уведомление на электронную почту о входе пользователя на устройство MikroTik

Пример Telegram сообщения:

Сообщение Telegram - уведомление о входе пользователя на устройство MikroTik

Статья на других языках:
?? — MikroTik Script: Device Login Notification
?? — MikroTik Script: Notificación de inicio de sesión del dispositivo
?? — Script MikroTik: Notification de connexion de l’appareil
?? — MikroTik-Script: Benachrichtigung über die Geräteanmeldung
?? — MikroTik-script: Melding apparaat aanmelding

Создать скрипт

Для запуска скрипта необходимы разрешения: read, write, test, policy.

[System] -> [Scripts] -> [+] -> [Name: ParseLogAccountEvents] -> [Policy: read, write, test, policy]

Код скрипта:

:local DeviceName [/system identity get name];
:local Time [/system clock get time];
:local Date [/system clock get date];
:local EmailMessageText;
:local TelegramMessageText;

:global ParseLogAccountEndArrayID;

:local IDsEventsAccount [/log find where  topics ~ "account"];

:local LenArrayIDs [:len $IDsEventsAccount];
:local StartArrayID [:find $IDsEventsAccount $ParseLogAccountEndArrayID];
:local EndArrayID ($IDsEventsAccount -> ($LenArrayIDs-1));

:log info "Script ParseLogAccountEvents: running.";

:if ($EndArrayID != $ParseLogAccountEndArrayID and [:tobool $ParseLogAccountEndArrayID] ) do={

    :log info "Script ParseLogAccountEvents: New events found.";

    :for KeyArray from=($StartArrayID+1) to=($LenArrayIDs-1) do={
        :local IDMessage ($IDsEventsAccount ->$KeyArray );
        :set EmailMessageText "$EmailMessageText \n\r  $[/log get number=$IDMessage time] - $[/log get number=$IDMessage message];";
        :set TelegramMessageText "$TelegramMessageText %0D%0A  $[/log get number=$IDMessage time] - $[/log get number=$IDMessage message];";
        }
    
    :log info "Script ParseLogAccountEvents: Events processed. Sending notifications.";

    # START SEND EMAIL
    :local SendTo "notify@mhelp.pro";
    :local Subject "\F0\9F\94\93 AUTH: $DeviceName [$Date $Time]";
    :local MessageText "$EmailMessageText";
    :local FileName "";
    :local SendEmail [:parse [/system script get SendEmailFunction source]];
    $SendEmail SendTo=$SendTo TextMail=$MessageText Subject=$Subject FileName=$FileName;
    # END SEND EMAIL

    # START SEND TELEGRAM
    :local MessageText "\F0\9F\94\93 <b>$DeviceName: AUTH</b> $TelegramMessageText";
    :local SendTelegramMessage [:parse [/system script  get MyTGBotSendMessage source]];
    $SendTelegramMessage MessageText=$MessageText;
    # END SEND TELEGRAM
}

:set ParseLogAccountEndArrayID $EndArrayID;

:log info "Script ParseLogAccountEvents: script completed successfully.";
MikroTik Скрипт: Уведомление о входе на устройство

Добавить скрипт в Планировщик

Для запуска скрипта необходимы разрешения: read, write, test, policy.

[System] -> [Schedule] -> [+] -> [Name: ParseLogAccountEvents] —>  [Interval: 00:05:00] -> [Policy: read, write, policy, test]

Или выполните в терминале:

/system scheduler add name=ParseLogAccountEvents policy=read,write,policy,test on-event="/system script run ParseLogAccountEvents" interval=5m comment="Analyze the log account and send login / logout events"
Добавить скрипт "уведомление о входе пользователя" в планировщик MikroTik

Теперь вы можете увеличить контроль над вашими устройствами MikroTik — контролируя время входа и выхода администраторов устройств. А так же настраивать выполнение действий при входе пользователя, например создать резервную копию настроек или создать копию конфигурации устройства.


? Как создать скрипт — уведомление о входе пользователя на устройство MikroTik и отправка уведомления на электронную почту или сообщение Telegram, обсуждалось в этой статье. Я надеюсь, что теперь вы сможете улучшить контроль над устройствами MikroTik отслеживая успешные входы администраторов на устройство или вовремя обнаружив действия злоумышленника. Однако, если вы столкнетесь с каким-то проблемами при настройке скрипта, не стесняйтесь написать в комментариях. Я постараюсь помочь.

Скрипт проверен: hAP ac lite [RouterBOARD 952Ui-5ac2nD], RouterOS 6.47.8 (stable).

21 комментарий к “MikroTik Скрипт: Уведомление о входе на устройство”

  1. Сергей, я не очень силен в скриптах, но мне похоже нужен именно ваш вариант, потому что он сканирует именно новый события в логах. Мне на самом деле нужно намного проще, чем у Вас сделано, но не хватает знаний упростить. Смысл в том чтобы скрипт искал среди новых событий строчку, например:lte1: reply timeout for: ATE0 и делал перезарузку модема, если событие присутствует /system routerboard usb power-reset duration=15s

    Ответить
  2. В скрипте обнаружена недоработка. При попытке подключится к устройству заблокированного IP адреса (из заблокированного адреслиста) в лог генерируется событие об отправке сообщения админу, и приходят пустые сообщения. Подключение, разумеется не проходит, ибо адрес лист заблокирован правилами фаервола

    Ответить
  3. Можно задать несколько тем?
    :local IDsEventsAccount [/log find where topics ~ «account» || topics ~ «warning»]; не отрабатывает.

    Ответить
  4. Привет, понравился твой скрипт, но походу в новой прошивке, что то пошло не так, и ROS жалуется на синтаксис:
    [123@5455455] > :local DeviceName [/system identity get name];
    [123@5455455] > :local Time [/system clock get time];
    [123@5455455] > :local Date [/system clock get date];
    [123@5455455] > :local EmailMessageText;
    [123@5455455] > :local TelegramMessageText;
    [123@5455455] >
    [123@5455455] > :global ParseLogAccountEndArrayID;
    [123@5455455] >
    [123@5455455] > :local IDsEventsAccount [/log find where topics ~ «account»];
    [123@5455455] >
    [123@5455455] > :local LenArrayIDs [:len $IDsEventsAccount];
    [123@5455455] > :local StartArrayID [:find $IDsEventsAccount $ParseLogAccountEndArrayID];
    [123@5455455] > :local EndArrayID ($IDsEventsAccount -> ($LenArrayIDs-1));
    [123@5455455] >
    [123@5455455] > :log info «Script ParseLogAccountEvents: running.»;
    [123@5455455] >
    [123@5455455] > :if ($EndArrayID != $ParseLogAccountEndArrayID and [:tobool $ParseLogAccountEndArrayID] ) do={
    {…
    {… :log info «Script ParseLogAccountEvents: New events found.»;
    {…
    {… :for KeyArray from=($StartArrayID+1) to=($LenArrayIDs-1) do={
    {{… :local IDMessage ($IDsEventsAccount ->$KeyArray );
    {{… :set EmailMessageText «$EmailMessageText \n\r $[/log get number=$IDMessage time] — $[/log get number=$IDMessage message];»;
    syntax error (line 7 column 14)
    [123@5455455] > :set TelegramMessageText «$TelegramMessageText %0D%0A $[/log get number=$IDMessage time] — $[/log get number=$IDMessage message];»;
    syntax error (line 1 column 14)
    [123@5455455] > }
    [123@5455455] >
    [123@5455455] > :log info «Script ParseLogAccountEvents: Events processed. Sending notifications.»;
    [123@5455455] >
    [123@5455455] > # START SEND EMAIL
    [123@5455455] > :local SendTo «notify@mhelp.pro»;
    [123@5455455] > :local Subject «\F0\9F\94\93 AUTH: $DeviceName [$Date $Time]»;
    [123@5455455] > :local MessageText «$EmailMessageText»;
    [123@5455455] > :local FileName «»;
    [123@5455455] > :local SendEmail [:parse [/system script get SendEmailFunction source]];
    no such item
    [123@5455455] > $SendEmail SendTo=$SendTo TextMail=$MessageText Subject=$Subject FileName=$FileName;
    [123@5455455] > # END SEND EMAIL
    [123@5455455] >
    [123@5455455] > # START SEND TELEGRAM
    [123@5455455] > :local MessageText «\F0\9F\94\93 $DeviceName: AUTH $TelegramMessageText»;
    [123@5455455] > :local SendTelegramMessage [:parse [/system script get MyTGBotSendMessage source]];
    [123@5455455] > $SendTelegramMessage MessageText=$MessageText;
    [123@5455455] > # END SEND TELEGRAM
    [123@5455455] > }
    [123@5455455] >
    [123@5455455] > :set ParseLogAccountEndArrayID $EndArrayID;
    [123@5455455] >
    [123@5455455] > :log info «Script ParseLogAccountEvents: script completed successfully.»;

    Подскажи что надо подправить в скрипте?

    Ответить
  5. Подскажите пожалуйста, что в понимании скрипта ParseLogAccountEndArrayID (хранит ID последнего элемента) что за ID? Это номер в логе, просто у меня потолок в 1000 записей…

    Ответить
    • При каждой перезагрузке роутера MikroTik очищает переменные и журнал устройства, после чего начинает вести журнал с ID=0.
      ID является служебным параметром устройства и не отображается для пользователя.
      Каждое событие в журнале устройства увеличивает счетчик ID на единицу.
      Количество элементов журнала системы вы можете задать вручную, например /system logging action set memory memory-lines=10 — очистит журнал устройства и установит хранение 10 записей, после чего записи будут затираться.
      Но изменение параметров журнала не затрагивает ID событий, счётчик ID будет по прежнему увеличиваться.

      Ответить
      • Никак не могу скрестить этот скрипт и другой, прошу помощи… ?
        Вот что имеем:

        # Monitoring password brute force and sending notifications to telegrams
        # Search for «login failure» records in the last 10 minutes
        :local loglist [:toarray [/log find time>([/system clock get time] — 10m) message~»login failure»]]
        # For all records, the loop
        :foreach i in=$loglist do={
        # Search message
        :local logMessage [/log get $i message]
        # Search ip, user, service
        :local ip [:pick $logMessage ([:find $logMessage «from»]+5) [:find $logMessage » via»]]
        :local user [:pick $logMessage ([:find $logMessage «user»]+5) [:find $logMessage » from»]]
        :local service [:pick $logMessage ([:find $logMessage «via»]+4) ([:find $logMessage «via»]+30)]
        # Sending a message to telegram
        :local MessageText «$DeviceModel —> \E2\9D\97 [$date $time]%0D%0Alogin failure for user $user from $ip via $service \E2\9D\97″;
        :local tgUrl «https://api.telegram.org/bot$BotToken/sendMessage?chat_id=$ChatID&text=$MessageText&parse_mode=$ParseMode&disable_web_page_preview=$DisableWebPagePreview&disable_notification=$DisableNotification»;
        /tool fetch http-method=get url=$tgUrl keep-result=no;
        :delay 5
        }

        Хотелось бы проводить поиск записей по глобальной переменной, а не по кругу каждые 10 минут (работает криво по ночам)

        Ответить
        • 1. Это тема следующей статьи.

          2. Разбираться в чужих скриптах — нет времени, а конструкции вида:
          :local service [:pick $logMessage ([:find $logMessage «via»]+4) ([:find $logMessage «via»]+30)]
          нечитаемы, плохо изменяемы и отбивают желание разбираться. 🙂
          Я могу писать «сжатый код», но это отвратительный подход, когда пишешь код для использования другими.

          3. «работает криво по ночам» — почему так, написал в статье на Habr.

        • Большое спасибо за скрипт в статье, все таки удалось сделать, что хотел (тоже самое, но с неудачными попытками входа).
          А то, что вы называете нечитаемым и плохо изменяемым, так это «выковыривание» нужных слов из лога. Нормальное решение кмк если нужен не весь текст сообщения, а определенная часть =)
          Либо так, либо через регулярные выражения, которые тоже не фонтан как читаемы.

  6. Добрый день. Опять обращаюсь за помощью к Вам. Дело в том, что Ваш скрипт перестал работать по не понятной мне причине. Логирование скрипта при ручной отработке скрипта показывает, что скрипт отработал но при этом сообщения в телеграмм не поступают (на email не настраивал из-за ненадобности). Попробовал настроить по способу, описанному на хабре и он заработал но на долго ли непонятно… Настроил таким же способом два других микротика hap ac2 (предыдущий cAP ac), находящихся в других сетях, скрипт не работает. Лог показал только:
    13:23:31 script,info Script ParseLogAccountEvents: running.
    13:23:31 script,info Script ParseLogAccountEvents: script completed successfully.
    Строка логирования :log info «Script ParseLogAccountEvents: New events found.».
    вот сам скрипт: https://pastebin.ubuntu.com/p/4cP7fZkbSV/
    И в дополнение: при добавлении в планировщик скрипта через терминал перед » /system script run ParseLogAccountEvents» появляется пробел. имеет ли он значение? нужен ли?

    Ответить
    • Проверьте что в тексте Телеграм сообщения не используются спец. символы (например в названии устройства), типа разного вида скобок, кавычек и подобного. По логу видно, что скрипт работает, сообщения находит, но так как финального лог сообщения нет, скрипт валится на моменте отправки. Отключите авто выполнение скрипта, выполните вход и запустите вручную, если выдаст сообщение при отправке — ищите проблему в тексте сообщения Телеграм, а это будет название устройства.

      Ответить
  7. Добрый день. Разобрался в чем ошибка была. Дело в том, интервал обновления скрипта стоит 5 минут и он выдает все значения попавшие в этот промежуток времени. А поскольку я заходил моногократно (проверял работу), то и соответственно в телегу вывалился, соответственно, большой список входов и выходов одним сообщением. Думаю нужно уменьшить данный интервал. И сразу вопрос: если поставить интервал проверки/срабатывания скрипта 30 сек. на сколько возрастет нагрузка на роутер и какую строку в скрипте нужно удалить, чтоб скрипт при проверке не прописывался в логе, а то с интервалом 30 сек. лог вырос в разы? Спасибо за помощь!

    Ответить
    • На практике вы не будете забегать каждую минуту, а даже 5 минутный интервал даст понять, что на устройстве появился «непрошенный гость».
      Лучше строки логов не удалять, а закомментировать. Поставьте перед строкой которая пишет в лог символ # , например #:log info "Script ParseLogAccountEvents: running.";
      Про нагрузку — создаст совершенно незначительную, незаметную для устройства. Можете поставить проверку скрипта через 3 сек и посмотреть загрузку CPU.

      Ответить
  8. Заработало, только теперь по каждому запросу sheduler он присылает одним сообщением все подключения которые были ранее. вот лог:
    17:25:24 info fetch: file «b> %0D%0A 17:25:17 — user ItadminARS logged in from 04:… via winbox;&parse_mode=html&disable_web_page_p
    review=True» downloaded
    17:25:25 script,info Send Telegram Message: \F0\9F\94\93 MikroTik cap ac ….: AUTH %0D%0A 17:25:17 — user It logged in from
    04:…. via winbox;
    17:25:25 script,info Script ParseLogAccountEvents: script completed successfully.
    17:26:29 system,info,account user It logged out from 04:… via winbox
    17:26:31 system,info,account user It logged out from 04:… via winbox
    17:26:31 system,info,account user It logged in from 04:… via winbox
    17:27:03 system,info changed scheduled script settings by ItadminARS
    17:27:12 script,info Script ParseLogAccountEvents: running.
    17:27:12 script,info Script ParseLogAccountEvents: New events found.
    17:27:12 script,info Script ParseLogAccountEvents: Events processed. Sending notifications.
    17:27:13 system,info,account user It logged out from 04:… via winbox
    17:27:15 system,info,account user It logged in from 04:… via winbox
    17:28:12 script,info Script ParseLogAccountEvents: running.
    17:28:12 script,info Script ParseLogAccountEvents: New events found.
    17:28:12 script,info Script ParseLogAccountEvents: Events processed. Sending notifications.
    17:29:12 script,info Script ParseLogAccountEvents: running.
    17:29:12 script,info Script ParseLogAccountEvents: New events found.
    17:29:12 script,info Script ParseLogAccountEvents: Events processed. Sending notifications.
    17:29:13 system,info,account user ItadminARS logged in via local

    вот сообщения с телеграмма:
    17:26:29 — user It logged out from 04:…. via winbox;
    17:26:31 — user It logged out from 04:…. via winbox;
    17:26:31 — user It logged in from 04:…. via winbox;
    17:27:13 — user It logged out from 04:…. via winbox;
    17:27:15 — user It logged in from 04:…. via winbox;
    17:29:13 — user It logged in via local;

    Ответить
    • Если он каждый интервал присылает все предыдущие сообщения значит, что-то мешает записать новое значение переменной ParseLogAccountEndArrayID, например ошибка в скрипте, которая прерывает скрипт до момента записи или отсутствие прав. Проверьте что права выставлены именно так как в статье, не больше. Не размещайте код скрипта с комментарии, разместите код например на Пастебин и скиньте сюда ссылкой.

      Ответить
  9. Добрый день. Настраивал по Вашим скриптам почему-то у меня не отрабатывает скрипт отправки сообщения боту в телеграмм (отдельно настраивал отправку в телеграмм и отдельно на mail). На mail сообщение приходит, повторюсь, а вот в телегу нет. сделал 2 скрипта: MyTGBotSendMessage и SebdMassegeToTelegram, и проверил работу (Run Skript). В телегу пришло сообщение: «MikroTik: italic inline fixed-width code plain text More Scripts (https://mhelp.pro/)». А вот при проверке скрипта ParseLogAccountEvents (предварительно вычленив из него отправку сообщения на почту) ничего не происходит, в логах никаких записей. Скрипт получился такой:
    :local DeviceName [/system identity get name];
    :local Time [/system clock get time];
    :local Date [/system clock get date];
    :local TelegramMessageText;

    :global ParseLogAccountEndArrayID;

    :local IDsEventsAccount [/log find where topics ~ "account"];

    :local LenArrayIDs [:len $IDsEventsAccount];
    :local StartArrayID [:find $IDsEventsAccount $ParseLogAccountEndArrayID];
    :local EndArrayID ($IDsEventsAccount -> ($LenArrayIDs-1));

    :if ($EndArrayID != $ParseLogAccountEndArrayID and [:tobool $ParseLogAccountEndArrayID] ) do={

    :for KeyArray from=($StartArrayID+1) to=($LenArrayIDs-1) do={
    :local IDMessage ($IDsEventsAccount ->$KeyArray );
    :set EmailMessageText "$EmailMessageText \n\r $[/log get number=$IDMessage time] - $[/log get number=$IDMessage message];";
    :set TelegramMessageText "$TelegramMessageText %0D%0A $[/log get number=$IDMessage time] - $[/log get number=$IDMessage message];";
    }

    :local MessageText "\F0\9F\94\93 $DeviceName: AUTH $TelegramMessageText";
    :local SendTelegramMessage [:parse [/system script get MyTGBotSendMessage source]];
    $SendTelegramMessage MessageText=$MessageText;
    }

    :set ParseLogAccountEndArrayID $EndArrayID;

    Ответить
    • Обновил скрипт в статье, добавив логирование.
      Добавьте у себя так же (строки логов, где они стоят по тексту).
      Переписав скрипт, удалите глобальную переменную ParseLogAccountEndArrayID в System — Script — Environment.
      Запустите скрипт, после чего выполните параллельный вход на устройство, снова запустите скрипт и напишите мне результат.

      Ответить
  10. в логах данные есть по входу, счетчик по срабатыванию скриптов растет.
    ни в почте, ни в телеге алертов нет…
    как проверить? в логах может отдельно надо чего сделать для отображения ошибок отправки?

    Ответить
    • Здравствуйте. Скрипт использует использует отдельные скрипты для отправки почты и Телеграм сообщений.
      Процедура проверки:
      1. Убедитесь что функции отправки почты и Телеграм работают нормально отдельно от скрипта «уведомления о входящих юзерах»;
      2. Если скрипты отправки почты и Телеграм, по-отдельности, работают нормально, значит проблема в том тексте который вы им передаете. Микротик утыкается в первую ошибку и прерывает скрипт. Удалите из скрипта поочередно модуль почты и Телеграм, проверяя поочередно какой из способов уведомления работает.

      Общий совет, если меняли названия скриптов проверьте что при вызове из скрипта «проверка входа», вы пытаетесь вызвать свои переименованные скрипты.
      Напишите, разберемся. Можете добавиться в Телеграм MHelp.pro.

      Ответить
  11. Здравствуйте.
    RouterBOARD 952Ui-5ac2nD
    Installed Version 6.47.8
    Latest Version 6.47.8

    При выполнении скрипта ничего не происходит.
    Пробовал как из Habr статьи так и с этого сайта (отдельно создал для отправки сообщений через телегу — скрипт отрабатывает, тестовое сообщение отправляется).
    Куда копать не понятно, т.к. под копирку все создал

    Ответить
    • Здравствуйте Алексей, большое спасибо что нашли время написать.
      Это моя оплошность, на Хабре была опубликована предыдущая версия скрипта. Для Хабра: перенесите строку :set ParseLogAccountEndArrayID $EndArrayID; из середины скрипта, в самый конец.
      На данном сайте расположена последняя, работающая версия скрипта.
      Сделал копи/паст с этой страницы.
      Скрипт отработал нормально, проверено на:
      RouterBOARD RB941-2nD
      Installed Version 6.47.7 (stable)
      НО, посмотрите журнал устройства, если вы получаете сообщения вида could not run script ParseLogAccountEvents: not enough permissions выставьте права на запускающий скрипт в Sceduler и сам скрипт ParseLogAccountEvents как указано в статье (read, write, test, policy). Заметил проблему, что при максимальных правах на скрипт Микротик ругается на недостаток прав для запуска.

      Ответить

Оставьте комментарий