From b5e43d75eaabf7826b6b9018cb01e7e8493a662d Mon Sep 17 00:00:00 2001 From: Fangliding Date: Thu, 5 Feb 2026 05:26:45 +0800 Subject: [PATCH] DNS: Refine DNS Host behavior --- docs/config/dns.md | 13 +++++++------ docs/en/config/dns.md | 13 +++++++------ docs/ru/config/dns.md | 13 +++++++------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/docs/config/dns.md b/docs/config/dns.md index 99aed6cf..a6fff068 100644 --- a/docs/config/dns.md +++ b/docs/config/dns.md @@ -90,13 +90,14 @@ DNS 服务器默认进入路由系统进行匹配,除非其包含 `+local` 在 > `hosts`: map{string: address} | map{string: [address]} -静态 IP 列表,其值为一系列的 "域名": "地址" 或 "域名": ["地址 1","地址 2"]。其中地址可以是 IP 或者域名。在解析域名时,如果域名匹配这个列表中的某一项: +静态 IP 列表,其值为一系列的 "域名": "地址" 或 "域名": ["地址 1","地址 2"]。其中地址可以是 IP 或者域名。在解析域名时,核心将检查全部映射条目并返回全部匹配成功的 IP 地址。如果未命中,则进入 DNS 查询阶段。 -- 当该项的地址为 IP 时,则解析结果为该项的 IP. -- 当该项的地址为域名时,将在 hosts 列表中使用此域名重复进行递归匹配,深度最高为 5,如果最后没有查出 IP,则这个域名会被交由后续的 DNS 服务器进行解析。 -- 当地址中同时设置了多个 IP 和域名,则只会返回第一个域名,其余 IP 和域名均被忽略。 -- 当地址中的第一个值为井号后加数字(如 `#3`)时,如果在使用 DNS 出站,核心会返回空的响应以及该数字编号对应的 rcode 以拒绝请求,如果请求来自内部查询则会单纯视为失败。 -- 当被解析域名匹配列表中多个域名时,所有关联的 IP 都会被返回。 +映射的目标可以是域名,当核心完成匹配,并且其中包含域名时行为会略有不同: + +- 其中同时包含 IP 和域名时,删去其中的域名,只返回 IP 地址。 +- 其中包含数个域名,存在歧义,查询失败,视为未命中,进入 DNS 查询阶段。 +- 其中有且仅有一个域名时,这个域名将重新进入 Hosts 模块递归解析,重复上面的步骤,最大递归深度为 5。 +- 上一条递归查询未查询到 IP,并且最终查询结果有且仅有一个域名,该域名替代原始请求域名,进入 DNS 查询阶段。 其匹配格式(`domian:` `full:` 等等)同常用的 [路由系统](./routing.md#ruleobject) 中的 domain. 不同的是无前缀时此处默认使用 `full:` 前缀(类似常见的 hosts 文件写法) diff --git a/docs/en/config/dns.md b/docs/en/config/dns.md index 4e72e259..8aba1383 100644 --- a/docs/en/config/dns.md +++ b/docs/en/config/dns.md @@ -90,13 +90,14 @@ When executing a DNS query, the core will query the servers in the Final Server > `hosts`: map{string: address} | map{string: [address]} -A list of static IPs. The value is a series of `"domain": "address"` or `"domain": ["address 1", "address 2"]`. The address can be an IP or a domain. When resolving a domain, if the domain matches an item in this list: +A static IP mapping. The value consists of entries in the form `"domain": "address"` or `"domain": ["address 1", "address 2"]`. Each address may be an IP or a domain name. When resolving a domain, the core will check all mapping entries and return all matched IP addresses. If nothing matches, the DNS query phase is entered. -- If the address of the item is an IP, the resolution result is that IP. -- If the address of the item is a domain, this domain is used to recursively match within the hosts list (max depth 5). If no IP is found ultimately, the domain is handed over to subsequent DNS servers for resolution. -- If multiple IPs and domains are set in the address list simultaneously, only the first domain is returned, and the remaining IPs and domains are ignored. -- If the first value in the address starts with a hash followed by a number (e.g., `#3`), and it is used in a DNS outbound, the core will return an empty response with the corresponding rcode number to reject the request. If the request comes from an internal query, it will simply be treated as a failure. -- When the resolved domain matches multiple domains in the list, all associated IPs are returned. +The mapping target may be a domain name. When the core finishes matching and the mapping contains domain name(s), the behavior is slightly different: + +- If the mapping contains both IP addresses and domain names, the domain names are removed and only the IP addresses are returned. +- If the mapping contains several domain names, the result is ambiguous: the match fails, is treated as a miss, and the DNS query phase is entered. +- If the mapping contains exactly one domain name, that domain will be fed back into the Hosts module for recursive resolution, repeating the above steps with a maximum recursion depth of 5. +- If the above recursive resolution yields no IPs, and the final resolution result contains exactly one domain name, that domain replaces the original requested domain and is sent to the DNS query phase. The matching format (`domain:`, `full:`, etc.) is the same as the domain in the commonly used [Routing System](./routing.md#ruleobject). The difference is that without a prefix, it defaults to using the `full:` prefix (similar to the common hosts file syntax). diff --git a/docs/ru/config/dns.md b/docs/ru/config/dns.md index 0198a969..b5c4b354 100644 --- a/docs/ru/config/dns.md +++ b/docs/ru/config/dns.md @@ -87,13 +87,14 @@ DNS-запросы, отправляемые встроенным DNS-серве > `hosts`: map{string: address} | map{string: [address]} -Список статических IP. Значениями являются пары "домен": "адрес" или "домен": ["адрес 1","адрес 2"]. Адрес может быть IP или доменом. При резолвинге, если домен совпадает с записью в этом списке: +Статический список сопоставлений. Значения представляют собой записи в форме "домен": "адрес" или "домен": ["адрес 1", "адрес 2"]. Адреса могут быть IP или доменными именами. При разрешении домена ядро проверяет все записи сопоставления и возвращает все совпавшие IP-адреса. Если совпадений не найдено, переходит к этапу DNS-запроса. -- Если адрес является IP, результатом будет этот IP. -- Если адрес является доменом, для получения IP будет использоваться этот новый домен, а не исходный. -- Если в адресе указано несколько IP и доменов, будет возвращен только первый домен, остальные IP и домены игнорируются. -- Если первое значение адреса начинается с решетки и цифры (например, `#3`), при использовании DNS Outbound ядро вернет пустой ответ и соответствующий `rcode` (код отказа), чтобы отклонить запрос. Если запрос пришел из внутреннего источника, он будет считаться неудачным. -- Если запрашиваемый домен совпадает с несколькими доменами в списке, возвращаются все связанные IP. +Целевое значение маппинга может быть доменом. Когда ядро завершает сопоставление и маппинг содержит доменное имя(а), поведение меняется следующим образом: + +- Если маппинг содержит одновременно IP-адреса и доменные имена, доменные имена удаляются, и возвращаются только IP-адреса. +- Если маппинг содержит несколько доменных имен, возникает неоднозначность: сопоставление считается неудачным, рассматривается как пропуск, и выполняется этап DNS-запроса. +- Если маппинг содержит ровно одно доменное имя, это доменное имя повторно передаётся в модуль Hosts для рекурсивного разрешения, повторяя описанные шаги; максимальная глубина рекурсии — 5. +- Если вышеописанная рекурсивная проверка не вернула IP, и итоговый результат содержит ровно одно доменное имя, это доменное имя заменяет исходный запрошенный домен и отправляется на этап DNS-запроса. Формат сопоставления (`domain:`, `full:` и т.д.) аналогичен `domain` в системе [маршрутизации](./routing.md#ruleobject). Отличие в том, что без префикса здесь по умолчанию используется `full:` (аналогично стандартному файлу hosts).