DNS — sing-box
DNS-движок sing-box — это список типизированных серверов плюс структурированная цепочка правил. Каждый сервер имеет type, выбирающий его транспорт (UDP, TCP, TLS, QUIC, HTTPS, HTTP/3, файл hosts, пул fake-ip, полученный по DHCP, mDNS, systemd-resolved, встроенный Tailscale или резолверы, переданные конечной точкой OpenVPN / OpenConnect). Правила используют тот же набор полей сопоставления, что и правила маршрутизации, но с действиями, специфичными для DNS, — а также могут сопоставляться с ответом.
Параметры верхнего уровня
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
servers | []DNSServerOptions | [] | [DNSServerOptions] | Список DNS-серверов. Каждая запись имеет type (local, hosts, tcp, udp, tls, quic, https, h3, dhcp, mdns, fakeip, tailscale, openconnect, openvpn, resolved) и соответствующий набор параметров. Записи без type (нетипизированный формат address) отклоняются. |
rules | []DNSRule | [] | [DNSRule] | Правила маршрутизации на уровне DNS. Той же формы, что правила маршрутизации, но с набором действий, специфичных для DNS. |
final | string | (unset) | <server tag> | DNS-сервер по умолчанию, когда ни одно правило не совпало. При пустом значении используется первый сервер из servers[]. |
reverse_mapping | bool | false | true | false | Вести обратное отображение (IP → домен), чтобы правила могли сопоставляться с исходным доменом после того, как соединение разрешило назначение в IP. |
Исходный код: option/dns.go:18-24 · зафиксировано на v1.14.2 (af6e64c)
Плюс встроенные DNSClientOptions:
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
strategy | DomainStrategy | (prefer_ipv4) | prefer_ipv4 | prefer_ipv6 | ipv4_only | ipv6_only | Предпочтение семейства адресов по умолчанию. |
timeout | badoption.Duration | 10s | <duration> | Тайм-аут по умолчанию для каждого DNS-запроса. Переопределяется в правиле (timeout действия DNS-правила) и в domain_resolver. |
disable_cache | bool | false | true | false | Отключить кэш ответов в памяти. |
disable_expire | bool | false | true | false | Не вытеснять кэшированные записи по TTL — хранить их бессрочно. |
independent_cache | bool | false | true | false | Устарело: кэш всегда ключуется по серверу, поэтому параметр ни на что не влияет. |
cache_capacity | uint32 | 1024 | <int> | Ёмкость LRU-кэша (записей). Значения меньше 1024 поднимаются до 1024. |
optimistic | *OptimisticDNSOptions | false | true | false | {enabled, timeout} | Оптимистичный кэш: истёкшая запись, ещё находящаяся в пределах timeout (по умолчанию 3d), возвращается сразу, а обновление идёт в фоне. Конфликтует с disable_cache и disable_expire. |
client_subnet | *badoption.Prefixable | (unset) | <CIDR> | ECS (EDNS Client Subnet), объявляемый в исходящих запросах. |
Исходный код: option/dns.go:62-71 · зафиксировано на v1.14.2 (af6e64c)
Типы серверов
Каждая запись в servers[] имеет поле type. Соответствующие поля:
type: "local"
Разрешение через резолвер ОС (удобно на macOS/iOS, где системный резолвер — авторитетный путь). Добавляет prefer_go для перехода на Go-резолвер без CGO. neighbor_domain отвечает на одноуровневые имена LAN из резолвера соседей. На платформах, кроме Apple, сервер local также разрешает *.local. и link-local-зоны обратного просмотра через mDNS (на Apple — через системный резолвер).
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
prefer_go | bool | false | true | false | Использовать net.Resolver из Go (без CGO) вместо нативного резолвера платформы. Полезно на системах, где нативный резолвер сломан или ограничен по частоте запросов. |
neighbor_domain | badoption.Listable[string] | [] | [<.suffix>] | Суффиксы доменов (каждый начинается с .), для которых одноуровневые A/AAAA-запросы обслуживаются резолвером соседей (имена хостов LAN из аренд DHCP), а не апстримом. . совпадает с любым одноуровневым именем, например [".", ".lan"]. |
Исходный код: option/dns.go:188-192 · зафиксировано на v1.14.2 (af6e64c)
type: "udp" и type: "tcp" — RemoteDNSServerOptions
{ "type": "udp", "tag": "local-udp", "server": "8.8.8.8", "server_port": 53 }| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
server | string | (required) | <host> | Имя хоста или IP сервера. |
server_port | uint16 | 53 (udp/tcp), 853 (tls), 443 (https/h3) | <port> | Порт сервера. |
Исходный код: option/dns.go:158-161 · зафиксировано на v1.14.2 (af6e64c)
type: "tls" — DNS-over-TLS
Те же поля, что у udp/tcp, плюс стандартный блок tls:. type: "quic" (DNS-over-QUIC) принимает ровно те же поля.
type: "https" и type: "h3" — DNS-over-HTTPS / -H3
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
path | string | /dns-query | /<path> | Путь конечной точки DoH. |
method | string | POST | POST | GET | HTTP-метод для DoH-запросов. |
headers | badoption.HTTPHeader | {} | {<header>: <value>} | Дополнительные HTTP-заголовки. |
Исходный код: option/dns.go:204-209 · зафиксировано на v1.14.2 (af6e64c)
type: "hosts" — локальный файл hosts
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
path | badoption.Listable[string] | [/etc/hosts] | [<file path>] | Список путей hosts-файлов для объединения. |
predefined | *badjson.TypedMap[string, badoption.Listable[netip.Addr]] | {} | {<domain>: [<IP>]} | Встроенная таблица hosts. Приоритет выше, чем у path. |
Исходный код: option/dns.go:179-182 · зафиксировано на v1.14.2 (af6e64c)
type: "fakeip"
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
inet4_range | *badoption.Prefix | (required for v4) | <CIDR> | IPv4 CIDR, выделяемый под поддельные IP. |
inet6_range | *badoption.Prefix | (required for v6) | <CIDR> | IPv6 CIDR, выделяемый под поддельные IP. |
Исходный код: option/dns.go:211-214 · зафиксировано на v1.14.2 (af6e64c)
type: "dhcp"
| Поле | Тип | По умолчанию | Допустимые значения | Описание |
|---|---|---|---|---|
interface | string | (auto) | <interface> | Интерфейс, чьи полученные по DHCP резолверы используются. |
Исходный код: option/dns.go:216-219 · зафиксировано на v1.14.2 (af6e64c)
Прочие типы
type: "resolved"— читать серверы имён systemd-resolved, привязанные к сетевым интерфейсам (только Linux).type: "tailscale"— использовать резолвер MagicDNS демона Tailscale.type: "mdns"— многоадресные запросы в локальной сети (mDNS), необязательный списокinterface. Рядом с серверомlocalобычно не нужен (он уже направляет*.local.через mDNS); добавляйте, чтобы ссылаться на него изpreferred_by.type: "openvpn"/type: "openconnect"— резолверы, переданные клиентской конечной точкой OpenVPN / OpenConnect (endpoint: "<tag>"), сaccept_default_resolversиaccept_search_domain. Переданные настройки в ОС не устанавливаются.
Типов серверов predefined и rcode нет: фиксированные ответы даёт действие DNS-правила predefined (см. ниже).
Правила DNS
Правила DNS используют ту же полиморфную форму _Rule, что и правила маршрутизации (type: "default" или type: "logical"), с 54 ключами сопоставления RawDefaultDNSRule — в том числе query_client_subnet, query_dnssec, package_name_regex, source_mac_address, source_hostname, preferred_by (совпадение с именами, которые перечисленные серверы считают своими: записи hosts, имена mDNS, split-DNS и домены поиска от Tailscale / VPN) и поля сопоставления ответа ниже. Различия — на уровне действий:
| DNS-действие | Значение |
|---|---|
route (по умолчанию) | Отправить запрос в server: "<tag>". Необязательно: disable_cache, disable_optimistic_cache, rewrite_ttl, timeout, client_subnet / remove_client_subnet, speculative; strategy устарел. |
route-options | Применить параметры DNS-маршрута (те же необязательные поля) к последующим совпадениям правил. |
evaluate | Запросить server и сохранить ответ (при желании под tag), чтобы последующие правила сопоставлялись с ним через match_response; не завершает вычисление правил. Только в правилах верхнего уровня. |
respond | Вернуть ответ, сохранённый предшествующим evaluate, без нового запроса. |
reject | Отклонить запрос. method: "default" отвечает REFUSED; method: "drop" не отвечает. |
predefined | Вернуть жёстко заданный ответ (rcode, answer, ns, extra). |
race: true (на правилах route / respond / reject / predefined, использующих match_response) позволяет судить зависящие от ответа правила параллельно — побеждает первое совпавшее, остальные запросы отменяются.
Сопоставление с ответом
Правила могут сопоставляться с ответом, а не только с запросом. Правило evaluate получает ответ; последующее правило с match_response: true (или tag того правила evaluate) сопоставляет его через ip_cidr / ip_is_private / ip_accept_any, IP-набор правил или поля ответа response_rcode, response_answer, response_ns, response_extra. Использование ip_cidr / ip_is_private без match_response (устаревший фильтр адресов), параметр действия strategy и rule_set_ip_cidr_accept_empty объявлены устаревшими и запланированы к удалению. Миграция для разделения по GeoIP:
{
"dns": {
"rules": [
{ "action": "evaluate", "server": "remote" },
{ "match_response": true, "rule_set": "geoip-cn",
"action": "route", "server": "local" },
{ "action": "route", "server": "remote" }
]
}
}Примеры
Разделение на два сервера — внутренние домены через локальный DoH, всё остальное через DoH Cloudflare:
{
"dns": {
"servers": [
{ "type": "https", "tag": "local",
"server": "doh.pub", "path": "/dns-query" },
{ "type": "https", "tag": "remote",
"server": "cloudflare-dns.com", "path": "/dns-query",
"detour": "proxy" },
{ "type": "fakeip", "tag": "fakeip",
"inet4_range": "198.18.0.0/15",
"inet6_range": "fc00::/18" }
],
"rules": [
{ "rule_set": ["geosite-cn"], "server": "local" }
],
"final": "remote",
"strategy": "prefer_ipv4"
}
}Блокировка рекламы через DNS:
{
"dns": {
"servers": [
{ "type": "https", "tag": "main",
"server": "cloudflare-dns.com" }
],
"rules": [
{
"domain_keyword": ["ads", "doubleclick", "googlesyndication"],
"action": "reject",
"method": "default"
}
],
"final": "main"
}
}Примечания
- Блок верхнего уровня
fakeip: {...}и записи серверов безtype(нетипизированный форматaddress: "tls://…") не поддерживаются — оба приводят к ошибке при запуске. Используйте типизированные записи (type: "fakeip",type: "tls"и т. д.). reverse_mapping: trueпозволяет последующим правилам маршрутизации сопоставляться с доменным именем даже после того, как сниффинг разрешил его в IP. Необходимо при использовании fake-ip вместе со сложными доменными правилами.independent_cacheни на что не влияет: кэш всегда ключуется по тегу сервера (и client subnet), так что split-horizon-серверы никогда не делят ответы. Параметр устарел — удалите его.ip_versionиquery_typeприменяются и к внутренним разрешениям, не нацеленным на конкретный сервер (например, действие маршрутизацииresolveбезserver). Сочетание их с устаревшими полями фильтра адресов в одной DNS-конфигурации отклоняется при запуске.- Устаревший элемент DNS-правила
outboundещё разбирается, но его следует заменить наroute.default_domain_resolverилиdomain_resolverисходящего. - Правила DNS и правила маршрутизации разделяют один и тот же словарь ключей сопоставления, но работают в разное время: правила DNS выполняются на запросе к резолверу; правила маршрутизации — на итоговом соединении.
type: "resolved"читает данные через D-Bus APIsystemd-resolved— работает только на Linux-системах, где resolved действительно является запущенным резолвером.
Сравнение с другими ядрами
- Xray-core использует плоский блок
dns:, гдеservers[]содержит URL-строки (или объекты NameServerConfig) — поляtypeнет, транспорт определяется схемой URL. См. DNS — Xray-core. - mihomo имеет блок
dns:из 25 полей с отдельными спискамиnameserver/fallbackи отображениемnameserver-policy. См. DNS — mihomo.
Исходный код: option/dns.go:18-224 · v1.14.2 (af6e64c)
