Инструменты пользователя

Инструменты сайта


mikrotik:rb3011uias:routeros:system:scripts:modem

Скрипт для управления USB-модемом через SMS

Скрипт предназначен для удаленного включения или выключения USB-модема, подключенного к MikroTik. Помимо этого он умеет тестировать поднятый канал, сбрасывать модем и, при необходимости, подключать удаленный доступ к WebFig. Естественно, для работы удаленного доступа модем должен иметь белый IP.

Комментарии к коду

Инициализация функций, используемых в скрипте. Эти функции вводятся скриптом «variable-initialization»!

:global sendEvent;
:global pingSession;
:global ispLogging;

Эти переменные также вводятся скриптом «variables-initialization».

:global pppNumber;
:global pingCount;

Настройка имени для удаленного доступа. Может не существовать в системе, тогда будет создано автоматически.

:local remoteName dasha;

Прочие нужные переменные. ;-)

:local interfaceName [/interface ppp-client get $pppNumber name];
:local pingCountTotal ($pingCount * 2);

Локальная функция простого генератора пин-кодов, основанного на текущей дате и времени, приправленные некоторым количеством псевдослучайных чисел. Используется для удаленного доступа к WebFig.

:local pinGen do={
     :local hourTemp ([:pick [/system clock get time] 0 2]);
     :local minuteTemp ([:pick [/system clock get time] 3 5]);
     :local secondTemp ([:pick [/system clock get time] 6 8]);
     :local dayTemp ([:pick [/system clock get date] 4 6]);
     :local arbitraryNumber 485;
     :local pickTemp;
     :set pickTemp ([:pick $secondTemp 0]);
     :local secondPick0 ([:pick "9563575442" $pickTemp]);
     :set pickTemp ([:pick $secondTemp 1]);
     :local secondPick1 ([:pick "9715837939" $pickTemp]);
     :set pickTemp ([:pick $minuteTemp 1]);
     :local minutePick1 ([:pick "8419467984" $pickTemp]);
     :set pickTemp;
     :local randomPick (($secondPick0 . $secondPick1 . $minutePick1));
     :local tempPin (($hourTemp+$minuteTemp+$secondTemp+$dayTemp+$randomPick)*($hourTemp+$dayTemp+$arbitraryNumber));
     :return $tempPin;
}

Включение модема

Включает модем и отчитывается посредством SMS.

:if ( $mode = "on" ) do={
  /interface ppp-client {
    :if ( [get $pppNumber disable] = true ) do={
      :log info ("Connecting modem via SMS command.");
      :do { set $pppNumber disable=no } on-error={
        :log warning ("Interface enabled at the second attempt!");
        set $pppNumber disable=no; }
      :delay 10s;
      $sendEvent mode=sms msg="Modem connected!";
      } else={ $sendEvent mode=sms msg="Modem is already connected!";
    }
  }
}

Баг и костыль

В версии RouterOS 6.46.3 (про другие не знаю) есть баг из-за которого, если в списке PPP интерфейсов есть только модем, он с первой попытки не включается, только со второй. Поэтому пришлось вводить костыль. Как только в списке их стало больше одного, добавилась постоянно подключенная VPN сессия, ошибка пропала!

Выключение модема

:if ( $mode = "off" ) do={
  /interface ppp-client {
    :if ( [get $pppNumber disable] = false ) do={
      set $pppNumber disable=yes;
      :log info ("Disconnecting modem via SMS command.");
      $sendEvent mode=sms msg="Modem disconnected!";
      } else={ $sendEvent mode=sms msg="Modem is already disconnected!";
    }
  }
}

Тестирование канала

Проверяет, поднят ли модем. Если нет то сообщает об этом и выходит. Если модем поднят, делает несколько сессий тестирования, пишет это в лог и отправляет результат в SMS.

:if ( $mode = "test" ) do={
  /interface ppp-client {
    :if ( [get $pppNumber disable] = true ) do={
      $sendEvent mode=sms msg="Modem disconnected!";
      } else={
        :local pingStatus;
        :set pingStatus [ $pingSession pingFrom=$interfaceName ];
        :local pingResult1 $pingStatus;
        $ispLogging outInt=$interfaceName receivedPing=$pingStatus totalPing=$pingCountTotal startMode="test-modem-sms" newFileAt=month;
        :delay 2s;
        :set pingStatus [ $pingSession pingFrom=$interfaceName ];
        $ispLogging outInt=$interfaceName receivedPing=$pingStatus totalPing=$pingCountTotal startMode="test-modem-sms" newFileAt=month;
        :local txtMsg "Received ping's:\r\nfirst test - $pingResult1/$pingCountTotal,\r\nsecond test - $pingStatus/$pingCountTotal";
        $sendEvent mode=sms msg=$txtMsg;
    }
  }
}

