0

Маршрутизация на основе политик. Часть четвертая

26.07.2023

Немного усложним конфигурацию сети из третьей части. У нашего компьютера теперь не два, а три сетевых интерфейса. Первый интерфейс имеет выход в интернет через сеть первого интернет-провайдера, второй интерфейс — через сеть второго интернет-провайдера. А третий интерфейс подключен к локальной сети 192.168.250.0/24. И наш компьютер должен обеспечивать выход в интернет для всех компьютеров этой сети.

Настройка сети

На компьютере gateway установлена ОС Ubuntu Server, настройка сети выполнена с использованием Netplan:

# nano /etc/netplan/01-netcfg.yamlКопировать
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses: [192.168.50.2/24]
      routes:
        # маршрут по умолчанию для таблицы main, метрика 100 (основной)
        - to: 0.0.0.0/0
          from: 192.168.50.2
          via: 192.168.50.1
          metric: 100
        # маршрут по умолчанию для таблицы primary (идентификатор 10)
        - to: 0.0.0.0/0
          via: 192.168.50.1
          table: 10
      routing-policy:
        # если отправитель 192.168.50.2, просматривать таблицу primary
        - from: 192.168.50.2
          table: 10
          priority: 31000
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
    enp0s8:
      addresses: [192.168.150.2/24]
      routes:
        # маршрут по умолчанию для таблицы main, метрика 200 (резервный)
        - to: 0.0.0.0/0
          from: 192.168.150.2
          via: 192.168.150.1
          metric: 200
        # маршрут по умолчанию для таблицы secondary (идентификатор 20)
        - to: 0.0.0.0/0
          via: 192.168.150.1
          table: 20
      routing-policy:
        # если отправитель 192.168.150.2, просматривать таблицу secondary
        - from: 192.168.150.2
          table: 20
          priority: 32000
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
    enp0s9:
      addresses: [192.168.250.1/24]
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]Копировать

После загрузки системы смотрим маршруты таблицы 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
192.168.250.0/24 dev enp0s9 proto kernel scope link src 192.168.250.1Копировать

