ToFoIn v 1. Backup Gateways and Switch Between External Channels on FreeBSD

  • Tutorial

annotation


The last article addressed the issue of organizing redundancy for local area network gateways. As a solution, a script was proposed, which at that time solved the problem, but had several disadvantages. After some time, it turned out to eliminate these shortcomings, partially rewrite the code and get something acceptable at the output. Now we can say that the scripts are sufficiently tested to be called stable. To simplify the understanding of the entire system, the main points on setting up secondary services (in terms of the topic of the article) will be partially duplicated below. The reason is simple - during this time, the ipfw rules were also reworked, the dns went live in AD on Samba4 with bind-frontend and safely updating records from isc-dhcpd using kerberos, as well as secondary dns-servers in the form of bind on gateways, was CARP is tuned ... In general It became much more interesting, but in more detail about how and how it works - below. All that can be given links to the source, will be designed in this way, so as not to produce the essence. What has been taken from any other places, but which is no longer available, will be presented here with appropriate comments.

Introduction


So, to increase the noise immunity of the communication channel with the outside world by the consumer, there are two ways: reservation of the gateway and reservation of the connection point. In other words, in the first case, a second gateway is put in place, in case the first one fails, in the second case, a backup Internet channel is organized in case of any problems with the main one, and the more they intersect, the better it is. If the first task for FreeBSD is solved by CARP , then the second, after the organization of the second external channel, can again be solved in several ways. At a minimum, traffic balancing or channel switching can be arranged. Due to the large difference in bandwidth of external channels, the first option did not fit me, so the main culprit of the publication was written:ToFoIn is a set of bash scripts that is aimed at solving problems of diagnostics and switching to a working external channel. After completion, it can be used for n gateways and m channels. The situation is poorly represented, where n and m are more than 2, but the following scripts should work up to large values ​​of n and m, since logical limit is not set. In general, I suspect that using these scripts you can solve a fairly wide range of tasks depending on the connection status, limited, perhaps, only by your imagination.


Approximately this network topology assumes in its simplest form the use of a set of ToFoIn scripts. Of course, the scripts must also work in the case of a single router, but in this case, the Daemon module will have to be greatly modified to remove the dependence of the sequence of actions on the state of CARP, which will simply be absent in the system. Further reservation of these and other nodes depends only on the degree of importance of the respective services.

Targets and goals


The goal of the project, as before, is to create a universal and easily scalable software package focused on identifying problems with external and internal connections and automatically switching to workable connections. In general, the logic is as follows:

  • There are n “routers” with m external channels on each. In this case, all n "routers" are in a strict hierarchy and are connected to each other with the help of CARP on all the necessary interfaces.
  • On all machines, an agent works independently of each other, whose task, based on the current CARP status of his machine:
    • If backup - identify and configure the machine on the router, which is the master at the moment;
    • If master - check the status of connections at the current time and, if necessary, switch between external channels.

Decision


CARP operates in the internal network, which provides backup gateways and allows you to not change the settings of other network devices of the internal network when switching channels.

Dhcpd operates in the primary - secondary mode and, in general, it doesn’t matter what other roles its car plays - the connection between dhcpd occurs in the internal network, which routers always look at.

Master bind is removed in AD, which is hidden in the local network, while secondary bind servers operate on gateway routers on an equal basis.

The ipfw rules differ depending on which channel is considered primary at a given moment and are restarted by the Daemon module when the role changes.

Finally, about the scripts themselves. Now the files are located in the appropriate directories, work from their user and have a startup script in rc.d. Tasks requiring root access are handled by sudo. There is an installation script that takes into account the possible presence of an installed version, as well as a fairly detailed configuration file. The modules are the same with minor changes, some of them have almost not changed in functionality:

