DoH(DNS on HTTPS)和DoT(DNS on TLS)协议详解

目录

简介

DNS over HTTPS利用HTTP协议的GET命令发出经由JSON等编码的DNS解析请求。较于传统的DNS协议,此处的HTTP协议通信处于具有加密作用的SSL/TLS协议(两者统称作HTTPS)的保护之下。但是,由于HTTPS本身需要经由多次数据来回传递才能完成协议初始化,其域名解析耗时较原DNS协议会显著增加。[[1]](#[1])DNS over TLS(缩写:DoT)是通过传输层安全协议(TLS)来加密并打包域名系统(DNS)的安全协议。[[2]](#[2])本文基于RFC 8484 - DNS Queries over HTTPS (DoH)介绍DoH协议的详情。

此外,本文还基于Boost的Asio、Beast实现了DoH和DoT的解析器ink19/Boost.dns

详情

DoH和DoT的请求包编码方式就是基于普通的DNS编码,具体可以参考这一篇博文[[3]](#[3])。为了简便,本文使用了c-ares[[4]](#[4]),对DNS的请求和回包进行解析。

请求

DoH

DoH的请求基于HTTPS,其将DNS的请求包使用base64编码,放在了dns参数上,如:

http 复制代码
GET /dns-query?dns=BAABAAABAAAAAAABBGhvbWUFaW5rMTkCY24AAAEAAQAAKQIAAAAAAAAA HTTP/1.1
Host: doh.pub
User-Agent: Boost.Beast/347
Accept: application/dns-message

其中需要注意的是Acceptapplication/dns-message

DoT

DoT是直接数据流传输,因此不需要使用base64编码,但是为了方便读写,需要在请求包前增加两个字节的请求长度。如:

c++ 复制代码
std::vector<boost::asio::const_buffer> req_buff;
uint16_t send_len = req.size();
send_len = htons(send_len);
req_buff.push_back(asio::buffer(&send_len, sizeof(send_len)));
req_buff.push_back(asio::buffer(req.data(), req.size()));

返回

DoH

DoH的回包放在body中,为二进制。直接读取解析即可。

DoT

DoT的回包和请求包类似,使用二进制,并有两个字节为前导长度。

c-ares的使用

打包

打包使用函数ares_create_query,签名为

c++ 复制代码
#include <ares.h>
 
int ares_create_query(const char *name,
                      int dnsclass,
                      int type,
                      unsigned short id,
                      int rd,
                      unsigned char **buf,
                      int *buflen,
                      int max_udp_size);

获取的buf,使用结束后需要使用ares_free_string释放。

dnsclasstype<arpa/nameser.h>中定义;id为16位,用于标记请求id;rd用于标识是否需要递归解析。

解析

解析使用ares_parse_xxxx_reply函数,比如A类型解析的签名为

c++ 复制代码
#include <ares.h>
 
int ares_parse_a_reply(const unsigned char *abuf, int alen,
                       struct hostent **host,
                       struct ares_addrttl *addrttls, int *naddrttls);

其中host需要使用ares_free_hostent进行释放。

使用方法为(注:该函数的使用方法在官方文档中描述的比较模糊,本文是在github中搜索ares_parse_a_reply后,找到了node库使用该函数的方法[[5]](#[5])

c++ 复制代码
struct hostent *hosts;
int ret = ares_parse_a_reply((const unsigned char *)rsp.data(), rsp.size(),
                              &hosts, NULL, NULL);

for (int i = 0; hosts->h_addr_list[i] != NULL; ++i) {
  uint32_t ip = ntohl(*(uint32_t *)hosts->h_addr_list[i]))
}
ares_free_hostent(hosts);

  1. DNS over HTTPS - 维基百科,自由的百科全书 ↩︎

  2. DNS over TLS - 维基百科,自由的百科全书 ↩︎

  3. 自己动手实现DNS协议 - 苍青浪 - 博客园 ↩︎

  4. c-ares documentation | c-ares: a modern asynchronous DNS resolver ↩︎

  5. node/src/node_cares.cc at 496be457b6a2bc5b01ec13644b9c9783976159b2 · kuno/node ↩︎

相关推荐
星马梦缘1 天前
计算机网络期末焚决 2024级
网络·计算机网络·dns·ospf·流量控制·路由算法·拥塞控制
tianyuanwo2 天前
深入解析CentOS 8中NetworkManager重启后DNS配置被覆盖的机制与解决方案
linux·运维·centos·dns
屹奕7 天前
恶意跳转网站问题分析与讨论
dns
岁岁种桃花儿11 天前
Nginx 站点垂直扩容(单机性能升级)全攻略
网络·nginx·dns
原来4516 天前
DNS a、ptr、ns、soa、srv、mx、cname记录
dns·域名解析·a记录·ptr记录
驰羽18 天前
NAT模式下VMware的虚拟机DNS解析失败的问题解决
linux·网络·dns
柯杰1 个月前
DNS劫持防护:从被动监测到主动防御
后端·dns
这儿有一堆花1 个月前
深入解析 DNS:互联网的隐形神经系统
dns
teamlet1 个月前
Gear DNS - 一个go语言开发的小型dns系统
golang·dns·网络服务
程序员老赵1 个月前
AdguardHome Docker 容器化部署指南
docker·dns