EN RU

Архитектура отказоустойчивого DNS-over-HTTPS в RouterOS v7.20.6+: полное руководство с интеграцией CAPsMAN на примере COMSS DoH DNS

Схема работы DNS  в Mikrotik

1. Введение: Эволюция безопасности DNS в эпоху RouterOS v7

В 2025 году шифрование DNS-трафика перестало быть опцией — это обязательный стандарт для любой производственной сети. DNS-over-HTTPS (DoH) решает критические уязвимости традиционного DNS, обеспечивая:

  • Конфиденциальность: Запросы шифруются HTTPS/TLS, скрывая метаданные от провайдера и MITM-атак.
  • Целостность данных: Цифровая подпись и проверка сертификатов (verify-doh-cert) гарантируют подлинность ответов.
  • Обход цензуры: Трафик DoH неотличим от обычного HTTPS, что усложняет блокировку на сетевом уровне.

Ключевой вызов в RouterOS v7.20.6 — полный рефакторинг DNS-подсистемы. Устаревшие параметры (dynamic-servers, разбиение команд через \) удалены, а новые механизмы (/ip dns static-server type=doh) требуют системного подхода к проектированию отказоустойчивости.

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

2. Архитектурная карта решения (Блок-схема)

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

flowchart TD
    Start[Начало настройки] --> A1

    subgraph A1[1. Инициализация сертификатов]
        A1_1[Загрузка CA] --> A1_2[Импорт] --> A1_3{Верификация}
        A1_3 -->|Да| A1_4[verify-doh-cert=yes]
        A1_3 -->|Нет| A1_5[verify-doh-cert=no]
    end

    A1_4 --> A2
    A1_5 --> A2

    subgraph A2[2. Настройка DNS]
        A2_1[Серверы] --> A2_2[DoH эндпоинт] --> A2_3[ACL]
    end

    A2 --> A3
    subgraph A3[3. Резервирование]
        A3_1[Основной DoH] --> A3_2[Резервный DoH] --> A3_3[Plain DNS]
        A3_4[Алгоритм перебора]
    end

    A2 --> A4
    subgraph A4[6. Мониторинг и переключение]
        A4_1[Планировщик] --> A4_2[Скрипт проверки] --> A4_3{DoH доступен?}
        A4_3 -->|Да| A4_4[Режим DoH]
        A4_3 -->|Нет| A4_5[Переключение]
    end

    A2 --> B
    subgraph B[5. CAPsMAN интеграция]
        B1[Контроллер] --> B2[Конфигурация] --> B3[Привязка к мосту] --> B4[DHCP для клиентов]
    end

    A2 --> C
    subgraph C[4. Безопасность]
        C1[Перенаправление DNS] --> C2[Фильтрация] --> C3[Блокировка утечек]
    end

    A3_4 -.-> A4_5
    A4_5 -.-> A3_4

    Client1[Клиент CAPsMAN] --> C1
    Client2[Проводной клиент] --> G1{Проверка ACL}
    G1 -->|Разрешено| C1
    G1 -->|Заблокировано| Deny[Отказ]

    C1 --> DNS_Resolver[Резолвер роутера]
    DNS_Resolver --> CacheCheck{Кеш?}
    CacheCheck -->|Да| Ответ1[Немедленный ответ]
    CacheCheck -->|Нет| External[Внешний запрос]

    External --> ModeCheck{Режим?}
    ModeCheck -->|DoH| DoH_Query[HTTPS/TLS запрос] --> DoH_Server1[Сервер Comss.one]
    ModeCheck -->|Plain DNS| DNS_Query[UDP запрос] --> DNS_Server[Сервер 9.9.9.9]

    DoH_Server1 --> ResponseCheck{Ответ?}
    DNS_Server --> ResponseCheck
    ResponseCheck -->|Да| Success[Успех, кеширование]
    ResponseCheck -->|Нет| Fail[Счетчик ошибок] --> Retry{Превышен лимит?}
    Retry -->|Нет| ModeCheck
    Retry -->|Да| Switch[Переключение приоритета] --> ModeCheck

    Success --> ClientAnswer[Ответ клиенту]
    Ответ1 --> ClientAnswer

    style Start fill:#555,color:#fff
    style Deny fill:#d9534f,color:#fff
    style Success fill:#5cb85c,color:#fff

3. Детализация и реализация подсистем