Daemon - as the name implies - is the main process that starts the testing and switching modules by timer, and also tracks CARP.
Tester - tests the availability of communication through external channels still with the help of the ping command. (if it is running, it considers that the car has CARP in Master state)
Judge- based on the test results, determines which external channel is working and whether switching is necessary, performs switching (if it is running, it considers that the machine has CARP in the Master state).
Scout is a new module. Runs when CARP is in Backup status. It is needed to determine which of the remaining routers is currently the primary one.
Logger - is responsible for logging events. It is necessary so that information about events is not duplicated and the magazine is easier to read.
Watchdog - runs on a schedule from the crontab. It determines the "freezing" of all modules and (if possible) tries to solve the problems that have arisen. Those. nail everyone, to put it simply.

In addition to the scripts themselves, it is worth considering some more important files:

Tofoin.conf - a single configuration file.
Tofoin.log is a single event log file.
Result_ <internal channel number> is a work file, test results are added here, created in / tmp next to .pid and other work files.

I am happy to answer questions regarding the work of the modules, explaining the decisions in the comments.

Technical part


Equipment


Compared to the previous time, the gateways moved to P4, received 1536 Mb of RAM and three 40 Gb HDDs each (mirror + spare). Network cards are still PCI, BP are normal, naturally in the presence of a UPS.
The increase in capacity is associated with the released iron and unnecessarily tedious update from the source, but mostly - the first. OS FreeBSD 11.1, FS zfs.

System Component Settings


Read more
The kernel is built with such additional parameters (something can be set in the loader, but better so):

options IPFIREWALL # ipfw firewall
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=50
options IPFIREWALL_NAT
options LIBALIAS
options DUMMYNET
options HZ=1000
options ROUTETABLES=4
options KSTACK_PAGES=4
options KVA_PAGES=512
device carp

Settings / boot / loader.conf:
geom_mirror_load="YES"
zfs_load="YES"
kern.geom.label.gptid.enable="0"
vm.kmem_size="1024M"
vm.kmem_size_max="1024M"
vfs.zfs.arc_max="512M"
vfs.zfs.vdev.cache.size="30M"
vfs.zfs.prefetch_disable=1
kern.vty=vt

Настройки /etc/rc.conf на первой машине(основной интерес представляет настройка CARP):
ifconfig_eth0="up"
vlans_eth0="vlan111 vlan222"
create_args_vlan111="vlan 111"
create_args_vlan222="vlan 222"
ifconfig_eth1="up"
vlans_eth1="vlan333 vlan444 vlan555"
create_args_vlan333="vlan 333"
create_args_vlan444="vlan 444"
create_args_vlan555="vlan 555"
ifconfig_eth2="up"
vlans_eth2="vlan666 vlan777 vlan888"
create_args_vlan666="vlan 666"
create_args_vlan777="vlan 777"
create_args_vlan888="vlan 888"
ifconfig_vlan666="inet 192.168.0.1/24"
ifconfig_vlan666_alias0="vhid 1 advskew 100 pass MyPassword alias 192.168.0.5/32"
ifconfig_vlan777="inet 192.168.1.1/24"
ifconfig_vlan777_alias0="vhid 1 advskew 100 pass MyPassword alias 192.168.1.5/32"
ifconfig_vlan888="inet 192.168.2.1/24"
ifconfig_vlan888_alias0="vhid 1 advskew 100 pass MyPassword alias 192.168.2.5/32"
ifconfig_vlan111="inet 192.168.3.1/30"
ifconfig_vlan111_alias0="vhid 1 advskew 100 pass MyPassword alias 1.1.1.2/24"
ifconfig_vlan222="inet 192.168.4.1/30"
ifconfig_vlan333="inet 192.168.5.1/30"
ifconfig_vlan333_alias0="vhid 1 advskew 100 pass MyPassword alias 2.2.2.2/30"
ifconfig_vlan444="inet 192.168.6.1/30"
ifconfig_vlan444_alias0="vhid 1 advskew 100 pass MyPassword alias 3.3.3.2/30"
ifconfig_vlan555="inet 192.168.7.1/30"
defaultrouter="1.1.1.1"
setfib1_enable="YES"
setfib1_defaultrouter="3.3.3.1"
setfib2_enable="YES"
setfib2_defaultrouter="2.2.2.1"
zfs_enable="YES"
named_enable="YES"
dhcpd_enable="YES"
firewall_enable="YES"
firewall_logging="YES"
firewall_script="/etc/firewall.sh"
gateway_enable="YES"
tofoin_enable="YES"

