DNS 域名解析

V2Ray 内建了一个 DNS 组件,其主要用途为:对目标地址(域名)进行 DNS 解析,同时为 IP 路由规则匹配提供判断依据。

TIP

由于 DNS 协议的复杂性,V2Ray 只支持最基本的 IP 查询(A 和 AAAA 记录)。如需完整的 DNS 功能,推荐使用 CoreDNSopen in new window

WARNING

freedom 协议的 outbound 中,domainStrategy 默认值为 AsIs,即 freedom outbound 默认不会使用本 DNS 组件进行目标地址解析。如需使用,应修改 freedom outbound 中的 domainStrategy 配置为 UseIPUseIPv4UseIPv6

支持的 DNS 协议及其路由策略

  • DNS over UDP:查询请求经过路由组件,可从用户指定 outbound 发出
    • 使用 IP 地址的形式,如 8.8.8.8
    • 默认使用 53 端口进行查询,支持使用非标准端口
  • DNS over TCP:查询请求经过路由组件,可从用户指定 outbound 发出
    • 使用 tcp://host:port 的形式,如 tcp://8.8.8.8:53
    • 默认使用 53 端口进行查询,支持使用非标准端口
  • DNS over TCP local mode:查询请求不经过路由组件,直接从 freedom outbound 发出
    • 使用 tcp+local://host:port 的形式,如 tcp+local://8.8.8.8:53
    • 默认使用 53 端口进行查询,支持使用非标准端口
  • DNS over HTTPS:查询请求经过路由组件,可从用户指定 outbound 发出
    • 使用 https://host:port/dns-query 的形式,如 https://dns.google/dns-queryhttps://1.1.1.1/dns-query
    • 默认使用 443 端口进行查询,支持使用非标准端口和非标准路径,如 https://a.b.c.d:8443/my-dns-query
  • DNS over HTTPS local mode:查询请求不经过路由组件,直接从 freedom outbound 发出
    • 使用 https+local://host:port/dns-query 的形式,如 https+local://223.5.5.5/dns-query
    • 默认使用 443 端口进行查询,支持使用非标准端口和非标准路径,如 https+local://a.b.c.d:8443/my-dns-query
  • DNS over QUIC local mode:查询请求不经过路由组件,直接从 freedom outbound 发出
    • 使用 quic+local://host 的形式,如 quic+local://dns.adguard.com
    • 默认使用 784 端口进行查询,支持使用非标准端口
    • 目前(2021 年 9 月 20 日),公共递归 DNS 服务中支持 DNS over QUIC 协议的有 dns.adguard.comdns.nextdns.io(除 784 端口外,亦支持使用 8853 端口查询)
  • 特殊项:
    • localhost:使用本机预设的 DNS 配置
    • FakeDNS:使用 V2Ray 内建的 FakeDNS 服务器。详情见 FakeDNS 服务器

TIP

当使用 localhost 时,本机的 DNS 请求不受 V2Ray 控制,需要额外的配置才可以使 DNS 请求由 V2Ray 转发。

WARNING

如果在 Linux 设备上使用 DNS over QUIC,可能需要调整接收缓冲区大小,下面的命令将其设置为 2.5 MB

sysctl -w net.core.rmem_max=2500000

Reference: https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Sizeopen in new window

DNS 处理流程

若当前要查询的域名:

  • 命中了 hosts 中的「域名 - IP」、「域名 - IP 数组」映射,则将该 IP 或 IP 数组作为 DNS 解析结果返回。
  • 命中了 hosts 中的「域名 - 域名」映射,则该映射的值(另一个域名)将作为当前要查询的新域名,进入 DNS 处理流程,直到解析出 IP 后返回,或返回空解析。
  • 没有命中 hosts,但命中了某(几)个 DNS 服务器中的 domains 域名列表,则按照命中的规则的优先级,依次使用该规则对应的 DNS 服务器进行查询。若命中的 DNS 服务器查询失败,或 expectIPs 不匹配,则使用下一个命中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有命中的 DNS 服务器均查询失败,此时 DNS 组件:
    • 默认会进行 「DNS 回退(fallback)查询」:使用「上一轮失败查询中未被使用的、且 skipFallback 为默认值 false 的 DNS 服务器」依次查询。若查询失败,或 expectIPs 不匹配,返回空解析;否则返回解析得到的 IP。
    • disableFallback 设置为 true,则不会进行「DNS 回退(fallback)查询」。
  • 既没有命中 hosts,又没有命中 DNS 服务器中的 domains 域名列表,则:
    • 默认使用「skipFallback 为默认值 false 的 DNS 服务器」依次查询。若第一个被选中的 DNS 服务器查询失败,或 expectIPs 不匹配,则使用下一个被选中的 DNS 服务器进行查询;否则返回解析得到的 IP。若所有被选中的 DNS 服务器均查询失败,返回空解析。
    • 若「skipFallback 为默认值 false 的 DNS 服务器」数量为 0 或 disableFallback 设置为 true,则使用 DNS 配置中的第一个 DNS 服务器进行查询。查询失败或不匹配 expectIPs 列表,返回空解析;否则返回解析得到的 IP。

