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

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


mikrotik:rb3011uias:routeros:system:scripts:failover

Это старая версия документа!


Скрипт для переключения Интернет-каналов на MiktoTik

:!: Настоящий скрипт является сильно переработанной версией скрипта Дмитрия. Огромная нечеловеческая благодарность ему за оригинал! 8-)

Скрипт разрабатывался для работы на MikroTik RB3011UiAS с RouterOS 6.46.3.

Функции скрипта

  1. Проверять основной Интернет-канал
  2. Проверять резервный Интернет-канал
  3. Автоматически переключать каналы
  4. Отключать/включать гостевую Wi-Fi сеть
  5. Отправлять уведомления по SMS
  6. Уведомлять сотрудников по Email
  7. Принимать удаленные SMS команды

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

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

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

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

:global eventEmail;
:global pingCount;
:global stableConnectFrom;
:global setFailCounter;
:global ether1Name;
:global ether2Name;

Объявление локальных переменных.

  • failoverScriptName должен совпадать с названием этого скрипта;
    • К сожалению, не нашел как этот процесс автоматизировать…
  • startModeEvent - это метка для логов по умолчанию;
  • failoverRunTime - максимальное время работы этого скрипта в секундах, вычисляется эмпирически;
:local failoverScriptName "failover";
:local startModeEvent "failover-scheduler";
:local failoverRunTime 30;

Объявление глобальных переменных, которые используются только этим скриптом, а также инициализация переменной pingFailCount, если она имеет не правильный тип.

:global pastCheckStatus;
:global failoverRun;
:global pingFailCount;
:if ( [ :typeof $pingFailCount ] = "nil" || [ :typeof $pingFailCount ] = "nothing" ) do={ :set pingFailCount $setFailCounter; }

# Local variables used in the script.

:local ether1Route;
:local ether2Route;
:local pingCountTotal ($pingCount * 2);
:local stableConnect $stableConnectFrom;
:local gateway1ip;
:local gateway2ip;
:local pingStatus;

Проверка двойного запуска

# Prohibition of execution of the second copy of the script and waiting for the completion of the first (the delay is calculated empirically for the current version of the script)

:if ( $failoverRun != true ) do={ :set failoverRun true; } else={
  :local alreadyRun "Script is already running, after $failoverRunTime seconds we will try again, do not worry.";
  :local scrComplete "Execution of the previous script is completed, continue execution of the current script.";
  :log warning ("$alreadyRun");
  $sendEvent msg=$alreadyRun;
  :delay $failoverRunTime;
  :if ( $failoverRun = true ) do={
    :local didtComplete "Script did not complete in $failoverRunTime seconds, execution of the current script and schedule stopped!";
    /system scheduler set [find on-event="$failoverScriptName"] disable=yes comment="$didtComplete";
    :log error ("$didtComplete");
    $sendEvent msg=$didtComplete;
    :set failoverRun false;
    :error "$didtComplete";
    } else={
      :log info ("$scrComplete");
      :set failoverRun true; }
}

SMS команды

# SMS command to force switch to the backup channel and disable the scheduler

:if ( $channel = "backup") do={
  :set stableConnect 60;
  :set pastCheckStatus false;
  :set startModeEvent "failover-man-back";
  :local ChannelSw "Channel switched to the $ether2Name manually via SMS, schedule stopped!";
  /system scheduler set [find on-event="$failoverScriptName"] disable=yes comment="$ChannelSw";
  :log warning ("$ChannelSw");
  $sendEvent msg=$ChannelSw;
}

# SMS command to force switch to the main channel and disable the scheduler

:if ( $channel = "primary") do={
  :set stableConnect -60;
  :set startModeEvent "failover-man-prim";
  :local ChannelSw "Channel switched to the $ether1Name manually via SMS, schedule stopped!";
  /system scheduler set [find on-event="$failoverScriptName"] disable=yes comment="$ChannelSw";
  :log warning ("$ChannelSw");
  $sendEvent msg=$ChannelSw;
}

# The command to enable automatic channel selection

:if ( $channel = "auto") do={
  :local ChannelSw "Automatic channel selection enabled via SMS, schedule running.";
  /system scheduler set [find on-event="$failoverScriptName"] disable=no comment="";
  :log warning ("$ChannelSw");
  $sendEvent msg=$ChannelSw;
  :set failoverRun false; 
  :error "The script completed its task and stopped!";
}

