В прошлой статье мы внедрили домашний сервер DoH с использованием Pi-Hole, чем не только пофильтровали большое количество рекламы, но и инкапсулировали наши DNS-запросы в HTTPS, что вывело их из поля фильтрации запросов оператором связи.

Всем замечательно это решение, но у него есть один нюанс. Если вдруг у нас закончились деньги на счету у оператора связи или по каким-то другим причинам пропал канал связи до внешнего мира, мы даже не сможем пополнить счет, чтобы восстановить сервис, потому что не будет работать DNS. Или, например, если наш Pi-Hole по каким-то причинам перестал работать - вот вроде и вся сеть работает, и гугл пингуется, а пока не пропишешь другой DNS-сервер - не будет счастья. А если вы еще в этот момент заняты чем-то другим и не можете приступить к восстановлению незамедлительно - домашние негодуют, портят радостное существование своими жалобами и даже котики, чуя общую нервозность, стремятся нагадить вам в тапки.

Огорчать котиков - дело последнее, поэтому в этой статье я опишу, как вы можете внедрить автоматическое переключение с использования Pi-Hole на использование операторских (как, впрочем, и любых других) DNS при проблемах на Pi-Hole.

TL;DR

Настраиваем автоматическое переключение DNS-сервиса между Pi-Hole и Mikrotik, используя протокол VRRP в реализации демона keepalived.
Никаких волшебных know-how не открывается, простая пошаговая инструкция для тех, кому не хочется разбираться во всех хитросплетениях самому.

Что вам для этого потребуется

  1. Внедренное решение Pi-Hole из предыдущей статьи. Понятно, что описываемое решение можно использовать для отказоустойчивости в принципе чего угодно, но в данном конкретном случае мы сосредоточимся на именно этой реализации. Базовый Linux у решения - Ubuntu.

  2. Маршрутизатор Mikrotik в качестве бордера. Опять же, подойдет и OpenWRT, и EdgeRouter, и какой-нибудь софтовый на PC, но рассмотреть всё разнообразие в статье не получится никак. Если ваш роутер поддерживает VRRP - он сможет быть частью этого решения, а как конкретно его настраивать, если возникнут сложности, спросите в комментариях к посту. Впрочем, если ваш роутер VRRP не поддерживает - можно всё то же самое построить между двумя Pi-Hole или Pi-Hole и другим DNS-сервером.

Исходные данные

  • IPv4-адрес нашего сервера Pi-Hole в домашней сети: 192.168.1.10 и он назначен как статический.

  • IPv4-адрес нашего маршрутизатора в домашней сети: 192.168.1.1 и он назначен как статический на интерфейсе bridge маршрутизатора.

  • Новый IPv4-адрес DNS: 192.168.1.9

  • Настройки на Linux выполняем от root (т.е. перед началом настройки выполняем команду sudo -i).

Логика решения и немного теории

Чтобы не превращать статью в совсем уж деревянную инструкцию "нажмите третьим пальцем левой руки на кнопку W", расскажу самую базовую теорию того, что мы пытаемся сделать.

Итак, название протокола VRRP расшифровывается как Virtual Router Redundancy Protocol и он входит в группу протоколов NHRP (Next-Hop Resolution Protocol). Почему-то многие люди считают, что с использованием этих протоколов можно резервировать только адреса шлюзов по умолчанию, хотя, разумеется, это не так. Самому протоколу совершенно без разницы, какие сервисы с его помощью резервируются, он работает на третьем уровне модели ISO/OSI и фактически просто создает виртуальный IP-адрес, который будет перемещаться между устройствами, входящими в VRRP-группу, по определенным критериям. Очевидно, что такая логика подразумевает существование этого адреса только на одном устройстве, поэтому обеспечить, например, балансировку нагрузки между серверами с помощью стандартного VRRP нельзя (но в нашем случае этого и не требуется). Для тех кейсов, где это необходимо, существует, например, проприетарный протокол Cisco GLBP, где адрес активен одновременно на всех устройствах группы, а балансировка осуществляется за счет разных ARP-ответов. По подобной GLBP логике работает и протокол CARP.

В случае VRRP все устройства, входящие в группу, анонсируют себя через рассылку мультикаст-пакетов на адрес 224.0.0.18, внутри которых передается множество технической информации. Из нее нам важен один параметр - приоритет. Логика простая - все устройства, входящие в группу, меряются приоритетом, у кого длиннее больше, тот и победил и приземлил на себя виртуальный IP группы. Остальные сидят в засаде и ждут, пока победитель зазевается и умрет (перестанет слать нужный мультикаст), в этом случае опять проходят выборы и опять побеждает устройство с наибольшим приоритетом. Если устройств с одинаковым приоритетом несколько - побеждает больший IP-адрес, но хорошим тоном считается таких ситуаций избегать и разруливать приоритеты явно.

Большим плюсом для нас является возможность изменять приоритет на ходу. У Cisco используемая для этого фича, например, называется Enhanced Object Tracking. Но она такая есть у любой известной мне имплементации протокола, в том числе и у линуксового демона.