Здесь два маршрута по умолчанию, но с разными значениями метрики — один маршрут основной (метрика 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
# добавляем новые таблицы
10      primary
20      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Копировать

Переключение каналов

За переключение каналов отвечает скрипт /root/swicth-channel/swicth-channel.sh:

# 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Копировать

Форвардинг пакетов

По умолчанию транзитный трафик отключен, так что редактируем файл /etc/sysctl.conf:

# nano /etc/sysctl.confКопировать
net.ipv4.ip_forward=1Копировать

После этого настраиваем netfilter с помощью утилиты iptables:

# iptables -P FORWARD DROPКопировать
# iptables -A FORWARD -i enp0s3 -o enp0s9 -d 192.168.250.0/24 -j ACCEPT
# iptables -A FORWARD -i enp0s8 -o enp0s9 -d 192.168.250.0/24 -j ACCEPT
# iptables -A FORWARD -i enp0s9 -o enp0s3 -s 192.168.250.0/24 -j ACCEPT
# iptables -A FORWARD -i enp0s9 -o enp0s8 -s 192.168.250.0/24 -j ACCEPTКопировать

И смотрим, что получилось:

# iptables -L -v --line-numbers
Chain INPUT (policy ACCEPT 181 packets, 43950 bytes)
num   pkts   bytes   target   prot   opt   in       out      source             destination

Chain FORWARD (policy DROP 0 packets, 0 bytes)
num   pkts   bytes   target   prot   opt   in       out      source             destination
1        0       0   ACCEPT   all    --    enp0s3   enp0s9   anywhere           192.168.250.0/24
2        0       0   ACCEPT   all    --    enp0s8   enp0s9   anywhere           192.168.250.0/24
3        0       0   ACCEPT   all    --    enp0s9   enp0s3   192.168.250.0/24   anywhere
4        0       0   ACCEPT   all    --    enp0s9   enp0s8   192.168.250.0/24   anywhere

Chain OUTPUT (policy ACCEPT 227 packets, 30799 bytes)
num   pkts   bytes   target   prot   opt   in       out      source             destinationКопировать

Мы разрешили ходить транзитным пакетам для нашего диапазона ip адресов, а всё остальное запретили.

Сохранение правил

Созданные с помощью утилиты iptables правила пропадут при перезагрузке. Так что их нужно сохранить и восстанавливать при перезагрузке. В этом нам поможет пакет iptables-persistent:

$ sudo apt install iptables-persistentКопировать

При установке пакета будет предложено сохранить текущие правила iptables:

  • в файл /etc/iptables/rules.v4 для протокола IPv4
  • в файл /etc/iptables/rules.v6 для протокола IPv6

После установки пакета будет добавлена новая служба netfilter-persistent.service, которая при загрузке системы будет восстанавливать созданные нами правила:

$ systemctl status netfilter-persistent.service
● netfilter-persistent.service - netfilter persistent configuration
   Loaded: loaded (/lib/systemd/system/netfilter-persistent.service; enabled; vendor preset: enabled)
   Active: active (exited) since Sat 2020-05-24 11:20:44 MSK; 2h 32min ago
  Process: 446 ExecStart=/usr/sbin/netfilter-persistent start (code=exited, status=0/SUCCESS)
 Main PID: 446 (code=exited, status=0/SUCCESS)

май 24 11:20:43 gateway systemd[1]: Starting netfilter persistent configuration...
май 24 11:20:44 gateway systemd[1]: Started netfilter persistent configuration.Копировать

Поднимаем web-сервер

Установим на машине web-server пакет apache2:

# apt install apache2Копировать

С компьютера pc-1 проверим, что сервер работает:

Чтобы обеспечить доступ к web-серверу из интернета, выполняем на gateway1 команду (подробности здесь):

# iptables -t nat -A PREROUTING -i enp0s3 -p tcp --dport 80 -j DNAT --to-destination 192.168.250.254Копировать

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

# iptables-save > /etc/iptables/rules.v4Копировать

Проверяем, что web-сервер теперь доступен, набирая в адресной строке http://111.111.111.111/:

В принципе, мы можем выполнить эти две команды и на gateway2 — тогда web-сервер будет доступен по двум ip-адресам. В этом случае при настройке DNS надо будет добавить две A-записи для домена (round-robin). Преобразование доменного имени в ip-адрес производится в произвольном порядке с равной вероятностью распределения. Некоторые DNS-сервера могут регулярно опрашивать серверы для проверки их доступности и нагруженности. Если сервер не отвечает, он временно удаляется из пула DNS, пока не будет готов к работе. Но это уже совсем другая история.

Настройка pc-1 и pc-2

Настройка сети одинаковая для pc-1 и pc-2, выполнена с использованием Netplan, им назначены ip-адреса 192.168.250.2 и 192.168.250.3:

$ sudo nano /etc/netplan/01-network-manager-all.yamlКопировать
# Настройка сети для компьютера pc-1
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses: [192.168.250.2/24]
      gateway4: 192.168.250.1
      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Копировать
$ sudo nano /etc/netplan/01-network-manager-all.yamlКопировать
# Настройка сети для компьютера pc-2
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses: [192.168.250.3/24]
      gateway4: 192.168.250.1
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]Копировать

Еще одна таблица маршрутизации

Давайте сделаем так, чтобы компьютер pc-2 выходил в интернет через резервный канал связи, т.е. через сеть второго провайдера. Для этого создадим еще одну таблицу маршрутизации (имена таблиц операционной системе не нужны, это исключительно для нашего удобства, чтобы обращаться не по номеру таблицы, а по говорящему имени):

