文章目录

  • 一、通过uslookup根据域名查看ip
  • 二、DNS协议报文格式
  • 三、C语言实现DNS请求
    • 1. 结构体定义
      • (1) dns_header
      • (2) dns_question
    • 2.头部初始化
    • 3.question初始化
    • 4.将header和question合并为一个报文
    • 5.通过socket实现DNS请求
    • 6.解析结果
  • 四、总结
    • 1.UDP传输速度快 --> 下载领域
    • 2.UDP响应速度快 --> 游戏领域

一、通过uslookup根据域名查看ip

打开Windows的cmd终端,输入:

nslookup www.baidu.com

二、DNS协议报文格式


Queries

查询名: 长度不固定,且不使用填充字节,一般该字段表示的就是需要查询的域名(如果是反向查询,则为 IP,反向查询即由 IP 。

三、C语言实现DNS请求

1. 结构体定义

根据dns报文协议,创建2个结构体:
1个存储dns首部header,另1个存储Queries

(1) dns_header

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

(2) dns_question

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

2.头部初始化

(id 随机,flags=0x0100 代表标准查询,questions = 1,表示只查询一个,htons是为了转化为网络字节序)

int dns_create_header(struct dns_header *header) {if (header == NULL) return -1;memset(header, 0, sizeof(struct dns_header));//randomsrandom(time(NULL)); header->id = random();header->flags = htons(0x0100);header->questions = htons(1); return 0;
}

3.question初始化

即dns协议报文中的Queries,由于规则问题,要将www.baidu.com转为3www5baidu3com’\0’,这个‘\0’是字符串结尾标志

//创建question
//hostname:www.baidu.com
//name:3www5baidu3com'\0'
int dns_create_question(dns_question* question,const char* hostname){if(question==NULL||hostname==NULL) return -1;memset(question,0,sizeof(question));question->name=(char*)malloc(strlen(hostname)+2);//因为要判断结尾'\0',然后再补充一个开头if(question->name==NULL){//如果内存分配失败return -2;}question->length=strlen(hostname)+2;question->qtype=htons(1);//查询类型,(1表示:由域名获得 IPv4 地址)question->qclass=htons(1);//通常为 1,表明是 Internet 数据//hostname->nameconst char delim[2]=".";//分隔符,末尾补个'\0'char* qname=question->name;char* hostname_dup=strdup(hostname);//复制一份hostname  --->malloc(所以后续要free)char* token=strtok(hostname_dup,delim);while(token!=NULL){size_t len=strlen(token);//第一个循环token为www,len=3*qname=len;//先把长度放上去qname++;strncpy(qname,token,len+1);//复制www,这里不+1也是可以的,这样是为了把最后的'\0'也复制过来,因为最后也会被覆盖的。(如果这边不+1,最后一步,需要额外加上'\0')qname+=len;token=strtok(NULL,delim);//因为上一次,token获取还未结束,因此可以指定NULL即可。(注意:要依赖上一次的结果,因此也是线程不安全的)}free(hostname_dup);}

4.将header和question合并为一个报文

//struct dns_header* header
//struct dns_question* question
//把上面两个合到request中 返回长度
int dns_build_requestion(dns_header* header,dns_question* question,char* request,int rlen){if(header==NULL||question==NULL||request==NULL) return -1;memset(request,0,rlen);//header-->requestmemcpy(request,header,sizeof(dns_header));//把header的数据 拷贝 到request中int offset=sizeof(dns_header);//question-->requestmemcpy(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;
}

5.通过socket实现DNS请求

  1. 创建sockfd
  2. servaddr服务器地址
  3. 获得request,
  4. sendto发送请求
  5. recvfrom接受数据
  6. 从数据中解析出ip地址
int dns_client_commit(const char* domin){int sockfd=socket(AF_INET,SOCK_DGRAM,0);//创建sockfd,AF_INET表示ipv4, SOCK_DGRAM为报文方式(UDP);if(sockfd<0){//创建失败return -1;}sockaddr_in servaddr={0};//服务器地址(sockaddr_in存储)servaddr.sin_family=AF_INET;//协议簇servaddr.sin_port=htons(DNS_SERVER_PORT);//端口servaddr.sin_addr.s_addr=inet_addr(DNS_SERVER_IP);//添加dns服务器ipint ret=connect(sockfd,(sockaddr*)&servaddr,sizeof(servaddr));//在udp编程中可加可不加printf("connect:%d",ret);dns_header header={0};dns_create_header(&header);dns_question question={0};dns_create_question(&question,domin);char request[1024]={0};//假设定义为1024长度int length = dns_build_requestion(&header,&question,request,1024);//request 发送请求int slen=sendto(sockfd,request,length,0,(sockaddr*)&servaddr,sizeof(sockaddr));//receive from 接受数据char response[1024]={0};sockaddr_in addr;size_t addr_len=sizeof(sockaddr_in);int n = recvfrom(sockfd,response,sizeof(response),0,(sockaddr*)&addr,(socklen_t*)&addr_len);printf("recvfrom:%d \n",n);for(int i=0;i<n;i++){printf("%c",response[i]);}for(int i=0;i<n;i++){printf("%x",response[i]);}printf("\n");return n;
}

6.解析结果

#define DNS_HOST         0x01
#define DNS_CNAME           0x05struct dns_item {char *domain;char *ip;
};
static int is_pointer(int in) {return ((in & 0xC0) == 0xC0);
}static void dns_parse_name(unsigned char *chunk, unsigned char *ptr, char *out, int *len) {int flag = 0, n = 0, alen = 0;char *pos = out + (*len);while (1) {flag = (int)ptr[0];if (flag == 0) break;if (is_pointer(flag)) {n = (int)ptr[1];ptr = chunk + n;dns_parse_name(chunk, ptr, out, len);break;} else {ptr ++;memcpy(pos, ptr, flag);pos += flag;ptr += flag;*len += flag;if ((int)ptr[0] != 0) {memcpy(pos, ".", 1);pos += 1;(*len) += 1;}}}}static int dns_parse_response(char *buffer, struct dns_item **domains) {int i = 0;unsigned char *ptr = (unsigned char* )buffer;ptr += 4;int querys = ntohs(*(unsigned short*)ptr);ptr += 2;int answers = ntohs(*(unsigned short*)ptr);ptr += 6;for (i = 0;i < querys;i ++) {while (1) {int flag = (int)ptr[0];ptr += (flag + 1);if (flag == 0) break;}ptr += 4;}char cname[128], aname[128], 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 ++) {bzero(aname, sizeof(aname));len = 0;dns_parse_name((unsigned char* )buffer, ptr, aname, &len);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) {bzero(cname, sizeof(cname));len = 0;dns_parse_name((unsigned char* )buffer, ptr, cname, &len);ptr += datalen;} else if (type == DNS_HOST) {bzero(ip, sizeof(ip));if (datalen == 4) {memcpy(netip, ptr, datalen);inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));printf("%s has address %s\n" , aname, ip);printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60);list[cnt].domain = (char *)calloc(strlen(aname) + 1, 1);memcpy(list[cnt].domain, aname, strlen(aname));list[cnt].ip = (char *)calloc(strlen(ip) + 1, 1);memcpy(list[cnt].ip, ip, strlen(ip));cnt ++;}ptr += datalen;}}*domains = list;ptr += 2;return cnt;}

