Версия 0.4.1 — это релиз про надёжность, а не про новые возможности: цепочка отказоустойчивости DoH на MikroTik получила жёсткий таймаут на каждой пробе, симметричную проверку при переключении на третий эндпоинт и честный счётчик попыток на всю цепочку. Но отдельной строки в истории изменений мало: с момента, когда вышла основная статья про этот набор (она описывала состояние 0.2.0), прошли ещё 0.3.1 и 0.4.0 — и там появилось то, ради чего всё делалось: падение в обычный DNS как последняя ступень, проба в памяти без временных файлов и автомат состояний с гистерезисом. Ниже — что именно изменилось, что обновлять на роутере и как убедиться, что изменения прижились.

TL;DR: что нового в 0.4.1
- Жёсткий таймаут. Каждый
/tool fetchв мониторе несётduration=5s— зависший эндпоинт больше не блокирует прогон дольше интервала планировщика. - Третий эндпоинт проверяется так же, как второй. Переключение на
dohUrlCтеперь идёт с проверкой после переключения и откатом при неудаче. - Счётчик честный.
DNSFailoverAttemptsрастёт на каждом реальном переключении — на второй, третий и обычный DNS, — а не только на первом. - Возврат из plain DNS не ждёт основной. Если основной эндпоинт лежит, а второй отвечает, монитор поднимается на любой рабочий DoH.
- Обновление — один импорт. Меняется только
05-dns-health-monitor.rsc, остальные скрипты трогать не нужно.
/import file-name=05-dns-health-monitor.rsc
:global DNSMonitorState; :set DNSMonitorState ""
:global DNSFailCount; :set DNSFailCount 0
:global DNSRecoverCount; :set DNSRecoverCount 0
:global DNSFailoverAttempts; :set DNSFailoverAttempts 0
:global DNSMonitorRunning; :set DNSMonitorRunning false
Проблема, которую решает версия
Монитор DoH — это скрипт, который сам решает, когда сеть переезжает на резервный резолвер. У такого скрипта три места, где ошибка стоит дорого: проба может зависнуть, переключение может оставить сеть на мёртвом эндпоинте, а возврат может застрять на неполной логике.
Первое место до 0.4.1 было открытым. Если эндпоинт принимает соединение и молчит, /tool fetch без таймаута ждёт столько, сколько даст сеть, и прогон выходит за интервал планировщика. На практике это значит, что следующий запуск накладывается на предыдущий, а в 0.3.1 появился защитный флаг от наложения — то есть сеть в такой ситуации не переключалась бы вообще, пока висит первая проба.
Второе место: третий эндпоинт (dohUrlC) добавлялся как «ещё один резерв», но проверка после переключения у него отсутствовала. Если адрес принимает соединение, а имён не разрешает, монитор оставался на сломанной третьей ступени, хотя основной к тому времени мог уже ожить.
Третье место — счётчик попыток. Логика «не больше трёх попыток на инцидент» полезна только тогда, когда считает все переключения; до 0.4.1 он рос лишь на первом, поэтому длинная цепочка могла прокручиваться дальше, чем задумано.
И четвёртое, самое неприятное по последствиям: возврат из обычного DNS. Пока резолвер работал без шифрования, монитор ждал именно основной эндпоинт. Если основной лежал час, а второй был жив, сеть час жила без DoH — при том что любая шифрованная ступень лучше открытого DNS.
Что нового: четыре изменения по существу
Жёсткий таймаут на каждой пробе
В скрипте на main шесть вызовов /tool fetch, и у всех теперь есть duration=5s (посчитано поиском по duration=5s в routeros/05-dns-health-monitor.rsc). Автор указывает, что поведение проверено на RouterOS 7.23.1.
| Что было | Что стало | Зачем |
|---|---|---|
| проба без ограничения времени | duration=5s на каждом fetch | зависший эндпоинт не выносит прогон за интервал планировщика |
| наложение прогонов защищено флагом | флаг остался, но теперь реже срабатывает | меньше «пропущенных» проверок |
Симметрия переключения: третий эндпоинт как второй
| Ступень | Проба до переключения | Проверка после | Откат при неудаче |
|---|---|---|---|
secondary (dohUrlB) | была | была | была |
tertiary (dohUrlC) | была | появилась в 0.4.1 | появилась в 0.4.1 |
plain DNS (plainFallback) | — | по содержимому | возврат на DoH |
Смысл симметрии простой: любая ступень, на которую сеть переехала, должна отвечать именами, а не просто открывать TCP. Если dohUrlC достижим, но не разрешает, монитор откатывается на основной, а не остаётся на сломанной третьей ступени.
Счётчик на всю цепочку
DNSFailoverAttempts теперь растёт на каждом реальном переключении: secondary, tertiary и plain. Вместе с maxAttempts = 3 это даёт ровно то поведение, которое обещано в документации: не больше трёх переключений на инцидент, дальше монитор ждёт восстановления основного и не забивает журнал.
Возврат из plain DNS на любой рабочий DoH
| Было | Стало |
|---|---|
из состояния plain выход только на основной эндпоинт | выход на любой рабочий DoH: если основной лежит, а второй отвечает — сеть возвращается в DoH |
| основной лежит час — час открытого DNS | открытый DNS только пока не отвечает ни один DoH |
Это изменение важнее, чем кажется: plain — это состояние с пониженной приватностью (в журнал оно пишется строкой PRIVACY DEGRADED), и держать его дольше необходимого нельзя.
Ключевые изменения с 0.2.0: что вы пропустили
Основная статья описывала 0.2.0. Между ней и текущей версией вышли две содержательные версии, и без них картина неполная.
flowchart LR V020["0.2.0: один DoH и резерв DoH, проба файлом"] --> V031["0.3.1: автомат состояний, гистерезис, строгий режим, Zabbix"] V031 --> V040["0.4.0: цепочка primary → secondary → tertiary → plain"] V040 --> V041["0.4.1: duration=5s, проверка tertiary, возврат на любой DoH"] V041 --> NOW["текущая цепочка отказоустойчивости DoH"]
| Версия | Что появилось | Почему это важно |
|---|---|---|
| 0.3.1 | автомат состояний HEALTHY → SUSPECT → FALLBACK → RECOVERING → HEALTHY плюс STUB, DEGRADED, CLOCK_INVALID, MANUAL-ONLY | поведение стало предсказуемым, а не «набором условий в скрипте» |
| 0.3.1 | failureThreshold и recoveryThreshold (оба 2) как защита от дребезга | сеть не переключается на каждой одиночной неудаче |
| 0.3.1 | настраиваемый monitorInterval (60 с вместо жёстких 3 минут) | проверка чаще, при этом без ручной правки тела скрипта |
| 0.3.1 | enforcement=strict в 02-security-policies.rsc: блокировка DoT (853) и известных публичных DoH | закрывает обход принудительного DNS, но с честно описанным остаточным риском |
| 0.3.1 | модуль zabbix/: 8 элементов, 5 триггеров, 2 дерева сервисов | состояние DoH видно по парку, а не по одному роутеру |
| 0.4.0 | проба через as-value output=user — ответ в памяти, без временных файлов в /file | убраны гонки очистки файлов |
| 0.4.0 | упорядоченная цепочка primary → secondary → tertiary → plain | появилась последняя ступень на случай, когда не отвечает ни один DoH |
| 0.4.0 | новые настройки dohUrlC, probeUrlC, plainFallback, plainServers | цепочка описывается конфигом, а не правкой тела |
| 0.4.1 | таймаут, симметрия tertiary, счётчик, возврат из plain | то, о чём эта статья |
Отдельная строка про гистерезис: два плохих прогона подряд на переключение и два хороших на возврат — это компромисс между скоростью реакции и дребезгом. При интервале 60 секунд переключение происходит примерно через две минуты после устойчивой деградации, а возврат — через две минуты после устойчивого восстановления.
Замеры и цифры
| Что | Значение | Откуда |
|---|---|---|
| Изменено файлов между 0.4.0 и 0.4.1 | 6 | заметки к релизу v0.4.1 |
| Коммитов между 0.4.0 и 0.4.1 | 3 | там же |
Вызовов /tool fetch с duration=5s | 6 | поиск по routeros/05-dns-health-monitor.rsc на main |
| Значений гистерезиса по умолчанию | 2 и 2 | config.example.rsc: failureThreshold, recoveryThreshold |
| Попыток на инцидент по умолчанию | 3 | maxAttempts |
| Интервал монитора по умолчанию | 60 с | monitorInterval |
| Тиков таймаута пробы | 5 с | duration=5s |
| Проверенных устройств | 6 | docs/verification.md |
| Проверенных версий RouterOS | 7.23.1 и 7.24.5 | там же |
| Объектов Zabbix в модуле | 8 элементов, 5 триггеров, 2 дерева | zabbix/ |
| Скриптов RouterOS в наборе | 7 (около 360 строк) | README, раздел «В цифрах» |
Все числа выше — из репозитория: либо из заметок к релизу, либо из самого кода на main. Замеров на собственном роутере в этом прогоне не было, поэтому строки про поведение на устройстве помечены как данные автора, а не как мой прогон.
Почему это круто
- Таймаут делает прогон предсказуемым. Монитор с планировщиком обязан укладываться в свой интервал;
duration=5sпревращает это из пожелания в свойство. - Симметрия убирает особый случай. Одна и та же логика для второй и третьей ступени — меньше ветвей, которые кто-то забудет обновить.
- Счётчик перестал врать. Ограничение «три попытки» наконец означает три попытки на всю цепочку.
- Возврат быстрее. Открытый DNS остаётся ровно столько, сколько нет ни одного рабочего DoH.
- Проба не оставляет мусора. С 0.4.0 ответ читается в памяти — временные файлы в
/fileи гонки их очистки больше не существуют. - Цепочка описывается конфигом.
dohUrlCпустой — ступени нет;plainFallback=false— открытый DNS запрещён полностью. - Строгий режим назван честно.
enforcement=strictблокирует DoT и публичные DoH, но остаточный риск описан, а не спрятан. - Мониторинг парка в комплекте. Модуль Zabbix видит состояние DoH с шести роутеров по SSH, а не по одному устройству.
Установка и обновление
Если набор уже стоит на 0.3.1 или 0.4.0
Меняется только монитор: якорь доверия, настройка апстрима и политики не тронуты. Порядок из заметок к релизу — импорт скрипта и очистка глобалов состояния, чтобы старые значения не влияли на новый код.
/import file-name=05-dns-health-monitor.rsc
:global DNSMonitorState; :set DNSMonitorState ""
:global DNSFailCount; :set DNSFailCount 0
:global DNSRecoverCount; :set DNSRecoverCount 0
:global DNSFailoverAttempts; :set DNSFailoverAttempts 0
:global DNSMonitorRunning; :set DNSMonitorRunning false
Перед импортом полезно снять состояние до правки — это и есть откат:
/export file=before-041
/system backup save name=before-041
Если набор ставится с нуля
flowchart TD
BKP["/export file=before-doh и /system backup save"] --> NTP["NTP по IP, без зависимости от DNS"]
NTP --> CA["00-install-ca.rsc: якорь доверия"]
CA --> DOH["01-configure-doh.rsc: один апстрим и четыре bootstrap-записи"]
DOH --> POL["02-security-policies.rsc: принудительный 53 и защита резолвера"]
POL --> MON{"обновление с 0.4.0?"}
MON -- да --> ONLY["импорт только 05-dns-health-monitor.rsc плюс очистка глобалов"]
MON -- "новая установка" --> ALL["05-dns-health-monitor.rsc целиком"]
ONLY --> VER["проверка по таблице из AGENTS.md §5"]
ALL --> VERПорядок важен: якорь доверия до апстрима, апстрим до политик, монитор последним. Каждый шаг проверяется отдельным блоком из AGENTS.md §5, и несовпадение ожидаемого значения — это дефект, а не повод «попробовать ещё раз».
| Шаг | Файл | Что делает |
|---|---|---|
| 0 | — | /export file=before-doh и /system backup save name=before-doh |
| 1 | пример конфигурации | NTP по IP-адресам: время не должно зависеть от DNS, который мы защищаем |
| 2 | 00-install-ca.rsc | импорт корневого CA и отметка trusted=yes |
| 3 | 01-configure-doh.rsc | один апстрим, verify-doh-cert=yes, четыре bootstrap-записи |
| 4 | 02-security-policies.rsc | принудительный 53 для локальной сети, отбрасывание DNS из WAN |
| 5 | 05-dns-health-monitor.rsc | скрипт монитора и планировщик |
Отдельная деталь про закрепление ссылок: main уходит вперёд тега, поэтому raw-файлы лучше брать по коммиту или тегу. В AGENTS.md закреплён коммит 38ef7e0 — это правильный подход, но помните, что вместе с ним вы получите и состояние документации на тот момент.
Проверка после обновления
Проверять нужно не «работает ли интернет», а четыре конкретные вещи: таймаут в теле скрипта, состояние монитора, счётчик попыток и отсутствие ошибок в журнале.
# 1. в скрипте на роутере есть duration=5s
/system script print where name="DNS_HealthMonitor_Failover"
# 2. состояние и счётчик
:put $DNSMonitorState
:put $DNSFailoverAttempts
# 3. разрешение имён идёт через DoH, а не через заглушку
/ip dns cache flush
:put [:resolve example.com]
# 4. в журнале нет ошибок соединения
/log print where message~"connection error"
flowchart TD
P["/tool fetch к DNS-JSON API, duration=5s"] --> R{"status пробы"}
R -- finished --> BODY{"в теле есть Status:0?"}
R -- "timeout или connection error" --> DOWN["endpoint недоступен: считать отказом"]
R -- "400 или 405" --> TLS["TLS и сертификат прошли: endpoint жив"]
BODY -- да --> OK["canary пройдена"]
BODY -- нет --> BAD["считать неудачей"]
TLS --> OK
OK --> COUNT{"failureThreshold плохих прогонов подряд?"}
BAD --> COUNT
DOWN --> COUNT
COUNT -- да --> SW["переключение по цепочке с проверкой и откатом"]
COUNT -- нет --> WAIT["ждать следующего прогона"]| Проверка | Ожидание |
|---|---|
| Состояние после чистого прогона | healthy |
| Счётчик попыток, пока основной отвечает | 0 |
Разрешение example.com | реальный адрес, не пара 8.6.112.x / 8.47.69.x |
/log print where message~"connection error" | пусто на здоровой конфигурации |
| Форма пробы | as-value output=user, без временных файлов |
Отдельно про диагностику: нельзя делать вывод «DoH мёртв» по ошибке /tool fetch. Ответ 400 или 405 означает, что TLS-рукопожатие и проверка сертификата прошли, — то есть эндпоинт жив, а запрос просто не того типа. Монитор ищет в ответе "Status":0, а не отсутствие ошибки.
Совместимость и ограничения
| Что | Значение |
|---|---|
| RouterOS | 7.20+ по заявлению, поведение проверено на 7.23.1 и 7.24.5 |
device-mode | advanced для планировщика; на home монитор запускается только вручную |
dedicated механизм блокировки клиентского DoH | enforcement=strict: DoT 853 и список публичных DoH |
| Провайдеры в цепочке | только те, что отвечают на DNS-JSON; Quad9 в резерв не годится |
| Полная реприоритизация | нет: подъём «вверх» по цепочке, но не переход «вбок» между резервами |
Ограничение про «вбок» стоит прочитать внимательно: монитор поднимается с открытого DNS на любой DoH и с резерва возвращается на основной, но не различает «сижу на втором» и «сижу на третьем», чтобы перескочить между ними. Строгий приоритет сохранён: основной всегда предпочтительнее.
Подводные камни
01и02не идемпотентны. Повторный импорт добавит вторую запись в/ip dns static, второе правило NAT и второе правило фильтра. Перед повторным импортом смотрят, что уже есть, по комментариямDoH bootstrap,force DNS,DNS.- Резервному хосту нужен свой корневой CA. Для
dns.googleэто не SSL.com: без корня Google проверка сертификата отклонит резерв, переключение не даст разрешения имён, и монитор откатится — то есть вы останетесь на мёртвом основном. durationне отменяет таймаутов планировщика. Пять секунд на пробу — это потолок на одну операцию; полный прогон из шести проб теоретически может занять больше интервала, если все эндпоинты висят.- Quad9 не может быть звеном цепочки. На JSON-пробу он отвечает
DoH unable to decode BASE64-URL, и выглядит недоступным. device-mode=homeблокирует и планировщик, иfetch. На таком устройстве монитор сохраняет текущую конфигурацию и работает только вручную.- Документация отстаёт от тега.
AGENTS.mdв заголовке называет версию 0.4.0, а README в блоке состояния документации пишет «покрытая версия 0.4.0, последний тег v0.3.1», хотя тег 0.4.1 уже выпущен. Читая инструкцию, сверяйтесь с датой и с самим кодом наmain— при расхождении верить коду. - Флаг
filteringничего не делает. В мониторе он объявлен и нигде не читается: пометка для читателя, а не переключатель поведения.
Чек-лист обновления
- Снять
/export file=before-041и/system backup save name=before-041. - Забрать
05-dns-health-monitor.rscпо закреплённому коммиту или тегу, не сmain. - Проверить в скачанном файле наличие
duration=5sиas-value output=user— до импорта, а не после. - Импортировать монитор и очистить пять глобалов состояния.
- Проверить
DNSMonitorStateиDNSFailoverAttemptsпосле первого чистого прогона. - Убедиться, что разрешение имён даёт реальный адрес, а журнал не содержит
connection error. - Если планируется третья ступень — задать
dohUrlCиprobeUrlCи проверить, что провайдер отвечает на DNS-JSON.
Критерий «обновление прижилось»: состояние healthy, счётчик попыток 0, разрешение имён работает, в журнале нет ошибок, а в теле скрипта на роутере есть duration=5s.
FAQ
Нужно ли обновлять остальные скрипты, кроме монитора?
Нет. В 0.4.1 меняется только 05-dns-health-monitor.rsc; 00, 01 и 02 остались прежними, и повторный их импорт вреден из-за отсутствия проверки существования записей.
Почему нельзя просто поставить duration=10s и забыть?
Можно, но тогда прогон из шести проб в худшем случае растянется до минуты, а интервал по умолчанию — 60 секунд. Пять секунд выбраны как компромисс между «дождаться медленного эндпоинта» и «уложиться в интервал».
Что будет, если третий эндпоинт настроен, но не разрешает имена?
Монитор проверит его после переключения и откатится на основной. Именно этого не хватало до 0.4.1: раньше сеть могла остаться на достижимом, но бесполезном эндпоинте.
Зачем нужен plainFallback, если он ухудшает приватность?
Как последняя ступень на случай, когда не отвечает ни один DoH. По умолчанию он выключен; если включён — в журнал пишется PRIVACY DEGRADED, и версия 0.4.1 сокращает время пребывания в этом состоянии до минимума.
Монитор может «перескочить» со второго эндпоинта на третий?
Нет. Подъём идёт «вверх» — с открытого DNS на DoH и с резерва на основной; различать «на втором» и «на третьем» для перехода вбок он не умеет. Это записано в известных ограничениях релиза.
Откуда берутся числа про шесть проверенных устройств?
Из docs/verification.md репозитория: три устройства на RouterOS 7.24.5 с беспроводным стеком, два без него и одно на 7.23.1. Собственных замеров на оборудовании в этой статье нет.
Стоит ли сразу включать enforcement=strict?
Сначала посмотрите, чем пользуются клиенты: строгий режим блокирует DoT и известные публичные DoH, и приложения, которые их используют, могут перестать разрешать имена. Остаточный риск при standard описан в документации проекта.
Итог
0.4.1 — маленький релиз, который закрывает три конкретные дыры: проба без таймаута, непроверенное переключение на третью ступень и счётчик, считавший только первое переключение. Вместе с 0.3.1 и 0.4.0 это превращает набор из «скрипта, который переключает DoH» в цепочку отказоустойчивости с предсказуемым поведением: автомат состояний, гистерезис против дребезга, последняя ступень на открытом DNS с честной пометкой в журнале и возврат на любой рабочий DoH. Если у вас стоит версия 0.2.0 — обновление стоит одного импорта и одной проверки.
Цитата: Отказоустойчивость — это не «есть второй адрес», а проверка каждой ступени до и после переключения и честный счётчик того, сколько раз сеть уже переезжала.
Связанные материалы
- mikrotik-doh-failover: отказоустойчивый DoH на MikroTik — основная статья продукта: установка, настройка, подводные камни.
- mikrotik-doh-failover v0.1.0 — первый релиз — разбор первой версии и её ошибок.
- Релиз v0.4.1 — заметки о выпуске, шаги обновления и известные ограничения.
- CHANGELOG.md — полная история изменений от 0.1.0 до 0.4.1.
- AGENTS.md — контракт для машинного исполнителя: предусловия, порядок применения, таблица проверок.
LLM Summary
- Тема: mikrotik-doh-failover v0.4.1 — релиз надёжности для цепочки отказоустойчивости DoH на MikroTik RouterOS; до него в блоге была только основная статья по состоянию 0.2.0.
- Что изменилось в 0.4.1:
duration=5sна каждом/tool fetch, проверка третьего эндпоинта после переключения с откатом,DNSFailoverAttemptsна всю цепочку, возврат из открытого DNS на любой рабочий DoH. - Что было пропущено с 0.2.0: 0.3.1 — автомат состояний, гистерезис
failureThreshold/recoveryThresholdпо 2,monitorInterval60 с,enforcement=strict, модуль Zabbix; 0.4.0 — пробаas-value output=userбез временных файлов, цепочка primary → secondary → tertiary → plain, настройкиdohUrlC,probeUrlC,plainFallback,plainServers. - Ключевые команды:
/import file-name=05-dns-health-monitor.rsc, очистка пяти глобалов состояния,:put $DNSMonitorState,:put $DNSFailoverAttempts,/log print where message~"connection error". - Замеры: 6 вызовов
/tool fetchс таймаутом (поиск по скрипту наmain), 3 коммита и 6 изменённых файлов между 0.4.0 и 0.4.1, 6 проверенных устройств, две версии RouterOS (7.23.1 и 7.24.5), 8 элементов и 5 триггеров Zabbix. - Ограничения: нельзя ставить Quad9 в цепочку (не отвечает на DNS-JSON),
device-mode=homeблокирует планировщик иfetch, перехода «вбок» между резервами нет,01и02не идемпотентны, документация в репозитории отстаёт от тега. - Проверка после обновления: состояние
healthy, счётчик попыток0, реальный адрес при разрешении имён, пустой журнал ошибок соединения,duration=5sв теле скрипта на роутере. - Ссылки: https://github.com/paulmann/mikrotik-doh-failover/releases/tag/v0.4.1, https://sysadministrator.ru/mikrotik-doh-failover/
Промт для агента (установка и настройка)
Готовый промт для AI-агента: скопируйте блок целиком кнопкой и отдайте своему ассистенту. Шаги, порядок применения и таблица проверок взяты из AGENTS.md репозитория — это инструкция автора для машинного исполнителя, а не пересказ.
Задача: обновить mikrotik-doh-failover до 0.4.1 на роутере RouterOS и доказать, что обновление прижилось.
Материалы:
- репозиторий: https://github.com/paulmann/mikrotik-doh-failover
- релиз: https://github.com/paulmann/mikrotik-doh-failover/releases/tag/v0.4.1
- контракт исполнителя (прочитать целиком до работы): https://github.com/paulmann/mikrotik-doh-failover/blob/main/AGENTS.md
- история изменений: https://github.com/paulmann/mikrotik-doh-failover/blob/main/CHANGELOG.md
Предусловия из AGENTS.md §2 — каждая строка проверяется, провал означает остановку, а не предупреждение:
- RouterOS 7.20 или новее: /system resource print
- время синхронизировано: /system ntp client print, status: synchronized
- device-mode известен: /system device-mode print (на home планировщик и fetch запрещены)
- административная сессия на роутере: импорт пишет в хранилище сертификатов
- файлы CA и .rsc загружены в ФАЙЛЫ роутера, а не в рабочий каталог: import file-name= читает файловую систему роутера
- имена интерфейсов совпадают с реальностью: /interface bridge print, /interface list print
- есть окно обслуживания: /export file=before-doh до первого шага
Порядок применения из AGENTS.md §4:
0. /export file=before-doh и /system backup save name=before-doh
1. NTP по IP-адресам: /system ntp client set enabled=yes servers=162.159.200.1,216.239.35.0
2. /import file-name=00-install-ca.rsc
3. /import file-name=01-configure-doh.rsc
4. /import file-name=02-security-policies.rsc
5. обновление до 0.4.1: /import file-name=05-dns-health-monitor.rsc, затем очистить глобалы DNSMonitorState, DNSFailCount, DNSRecoverCount, DNSFailoverAttempts, DNSMonitorRunning
Проверка из AGENTS.md §5 — ожидаемые значения, несовпадение является отчётом о дефекте:
- /certificate print where trusted=yes — доверенный SSL.com TLS ECC Root CA 2022
- /ip dns print — servers=1.1.1.1,1.0.0.1, use-doh-server=https://cloudflare-dns.com/dns-query, verify-doh-cert=yes
- /ip dns static print where comment~"DoH bootstrap" — четыре записи: две для cloudflare-dns.com, две для dns.google
- /ip firewall nat print where comment~"force DNS" — два правила redirect, UDP и TCP, порт 53
- /ip firewall filter print where comment~"DNS" — accept из LAN, drop из WAN, UDP и TCP
- /ip dns cache flush, затем :put [:resolve example.com] — реальный адрес, НЕ пара 8.6.112.x / 8.47.69.x
- :put $DNSMonitorState — healthy после чистого прогона
- :put $DNSFailoverAttempts — 0, пока отвечает основной
- проба эндпоинта: /tool fetch с as-value output=user и duration=5s — status finished и неотрицательная позиция :find по "Status":0
- /log print where message~"connection error" — пусто на здоровой конфигурации
Запрещено:
- повторно импортировать 01 и 02 без проверки: они не идемпотентны и создадут дубли (/ip dns static print where comment~"DoH bootstrap", /ip firewall nat print where comment~"force DNS", /ip firewall filter print where comment~"DNS")
- считать ошибку /tool fetch доказательством «DoH мёртв»: 400 или 405 означают, что TLS и сертификат прошли
- ставить Quad9 звеном цепочки: он не отвечает на DNS-JSON
- рассчитывать на автоматический планировщик при device-mode=home: там только ручной запуск /system script run DNS_HealthMonitor_Failover
Что считать успехом: состояние healthy, счётчик попыток 0, разрешение имён даёт реальный адрес, журнал без ошибок соединения, в теле скрипта на роутере присутствует duration=5s.