Multi VPN-channels switcher (failover)

Задача: имеется центральный офис, есть удаленный офис. Связь между офисами организована с помощью VPN ( L2TP/PTPP ). С целью резервирования имеется несколько каналов WAN, соотвественно несколько каналов VPN. Каналы VPN не привязаны к конкретному Wan  В каждый момент времени основным есть только один из каналов VPN. Особенность – через каждый из каналов должны быть доступны определенные ресурсы-сервера на стороне удаленного офиса.

Необходимо: при пропадании связи через основной попытаться установить связь через один из остальных. В качестве следующего основного выбирается первый из оставшихся VPN каналов, через который удалось установить связь.

Для начала рекомендую посмотреть/почитать следующие ссылки:

Mikrotik: load balancing

Mikrotik: Advanced Routing Failover without Scripting

Итак, какие вообще есть варианты и почему мы их не используем %) :

Вариант 1. С помощью метрик

То есть имеем несколько однотипных роутов, на одну и ту же сеть, но через разные каналы и с разными метриками. Если соединение разрывается, соответсвующий роут становится неактивным и трафик пойдет по другому активному роуту. Подвох тут в “если соединение разрывается”. Очень часто соединение остается активным, хотя трафик через него не может пройти. На помощь приходит свойство check-gateway = ping/arp (читаем Manual:IP/Route ). Если выставить этот параметр, то раз в 10 секунд роутер будет пинговать гейт. Если он два раза не отозвется, то гейт считается недоступным и роут будет неактивным.

Минусы – пингуется только гейт. Только каждые 10 секунд и только два пинга достаточно чтобы деактивировать роут. К примеру, для того же 3G/4G пропадание пару пингов – вполне обычная вещь…

Также особенность Микротика – если для какого-то роута гейт не пингуется, ВСЕ роуты использующие этот гейт (даже если это ECMP роут) , становятся неактивными (именно поэтому check-gateway имеет смысл ставить только в одном роуте, использующий конкретный гейт). А это уже может занчительно усложить жизнь админа при наличии ECMP роутов.

Насколько мне известно, check-gateway не работает, если в качестве гейт указан не IP, а интерфейс (что логично – чтобы пинговать, нужно знать, кого конкретно пинговать).

Можно ли пинговать не гейт, а что-то еще? Можно.

Вариант 2. Пингуем не гейты, а сервера за гейтом

Самый простой вариант с точки реализации – Advanced Routing Failover without Scripting . Если кратко – с помощью специальных роутов мы делаем доступными некоторые ресурсы за гейтами только через определенные каналы. В таком случа, если пропадет пинг на конкретный узел, это означает две вещи – либо “упал” соответсвующий канал, либо упал соответсвующий узел %). К примеру, если в качестве узлов используются общеизвестные DNS-сервера Google 8.8.8.8 и 8.8.4.4, то вероятность второго значительно ниже.

Остальные особенности те же – пинг каждые 10 секунд, два пинга чтобы определить доступность гейта. Плюс число пингуемых узлов должно равняться числу каналов. А если нам нужно определять доступность именно одного сервера? Можно конечно этому сервера назначить два IP, почему бы и нет. При условии, что это ваш сервер и вы можете менять настройки на нем.

Минус – тут используются рекурсивные роуты и если на вашем роутере достаточно большая таблица роутов, то не всегда сразу легко будет разобраться в них, если вдруг какой затык.

Вариант 3. NetWatch

Принцип тот же, что и при использовании check-gateway, только с помощью утилиты NetWatch и скриптинга. Разница только в том, что в NetWatch мы можем задавать, как часто пинговать, и после скольки пингов сайт будет считаться недоступным. Минус – мы не можем, к большому сожалению, задавать интерфейс, через который пингуем, то есть придется применять трюки с роутами из Варианта 2. Минус (и плюс одновременно) – в качестве реакцции выполняются соответсвующие скрипты, которые нужно еще написать (минус), но которые дают гораздо больше свободы (плюс).

Вариант 4. Скрипты

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

