Резервирование каналов в FreeBSD
Наконец-то в нашей компании пришло понимание, что «на всякий пожарный случай» неплохо бы иметь ещё один канал выхода в сеть интернет, если по какой-то причине основной канал внезапно уйдёт в down. В таком случае доступ к ресурсам internet и почта (и не только, при соответствующих настройках) останется нормально функционировать, что при современном ведении бизнеса абсолютно необходимо. Одним из наших шлюзов является сервер под управлением FreeBSD, на котором мной было настроено простейшее резервирование каналов доступа в интернет без балансировки нагрузки. Об этом – далее… |
Необходимые нам исходные данные:
- интерфейс bce0 — локальная сеть 192.168.0.1/24;
- интерфейс bce1 — сеть основного провайдера 172.16.0.1/30;
- интерфейс re0 — сеть вспомогательного провайдера 10.10.0.1/30;
- 172.16.0.2 — шлюз по умолчанию основного провайдера;
- 10.10.0.2 — шлюз вспомогательного провайдера.
# ifconfig | grep -v options bce0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 00:1d:09:70:39:b9 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 media: Ethernet autoselect (1000baseT <full-duplex>) status: active bce1: flags=8943<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 00:1d:09:70:39:b7 inet 172.16.0.1 netmask 0xfffffffc broadcast 172.16.0.3 media: Ethernet autoselect (100baseTX <full-duplex>) status: active re0: flags=8943<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 ether 00:1c:f0:bc:68:64 inet 10.10.0.1 netmask 0xfffffffc broadcast 10.10.0.3 media: Ethernet autoselect (100baseTX <full-duplex>) status: active lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384 inet 127.0.0.1 netmask 0xff000000 groups: lo
Файл rc.conf в части касающейся при таких исходных должен выглядеть так:
# less /etc/rc.conf ifconfig_bce0="inet 192.168.0.1 netmask 255.255.255.0" ifconfig_bce1="inet 172.16.0.1 netmask 255.255.255.252" ifconfig_re0="inet 10.10.0.1 netmask 255.255.255.252" defaultrouter="172.16.0.2" gateway_enable="YES"
Вам необходимо определиться с двумя хорошо известными хостами в сети интернет, которые априори находятся постоянно online. Я остановился на всем известном ip dns компании Google (8.8.8.8) и ip dns компании Яндекса (77.88.8.8). Добавил статические роутинги на dns Google через шлюз по умолчанию основного провайдера и на dns Яндекса через шлюз вспомогательного провайдера соответственно. Их мы будем впоследствии постоянно проверять на доступность с помощью команды ping:
# route add -host 8.8.8.8 172.16.0.2 # route add -host 77.88.8.8 10.10.0.2
Чтобы эти настроенные статические роутинги не пропали после перезагрузки сервера, внесите в свой rc.conf следующие строки:
static_routes="10 172" #Yandex DNS route_10="-host 77.88.8.8 10.10.0.2" #Google DNS route_172="-host 8.8.8.8 172.16.0.2"
Проверим наши роутинги командой:
# netstat -rn Routing tables Internet: Destination Gateway Flags Netif Expire default 172.16.0.2 UGS bce1 8.8.8.8 172.16.0.2 UGHS bce1 10.10.0.0/30 link#4 U re0 10.10.0.1 link#4 UHS lo0 77.88.8.8 10.10.0.2 UGHS re0 172.16.0.0/30 link#2 U bce1 172.16.0.1 link#2 UHS lo0 127.0.0.1 link#3 UH lo0 192.168.0.0/24 link#1 U bce0 192.168.0.1 link#1 UHS lo0
Теперь выполним последовательность следующих команд:
# touch /root/ch-gw # chmod 700 /root/ch-gw # touch /var/log/ch-gw.log
Которыми мы создали файл ch-gw, где мы пропишем последовательность команд на проверку доступности наших выбранных хостов и смене шлюза по умолчанию по определённой логике. Сделали этот файл исполняемым и создали файл лога для записи событий по смене шлюза.
Занесите в файл ch-gw следующие строки (не забудьте отредактировать их под свои нужды):
# nano -w /root/ch-gw #!/bin/sh IP1=172.16.0.1 IP2=10.10.0.1 GW1=172.16.0.2 GW2=10.10.0.2 dtime=`date "+%Y-%m-%d %H:%M:%S"` TARG1=8.8.8.8 TARG2=77.88.8.8 /sbin/ping -q -S $IP1 -c 4 $TARG1 > /dev/null 2>&1 if [ $? != 0 ]; then /sbin/ping -q -S $IP2 -c 4 $TARG2 > /dev/null 2>&1 if [ $? = 0 ]; then if [ ! -f /tmp/gw.changed ]; then /sbin/route change default $GW2 && /bin/echo "${dtime} the gateway was replaced by ${GW2}" >> /var/log/ch-gw.log && touch /tmp/gw.changed fi fi else if [ -f /tmp/gw.changed ]; then /sbin/route change default $GW1 && /bin/echo "${dtime} the gateway was replaced by ${GW1}" >> /var/log/ch-gw.log && rm /tmp/gw.changed fi fi
Где:
- 172.16.0.1 — интернет адрес, выданный основным провайдером;
- 10.10.0.1 — интернет адрес, выданный вспомогательным провайдером;
- 172.16.0.2 — шлюз основного провайдера;
- 10.10.0.2 — шлюз вспомогательного провайдера;
- dtime — время события в формате 2016-08-19 10:10:45 для записи в лог;
- 8.8.8.8 — dns Google, доступность которого постоянно проверяется через шлюз основного провайдера;
- 77.88.8.8 — dns Яндекса, доступность которого постоянно проверяется через шлюз вспомогательного провайдера в случае, если пинги до dns Google пропадут;
- /tmp/gw.changed — своеобразный маркер смены шлюза по умолчанию.
Всё остальное – предельно простая и понятная логика…
Нам осталось прописать в crontab следующую строку:
# crontab -l | grep ch-gw */1 * * * * /root/ch-gw; /bin/sleep 15; /root/ch-gw; /bin/sleep 15; /root/ch-gw; /bin/sleep 15; /root/ch-gw
— которая будет запускать наш исполняемый файл ch-gw через каждые 15 секунд круглосуточно.
В случае, если dns Google через шлюз по умолчанию основного провайдера будет недоступен (как правило – проблемы связи), вы увидите в логе /var/log/ch-gw.log следующую запись:
# less /var/log/ch-gw.log ... 2016-11-23 16:32:00 the gateway was replaced by 10.10.0.2 ...
Означающую, что шлюз по умолчанию сменился с основного провайдера на вспомогательного. Как только dns Google через шлюз основного провайдера будет снова доступен (пинги до него идут согласно нашего статического роутинга только таким образом) – в лог запишется следующее событие:
# less /var/log/ch-gw.log ... 2016-11-23 16:32:32 the gateway was replaced by 172.16.0.2 ...
Это значит, что наш шлюз по умолчанию снова вернулся к настройкам основного провайдера.
Если в вашем crontab присутствует строка вроде: MAILTO=max@maxblogs.ru
, то на почту вы будете получать уведомления вида:
Вот, в принципе, и всё!