Аппаратный сброс

Пытается сделать USB Power reset и отправить SMS, если не получилось, отправляет Email.

:if ( $mode = "reset" ) do={
  :local smsError "Failed to enable SMS reception after modem reset!";
  :log warning ("Starting USB power reset via SMS command...");
  $sendEvent mode=sms msg="Power reset started...";
  :do { /interface ppp-client set $pppNumber disable=yes; } on-error={}
  :delay 10s;
  :do { /tool sms set receive-enabled=no; } on-error={}
  :delay 10s;
  /system routerboard usb power-reset duration=10s;
  :delay 30s;
  :do { /tool sms set receive-enabled=yes; } on-error={
      $sendEvent mode=mail body=$smsError;
      :error "$smsError"; }
  :delay 10s;
  $sendEvent mode=sms msg="Power reset complited!";
}

Включение удаленного доступа

При получении соответствующей команды происходит следующее:

  1. Проверяется, поднят ли модем
  2. Генерируется пин-код
  3. Включается учетная запись
    • Элемент ненумерованного спискаЕсли она не существует, то создается
  4. Присваивается учетной записи новый пин
  5. Выясняется внешний IP модема
  6. Включается web-сервер на 443 порту
    • Заранее необходимо импортировать или выпустить самоподписанный сертификат
  7. Включается заранее созданное правило фаервола
    • Поиск производится по id в комментарии
  8. Отправляется SMS с параметрами входа

Если команда на включение удаленного доступа отсутствует происходит следующее:

  1. Выключается пользователь
    • Любая ошибка игнорируется
  2. Выключается web-серве
  3. Выключается правило фаервола
  4. Отправляется SMS уведомление

Отдельной команды на выключение нет, т.к. оно выполняется при получении любых команд, кроме ping.

:if ( [/interface ppp-client get $pppNumber disable] = false && $remote = "on" ) do={
  :local tempPin;
  :do { /user set $remoteName disable=no; } on-error={
    /user add name="$remoteName" group="full" password="485158" disabled=no; }
  :set tempPin [$pinGen];
  /user set $remoteName password="$tempPin";
  :local pppAddress [/ip address get [find interface="$interfaceName"] address ];
  :local pppClearAddr ([:pick $pppAddress 0 [:find $pppAddress "/"]]);
  /ip service set www-ssl disable=no;
  /ip firewall filter set [find comment~"id4534233"] disabled=no;
  :local txtMsg "WebFig: https://$pppClearAddr; User: $remoteName, Password: $tempPin";
  $sendEvent mode=sms msg=$txtMsg;
  } else={
    :if ( $mode != "test" ) do={
      :do { /user set $remoteName disable=yes; } on-error={};
      /ip service set www-ssl disable=yes;
      /ip firewall filter set [find comment~"id4534233"] disabled=yes;
      :local txtMsg "User \"$remoteName\", WWW-service, FireWall filter rule and WebFig disabled!";
      $sendEvent mode=sms msg=$txtMsg; }
    }

Код для импорта