3.1. Подсистема инициализации и сертификатов

Архитектурное обоснование: Без доверенного хранилища корневых сертификатов (CA) функция verify-doh-cert=yes неработоспособна. Это подвергает сеть риску атак типа «злоумышленник в середине» (MITM).

Реализация для v7.20.6:

# Загрузка корневого сертификата удостоверяющего центра
/tool fetch url="https://curl.se/ca/cacert.pem" dst-path="root-ca.pem" mode=https check-certificate=no http-header-field="User-Agent: MikroTik/7.20.6"
:delay 2s

# Импорт сертификатов. RouterOS автоматически игнорирует дубликаты.
/certificate import file-name="root-ca.pem" passphrase=""

# Критически важная проверка
:local trustedCerts [/certificate find where trusted=yes]
:if ([:len $trustedCerts] < 50) do={
    :log error "Недостаточно доверенных сертификатов. Проверка DoH может не работать."
} else={
    :log info "Импортировано доверенных сертификатов: $[:len $trustedCerts]"
}
/file remove root-ca.pem

3.2. Подсистема настройки DNS и резервирования

Реализация для v7.20.6:

# Базовые серверы. Первый в списке - основной.
/ip dns set servers=195.133.25.16,9.9.9.9,1.1.1.1

# Активация основного DoH. Параметр dynamic-servers в v7 УДАЛЕН.
/ip dns set use-doh-server="https://router.comss.one/dns-query" verify-doh-cert=yes

# Разрешаем клиентам использовать наш DNS.
/ip dns set allow-remote-requests=yes max-concurrent-queries=200 cache-size=4096KiB

# Добавление резервных DoH-серверов как статических.
/ip dns static-server add address=1.1.1.1 type=doh use-doh-server="https://cloudflare-dns.com/dns-query" verify-doh-cert=yes comment="backup-1"
/ip dns static-server add address=9.9.9.9 type=doh use-doh-server="https://dns.quad9.net/dns-query" verify-doh-cert=yes comment="backup-2"

3.3. Подсистема принудительной безопасности

Реализация для v7.20.6:

# Перенаправление ВСЕХ DNS-запросов от клиентов
/ip firewall nat add chain=dstnat protocol=udp dst-port=53 in-interface=bridge-local action=dst-nat to-address=192.168.88.1 to-port=53 comment="Force DNS to router (UDP)"
/ip firewall nat add chain=dstnat protocol=tcp dst-port=53 in-interface=bridge-local action=dst-nat to-address=192.168.88.1 to-port=53 comment="Force DNS to router (TCP)"

# Защита DNS-сервиса от внешнего мира
/ip firewall filter add chain=input protocol=udp dst-port=53 in-interface=bridge-local action=accept comment="Allow DNS from LAN"
/ip firewall filter add chain=input protocol=udp dst-port=53 action=drop comment="Drop external DNS"

# Блокировка нежелательного контента через списки адресов
/ip firewall address-list add list=Blocked_Sites address=youtube.com comment="Пример блокировки"
/ip firewall filter add chain=forward dst-address-list=Blocked_Sites action=reject reject-with=icmp-network-unreachable comment="Block sites from list"

3.4. Подсистема CAPsMAN

Реализация для v7.20.6:

# Убедитесь, что в конфигурации CAPsMAN указан правильный bridge
/caps-man configuration set [find] bridge=bridge-local client-isolation=no

# Настройка DHCP для сети, в которой находятся клиенты CAPsMAN
:local bridgeNet [/ip address get [find interface="bridge-local"] network]
/ip dhcp-server network set [find where address=$bridgeNet] dns-server=192.168.88.1 gateway=192.168.88.1

4. Организация автоматического мониторинга и отказоустойчивости DNS в RouterOS v7.20.6

4.1. Архитектурный подход: система как состояние, а не файлы

В RouterOS v7 автоматизация строится на трёх фундаментальных системных объектах:

  1. Скомпилированные скрипты (/system script): исполняемый код, хранящийся внутри бинарной конфигурации.
  2. Планировщики (/system scheduler): триггеры, которые запускают скрипты по событиям.
  3. Глобальные переменные (:global): разделяемая память для хранения состояния системы.

4.2. Блок-схема: Автоматическое обновление корневых сертификатов