Легенда:
eth0,eth1,eth2 — физические адаптеры
vlan666, vlan777, vlan888 — виртуальные адаптеры локальной сети,
vlan222 и vlan555 — адаптеры для резервной связи между внешними сетевыми картами(возможно уже и не нужны, активно использовались ранее)
vlan111 — основной внешний канал
vlan444 — резервный внешний канал
vlan333 — телефония

Настройки /etc/rc.conf на второй машине(основной интерес представляет настройка CARP, часть повторяющихся строк убрана):
ifconfig_vlan666="inet 192.168.0.2/24"
ifconfig_vlan666_alias0="vhid 1 advskew 0 pass MyPassword alias 192.168.0.5/32"
ifconfig_vlan777="inet 192.168.1.2/24"
ifconfig_vlan777_alias0="vhid 1 advskew 0 pass MyPassword alias 192.168.1.5/32"
ifconfig_vlan888="inet 192.168.2.2/24"
ifconfig_vlan888_alias0="vhid 1 advskew 0 pass MyPassword alias 192.168.2.5/32"
ifconfig_vlan111="inet 192.168.3.2/30"
ifconfig_vlan111_alias0="vhid 1 advskew 0 pass MyPassword alias 1.1.1.2/24"
ifconfig_vlan222="inet 192.168.4.2/30"
ifconfig_vlan333="inet 192.168.5.2/30"
ifconfig_vlan333_alias0="vhid 1 advskew 0 pass MyPassword alias 2.2.2.2/30"
ifconfig_vlan444="inet 192.168.6.2/30"
ifconfig_vlan444_alias0="vhid 1 advskew 0 pass MyPassword alias 3.3.3.2/30"
ifconfig_vlan555="inet 192.168.7.2/30"
defaultrouter="1.1.1.1"
setfib1_enable="YES"
setfib1_defaultrouter="3.3.3.1"
setfib2_enable="YES"
setfib2_defaultrouter="2.2.2.1"

Некоторые правила, которые пригодятся при настройке ipfw(nat):
для разрешения траффика CARP:
/sbin/ipfw -q add allow carp from any to any

«ядерный» nat:
/sbin/ipfw -q nat 1 config log ip vlan111 reset same_ports deny_in unreg_only
/sbin/ipfw -q add nat 1 ip from any to any in

использование определённых таблиц маршрутизации с определёнными адаптерами:
/sbin/ipfw -q add setfib 0 all from any to any via vlan666

Вообще, про применённые у меня настройки ipfw можно было бы спокойно отдельную статью написать, но это в какой-нибудь другой раз.

Third Party Software


