24 个版本

0.9.11 2024 年 7 月 3 日
0.9.10 2023 年 7 月 15 日
0.9.9 2023 年 4 月 14 日
0.9.8 2023 年 2 月 19 日
0.2.1 2019 年 12 月 24 日

#1574 in 网络编程

每月 22 次下载
用于 doh-proxy

MIT 许可证

45KB
1K SLoC

DoH server (and ODoH - Oblivious DoH server)

一个快速且安全的 DoH (DNS-over-HTTPS) 和 ODoH (Oblivious DoH) 服务器。

doh-proxy 使用 Rust 编写,自 2018 年 2 月以来已在生产环境中进行过实战测试。它本身不执行 DNS 解析,但可以位于任何 DNS 解析器之前,以便通过 DoH 支持来增强它。

安装

选项 1:Linux 的预编译二进制文件

Linux/x86_64 的预编译 tar 包和 Debian 软件包 可以在此处下载

选项 2:从源代码

这需要安装 rust 编译器。

  • 内置 HTTPS 支持(默认)
cargo install doh-proxy
  • 无内置 HTTPS 支持
cargo install doh-proxy --no-default-features

使用方法

USAGE:
    doh-proxy [FLAGS] [OPTIONS]

FLAGS:
    -O, --allow-odoh-post      Allow POST queries over ODoH even if they have been disabed for DoH
    -K, --disable-keepalive    Disable keepalive
    -P, --disable-post         Disable POST queries
    -h, --help                 Prints help information
    -V, --version              Prints version information

OPTIONS:
    -E, --err-ttl <err_ttl>                          TTL for errors, in seconds [default: 2]
    -H, --hostname <hostname>                        Host name (not IP address) DoH clients will use to connect
    -l, --listen-address <listen_address>            Address to listen to [default: 127.0.0.1:3000]
    -b, --local-bind-address <local_bind_address>    Address to connect from
    -c, --max-clients <max_clients>                  Maximum number of simultaneous clients [default: 512]
    -C, --max-concurrent <max_concurrent>            Maximum number of concurrent requests per client [default: 16]
    -X, --max-ttl <max_ttl>                          Maximum TTL, in seconds [default: 604800]
    -T, --min-ttl <min_ttl>                          Minimum TTL, in seconds [default: 10]
    -p, --path <path>                                URI path [default: /dns-query]
    -g, --public-address <public_address>            External IP address DoH clients will connect to
    -j, --public-port <public_port>                  External port DoH clients will connect to, if not 443
    -u, --server-address <server_address>            Address to connect to [default: 9.9.9.9:53]
    -t, --timeout <timeout>                          Timeout, in seconds [default: 10]
    -I, --tls-cert-key-path <tls_cert_key_path>
            Path to the PEM-encoded secret keys (only required for built-in TLS)

    -i, --tls-cert-path <tls_cert_path>
            Path to the PEM/PKCS#8-encoded certificates (only required for built-in TLS)

示例命令行

doh-proxy -H 'doh.example.com' -u 127.0.0.1:53 -g 233.252.0.5

在这里,doh.example.com 是主机名(应与 TLS 证书中包含的名称匹配),127.0.0.1:53 是 DNS 解析器的地址,而 233.252.0.5 是 DoH 服务器的公网 IP 地址。

HTTP/2 和 HTTP/3 终止

使用 doh-proxy 的推荐方式是使用 TLS 终止代理(如 hitchrelayd),CDN 或具有代理功能的 Web 服务器作为前端。

这样,DoH 服务可以作为虚拟主机暴露,与现有网站共享相同的 IP 地址。

如果 doh-proxy 和 HTTP/2 (/ HTTP/3) 前端运行在同一主机上,使用 HTTP 协议在两者之间进行通信是可行的。

如果两者位于不同的网络中,例如在使用CDN时,只要编译时带有tls功能,doh-proxy就可以处理HTTPS请求。

证书和私钥必须以PEM/PKCS#8格式编码。它们可以存储在同一文件中。

如果您使用的是ECDSA证书,并且ECDSA私钥以-----BEGIN EC PRIVATE KEY-----开头,而不是-----BEGIN PRIVATE KEY-----,则需要将它们转换为PKCS#8。在这个示例中,example.key是原始文件。

openssl pkcs8 -topk8 -nocrypt -in example.key -out example.pkcs8.pem

为了启用内置的HTTPS支持,请添加--tls-cert-path选项以指定证书文件的位置,以及使用--tls-cert-key-path指定私钥文件的位置。

一旦启用HTTPS,将不接受HTTP连接。