# SMS command to check both channels and send a report

:if ( $channel = "test") do={
  :local ether1Status [ $pingSession pingFrom=$ether1Name myPingCount=8; ];
  $ispLogging outInt=$ether1Name receivedPing=$ether1Status totalPing=16 startMode="failover-sms" newFileAt=month;
  :local ether2Status [ $pingSession pingFrom=$ether2Name myPingCount=8; ];
  $ispLogging outInt=$ether2Name receivedPing=$ether2Status totalPing=16 startMode="failover-sms" newFileAt=month;
  :local channelStatus "Received ping's:\r\n$ether1Name - $ether1Status/16;\r\n$ether2Name - $ether2Status/16";
  $sendEvent msg=$channelStatus;
  :set failoverRun false; 
  :error "The script completed its task and stopped!";
}

Проверка маршрутов

# Checking routes, if one of them is not - turn off the sheduler, error and send an alert

/ip route { :do {
  :set gateway1ip [get [find dst-address="0.0.0.0/0" gateway-status~"$ether1Name"] gateway];
  :set gateway2ip [get [find dst-address="0.0.0.0/0" gateway-status~"$ether2Name"] gateway];
  } on-error={
    :local noRoute "No default route found for channel $ether1Name or $ether2Name, schedule stopped!";
    /system scheduler set [find on-event="$failoverScriptName"] disable=yes comment="$noRoute";
    :log error ("$noRoute");
    $sendEvent msg=$noRoute;
    :set failoverRun false;
    :error "$noRoute"; }
}

# Selective ARP cleaning function, not used

:local clearArp do={
  :global ether1Name;
  :global ether2Name;
    /ip arp remove [find interface="$ether1Name" || interface="$ether2Name"];
    :log warning ("ARP for $ether1Name and $ether2Name removed!");
}

Функция для CAPsMAN

# Function of switching guest network availability through CAPsMAN

:local swWireless do={
  /caps-man provisioning {
    :if ( $hotSpotOff = "yes" ) do={
      set [find name-prefix~"Wi.Ghs"] disable=yes;
      set [find name-prefix~"Wi.Gln"] disable=no;
      :log warning ("CAPsMAN settings has changed: mobile Wi-Fi disabled!");
      } else={
        set [find name-prefix~"Wi.Ghs"] disable=no;
        set [find name-prefix~"Wi.Gln"] disable=yes;
        :log info ("CAPsMAN settings has changed: mobile Wi-Fi enabled!"); }
      }
  /caps-man radio provision [find remote-cap-identity~"cs-ap"];
}

Проверка интерфейсов

# Check interfaces, if any is turned off - turn on

/interface ethernet {
  :if ( [get $ether1Name disable] = true ) do={
    set $ether1Name disable=no;
    :delay 2s;
  }
  :if ( [get $ether2Name disable] = true ) do={
    set $ether2Name disable=no;
    :delay 2s;
  }
}

Проверка резервного канала

# Call ping session function to check the backup channel

:set pingStatus [ $pingSession pingFrom=$ether2Name; ];

# Checking the response of the function and suppressing frequent alerts about the failure of the backup channel

 :if ( $pingStatus < $stableConnectFrom ) do={
  :if ( $pingFailCount = $setFailCounter ) do={
    $ispLogging outInt=$ether2Name receivedPing=$pingStatus totalPing=$pingCountTotal startMode=$startModeEvent newFileAt=month;
    :local noInet "$ether2Name failure (received $pingStatus/$pingCountTotal)!";
    :log error ("$noInet");
    $sendEvent msg=$noInet;
    :set pingFailCount 0; } else={ :set pingFailCount ( $pingFailCount + 1 ); }
    } else={
      :if ( $pingFailCount != $setFailCounter ) do={
        $ispLogging outInt=$ether2Name receivedPing=$pingStatus totalPing=$pingCountTotal startMode=$startModeEvent newFileAt=month;
        :set pingFailCount $setFailCounter;
        :local worksFine "$ether2Name works fine (received $pingStatus/$pingCountTotal).";
        $sendEvent msg=$worksFine;
        :log info ("$worksFine"); }
}

# Script kernel - checks the availability of the main channel, switches to the backup and sends notifications to the administrator and employees

