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

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

目录

目录

简介

详情

请求

DoH

DoT

返回

DoH

DoT

c-ares的使用

打包

解析

简介

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参数上,如:

GET /dns-query?dns=BAABAAABAAAAAAABBGhvbWUFaW5rMTkCY24AAAEAAQAAKQIAAAAAAAAA HTTP/1.1

Host: doh.pub

User-Agent: Boost.Beast/347

Accept: application/dns-message

其中需要注意的是Accept为application/dns-message。

DoT

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

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,签名为

#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释放。

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

解析

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

#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])

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) {

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛马程序员2025

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值