modem.rsc
/system script
add comment="\D3\E4\E0\EB\E5\ED\ED\EE\E5 \F3\EF\F0\E0\E2\EB\E5\ED\E8\E5 3G \EC\
    \EE\E4\E5\EC\EE\EC \F1 \EE\F2\EF\F0\E0\E2\EA\EE\E9 SMS" \
    dont-require-permissions=no name=modem owner=petya policy=\
    ftp,read,write,policy,test,password,sensitive source="# Written by Nikolay\
    \_Soloshin (nikolay@soloshin.su) for RouterOS v6.46.3 on RB3011UiAS (arm) \
    @ 2020.03\r\
    \n\r\
    \n# Functions used in the script. They are entered by the script \"variabl\
    e-initialization\" when the device starts!\r\
    \n:global sendEvent;\r\
    \n:global pingSession;\r\
    \n:global ispLogging;\r\
    \n\r\
    \n# These variables are set by the script \"variables-initialization\" whe\
    n the device starts!\r\
    \n:global pppNumber;\r\
    \n:global pingCount;\r\
    \n\r\
    \n# Local variables set and used only by this script.\r\
    \n# Remote control username\r\
    \n:local remoteName dasha;\r\
    \n\r\
    \n# Local variables used in the script.\r\
    \n:local interfaceName [/interface ppp-client get \$pppNumber name];\r\
    \n:local pingCountTotal (\$pingCount * 2);\r\
    \n\r\
    \n# Function. Simple pincode generator.\r\
    \n:local pinGen do={\r\
    \n     :local hourTemp ([:pick [/system clock get time] 0 2]);\r\
    \n     :local minuteTemp ([:pick [/system clock get time] 3 5]);\r\
    \n     :local secondTemp ([:pick [/system clock get time] 6 8]);\r\
    \n     :local dayTemp ([:pick [/system clock get date] 4 6]);\r\
    \n     :local arbitraryNumber 977;\r\
    \n     :local pickTemp;\r\
    \n     :set pickTemp ([:pick \$secondTemp 0]);\r\
    \n     :local secondPick0 ([:pick \"2346712653\" \$pickTemp]);\r\
    \n     :set pickTemp ([:pick \$secondTemp 1]);\r\
    \n     :local secondPick1 ([:pick \"5269938717\" \$pickTemp]);\r\
    \n     :set pickTemp ([:pick \$minuteTemp 1]);\r\
    \n     :local minutePick1 ([:pick \"4746588836\" \$pickTemp]);\r\
    \n     :set pickTemp;\r\
    \n     :local randomPick ((\$secondPick0 . \$secondPick1 . \$minutePick1))\
    ;\r\
    \n     :local tempPin ((\$hourTemp+\$minuteTemp+\$secondTemp+\$dayTemp+\$r\
    andomPick)*(\$hourTemp+\$dayTemp+\$arbitraryNumber));\r\
    \n     :return \$tempPin;\r\
    \n}\r\
    \n\r\
    \n# SMS command to turn on the modem\r\
    \n:if ( \$mode = \"on\" ) do={\r\
    \n  /interface ppp-client {\r\
    \n    :if ( [get \$pppNumber disable] = true ) do={\r\
    \n      :log info (\"Connecting modem via SMS command.\");\r\
    \n      :do { set \$pppNumber disable=no } on-error={\r\
    \n        :log warning (\"Interface enabled at the second attempt!\");\r\
    \n        set \$pppNumber disable=no; }\r\
    \n      :delay 10s;\r\
    \n      \$sendEvent mode=sms msg=\"Modem connected!\";\r\
    \n      } else={ \$sendEvent mode=sms msg=\"Modem is already connected!\";\
    \r\
    \n    }\r\
    \n  }\r\
    \n}\r\
    \n\r\
    \n# SMS command to turn off the modem\r\
    \n:if ( \$mode = \"off\" ) do={\r\
    \n  /interface ppp-client {\r\
    \n    :if ( [get \$pppNumber disable] = false ) do={\r\
    \n      set \$pppNumber disable=yes;\r\
    \n      :log info (\"Disconnecting modem via SMS command.\");\r\
    \n      \$sendEvent mode=sms msg=\"Modem disconnected!\";\r\
    \n      } else={ \$sendEvent mode=sms msg=\"Modem is already disconnected!\
    \";\r\
    \n    }\r\
    \n  }\r\
    \n}\r\
    \n\r\
    \n# SMS command for testing communication through a modem\r\
    \n:if ( \$mode = \"test\" ) do={\r\
    \n  /interface ppp-client {\r\
    \n    :if ( [get \$pppNumber disable] = true ) do={\r\
    \n      \$sendEvent mode=sms msg=\"Modem disconnected!\";\r\
    \n      } else={\r\
    \n        :local pingStatus;\r\
    \n        :set pingStatus [ \$pingSession pingFrom=\$interfaceName ];\r\
    \n        :local pingResult1 \$pingStatus;\r\
    \n        \$ispLogging outInt=\$interfaceName receivedPing=\$pingStatus to\
    talPing=\$pingCountTotal startMode=\"test-modem-sms\" newFileAt=month;\r\
    \n        :delay 2s;\r\
    \n        :set pingStatus [ \$pingSession pingFrom=\$interfaceName ];\r\
    \n        \$ispLogging outInt=\$interfaceName receivedPing=\$pingStatus to\
    talPing=\$pingCountTotal startMode=\"test-modem-sms\" newFileAt=month;\r\
    \n        :local txtMsg \"Received ping's:\\r\\nfirst test - \$pingResult1\
    /\$pingCountTotal,\\r\\nsecond test - \$pingStatus/\$pingCountTotal\";\r\
    \n        \$sendEvent mode=sms msg=\$txtMsg;\r\
    \n    }\r\
    \n  }\r\
    \n}\r\
    \n\r\
    \n# SMS command for hardware reset of the modem\r\
    \n:if ( \$mode = \"reset\" ) do={\r\
    \n  :local smsError \"Failed to enable SMS reception after modem reset!\";\
    \r\
    \n  :log warning (\"Starting USB power reset via SMS command...\");\r\
    \n  \$sendEvent mode=sms msg=\"Power reset started...\";\r\
    \n  :do { /interface ppp-client set \$pppNumber disable=yes; } on-error={}\
    \r\
    \n  :delay 10s;\r\
    \n  :do { /tool sms set receive-enabled=no; } on-error={}\r\
    \n  :delay 10s;\r\
    \n  /system routerboard usb power-reset duration=10s;\r\
    \n  :delay 30s;\r\
    \n  :do { /tool sms set receive-enabled=yes; } on-error={\r\
    \n      \$sendEvent mode=mail body=\$smsError;\r\
    \n      :error \"\$smsError\"; }\r\
    \n  :delay 10s;\r\
    \n  \$sendEvent mode=sms msg=\"Power reset complited!\";\r\
    \n}\r\
    \n\r\
    \n# SMS command to enable remote access (access is turned off automaticall\
    y when sending any commands except ping)\r\
    \n:if ( [/interface ppp-client get \$pppNumber disable] = false && \$remot\
    e = \"on\" ) do={\r\
    \n  :local tempPin;\r\
    \n  :do { /user set \$remoteName disable=no; } on-error={\r\
    \n    /user add name=\"\$remoteName\" group=\"full\" password=\"485158\" d\
    isabled=no; }\r\
    \n  :set tempPin [\$pinGen];\r\
    \n  /user set \$remoteName password=\"\$tempPin\";\r\
    \n  :local pppAddress [/ip address get [find interface=\"\$interfaceName\"\
    ] address ];\r\
    \n  :local pppClearAddr ([:pick \$pppAddress 0 [:find \$pppAddress \"/\"]]\
    );\r\
    \n  /ip service set www-ssl disable=no;\r\
    \n  /ip firewall filter set [find comment~\"id4534233\"] disabled=no;\r\
    \n  :local txtMsg \"WebFig: https://\$pppClearAddr; User: \$remoteName, Pa\
    ssword: \$tempPin\";\r\
    \n  \$sendEvent mode=sms msg=\$txtMsg;\r\
    \n  } else={\r\
    \n    :if ( \$mode != \"test\" ) do={\r\
    \n      :do { /user set \$remoteName disable=yes; } on-error={};\r\
    \n      /ip service set www-ssl disable=yes;\r\
    \n      /ip firewall filter set [find comment~\"id4534233\"] disabled=yes;\
    \r\
    \n      :local txtMsg \"User \\\"\$remoteName\\\", WWW-service, FireWall f\
    ilter rule and WebFig disabled!\";\r\
    \n      \$sendEvent mode=sms msg=\$txtMsg; }\r\
    \n    }\r\
    \n\r\
    \n# With love from Vladivostok."