Учитывая, что по определенным причинам мне не подошли первые три варианта, был написан соответсвующий скрипт, вернее два скрипта: VPN_switcher_v1.0

Логика работы такая:

vpn-tunnel-check скрипт периодически вызывается (по умолчанию раз в 6 секунд, задается в Scheduler) и проверяет, или пингуется удаленный сервер. Если сервер не отвечает определенное число пингов – то канал считает “плохим” и вызывается второй скрипт – vpn-interfaces , который глушит текущий канал и пытается поднять следующий по списку. Число каналов не ограничено. Если, к примеру, у нас 10 каналов – то он попытается по очереди поднять каждый из 10-ти, начиная со следующего после упавшего.

Вот и всё.

Как установить и настроить:

  1. Распаковываем архив VPN_switcher_v1.0 и файл VPN_switcher.rsc закидываем на роутер.
  2. Импортируем его командой из терминала:

    /import VPN_switcher.rsc

  3. У вас должны появиться два скрипта ( vpn-interfaces и vpn-tunnel-check ) и одно неактивное задание в Scheduler ( vpn-check-task ).
  4. Открываем скрипт vpn-tunnel-check и настраиваем параметры:
    :local gw “10.174.2.1” – ip удаленного узла, который будем пинговать для проверки каналов. В моем случае это узел 10.174.2.1;
    :local cnt2ping 10 – число пингов;
    :local minlevel 6 – минимально допустимое число успешных пингов чтобы считать канал “хорошим”. В моем случае если пропадает более 10-6=4 пингов, канал считается “плохим”.
  5. Открываем скрипт vpn-interfaces и настраиваем параметры:
    local imask “^VPN*” – маска для каналов, которые переключаются. В данном случае все переключаемые каналы начинаются на “VPN”. К примеру, по умолчанию L2TP каналы начинаются на “pptp” и маска будет “^pptp*”.
    :local delayBeforeChecks 1s – сколько ждем перед тем, как начнем проверять, или поднялся канал.
    #:local checkIfRunning false – если false – то не проверяем свойство running . Это свойство есть смысл проверять только у l2tp/p2tp каналов. Оно становится true, если клиент смог договориться с сервером и установить соединение. К сожалению, если потом сервер перестанет отвечать или трафик не будет ходить через канал, то статус останется по-прежнему running ^(. Поэтому дополнительно пингуем через канал.
    :local checkIfRunning true – ставим true для VPN каналов. Так как бесмысленно пробовать пинговать через канал, если канал не поднялся (будет ошибка пинга).
    :local runningDelay 1s – этот как часто проверяем статус running.
    :local runningMaxCount 15 – а это сколько раз максимум проверяем статус running . В данном случае, если канал не поднялся за 1*15=15 секунд, то канал счиатется плохим и пробуем поднять следующий.
    :local checkIfPing trueбудем ли проверять пингом, жив ли канал. По умолчанию true .
    :local checkPing2Interface true – пингуем через конкретный интерфейс или просто пингуем без указания интерфейса. true – пингуем через конкретный канал.
    :local ping2host “8.8.8.8” – что пингуем
    :local pingMaxCount 10 – сколько раз пингуем
    :local pingMinCount 3 – допустимое число успешных пингов, чтобы считать канал “хорошим”.
  6. Как настроили все параметры, глушим все VPN каналы и проверяем работу сперва основного скрипта через терминал:
    /system script run vpn-interface
    Если всё прошло успешно, то скрипт поднимет первый канал. Если нет – читаем внимательно диагностический вывод на терминал и еще раз проверяем все параметры из п.5
  7. Если в предыдущем пункте вызов прошел успешно, то тогда вручную в терминале проверяем второй скрипт:
    /system script run vpn-tunnel-check
    И проверяем вывод в терминал и лог на отсутсвие ошибок. Если что-то пошло не так – смотрим вывод в терминал, в лог и еще раз проверяем параметры скрипта (п.4.)
  8. Если всё ок – активируем задание vpn-check-task в Scheduler.

По сути всё.

Скрипт легко может быть расширен для пингования нескольких серверов.

Обсуждение тут .