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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从裸机启动开始运行一个C++程序(二)

先序文章请看: 从裸机启动开始运行一个C程序(一) 运行在8086上的第一个程序 既然硬件环境已经就绪了,那接下来,就要想办法让它运行我们的程序了。不过在此之前,我们必须要了解一下8086的主要架构&#xf…

微星MSI GE66 10SF-416RU电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网,转载需注明出处。(下载请直接百度黑果魏叔) 硬件配置 硬件型号驱动情况 主板Intel HM470 处理器Intel Core i7-10875H 2.30GHz up to 5.10GHz已驱动 内存Kingston Fury Impact DDR4 2x16Gb 3200mhz已驱动 硬盘NT…

【Linux】权限的理解

🌇个人主页:平凡的小苏 📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风…

Apache Flink 文件上传漏洞 (CVE-2020-17518)

文章目录 一、Apache Flink简介二、漏洞简介三、漏洞复现四、上传jar包getshell 一、Apache Flink简介 Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任…

自定义组件3-behaviors

1、behaviors是小程序中用于实现组件间代码共享的特性,类似于Vue.js中的mixins 2、behaviors的工作方式 每个behaviors可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的数据和属性和方法会被 合并到组件中。 每个组件可以引用多个behav…

NXP MCUXPresso - cc1plus.exe: out of memory allocating 65536 bytes

文章目录 NXP MCUXPresso - cc1plus.exe: out of memory allocating 65536 bytes概述实验结论补充END NXP MCUXPresso - cc1plus.exe: out of memory allocating 65536 bytes 概述 在尝试迁移 openpnp - Smoothieware project 从gcc命令行 MRI调试方式 到NXP MCUXpresso工程…

数据库界的科技与狠活: 创邻科技Galaxybase X英特尔SGX数据加密解决方案正式发布

引言 近日,创邻科技入选与英特尔合作,在基于第四代英特尔至强处理器的支持下,利用软件防护扩展(Software Guard Extension,SGX) 技术,打造出了具备可信执行环境的图数据库产品,保护企业释放关联…

nodejs进阶(4)—读取图片到页面

我们先实现从指定路径读取图片然后输出到页面的功能。 先准备一张图片imgs/dog.jpg。 file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明binary。(file.js 在上一篇文章nodejs进阶3-路由处理中有完整的内容) readImg:functi…

03)FastDFS配置nginx 服务,使用http方式访问图片

FastDFS是没有文件访问功能的,需要借助其他工具实现图片HTTP访问的。 没安装nginx时比如前端html网页想获取 FastDFS的一张图片显示,需要java写个controller,然后使用 FastDFS-java client客户端调用文件获取api,HttpServletResponre在返回图片流.给前端显示。 安装了nginx…

计算机图形学-GAMES101-9

前言 材质和光的相互作用很重要。VertexShader和FragmentShader。纹理贴图Texture mapping。 一、在三角形中插值 为什么要在三角形内部插值?虽然我们的操作很多是在三角形顶点上进行计算的,但是对于三角形内部我们也希望每个像素点能得到一个值&…

ChatGPT的兴起的时代,国内chatgpt产品大盘点

在人工智能技术的不断发展和应用下,自然语言处理技术成为了研究的热点之一。而其中最受关注的就是“聊天机器人”技术,而GPT(Generative Pre-trained Transformer)模型则是目前最流行的聊天机器人生成模型之一。 随着 ChatGPT 技…

模板类与友元

目录 分类 一、非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数; 代码 分析 运行结果 二、约束模板友元:模板类实例化时,每个实例化的类对应一个友元函数;并且这个模板友元适用多种类模…

pg事务:事务ID

事务ID pg中每个事务都会分配事务ID,事务ID分为虚拟事务ID和持久化事务ID(transactionID)。pg的事务ID非常重要,是理解事务、数据可见性、事务ID回卷等等的重要知识点。 虚拟事务ID 只读事务不会分配事务ID,事务ID是…

Chrome Performance 页面性能分析

Chrome Performance 页面性能分析 背景介绍 性能优化是前端开发一个非常重要的组成部分,如何更好地进行网络传输,如何优化浏览器渲染过程,来定位项目中存在的问题。Chrome DevTools给我们提供了2种常用方式 Audits和Performance&#xff0c…

三分钟看懂JDK、JRE和JVM的区别和联系

节选自JavaGuide(Github 标星 134k star!「Java学习 + 面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识) JVM Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同…

【C++】21年精通C++之泛型编程和模板初阶知识

❤️前言 大家好!今天和大家一起学习关于C泛型编程和模板初阶的相关知识。 正文 我们之前已经学习了C中非常重要的一个特性——函数重载,函数重载很好地提高了我们代码的可读性。但是对于适配多种参数的某种函数来说,我们如果使用函数重载就…

Maven安装和配置(详细版)

Maven安装和配置 Maven安装1、安装链接:2、配置环境变量: Maven配置1、修改Maven仓库下载镜像及修改仓库位置:2、在Idea上配置Maven: 测试Maven安装能否安装jar包 Maven安装 1、安装链接: Maven – Download Apache …

阿里云服务器 之 mqtt服务器搭建及使用

本文主要是对mqtt的学习使用,其中服务器是基于阿里云服务器的mqtt功能,客户端使用的是mqttx软件。 一、服务器部分搭建说明 1、如果是首次使用,则需要经过注册与认证的步骤。 2、找到"产品与服务"-->"物联网平台"&…

【MySQL】多表查询

上一篇介绍了外键约束,外键约束是用于连接两张数据表的,所以在此基础上就有了多表查询 之前的查询都是单表查询,这里我们会将多个数据表的数据结果返回在一张表上 文章目录 1.多表关系2.多表查询2.1 多表查询分类2.2 内连接2.3 外连接2.4 自连接2.5 联合查询2.6子查询 1.多表关…

微信小程序nodejs+vue+uniapp超市网上购物商城系统

超市购物系统用户端要求在系统的安卓手机上可以运行,主要实现了管理端;首页、个人中心、用户管理、商品分类管理、商品信息管理、商品入库管理、订单信息管理、订单配送管理、订单评价管理、退货申请管理、换货申请管理、系统管理,用户端&…