@REM coding:OEM @ECHO OFF REM здесь надо указать путь к файлу журнала. Можно относительный, можно абсолютный. SET log="d:\var\logs\%~n0\%~n0.log" REM Журнал надо периодически чистить, делать logrotate то есть. Или можно просто удалять файл. REM цель только по IP (213.180.204.3), по hostname (ya.ru) нельзя, потому что: REM 1. связи с DNS может не быть, и соответственно имя в IP не разрешится REM 2. route add работает только с IP REM здесь указан первый IP OpenDNS SET target=208.67.222.222 rem Если не надо возвращаться с резервного канала при восстановлении основного, rem раскомментируйте следующую строчку. В этом случае меньше будет манипуляций с таблицей маршрутов. rem PING %target% -n 1 >>%log% 2>&1 && EXIT /B REM --- настройка закончена, дальше трогать ничего не надо --- REM последний использованный шлюз записан в currentgw.txt. Если файла нет, будет создан. FOR /F "usebackq delims=" %%I IN ("currentgw.txt") DO SET currentgw=%%I ECHO. ECHO currentgw.txt: %currentgw%|tee -a %log% CALL :ReadRoute currentgw 0.0.0.0 ECHO Current default route: %currentgw%|tee -a %log% REM Кроме, может быть, последней функции, где разбирается вывод ping-а. SET foundgw= REM небольшая вставка для мониторинга хостов IF EXIST "IPs_to_monitor.list" CALL :CheckHost %currentgw% && CALL :HostsMonitoring REM из файла gateways.list читаются IP адреса шлюзов (1 строка - 1 IP) REM начало цикла перебора шлюзов FOR /F "usebackq delims=" %%I IN ("gateways.list") DO ( CALL :CheckGateway %%I && EXIT /B ) REM собственно, если выполнение дошло сюда, значит ни через один из шлюзов цель недоступна. REM Либо настал конец Интернета, либо надо выбирать более лучше отличающихся провайдеров, REM либо просто умерла цель. Можно было бы сообщить что-н типа REM net send * Интернет кончился! Мы все умрём! REM Но я не буду. ECHO %DATE% %TIME% No working gateways found! EXIT /B :CheckGateway ECHO %DATE% %TIME% checking gateway %1|tee -a %log% REM проверяется связь со шлюзом ping %1 -n 1 rem >>%log% 2>&1 REM Пинги сначала идут через стандартный маршрут, REM поэтому пигновать что-либо за любым из роутеров бесполезно REM если шлюз не отвечает, продолжать нет смысла IF ERRORLEVEL 1 EXIT /B REM Шлюз отвечает, надо проверить, доступна ли через него цель (target) REM добавляется маршрут для цели, но только если текущий шлюз не тот же, что и проверяемый REM MASK 255.255.255.255 по умолчанию ROUTE DELETE %target% 2>&1 ping 127.0.0.1 -n 2 >NUL ECHO Adding temporary route to %target% through %1|tee -a %log% IF "%currentgw%"=="%1" GOTO :SkipAddingTempRoute ROUTE ADD %target% %1 METRIC 1 2>&1 |tee -a %log% CALL :CheckRoute %target% %1 || EXIT /B 1 REM если не подождать, Windows не успевает обновить таблицу маршрутов, REM и даже удаление перед закрывающей строчкой не удаётся с сообщением, REM что удалять нечего и маршрута нет. REM Но маршрут внезапно обнаруживается к следующему шагу цикла REM и не позволяет использовать следующий шлюз. ping 127.0.0.1 -n 2 >NUL :SkipAddingTempRoute ECHO Checking %target% availability|tee -a %log% REM проверка, и если ошибки нет, запись найденного работающего шлюза CALL :CheckHost %target% && SET foundgw=%1 IF NOT "%currentgw%"=="%foundgw%" ( ECHO Removing temporary route to %target%|tee -a %log% REM удаление временного маршрута. ROUTE DELETE %target% 2>&1 |tee -a %log% ping 127.0.0.1 -n 2 >NUL CALL :CheckRoute %target% %1 && ECHO Temporary route not removed!!!|tee -a %log% ) ECHO Current gateway: "%currentgw%" Working gateway: "%foundgw%"|tee -a %log% REM foundgw устанавливается только если найден шлюз, через который доступна цель REM но если он совпадает с тем, что используется сейчас, менять ничего не надо IF "%currentgw%"=="%foundgw%" EXIT /B 0 IF NOT "%foundgw%"=="" GOTO :SwitchGateway REM конец цикла перебора шлюзов EXIT /B 1 :SwitchGateway ECHO %DATE% %TIME% Switching route to %foundgw%|tee -a %log% REM Удаление старого маршрута ECHO Removing default route|tee -a %log% ROUTE DELETE 0.0.0.0 2>&1 |tee -a %log% ping 127.0.0.1 -n 2 >NUL CALL :CheckRoute 0.0.0.0 && ECHO Default route not removed!|tee -a %log% REM Добавление нового ECHO Adding default route through %foundgw%|tee -a %log% ROUTE ADD 0.0.0.0 MASK 0.0.0.0 %foundgw% METRIC 50 2>&1 |tee -a %log% CALL :CheckRoute 0.0.0.0 %foundgw% || ECHO New default route not added!|tee -a %log% REM и запись нового в файл ECHO %foundgw%>currentgw.txt EXIT /B 0 :ReadRoute rem Читает первый шлюз для %2 в переменную %1 FOR /F "usebackq tokens=1,3" %%I IN (`route print^|FIND " %~2 "`) DO IF "%%I"=="%~2" ( SET %~1=%%J EXIT /B 0 ) EXIT /B 1 :CheckRoute rem Проверка, что в существует маршрут до %1 через %2 rem ROUTE ADD не возвращает код ошибки, даже если маршрут добавить не удалось rem поэтому надо проверять, насколько удачно он добавился FOR /F "usebackq tokens=1,3" %%I IN (`route print^|FIND " %~1 "`) DO IF "%%I"=="%~1" ( IF "%~2"=="" EXIT /B 0 IF "%%J"=="%~2" EXIT /B 0 ) EXIT /B 1 rem Пинг сволочь, ибо возвращает 0 даже если ему ответили no route to host rem Наример: rem c:\Scripts>PING 208.67.222.222 -n 1 rem Pinging 208.67.222.222 with 32 bytes of data: rem Reply from 193.46.213.10: Destination host unreachable. rem Ping statistics for 208.67.222.222: rem Packets: Sent = 1, Received = 1, Lost = 0 (0% loss), rem Approximate round trip times in milli-seconds: rem Minimum = 0ms, Maximum = 0ms, Average = 0ms rem После этого errorlevel 0, видимо, потому что Lost = 0. Но связи-то нет! rem поэтому нужна следующая функция: :CheckHost rem FOR используется для разбора того, что пишет ping, поскольку код ошибки неадекватен. rem skip=3 значит, что из ответа надо пропустить первые 3 строки: rem пустая, обмен данными с ..., и ещё пустая. rem Если у Вас ответ PING выглядит по другому, эту часть надо исправлять. rem Например, в Vista skip=2 FOR /F "usebackq delims==: skip=3 tokens=1,2*" %%J IN (`PING %1 -n 1`) DO ( ECHO Pinging %1: %%J: %%K=%%L >>%log% rem Ping %1 -n 1 -r 4 >>%log% 2>&1 rem Следующая строка для русской версии Windows. Если у Вас английская, её можно закомментировать. IF NOT ERRORLEVEL 1 IF "%%~J"=="Ответ от %1" IF "%%~K"==" число байт" EXIT /B rem Если у Вас русская версия Windows, можно закомментировать следующую строчку. IF NOT ERRORLEVEL 1 IF "%%~J"=="Reply from %1" IF "%%~K"==" bytes" EXIT /B rem Возможно, у Вас ping будет отвечать, используя другие слова. rem В этом случае во второй IF вместо Reply from надо написать то, что написано до IP, rem а в 3й, вместо " bytes", то, что написано между двоеточием : и знаком равенства =, rem включая пробелы. rem Если первая строчка ответа PING не соответствует нормальному ответу можно выходить, rem Ибо сводка неинтересна. EXIT /B 1 ) rem Если выполнение дошло до сюда, значит PING ответил меньше skip= строк. rem Это явно что-то ненормальное, так что стоит записать в лог. ECHO Last ping reply contains less than 3 lines>>%log% ping %1 -n 1 >>%log% 2>&1 EXIT /B 1 :HostsMonitoring ECHO Hosts monitoring...|tee -a %log% FOR /F "usebackq tokens=1* delims=:" %%I IN ("IPs_to_monitor.list") DO ( CALL :CheckHost %%J && ECHO %%I %%J ok IF ERRORLEVEL 1 ( ECHO Error pinging %%I: %DATE% %TIME% %%J|tee -a "d:\var\logs\link-monitoring\%%~I %%~J.log" IF NOT EXIST "d:\var\logs\link-monitoring\pathping %%~I %%~J %DATE%.log" START "" %comspec% /C pathping %%~J ^>"d:\var\logs\link-monitoring\pathping %%~I %%~J %DATE%.log" 2^>^&1 ECHO %%I %%J failure ) ) EXIT /B