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
45KB
1K SLoC
一个快速且安全的 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 终止代理(如 hitch 或 relayd),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_path
和proxy_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