DNS outbound: Add rules (matches qtype, domain, then action)

This commit is contained in:
Meow
2026-04-26 01:22:13 +08:00
parent 0f8ded11a1
commit b63b2a3b00
6 changed files with 447 additions and 60 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ Xray 内置的 DNS 模块,主要有三大用途:
- 如 在 `freedom` 出站中,将 `domainStrategy` 设置为 `UseIP`, 由此出站发出的请求, 会先将域名通过内置服务器解析成 IP, 然后进行连接。
- 如 在 `sockopt` 中,将 `domainStrategy` 设置为 `UseIP`, 此出站发起的系统连接,将先由内置服务器解析为 IP, 然后进行连接。
- 透明代理时劫持 DNS 流量;或直接对外暴露 53 端口充当递归 DNS 服务器。
- TUN/透明代理时通过路由和 DNS 出站组合,以劫持 DNS 流量到此模块;或直接对外暴露 53 端口充当递归 DNS 服务器。
::: tip TIP 1
DNS 服务器默认进入路由系统进行匹配,除非其包含 `+local` 在其中使用域名时,注意可能的回环问题,`hosts` 可能有帮助。
+146 -17
View File
@@ -1,27 +1,38 @@
# DNS
DNS 是一个出站协议,主要用于拦截和转发 DNS 查询。
DNS 是一个出站协议,用于接收由 routing 送入的 DNS 查询,并按规则转发或处理。
此出站协议只能接收 DNS 流量(包含基于 UDP 和 TCP 协议的查询),其它类型的流量会导致错误。
此出站只支持传统明文 DNS,即基于 UDP 和 TCP 的查询;DoH、DoT、DoQ 等非传统明文 DNS 不适用于此出站。常见场景是 TUN、透明代理或 `dokodemo-door` 接收到 DNS 流量后,再由 routing 将其分流到此出站。
在处理 DNS 查询时,此出站协议会将 IP 查询(即 A 和 AAAA)转发给内置的 [DNS 服务器](../dns.md)。其它类型的查询流量见下的 `nonIPQuery`。
它可以按规则将查询放行到目标 DNS 服务器、`hijack` 到内置的 [DNS 服务器](../dns.md) 进一步处理、直接丢弃或显式拒绝,也可以改写目标地址、端口和传输协议。
## OutboundConfigurationObject
```json
{
"network": "tcp",
"network": "udp",
"address": "1.1.1.1",
"port": 53,
"userLevel": 0,
"nonIPQuery": "drop",
"blockTypes": []
"rules": [
{
"action": "reject",
"domain": ["domain:example.com"]
},
{
"action": "direct",
"qtype": 65,
"domain": ["geosite:geolocation-!cn"]
}
]
}
```
> `network`: "tcp" | "udp"
上例仅示意各字段写法,完整配置见下方示例。
修改 DNS 流量的传输层协议,可选的值有 `"tcp"` 和 `"udp"`。当不指定时,保持来源的传输方式不变。
> `network`: [ "tcp" | "udp" ]
修改 DNS 流量的传输层协议,可选值为 `"tcp"` 和 `"udp"`。当不指定时,保持来源的传输方式不变。
> `address`: address
@@ -35,20 +46,138 @@ DNS 是一个出站协议,主要用于拦截和转发 DNS 查询。
用户等级,连接会使用这个用户等级对应的 [本地策略](../policy.md#levelpolicyobject)。
userLevel 的值,对应 [policy](../policy.md#policyobject) 中 `level` 的值。如不指定,默认为 0。
`userLevel` 的值,对应 [policy](../policy.md#policyobject) 中 `level` 的值。如不指定,默认为 `0`。
> `nonIPQuery`: string
> `rules`: \[[RuleObject](#ruleobject)\]
控制非 IP 查询(非 A 和 AAAA),`"drop"` 丢弃; `"skip"` 不由内置 DNS 服务器处理,将转发给目标; `"reject"` 返回一个 DNS reject 响应,直接显式拒绝请求,相比 `"drop"` 可以避免应用程序消耗过长时间等待 DNS 响应到超时。
按顺序匹配 DNS 查询规则,并支持按 `qtype` 和 `domain` 进行细粒度控制。
默认值为 `"reject"`。
若未命中任何规则,则使用内置兜底规则:A 和 AAAA 查询会被导入内置 DNS 模块,其它类型会被显式拒绝。
> `blockTypes`: array
## RuleObject
为一个 int 数组,屏蔽数组中的查询类型,如 `"blockTypes": [65,28]` 表示屏蔽 type 65(HTTPS) 和 28(AAAA). 常见用途包括屏蔽 type 65 以阻止浏览器发起 ECH.
```json
{
"action": "hijack",
"qtype": 1,
"domain": ["geosite:cn"]
}
```
由于 `nonIPQuery` 默认 drop 所有非 A 和 AAAA 查询, 所以需要将其设置为 skip 本选项才能进一步发挥作用。当然也可以不修改,单纯用来屏蔽 A 或者 AAAA 来屏蔽 IPv4/IPv6 查询,但非常不推荐那么做,建议在内置 DNS 的 `queryStrategy` 对相关内容进行设置。
规则中的各匹配条件为与关系;省略某个条件时,表示对此条件不作限制。
注意:当只使用 `blockTypes` 屏蔽 A 或 AAAA 时, 如果 `nonIPQuery` 设置为了 `reject` 那么屏蔽方式也会是返回 DNS reject 而不是丢弃。
> `action`: [ "direct" | "hijack" | "drop" | "reject" ]
## DNS 配置实例 <Badge text="WIP" type="warning"/>
定义规则命中后的动作。
- `direct`: 直接放行到目标 DNS 服务器;若同时配置了出站级别的 `network`、`address` 或 `port`,则按改写后的目标继续转发。
- `hijack`: 将查询导入内置的 [DNS 服务器](../dns.md) 继续处理,可用于按照内置 DNS 的配置进一步分流;目前仅支持 A 和 AAAA 记录。
- `drop`: 直接丢弃请求,不返回响应。
- `reject`: 返回显式拒绝响应,相比 `drop` 可以避免应用长时间等待 DNS 超时。
> `qtype`: number | string
匹配 DNS 查询类型,有三种形式:
- `"a-b"`:`a` 和 `b` 均为整数。这个范围是一个前后闭合区间,当查询类型落在此范围内时,此规则生效。
- `a`:`a` 为整数。当查询类型为 `a` 时,此规则生效。
- 以上两种形式的混合,以逗号 `,` 分隔。形如:`"1,3,23-24"`。
常见类型编号可参考 [DNS 记录类型列表](https://zh.wikipedia.org/zh-cn/DNS%E8%AE%B0%E5%BD%95%E7%B1%BB%E5%9E%8B%E5%88%97%E8%A1%A8)。
省略时表示匹配所有查询类型。
> `domain`: [string]
匹配域名列表,写法与 [路由规则中的 `domain`](../routing.md#ruleobject) 一致,例如 `domain:example.com`、`full:example.com`、`geosite:cn`。省略时表示不限制域名。
## DNS 配置实例
下面的示例演示一个实际场景:透明代理环境中,入站开启 `sniffing` 做域名 / SNI 分流,国外域名走代理,其余 IP 流量直连;同时通过 `dns-out` 拒绝国外域名的 HTTPS 记录,以减少客户端获取 ECH 配置后影响明文 SNI 分流的情况,并将常见的 MX、TXT、SRV 等查询转发到指定上游;代理服务器没有 IPv6 环境因此还需要屏蔽 AAAA 查询。
```json
{
"inbounds": [
{
"tag": "all-in",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"routeOnly": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"dns": {
"servers": ["https+local://1.1.1.1/dns-query"]
},
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "proxy",
"protocol": "vless",
"settings": {
// 忽略...
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"network": "tcp",
"address": "1.1.1.1",
"port": 53,
"rules": [
{
"action": "reject",
"qtype": "28,65",
"domain": ["geosite:geolocation-!cn"]
},
{
"action": "direct",
"qtype": "15-16,33"
}
]
}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"inboundTag": ["all-in"],
"network": "tcp,udp",
"port": "53",
"outboundTag": "dns-out"
},
{
"domain": ["geosite:geolocation-!cn"],
"outboundTag": "proxy"
}
]
}
}
```
上例的行为如下:
- `all-in` 开启了 `sniffing`,并使用 `routeOnly: true` 让 routing 能基于嗅探出的 HTTP、TLS、QUIC 目标域名进行分流,同时保留原始目标地址。
- 来自 `all-in`、发往 53 端口的 UDP/TCP 明文 DNS 查询,会被 routing 规则分流到 `dns-out`。
- 普通流量中,`geosite:geolocation-!cn` 走 `proxy`,未命中该域名规则的流量自动默认走第一个出站 `direct`。
- `geosite:geolocation-!cn` 中域名的 `qtype` 为 `65` 的 HTTPS 记录会被显式拒绝,可用于配合基于明文 SNI 的分流。
- `geosite:geolocation-!cn` 中域名的 `qtype` 为 `28` 的 AAAA 查询会被显式拒绝,可用于屏蔽国外域名的 IPv6 解析。
- `qtype` 为 `15-16,33` 的查询会被直接放行,并按出站配置转发到 `1.1.1.1:53`,传输方式改为 TCP。
- 其余未命中的查询会进入默认兜底逻辑:A 和 AAAA 查询被导入内置 DNS 模块,其它类型被显式拒绝;内置 DNS 再通过 `https+local://1.1.1.1/dns-query` 向上游发起查询,避免形成回环。
+1 -1
View File
@@ -12,7 +12,7 @@ The built-in DNS module in Xray has three main purposes:
- For example, in a `freedom` outbound, if `domainStrategy` is set to `UseIP`, requests sent from this outbound will first resolve the domain to an IP using the built-in server before connecting.
- For example, in `sockopt`, if `domainStrategy` is set to `UseIP`, system connections initiated by this outbound will first resolve to an IP using the built-in server before connecting.
- **DNS Traffic Hijacking (Transparent Proxy) or Acting as a Recursive DNS Server:** Directly exposing port 53 to serve as a DNS server.
- **TUN/Transparent Proxy DNS Traffic Hijacking:** Combines routing with the DNS outbound to hijack DNS traffic into this module; or directly exposes port 53 to act as a recursive DNS server.
::: tip TIP 1
The DNS server enters the routing system for matching by default unless it contains `+local`. When using domain names within it, be aware of potential routing loops; `hosts` may help.
+149 -20
View File
@@ -1,54 +1,183 @@
# DNS
DNS is an outbound protocol, mainly used to intercept and forward DNS queries.
DNS is an outbound protocol used to receive DNS queries sent in by routing, then forward or process them according to rules.
This outbound protocol can only receive DNS traffic (including queries based on UDP and TCP protocols); other types of traffic will cause errors.
This outbound only supports traditional plaintext DNS queries over UDP and TCP; non-plaintext DNS protocols such as DoH, DoT, and DoQ are not applicable to this outbound. Common scenarios include TUN, transparent proxy, or `dokodemo-door` receiving DNS traffic and then routing sending that traffic to this outbound.
When processing DNS queries, this outbound protocol forwards IP queries (i.e., A and AAAA) to the built-in [DNS server](../dns.md). For other types of query traffic, see `nonIPQuery` below.
It can allow queries to the target DNS server, `hijack` them to the built-in [DNS server](../dns.md) for further processing, drop them, or explicitly refuse them according to rules. It can also rewrite the target address, port, and transport protocol.
## OutboundConfigurationObject
```json
{
"network": "tcp",
"network": "udp",
"address": "1.1.1.1",
"port": 53,
"userLevel": 0,
"nonIPQuery": "drop",
"blockTypes": []
"rules": [
{
"action": "reject",
"domain": ["domain:example.com"]
},
{
"action": "direct",
"qtype": 65,
"domain": ["geosite:geolocation-!cn"]
}
]
}
```
> `network`: "tcp" | "udp"
The example above only demonstrates the field syntax. See the full example below for a complete configuration.
Modifies the transport layer protocol for DNS traffic. Optional values are `"tcp"` and `"udp"`. When unspecified, the source transport method remains unchanged.
> `network`: [ "tcp" | "udp" ]
Modifies the transport protocol used for DNS traffic. Available values are `"tcp"` and `"udp"`. If omitted, the original transport method is preserved.
> `address`: address
Modifies the DNS server address. When unspecified, the address specified in the source remains unchanged.
Modifies the DNS server address. If omitted, the address specified by the source is preserved.
> `port`: number
Modifies the DNS server port. When unspecified, the port specified in the source remains unchanged.
Modifies the DNS server port. If omitted, the port specified by the source is preserved.
> `userLevel`: number
User level. Connections will use the [Local Policy](../policy.md#levelpolicyobject) corresponding to this user level.
User level. Connections will use the [local policy](../policy.md#levelpolicyobject) corresponding to this user level.
The value of `userLevel` corresponds to the value of `level` in [policy](../policy.md#policyobject). If not specified, it defaults to 0.
The value of `userLevel` corresponds to the `level` value in [policy](../policy.md#policyobject). If omitted, it defaults to `0`.
> `nonIPQuery`: string
> `rules`: \[[RuleObject](#ruleobject)\]
Controls non-IP queries (non-A and non-AAAA). `"drop"` means discard; `"skip"` means it is not processed by the built-in DNS server and is forwarded to the destination; `"reject"` returns a DNS reject response, explicitly refusing the request immediately. Compared to `"drop"`, this avoids applications waiting too long for a DNS response until timeout.
Matches DNS query rules in order, and supports fine-grained control by `qtype` and `domain`.
The default value is `"reject"`.
If no rule is matched, the built-in fallback rule is used: A and AAAA queries are imported into the built-in DNS module, while other query types are explicitly refused.
> `blockTypes`: array
## RuleObject
An integer array used to block query types listed in the array. For example, `"blockTypes": [65,28]` means blocking type 65 (HTTPS) and 28 (AAAA). Common uses include blocking type 65 to prevent browsers from initiating ECH.
```json
{
"action": "hijack",
"qtype": 1,
"domain": ["geosite:cn"]
}
```
Since `nonIPQuery` drops all non-A and non-AAAA queries by default, this option requires `nonIPQuery` to be set to `skip` to take further effect on other types. Of course, you can also use it solely to block A or AAAA (IPv4/IPv6 queries), but this is highly discouraged. It is recommended to configure `queryStrategy` in the built-in DNS settings for relevant content instead.
All matching conditions in a rule are combined with AND logic. If a condition is omitted, that condition is not restricted.
Note: When using `blockTypes` to block only A or AAAA, if `nonIPQuery` is set to `reject`, the blocking method will also be to return a DNS reject response instead of dropping.
> `action`: [ "direct" | "hijack" | "drop" | "reject" ]
## DNS Configuration Examples <Badge text="WIP" type="warning"/>
Defines the action to take when the rule matches.
- `direct`: Allows the query directly to the target DNS server. If outbound-level `network`, `address`, or `port` is also configured, the query is forwarded to the rewritten target.
- `hijack`: Imports the query into the built-in [DNS server](../dns.md) for further processing. This can be used for additional routing based on the built-in DNS configuration. Currently, only A and AAAA records are supported.
- `drop`: Drops the request directly without returning a response.
- `reject`: Returns an explicit refusal response. Compared with `drop`, this can prevent applications from waiting too long for a DNS timeout.
> `qtype`: number | string
Matches DNS query types. It has three forms:
- `"a-b"`: `a` and `b` are both integers. This is a closed interval; the rule takes effect when the query type falls within this range.
- `a`: `a` is an integer. The rule takes effect when the query type is `a`.
- A comma-separated mix of the two forms above. For example: `"1,3,23-24"`.
Common type numbers can be found in the [List of DNS record types](https://en.wikipedia.org/wiki/List_of_DNS_record_types).
If omitted, all query types are matched.
> `domain`: [string]
Matches a list of domains. The syntax is the same as [`domain` in routing rules](../routing.md#ruleobject), such as `domain:example.com`, `full:example.com`, and `geosite:cn`. If omitted, domains are not restricted.
## DNS Configuration Example
The following example demonstrates a practical scenario: in a transparent proxy environment, the inbound enables `sniffing` for domain / SNI routing, foreign domains go through the proxy, and other IP traffic goes directly. At the same time, `dns-out` refuses HTTPS records for foreign domains to reduce cases where clients obtain ECH configuration and affect plaintext SNI routing, forwards common MX, TXT, SRV, and similar queries to a specified upstream, and refuses AAAA queries because the proxy server has no IPv6 environment.
```json
{
"inbounds": [
{
"tag": "all-in",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"routeOnly": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"dns": {
"servers": ["https+local://1.1.1.1/dns-query"]
},
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "proxy",
"protocol": "vless",
"settings": {
// Omitted...
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"network": "tcp",
"address": "1.1.1.1",
"port": 53,
"rules": [
{
"action": "reject",
"qtype": "28,65",
"domain": ["geosite:geolocation-!cn"]
},
{
"action": "direct",
"qtype": "15-16,33"
}
]
}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"inboundTag": ["all-in"],
"network": "tcp,udp",
"port": "53",
"outboundTag": "dns-out"
},
{
"domain": ["geosite:geolocation-!cn"],
"outboundTag": "proxy"
}
]
}
}
```
The example behaves as follows:
- `all-in` enables `sniffing` and uses `routeOnly: true`, allowing routing to split traffic based on sniffed HTTP, TLS, and QUIC target domains while preserving the original target address.
- UDP/TCP plaintext DNS queries from `all-in` to port 53 are routed to `dns-out`.
- For regular traffic, `geosite:geolocation-!cn` goes through `proxy`; traffic that does not match this domain rule automatically uses the first outbound, `direct`.
- HTTPS records with `qtype` `65` for domains in `geosite:geolocation-!cn` are explicitly refused, which can help with plaintext SNI-based routing.
- AAAA queries with `qtype` `28` for domains in `geosite:geolocation-!cn` are explicitly refused, which can be used to block IPv6 resolution for foreign domains.
- Queries with `qtype` `15-16,33` are allowed directly and forwarded to `1.1.1.1:53` according to the outbound configuration, using TCP as the transport.
- Queries that do not match any rule enter the built-in fallback logic: A and AAAA queries are imported into the built-in DNS module, while other query types are explicitly refused. The built-in DNS then queries upstream through `https+local://1.1.1.1/dns-query`, avoiding a loop.
+1 -1
View File
@@ -12,7 +12,7 @@
- Например, в `freedom` Outbound, если `domainStrategy` установлен в `UseIP`, запрос, исходящий из этого Outbound, сначала будет разрешен в IP через встроенный сервер, а затем произойдет подключение.
- Например, в `sockopt`, если `domainStrategy` установлен в `UseIP`, системное подключение, инициированное этим Outbound, сначала будет разрешено в IP встроенным сервером.
- Перехват DNS-трафика в режиме Transparent Proxy или работа в качестве рекурсивного DNS-сервера, открытого на порту 53.
- Перехват DNS-трафика в режиме TUN/Transparent Proxy через связку routing и DNS outbound, чтобы направлять DNS-трафик в этот модуль; либо работа в качестве рекурсивного DNS-сервера, открытого на порту 53.
::: tip TIP 1
DNS-запросы, отправляемые встроенным DNS-сервером, автоматически перенаправляются в соответствии с конфигурацией маршрутизации (Routing).
+149 -20
View File
@@ -1,54 +1,183 @@
# DNS
DNS — это исходящий протокол, который в основном используется для перехвата и пересылки DNS-запросов.
DNS — это исходящий протокол, который принимает DNS-запросы, переданные routing, и пересылает или обрабатывает их по правилам.
Этот исходящий протокол может принимать только DNS-трафик (включая запросы по протоколам UDP и TCP), другие типы трафика вызовут ошибку.
Этот outbound поддерживает только традиционный открытый DNS, то есть запросы по UDP и TCP; нестандартные для него варианты, такие как DoH, DoT и DoQ, к этому outbound не применимы. Типичные сценарии: TUN, прозрачный прокси или `dokodemo-door` принимают DNS-трафик, после чего routing направляет его в этот outbound.
При обработке DNS-запросов этот исходящий протокол пересылает запросы IP-адресов (то есть A и AAAA) на встроенный [DNS-сервер](../dns.md). Другие типы запросов см. в разделе `nonIPQuery` ниже.
По правилам он может пропускать запросы к целевому DNS-серверу, выполнять `hijack` во встроенный [DNS-сервер](../dns.md) для дальнейшей обработки, отбрасывать запросы или явно отказывать в них. Также он может изменять целевой адрес, порт и транспортный протокол.
## OutboundConfigurationObject
```json
{
"network": "tcp",
"network": "udp",
"address": "1.1.1.1",
"port": 53,
"userLevel": 0,
"nonIPQuery": "drop",
"blockTypes": []
"rules": [
{
"action": "reject",
"domain": ["domain:example.com"]
},
{
"action": "direct",
"qtype": 65,
"domain": ["geosite:geolocation-!cn"]
}
]
}
```
> `network`: "tcp" | "udp"
Пример выше только демонстрирует синтаксис полей. Полную конфигурацию см. в примере ниже.
Изменяет транспортный протокол DNS-трафика. Допустимые значения: `"tcp"` и `"udp"`. Если не указано, используется исходный транспортный протокол.
> `network`: [ "tcp" | "udp" ]
Изменяет транспортный протокол DNS-трафика. Допустимые значения: `"tcp"` и `"udp"`. Если не указано, исходный транспортный способ сохраняется.
> `address`: address
Изменяет адрес DNS-сервера. Если не указано, используется адрес, указанный в источнике.
Изменяет адрес DNS-сервера. Если не указано, сохраняется адрес, указанный источником.
> `port`: number
Изменяет порт DNS-сервера. Если не указано, используется порт, указанный в источнике.
Изменяет порт DNS-сервера. Если не указано, сохраняется порт, указанный источником.
> `userLevel`: number
Уровень пользователя. Соединение будет использовать [локальную политику](../policy.md#levelpolicyobject), соответствующую этому уровню пользователя.
Уровень пользователя. Соединения будут использовать [локальную политику](../policy.md#levelpolicyobject), соответствующую этому уровню пользователя.
Значение `userLevel` соответствует значению `level` в [policy](../policy.md#policyobject). Если не указано, по умолчанию используется значение `0`.
Значение `userLevel` соответствует значению `level` в [policy](../policy.md#policyobject). Если не указано, по умолчанию используется `0`.
> `nonIPQuery`: string
> `rules`: \[[RuleObject](#ruleobject)\]
Управляет запросами, не относящимися к IP-адресам (не A и AAAA). `"drop"` — отклонять, `"skip"` — не обрабатывать встроенным DNS-сервером, а пересылать на целевой сервер. В отличие от `"drop"`, это позволяет избежать ситуации, когда приложение тратит слишком много времени в ожидании ответа DNS до тайм-аута.
DNS-запросы сопоставляются с правилами по порядку; поддерживается детальное управление по `qtype` и `domain`.
Значение по умолчанию — `"reject"`.
Если ни одно правило не совпало, используется встроенное правило по умолчанию: запросы A и AAAA направляются во встроенный DNS-модуль, а запросы других типов явно отклоняются.
> `blockTypes`: array
## RuleObject
Массив целых чисел (`int`), определяющий типы DNS-запросов, которые необходимо блокировать. Например, `"blockTypes": [65,28]` означает блокировку типа 65 (HTTPS) и 28 (AAAA). Распространенный сценарий использования — блокировка типа 65 для предотвращения инициализации ECH браузерами.
```json
{
"action": "hijack",
"qtype": 1,
"domain": ["geosite:cn"]
}
```
Поскольку опция `nonIPQuery` по умолчанию отбрасывает (`drop`) все запросы, кроме A и AAAA, необходимо переключить её в режим `skip`, чтобы данная настройка могла вступить в силу (для типов, отличных от A/AAAA). Разумеется, можно не изменять `nonIPQuery` и использовать эту опцию исключительно для блокировки A или AAAA (отключение IPv4/IPv6), однако делать это **крайне не рекомендуется**. Для этих целей лучше использовать настройку `queryStrategy` во встроенном DNS.
Все условия сопоставления внутри правила объединяются логикой AND. Если условие не указано, ограничение по этому условию не применяется.
Внимание: если вы используете `blockTypes` только для блокировки A или AAAA, и при этом `nonIPQuery` установлен в значение `reject`, то блокировка также будет осуществляться путем возврата ответа DNS reject, а не простым отбрасыванием пакета.
> `action`: [ "direct" | "hijack" | "drop" | "reject" ]
## Примеры конфигурации DNS <Badge text="В РАЗРАБОТКЕ" type="warning"/>
Определяет действие при совпадении правила.
- `direct`: напрямую пропускает запрос к целевому DNS-серверу. Если на уровне outbound также настроены `network`, `address` или `port`, запрос пересылается к измененной цели.
- `hijack`: направляет запрос во встроенный [DNS-сервер](../dns.md) для дальнейшей обработки. Это можно использовать для дополнительного разделения трафика через конфигурацию встроенного DNS. В настоящее время поддерживаются только записи A и AAAA.
- `drop`: напрямую отбрасывает запрос и не возвращает ответ.
- `reject`: возвращает явный отказ. По сравнению с `drop`, это может предотвратить слишком долгое ожидание DNS timeout приложениями.
> `qtype`: number | string
Сопоставляет типы DNS-запросов. Есть три формы:
- `"a-b"`: `a` и `b` — целые числа. Это закрытый интервал; правило срабатывает, когда тип запроса попадает в этот диапазон.
- `a`: `a` — целое число. Правило срабатывает, когда тип запроса равен `a`.
- Комбинация двух форм выше через запятую. Например: `"1,3,23-24"`.
Распространенные номера типов можно посмотреть в [List of DNS record types](https://en.wikipedia.org/wiki/List_of_DNS_record_types).
Если не указано, сопоставляются все типы запросов.
> `domain`: [string]
Сопоставляет список доменов. Синтаксис такой же, как у [`domain` в правилах routing](../routing.md#ruleobject), например `domain:example.com`, `full:example.com`, `geosite:cn`. Если не указано, домены не ограничиваются.
## Пример конфигурации DNS
Следующий пример показывает практический сценарий: в прозрачном прокси inbound включает `sniffing` для разделения по домену / SNI, зарубежные домены идут через proxy, а остальной IP-трафик идет напрямую. При этом `dns-out` отклоняет HTTPS-записи для зарубежных доменов, чтобы уменьшить случаи, когда клиент получает ECH-конфигурацию и это влияет на разделение по открытому SNI; распространенные запросы вроде MX, TXT и SRV пересылаются указанному upstream, а запросы AAAA блокируются, потому что у proxy-сервера нет IPv6-среды.
```json
{
"inbounds": [
{
"tag": "all-in",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"],
"routeOnly": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}
],
"dns": {
"servers": ["https+local://1.1.1.1/dns-query"]
},
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "proxy",
"protocol": "vless",
"settings": {
// Опущено...
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"network": "tcp",
"address": "1.1.1.1",
"port": 53,
"rules": [
{
"action": "reject",
"qtype": "28,65",
"domain": ["geosite:geolocation-!cn"]
},
{
"action": "direct",
"qtype": "15-16,33"
}
]
}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"inboundTag": ["all-in"],
"network": "tcp,udp",
"port": "53",
"outboundTag": "dns-out"
},
{
"domain": ["geosite:geolocation-!cn"],
"outboundTag": "proxy"
}
]
}
}
```
Поведение примера:
- `all-in` включает `sniffing` и использует `routeOnly: true`, позволяя routing разделять трафик по определенным целевым доменам HTTP, TLS и QUIC, сохраняя исходный целевой адрес.
- Открытые DNS-запросы UDP/TCP от `all-in` к порту 53 направляются правилом routing в `dns-out`.
- Для обычного трафика `geosite:geolocation-!cn` идет через `proxy`; трафик, который не совпал с этим доменным правилом, автоматически использует первый outbound — `direct`.
- HTTPS-записи с `qtype` `65` для доменов из `geosite:geolocation-!cn` явно отклоняются, что может помочь при разделении по открытому SNI.
- AAAA-запросы с `qtype` `28` для доменов из `geosite:geolocation-!cn` явно отклоняются; это можно использовать для блокировки IPv6-резолвинга зарубежных доменов.
- Запросы с `qtype` `15-16,33` напрямую разрешаются и пересылаются на `1.1.1.1:53` согласно конфигурации outbound, используя TCP в качестве транспорта.
- Запросы, которые не совпали ни с одним правилом, попадают во встроенную fallback-логику: запросы A и AAAA направляются во встроенный DNS-модуль, а другие типы запросов явно отклоняются. Затем встроенный DNS обращается к upstream через `https+local://1.1.1.1/dns-query`, избегая зацикливания.