/ip route {
  :set ether1Route [find dst-address="0.0.0.0/0" gateway=$gateway1ip];
  :set ether2Route [find dst-address="0.0.0.0/0" gateway=$gateway2ip];

Тексты писем

# Text strings used in the email to employees on the mailing list.

  :local eventHeader "Header,";
  :local eventTextBackup "Text\r\n\r\nBackup";
  :local eventTextPrimary "Text\r\nPrimary";
  :local eventSign "Sign";
  :local dateTime ([/system clock get date]."@".[/system clock get time]);
  :local userSubjBackup "Subj Backup $dateTime";
  :local userSubjPrimary "Subj Primary $dateTime";
  :local eventPrimary "$eventHeader\r\n\r\n$eventTextPrimary\r\n\r\n$eventSign";
  :local eventBackup "$eventHeader\r\n\r\n$eventTextBackup\r\n\r\n$eventSign";

Корректировка маршрутов

  :if ( [get $ether1Route distance] != 2 ) do={
    set $ether1Route distance=2;
    :log warning ("Distance for " . $ether1Name . " corrected!");
  }
  :if ( [get $ether2Route distance] != 1 && [get $ether2Route distance] != 3 ) do={
    set $ether2Route distance=3;
    :log warning ("Distance for " . $ether2Name . " corrected!");
  }

Проверка основного канала

:local pingStatus [ $pingSession pingFrom=$ether1Name; ];
  :if ( $pingStatus < $stableConnect ) do={
    :if ( [get $ether2Route distance] != 1 ) do={
      $ispLogging outInt=$ether1Name receivedPing=$pingStatus totalPing=$pingCountTotal startMode=$startModeEvent newFileAt=month;
      :local noPriInet "$ether1Name failure (received $pingStatus/$pingCountTotal), $ether2Name enabled!";
      :if ( $pastCheckStatus = false ) do={
        set $ether2Route distance=1;
        :log warning ("Distance for " . $ether2Name . " changed!");
#        $clearArp;
        $swWireless hotSpotOff=yes;
        :log error ("$noPriInet");
        $sendEvent msg=$noPriInet;
        $sendEvent mode=mail to=$eventEmail subj=$userSubjBackup msg=$eventBackup;
        } else={
          :local badPriInet "$ether1Name is bad (received $pingStatus/$pingCountTotal)!";
          :log warning ("$badPriInet");
          $sendEvent msg=$badPriInet;
          :set pastCheckStatus false; }
      }
      } else={
        :if ( [get $ether2Route distance] != 3 ) do={
          $ispLogging outInt=$ether1Name receivedPing=$pingStatus totalPing=$pingCountTotal startMode=$startModeEvent newFileAt=month;
          :local PriInetGood "$ether1Name connected (received $pingStatus/$pingCountTotal), $ether2Name disabled.";
          :log warning ("$PriInetGood");
          set $ether2Route distance=3;
          :log warning ("Distance for " . $ether2Name . " changed!");
#          $clearArp;
          $swWireless;
          $sendEvent msg=$PriInetGood;
          $sendEvent mode=mail to=$eventEmail subj=$userSubjPrimary msg=$eventPrimary;
        }
        :set pastCheckStatus true;
      }
}
:set failoverRun false;

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