四、总结

1.UDP传输速度快 --> 下载领域

2.UDP响应速度快 --> 游戏领域

DNS协议与请求的C语言实现相关推荐

  1. linux系统c语言并发测试http协议post请求

    linux系统c语言并发测试http协议post请求 特殊场景,工作中遇到的. 有一个http服务端需要并发测试接口处理能力. 之前开发过程中测试都是用的postman 面对高并发模拟,postman ...

  2. TCP/IP协议、请求报文和响应报文

    一.TCP/IP协议 1.计算机与网络设备相互通信 计算机与网络设备要相互通信, 双方就必须基于相同的方法. 比如:如何探测到通信目标. 由哪一边先发起通信. 使用哪种语言进行通 信. 怎样结束通信等 ...

  3. 【计算机网络】TCP/IP协议(DNS协议、IP协议、TCP协议、UDP协议、三次握手、四次挥手)

    TCP/IP协议 TCP/IP协议 TCP/IP各层作用与常见协议 各种协议与HTTP协议的关系 TCP/IP协议 本文参考<图解HTTP>--上野宣 TCP/IP是Internet上所有 ...

  4. DNS协议与DNS服务器搭建(bind)

    写在前面: 博客书写牢记5W1H法则:What,Why,When,Where,Who,How. 本篇主要内容: ● tcp/ip回顾 ● DNS协议/DNS服务相关概念 ● bind安装配置   正向 ...

  5. 计算机网络协议分析dns,DNS协议分析

    一直有一个愿望,能把知道的东西的原理搞明白:计算机网络.操作系统等等等等.今天好好研究了研究DNS协议. DNS协议是应用层协议,一般是基于UDP协议,不过我看了Golangnet 包里相关源码用的是 ...

  6. TCP/IP协议应用层之DNS协议

    为什么会有TCP/IP协议? 世界各地有各种各样的计算机,每台计算机装有不同的操作系统,这就会导致他们对同一种信息存在多种不同的表达方式,这就好比世界各地的人们会说不同的语言.我们使用互联网可以把不同 ...

  7. 协议分析---HTTP协议和DNS协议

    协议分析-HTTP协议和DNS协议 一.HTTP协议 1.HTTP协议简介 1.1 什么是超文本(HyperText) ?   包含有超链接(Link)和各种多媒体元素标记(Markup)的文本.这些 ...

  8. 使用Wireshark进行DNS协议解析

    " DNS协议格式解析及说明." DNS即域名系统(Domain Name System),是用来将域名与IP地址建立映射的协议,通过DNS协议,可以方便记忆. DNS可基于TCP ...

  9. 万字长文爆肝 DNS 协议!

    试想一个问题,我们人类可以有多少种识别自己的方式?可以通过身份证来识别,可以通过社保卡号来识别,也可以通过驾驶证来识别,尽管我们有多种识别方式,但在特定的环境下,某种识别方法可能比另一种方法更为适合. ...