На основе этой фичи вырисовывается логика всей нашей конструкции:

  1. Настраиваем на нашем маршрутизаторе в качестве основных DNS сервера провайдера

  2. Настраиваем между маршрутизатором и Pi-Hole VRRP с приоритетами 100 на маршрутизаторе и 90 на Pi-Hole

  3. Создаем на Pi-Hole скрипт, проверяющий работоспособность DNS и при успешности повышающий приоритет на Pi-Hole до 110

  4. Раздаем домашним клиентам по DHCP наш виртуальный IP-адрес как адрес DNS.

Настройка

1. Настройка DNS на Mikrotik

Если помните, в предыдущей статье мы много обсуждали, какой адрес DNS раздавать клиентам и куда форвардить запросы с маршрутизатора. Для целей же нашего нового решения важно на маршрутизаторе указать в качестве DNS-серверов именно сервера нашего провайдера - чтобы они оставались доступны при блокировке сервиса за неуплату, например. Поэтому или настраиваем получение DNS от оператора по DHCP, или идем в Winbox по пути IP - DNS и в поле Servers прописываем адреса DNS-серверов провайдера.

2. Настройка VRRP на Mikrotik

Создаем новый VRRP интерфейс с привязкой к интерфейсу Bridge и навязываем на него наш виртуальный адрес. Можно сделать в Winbox, но гораздо проще сделать это в терминале:

/interface vrrp add interface=bridge name=vrrp-dns version=2 vrid=10
/ip address add address=192.168.1.9/24 interface=vrrp-dns network=192.168.1.0

Здесь vrrp-dns - это имя интерфейса (можете выбрать любое на свой вкус, главное совпасть в обеих командах), vrid - ID группы, можно тоже выбрать любой в диапазоне 1-255, нужно совпасть на обоих устройствах. Имя интерфейса bridge и IPv4-адреса нужно скорректировать под вашу домашнюю сеть.

После выполнения этого действия можно попинговать 192.168.1.9 - он уже должен отвечать с маршрутизатора, если пинг не закрыт файрволом.

3. Настройка VRRP на Pi-Hole

Устанавливаем демон keepalived:

apt install keepalived

Создаем файл конфигурации демона /etc/keepalived/keepalived.conf:

! Configuration File for keepalived

vrrp_script check_dns {
  script "/etc/keepalived/check_dns.sh"
  interval 5 # every 5 seconds
  weight 20 # add 20 points if OK
  timeout 5 # 
  rise 2 # avoid flapping
  fall 2 # avoid flapping
}

vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 10
    priority 90
    advert_int 1
    virtual_ipaddress {
        192.168.1.9/24
    }
    track_script {
        check_dns
    }
}

Здесь обратите внимание на имя интерфейса, на котором сейчас работает Pi-Hole - в примере дефолтное ens160, у вас может быть другое (проверить можно, например, через команду ifconfig).

Создаем скрипт проверки живости DNS /etc/keepalived/check_dns.sh:

#!/bin/bash
host -s -4 -t A amazon.com 127.0.0.1 > /dev/null 2>&1

и не забываем сделать его исполняемым:

chmod +x /etc/keepalived/check_dns.sh

С методикой проверки DNS вы можете экспериментировать как угодно. Для себя я выбрал проверку резолвинга адреса amazon.com. Плюс этого варианта в том, что TTL этой записи - 1 минута, поэтому дольше чем на минуту ваш Pi-Hole закэшировать запись не сможет и, соответственно, на это время максимум и отложится убегание сервиса в случае потери связи с миром. Основной принцип, который надо помнить - если скрипт выдает 0 в качестве error code, то keepalived будет считать, что всё хорошо, и добавит приоритета. Любой другой error code - и адрес уползет на Mikrotik.

Теперь достаточно перезапустить сервис:

systemctl restart keepalived

и всё заработает. В логе Mikrotik можно будет увидеть запись, подобную этой:

vrrp-dns now BACKUP, got higher priority 110 from 192.168.1.10

Вы можете проверить, что теперь на адресе 192.168.1.9 отвечает Pi-Hole, самый простой способ проверки - это резолвинг имени pi.hole:

nslookup pi.hole 192.168.1.9
Server:		192.168.1.9
Address:	192.168.1.9#53

Name:	pi.hole
Address: 192.168.1.10

Обратите внимание, что резолвиться будет в адрес сервера Pi-Hole, а не в наш виртуальный IP - это правильно и так и должно быть.

4. Настройка DHCP на Mikrotik

Ну и наконец нам надо научить DHCP-сервис Mikrotik раздавать клиентам правильный адрес DNS. Это удобнее сделать из WinBox - там вы увидите все свои пулы. Идем по пути IP - Networks, смотрим глазами на все сети, которые у вас связаны с Pi-Hole сейчас и изменяем поле DNS Servers с адреса Pi-Hole 192.168.1.10 на виртуальный адрес 192.168.1.9.

Обновляем аренду адреса на компьютерах, проверяем, что получили правильный адрес DNS, проверяем, что резолвинг работает (например, командой nslookup pi.hole - уже без прямого указания имени используемого сервера). Радуемся.

Особо ответственные могут каким-либо образом сломать своему DNS-серверу резолвинг и проконтролировать, что по истечении таймаута виртуальный адрес переползет на Mikrotik. Но это уже зависит от вашей фантазии.

Заключение

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

На вопросы, традиционно, отвечу и с настройками помогу.