Skip to content

DNS — Xray-core

Блок dns настраивает внутренний резолвер Xray: список серверов, необязательные статические хосты и набор переключателей кеширования / fallback. DNS-движок также представляет себя внутренним входящим подключением (по умолчанию с тегом dns), поэтому DNS-трафик можно маршрутизировать как любое другое соединение.

Параметры верхнего уровня

ПолеТипПо умолчаниюДопустимые значенияОписание
servers[]*NameServerConfig[][NameServerConfig | <string>]Список резолверов. Каждая запись — либо строка `address` (`8.8.8.8`, `https://dns.google/dns-query`, `tcp+local://`, `fakedns`, …), либо полный объект NameServerConfig.
hosts*HostsWrapper{}{<domain or pattern>: <IP | [IP, …]>}Статические хосты. Ключи поддерживают те же префиксы `full:`, `domain:`, `regexp:`, `keyword:`, `geosite:`, что и правила маршрутизации.
clientIp*Address(unset)<IP>ECS (EDNS Client Subnet), объявляемый в исходящих запросах. Помогает резолверам, знающим о CDN, возвращать географически близкий ответ.
tagstringdns<inbound tag>Внутренний тег входящего подключения DNS-движка. Используется правилами маршрутизации, которым нужно выделить DNS-трафик.
queryStrategystringUseIPUseIP | UseIPv4 | UseIPv6Стратегия запросов по умолчанию, применяемая, когда стратегия для конкретного сервера не задана. `UseIP` запрашивает и A, и AAAA; `UseIPv4`/`UseIPv6` пропускает другое семейство.
disableCacheboolfalsetrue | falseОтключить кеш ответов в памяти. Каждый запрос уходит наружу заново.
serveStaleboolfalsetrue | falseОтдавать просроченные записи кеша, пока в фоне идёт обновление. Улучшает воспринимаемую задержку.
serveExpiredTTLuint320<seconds>Максимум секунд, в течение которых просроченная запись отдаётся при включённом `serveStale`. 0 — без ограничения.
disableFallbackboolfalsetrue | falseНе переходить к последующим серверам, когда первый сервер не вернул пригодный ответ.
disableFallbackIfMatchboolfalsetrue | falseТо же, но только когда у совпавшего сервера есть собственный список `domains` — т. е. серверы, совпавшие по домену, никогда не запускают fallback.
enableParallelQueryboolfalsetrue | falseОпрашивать все подходящие серверы параллельно; побеждает первый корректный ответ.
useSystemHostsboolfalsetrue | falseДополнительно сверяться с `/etc/hosts` ОС (или платформенным эквивалентом), прежде чем идти в сеть.

Исходный код: infra/conf/dns.go:160-173 · зафиксировано на v26.7.28 (5ca6f4b)

servers[] — NameServerConfig

Каждая запись — либо голая строка адреса (разбирается в address), либо развёрнутая объектная форма:

ПолеТипПо умолчаниюДопустимые значенияОписание
address*Address(required)<DNS URL>Адрес резолвера. Голый IP (`8.8.8.8` = UDP/53), `tcp://`, `tls://`, `https://`, `quic://`, `tcp+local://...` (локальный DNS в обход прокси), `localhost` или `fakedns`.
clientIp*Address(inherit)<IP>Переопределение ECS для этого сервера.
portuint1653<port>Порт сервера (только для голых IP-адресов).
skipFallbackboolfalsetrue | falseЕсли true и этот сервер не дал ответа, цепочка fallback *не* пробуется — запрос просто завершается неудачей.
domainsStringList[]<domain pattern>Домены, на которые должен отвечать этот сервер. Синтаксис как у правил маршрутизации. Если список непуст, сервер опрашивается только для этих доменов.
expectedIPsStringList[]<IP / CIDR / geoip:>Принимать ответ этого сервера, только когда разрешённый IP совпадает с одним из этих шаблонов. Используется для отсеивания цензурированных или перехваченных ответов.
expectIPsStringList(alias)(alias of expectedIPs)Псевдоним для совместимости с `expectedIPs`.
queryStrategystring(inherit)UseIP | UseIPv4 | UseIPv6Переопределение стратегии для этого сервера.
tagstring(unset)<string>Тег сервера — на него ссылаются правила маршрутизации, направляющие исходящий трафик резолвера.
timeoutMsuint644000<ms>Тайм-аут одного запроса в миллисекундах.
disableCache*bool(inherit)true | falseПереопределение кеша для этого сервера.
serveStale*bool(inherit)true | falseПереопределение serve-stale для этого сервера.
serveExpiredTTL*uint32(inherit)<seconds>Потолок TTL просроченных записей для этого сервера.
finalQueryboolfalsetrue | falseПометить сервер как финальный fallback — если он ответил, дальнейшее разрешение не выполняется.
unexpectedIPsStringList[]<IP / CIDR / geoip:>Отклонять ответ этого сервера, если разрешённый IP совпал с любым из этих шаблонов. Дополнение к `expectedIPs`.