DNS 处理流程示意图如下:

DNS resolution process

DnsObject

DnsObject 对应配置文件的 dns 项。

{
    "nameServer": [{
        "address": {
            "network": "udp",
            "address": "1.1.1.1",
            "port": 53
        },
        "clientIp": "5.6.7.8",
        "skipFallback": true,
        "prioritizedDomain": [{
            "type": "subdomain",
            "domain": "youtube.com"
        }, {
            "type": "Keyword",
            "domain": "google"
        }],
        "expectIPs": [{
            "countryCode": "cn",
            "cidr": [{
                "ipAddr": "119.29.0.0",
                "prefix": 16
            }],
            "inverseMatch": true
        }, {
            "filePath": "geoip.dat",
            "code": "private"
        }]
    }],
    "clientIp": "1.2.3.4",
    "staticHosts": [{
        "type": "full",
        "domain": "cloudflare.com",
        "ip": ["1.1.1.1", "1.0.0.1"]
    }, {
        "type": "full",
        "domain": "cloudflare.com",
        "proxiedDomain": "api.v2fly.org"
    }],
    "queryStrategy": "UseIPv4",
    "disableCache": false,
    "disableFallback": false,
    "disableFallbackIfMatch": true,
    "tag": "dns"
}

nameServer: [ NameServerObject ]

DNS 服务器列表。

clientIp: string

当前网络的 IP 地址。用于 DNS 查询时通知 DNS 服务器,客户端所在的地理位置(不能是私有 IP 地址)。

TIP

此功能需要 DNS 服务器支持 EDNS Client Subnet(RFC7871)。

staticHosts: [ HostMappingObject ]

静态域名映射。

TIP

当地址中同时设置了多个 IP 和域名,则只会返回第一个域名,其余 IP 和域名均被忽略。【TODO】

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

DNS 查询所使用的网络类型。默认值为 UseIP,即 DNS 同时查询域名的 A 和 AAAA 记录。UseIPv4UseIPv6 分别为只查询 A 记录、只查询 AAAA 记录。

TIP

建议没有 IPv6 网络的用户,设置为 UseIPv4。本选项与 freedom 协议 outbound 中的 domainStrategy 选项优先级相同,建议同时设置为 UseIPv4

WARNING

如果本选项设置为 UseIPv4,而 freedom 协议 outbound 中的 domainStrategy 选项设置为 UseIPv6,会导致从 freedom 协议 outbound 发出的连接的 DNS 查询被 Go 运行时接管,进而导致 DNS 泄漏;反之同理。

disableCache: bool

禁用 DNS 缓存。默认为 false,即为不禁用。

disableFallback: bool

禁用 DNS 回退(fallback)查询。默认为 false,即为不禁用。详情见 DNS 处理流程

WARNING

如果本选项设置为 true,则 ServerObject 中的 skipFallback 均不会生效。

disableFallbackIfMatch: bool

禁用在 DNS 服务器的优先匹配域名列表命中时执行 DNS 回退(fallback)查询。

tag: string

由此 DNS 发出的查询流量,除 localhostDOHL_ 模式外,都会带有此标识,可在路由使用 inboundTag 进行匹配。

NameServerObject

{
    "address": {
        "address": "1.1.1.1",
        "port": 53
    },
    "clientIp": "5.6.7.8",
    "skipFallback": true,
    "prioritizedDomain": [{
        "type": "subdomain",
        "domain": "youtube.com"
    }, {
        "type": "keyword",
        "domain": "google"
    }],
    "expectIPs": [{
        "cidr": [{
            "ipAddr": "119.29.0.0",
            "prefix": 16
        }],
        "inverseMatch": true
    }, {
        "filePath": "geoip.dat",
        "code": "private"
    }]
}

address: EndpointObject

DNS 服务器地址。