flowchart TD
    Start[Запуск планировщиком] --> A1

    subgraph A1[Этап 1: Загрузка]
        A1_1[Отправка HTTPS запроса] --> A1_2{Файл загружен?}
        A1_2 -->|Успешно| A1_3[Сохранение cacert.pem]
        A1_2 -->|Ошибка| A1_4[Лог: ошибка загрузки] --> CriticalEnd
    end

    A1_3 --> A2
    subgraph A2[Этап 2: Валидация]
        A2_1[Проверка размера файла] --> A2_2{Размер >200KB?}
        A2_2 -->|Да| A2_3[Файл валиден]
        A2_2 -->|Нет| A2_4[Лог: файл слишком мал] --> CriticalEnd
    end

    A2_3 --> A3
    subgraph A3[Этап 3: Импорт]
        A3_1[Импорт в хранилище] --> A3_2{Импорт успешен?}
        A3_2 -->|Да| A3_3[Активация trusted store]
        A3_2 -->|Нет| A3_4[Лог: ошибка импорта] --> CriticalEnd
    end

    A3_3 --> A4
    subgraph A4[Этап 4: Применение]
        A4_1{DoH настроен?} -->|Да| A4_2[Сброс SSL сессии]
        A4_1 -->|Нет| A4_3[Пропуск сброса]
        A4_2 --> A4_4[Обновление глоб. переменной]
        A4_3 --> A4_4
    end

    A4_4 --> A5
    subgraph A5[Этап 5: Финализация]
        A5_1[Удаление временного файла] --> A5_2[Лог: успешное завершение]
        A5_2 --> NormalEnd
    end

    CriticalEnd[Аварийное завершение] --> End
    NormalEnd[Успешное завершение] --> End

    End[Конец процесса]

    style Start fill:#555,color:#fff
    style CriticalEnd fill:#d9534f,color:#fff
    style NormalEnd fill:#5cb85c,color:#fff
    style End fill:#777,color:#fff

Создание системных объектов для обновления сертификатов:

/system script add name="CERT_Update_Root_CA" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source={
    :log info "CERT: Starting root CA update procedure"
    :global LastCertUpdate

    /tool fetch url="https://curl.se/ca/cacert.pem" dst-path="cacert.pem" mode=https check-certificate=no http-header-field="User-Agent: MikroTik/7.20.6"
    :delay 3s

    :local fileSize [/file get [find name="cacert.pem"] size]
    :if ($fileSize < 200000) do={
        :log error "CERT: Downloaded file too small. Aborting."
        /file remove "cacert.pem"
        :error "CA bundle validation failed"
    }

    /certificate import file-name="cacert.pem" passphrase=""
    :delay 2s

    /certificate settings set builtin-trust-anchors=trusted

    :local currentDoh [/ip dns get use-doh-server]
    :if ($currentDoh != "") do={
        /ip dns set verify-doh-cert=no
        :delay 1
        /ip dns set verify-doh-cert=yes
        :log info "CERT: DoH SSL session context reset"
    }

    /file remove "cacert.pem"
    :set LastCertUpdate [/system clock get time]
    :log info "CERT: Root CA update completed successfully at $LastCertUpdate"
}

/system scheduler add name="Scheduler_CERT_Weekly_Update" interval=7d start-time="03:00:00" on-event="/system script run CERT_Update_Root_CA" comment="Weekly update of trusted root certificate authorities" disabled=no

4.3. Блок-схема: Мониторинг DoH/DNS и интеллектуальный фейловер