Read more
Т. к. есть необходимость одновременно работать с двумя и более внешними каналами, для этого удобно иметь несколько таблиц маршрутизации, по одной на каждый канал. И неплохо было бы, если бы эти таблицы создавались при старте сами. В этом поможет rc.d скрипт setfib. Логика, используемая в ToFoIn, предполагает, что имя файла(setfib1, setfib2 и т. д.) совпадает с номером таблицы, в которую отдельно взятый скрипт добавляет маршрут по умолчанию. Таблица по умолчанию имеет номер «0».
DNS сервера с Bind в главной роли работают в режиме вторичных, в роли основного выступает samba4+bind, спрятанная в локальной сети. Настройка вторичных bind прекрасно раскрыта в книге «DNS и BIND» Крикета Ли и Пола Альбитца. Каких-то особых требований, учитывающих использование samba4 для secondary серверов, я не помню, и у меня в файле настроек о них упоминания нет. Разве что, для разных интернет каналов может потребоваться создать 2 разных файла, которые затем скриптом ToFoIn будут копироваться в место, из которого его будет читать сам bind. Это сделано вследствие того, что при указании в одном файле адресов dns-серверов обоих провайдеров, с учетом того, что bind работает только с одной таблицей маршрутизации, возникает проблема, связанная с разрешением адресов с недоступных в определённый момент вышестоящих серверов.
Failover isc-dhcpd. Dhcpd не принципиален для работы ToFoIn, более того, его отсутствие вообще никак не скажется на работе скриптов, однако, как мне кажется, достаточно логично разместить dhcp сервера именно на шлюзах и тогда вопрос failover всё-таки встаёт. А тут, по сравнению с прошлым разом, стало интереснее… Помимо настройки, необходимой для failover, которую я описывал в прошлый раз(начало раздела «предварительная настройка» внутри раскрывающегося меню).
Потребуется также скрипт для безопасного обновления записей dns в AD средствами samba4. Сам сервер samba4 должен быть просто установлен. Настройка и запуск не требуется, нас интересуют только инструменты управления, идущие в комплекте. Прочую информацию желающие могут найти в разделе «DHCP with dynamic DNS updates» по адресу.
Выглядит страшно, но работает.
На этом с настройкой стороннего софта закончено.

Little about ToFoIn


All the text of the project along with the installation script is available on gitlab .

Finally, an example of the parameters of the ToFoIn settings file is considered:
Число маршрутизаторов, используемых в системе:
RNUMBER=2

При использовании дополнительных подсетей, необходимо устанавливать маршрут по умолчанию, когда маршрутизатор становится основным. Здесь можно указать номер соответствующего файла setfib, который будет перезапускаться. В данном примере setfib2:
ADDITLAN=2

Имя внутреннего адаптера:
INT_IF=vlan666

Все остальные интерфейсы, по которым маршрутизаторы связаны посредством CARP. Необходимы для контроля и поддержания одинакового состояния всех интерфейсов:
ALL_IF="vlan111 vlan333 vlan444 vlan666 vlan777 vlan888"

vhid, который был использован при настройке CARP:
CARP_VHID=1

IP адреса во внутренней сети других маршрутизаторов в порядке важности, при необходимости, далее просто используется ASERV_IP_2, ASERV_IP_3 и т.д.
ASERV_IP_1=192.168.0.2

Число внешних каналов подключения:
CNUMBER=2

Настройки для основного внешнего канала подключения:
Имя адаптера:
EXT_0_IF=vlan111

Номер таблицы маршрутизации:
RTABLE_0=0

Шлюз по умолчанию:
DEFAULT_GATEWAY=2.2.2.1

Настройки для резервного внешнего канала подключения:
Имя адаптера:
EXT_1_IF=vlan444

Номер таблицы маршрутизации:
RTABLE_1=1

Шлюз по умолчанию не требуется, т. к. для всех таблиц маршрутизации, кроме основной используется rc.d скрипт setfib<номер таблицы>, который, как предполагается логикой, должен совпадать с номером таблицы.
Параметры модуля Tester:
Число адресов, по которым будет происходить проверка:
TNUMBER=2

Адреса машин, по которым отправляются ping-запросы. Лучше всего использовать в первом случае доменное имя, и только после этого ip адреса:
PTARGET_0=ya.ru
PTARGET_1=8.8.8.8

Число ping пакетов, отправляемых одной целе:
PNUMBER=2

Настройки модуля Judge
Число успешных тестирований основного канала перед возвращением на него. Время возврата на основной канал после возобновления его работы приблизительно рассчитывается по формуле: (WNUMBER+1)*JUDGEPERIOD секунд.
WNUMBER=3

Настройки модуля Logger
Данные 2 параметра означают, с какой частотой Logger будет записывать повторяющиеся события. После записи о событии в следующий раз сообщается о LOGFREQ1 числе повторов, далее о LOGFREQ2 числе повторов. Учитываются только события идущие подряд.
LOGFREQ1=5
LOGFREQ2=20

