Допустим, у нас есть компьютер с двумя сетевыми интерфейсами, которые
подключены к сетям двух интернет-провайдеров. И нам нужно переключаться на резервный канал в случае сбоя основного. И переключаться обратно на основной канал после восстановления связи. Для этого напишем скрипт, который будет проверять доступность основного канала с помощью команды ping и при необходимости изменять маршрут по умолчанию.
Настройка сети
На компьютере установлена ОС Ubuntu Desktop, настройка сети выполнена с использованием Netplan:
# nano /etc/netplan/01-network-manager-all.yaml
network:
version: 2
renderer: networkd
ethernets:
enp0s3:
addresses: [192.168.50.2/24]
routes:
- to: 0.0.0.0/0 # основной маршрут по умолчанию для таблицы main
from: 192.168.50.2
via: 192.168.50.1
metric: 100
- to: 0.0.0.0/0 # маршрут по умолчанию для таблицы primary (или 100)
via: 192.168.50.1
table: 100
routing-policy:
- from: 192.168.50.2
table: 100
priority: 31000
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
enp0s8:
addresses: [192.168.150.2/24]
routes:
- to: 0.0.0.0/0 # резервный маршрут по умолчанию для таблицы main
from: 192.168.150.2
via: 192.168.150.1
metric: 200
- to: 0.0.0.0/0 # маршрут по умолчанию для таблицы secondary (или 200)
via: 192.168.150.1
table: 200
routing-policy:
- from: 192.168.150.2
table: 200
priority: 32000
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
Служба NetworkManager отключена, вместо нее за сеть отвечает служба systemd-networkd:
# systemctl stop NetworkManager.service
# systemctl disable NetworkManager.service
# systemctl start systemd-networkd.service
# systemctl enable systemd-networkd.service
После загрузки системы смотрим маршруты таблицы main:
$ ip route show
default via 192.168.50.1 dev enp0s3 proto static src 192.168.50.2 metric 100
default via 192.168.150.1 dev enp0s8 proto static src 192.168.150.2 metric 200
192.168.50.0/24 dev enp0s3 proto kernel scope link src 192.168.50.2
192.168.150.0/24 dev enp0s8 proto kernel scope link src 192.168.150.2
Здесь два маршрута по умолчанию, но с разными значениями метрики — один маршрут основной (метрика 100), другой запасной (метрика 200).
Таблицы маршрутизации
И есть два правила, которые предписывают просматривать таблицы primary и secondary, если пакеты отправляются с ip-адресов 192.168.50.2 и 192.168.150.2 соответственно.
$ ip rule show
0: from all lookup local
31000: from 192.168.50.2 lookup primary
32000: from 192.168.150.2 lookup secondary
32766: from all lookup main
32767: from all lookup default
Таблицы маршрутизации primary и secondary определены в файле /etc/iproute2/rt_tables:
# nano /etc/iproute2/rt_tables
# предопределенные таблицы
255 local
254 main
253 default
0 unspec
# добавляем новые таблицы
100 primary
200 secondary
Каждая из таблиц маршрутизации содержит маршрут по умолчанию:
$ ip route show table primary
default via 192.168.50.1 dev enp0s3 proto static
$ ip route show table secondary
default via 192.168.150.1 dev enp0s8 proto static
Доступ из интернета
Допустим, у нас на компьютере установлен ssh-сервер и нам нужна
возможность подключения извне. Разумеется, здесь не обойтись без помощи
интернет-провайдеров, потому что наш компьютер не имеет белого
ip-адреса. На маршрутизаторах gateway1 и gateway2 нужно настроить проброс портов. Настройки, которые мы выполнили на компьютере, обеспечивают маршрутизацию ответов через интерфейс, на котором был получен запрос. Так что тут не будет такой ситуации, что входящее соединение на одном интерфейсе, а исходящее — на другом.
Проброс порта на маршрутизаторе gateway1:
# iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 22 -j DNAT --to-destination 192.168.50.2
Проброс порта на маршрутизаторе gateway2:
# iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 22 -j DNAT --to-destination 192.168.150.2
Проверяем подключение по ssh через маршрутизатор gateway1:
$ ssh evgeniy@111.111.111.111
The authenticity of host '111.111.111.111 (111.111.111.111)' can't be established.
ECDSA key fingerprint is SHA256:SNK5y+y11LWgJFlW8nKYVqhy3oDpgQtOXRcRaymhWAs.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '111.111.111.111' (ECDSA) to the list of known hosts.
evgeniy@111.111.111.111's password: пароль
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 5.3.0-51-generic x86_64)
Проверяем подключение по ssh через маршрутизатор gateway2:
$ ssh evgeniy@222.222.222.222
The authenticity of host '222.222.222.222 (222.222.222.222)' can't be established.
ECDSA key fingerprint is SHA256:SNK5y+y11LWgJFlW8nKYVqhy3oDpgQtOXRcRaymhWAs.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '222.222.222.222' (ECDSA) to the list of known hosts.
evgeniy@222.222.222.222's password: пароль
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 5.3.0-51-generic x86_64)
Переключение каналов
Теперь напишем скрипт, который будет переключать каналы доступа в интернет:
# mkdir /root/swicth-channel/
# nano /root/swicth-channel/swicth-channel.sh
#!/bin/sh
# Доступность этого хоста означает доступность основного канала
PING_HOST='8.8.8.8'
# Файл-флаг создается в момент переключении на резервный канал
LOCK_FILE='/root/switch-channel/switch-channel.lock'
# Будем записывать в журнал события переключения на другой канал
LOG_FILE='/root/switch-channel/switch-channel.log'
# Сетевой интерфейс, который смотрит в сеть первого интернет провайдера
IFACE_ONE='enp0s3'
# Сетевой интерфейс, который смотрит в сеть второго интернет провайдера
IFACE_TWO='enp0s8'
# IP-адрес первого сетевого интерфейса (первый интернет провайдер)
IP_IF_ONE='192.168.50.2'
# IP-адрес второго сетевого интерфейса (второй интернет провайдер)
IP_IF_TWO='192.168.150.2'
# IP-адрес шлюза первого интернет провайдера
IP_GW_ONE='192.168.50.1'
# IP-адрес шлюза второго интернет провайдера
IP_GW_TWO='192.168.150.1'
# Возможна такая ситуация, что компьютер был перезагружен в момент, когда работал
# резервный канал интернет. А за время перезагрузки восстановился основной канал
# интернет. В этом случае файл-флаг продолжит существовать и не позволит скрипту
# в дальнейшем переключаться на резервный канал.
if [ -f ${LOCK_FILE} ]; then
# Получаем вывод команды ip route show, берем только первую строку, ищем в этой
# строке подстроку ${IFACE_ONE}. Если такая подстрока найдена, значит работает
# основной канал интернет — и нужно удалить файл-флаг.
ip route show | head -1 | grep ${IFACE_ONE}
if [ $? -eq 0 ]; then
rm -f ${LOCK_FILE}
fi
fi
# Пингуем проверочный хост через основной канал
ping -I ${IP_IF_ONE} -c1 -n ${PING_HOST} > /dev/null
# Если проверочный хост не доступен
if [ $? -ne 0 ]; then
# Если нет файла-флага, значит мы сейчас на основном канале
if [ ! -f ${LOCK_FILE} ]; then
# Переключаемся на резервный канал (метрика основного маршрута 300, метрика резервного маршрута 200)
ip route del default via ${IP_GW_ONE} dev ${IFACE_ONE} src ${IP_IF_ONE} proto static metric 100
ip route add default via ${IP_GW_ONE} dev ${IFACE_ONE} src ${IP_IF_ONE} proto static metric 300
# Создаём файл-флаг, что мы на резервном канале
touch ${LOCK_FILE}
# Делаем запись в файл журнала
echo `date +'%Y/%m/%d %H:%M:%S'` Switching to secondary channel >> ${LOG_FILE}
fi
else # Если проверочный хост доступен
# Если есть файл-флаг, значит мы сейчас на резервном канале
if [ -f ${LOCK_FILE} ]; then
# Переключаемся на основной канал (метрика основного маршрута 100, метрика резервного маршрута 200)
ip route del default via ${IP_GW_ONE} dev ${IFACE_ONE} src ${IP_IF_ONE} proto static metric 300
ip route add default via ${IP_GW_ONE} dev ${IFACE_ONE} src ${IP_IF_ONE} proto static metric 100
# Удаляем файл-флаг, мы опять на основном канале
rm -f ${LOCK_FILE}
# Делаем запись в файл журнала
echo `date +'%Y/%m/%d %H:%M:%S'` Switching to primary channel >> ${LOG_FILE}
fi
fi
# chmod +x /root/swicth-channel/swicth-channel.sh
И будем запускать этот скрипт каждую минуту:
# nano /etc/crontab
# проверка каналов выхода в интернет и переключение канала при необходимости
* * * * * root /root/switch-channel/switch-channel.sh
Чтобы проверить работу скрипта, выключим интерфейс enp0s8 на маршрутизаторе gateway1:
# ip link set dev enp0s8 down
Подождем минуту и проверим маршруты на нашем компьютере:
$ ip route show
default via 192.168.150.1 dev enp0s8 proto static src 192.168.150.2 metric 200
default via 192.168.50.1 dev enp0s3 proto static src 192.168.50.2 metric 300
192.168.50.0/24 dev enp0s3 proto kernel scope link src 192.168.50.2
192.168.150.0/24 dev enp0s8 proto kernel scope link src 192.168.150.2
Включим интерфейс enp0s8 на маршрутизаторе gateway1:
# ip link set dev enp0s8 up
Подождем минуту и еще раз проверим маршруты на компьютере:
$ ip route show
default via 192.168.50.1 dev enp0s3 proto static src 192.168.50.2 metric 100
default via 192.168.150.1 dev enp0s8 proto static src 192.168.150.2 metric 200
192.168.50.0/24 dev enp0s3 proto kernel scope link src 192.168.50.2
192.168.150.0/24 dev enp0s8 proto kernel scope link src 192.168.150.2
Обсудить эту статью можно в Телеграм канале: https://t.me/linautonet