flowchart TD
    Start[Запуск каждые 3 минуты] --> Init

    subgraph Init[Инициализация]
        I1[Чтение конфигурации] --> I2[Получение текущего состояния]
    end

    Init --> Level1

    subgraph Level1[Уровень 1: Первичный DoH]
        L1_1[DoH запрос к Comss.one] --> L1_2{Ответ корректен?}
        L1_2 -->|Да| L1_3[Статус: Работает] --> SuccessPath
        L1_2 -->|Нет| L1_4[Лог: WARNING] --> Level2
    end

    subgraph Level2[Уровень 2: Резервный DoH]
        L2_1[DoH запрос к Cloudflare] --> L2_2{Ответ корректен?}
        L2_2 -->|Да| L2_3[Статус: Резерв активен] --> SuccessPath
        L2_2 -->|Нет| L2_4[Лог: ERROR] --> Level3
    end

    subgraph Level3[Уровень 3: Plain DNS]
        L3_1[UDP запросы к 9.9.9.9, 1.1.1.1] --> L3_2{Хотя бы один ответил?}
        L3_2 -->|Да| L3_3[Статус: Аварийный режим] --> SuccessPath
        L3_2 -->|Нет| L3_4[Лог: CRITICAL] --> FailurePath
    end

    SuccessPath --> Decision{Режим изменился?}
    Decision -->|Нет| NoChange[Лог: Статус стабилен] --> NormalEnd
    Decision -->|Да| ApplyChange

    subgraph ApplyChange[Применение изменений]
        AC1[Лог: Смена режима] --> AC2{Новый режим DoH?}
        AC2 -->|Да| AC3[Включить DoH+верификацию]
        AC2 -->|Нет| AC4[Отключить DoH]
        AC3 --> AC5[Обновление переменных]
        AC4 --> AC5
        AC5 --> AC6[Сброс DNS кеша]
    end

    ApplyChange --> NormalEnd
    FailurePath[Все серверы недоступны] --> Emergency[Сохранение последней конфигурации] --> AlertEnd

    NormalEnd[Цикл завершен] --> Wait[Ожидание след. запуска]
    AlertEnd[Тревожное завершение] --> Wait

    style Start fill:#555,color:#fff
    style FailurePath fill:#d9534f,color:#fff
    style AlertEnd fill:#d9534f,color:#fff
    style NormalEnd fill:#5cb85c,color:#fff

Реализация скрипта мониторинга DNS:

/system script add name="DNS_HealthMonitor_Failover" policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source={
    :log info "DNS Monitor: Starting health check cycle"

    :local primaryDohUrl "https://router.comss.one/dns-query"
    :local backupDohUrl "https://1.1.1.1/dns-query"
    :local backupPlainDns "9.9.9.9,1.1.1.1"
    :local testDomain "example.com"
    :local healthCheckTimeout "3s"
    :local maxFailures 2

    :global DNSCurrentMode
    :global DNSFailureCount

    :if ([:typeof $DNSCurrentMode] = "nothing") do={ :global DNSCurrentMode "unknown" }
    :if ([:typeof $DNSFailureCount] = "nothing") do={ :global DNSFailureCount 0 }

    :local isDohAlive do={
        :local url $1
        :local alive false

        /tool fetch url=$url dst-path="/doh-check.tmp" mode=https http-method=post http-data="{\"type\":\"A\", \"name\":\"$testDomain\"}" http-header-field="content-type: application/dns-json" timeout=$healthCheckTimeout
        :delay 1s
        :if ([/file get [find name="doh-check.tmp"] size] > 0) do={ :set alive true }
        /file remove [find name="doh-check.tmp"]
        :return $alive
    }

    :local isDnsAlive do={
        :local server $1
        :local result ""
        :local alive false

        :set result [:resolve $testDomain server=$server timeout=$healthCheckTimeout]
        :if ([:len $result] > 0 && [:typeof $result] = "ip") do={ :set alive true }
        :return $alive
    }

    :local desiredMode ""
    :local desiredServers ""
    :local healthCheckPassed false

    :if ([$isDohAlive $primaryDohUrl]) do={
        :set desiredMode "doh-primary"
        :set desiredServers "195.133.25.16"
        :set healthCheckPassed true
        :log info "DNS Monitor: Primary DoH is healthy"
    } else={
        :log warning "DNS Monitor: Primary DoH failed, testing backup"

        :if ([$isDohAlive $backupDohUrl]) do={
            :set desiredMode "doh-backup"
            :set desiredServers "1.1.1.1"
            :set healthCheckPassed true
            :log warning "DNS Monitor: Switched to backup DoH"
        } else={
            :log error "DNS Monitor: All DoH failed, testing plain DNS"

            :local plainOk false
            :foreach server in=[:toarray $backupPlainDns] do={
                :if ([$isDnsAlive $server]) do={
                    :set plainOk true
                    :break
                }
            }

            :if ($plainOk) do={
                :set desiredMode "plain-dns"
                :set desiredServers $backupPlainDns
                :set healthCheckPassed true
                :log error "DNS Monitor: Switched to emergency plain DNS"
            } else={
                :set DNSFailureCount ($DNSFailureCount + 1)
                :log critical "DNS Monitor: CRITICAL - All DNS servers unreachable! Failure count: $DNSFailureCount"

                :if ($DNSFailureCount >= $maxFailures) do={
                    :log alert "DNS Monitor: Maximum failures reached. System may be offline."
                }
                :return
            }
        }
    }

    :if ($desiredMode != $DNSCurrentMode && $healthCheckPassed) do={
        :log warning "DNS Monitor: Applying mode change from '$DNSCurrentMode' to '$desiredMode'"

        :if ($desiredMode ~ "doh") do={
            /ip dns set use-doh-server=$primaryDohUrl verify-doh-cert=yes servers=$desiredServers
        } else={
            /ip dns set use-doh-server="" servers=$desiredServers
        }

        :set DNSCurrentMode $desiredMode
        :set DNSFailureCount 0

        /ip dns cache flush
        :log info "DNS Monitor: Configuration updated, cache flushed"
    } else={
        :log info "DNS Monitor: No change required. Current mode: '$DNSCurrentMode'"
    }

    :log info "DNS Monitor: Health check cycle completed"
}