一个示例自签名证书localhost.pem([链接](https://github.com/jedisct1/doh-server/raw/master/localhost.pem))可用于测试。该文件还包括私钥。

可以使用acme.sh创建和更新TLS证书,使用Let's Encrypt和其他ACME兼容提供商。如果您使用它来创建ECDSA密钥,请参阅上面的说明以将密钥转换为PKCS#8。

证书路径必须设置为完整的证书链(fullchain.cer),密钥路径设置为私钥文件(.key文件)。

doh-proxy -i /path/to/fullchain.cer -I /path/to/domain.key ...

启动后,doh-proxy将自动重新加载证书;无需重新启动服务器。

如果客户端收到x509: certificate signed by unknown authority错误,请再次确认证书文件是完整的证书链,而不是其他.cer文件。

在443端口上接受DNSCrypt和DoH连接

DNSCrypt是一种替代加密DNS协议,比DoH更快、更轻量。

可以使用Encrypted DNS Server在同一个TCP端口上接受DNSCrypt和DoH连接。

当检测到TLS连接时,加密DNS服务器将DoH查询转发到Nginx或doh-proxy,或者直接对DNSCrypt查询进行响应。

它还提供DNS缓存、服务器端过滤、指标和TCP连接重用,以减轻耗尽攻击。

除非前端是CDN,否则理想的设置是在Encrypted DNS Server后面使用doh-proxy

无意识DoH (ODoH)

无意识DoH类似于匿名化DNSCrypt,但针对DoH。它需要中继,但还需要支持该协议的上游DoH服务器。

此代理支持ODoH终止(不是中继)功能。

然而,临时密钥目前仅存储在内存中。在负载均衡配置中,必须使用粘性会话。

目前可用的ODoH中继仅使用POST查询。因此,为了与ODoH中继兼容,常规DoH查询已禁用POST查询,接受它们是必要的。

可以通过命令行开关--allow-odoh-post实现。

操作建议

  • 可以使用SNI检查轻松检测和阻止DoH。作为缓解措施,DoH端点最好与现有的、流行的网站共享同一个虚拟主机,而不是使用专门的虚拟主机。
  • 当使用DoH时,DNS戳应包括解析器IP地址,以便消除对非加密、非认证、易于阻止的解析器的依赖。
  • 与DNSCrypt不同,DNSCrypt要求用户明确信任DNS服务器的公钥,DoH的安全性依赖于传统的公共证书颁发机构。客户端立即安装额外的根证书(由政府、安全软件、企业网关所需)会使DoH容易受到中间人攻击。为了防止这种情况,DNS戳应包括父证书的哈希值。
  • TLS证书与主机名相关联。但域名会过期、重新分配和频繁更换。如果一个原本用于DoH服务的域名获得了新的、可能是有害的所有者,如果CA相同,客户端仍然配置为使用该服务,仍然会盲目信任它。作为缓解措施,CA应签署一个中间证书(这是唯一出现在戳中的证书),用于签署DoH服务器使用的名称。虽然商业CA提供此功能,但Let's Encrypt目前还没有。
  • 确保前端至少支持HTTP/2和TLS 1.3。
  • 内部DoH服务器仍然需要TLS证书。因此,如果您计划部署内部服务器,您需要设置内部CA,或将自签名证书添加到每个客户端。

使用encrypted-dns-server的示例用法

将以下部分添加到配置文件中

[tls]
upstream_addr = "127.0.0.1:3000"

使用nginx的示例用法

在现有的server中,可以通过这种方式公开/dns-query端点

location /dns-query {
  proxy_pass http://127.0.0.1:3000;
}

此示例假设DoH代理正在本地监听端口3000

可以添加HTTP缓存(请参阅Nginx文档中的proxy_cache_pathproxy_cache指令),但请注意,DoH服务器会迅速创建大量的文件。

DNS戳和证书哈希

使用在线DNS戳计算器计算您的服务器的戳。

将其添加到dnscrypt-proxy[static]部分,并检查一切是否按预期工作。

然后,使用命令行标志-show-certs启动dnscrypt-proxy,以打印您的证书链的哈希值。

以下是一个示例输出

[NOTICE] Advertised cert: [CN=dohtrial.att.net,O=AT&T Services\, Inc.,L=Dallas,ST=Texas,C=US] [f679e8451940f06141854dc94e1eb79fa5e04463c15b88f3b392da793c16c353]
[NOTICE] Advertised cert: [CN=DigiCert Global CA G2,O=DigiCert Inc,C=US] [f61e576877da9650294cccb5f96c75fcb71bda1bbc4646367c4ebeda89d7318f]

第一个打印的证书是服务器的证书。下一行是签署该证书的证书。随着您继续向下,您将越来越接近证书颁发机构。

除非您正在使用中间证书,否则最安全的选项可能是包含最后一个打印的哈希证书到您的DNS戳中。

返回到在线DNS戳计算器,并复制粘贴哈希(在这个例子中:f61e576877da9650294cccb5f96c75fcb71bda1bbc4646367c4ebeda89d7318f)。

如果您正在使用Let's Encrypt,最后一行可能如下所示

Advertised cert: [CN=Let's Encrypt Authority R3,O=Let's Encrypt,C=US] [444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce]

这就是它。您的证书哈希是444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce

Go代码片段也可以根据给定的.der文件计算证书的哈希。

常见的证书哈希

  • Let's Encrypt E1
    • cc1060d39c8329b62b6fbc7d0d6df9309869b981e7e6392d5cd8fa408f4d80e6
  • Let's Encrypt R3
    • 444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce
  • Let's Encrypt R10
    • e644ba6963e335fe765cb9976b12b10eb54294b42477764ccb3a3acca3acb2fc
  • ZeroSSL
    • 9a3a34f727deb9bca51003d9ce9c39f8f27dd9c5242901c2bab1a44e635a0219

客户端

doh-proxy可以作为客户端与dnscrypt-proxy一起使用。

doh-proxy在生产中被用于doh.crypto.sx公共DNS解析器和其他许多场合。

可以在以下位置找到公共DoH服务器的大量列表:[公共加密DNS服务器](https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/public-resolvers.md)。

依赖关系

约12-24MB
约316K SLoC