failover.rsc
add comment="\D2\E5\F1\F2\E8\F0\EE\E2\E0\ED\E8\E5 \E8\ED\F2\E5\F0\ED\E5\F2 \EA\
    \E0\ED\E0\EB\EE\E2 \E8 \EF\E5\F0\E5\EA\EB\FE\F7\E5\ED\E8\E5 \ED\E0 \F0\E5\
    \E7\E5\F0\E2\ED\FB\E9" dont-require-permissions=no name=script1 owner=\
    petya policy=ftp,read,write,policy,test,sensitive source="# Written by Nik\
    olay Soloshin (nikolay@soloshin.su) for RouterOS v6.46.3 on RB3011UiAS (ar\
    m) @ 2020.03\r\
    \n# Based on script \"Mikrotik Advanced Failover\" by Dmitriy (https://web\
    lance.com.ua)\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 eventEmail;\r\
    \n:global pingCount;\r\
    \n:global stableConnectFrom;\r\
    \n:global setFailCounter;\r\
    \n:global ether1Name;\r\
    \n:global ether2Name;\r\
    \n\r\
    \n# Local variables\r\
    \n:local failoverScriptName \"failover\";\r\
    \n:local startModeEvent \"failover-scheduler\";\r\
    \n:local failoverRunTime 30;\r\
    \n\r\
    \n# Global variables set and used only by this script.\r\
    \n:global pastCheckStatus;\r\
    \n:global failoverRun;\r\
    \n:global pingFailCount;\r\
    \n:if ( [ :typeof \$pingFailCount ] = \"nil\" || [ :typeof \$pingFailCount\
    \_] = \"nothing\" ) do={ :set pingFailCount \$setFailCounter; }\r\
    \n\r\
    \n# Local variables used in the script.\r\
    \n:local ether1Route;\r\
    \n:local ether2Route;\r\
    \n:local pingCountTotal (\$pingCount * 2);\r\
    \n:local stableConnect \$stableConnectFrom;\r\
    \n:local gateway1ip;\r\
    \n:local gateway2ip;\r\
    \n:local pingStatus;\r\
    \n\r\
    \n# Prohibition of execution of the second copy of the script and waiting \
    for the completion of the first (the delay is calculated empirically for t\
    he current version of the script)\r\
    \n:if ( \$failoverRun != true ) do={ :set failoverRun true; } else={\r\
    \n  :local alreadyRun \"Script is already running, after \$failoverRunTime\
    \_seconds we will try again, do not worry.\";\r\
    \n  :local scrComplete \"Execution of the previous script is completed, co\
    ntinue execution of the current script.\";\r\
    \n  :log warning (\"\$alreadyRun\");\r\
    \n  \$sendEvent msg=\$alreadyRun;\r\
    \n  :delay \$failoverRunTime;\r\
    \n  :if ( \$failoverRun = true ) do={\r\
    \n    :local didtComplete \"Script did not complete in \$failoverRunTime s\
    econds, execution of the current script and schedule stopped!\";\r\
    \n    /system scheduler set [find on-event=\"\$failoverScriptName\"] disab\
    le=yes comment=\"\$didtComplete\";\r\
    \n    :log error (\"\$didtComplete\");\r\
    \n    \$sendEvent msg=\$didtComplete;\r\
    \n    :set failoverRun false;\r\
    \n    :error \"\$didtComplete\";\r\
    \n    } else={\r\
    \n      :log info (\"\$scrComplete\");\r\
    \n      :set failoverRun true; }\r\
    \n}\r\
    \n\r\
    \n# SMS command to force switch to the backup channel and disable the sche\
    duler\r\
    \n:if ( \$channel = \"backup\") do={\r\
    \n  :set stableConnect 60;\r\
    \n  :set pastCheckStatus false;\r\
    \n  :set startModeEvent \"failover-man-back\";\r\
    \n  :local ChannelSw \"Channel switched to the \$ether2Name manually via S\
    MS, schedule stopped!\";\r\
    \n  /system scheduler set [find on-event=\"\$failoverScriptName\"] disable\
    =yes comment=\"\$ChannelSw\";\r\
    \n  :log warning (\"\$ChannelSw\");\r\
    \n  \$sendEvent msg=\$ChannelSw;\r\
    \n}\r\
    \n\r\
    \n# SMS command to force switch to the main channel and disable the schedu\
    ler\r\
    \n:if ( \$channel = \"primary\") do={\r\
    \n  :set stableConnect -60;\r\
    \n  :set startModeEvent \"failover-man-prim\";\r\
    \n  :local ChannelSw \"Channel switched to the \$ether1Name manually via S\
    MS, schedule stopped!\";\r\
    \n  /system scheduler set [find on-event=\"\$failoverScriptName\"] disable\
    =yes comment=\"\$ChannelSw\";\r\
    \n  :log warning (\"\$ChannelSw\");\r\
    \n  \$sendEvent msg=\$ChannelSw;\r\
    \n}\r\
    \n\r\
    \n# The command to enable automatic channel selection\r\
    \n:if ( \$channel = \"auto\") do={\r\
    \n  :local ChannelSw \"Automatic channel selection enabled via SMS, schedu\
    le running.\";\r\
    \n  /system scheduler set [find on-event=\"\$failoverScriptName\"] disable\
    =no comment=\"\";\r\
    \n  :log warning (\"\$ChannelSw\");\r\
    \n  \$sendEvent msg=\$ChannelSw;\r\
    \n  :set failoverRun false; \r\
    \n  :error \"The script completed its task and stopped!\";\r\
    \n}\r\
    \n\r\
    \n# SMS command to check both channels and send a report\r\
    \n:if ( \$channel = \"test\") do={\r\
    \n  :local ether1Status [ \$pingSession pingFrom=\$ether1Name myPingCount=\
    8; ];\r\
    \n  \$ispLogging outInt=\$ether1Name receivedPing=\$ether1Status totalPing\
    =16 startMode=\"failover-sms\" newFileAt=month;\r\
    \n  :local ether2Status [ \$pingSession pingFrom=\$ether2Name myPingCount=\
    8; ];\r\
    \n  \$ispLogging outInt=\$ether2Name receivedPing=\$ether2Status totalPing\
    =16 startMode=\"failover-sms\" newFileAt=month;\r\
    \n  :local channelStatus \"Received ping's:\\r\\n\$ether1Name - \$ether1St\
    atus/16;\\r\\n\$ether2Name - \$ether2Status/16\";\r\
    \n  \$sendEvent msg=\$channelStatus;\r\
    \n  :set failoverRun false; \r\
    \n  :error \"The script completed its task and stopped!\";\r\
    \n}\r\
    \n\r\
    \n# Checking routes, if one of them is not - turn off the sheduler, error \
    and send an alert\r\
    \n/ip route { :do {\r\
    \n  :set gateway1ip [get [find dst-address=\"0.0.0.0/0\" gateway-status~\"\
    \$ether1Name\"] gateway];\r\
    \n  :set gateway2ip [get [find dst-address=\"0.0.0.0/0\" gateway-status~\"\
    \$ether2Name\"] gateway];\r\
    \n  } on-error={\r\
    \n    :local noRoute \"No default route found for channel \$ether1Name or \
    \$ether2Name, schedule stopped!\";\r\
    \n    /system scheduler set [find on-event=\"\$failoverScriptName\"] disab\
    le=yes comment=\"\$noRoute\";\r\
    \n    :log error (\"\$noRoute\");\r\
    \n    \$sendEvent msg=\$noRoute;\r\
    \n    :set failoverRun false;\r\
    \n    :error \"\$noRoute\"; }\r\
    \n}\r\
    \n\r\
    \n# Selective ARP cleaning function, not used\r\
    \n:local clearArp do={\r\
    \n  :global ether1Name;\r\
    \n  :global ether2Name;\r\
    \n    /ip arp remove [find interface=\"\$ether1Name\" || interface=\"\$eth\
    er2Name\"];\r\
    \n    :log warning (\"ARP for \$ether1Name and \$ether2Name removed!\");\r\
    \n}\r\
    \n\r\
    \n# Function of switching guest network availability through CAPsMAN\r\
    \n:local swWireless do={\r\
    \n  /caps-man provisioning {\r\
    \n    :if ( \$hotSpotOff = \"yes\" ) do={\r\
    \n      set [find name-prefix~\"Wi.Ghs\"] disable=yes;\r\
    \n      set [find name-prefix~\"Wi.Gln\"] disable=no;\r\
    \n      :log warning (\"CAPsMAN settings has changed: mobile Wi-Fi disable\
    d!\");\r\
    \n      } else={\r\
    \n        set [find name-prefix~\"Wi.Ghs\"] disable=no;\r\
    \n        set [find name-prefix~\"Wi.Gln\"] disable=yes;\r\
    \n        :log info (\"CAPsMAN settings has changed: mobile Wi-Fi enabled!\
    \"); }\r\
    \n      }\r\
    \n  /caps-man radio provision [find remote-cap-identity~\"cs-ap\"];\r\
    \n}\r\
    \n\r\
    \n# Check interfaces, if any is turned off - turn on\r\
    \n/interface ethernet {\r\
    \n  :if ( [get \$ether1Name disable] = true ) do={\r\
    \n    set \$ether1Name disable=no;\r\
    \n    :delay 2s;\r\
    \n  }\r\
    \n  :if ( [get \$ether2Name disable] = true ) do={\r\
    \n    set \$ether2Name disable=no;\r\
    \n    :delay 2s;\r\
    \n  }\r\
    \n}\r\
    \n\r\
    \n# Call ping session function to check the backup channel\r\
    \n:set pingStatus [ \$pingSession pingFrom=\$ether2Name; ];\r\
    \n\r\
    \n# Checking the response of the function and suppressing frequent alerts \
    about the failure of the backup channel\r\
    \n :if ( \$pingStatus < \$stableConnectFrom ) do={\r\
    \n  :if ( \$pingFailCount = \$setFailCounter ) do={\r\
    \n    \$ispLogging outInt=\$ether2Name receivedPing=\$pingStatus totalPing\
    =\$pingCountTotal startMode=\$startModeEvent newFileAt=month;\r\
    \n    :local noInet \"\$ether2Name failure (received \$pingStatus/\$pingCo\
    untTotal)!\";\r\
    \n    :log error (\"\$noInet\");\r\
    \n    \$sendEvent msg=\$noInet;\r\
    \n    :set pingFailCount 0; } else={ :set pingFailCount ( \$pingFailCount \
    + 1 ); }\r\
    \n    } else={\r\
    \n      :if ( \$pingFailCount != \$setFailCounter ) do={\r\
    \n        \$ispLogging outInt=\$ether2Name receivedPing=\$pingStatus total\
    Ping=\$pingCountTotal startMode=\$startModeEvent newFileAt=month;\r\
    \n        :set pingFailCount \$setFailCounter;\r\
    \n        :local worksFine \"\$ether2Name works fine (received \$pingStatu\
    s/\$pingCountTotal).\";\r\
    \n        \$sendEvent msg=\$worksFine;\r\
    \n        :log info (\"\$worksFine\"); }\r\
    \n}\r\
    \n\r\
    \n# Script kernel - checks the availability of the main channel, switches \
    to the backup and sends notifications to the administrator and employees\r\
    \n/ip route {\r\
    \n  :set ether1Route [find dst-address=\"0.0.0.0/0\" gateway=\$gateway1ip]\
    ;\r\
    \n  :set ether2Route [find dst-address=\"0.0.0.0/0\" gateway=\$gateway2ip]\
    ;\r\
    \n\r\
    \n# Text strings used in the email to employees on the mailing list.\r\
    \n  :local eventHeader \"\D3\E2\E0\E6\E0\E5\EC\FB\E5 \EA\EE\EB\EB\E5\E3\E8\
    ,\";\r\
    \n  :local eventTextBackup \"\E2 \F1\E2\FF\E7\E8 \F1 \EF\E5\F0\E5\E1\EE\E5\
    \EC \E2 \F0\E0\E1\EE\F2\E5 \EE\F1\ED\EE\E2\ED\EE\E3\EE \E8\ED\F2\E5\F0\ED\
    \E5\F2-\EA\E0\ED\E0\EB\E0, \EE\F4\E8\F1 \EA\EE\EC\EF\E0\ED\E8\E8 \E1\FB\EB\
    \_\E0\E2\F2\EE\EC\E0\F2\E8\F7\E5\F1\EA\E8 \EF\E5\F0\E5\EA\EB\FE\F7\E5\ED \
    \ED\E0 \F0\E5\E7\E5\F0\E2\ED\FB\E9, \E0 Wi-Fi-\F1\E5\F2\FC \EE\F2\EA\EB\FE\
    \F7\E5\ED\E0!\\r\\n\\r\\n\CF\F0\EE\F8\F3 \EF\EE \E2\EE\E7\EC\EE\E6\ED\EE\
    \F1\F2\E8 \E2\EE\E7\E4\E5\F0\E6\E0\F2\FC\F1\FF \EE\F2 \EF\EE\F1\E5\F9\E5\
    \ED\E8\FF \C8\ED\F2\E5\F0\ED\E5\F2-\F0\E5\F1\F3\F0\F1\EE\E2 \E2 \FD\F2\EE\
    \F2, \EF\F0\FF\EC\EE \F1\EA\E0\E6\E5\EC, \ED\E5 \EF\F0\EE\F1\F2\EE\E9 \E4\
    \EB\FF \E2\F1\E5\F5 \ED\E0\F1 \EF\E5\F0\E8\EE\E4, \E8 \E7\E0\ED\FF\F2\FC\
    \F1\FF \F7\E5\EC-\F2\EE \E4\F0\F3\E3\E8\EC - \EE\E3\EB\FF\ED\E8\F2\E5\F1\
    \FC \E2\EE\EA\F0\F3\E3, \E2\EE\E7\EC\EE\E6\ED\EE, \F1\F2\EE\E8\F2 \EF\F0\
    \E8\E1\F0\E0\F2\FC\F1\FF \ED\E0 \F1\F2\EE\EB\E5 \E8 \F0\E0\E7\EE\E1\F0\E0\
    \F2\FC \E7\E0\EB\E5\E6\E0\E2\F8\E8\E5\F1\FF \E4\EE\EA\F3\EC\E5\ED\F2\FB\? \
    \CD\F3 \E8\EB\E8, \ED\EE \FD\F2\EE, \EA\EE\ED\E5\F7\ED\EE \E6\E5, \ED\E0 \
    \F1\E0\EC\FB\E9 \EA\F0\E0\E9\ED\E8\E9 \F1\EB\F3\F7\E0\E9, \E2\FB\E9\F2\E8 \
    \ED\E0 \F3\EB\E8\F6\F3 \E8 \EF\EE\EF\E8\F2\FC \F7\E0\E9\EA\F3\? \CD\E5\F2\
    \?.. \CD\F3 \EB\E0\E4\ED\EE. :)\\r\\n\\r\\n\C2\ED\E8\EC\E0\ED\E8\E5! \CE \
    \EF\E5\F0\E5\F5\EE\E4\E5 \ED\E0 \EE\F1\ED\EE\E2\ED\EE\E9 \EA\E0\ED\E0\EB \
    \E1\F3\E4\E5\F2 \F1\EE\EE\E1\F9\E5\ED\EE \EE\F2\E4\E5\EB\FC\ED\EE.\";\r\
    \n  :local eventTextPrimary \"\EE\F4\E8\F1 \EF\E5\F0\E5\EA\EB\FE\F7\E5\ED \
    \ED\E0 \EE\F1\ED\EE\E2\ED\EE\E9 \EA\E0\ED\E0\EB, \E0 Wi-Fi-\F1\E5\F2\FC \
    \F1\ED\EE\E2\E0 \E4\EE\F1\F2\F3\EF\ED\E0! \CD\E0\EA\EE\ED\E5\F6-\F2\EE!\\r\
    \\n\\r\\n\CC\EE\E6\E5\F2\E5 \EF\F0\EE\E4\EE\EB\E6\E8\F2\FC \F1\EC\EE\F2\F0\
    \E5\F2\FC \FD\F2\E8\F5 \E2\E0\F8\E8\F5 \EA\EE\F2\E8\EA\EE\E2 \E2 \ED\E5 \
    \EC\E5\ED\E5\E5 \FD\F2\E8\F5 \E2\E0\F8\E8\F5 \E8\ED\F2\E5\F0\ED\E5\F2\E0\
    \F5! \C5\F1\EB\E8, \EA\EE\ED\E5\F7\ED\EE, \E2\F1\E5 \F1\E4\E5\EB\E0\EB\E8 \
    \E8 \E8\EC\E5\E5\F2\E5 \EC\EE\F0\E0\EB\FC\ED\EE\E5 \EF\F0\E0\E2\EE. ;) \CA\
    \_\F1\EB\EE\E2\F3, \F3\F7\E5\ED\FB\E5 \E4\EE\EA\E0\E7\E0\EB\E8, \F7\F2\EE \
    \FD\F2\EE \EF\EE\EB\E5\E7\ED\EE. \CD\EE \F3\E2\EB\E5\EA\E0\F2\FC\F1\FF \E2\
    \F1\E5 \E6\E5 \ED\E5 \F1\F2\EE\E8\F2, \E1\EE\EB\FC\F8\EE\E9 \E1\F0\E0\F2 \
    \E1\E4\E8\F2, \F7\F2\EE \E5\EC\F3 \E1\F3\E4\E5\F2.\";\r\
    \n  :local eventSign \"\D1 \F3\E2\E0\E6\E5\ED\E8\E5\EC,\\r\\n\D0\FD\E9 \D1\
    \FD\EC\FE\FD\EB \D2\EE\EC\EB\E8\ED\F1\EE\ED.\";\r\
    \n\r\
    \n  :local dateTime ([/system clock get date].\"@\".[/system clock get tim\
    e]);\r\
    \n  :local userSubjBackup \"\D0\E5\E7\E5\F0\E2\ED\FB\E9 \EA\E0\ED\E0\EB \
    \E0\EA\F2\E8\E2\E8\F0\EE\E2\E0\ED \$dateTime\";\r\
    \n  :local userSubjPrimary \"\CE\F1\ED\EE\E2\ED\EE\E9 \EA\E0\ED\E0\EB \E0\
    \EA\F2\E8\E2\E8\F0\EE\E2\E0\ED \$dateTime\";\r\
    \n  :local eventPrimary \"\$eventHeader\\r\\n\\r\\n\$eventTextPrimary\\r\\\
    n\\r\\n\$eventSign\";\r\
    \n  :local eventBackup \"\$eventHeader\\r\\n\\r\\n\$eventTextBackup\\r\\n\
    \\r\\n\$eventSign\";\r\
    \n\r\
    \n  :if ( [get \$ether1Route distance] != 2 ) do={\r\
    \n    set \$ether1Route distance=2;\r\
    \n    :log warning (\"Distance for \" . \$ether1Name . \" corrected!\");\r\
    \n  }\r\
    \n\r\
    \n  :if ( [get \$ether2Route distance] != 1 && [get \$ether2Route distance\
    ] != 3 ) do={\r\
    \n    set \$ether2Route distance=3;\r\
    \n    :log warning (\"Distance for \" . \$ether2Name . \" corrected!\");\r\
    \n  }\r\
    \n\r\
    \n:local pingStatus [ \$pingSession pingFrom=\$ether1Name; ];\r\
    \n\r\
    \n  :if ( \$pingStatus < \$stableConnect ) do={\r\
    \n    :if ( [get \$ether2Route distance] != 1 ) do={\r\
    \n      \$ispLogging outInt=\$ether1Name receivedPing=\$pingStatus totalPi\
    ng=\$pingCountTotal startMode=\$startModeEvent newFileAt=month;\r\
    \n      :local noPriInet \"\$ether1Name failure (received \$pingStatus/\$p\
    ingCountTotal), \$ether2Name enabled!\";\r\
    \n      :if ( \$pastCheckStatus = false ) do={\r\
    \n        set \$ether2Route distance=1;\r\
    \n        :log warning (\"Distance for \" . \$ether2Name . \" changed!\");\
    \r\
    \n#        \$clearArp;\r\
    \n        \$swWireless hotSpotOff=yes;\r\
    \n        :log error (\"\$noPriInet\");\r\
    \n        \$sendEvent msg=\$noPriInet;\r\
    \n        \$sendEvent mode=mail to=\$eventEmail subj=\$userSubjBackup msg=\
    \$eventBackup;\r\
    \n        } else={\r\
    \n          :local badPriInet \"\$ether1Name is bad (received \$pingStatus\
    /\$pingCountTotal)!\";\r\
    \n          :log warning (\"\$badPriInet\");\r\
    \n          \$sendEvent msg=\$badPriInet;\r\
    \n          :set pastCheckStatus false; }\r\
    \n      }\r\
    \n      } else={\r\
    \n        :if ( [get \$ether2Route distance] != 3 ) do={\r\
    \n          \$ispLogging outInt=\$ether1Name receivedPing=\$pingStatus tot\
    alPing=\$pingCountTotal startMode=\$startModeEvent newFileAt=month;\r\
    \n          :local PriInetGood \"\$ether1Name connected (received \$pingSt\
    atus/\$pingCountTotal), \$ether2Name disabled.\";\r\
    \n          :log warning (\"\$PriInetGood\");\r\
    \n          set \$ether2Route distance=3;\r\
    \n          :log warning (\"Distance for \" . \$ether2Name . \" changed!\"\
    );\r\
    \n#          \$clearArp;\r\
    \n          \$swWireless;\r\
    \n          \$sendEvent msg=\$PriInetGood;\r\
    \n          \$sendEvent mode=mail to=\$eventEmail subj=\$userSubjPrimary m\
    sg=\$eventPrimary;\r\
    \n        }\r\
    \n        :set pastCheckStatus true;\r\
    \n      }\r\
    \n}\r\
    \n\r\
    \n:set failoverRun false;\r\
    \n\r\
    \n# With love from Vladivostok."

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

Скрипт должен выполняться периодически или может запускаться через SMS на номер модема с синтаксисом :cmd 12345 script failover channel=variable, где 12345, это секрет, назначенный при настройке приема SMS, а variable - одна из поддерживаемых переменных.

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

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

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

Обсуждение

Ваш комментарий:
H R F U S S F P D V Q A U J C N
 
Последнее изменение: 2022/02/12 11:40 (внешнее изменение)