45个版本
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.1.5 | 2018年2月12日 |
#74 in 网络编程
389次每月下载
130KB
1.5K SLoC
一个快速且安全的DoH (DNS-over-HTTPS) 和 ODoH (无感知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
可用于测试。文件还包括私钥。
acme.sh
可用于使用Let's Encrypt和其他ACME兼容提供商创建和更新TLS证书。如果您使用它创建ECDSA密钥,请参见上述内容以将密钥转换为PKCS#8。
证书路径必须设置为完整的证书链(fullchain.cer
),密钥路径设置为私钥(.key
文件)。
doh-proxy -i /path/to/fullchain.cer -I /path/to/domain.key ...
一旦启动,doh-proxy
将自动重新加载证书,无需重新启动服务器。
如果客户端收到x509: 由未知机构签发的证书
错误,请再次确认证书文件是完整的证书链,而不是其他.cer
文件。
在443端口接受DNSCrypt和DoH连接
DNSCrypt是一种比DoH更快、更轻量级的加密DNS协议。
可以使用Encrypted DNS Server在同一TCP端口上接受DNSCrypt和DoH连接。
当检测到TLS连接时,Encrypted DNS Server将DoH查询转发到Nginx或doh-proxy
,或者直接响应DNSCrypt查询。
它还提供了DNS缓存、服务器端过滤、指标和TCP连接重用,以减轻耗尽攻击。
除非前端是CDN,否则理想的设置是在Encrypted DNS Server
之后使用doh-proxy
。
无意识DoH (ODoH)
无意识DoH与匿名DNSCrypt类似,但用于DoH。它需要中继站,但还需要支持该协议的上游DoH服务器。
此代理支持开箱即用的ODoH终止(非中继)。
然而,临时密钥目前仅存储在内存中。在负载均衡配置中,必须使用粘性会话。
目前可用的ODoH中继仅使用POST
查询。因此,对于常规DoH查询已禁用POST
查询,接受它们是兼容ODoH中继所必需的。
可以通过--allow-odoh-post
命令行开关来实现。
操作建议
- 可以通过SNI检查轻松检测和阻止DoH。作为一种缓解措施,DoH端点应尽可能与现有的、流行的网站共享同一个虚拟主机,而不是使用专用虚拟主机。
- 当使用DoH时,DNS戳记应包括解析器IP地址,以消除对非加密、非认证、易于阻止的解析器的依赖。
- 与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服务器。
依赖项
~15–29MB
~421K SLoC