Таймеры запуска модулей в секундах
Период запуска модуля Tester. Имеет смысл рассчитывать исходя из времени неудачных попыток тестирования всех целей.
TESTERPERIOD=240

Период запуска модуля Judge. Не стоит устанавливать меньше TESTERPERIOD.
JUDGEPERIOD=300

Период запуска модуля Scout.
SCOUTPERIOD=360

Период ожидания перед проверкой таймеров запуска модулей Tester и Judge. Логично устанавливать меньше или равным значению TESTERPERIOD.
SENSITIVITY=60

Время, по истечению которого работающий модуль считается зависшим. Используются модулем Watchdog.
TESTERLIMIT=40
JUDGELIMIT=30
LOGGERLIMIT=20
SCOUTLIMIT=120
WATCHDOGLIMIT=150

Пути к файлам и каталогам
Путь к скрипту ipfw.
FIRESCRIPT=/etc/firewall.sh

Настройки ipfw. Если настройки ipfw не вынесены в отдельный файл, то FIRESCRIPT=FIRESETDEF.
FIRESETDEF=/etc/firewall/config

Путь к настройкам ipfw для основного внешнего канала:
FIRESET_0=/etc/firewall/config_0

Путь к настройкам ipfw для резервного внешнего канала, при необходимости можно продолжать далее FIRESET_2 и т.д.:
FIRESET_1=/etc/firewall/config_1

Пути к настройкам bind
BINDSETDEF=/usr/local/etc/namedb/named.conf

Настройки bind для основного внешнего канала:
BINDSET_0=/usr/local/etc/namedb/named.conf.0

Настройки bind для резервного внешнего канала, при необходимости можно продолжать далее BINDSET_2 и т.д.:
BINDSET_1=/usr/local/etc/namedb/named.conf.1

Пути ко всем исполняемым файлам ToFoIn:
DAEMON=/local/sbin/tofoin/daemon.sh
TESTER=/usr/local/sbin/tofoin/tester.sh
JUDGE=/usr/local/sbin/tofoin/judge.sh
LOGGER=/usr/local/sbin/tofoin/logger.sh
SCOUT=/usr/local/sbin/tofoin/scout.sh
WATCHDOG=/usr/local/sbin/tofoin/watchdog.sh

Журнал событий. Этот файл сейчас НЕ создаётся при установке:
LOGFILE=/var/log/tofoin.log

Временные файлы и каталоги, создаются при запуске соответствующих модулей, некоторые удаляются при остановке:
DIR_TMP=/tmp/tofoin
DIR_PID=/var/run/tofoin
JUDGEMETER=/tmp/tofoin/judgemeter
PREVSTATE=/tmp/tofoin/prevstate
SCOUTGATE=/tmp/tofoin/scoutgate
LOGTMP=/tmp/tofoin/logger.tmp
LOGMETER=/tmp/tofoin/logmeter
DAEMON_PID=/var/run/tofoin/daemon.pid
TESTER_PID=/var/run/tofoin
SCOUT_PID=/var/run/tofoin/scout.pid
JUDGE_PID=/var/run/tofoin/judge.pid
LOGGER_PID=/var/run/tofoin/logger.pid
WATCHDOG_PID=/var/run/tofoin_watchdog.pid


Total


It turned out to be quite a workable and reliable set of scripts that copes well with the task of switching to the working channel in the case of 2 routers with 2 external communication channels.

Plans


My plans for this project are, perhaps, rewriting from bash to pure sh in order to get rid of excess software on the server. On the other hand, now everything works amazingly and I don’t really want to interfere in this process, besides the transition to sh is fraught with more terrible language constructions necessary to achieve the same result.
For the rest, probably, it would be worthwhile to think about the best implementation of test modules.

References:


Previous article
ToFoIn project page on gitlab

Also popular now: