基于linux 实现DNS Client请求
创始人
2024-05-29 05:42:24
0

DNS是什么:

DNS是域名系统,Domain Name System的缩写,是一个服务。

作用:

DNS就是把域名解析为IP地址,提供我们上网,我们能够上网最终是找到IP地址。

DNS请求报文格式:

在这里插入图片描述
分别包含

  • Transaction ID:会话标识
  • Flags:标志
  • Questions:问题数量
  • Answer RRs:回答数量
  • Authority RRs:授权数量
  • Additional RRs:附加数量
  • Queries:查询区域

再细分展开Flags与Queries:
Flags:
在这里插入图片描述
其包含:

  • Response: 0 为查询,1 为响应
  • Opcode: 0 表示标准查询,1 表示反向查询,2 表示服务器状态请求
  • Truncated: 表示可截断的
  • Recursion desired: 表示期望递归
  • Z: 保留
  • Non-authenticated data: 是否为未经验证的数据

Queries
在这里插入图片描述
其包含1个问题,问题内容为:

  • Name: m.baidu.com
  • Type: A (Host Address) (1)
  • Class: IN (0x0001)

type数值依据:
在这里插入图片描述

Class(查询类)
通常为 1,是 Internet 数据

构建DNS :

header :

struct header {unsigned short id;			unsigned short flags;		unsigned short questions;	unsigned short answer;		unsigned short authority;unsigned short additional;
};

queries:

struct queries {int length;unsigned short qtype;unsigned short qclass;unsigned char* name;
};

创建结构体存储ip

struct dns_item {char* ip;

};
header创建:

int create_header(struct header* header) {if (header == NULL)
{ 
return -1;
}memset(header, 0, sizeof(struct header));srandom(time(NULL));header->id = random();header->flags = htons(0x0100);//16位主机字节顺序转化成网络字节序 0000 0001 0000 0000 =十进制256header->questions = htons(1);//0000 0001 转换}

创建Queries

int create_queries(struct queries* question, const char* hostname) {if (question == NULL || hostname == NULL){return -1;}memset(question, 0, sizeof(struct queries));question->name = (char*)malloc(strlen(hostname) + 2);if (question->name == NULL) {return -1;}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); char* token = strtok(hostname_dup, delim);while (token != NULL) {size_t len = strlen(token);*qname = len;qname++;strncpy(qname, token, len + 1);qname += len;token = strtok(NULL, delim);}free(hostname_dup);
}

将header和Queries组包:

int dns_build_request(struct header* header, struct queries* question, char* request,int rlen) {if (header == NULL || question == NULL || request == NULL){return -1;}int offset = 0;memset(request, 0, rlen);memcpy(request, header, sizeof(struct header));offset = sizeof(struct header);memcpy(request + offset, question->name, question->length);offset += question->length;memcpy(request + offset, &question->qtype, sizeof(question->qtype));offset += sizeof(question->qtype);memcpy(request + offset, &question->qclass, sizeof(question->qclass));offset += sizeof(question->qclass);return offset;
}

DNS回复报文格式:

在这里插入图片描述
下面是Queris的展开
在这里插入图片描述
下面是Answer的展开(没用截图到回复的DNS_HOST类型,只有CNAME,逻辑可以参考有回复IP的):
在这里插入图片描述

服务器回复后的解析包:

static int dns_parse_response(char* buffer, struct dns_item** domains) {int i = 0;unsigned char* ptr = buffer;ptr += 4;int querys = ntohs(*(unsigned short*)ptr);printf("------问题数querys:%#x------------\n",querys);ptr += 2;int answers = ntohs(*(unsigned short*)ptr);printf("-----回复数answers:%#x------------\n",answers);ptr += 6;//queriesfor (i = 0; i < querys; i++) {while (1) {int flag = (int)ptr[0];ptr += (flag + 1);if (flag == 0) break;}ptr += 4;}char  ip[20], netip[4];int len, type, ttl, datalen;int cnt = 0;struct dns_item* list = (struct dns_item*)calloc(answers, sizeof(struct dns_item));if (list == NULL) {return -1;}for (i = 0; i < answers; i++) {//ptr answerslen = 0;ptr += 2;type = htons(*(unsigned short*)ptr);ptr += 4;ttl = htons(*(unsigned short*)ptr);ptr += 4;datalen = ntohs(*(unsigned short*)ptr);ptr += 2;if (type == DNS_CNAME) {printf("--------DNS_CNAME--------\n");ptr += datalen;}else if (type == DNS_HOST) {printf("--------DNS_HOST--------\n");bzero(ip, sizeof(ip));if (datalen == 4) {memcpy(netip, ptr, datalen);inet_ntop(AF_INET, netip, ip, sizeof(ip));list[cnt].ip = (char*)calloc(strlen(ip) + 1, 1);memcpy(list[cnt].ip, ip, strlen(ip));printf("ip address %s\n", list[cnt].ip);cnt++;}ptr += datalen;}}*domains = list;ptr += 2;return cnt;}

socket请求

int dns_client_commit(const char* domain) {int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {return -1;}struct sockaddr_in servaddr = { 0 };servaddr.sin_family = AF_INET;servaddr.sin_port = htons(DNS_SERVER_PORT);servaddr.sin_addr.s_addr = inet_addr(DNS_SERVER_IP);int ret = connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));//绑定struct header header = { 0 };dns_create_header(&header);struct queries question = { 0 };dns_create_queries(&question, domain);char request[1024] = { 0 };int length = dns_build_request(&header, &question, request,1024);int slen = sendto(sockfd, request, length, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));char response[1024] = { 0 };struct sockaddr_in addr = { 0 };size_t addr_len = sizeof(struct sockaddr_in);int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);struct dns_item* dns_domain = NULL;dns_parse_response(response, &dns_domain);free(dns_domain);return 1;
}

main函数(查询百度dns):

int main(void) {dns_client_commit("www.baidu.com");
}

所有的代码

#include
#include
#include
#include
#include
#include
#include #define DNS_SERVER_PORT		53
#define DNS_SERVER_IP		"114.114.114.114"#define DNS_HOST			0x01
#define DNS_CNAME			0x05struct header {unsigned short id;			unsigned short flags;		unsigned short questions;	unsigned short answer;		unsigned short authority;unsigned short additional;
};struct queries {int length;unsigned short qtype;unsigned short qclass;unsigned char* name;
};
struct dns_item {char* ip;int create_header(struct header* header) {if (header == NULL)
{ 
return -1;
}memset(header, 0, sizeof(struct header));srandom(time(NULL));header->id = random();header->flags = htons(0x0100);//16位主机字节顺序转化成网络字节序 0000 0001 0000 0000 =十进制256header->questions = htons(1);//0000 0001 转换}int create_queries(struct queries* question, const char* hostname) {if (question == NULL || hostname == NULL){return -1;}memset(question, 0, sizeof(struct queries));question->name = (char*)malloc(strlen(hostname) + 2);if (question->name == NULL) {return -1;}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); char* token = strtok(hostname_dup, delim);while (token != NULL) {size_t len = strlen(token);*qname = len;qname++;strncpy(qname, token, len + 1);qname += len;token = strtok(NULL, delim);}free(hostname_dup);
}int dns_build_request(struct header* header, struct queries* question, char* request,int rlen) {if (header == NULL || question == NULL || request == NULL){return -1;}int offset = 0;memset(request, 0, rlen);memcpy(request, header, sizeof(struct header));offset = sizeof(struct header);memcpy(request + offset, question->name, question->length);offset += question->length;memcpy(request + offset, &question->qtype, sizeof(question->qtype));offset += sizeof(question->qtype);memcpy(request + offset, &question->qclass, sizeof(question->qclass));offset += sizeof(question->qclass);return offset;
}
static int dns_parse_response(char* buffer, struct dns_item** domains) {int i = 0;unsigned char* ptr = buffer;ptr += 4;int querys = ntohs(*(unsigned short*)ptr);printf("------问题数querys:%#x------------\n",querys);ptr += 2;int answers = ntohs(*(unsigned short*)ptr);printf("-----回复数answers:%#x------------\n",answers);ptr += 6;//queriesfor (i = 0; i < querys; i++) {while (1) {int flag = (int)ptr[0];ptr += (flag + 1);if (flag == 0) break;}ptr += 4;}char  ip[20], netip[4];int len, type, ttl, datalen;int cnt = 0;struct dns_item* list = (struct dns_item*)calloc(answers, sizeof(struct dns_item));if (list == NULL) {return -1;}for (i = 0; i < answers; i++) {//ptr answerslen = 0;ptr += 2;type = htons(*(unsigned short*)ptr);ptr += 4;ttl = htons(*(unsigned short*)ptr);ptr += 4;datalen = ntohs(*(unsigned short*)ptr);ptr += 2;if (type == DNS_CNAME) {printf("--------DNS_CNAME--------\n");ptr += datalen;}else if (type == DNS_HOST) {printf("--------DNS_HOST--------\n");bzero(ip, sizeof(ip));if (datalen == 4) {memcpy(netip, ptr, datalen);inet_ntop(AF_INET, netip, ip, sizeof(ip));list[cnt].ip = (char*)calloc(strlen(ip) + 1, 1);memcpy(list[cnt].ip, ip, strlen(ip));printf("ip address %s\n", list[cnt].ip);cnt++;}ptr += datalen;}}*domains = list;ptr += 2;return cnt;}
int dns_client_commit(const char* domain) {int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {return -1;}struct sockaddr_in servaddr = { 0 };servaddr.sin_family = AF_INET;servaddr.sin_port = htons(DNS_SERVER_PORT);servaddr.sin_addr.s_addr = inet_addr(DNS_SERVER_IP);int ret = connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));//绑定struct header header = { 0 };dns_create_header(&header);struct queries question = { 0 };dns_create_queries(&question, domain);char request[1024] = { 0 };int length = dns_build_request(&header, &question, request,1024);int slen = sendto(sockfd, request, length, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));char response[1024] = { 0 };struct sockaddr_in addr = { 0 };size_t addr_len = sizeof(struct sockaddr_in);int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr*)&addr, (socklen_t*)&addr_len);struct dns_item* dns_domain = NULL;dns_parse_response(response, &dns_domain);free(dns_domain);return 1;
}
int main(void) {dns_client_commit("www.baidu.com");
}

