Linux下C/C++实现DNS查询(DNS QUERY)

news2025/1/4 15:40:37

DNS 的全称是 Domain Name System 或者 Domain Name Service,它主要的作用就是将人们所熟悉的网址 (域名) “翻译”成电脑可以理解的 IP 地址,这个过程叫做 DNS 域名解析。域名是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识。

DNS 查询到底是怎么完成的?

我们输入域名,浏览器就会在后台,自动向 DNS 服务器发出请求,获取对应的 IP 地址。这就是 DNS 查询。

命令行工具 dig 可以跟 DNS 服务器互动,我们就用它演示 DNS 查询。简单介绍dig,dig(域信息搜索器)是一个用于询问 DNS 域名服务器的灵活的工具。它执行 DNS 搜索,显示从受请求的域名服务器返回的答复。


然后说了查询的目标数例如上述命令只查询了一个网站,所以query就为1,但是有三个answer,所以answer=3.

上面这几行字需要注意question section,这个显示的是你查询了什么,这边显示的是你在查询www.baidu.com的A记录。也是仅仅只有一条查询。

最后显示查询结果及查询时间与DNS服务器。

DNS用的是TCP协议还是UDP协议

DNS占用53号端口,同时使用TCP和UDP协议。那么DNS在什么情况下使用这两种协议?

首先了解一下TCP与UDP传送字节的长度限制:

UDP报文的最大长度为512字节,而TCP则允许报文长度超过512字节。当DNS查询超过512字节时,协议的TC标志出现删除标志,这时则使用TCP发送。通常传统的UDP报文一般不会大于512字节。

DNS在区域传输的时候使用TCP协议,其他时候使用UDP协议。

  • 域名解析 - UDP

客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过TCP三次握手,这样DNS服务器负载更低,响应更快。虽然从理论上说,客户端也可以指定向DNS服务器查询的时候使用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。

  • 区域传输 -TCP

实现这种功能时则有时需要TCP协议,即进行与主域名服务器进行查询以确认数据是否有效,用TCP则是依赖了其可靠性

理论上来说,在客户端与DNS进行通信的过程中,使用两种传输协议在理论上都是可以实行的,但是事实上在目前的浏览器或者说在目前的清醒进行客户端与DNS的通信时一般默认使用UDP,而且某些客户端与DNS进行通信的时候还指定了使用UDP的通信方式,这就和当前HTTP与HTTPS对比下,在民用,安全问题不严峻的前提下,会偏向于使用速度更快的协议。

域名结构


DNS 整个结构图是树状结构,最顶层称为 根域, 用 点 " . " 表示,相应服务器称为根服务器,整个域名空间的解析权都归根服务器所有。

因为负载庞大,所以采用 “ 委派” 机制,根域下设置一级域,将顶级域解析权委派给一级域服务器。同理,顶级域 下面设置 二级域, 二级域 下设 三级域。

根域:

位于域名空间最顶层, 一般用 一个 点 " . " 表示

一级域:

一般代表一种类型的组织机构或者国家地区。如 .net (网络供应商), .com (工商企业) , .org (团体组织), .edu (教育机构) , .gov (政府部门) , .cn (中国国家域名)

二级域:

用来标明顶级域内的一个特定组织,国家顶级域下面的二级域名有国家网络部门统一管理,如 .cn 顶级域名下面设置的二级域名 : .com.cn , .net.cn , .edu.cn

子域:

二级域下所创建的各级域统称为子域,各个组织或用户可以自由申请注册自己的域名

DNS Packet Structure

DNS 分为查询请求和查询响应,请求和响应的报文结构基本相同。DNS 报文格式如图所示。


上图中显示了 DNS 的报文格式。其中,事务 ID、标志、问题计数、回答资源记录数、权威名称服务器计数、附加资源记录数这 6 个字段是DNS的报文首部,共 12 个字节。整个 DNS 格式主要分为 3 部分内容,即基础结构部分(报文首部)、问题部分、资源记录部分。

DNS Headers
DNS数据包具有如下所示的标头。请注意,请求和回复遵循相同的内容标头格式。

标志字段中每个字段的含义如下:

QR(Response):查询请求/响应的标志信息。查询请求时,值为 0;响应时,值为 1。