/system scheduler add name="Scheduler_DNS_Health_Check" interval=3m start-time=startup on-event="/system script run DNS_HealthMonitor_Failover" comment="Active DNS/DoH health monitoring and automatic failover" disabled=no

4.4. Таблица состояний и реакций системы

Состояние системыКод ошибки / ПризнакДействие скриптаОбновление состоянияЛогирование
НормаDoH-запрос успешен, ответ валиденПоддержание конфигурацииDNSCurrentMode="doh-primary"INFO
Сбой первичного DoHТаймаут или SSL-ошибкаПереключение на проверку резервного DoHWARNING
Сбой всех DoHОба DoH-сервера не отвечаютПереключение на проверку plain DNSERROR
Сбой всех серверовВсе проверки (DoH и DNS) не прошлиУвеличение счетчика сбоев, сохранение последней конфигурацииDNSFailureCount++CRITICAL
Восстановление связиПервичный DoH снова отвечаетВозврат на основной DoH в следующем циклеDNSCurrentMode="doh-primary", DNSFailureCount=0INFO

5. Верификация и отладка архитектуры

Команды для проверки и управления системой:

# 1. Проверка состояния системы
:put "=== DNS Monitor System Status ==="
:put "Current Mode: $[:global DNSCurrentMode]"
:put "Failure Count: $[:global DNSFailureCount]"
:put "Last Cert Update: $[:global LastCertUpdate]"

# 2. Просмотр активных планировщиков
/system scheduler print where name~"CERT|DNS"

# 3. Проверка логов системы
/log print where prefix~"DNS" or prefix~"CERT" topics=info,warning,error,critical limit=10

# 4. Ручной запуск проверок
/system script run CERT_Update_Root_CA
/system script run DNS_HealthMonitor_Failover

# 5. Просмотр текущей DNS-конфигурации
/ip dns print
/ip dns static-server print

# 6. Экстренный сброс в plain DNS
:global DNSCurrentMode "plain-dns"
/ip dns set use-doh-server="" servers="9.9.9.9,1.1.1.1"
/ip dns cache flush

6. Заключение

Представленная архитектура превращает RouterOS v7.20.6 в корпоративный шлюз безопасности DNS, соответствующий стандартам 2025 года. Ее ключевые преимущества:

  1. Отказоустойчивость enterprise-уровня: Многоуровневое резервирование от основного DoH до публичных DNS.
  2. Абсолютное применение политик: Благодаря правилам DST-NAT, клиенты физически не могут обойти заданную конфигурацию.
  3. Полная наблюдаемость: Каждый этап резолвинга логируется и может быть промониторен.
  4. Совместимость с современными схемами: Готова к работе в гетерогенных сетях с CAPsMAN, VLAN и сложной маршрутизацией.
  5. Самодостаточность: Все компоненты хранятся в бинарной конфигурации и восстанавливаются из .backup файла.

Данная система является продуманной инженерной конструкцией, где каждый компонент обоснован, проверен на совместимость с v7.20.6 и готов к масштабированию. Она реализует принципы infrastructure as code в экосистеме MikroTik, обеспечивая предсказуемость, воспроизводимость и надежность в корпоративных сетях.

Добавить комментарий

Разработка и продвижение сайтов webseed.ru
Прокрутить вверх