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

目录

简介

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

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

详情

DoH和DoT的请求包编码方式就是基于普通的DNS编码,具体可以参考这一篇博文^[3]^。为了简便,本文使用了c-ares^[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]^)

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 ↩︎

相关推荐
石牌桥网管10 天前
DNS Resolver解析服务器出口IP查询
运维·网络·tcp/ip·dns
火山引擎边缘云12 天前
QCon演讲实录|赵彦奇:HTTPDNS 边缘下沉,性能、成本和稳定性之间的取舍与思考
http·边缘计算·dns
CXDNW12 天前
【网络面试篇】其他面试题——Cookie、Session、DNS、CDN、SSL/TLS、加密概念
网络·笔记·面试·cdn·dns·cookie
桃酥40313 天前
day08|计算机网络重难点之 DNS查询过程、CDN是什么,有什么作用?、Cookie和Session是什么?有什么区别?
计算机网络·cdn·dns·cookie·session
UestcXiye14 天前
《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址
c++·计算机网络·ip·tcp·dns
初晴~1 个月前
【网络原理】数据链路层协议与DNS
网络·c++·python·网络协议·以太网·dns·数据链路层
火山引擎边缘云1 个月前
亮相QCon2024,火山引擎边缘云揭秘云原生操作系统与HTTPDNS技术实践
云原生·边缘计算·dns
fareast_mzh1 个月前
Difference between `systemd-resolved` and `dnsmasq`
运维·dns
CXDNW2 个月前
【网络篇】计算机网络——应用层详述(笔记)
服务器·笔记·计算机网络·http·web·cdn·dns