# nano /etc/iproute2/rt_tablesКопировать
# предопределенные таблицы
255     local
254     main
253     default
0       unspec
# добавляем новые таблицы
10      primary
20      secondary
30      pc2-via-gw2Копировать

Теперь добавляем новое правило — какие таблицы просматривать при отправке пакета:

# ip rule add from 192.168.250.3 table pc2-via-gw2 pref 30000Копировать

Смотрим список правил — какие таблицы будут просмотрены при отправке пакета:

# ip rule show
0:      from all lookup local
30000:  from 192.168.250.3 lookup pc2-via-gw2
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Копировать

Для таблицы pc2-via-gw2 зададим маршрут по умолчанию:

# ip route add default via 192.168.150.1 dev enp0s8 table pc2-via-gw2Копировать

Убедимся, что маршрут по умолчанию для pc2-via-gw2 добавлен:

# ip route show table pc2-via-gw2
default via 192.168.150.1 dev enp0s8 proto staticКопировать

Проверка маршрута для pc-2

Проверим, что компьютер pc-2 выходит в интернет через резервный канал связи:

$ traceroute -n ya.ru
traceroute to ya.ru (87.250.250.242), 30 hops max, 60 byte packets
1  192.168.250.1  0.454 ms  0.384 ms  0.341 ms
2  192.168.150.1  1.177 ms  1.142 ms  1.091 ms
..........
9  87.250.250.242  10.984 ms  10.768 ms  10.716 msКопировать

Удостоверимся, что компьютер pc-1 выходит в интернет через основной канал связи:

$ traceroute -n ya.ru
traceroute to ya.ru (87.250.250.242), 30 hops max, 60 byte packets
1  192.168.250.1  0.329 ms  0.225 ms  0.172 ms
2  192.168.50.1  0.376 ms  0.326 ms  0.394 ms
..........
9  87.250.250.242  8.377 ms  10.626 ms  11.813 msКопировать

Файл конфигурации сети

Созданные нами правило и маршрут по умолчанию для таблицы pc2-via-gw2 пропадут при перезагрузке gateway, поэтому надо изменить файл конфигурации сети:

# nano /etc/netplan/01-netcfg.yamlКопировать
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses: [192.168.50.2/24]
      routes:
        # маршрут по умолчанию для таблицы main, метрика 100 (основной)
        - to: 0.0.0.0/0
          from: 192.168.50.2
          via: 192.168.50.1
          metric: 100
        # маршрут по умолчанию для таблицы primary (идентификатор 10)
        - to: 0.0.0.0/0
          via: 192.168.50.1
          table: 10
      routing-policy:
        # если отправитель 192.168.50.2, просматривать таблицу primary
        - from: 192.168.50.2
          table: 10
          priority: 31000
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
    enp0s8:

Свежие комментарии

Подписка

Лучшие статьи


Fatal error: Uncaught Error: Call to a member function have_posts() on null in /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/blog.php:380 Stack trace: #0 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/widgets/latest-posts/widget.php(257): fox56_blog_grid(NULL, Array) #1 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/widgets/latest-posts/register.php(33): include('/home/host18670...') #2 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/class-wp-widget.php(394): Wi_Widget_Latest_Posts->widget(Array, Array) #3 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/widgets.php(837): WP_Widget->display_callback(Array, Array) #4 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(417): dynamic_sidebar('sidebar') #5 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(136): fox56_single_sidebar() #6 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/single.php(7): fox56_single_inner() #7 /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/single.php(23): fox56_single() #8 /home/host1867038/the-devops.ru/htdocs/www/wp-includes/template-loader.php(106): include('/home/host18670...') #9 /home/host1867038/the-devops.ru/htdocs/www/wp-blog-header.php(19): require_once('/home/host18670...') #10 /home/host1867038/the-devops.ru/htdocs/www/index.php(17): require('/home/host18670...') #11 {main} thrown in /home/host1867038/the-devops.ru/htdocs/www/wp-content/themes/fox/inc/blog.php on line 380