结语

属于应用层的编程,对于我i们后续的协议理解是很有帮助的。上面提供的所有代码可以直接编译运行,执行的时候请检查电脑是否有网络,否则无法正常执行。

上一篇:Java开发环境搭配

下一篇:Vue学习[2023]

相关内容

热门资讯

台风的英语作文(通用4篇) 台风的英语作文 篇一The Terrifying TyphoonTyphoon is a power...
代沟的作文(精彩5篇) 代沟的作文 篇一随着社会的不断发展和进步,代沟问题逐渐凸显出来。代沟是指不同年龄群体之间由于生活经历...
电子书的利弊英语作文【优质3... Article 1: The Pros and Cons of E-booksWith the ra...
话题英语作文【优选6篇】 话题英语作文 篇一:The Impact of Social Media on TeenagersW...
介绍自己英语作文【经典5篇】 Introducing Myself - Part OneHello, everyone! My n...
关于幽默感的英语句子【优选3... 关于幽默感的英语句子 篇一Humor is the best medicineHumor has t...
一封信英语作文(优选6篇) 一封信英语作文 篇一Dear Grandma,I hope this letter finds yo...
代沟的英语作文带翻译 有关代沟的英语作文带翻译(精选3篇)  在日常学习、工作和生活中,许多人都有过写作文的经历,对作文都...
新年计划英语作文(精简6篇) 新年计划英语作文 篇一My New Year's ResolutionsAs the new yea...
期盼元旦的英语作文【精彩3篇... Anticipating New Year's Day - Article OneNew Year'...
面试学校老师英语作文范文(推... 面试学校老师英语作文范文 篇一Title: The Importance of Communicat...
冬至英语作文(精选6篇) 冬至英语作文 篇一Winter SolsticeWinter Solstice, also know...
去动物园英语作文【通用6篇】 Going to the Zoo - Part 1Last weekend, my family a...
在公园里的五年级英语作文【最... 在公园里的五年级英语作文 篇一A Day in the ParkLast weekend, my f...
英语创意作业评比报道范文(优... 英语创意作业评比报道范文 篇一英语创意作业评比活动圆满结束,参赛学生们展示了精彩的作品,令人难以选择...
如何让你活出精彩真自我英语作... 如何让你活出精彩真自我英语作文 篇一Title: Discovering Your True Sel...
你喜欢我吗小学英语作文(推荐... 你喜欢我吗小学英语作文 篇一Title: Do You Like Me?Hello everyone...
负能量英语句子【实用3篇】 负能量英语句子 篇一Negative Energy English SentencesNegativ...
如何保护环境英语作文【通用6... 如何保护环境英语作文 篇一Title: The Importance of Individual A...
玫瑰花的英语作文【推荐5篇】 玫瑰花的英语作文 篇一Roses - The Symbol of Love and BeautyRo...