Files
XTLS_Xray-docs-next/docs/ru/config/dns.md
T

32 KiB
Raw Blame History

Встроенный DNS-сервер

DNS-сервер

Встроенный модуль DNS в Xray имеет три основных назначения:

  • На этапе маршрутизации: разрешение доменов в IP и сопоставление правил на основе полученных IP для разделения трафика.
    Разрешение домена для маршрутизации зависит от значения routing.domainStrategy. Встроенный DNS-сервер используется для запросов только при следующих значениях:

    • "IPIfNonMatch": если цель запроса задана доменным именем без сопутствующего IP, сначала выполняется проход сопоставления по остальным условиям. Если за этот проход не совпало ни одно правило маршрутизации, домен разрешается через встроенный DNS-сервер, после чего выполняется еще один проход сопоставления правил с использованием полученных IP-адресов.
    • "IPOnDemand": если цель запроса задана доменным именем без сопутствующего IP, при обнаружении правила, основанного на IP, домен сразу разрешается в IP для сопоставления.
  • На этапе исходящего подключения: разрешение целевых доменных имен для подключения или передачи удаленному прокси-серверу:

    • Например, если в исходящем подключении VLESS задать targetStrategy равным UseIP, целевой домен проксируемого запроса сначала разрешается локальным встроенным модулем DNS, затем полученный IP передается удаленному прокси-серверу.
    • Если в исходящем подключении VLESS задать sockopt.domainStrategy равным UseIP, домен сервера VLESS разрешается встроенным модулем DNS, затем устанавливается соединение с полученным IP.
    • Если в исходящем подключении Freedom задать sockopt.domainStrategy равным UseIP, целевой домен запроса разрешается встроенным модулем DNS, затем устанавливается соединение с полученным IP.
    • Протокол WireGuard не допускает передачу доменного имени в качестве цели, поэтому его исходящее подключение может использовать встроенный модуль DNS для разрешения доменов в IP.
  • Перехват DNS-трафика в режиме TUN/прозрачного прокси с помощью маршрутизации и исходящего подключения DNS для направления запросов в этот модуль; либо использование Tunnel для открытия порта 53 и работы в качестве рекурсивного DNS-сервера.

    • Поддерживаются только базовые IP-запросы (записи A и AAAA). Записи CNAME будут запрашиваться повторно до тех пор, пока не будет возвращена запись A/AAAA. Другие типы запросов не попадают во встроенный DNS-сервер, а либо отбрасываются, либо передаются другим серверам в зависимости от вашей конфигурации исходящего подключения.

Процесс обработки DNS

Домен сначала проходит проверку сопоставления Hosts (см. поле hosts). Если нужный IP не найден, для запроса используется DNS-сервер.

Затем ядро начинает строить список серверов, сортируя их в зависимости от запрашиваемого домена по следующим правилам.

  • Построение списка 1: содержит серверы, у которых поле domains успешно совпало с запрашиваемым доменом, в порядке их появления в конфигурационном файле.
  • Проверка disableFallback: если true, построение списка 2 пропускается.
  • Проверка disableFallbackIfMatch: если true и список 1 не пуст, построение списка 2 пропускается.
  • Построение списка 2: содержит серверы, не входящие в список 1, у которых skipFallback не равно true, в порядке их появления в конфигурационном файле.
  • Итоговый список серверов = список 1 + список 2.

Примечание: любой DNS-сервер с FinalQuery, равным true, напрямую усекает последующую часть списка.

При выполнении DNS-запроса ядро последовательно опрашивает серверы из итогового списка, фильтруя результаты с помощью expectedIPs и unexpectedIPs; если результат пуст, переходит к следующему серверу в списке. (При enableParallelQuery, равном true, поведение немного отличается, подробнее см. описание этого поля.)

DnsObject

DnsObject соответствует разделу dns в конфигурационном файле.