Запуск скрипта

Скрипт запускается через SMS на номер модема с синтаксисом :cmd 12345 script modem mode=variable [remote=on], где 12345, это секрет, назначенный при настройке приема SMS, а variable - одна из поддерживаемых переменных.

Политики запуска

Это минимально необходимый набор для работы скрипта.

  • ftp,
  • read,
  • write,
  • policy,
  • test,
  • password,
  • sensitive.

Дисклеймер

  • Использование материалов данной базы знаний разрешено на условиях лицензии, указанной внизу каждой страницы! При использовании материалов активная гиперссылка на соответствующую страницу данной базы знаний обязательна!
  • Автор не несет и не может нести какую либо ответственность за последствия использования материалов, размещенных в данной базе знаний. Все материалы предоставляются по принципу «как есть». Используйте их исключительно на свой страх и риск.
  • Все высказывания, мысли или идеи автора, размещенные в материалах данной базе знаний, являются исключительно его личным субъективным мнением и могут не совпадать с мнением читателей!
  • При размещении ссылок в данной базе знаний на интернет-страницы третьих лиц автор не несет ответственности за их техническую функциональность (особенно отсутствие вирусов) и содержание! При обнаружении таких ссылок, можно и желательно сообщить о них в комментариях к соответствующей статье.

Обсуждение

Ваш комментарий:
K R A᠎ D T P S R P X S D O B Q S
 
Последнее изменение: 2022/02/12 11:40 (внешнее изменение)