Opcode:操作码。其中,0 表示标准查询;1 表示反向查询;2 表示服务器状态请求。

AA(Authoritative):授权应答,该字段在响应报文中有效。值为 1 时,表示名称服务器是权威服务器;值为 0 时,表示不是权威服务器。

TC(Truncated):表示是否被截断。值为 1 时,表示响应已超过 512 字节并已被截断,只返回前 512 个字节。

RD(Recursion Desired):期望递归。该字段能在一个查询中设置,并在响应中返回。该标志告诉名称服务器必须处理这个查询,这种方式被称为一个递归查询。如果该位为 0,且被请求的名称服务器没有一个授权回答,它将返回一个能解答该查询的其他名称服务器列表。这种方式被称为迭代查询。

RA(Recursion Available):可用递归。该字段只出现在响应报文中。当值为 1 时,表示服务器支持递归查询。
Z:保留字段,在所有的请求和应答报文中,它的值必须为 0。

rcode(Reply code):返回码字段,表示响应的差错状态。当值为 0 时,表示没有错误;当值为 1 时,表示报文格式错误(Format error),服务器不能理解请求的报文;当值为 2 时,表示域名服务器失败(Server failure),因为服务器的原因导致没办法处理这个请求;当值为 3 时,表示名字错误(Name Error),只有对授权域名解析服务器有意义,指出解析的域名不存在;当值为 4 时,表示查询类型不支持(Not Implemented),即域名服务器不支持查询类型;当值为 5 时,表示拒绝(Refused),一般是服务器由于设置的策略拒绝给出应答,如服务器不希望对某些请求者给出应答
图中的数据包为 DNS 请求包,Domain Name System(query) 部分方框标注中的信息为 DNS 报文中的基础结构部分。

Linux下C/C++实现DNS查询(DNS QUERY)

// query type
enum {
	QTYPE_A = 1,		
	QTYPE_NS = 2,		
	QTYPE_MD = 3,		
	QTYPE_MF = 4,		
	QTYPE_CNAME = 5,	
	QTYPE_SOA = 6,		
	QTYPE_MB = 7,		
	QTYPE_MG = 8,		
	QTYPE_MR = 9,		
	QTYPE_NULL = 10,	
	QTYPE_WKS = 11,		
	QTYPE_PTR = 12,		
	QTYPE_HINFO = 13,	
	QTYPE_MINFO = 14,	
	QTYPE_MX = 15,		
	QTYPE_TXT = 16,		
	QTYPE_AAAA = 28,	
	QTYPE_ANY = 255
};

// options
enum {
	DNS_OPT_TIMEOUT,
	DNS_OPT_RETRY,
	DNS_OPT_IPV4,
	DNS_OPT_IPV6,
	DNS_OPT_PORT,
	DNS_OPT_BUF,
	DNS_OPT_BUFSIZE
};

struct dns_query *dns_init(struct dns_query *dns, int query_type);
int dns_set_option(struct dns_query *dns, int opt, ...);
int dns_add_question(struct dns_query *dns, const char *domain, uint16_t qtype);
int dns_send_query(struct dns_query *dns);
struct dns_packet *dns_response_packet(struct dns_query *dns);
int dns_next_rr(struct dns_rr *rr, struct dns_query *dns);
char *tdns_extract_domain(struct dns_query *query, unsigned char *domain);