最新文章

  1. Web版VS Code上线:最好用的IDE终于发布网页版,然而微软发完秒删
  2. 次世代3D游戏角色是如何打造出来的?
  3. qtdesigner设计表格_实例9 利用Qt Designer设计一个对话框
  4. oxyen eclipse 启动 报错 se启动提示javaw.exe in your current PATH、No java virtual machine
  5. python的功能名称_ML获取功能选择后的功能名称SelectPercentile,python
  6. gfs mysql_linux搭建gfs系统--iscsi+GFS实现网络存储
  7. SSL/TLS 工具 OpenSSL
  8. [CLS]预训练语言模型的前世今生[SEP]萌芽时代[SEP]
  9. 学生选课系统的源码-代码布局截图
  10. 呼叫中心几种常见质检方式的对比
  11. 步进电机驱动控制器,电动云台控制。
  12. 谷歌Chrome浏览器无法打开网页,提示您与此网站之间建立不安全连接【解决】
  13. html邮件和英文邮件,英文邮件中Best wishes和Best regards的区别
  14. Python3.7.0安装报:0x80072efd
  15. 【AOP】面向切面谈恋爱(二)| 学废了AOP,他最终失去了爱情
  16. python入门基础知识(九):函数
  17. 也谈分布式系统中的网络模型和故障模型
  18. 海康威视监控摄像头大华摄像头webrtc监控低时延无插件直播页面播放毫无延迟
  19. 2019年谷歌SEO排名主要因素
  20. 通过雪花(snowflake)算法用Python实现一个简单的发号器

热门文章

  1. Github博客+腾讯云域名的快捷绑定方案
  2. WebGoat(一)——HTTPSplitting(Http拆分攻击)
  3. Linux 命令 htop 的使用
  4. 360网页html,360综艺频道-更新更全更受欢迎的影视网站-在线观看
  5. 航空总线1553B接口设计
  6. 【实战】爬虫实战-pixabay图片存储mysql
  7. Lazada卖家上传产品实操,采采Lazada上货铺货助手,一键采集刊登上架,批量上品删除宝贝上下架更改产品属性,自动翻译,图片文字翻译
  8. Fiddler抓包及_Fiddler过滤
  9. 生产质量优化方案,助力企业搞好“质量”与“成本”关系!
  10. 银行提供了整存整取定期储蓄业务,存期分为1年,2年,3年,5年,到期取本息之和,年利率如下 1年 2.25% 2年 2.7% 3年 3.24% 5年