clientIp: string

当前网络的 IP 地址。用于 DNS 查询时通知 DNS 服务器,客户端所在的地理位置(不能是私有 IP 地址)。此处 clientIp 的优先级高于外层配置的 clientIp,由此可实现「使用不同的 clientIp 从相同的 DNS 服务器获取同一域名在不同地区的解析结果」。

TIP

此功能需要 DNS 服务器支持 EDNS Client Subnet(RFC7871)。

skipFallback: bool

在 DNS 回退(fallback)查询过程中,是否跳过本 DNS。默认为 false,即为不跳过。详情见 DNS 处理流程

TIP

本选项可用于防止 DNS 回退(fallback)查询 AAAAA 记录过程中的 DNS 泄漏。

WARNING

如果 DnsObject 中的 disableFallback 设置为 true,则本选项不会生效。

prioritizedDomain: [ PriorityDomainObject ]

一个域名列表,此列表包含的域名,将优先使用此服务器进行查询。

expectIPs:[ GeoIPObject ]

一个 IP 范围列表。

当配置此项时,V2Ray DNS 会对返回的 IP 进行校验,只返回满足 expectIPs 列表的地址。如果未配置此项,会原样返回 IP 地址。

EndpointObject

{
    "address": "1.1.1.1",
    "port": 53
}

address: string

DNS 服务器地址,如 8.8.8.8tcp+local://8.8.8.8:53https://dns.google/dns-query 等,详情查看支持的 DNS 协议及其路由策略

port: number

DNS 服务器端口,如 53。此项缺省时默认为 53。当使用 DOH、DOHL、DOQL 模式时,该项无效。非标准端口应在 URL 中指定。

PriorityDomainObject

{
    "type": "subdomain",
    "domain": "youtube.com"
}

type: "full" | "subdomain" | "keyword" | "regex"

domain 的匹配类型。

domain: string

type 所对应的 domain 值。以下为 typedomain 的对应关系:

  • full:当此域名完整匹配目标域名时,该规则生效。例如 v2ray.com 匹配 v2ray.com 但不匹配 www.v2ray.com
  • regex:当 domain 所表示的正则表达式匹配目标域名时,该规则生效。例如 \.goo.*\.com$ 匹配 www.google.comfonts.googleapis.com,但不匹配 google.com
  • subdomain (推荐):当此域名是目标域名或其子域名时,该规则生效。例如 v2ray.com 匹配 www.v2ray.comv2ray.com,但不匹配 xv2ray.com
  • keyword:当此字符串匹配目标域名中任意部分,该规则生效。比如 sina.com 可以匹配 sina.comsina.com.cnwww.sina.comwww.sina.company,但不匹配 sina.cn

GeoIPObject

{
    "cidr": [{
        "ipAddr": "10.0.0.0",
        "prefix": 8
    }, {
        "ipAddr": "192.168.0.0",
        "prefix": 16
    }],
    "filePath": "geoip.dat",
    "code": "private",
    "inverseMatch": true
}

code: string

从文件中加载 IP 时,所指定的 code。例如从 gepip.dat 中加载时,code 为双字符国家或地区代码open in new window,支持所有可以上网的国家和地区。

filePath: string

从文件中加载 IP 时,所指定的文件路径。默认值为 geoip.dat

cidr: [ CIDRObject ]

CIDRopen in new window:形如 10.0.0.0/8

WARNING

codecidr 同时指定时,从文件中加载的 IP 会覆盖 cidr 的值。

inverseMatch: bool

是否反向匹配。当该值为 true 时,匹配不在指定 IP 范围内的地址。

CIDRObject

{
    "ipAddr": "119.29.0.0",
    "prefix": 16
}

ipAddr: string

IP 地址。

prefix: number

IP 地址前缀匹配的长度,单位为比特。

HostMappingObject

{
    "type": "regex",
    "domain": "cloudflare.com",
    "ip": ["1.1.1.1", "1.0.0.1"],
    "proxiedDomain": "api.v2fly.org"
}

type: "full" | "subdomain" | "keyword" | "regex"

domain 的匹配类型。

domain: string

type 所对应的 domain 值。格式与 PriorityDomainObject 相同。

ip: [ string ]

匹配的域名所映射的 IP 地址列表。

proxiedDomain: string

如指定 proxiedDomain,匹配的域名将直接使用该域名的查询结果,类似于 CNAME。

TIP

如果同时指定了 ipproxiedDomain,将优先生效 proxiedDomain