.....
int main(int argc, char **argv)
{
...

	dns_init(&dns, QUERY_STANDARD);

	// 超时(毫秒)
	dns_set_option(&dns, DNS_OPT_TIMEOUT, 3000);

	// 超时超过时重试的次数
	dns_set_option(&dns, DNS_OPT_RETRY, 2);

	// DNS服务器ipv4
	dns_set_option(&dns, DNS_OPT_IPV4, "8.8.8.8");

	// 或者可以使用ipv6
	// tinydns_set_option(&dns, DNS_OPT_IPV6, "2001:4860:4860::8888");

	// 响应缓冲区,它应该大于或等于512字节
	dns_set_option(&dns, DNS_OPT_BUF, buf);
	dns_set_option(&dns, DNS_OPT_BUFSIZE, sizeof(buf));
...
	if (dns_add_question(&dns, argv[1], QTYPE_A)) 
	{
		printf("failed to add a question\n");
		goto end;
	}

	if (dns_send_query(&dns)) 
	{
		printf("failed to send dns query...\n");
		goto end;
	}

	response = dns_response_packet(&dns);
	if (response == NULL) 
	{
		printf("response is too short...\n");
		goto end;
	}

	printf("-- header --\n");
	printf("id:                         %u\n", response->id);

	printf("query(0) or response(1):    %u\n", response->qr);
	printf("opcode:                     %u\n", response->opcode);
	printf("authoritative answer:       %u\n", response->aa);
	printf("truncated packet:           %u\n", response->tc);
	printf("recursion desired:          %u\n", response->rd);

	printf("recursion available:        %u\n", response->ra);
	printf("zero:                       %u\n", response->z);
	printf("response code (0 is okay):  %u\n", response->rcode);

	printf("questions:                  %u\n", response->qdcount);
	printf("answers:                    %u\n", response->ancount);
	printf("name servers:               %u\n", response->nscount);
	printf("additional records:         %u\n", response->arcount);
	printf("---\n\n");

	printf("RRs (resource records):\n");

	while (dns_next_rr(&rrbuf, &dns)) 
	{
		char *domain = dns_extract_domain(&dns, rrbuf.name);
		printf("\n\n");
		printf("domain:      %s\n", domain);
		printf("type:        %u\n", rrbuf.type);
		printf("class:       %u\n", rrbuf.class);
		printf("ttl:         %u\n", rrbuf.ttl);
		printf("rdlength:    %u\n", rrbuf.rdlength);

...

		free(domain);
	}
...
}

运行结果:



tcpdump观察:

同时我们保存了dns_query报文

If you need the complete source code, please add the WeChat number (c17865354792)

总结

DNS是一个域名系统,是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。

Welcome to follow WeChat official account【程序猿编码

参考:RFC 1035

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/542086.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux维护安全-PHP安全-php高危函数禁用-php必需禁用的最高危函数总结-必禁

Linux维护安全-PHP安全-php高危函数禁用-php必需禁用的最高危函数总结,优雅草松鼠蜻蜓系统安装必须开启proc_open,putenv,但是希望大家在安装完成后一定要禁用。 必须禁用的高危函数: system,exec,passthru,shell_exec,popen,proc_open,pute…

国考省考行测:数量关系,十字交叉法,增长率反应去年的量,浓度反应的是浓液,平均反应的是人数

国考省考行测:十字交叉法 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能,附带行测和申论,而常规国考省考最重要的还是申论和行测,所以大家认真准备吧,我讲一起屡屡申论和行测的重要知识点 遇…

3网络互联-3.5【实验】【计算机网络】

3网络互联-3.5【实验】【计算机网络】 前言推荐3网络互联3.4 IP分组转发与静态路由3.5 动态路由配置及RIP协议分析实验目的实验内容及实验环境实验原理1. RIP协议2.RIP分组格式3.RIP协议工作原理 实验过程1.搭建一个多跳网络拓扑,配置RIP协议参数2&#…

【ONE·C++ || 哈希(一)】

总言 主要介绍哈希基本框架及其unordered系列容器简述。 文章目录 总言0、思维导图1、unordered系列介绍2、底层:哈希2.1、哈希概念介绍:哈希(散列)函数和哈希表(散列表)2.2、映射关系建立与问题说明:除留余数法、哈希冲突2.3、闭散列及其实…

企业邮箱解析:为何它是企业必备的高效沟通工具?

企业家都知道,一个一致的品牌可以提高它在人们心中的可靠性。这就是为什么大多数企业投资于他们的网络和企业邮箱提供商的原因,可以体现品牌正规性。 企业邮箱为您提供与您的域名匹配的企业电子邮件(nameyourbusiness.com)。它还为您提供: 1、…

【HelloWorld篇】深入学习Spring-Boot

前言 该专栏用来记录一下深入学习SpringBoot,了解SpringBoot如何扩展、如何自定义编写属于自己的start,了解 AOP,IOC,过滤器,拦截器,注解,定时器等实际开发用到的场景以及如何整合第三方&#…

Vivado综合属性系列之六 MAX_FANOUT

目录 一、前言 二、MAX_FANOUT ​ ​2.1 工程代码 ​ ​2.2 工程结果 ​ 一、前言 ​ ​在时序违例的工程中,有一个很常见的原因:高扇出,此时就需要降低信号的扇出,可通过属性MAX_FANOUT来控制信号的扇出值&#xff…

