DNS Keenetic через Mihomo: штатный путь через ProxyN (DoT/DoH on ProxyN)¶
Статус: Confirmed (архитектурные примитивы: синтаксис CLI Keenetic, контракт ProxyN в
keenetic-auto-setup, возможности Mihomo) + Research (сквозная цепочка целиком не
проверялась на живом роутере; live-тест — обязательный следующий шаг)
Область применения: KeeneticOS 3.9+ (компонент «Proxy client»); связка
keenetic-auto-setup (ProxyN → Mihomo 127.0.0.1:7890); задача «DNS самого Keenetic не
должен уходить через провайдера напрямую»
Проверено на: официальный CLI-справочник Keenetic (команды dns-proxy tls/https
upstream, ip name-server, ip route, dns-proxy intercept enable), код
saymer-alt/keenetic-auto-setup (install.sh, ARCHITECTURE.md), документация Mihomo
(wiki.metacubex.one) — всё на 2026-09-24
Последняя проверка: 2026-09-24
Source of truth: CLI-справочник Keenetic; keenetic-auto-setup/install.sh (контракт
ProxyN); wiki.metacubex.one/config/dns
Provenance: research-диалог mihomo-dns.md (снимок 2026-09-22);
форум Keenetic — как поддерживающее свидетельство, не как истина
Что решаем¶
Задача: upstream DNS самого Keenetic (куда роутер ходит за резолвингом) должен проходить через Mihomo и его proxy/outbound, а не напрямую через провайдера. При этом решение должно оставаться штатным для KeeneticOS — без iptables-хаков и без принудительного заворачивания системного DNS в TUN Mihomo.
Кандидатная архитектура:
Keenetic DNS-proxy
↓ DoT (TCP/853) или DoH, привязанный к ProxyN
ProxyN (прокси-интерфейс KeeneticOS)
↓ SOCKS5
127.0.0.1:7890 (mixed-port Mihomo)
↓ правила Mihomo
выбранный proxy / proxy-group
↓
удалённый DNS-резолвер (DoT/DoH)
Статья фиксирует, какие примитивы этой схемы подтверждены синтаксисом и кодом, а какие части остаются непроверенными до live-теста. Полная цепочка целиком нигде ещё не запускалась — это Research-интеграция на подтверждённых примитивах.
Контекст: три независимых DNS-решения¶
Прежде чем менять DNS, важно развести три разных вопроса (модель — из
ARCHITECTURE.md
проекта keenetic-auto-setup):
- DNS клиента — куда клиенты отправляют запросы. Установщик проекта включает
перехват транзитного DNS (
dns-proxy intercept enable), чтобы классический DNS/53 приходил в DNS-прокси роутера (нужно MagiTrickle для классификации). - DNS upstream — куда за резолвингом ходит сам Keenetic. Этим управляют
ip name-server(классические DNS) иdns-proxy tls/https upstream(DoT/DoH). Только этот уровень — предмет настоящей статьи. - DoH/DoT клиентов — шифрованный DNS браузеров и приложений идёт мимо порта 53 в любом случае и перехватом не контролируется.
Ключевое различение: dns-proxy intercept ≠ выбор upstream-пути¶
dns-proxy intercept enable — это перехват транзитных DNS-запросов клиентов:
клиент хотел отправить классический DNS/53 внешнему резолверу, а Keenetic перенаправил
запрос в собственный DNS-proxy. Официальный справочник описывает команду именно так:
«Enable transit DNS requests interception for system profile» (появилась в 3.06, в 3.08
убиралась как устаревшая, с 3.09 снова присутствует).
client DNS interception Keenetic DNS-proxy → upstream
(перехват запросов клиентов) (транспорт/путь собственного резолва)
dns-proxy intercept enable ip name-server / dns-proxy tls|https upstream
Это не настройка того, через какой интерфейс/WAN/Proxy идёт upstream DNS самого
Keenetic. Для управления upstream-путем служит привязка on <interface> в командах
upstream — см. ниже. Смешение этих двух механизмов — типичная ошибка при обсуждении
«завести DNS в прокси».
Как это работает (подтверждённые примитивы)¶
CLI Keenetic: upstream с привязкой к интерфейсу¶
Официальный CLI-справочник подтверждает синтаксис (версии — по history справочника; проверено 2026-09-24):
DoT upstream (с 3.01; аргумент domain — с 3.08):
dns-proxy tls upstream <address> [<port>] [sni <fqdn>] [spki <hash>] [on <interface>] [domain <domain>]
no dns-proxy tls upstream [<address>] [<port>]
Родной пример справочника — ровно тот случай, который нужен для эксперимента:
(config-dnspx)> tls upstream 1.1.1.1 853 sni cloudflare-dns.com on ISP
Dns::Secure::ManagerDot: DNS-over-TLS name server 1.1.1.1:853 added.
DoH upstream (с 3.01; domain — с 3.08):
dns-proxy https upstream <url> [<format>] [sni <hash>] [on <interface>] [domain <domain>]
no dns-proxy https upstream [<url>]
Пример справочника: https upstream https://dns.adguard.com/dns-query dnsm on ISP.
Отличие от DoT: endpoint задаётся URL (доменное имя), что добавляет задачу начального
резолва имени самого DoH-сервера; в справочнике для DoH параметр закрепления сертификата
идёт как hash (spki) — тонкость синтаксиса, которую при live-тесте нужно сверить с
подсказкой CLI на месте (dns-proxy https upstream ?).
Классический DNS с привязкой (ip name-server, с 2.00; порт — с 2.14):
ip name-server <address> [:<port>] [<domain> [on <interface>]]
no ip name-server [<address>[:<port>]] [<domain> [on <interface>]]
Пример справочника: ip name-server 8.8.8.8 "" on ISP (пустая строка "" — домен по
умолчанию, сервер используется для всех запросов; до 16 доменов на одну запись).
Скоупинг эксперимента доменом. И DoT/DoH upstream, и ip name-server принимают
аргумент domain <домен> — запись обслуживает только указанную зону. Это позволяет
проводить проверку, не переводя весь роутер на новый DNS.
Статический /32-маршрут с fail-closed семантикой (ip route; reject — с 3.08,
работает только вместе с auto, неприменим к default route):
ip route <host> <interface> auto reject
Официальное описание reject: «If the specified interface is not active, the traffic is
not sent via other possible routes» — то есть при недоступности выбранного интерфейса
трафик не уходит через другие маршруты. Родной пример справочника:
ip route 123.123.123.123 Wireguard1 auto reject.
Контракт ProxyN из кода keenetic-auto-setup¶
Подтверждено по install.sh текущего main (проверено 2026-09-24):
- проектный ProxyN — Proxy-интерфейс KeeneticOS с upstream SOCKS5 на
127.0.0.1:7890(фиксированный контрактный порт Mihomo); - порядок настройки в установщике: сначала
interface ProxyN proxy protocol socks5, затемinterface ProxyN proxy socks5-udp, затемinterface ProxyN proxy upstream 127.0.0.1 7890, затемdescription "mihomo t2sN"; - проектный интерфейс опознаётся по двум маркерам сразу (
description "mihomo t2sN"иproxy upstream 127.0.0.1 7890в одном блоке running-config); чужой Proxy не трогается; на чистом роутере создаётсяProxy0, при занятом — первый свободныйProxyN; - bootstrap-конфиг Mihomo от установщика содержит только
mixed-port: 7890— секцииdns:в проекте нет: DNS-listener Mihomo не является частью текущей установки.
Компонент «Proxy client» существует с KeeneticOS 3.9 (официальная статья «Proxy client»),
поддерживает HTTP/HTTPS/SOCKS5. Сами подкоманды proxy protocol / proxy socks5-udp /
proxy upstream в индекс CLI-справочника не входят — они живут в контексте интерфейса
(документированы в PDF-справочниках CLI и видны в show running-config); для нас их
авторитетный источник — код установщика, который применяет их на реальных роутерах.
Возможности Mihomo (текущая документация)¶
Подтверждено по wiki.metacubex.one/config/dns (проверено 2026-09-24):
dns.enable+dns.listen— встроенный DNS-сервер Mihomo; listener поддерживает UDP и TCP (пример:listen: 127.0.0.1:1053);enhanced-mode: redir-host | fake-ip— оба режима документированы (default — redir-host); redir-host не помечен deprecated;- upstream-DNS можно привязать к прокси или интерфейсу суффиксом
#:'https://8.8.8.8/dns-query#PROXY'(имя существующего прокси; иначе — имя интерфейса),#RULES— следовать routing-правилам; proxy-server-nameserver— отдельный резолвер для доменных имён proxy-нод; без него при proxy-bound DNS возможен chicken-and-egg (документированное предупреждение);default-nameserver— резолвер имён самих DNS-серверов (нужен, когда upstream задан доменным именем, например DoH URL);- routing-правила Mihomo матчатся сверху вниз, приоритет у верхних; у IP-правил есть
параметр
no-resolve(нюанс: если DNS-резолв уже был вызван более ранним правилом, target-IP правило сматчится и сno-resolve).
Кандидатные варианты¶
| Схема | Что происходит | Статус |
|---|---|---|
dns-proxy tls upstream … on ProxyN |
Keenetic отправляет DoT (TCP/853) через SOCKS5/Mihomo | Первый кандидат; примитивы Confirmed, цепочка — Research |
dns-proxy https upstream … on ProxyN |
То же через DoH | Research (сложнее: bootstrap имени endpoint) |
ip name-server <IP> "" on ProxyN |
Классический UDP/TCP DNS через ProxyN (SOCKS5 UDP) | Research; зависит от фактической работы proxy socks5-udp |
/32 ip route → ProxyN [auto reject] |
Принудительный маршрут IP резолвера через Proxy-интерфейс | Research-fallback; риск петли при DIRECT в Mihomo (см. ниже) |
Keenetic → 127.0.0.1:1053 → DNS Mihomo с #PROXY upstream |
DNS полностью отдаётся Mihomo | Research (план B/C: требует правки config.yaml, не входит в проект) |
Keenetic → mitun0 напрямую |
Системный DNS заворачивается в TUN Mihomo | Не рекомендуется — см. ниже |
Почему не mitun0 напрямую¶
mitun0 — Linux TUN, созданный самим Mihomo; ProxyN — полноценный интерфейс
KeeneticOS, который NDM знает как соединение. При заворачивании системного DNS в
mitun0 нет простой гарантии, что собственные outbound-соединения Mihomo не попадут
обратно в его же TUN (особенно для локально созданного трафика роутера). У ProxyN
граница компонентов ясная: Keenetic application → ProxyN → SOCKS → Mihomo → outbound.
Прямой mitun0-вариант не является каноническим, пока не доказан отдельно (обратное
тоже не доказано — это осознанный выбор более простой для рассуждения границы).
Требования¶
- KeeneticOS 3.9+ с установленным компонентом «Proxy client»;
- развёрнутый
keenetic-auto-setup(существующий проектный ProxyN, Mihomo слушает127.0.0.1:7890); - доступ к CLI роутера (
ndmc) и понимание, что команды ниже меняют running-config (не persistent доsystem configuration save); - для доказательства egress — доступ к VPS, через который реально выходит выбранный proxy (tcpdump на выходе).
Безопасный тест-план (НЕ выполнен; выполнять только как задачу на живом роутере)¶
Цель: доказать цепочку Keenetic DoT → ProxyN → Mihomo → proxy (не DIRECT) → 1.1.1.1:853,
не переводя роутер на новый DNS и не сохраняя конфигурацию до успешной проверки.
- Снять состояние, ничего не меняя. Определить фактический проектный
ProxyN(не предполагатьProxy0):
ndmc -c 'show version'
ndmc -c 'show ip name-server'
ndmc -c 'show dns-proxy'
ndmc -c 'show running-config' | grep -E 'interface Proxy|description.*mihomo|proxy protocol|proxy socks5-udp|proxy upstream|ip global'
Проектный интерфейс опознаётся по паре маркеров в одном блоке:
description "mihomo t2sN" + proxy upstream 127.0.0.1 7890. Ниже в примерах —
Proxy0; подставить фактический.
-
Выбрать DNS-IP, которого сейчас нет среди name-server/upstream — это упростит чистое удаление тестовой записи. Если
1.1.1.1уже используется, взять другой публичный DoT-резолвер (например, из Quad9/Google) и соответствующий ему SNI. -
Добавить domain-scoped DoT upstream (меняет только running-config; не трогает DNS остальных зон):
ndmc -c 'dns-proxy tls upstream 1.1.1.1 853 sni cloudflare-dns.com on Proxy0 domain example.com'
ndmc -c 'show dns-proxy'
domain example.com ограничивает запись тестовой зоной: весь остальной резолв
роутера не меняется.
- Проверить резолв через Keenetic с LAN-клиента, явно указав роутер как DNS (чтобы не смешивать с DNS самой ОС клиента; если DHCP выдаёт клиентам внешний DNS напрямую, клиент вообще минует DNS-proxy роутера):
nslookup example.com <LAN-IP-роутера>
- Доказать путь трафика, а не только успешный резолв:
# на Keenetic (Entware): активность между Proxy-интерфейсом и Mihomo
tcpdump -ni lo 'port 7890'
# не появляется ли ПРЯМОЕ соединение с 1.1.1.1 через WAN (утечка мимо ProxyN)
tcpdump -ni any 'host 1.1.1.1 and tcp port 853'
Плюс Mihomo-дашборд (Connections): куда Mihomo отправил 1.1.1.1:853. Самое сильное
доказательство — tcpdump на VPS, через который выходит выбранный proxy:
host 1.1.1.1 and tcp port 853 на выходе VPS закрывает цепочку полностью.
- Различить «попал в Mihomo» и «вышел через proxy». Попадание DNS в Mihomo ещё не
означает выход через туннель: если правила Mihomo выбирают
DIRECTдля1.1.1.1, DNS уйдёт через провайдера, хотя ProxyN сработал. Правила матчатся сверху вниз; для эксперимента можно временно закрепить адрес за реальной proxy-группой:
rules:
- IP-CIDR,1.1.1.1/32,ИМЯ_PROXY_ГРУППЫ,no-resolve
(имя группы — из фактического config.yaml; правка — временная, с откатом).
- Удалить тестовую запись штатной командой:
ndmc -c 'no dns-proxy tls upstream 1.1.1.1 853'
ndmc -c 'show dns-proxy'
- Не выполнять
system configuration saveдо успешного завершения проверки; после удаления тестовой записи running-config возвращается к исходному состоянию перезагрузкой или сохранением без тестовых записей — по выбору оператора.
Если on Proxy0 принимается, но DoT фактически не идёт через Proxy — резервный путь:
/32-маршрут ip route 1.1.1.1 Proxy0 auto reject (fail-closed). Только после
проверки правила Mihomo из шага 6: при DIRECT для этого адреса маршрут зациклится
(1.1.1.1 → Proxy0 → Mihomo → DIRECT → маршрут Proxy0 → …).
Типичные проблемы¶
«DNS работает», но уходит через провайдера¶
Резолв успешен, tcpdump на WAN видит 1.1.1.1:853 напрямую. Причина: правила Mihomo
выбрали DIRECT (шаг 6). Лечение — закрепить адрес за proxy-группой.
Петля при /32-маршруте¶
ip route … auto reject + DIRECT для того же адреса в Mihomo = цикл. Всегда сначала
правило Mihomo, потом маршрут.
Chicken-and-egg у proxy-bound DNS Mihomo¶
Upstream вида https://8.8.8.8/dns-query#PROXY требует, чтобы домен proxy-ноды
резолвился без прокси — для этого существуют proxy-server-nameserver и
default-nameserver (документированное предупреждение Mihomo).
ISP DNS всё ещё опрашивается параллельно¶
Keenetic обращается к нескольким настроенным DNS (до 8 upstream, приоритет по времени
отклика; статические/динамические name-server описаны в справочнике ip name-server).
«Ни одного DNS через провайдера» — отдельная задача: удаление/игнорирование ISP DNS и
fail-closed политика поверх доказанной схемы, не часть первого эксперимента.
Rollback / recovery¶
Все команды теста обратимы штатными no-формами без сохранения конфигурации:
ndmc -c 'no dns-proxy tls upstream 1.1.1.1 853' # удалить DoT upstream
ndmc -c 'no ip name-server <IP> [domain]' # удалить классический NS (если использовался)
ndmc -c 'no ip route 1.1.1.1 Proxy0' # удалить тестовый /32-маршрут
ndmc -c 'show dns-proxy' # убедиться, что тестовых записей нет
Эксперимент domain-scoped, не меняет default route и не трогает dns-proxy intercept;
после no-форм и проверки show-командами сохранение конфигурации не требуется.
Что подтверждено, а что нет¶
Confirmed (по официальному справочнику/коде/документации, 2026-09-24):
- синтаксис
dns-proxy tls upstream … [on <interface>] [domain <domain>](с 3.01,domainс 3.08), включая родной пример1.1.1.1 853 sni cloudflare-dns.com on ISP; - синтаксис
dns-proxy https upstream … [on <interface>] [domain <domain>]; - синтаксис
ip name-server <address>[:port] [<domain> [on <interface>]](с 2.00); no-формы удаления всех трёх;dns-proxy intercept enable= перехват транзитного DNS (не выбор upstream-пути);ip route <host> <iface> auto reject— fail-closed маршрут (с 3.08, только сauto);- проектный ProxyN: SOCKS5, upstream
127.0.0.1:7890, порядокprotocol socks5 → socks5-udp → upstream, маркерыmihomo t2sN+ upstream, первый свободный ProxyN (кодkeenetic-auto-setup); - в проекте нет DNS-listener Mihomo (bootstrap-конфиг = только
mixed-port: 7890); - Mihomo:
dns.listenUDP/TCP, redir-host валиден, привязка upstream#PROXY/#RULES,proxy-server-nameserver,default-nameserver, правила сверху вниз,no-resolve; - официальная рекомендация использовать DoT/DoH при работе через Proxy (статья «Proxy client»; тема форума «DNS через прокси-клиент» — поддерживающее свидетельство).
Observed:
- ProxyN как рабочий egress подтверждён практическим кейсом владельца (камеры в
политике с выходом через
t2s0/ProxyN → Mihomo— см. статью о слоях именования); - на форуме Keenetic зафиксирован чужой рабочий тест UDP-DNS через
proxy socks5-udpпосле порядкаprotocol socks5 → socks5-udp(тема «туннелирование UDP через socks5 proxy», проверка черезmyip.opendns.com @resolver1.opendns.com) — стороннее наблюдение, не наш тест.
Research / needs live test (не считать доказанным):
- что DoT/DoH upstream с
on ProxyNфактически маршрутизируется через SOCKS5 на живом роутере (справочник допускает интерфейс, форумы поддерживают, но на нашей KeeneticOS это не проверялось); - фактическая работа
proxy socks5-udpдля классического DNS через ProxyN (UDP/53 в SOCKS5 UDP ASSOCIATE); - вся цепочка целиком, включая «вышел через proxy, а не DIRECT» и подтверждение на выходе VPS;
- варианты DoH (bootstrap имени endpoint),
/32 reject-маршрута и DNS-listener Mihomo; - поведение при недоступности ProxyN (что делает DoT-upstream: ждёт, fallback на другие upstream, молчит) — определить в live-тесте;
- интернет-детали реализации Proxy client (hev-socks5-tunnel и история фикса UDP) — форумные свидетельства, не официальная документация.
Источники и provenance¶
- Официальный CLI-справочник Keenetic (команды
dns-proxy tls/https upstream,ip name-server,ip route,dns-proxy intercept enable; проверено через встроенный справочник 2026-09-24) — источник истины по синтаксису. - Статья «Proxy client» (support.keenetic.com, компонент с OS 3.9, HTTP/HTTPS/SOCKS5, рекомендация DoT/DoH).
- Код:
saymer-alt/keenetic-auto-setup—install.sh(контракт ProxyN, порядок подкоманд, маркеры, bootstrap-конфиг Mihomo),ARCHITECTURE.md(три уровня DNS, 8 upstream, DoT/DoH с OS 3.0). - Mihomo: DNS configuration, Route Rules (проверено 2026-09-24).
- Форум Keenetic (поддерживающие свидетельства): «DNS через прокси-клиент» (тема 19957), «туннелирование UDP через socks5 proxy» (тема 19036), «Настройка Proxy только для определённых сайтов» (тема 17351, /32 через Proxy-интерфейс).
- Raw/provenance:
mihomo-dns.md— research-диалог 2026-09-22, из которого извлечена эта статья; его команды не проверялись как production-процедура.
Связанные материалы¶
- Mihomo на Keenetic: где он в архитектуре маршрутизации — слои и три пути трафика, ProxyN/mitun0.
- Политика, сегмент, SSID и маршрут: не называйте всё WL — где ProxyN/t2sN и политика доступа лежат в общей карте слоёв.
- Режим белых списков: как это устроено и что работает — внешний контекст, в котором вопрос «DNS через Mihomo» возникает.