{
  "dns": {
    "hosts": {
      "baidu.com": "127.0.0.1",
      "dns.google": ["8.8.8.8", "8.8.4.4"]
    },
    "servers": [
      "8.8.8.8",
      "8.8.4.4",
      {
        "address": "1.2.3.4",
        "port": 5353,
        "domains": ["domain:xray.com"],
        "expectedIPs": ["geoip:cn"],
        "skipFallback": false,
        "clientIP": "1.2.3.4"
      },
      {
        "address": "https://8.8.8.8/dns-query",
        "domains": ["geosite:netflix"],
        "skipFallback": true,
        "queryStrategy": "UseIPv4"
      },
      {
        "address": "https://1.1.1.1/dns-query",
        "domains": ["geosite:openai"],
        "skipFallback": true,
        "queryStrategy": "UseIPv6"
      },
      "localhost"
    ],
    "clientIp": "1.2.3.4",
    "queryStrategy": "UseIP",
    "disableCache": false,
    "serveStale": false,
    "serveExpiredTTL": 0,
    "disableFallback": false,
    "disableFallbackIfMatch": false,
    "enableParallelQuery": false,
    "useSystemHosts": false,
    "tag": "dns_inbound"
  }
}

hosts: map{string: address} | map{string: [address]}

Статический список сопоставлений. Значения представляют собой записи в форме "домен": "адрес" или "домен": ["адрес 1", "адрес 2"]. Адреса могут быть IP или доменными именами. При разрешении домена ядро проверяет все записи сопоставления и возвращает все совпавшие IP-адреса. Если совпадений не найдено, переходит к этапу DNS-запроса.

