DNS协议与请求

win系统下, CMD中可以使用nslookup命令查看域名IP地址。

DNS服务器与客户端通过带有header和question的协议进行查询与返回,其中header分为六项,分别为ID(会话标识),Flags(标志),questions(问题数),Answer RRs(回答资源记录数),Authority RRs(授权 资源记录数),Addition RRs(附加资源记录数)。

1.header 填充函数

        首先判断输入参数是否有效,对暂不使用的线束进行归零处理。

struct dns_header {

	unsigned short id;
	unsigned short flags;

	unsigned short questions; 
	unsigned short answer;

	unsigned short authority;
	unsigned short additional;

};

int dns_create_header(struct dns_header *header) {
	srandom(time(NULL));
	header->id = random();
    //1970年至今的秒数为范围产生一个随机数   为多线程不安全函数

	header->flags = htons(0x0100); //htons 为网络字节转换  将其转换为相应格式
	header->questions = htons(1);  //请求一个域名

	return 0;
}

         其中flags标志位分为以下位置(2字节)

         QR为查询与响应标志,0查询,1响应

        opcode 0表示标准查询 1 反向查询 2 服务器请求状态

        AA表示授权回答 

        TC表示可截断的

        RD表示期望递归

        RA表示可用递归

        rcode表示返回码 0表示无差错 3表示名字错 2表示服务器错误

        Questions、Answer RRs、Authority RRs、Additional RRs 各自 表示后面的四个区域的数目。Questions 表示查询问题区域节的数量,Answers 表示回答区 域的数量,Authoritative namesversers 表示授权区域的数量,Additional recoreds 表示 附加区域的数量

2.问题创建

        由以下四部分组成,查询名 name,查询类型 type,class 查询类,length域名字节数

struct dns_question {
	int length;
	unsigned short qtype;  //1 表示IPV4 地址  5 表示查询规范域名
	unsigned short qclass; // 通常为1 表示inet数据
	unsigned char *name; // 
};

其中,name 不定长字符串,且域名需要按照相应规范书写。例如www.baidu.com应保存为3www5baidu3com0,末尾0不可省去。

int dns_create_question(struct dns_question *question, const char *hostname) {

	question->name = (char*)malloc(strlen(hostname) + 2);
	question->length = strlen(hostname) + 2;

	question->qtype = htons(1); 
	question->qclass = htons(1);


	const char delim[2] = "."; //分隔符
	char *qname = question->name;
	
	char *hostname_dup = strdup(hostname); //  函数中存在一个malloc 进行复制一份需要对应free
	char *token = strtok(hostname_dup, delim);  //分割出第一段 www

	while (token != NULL) {           //还没分割结束

		size_t len = strlen(token);   //长度

		*qname = len;                 //长度放入字符串
		qname ++;

		strncpy(qname, token, len+1); //字符串放入  +1可以使最后不需要单独放一次0
		qname += len;                 //向后移位

		token = strtok(NULL, delim);  //再次分割
                                      // 此处使用NULL 上次的tok还未结束,仍然tok的是hostname
                                      //如操作临界资源  则为线程不安全函数

	}

	free(hostname_dup);
	
}

  3.数据发送

        建立一个sockfd句柄

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET 表示协议组 SOCK_DGRAM表示数据报文方式

        建立地址结构,其中sockaddr_in为发往服务器结构,约定俗成三项地址定义,欢迎抬杠知识老师原话。

struct sockaddr_in servaddr = {0}; // 
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(IP);

        创建header、question并进行合并。request即为将字符串合为一个。

struct dns_header header = {0};
dns_create_header(&header);

struct dns_question question = {0};
dns_create_question(&question, domain);

char request[1024] = {0};
int length = dns_build_request(&header, &question, request, 1024);

        数据发送,参数为sock句柄,发送的字符串,字符串长度,地址以及地址长度。

sendto(sockfd, request, length, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));

        数据接收,参数与上一个函数基本相同。在response中即可查询到相应IP地址。

	struct sockaddr_in addr;
	size_t addr_len = sizeof(struct sockaddr_in);
	int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr*)&addr, 
    (socklen_t*)&addr_len);

4.UDP好处 

相较于TCP,UDP速度更快,不限下载带宽,一人下载一屋子骂人,且响应速度快,多应用于游戏中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值