Исходный код: infra/conf/dns.go:19-35 · зафиксировано на v26.7.28 (5ca6f4b)

hosts

Поле hosts — плоское отображение. Ключи поддерживают те же префиксы, что и правила маршрутизации; значения — одиночный IP либо массив IP.

json
{
  "dns": {
    "hosts": {
      "domain:example.com": "203.0.113.10",
      "domain:internal.corp": ["10.0.0.1", "10.0.0.2"],
      "geosite:cn": "8.8.8.8"
    }
  }
}

Значение "fakedns" вместо IP заставляет Xray выдавать поддельный адрес из пула FakeDNS.

Примеры

Стандартный раздельный резолвер — домены КНР через локальный DoH, всё остальное через Cloudflare DoH:

json
{
  "dns": {
    "servers": [
      {
        "address": "https://doh.pub/dns-query",
        "domains": ["geosite:cn"],
        "expectedIPs": ["geoip:cn"]
      },
      "https://1.1.1.1/dns-query",
      {
        "address": "tcp+local://223.5.5.5",
        "domains": ["geosite:cn"]
      }
    ],
    "hosts": {
      "domain:example.com": "203.0.113.10"
    },
    "queryStrategy": "UseIP",
    "disableFallbackIfMatch": true,
    "enableParallelQuery": false
  }
}

Маршрутизация FakeDNS:

json
{
  "dns": {
    "servers": ["fakedns", "1.1.1.1"]
  },
  "fakeDns": { "ipPool": "198.18.0.0/15", "poolSize": 32768 },
  "inbounds": [{
    "port": 1080,
    "protocol": "socks",
    "sniffing": {
      "enabled": true,
      "destOverride": ["http", "tls", "fakedns"]
    }
  }]
}

Примечания

  • Голая строка 8.8.8.8 в servers[] — сокращение для {"address": "8.8.8.8"}: UnmarshalJSON структуры NameServerConfig (infra/conf/dns.go:36-43) принимает обе формы.
  • address: "localhost" использует резолвер ОС (удобно на платформах со stub-резолвером вроде systemd-resolved).
  • address: "tcp+local://..." выполняет запрос по TCP в обход движка маршрутизации — полезно для bootstrap-резолвера, от которого зависит остальная DNS-настройка.
  • Шаблоны domains: голые строки по умолчанию сопоставляются по суффиксу; префикс full: — точное совпадение, regexp: — регулярное выражение, keyword: — подстрока, geosite: — категория GeoSite.
  • expectedIPs / unexpectedIPs вместе реализуют паттерн «отклоняй отравленные ответы»: задайте expectedIPs: ["geoip:cn"] на домашнем резолвере и unexpectedIPs: ["geoip:cn"] на публичном.
  • clientIpclientIp конкретного сервера) задаёт опцию EDNS Client Subnet. Используйте реалистичное значение (например, один из своих IP), чтобы получать ответы с учётом CDN.
  • finalQuery: true помечает сервер как терминальный — как только он ответил, fallback не выполняется.

Исходящий dns

В отличие от блока dns выше, Xray поставляет исходящее подключение dns ("protocol": "dns"). Направьте DNS-трафик в него — и оно либо перешлёт каждый запрос фиксированному резолверу, либо ответит на него согласно списку правил. Недавние версии Xray добавили поля rewrite для перезаписи адресата и движок rules (старые ручки nonIPQuery / blockTypes теперь считаются устаревшими).

ПолеТипПо умолчаниюДопустимые значенияОписание
rewriteNetworkNetwork(unset)tcp | udp | tcp,udpТранспорт, на который переписываются запросы. Каноническое имя для устаревшего `network`.
rewriteAddress*Address(unset)<host>Резолвер, на который переписываются перехваченные DNS-запросы. Каноническое имя для устаревшего `address`.
rewritePortuint160<port>Порт, на который переписываются запросы. Каноническое имя для устаревшего `port`.
networkNetwork(alias)(alias of rewriteNetwork)Устаревший псевдоним для `rewriteNetwork`.
address*Address(alias)(alias of rewriteAddress)Устаревший псевдоним для `rewriteAddress`.
portuint16(alias)(alias of rewritePort)Устаревший псевдоним для `rewritePort`.
userLeveluint320<uint32>Уровень политики для соединений этого исходящего подключения.
rules[]*DNSOutboundRuleConfig(unset)[DNSOutboundRuleConfig]Правила для каждого запроса, вычисляемые по порядку; первое совпадение решает, как обрабатывается запрос.
nonIPQuery*string(legacy)reject | drop | skipУстаревшая обработка не-IP-запросов. Вытеснена `rules` и не может с ними сочетаться.
blockTypes*[]int32(legacy)[<qType number>]Устаревший список номеров типов DNS-запросов для блокировки. Вытеснен `rules`.

Исходный код: infra/conf/dns_proxy.go:60-71 · зафиксировано на v26.7.28 (5ca6f4b)

rules[]

ПолеТипПо умолчаниюДопустимые значенияОписание
actionstring(required)direct | drop | return | hijackЧто делать с совпавшим запросом. `direct` пересылает как есть; `drop` отбрасывает; `return` отвечает локально кодом `rCode`; `hijack` перенаправляет запрос на сервер из rewrite-полей.
qType*PortList(any)<DNS type number / range>Сопоставление по номерам типов DNS-запросов (1 = A, 28 = AAAA, 65 = HTTPS, …). Принимает списки через запятую и диапазоны.
domain*StringList(any)<domain pattern>Сопоставление по доменам (по умолчанию — подстрока; те же префиксы шаблонов, что и у правил маршрутизации).
rCodeuint3200-65535Код ответа, возвращаемый при `action` равном `return` (например, 5 = REFUSED, 3 = NXDOMAIN).

Исходный код: infra/conf/dns_proxy.go:13-18 · зафиксировано на v26.7.28 (5ca6f4b)

Перехватить A/AAAA на фиксированный резолвер, отбрасывать запросы HTTPS-записей (тип 65) и отказывать во всём остальном:

json
{
  "outbounds": [
    {
      "tag": "dns-out",
      "protocol": "dns",
      "settings": {
        "rewriteAddress": "1.1.1.1",
        "rewritePort": 53,
        "rewriteNetwork": "udp",
        "rules": [
          { "action": "hijack", "qType": "1,28" },
          { "action": "drop",   "qType": "65" },
          { "action": "return", "rCode": 5 }
        ]
      }
    }
  ]
}

nonIPQuery и blockTypes нельзя смешивать с rules — это ошибка при запуске. Мигрируйте устаревшие конфигурации на rules.

Сравнение с другими ядрами

  • sing-box использует полиморфную схему серверов по типу (type: "https", type: "tls", type: "fakeip", …) плюс структурированные DNS-правила с action: "route"|"reject"|"predefined". См. DNS — sing-box.
  • mihomo использует плоский блок dns: с отдельными списками nameserver / fallback и мощным отображением nameserver-policy для маршрутизации по доменам. См. DNS — mihomo.

Исходный код: infra/conf/dns.go:19-173 · v26.7.28 (5ca6f4b)

Core Tutorial от Argsment