本文转自:http://basiccoder.com/dns-resolver-by-c.html

看了看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 75 03 63 6f 6d 00

粗体的是长度,将域名中的点去掉,用长度来分隔域名,以0结束。DNS允许的长度为0-63个字节,所以一个8位的长度最高两位都为0。

而如果此处域名重复出现,信令中便会用DNS指针代替长度,指针为两个字节,16位的最位都为1,剩下的14位表示在在整个数据包中的偏移量,当程序读取到c00c的时候很容易判断它是一个指针而不是一个长度字段,于是根据c00c指向的领移量,即从数据包开始后的第12个字节,跳转过去读取出域名信息。

/** mytest.c**  Created on: Jan 22, 2016*      Author: allen*/#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>
#include <arpa/inet.h>#define DNS_SVR "202.96.199.133"#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);printf("%s\n",argv[1]);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;
}

C语言域名解析的简单实现相关推荐

  1. 语言axff所占字节数_【每日一答】(74)数组名v.s.指针变量,C语言其实很简单形象比喻为“是一个朋友圈的”...

    下图选自<C语言其实很简单>第8章: 问:请问张老师!书上第227页一句话:指针变量a本身的地址(a所在内存字节编号)是数组的地址,数值上与元素a[0]的地址相等! 这句话是什么意思,我看 ...

  2. 语言都是相通的,学好一门语言,再学第二门语言就很简单,记录一下我复习c语言的过程。...

    语言都是相通的,学好一门语言,再学第二门语言就很简单,记录一下我复习c语言的过程. 为了将本人的python培训提高一个层次,本人最近买了很多算法的书. 这个书上的代码基本都是c语言实现的,c语言很久 ...

  3. R语言grafify包简单、快速绘制19个漂亮的统计图实战

    R语言grafify包简单.快速绘制19个漂亮的统计图实战 目录 R语言grafify包简单.快速绘制19个漂亮的统计图实战 #grafify是什么?

  4. c语言游戏总出bug,C语言 编写的简单移动游戏出现bug?_编程_游戏设计_C语言_天涯问答_天涯社区...

    C语言 编写的简单移动游戏出现bug? 第一次按上下左右没什么问题,之后就会卡住..不知道出了什么错 源码如下:(用vc++的win32 console程序编写) #include #include ...

  5. 简单算法的举例c语言,计算机科学与技术系C语言程序设计22简单算法举例.PPT

    计算机科学与技术系C语言程序设计22简单算法举例 第2章 程序的灵魂--算法 本章主要介绍算法的思想及算法的表示方法. 2.0 绪论 2.1 算法的概念 2.2 简单算法举例 2.3 算法的特性 2. ...

  6. c语言表现一些简单的图片,C语言的一些简单例题.doc

    C语言的一些简单例题 基础知识 例1.1 分析下面程序的输出结果. void main() {int a,b,c; a=2;b=3; c=a+b; printf("\nThe sum of ...

  7. web python php golang_python go 语言完成最简单的web应用

    徒手使用python和go语言搭建最简单的web页面-使用模板,无持久化 也许我们会接触到很多语言的web应用,譬如php,java,包括今天介绍的python和go,实际上我们在使用这些语言构建we ...

  8. C语言实现的简单的线程池

    http://www.linuxidc.com/Linux/2013-01/77619.htm 有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程 ...

  9. C语言如何编辑资源文件,用C语言做个简单的计算机,上面是代码,请教上资源文件在哪里编写,要新建什么文件...

    当前位置:我的异常网» C语言 » 用C语言做个简单的计算机,上面是代码,请教上资源 用C语言做个简单的计算机,上面是代码,请教上资源文件在哪里编写,要新建什么文件 www.myexceptions. ...

最新文章

  1. 深度学习数据特征提取:ICCV2019论文解析
  2. R语言基于机器学习算法进行特征筛选(Feature Selection)
  3. 吉大c 语言程序设计奥鹏作业,吉大20春学期《可编程控制器》在线作业一百分...
  4. Boost:容器std::pair与宏BOOST_TEST_EQ相关的测试
  5. ubuntu中解决无法调节屏幕亮度的问题
  6. 前端 html结合css-1篇
  7. Xcode6.1 模拟器路径
  8. BDD框架之Cucumber研究
  9. 21南阳理工oj新生赛Round#5--这是一道防ak题
  10. c专家编程 读书笔记
  11. extjs5(03--项目中文件的加载过程)
  12. WebLogic安装的目录结构及应用部署的3种方式
  13. 导入一个maven项目出现红色叉号的解决办法
  14. linux 文件隐藏权限,linux文件基本权限、默认权限、隐藏权限和ACL权限
  15. BoM在企业管理中的重要作用
  16. 公司人事管理系统(C++)
  17. modbus模拟器使用
  18. IT行业岗位薪资大调查:收入最高的职位是什么?
  19. 步进电机的计算机控制系统设计,基于计算机并口的步进电机控制系统设计
  20. Linux平台上直接运行Android应用,android开发入门与实战体验

热门文章

  1. 电感(29)之铁氧体磁珠工作原理透彻详解
  2. 网易轻舟 Serverless 平台 Knative 性能调优实践
  3. lauyi实现表格内显示文件名称,点击实现下载功能。
  4. Bulter-Volmer 方程推导 Tafel斜率
  5. 右值引用与move语义
  6. 【python爬虫】爬取网贷之家所有P2P平台基本数据并写入MYsql数据库
  7. 普通家用4G路由器和工业4G路由器有什么区别
  8. OpenCV-Python 4.5.4 人脸识别应用
  9. css 科技 边框_CSS3实现发光边框特效
  10. ACK打击是什么意思?ACK打击怎么防御?