32.Git分布式版本控制

目录 一、Git分布式版本控制。 (1)Git简介。 (2)Git工作流程图。 (3)Git安装。 (4)Git基本配置。 (4.1)用户信息配置(不一定是真实的信息&a…

RK3568平台开发系列讲解(项目篇)手写数字识别

🚀返回专栏总目录 文章目录 一、安装飞桨(PaddlePaddle)二、手写数字识别任务2.1、准备训练集和测试集2.2、模型组网2.3、模型训练与评估2.4、模型保存和导出ONNX模型2.5、完整程序2.6、模拟推理和导出RKNN模型三、板端部署推理3.1、安装RKNN Toolkit Lite2和相关库3.2、推…

从零开始学习JVM(五)-运行时数据区的方法区

1. 方法区基本介绍 官方文档:The Java Virtual Machine Specification 《Java虚拟机规范》中明确说明:“尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。”但对于HotSpotJVM而言&…

手写简易RPC框架

目录 简介 服务提供者 服务注册:注册中心 HttpServerHandler处理远程调用请求 consumer服务消费端 简介 RPC(Remote Procedure Call)——远程过程调用,它是一种通过网络从远程计算机程序上请求服务, 而不需要了解…

我在VScode学Java(Java二维数组)

我的个人博客主页:如果\真能转义1️⃣说1️⃣的博客主页 关于Java基本语法学习---->可以参考我的这篇博客:(我在Vscode学Java) 接上回Java一维数组的介绍(我在VScode学Java(Java一维数组) ) 二维数组是Java中的一…

MySQL:数据库的约束

目录 1.数据库约束 1.1 非空:not null 1.2 唯一:unique ​​​​​​​ 1.3 默认值:default 1.4 列描述:comment 1.5 主键约束:primary key 1.6 外键约束 1.7 综合案例 2.插入查询结果 3.聚合函数 4.group by…

AI心理咨询师:舒缓焦虑,解放压力的秘诀

在如今高压力的生活和工作环境下,焦虑和内耗成为了越来越多人的问题。这一现象对我们的身体和心理都会造成很大的影响。如何治愈我们的焦虑和精神内耗? 1.减少工作压力 - 了解和认可自己的能力和限制,不要让工作压力压垮自己。 - 适当的规…

软件测试工程师的职业发展方向

一、软件测试工程师大致有4个发展方向: 1 资深软件测试工程师 一般情况,软件测试工程师可分为测试工程师、高级测试工程师和资深测试工程师三个等级。 达到这个水平比较困难,这需要了解很多知识,例如C语言,JAVA语言&#xff0c…

浙大数据结构

题目详情:06-图1 列出连通集 给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。 输入格式: 输入第1…

<数据结构>NO5.栈和队列

目录 栈 Ⅰ.栈的概念 Ⅱ.栈的实现 Ⅲ.测试代码 队列 Ⅰ.队列的概念 Ⅱ.队列的实现 💭前言 栈和队列也是一种常见的线性存储的数据结构,只不过它们的某些操作受到了限制,比如栈只允许从栈顶插入删除元素、队列只允许从队尾插入元素&…

[算法] ArrayList 和 LinkedList 的优缺点比较及使用场景

😚一个不甘平凡的普通人,致力于为Golang社区和算法学习做出贡献,期待您的关注和认可,陪您一起学习打卡!!!😘😘😘 🤗专栏:算法学习 &am…

MySQL高级_第12章_数据库其它调优策略

MySQL高级_第12章_数据库其它调优策略 1. 数据库调优的措施 1.1 调优的目标 尽可能 节省系统资源 ,以便系统可以提供更大负荷的服务。(吞吐量更大) 合理的结构设计和参数调整,以提高用户操作 响应的速度 。(响应速…

使用Visual Studio进行cuda编程配置环境四大坑(附解决方案)

写在前面,用于没有使用过Visual Studio进行cuda编程的同学看,以免在安装环境的时候踩到坑 第一坑:CUDA版本与NVIDIA显卡版本不匹配问题: 安装cuda版本坑,强烈建议看下自己的显卡支持什么版本的cuda,切记不要用最新版…