Это старая версия документа!
Настоящий скрипт является сильно переработанной версией скрипта Дмитрия. Огромная нечеловеческая благодарность ему за оригинал!
Скрипт разрабатывался для работы на MikroTik RB3011UiAS с RouterOS 6.46.3.
# Functions used in the script. They are entered by the script «variable-initialization» when the device starts!
:global sendEvent; :global pingSession; :global ispLogging;
# These variables are set by the script «variables-initialization» when the device starts!
:global eventEmail; :global pingCount; :global stableConnectFrom; :global setFailCounter; :global ether1Name; :global ether2Name;
# Local variables
:local failoverScriptName "failover"; :local startModeEvent "failover-scheduler"; :local failoverRunTime 30;
# Global variables set and used only by this script.
: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 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!");
}
# 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;
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 - одна из поддерживаемых переменных.
Это минимально необходимый набор для работы скрипта.
Обсуждение