Целевое значение маппинга может быть доменом. Когда ядро завершает сопоставление и маппинг содержит доменное имя(а), поведение меняется следующим образом:

  • Если маппинг содержит одновременно IP-адреса и доменные имена, доменные имена удаляются, и возвращаются только IP-адреса.
  • Если маппинг содержит несколько доменных имен, возникает неоднозначность: запрос завершается неудачей.
  • Если маппинг содержит ровно одно доменное имя, это доменное имя повторно передаётся в модуль Hosts для рекурсивного разрешения, повторяя описанные шаги; максимальная глубина рекурсии — 5.
  • Если вышеописанная рекурсивная проверка не вернула IP, и итоговый результат содержит ровно одно доменное имя, это доменное имя заменяет исходный запрошенный домен и отправляется на этап DNS-запроса.
  • В частности, если «домен» имеет формат знака решётки и следующего за ним числа (например, #3), любой запрос, совпавший с этой записью, немедленно завершается неудачей. Если запрос поступил от DNS outbound, ядро вернёт пустой ответ и соответствующий этому числу rcode, чтобы отклонить запрос.

Формат сопоставления (domain:, full: и т.д.) аналогичен domain в системе маршрутизации. Отличие в том, что без префикса здесь по умолчанию используется full: (аналогично стандартному файлу hosts).

servers: [string | DnsServerObject ]

Список DNS-серверов. Поддерживаются два типа: адрес DNS (строка) и DnsServerObject.

Если значение "localhost", используется конфигурация DNS локальной системы.

Если значение — адрес DNS "IP:Port", например, "8.8.8.8:53", Xray будет использовать указанный UDP-порт этого адреса для DNS-запроса. Запрос следует правилам маршрутизации. Если порт не указан, по умолчанию используется 53.

Если значение в формате "tcp://host:port", например, "tcp://8.8.8.8:53", Xray будет использовать DNS over TCP. Запрос следует правилам маршрутизации. По умолчанию порт 53.

Если значение в формате "tcp+local://host:port", например, "tcp+local://8.8.8.8:53", Xray будет использовать TCP Local Mode (TCPL). DNS-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound для снижения задержек. По умолчанию порт 53.

Если значение в формате "https://host:port/dns-query", например, "https://dns.google/dns-query", Xray будет использовать DNS over HTTPS (RFC8484, сокращенно DoH). Некоторые провайдеры имеют сертификаты для IP-адресов, поэтому можно указывать IP напрямую, например, https://1.1.1.1/dns-query. Также можно использовать нестандартные порты и пути, например, "https://a.b.c.d:8443/my-dns-query".

Если значение в формате "h2c://host:port/dns-query", например, "h2c://dns.google/dns-query", Xray будет использовать формат запроса DNS over HTTPS, но отправит его в открытом виде (h2c). Это нельзя использовать напрямую; требуется настроить Freedom Outbound + streamSettings с TLS, чтобы обернуть запрос в нормальный DoH. Используется для специальных целей, например, для настройки SNI в DoH-запросе или использования utls отпечатков.

Если значение в формате "https+local://host:port/dns-query", например, "https+local://dns.google/dns-query", Xray будет использовать DoH Local Mode (DOHL). DoH-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound. Обычно подходит для использования на сервере. Поддерживаются нестандартные порты и пути.

Если значение в формате "quic+local://host", например, "quic+local://dns.adguard.com", Xray будет использовать DNS over QUIC Local Mode (DOQL). DNS-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound. Требуется поддержка DNS over QUIC сервером. По умолчанию используется порт 853, можно указать нестандартный.

Если значение fakedns, используется функционал FakeDNS.

::: tip TIP 1 При использовании localhost DNS-запросы системы не контролируются Xray. Требуется дополнительная настройка, чтобы перенаправить системные DNS-запросы в Xray. :::

::: tip TIP 2 DNS-клиенты, инициализированные различными правилами, будут отображаться в логе запуска Xray с уровнем info, например, режимы local DOH, remote DOH и udp. :::

::: tip TIP 3 (v1.4.0+) В логах можно включить журналирование DNS-запросов. :::

::: tip TIP 4 DNS-сервер по умолчанию проходит сопоставление в системе маршрутизации, если только он не содержит +local. При использовании доменных имён внутри него обратите внимание на возможные петли (loop); может помочь hosts. :::

clientIp: string

IP-адрес, используемый в расширении EDNS Client Subnet (ECS).

Должен быть валидным IPv4 или IPv6. При фактической отправке последние биты автоматически стираются: отправляются подсети /24 для IPv4 и /96 для IPv6.

queryStrategy: "UseIP" | "UseIPv4" | "UseIPv6" | "UseSystem"

Ограничивает возможности всех серверов в модуле DNS, а также задает значение по умолчанию для типов IP-запросов, инициированных самим Xray.

Значение по умолчанию UseIP разрешает запросы A + AAAA. Если тип IP не указан в запросе, инициированном самим Xray, у вышестоящего DNS-сервера запрашиваются одновременно A и AAAA записи. UseIPv4 запрашивает и разрешает только A записи; UseIPv6 запрашивает и разрешает только AAAA записи.

UseSystem адаптируется к сетевой среде операционной системы. Перед запросом проверяется наличие шлюзов по умолчанию для IPv4 и IPv6, чтобы ограничить возможности серверов и установить тип запроса. В ОС с графическим интерфейсом проверка выполняется в реальном времени, в среде командной строки — только один раз.

{
  "dns": {
    "servers": [
      "https://1.1.1.1/dns-query",
      {
        "address": "https://8.8.8.8/dns-query",
        "domains": ["geosite:netflix"],
        "skipFallback": true,
        "queryStrategy": "UseIPv4" // Для доменов netflix запрашивать A запись
      },
      {
        "address": "https://1.1.1.1/dns-query",
        "domains": ["geosite:openai"],
        "skipFallback": true,
        "queryStrategy": "UseIPv6" // Для доменов openai запрашивать AAAA запись
      }
    ],
    "queryStrategy": "UseIP" // Глобально запрашивать одновременно A и AAAA записи
  }
}

::: tip TIP 1 Глобальное значение "queryStrategy" имеет приоритет. Если "queryStrategy" во вложенном элементе конфликтует с глобальным "queryStrategy", запрос вложенного элемента вернет пустой ответ. :::

::: tip TIP 2 Если параметр "queryStrategy" во вложенном элементе не указан, используется глобальное значение "queryStrategy". Поведение аналогично версиям Xray-core до v1.8.6. :::

Например:
Глобальный "queryStrategy": "UseIPv6" и вложенный "queryStrategy": "UseIPv4" — конфликт.
Глобальный "queryStrategy": "UseIPv4" и вложенный "queryStrategy": "UseIPv6" — конфликт.
Глобальный "queryStrategy": "UseIP" и вложенный "queryStrategy": "UseIPv6" — не конфликтуют.
Глобальный "queryStrategy": "UseIP" и вложенный "queryStrategy": "UseIPv4" — не конфликтуют.

{
  "dns": {
    "servers": [
      "https://1.1.1.1/dns-query",
      {
        "address": "https://8.8.8.8/dns-query",
        "domains": ["geosite:netflix"],
        "skipFallback": true,
        "queryStrategy": "UseIPv6" // Конфликт: глобальный "UseIPv4" и "UseIPv6" вложенного элемента
      }
    ],
    "queryStrategy": "UseIPv4"
  }
}

Запрос домена Netflix получит пустой ответ из-за конфликта значений "queryStrategy". Домен Netflix будет запрошен через https://1.1.1.1/dns-query и получит запись A.

disableCache: true | false

true отключает кэширование DNS. По умолчанию false (не отключено).

Это не влияет на localhost DNS (системный DNS), который всегда следует поведению кэширования DNS в Golang (cgo и pure go могут немного отличаться).

serveStale: true | false

true включает оптимистичное кэширование DNS (DNS optimistic caching). По умолчанию false (не включено).

Работает только если кэширование включено на сервере (зависит от disableCache).

serveExpiredTTL: number

Срок жизни оптимистичного кэша в секундах. По умолчанию 0 (никогда не истекает).

Если сервер использует кэш и включено оптимистичное кэширование: когда основной кэш истек, но оптимистичный кэш еще действителен, немедленно возвращается устаревшая запись DNS из кэша, а обновление кэша происходит в фоновом режиме. Это снижает Latency.

disableFallback: true | false

true отключает fallback-запросы DNS. По умолчанию false (не отключено).

disableFallbackIfMatch: true | false

true отключает fallback-запросы, если сработал список приоритетных доменов DNS-сервера. По умолчанию false (не отключено).

enableParallelQuery: true | false

true включает параллельные запросы. По умолчанию false (не включено).

Отказоустойчивость (failover) DNS по умолчанию последовательна: запрос к следующему серверу отправляется только после неудачи предыдущего или несовпадения expectedIPs / unexpectedIPs.

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

Динамическая группировка: соседние серверы в списке выбранных считаются одной группой, если их параметры clientIP, skipFallback, queryStrategy, tag, domains, expectedIPs, unexpectedIPs полностью совпадают.

Гонка внутри группы: если любой DNS-сервер в группе успешно выполнил запрос и полученный IP соответствует expectedIPs / unexpectedIPs, группа считается успешной. Результаты остальных серверов группы игнорируются.

Откат между группами: пока первая группа выполняет запрос, система ждет. Если первая группа успешна — возвращается IP. Если все серверы первой группы потерпели неудачу или IP не подошел — происходит откат (fallback) к следующей группе. Если все группы потерпели неудачу, возвращается пустой ответ.

useSystemHosts: true | false

Если true, системный файл hosts добавляется к hosts встроенного DNS.

tag: string

Для трафика запросов, исходящих от встроенного DNS (кроме режимов localhost, fakedns, TCPL, DOHL и DOQL), можно использовать этот тег для сопоставления в маршрутизации через inboundTag.

DnsServerObject

{
  "address": "1.2.3.4",
  "port": 5353,
  "domains": ["domain:xray.com"],
  "expectedIPs": ["geoip:cn"],
  "unexpectedIPs": ["geoip:cloudflare"],
  "skipFallback": false,
  "finalQuery": false,
  "tag": "dns-tag",
  "clientIP": "1.2.3.4",
  "queryStrategy": "UseIPv4",
  "disableCache": false
}

address: address

Список DNS-серверов. Поддерживаются два типа: адрес DNS (строка) и DnsServerObject.

Если значение "localhost", используется конфигурация DNS локальной системы.

Если значение — адрес DNS "IP", например, "8.8.8.8", Xray будет использовать указанный UDP-порт этого адреса для DNS-запроса. Запрос следует правилам маршрутизации. По умолчанию используется порт 53.

Если значение в формате "tcp://host", например, "tcp://8.8.8.8", Xray будет использовать DNS over TCP. Запрос следует правилам маршрутизации. По умолчанию порт 53.

Если значение в формате "tcp+local://host", например, "tcp+local://8.8.8.8", Xray будет использовать TCP Local Mode (TCPL). DNS-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound для снижения задержек. Если порт не указан, по умолчанию используется 53.

Если значение в формате "https://host:port/dns-query", например, "https://dns.google/dns-query", Xray будет использовать DNS over HTTPS (RFC8484, сокращенно DoH). Некоторые провайдеры имеют сертификаты для IP-адресов, поэтому можно указывать IP напрямую, например, https://1.1.1.1/dns-query. Также можно использовать нестандартные порты и пути, например, "https://a.b.c.d:8443/my-dns-query".

Если значение в формате "https+local://host:port/dns-query", например, "https+local://dns.google/dns-query", Xray будет использовать DoH Local Mode (DOHL). DoH-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound для снижения задержек. Обычно подходит для использования на сервере. Поддерживаются нестандартные порты и пути.

Если значение в формате "quic+local://host:port", например, "quic+local://dns.adguard.com", Xray будет использовать DOQ Local Mode (DOQL). DNS-запрос не проходит через компонент маршрутизации, а отправляется напрямую через Freedom outbound. Требуется поддержка DNS over QUIC сервером. По умолчанию используется порт 853, можно указать нестандартный.

Если значение fakedns, используется функционал FakeDNS.

::: tip О режиме local и доменах самих DNS-серверов DNS-запросы, отправляемые модулем DNS, бывают двух типов:

Режим local: соединение устанавливается ядром напрямую во внешнюю сеть. Если адрес является доменом, он будет разрешен самой системой. Логика здесь проста.

В режиме non-local DNS-запросы поступают в систему маршрутизации как внутренние запросы, а их inboundTag задается полем tag в конфигурации DNS. Если запрос направлен в локальное исходящее подключение Freedom, доменное имя самого DNS-сервера разрешается согласно sockopt.domainStrategy этого подключения (возможны петли). Если запрос направлен в исходящее подключение удаленного прокси, домен можно передать удаленной стороне для разрешения.

Поскольку обычным пользователям сложно разобраться в этой логике, рекомендуется (особенно в среде Transparent Proxy) напрямую указывать соответствующие IP для серверов с доменными именами в опции hosts модуля DNS, чтобы предотвратить возникновение петель (loop).

Кстати, DNS-запросы в режиме non-local автоматически пропускают этапы резолвинга IPIfNonMatch и IPOnDemand в модуле маршрутизации, чтобы их резолвинг не был отправлен обратно в модуль DNS, вызывая бесконечный цикл. :::

port: number

Порт DNS-сервера, например 53. Если не указано, по умолчанию 53. Для режимов DOH, DOHL, DOQL этот параметр недействителен; нестандартные порты следует указывать в URL.

domains: [string]

Список доменов. Домены из этого списка будут приоритетно запрашиваться через данный сервер. Формат доменов аналогичен конфигурации маршрутизации.

expectedIPs:[string]

Список диапазонов IP. Формат аналогичен конфигурации маршрутизации.

Если этот параметр настроен, Xray DNS проверит возвращенный IP и вернет его только в том случае, если он входит в список expectedIPs.

Если в списке присутствует *, и после фильтрации IP не найден, будет возвращен исходный IP, чтобы запрос не завершился ошибкой.

unexpectedIPs: [string]

Обратная версия expectedIPs. Исключает IP, входящие в этот список. Звездочка работает так же.

skipFallback: true | false

true — пропускать этот сервер при выполнении DNS fallback запросов. По умолчанию false (не пропускать).

timeoutMs: number

Таймаут DNS-сервера. По умолчанию 4000 мс.

Это не влияет на localhost DNS (системный DNS), который всегда следует поведению таймаута DNS в Golang (cgo и pure go могут немного отличаться).

finalQuery: true | false

Если true, запрос к этому DNS-серверу будет последней попыткой; fallback не будет инициирован.

queryStrategy: "UseIP" | "UseIPv4" | "UseIPv6" | "UseSystem"

Если не указано, наследуется из глобальной конфигурации. Если указано, позволяет дополнительно ограничить возможности этого сервера, а также задать значение по умолчанию для типов IP-запросов, инициированных самим Xray.

Внимание: этот параметр всегда ограничен глобальным queryStrategy.

Следующие параметры, если не указаны, наследуются из глобальной конфигурации, но могут переопределять её здесь

tag: string

clientIP: [string]

disableCache: true | false

serveStale: true | false

serveExpiredTTL: number