DNS解析协议的C语言简单实现
仔细看了看DNS协议的相关东西,其实实际编程的时候根本用不到DNS细节的东西,要获取域名的时候经终端下用host或者nslookup指令就可以,在c里面使用gethostbyname或者getaddrinfo都能很轻松得将dns域名解析为ip地址,写这个纯粹出于个人兴趣,或者说是闲得吧。
在进行域名解析的时候,解析程序向域名服务器发起请求,域名服务器也就是在操作系统网络配置的时候写进去的那个DNS服务器地址,或者也有可能是由ISP提供的自动获取的,原理都一样,域名服务器收到请求后进行处理,首先在本地缓存中查找对应的域名,找到后将IP地址直接返回,找不到就向其它的授权服务器请求数据,又可以分为著名的递归查询和非递归查询。
递归查询就是说自始至终都由一台域名服务器进行查询,它在自己这里找不到的时候会向其它的域名服务器请求并且获取数据,然后返回给请求方。
非递归查询是指域名服务器收到请求后,如果自己有这个域名的信息就返回,如果没有就返回其它域名服务器的指针,请求方再根据这些域名服务器再发起查询。
按自己的理解瞎扯了一通,也不知道准不准确,关于DNS的相关资料网上有的是,中文的都大批大批的。
DNS服务器的原理其实没什么好说的,每天都在跟DNS打交道,但DNS的协议在实现上还是稍微有点意思的,本来想写个程序来测试一个我所了解的DNS协议,后来在写的时候还真发现一个小问题,DNS域名有时候会是一个主域名的别名,比如www.baidu.com,它就是www.a.shifen.com这个域名的别名,在DNS请求发送过去之后,response里面会有一个类型为CNAME的Answers项,里面包含了主域名的相关信息(其实也就是主域名的名称和TTL),在这个应答消息里面可能会出现多个域名消息,比如每个Answers的第一个字段就是一个域名,当然为了减少数据包的容量,DNS系统对域名进行了压缩,同一个域名只会出现一次,其它的时候再出现的话就会用一个DNS指针表示。
比如域名:www.baidu.com在数据包中的表示是 03 77 77 77 05 62 61 69 64 7503 63 6f 6d 00
粗体的是长度,将域名中的点去掉,用长度来分隔域名,以0结束。DNS允许的长度为0-63个字节,所以一个8位的长度最高两位都为0。
而如果此处域名重复出现,信令中便会用DNS指针代替长度,指针为两个字节,16位的最位都为1,剩下的14位表示在在整个数据包中的偏移量,当程序读取到c00c的时候很容易判断它是一个指针而不是一个长度字段,于是根据c00c指向的领移量,即从数据包开始后的第12个字节,跳转过去读取出域名信息。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h>#define DNS_SVR "211.68.71.4"#define DNS_HOST 0x01 #define DNS_CNAME 0x05int socketfd; struct sockaddr_in dest;static void send_dns_request(const char *dns_name);static void parse_dns_response();/*** Generate DNS question chunk*/ static void generate_question(const char *dns_name, unsigned char *buf , int *len);/*** Check whether the current byte is * a dns pointer or a length*/ static int is_pointer(int in);/*** Parse data chunk into dns name* @param chunk The complete response chunk* @param ptr The pointer points to data* @param out This will be filled with dns name* @param len This will be filled with the length of dns name*/ static void parse_dns_name(unsigned char *chunk , unsigned char *ptr, char *out , int *len);int main(int argc , char *argv[]){if(argc != 2){printf("Usage : %s <domain name>\n" , argv[0]);exit(-1);}socketfd = socket(AF_INET , SOCK_DGRAM , 0);if(socketfd < 0){perror("create socket failed");exit(-1);}bzero(&dest , sizeof(dest));dest.sin_family = AF_INET;dest.sin_port = htons(53);dest.sin_addr.s_addr = inet_addr(DNS_SVR);send_dns_request(argv[1]);parse_dns_response();return 0; }static void parse_dns_response(){unsigned char buf[1024];unsigned char *ptr = buf;struct sockaddr_in addr;char *src_ip;int n , i , flag , querys , answers;int type , ttl , datalen , len;char cname[128] , aname[128] , ip[20] , *cname_ptr;unsigned char netip[4];size_t addr_len = sizeof(struct sockaddr_in);n = recvfrom(socketfd , buf , sizeof(buf) , 0, (struct sockaddr*)&addr , &addr_len);ptr += 4; /* move ptr to Questions */querys = ntohs(*((unsigned short*)ptr));ptr += 2; /* move ptr to Answer RRs */answers = ntohs(*((unsigned short*)ptr));ptr += 6; /* move ptr to Querys *//* move over Querys */for(i= 0 ; i < querys ; i ++){for(;;){flag = (int)ptr[0];ptr += (flag + 1);if(flag == 0)break;}ptr += 4;}printf("-------------------------------\n");/* now ptr points to Answers */for(i = 0 ; i < answers ; i ++){bzero(aname , sizeof(aname));len = 0;parse_dns_name(buf , ptr , aname , &len);ptr += 2; /* move ptr to Type*/type = htons(*((unsigned short*)ptr));ptr += 4; /* move ptr to Time to live */ttl = htonl(*((unsigned int*)ptr));ptr += 4; /* move ptr to Data lenth */datalen = ntohs(*((unsigned short*)ptr));ptr += 2; /* move ptr to Data*/if(type == DNS_CNAME){bzero(cname , sizeof(cname));len = 0;parse_dns_name(buf , ptr , cname , &len);printf("%s is an alias for %s\n" , aname , cname);ptr += datalen;}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);}ptr += datalen;}}ptr += 2; }static void parse_dns_name(unsigned char *chunk, unsigned char *ptr , char *out , int *len){int n , alen , flag;char *pos = out + (*len);for(;;){flag = (int)ptr[0];if(flag == 0)break;if(is_pointer(flag)){n = (int)ptr[1];ptr = chunk + n;parse_dns_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 is_pointer(int in){return ((in & 0xc0) == 0xc0); }static void send_dns_request(const char *dns_name){unsigned char request[256];unsigned char *ptr = request;unsigned char question[128];int question_len;generate_question(dns_name , question , &question_len);*((unsigned short*)ptr) = htons(0xff00);ptr += 2;*((unsigned short*)ptr) = htons(0x0100);ptr += 2;*((unsigned short*)ptr) = htons(1);ptr += 2;*((unsigned short*)ptr) = 0;ptr += 2;*((unsigned short*)ptr) = 0;ptr += 2;*((unsigned short*)ptr) = 0;ptr += 2;memcpy(ptr , question , question_len);ptr += question_len;sendto(socketfd , request , question_len + 12 , 0, (struct sockaddr*)&dest , sizeof(struct sockaddr)); }static void generate_question(const char *dns_name , unsigned char *buf , int *len){char *pos;unsigned char *ptr;int n;*len = 0;ptr = buf; pos = (char*)dns_name; for(;;){n = strlen(pos) - (strstr(pos , ".") ? strlen(strstr(pos , ".")) : 0);*ptr ++ = (unsigned char)n;memcpy(ptr , pos , n);*len += n + 1;ptr += n;if(!strstr(pos , ".")){*ptr = (unsigned char)0;ptr ++;*len += 1;break;}pos += n + 1;}*((unsigned short*)ptr) = htons(1);*len += 2;ptr += 2;*((unsigned short*)ptr) = htons(1);*len += 2; }
DNS解析协议的C语言简单实现相关推荐
- 【mDNS】本地DNS解析协议
组播地址 224.0.0.251:5353 mDNS-client : 客户端(组播请求), 带缓存(过期时间) mDNS-server : 服务器(组播/单播响应)
- DNS传输协议解析!pcap报文中的域名获取
回想一下,当我们想访问谷歌的时候,通常输入域名(网址):https://www.google.com,其实这就是一个域名. DNS 解析过程涉及将主机名(例如 https://www.google.c ...
- Linux运维系列总结-Linux系统启动过程、WEB工作原理、DHCP工作原理、DNS解析原理、NFS网络文件系统、FTP文件传输协议、PXE+KICKSTART自动安装系统
Linux运维系列总结-Linux系统启动过程.WEB工作原理.DHCP工作原理.DNS解析原理.NFS网络文件系统.FTP文件传输协议.PXE+KICKSTART自动安装系统 1.Linux系统的启 ...
- ※C++随笔※=☆C++基础☆=※№如何简单解析协议Demo
在日常的开发过程中,我们可能会遇上解析协议的事情,其实是不用担心的,一般情况下此类的问题都不会太难.我们来一一详细研究下解析协议的过程. 既然是解析协议,当然得有个协议的文档之类的东东啦.首先我们得看 ...
- c-ares 一个C语言的异步DNS解析库
c-ares是一个C语言的异步DNS解析库,可以很方便的和使用者的事件循环统一起来,实现DNS的非 阻塞异步解析,libcurl, libevent, gevent, nodejs都在使用. 下面摘自 ...
- UDP编程-DNS解析器的分析与实现(C语言)
基本知识 基本介绍 域名系统(英文:Domain Name System,缩写:DNS)的作用是将人类可读的域名 (如,www.example.com) 转换为机器可读的 IP 地址 (如,192.0 ...
- 简单的dns解析过程
1.在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析. 2.如果hosts里没有这个域名的映射,则 ...
- 渗透测试-----信息收集(通过DNS解析找IP地址、CDN、IP查询、IP物理地址、搜索引擎、网站信息收集)
文章目录 渗透测试 信息收集 一.IP地址信息收集 1. 通过DNS解析找IP地址 1.1 ping命令 1.2 nslookup命令 1.3 dig工具 1.4 dnsenum 1.5 站长工具 2 ...
- Android网络优化基础操作攻略(DNS解析,连接复用,Response Cache,数据压缩,弱网,网络安全,监控)
做网络优化,首先我们要这个流程有一定的认识,大致流程如下: 生成请求行 查找强缓存(不一定都有) DNS域名解析(找到Host主机IP) 建立TCP连接(三次握手) 发送HTTP请求 接收HTTP响应 ...
最新文章
- Docker 容器技术 — Compose 编排
- es6 - 解构赋值
- android p 权限流程,Android native 权限控制流程
- JavaScript实现CountingSort计数排序算法(附完整源码)
- uLua Unity工作机制
- 230. Kth Smallest Element in a BST
- python数据结构之链表_Python数据结构之翻转链表
- Windows Mobile 5 编程体验4
- leetcode 53 python 动态规划
- 测试工程师应懂的Python知识
- linux 删除压缩包_【干货】记住!这些 Linux 命令千万不要运行!
- jsdroid 教程_教程24富怡服装cad软件V8安装包送操作说明书自学180部视频教程制版排料放码工具操作教学打赏49.8大洋...
- Vue中使用Bscroll @click无法执行的问题
- php 0x80004005,解决Access出现Microsoft JET Database Engine (0x80004005)未指
- ​6. 独享锁 VS 共享锁
- 比亚迪决定不给日系留“活路”了
- 神经网络理论及应用答案,神经网络理论名词解释
- 高等数学(第七版)同济大学 习题12-6 个人解答
- android uinput 按键_Android 触摸屏Event上报操作
- 计算机水平一般良好怎么填,计算机水平一般怎么填
热门文章
- js---开发一款软件,根据公式(身高-108)*2=体重,可以有10斤左右的浮动。来观察测试者体重是否合适(身高:cm)
- 基于单片机开发的快速体温计方案
- mfc调取摄像头显示并截图_利用MFC来显示摄像头并拍照
- 六级备考15天|CET-6|翻译真题练习|北京大兴国际机场|9:15~10:20
- FFmpeg简述,源码分析,录制/压缩/水印/剪切/旋转/滤镜/美颜/上传视频等(CPU软编码和解码)
- 微信视频号直播功能玩法详解:国仁楠哥
- php实现app消息推送
- 中文的游戏配音一定不好吗?
- 惊喜警报!Mini XMan线上快闪活动即将来袭!
- 计算机信息维护,计算机的日常维护_计算机的基本知识_IT /计算机_信息