Chinaunix首页 | 论坛 | 博客
  • 博客访问: 79301
  • 博文数量: 83
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 00:36
文章分类

全部博文(83)

文章存档

2014年(83)

我的朋友

分类: C/C++

2014-07-17 14:39:56

原文地址:请求DNS相关介绍和代码 作者:bjpiao

创建文件dns-test.cpp

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <netdb.h>
  5. #include <sys/types.h>
  6. #include <netinet/in.h>
  7. #include <arpa/nameser.h>
  8. #include <resolv.h>
  9. #include <errno.h>
  10. #include <iostream>
  11. using namespace std;

  12. #define DNS_MSG_END -2
  13. #define dns_mx_query(str) dns_resolve((str),T_MX)
  14. #define dns_mx_expand() dns_findmx(T_MX)
  15. #define foreach_mxrr(p,dn) while(dns_mx_expand()!=DNS_MSG_END && (!dns_get_m
  16. xrr(&p,dn,MAXDNAME)))


  17. static unsigned short getshort(unsigned char *c)
  18. {
  19.     unsigned short u;
  20.     u = c[0];
  21.     return (u << 8) + c[1];
  22. }

  23. unsigned int getint(unsigned char *c)
  24. {
  25.     unsigned int u;
  26.     u = c[0];
  27.     return (((((u << 8 ) + c[1]) << 8) + c[2] ) << 8 ) + c[3];
  28. }

  29. static union
  30. {
  31.     HEADER hdr;
  32.     unsigned char buf[PACKETSZ];
  33. } response;

  34. static int responselen;
  35. static unsigned char *responseend;
  36. static unsigned char *responsepos;
  37. static int numanswers;
  38. static char name[MAXDNAME];
  39. unsigned short pref;

  40. int dns_resolve(char *domain, int type)
  41. {
  42.     int n;
  43.     int i;
  44.     errno = 0;
  45.     if (NULL == domain)
  46.     {
  47.         return -1;
  48.     }
  49.     responselen = res_search(domain, C_IN, type, response.buf, sizeof(response));
  50.     if (responselen <= 0)
  51.     {
  52.         return -1;
  53.     }
  54.     if (responselen >= sizeof(response))
  55.     {
  56.         responselen = sizeof(response);
  57.     }
  58.     responseend = response.buf + responselen;
  59.     responsepos = response.buf + sizeof(HEADER);
  60.     n = ntohs(response.hdr.qdcount);
  61.     
  62.     int m = n;
  63.     while (n-- > 0)
  64.     {
  65.         i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME);
  66.         responsepos += i;
  67.         i = responseend - responsepos;
  68.         if (i < QFIXEDSZ)
  69.         {
  70.             return -1;
  71.         }
  72.         //responsepos += QFIXEDSZ;
  73.     }
  74.     numanswers = ntohs(response.hdr.ancount);
  75.   
  76.     cout << "request name : " << name << endl;
  77.     cout << "request type : " << getshort(responsepos) << endl;
  78.     cout << "request class : " << getshort(responsepos+2) << endl;
  79.     cout << "question number : " << m << endl;
  80.     cout << "answer number : " << numanswers << endl;
  81.     
  82.     responsepos += QFIXEDSZ;
  83.     return numanswers;
  84. }

  85. int dns_findmx(int wanttype)
  86. {
  87.     unsigned short rrtype;
  88.     unsigned short rrdlen;
  89.     int i;

  90.     if (numanswers <= 0)
  91.     {
  92.         return DNS_MSG_END;
  93.     }
  94.     numanswers--;
  95.     if (responsepos == responseend)
  96.     {
  97.         return -1;
  98.     }
  99.     i = dn_expand(response.buf, responseend, responsepos, name, MAXDNAME);
  100.     if (i < 0)
  101.     {
  102.         return -1;
  103.     }
  104.     responsepos += i;
  105.     i = responseend - responsepos;
  106.     if (i < 10)
  107.     {
  108.         return -1;
  109.     }
  110.   
  111.     cout << "domain : " << name << endl;
  112.     rrtype = getshort(responsepos);
  113.     int ttl = getint(responsepos+4);
  114.     cout << "ttl : " << ttl << endl;
  115.     rrdlen = getshort(responsepos + 8);
  116.     responsepos += 10;
  117.     if (rrtype == wanttype)
  118.     {
  119.         if (rrdlen < 3)
  120.         {
  121.             return -1;
  122.         }
  123.         pref = (responsepos[0] << 8) + responsepos[1];
  124.         memset(name, 0, MAXDNAME);
  125.         if (dn_expand(response.buf, responseend, responsepos + 2, name, MAXDNAME) < 0)
  126.         {
  127.             return -1;
  128.         }
  129.         responsepos += rrdlen;
  130.         return strlen(name);
  131.     }
  132.     responsepos += rrdlen;
  133.     return 0;
  134. }

  135. void dns_init()
  136. {
  137.     res_init();
  138.     memset(name, 0, MAXDNAME);
  139. }

  140. int dns_get_mxrr(unsigned short *p, unsigned char *dn, unsigned int len)
  141. {
  142.     *p = pref;
  143.     strncpy((char *)dn, name, len);
  144.     if (len < (strlen(name) + 1))
  145.     {
  146.         return -1;
  147.     }
  148.     return 0;
  149. }

  150. int main(int argc, char *argv[])
  151. {
  152.     char dname[MAXDNAME];
  153.     int i;
  154.     unsigned short p;
  155.     dns_init();
  156.     if (argc != 2)
  157.     {
  158.         fprintf(stderr, "bad argumentn");
  159.         exit(-1);
  160.     }
  161.     i = dns_mx_query(argv[1]);
  162.     if (i < 0)
  163.     {
  164.         fprintf(stderr, "errn");
  165.         return 0;
  166.     }
  167.     printf("preftdomain namen");
  168.     foreach_mxrr(p, (unsigned char *)dname)
  169.     {
  170.         printf("%dt%sn", p, dname);
  171.     }
  172.     return 0;
  173. }

编译: g++ dns-test.cpp -lresolv
         ./a.out sina.com.cn       
request name : qq.com
request type : 15
request class : 1
question number : 1
answer number : 3
pref    domain name
domain : qq.com
ttl : 7045
20      mx2.qq.com
domain : qq.com
ttl : 7045
30      mx1.qq.com
domain : qq.com
ttl : 7045
10      mx3.qq.com


原理介绍:
1    概述
DNS 查询中, 最常用的两类分别是A类查询(A query)和指针查询(PTR query). 前者是已知主机名, 询问IP; 后者是已知IP, 询问主机名. 对于这些查询, 在Unix主机中可以直接调用基本DNS函数: gethostbyname(3)和gethostbyaddr(3)来实现. 但是对于其他类型的查询(例如MX查询), 则没有专门的函数来负责处理.

2    DNS报文格式
在对地址解析函数讲解之前, 有必要先了解一下DNS报文格式. 之后的几节会频繁地涉及到本节所讲的内容.

DNS定义了一个用于查询和响应的报文格式, 图1 显示了这个报文的总体格式.

每个DNS查询(或响应)报文都包含有一个12字节长的首部和四个变长的字段组成.
对于本文来说, 首部中主要关心的是问题数和资源记录数两个字段. 这两个字段分别用于说明各自对应的变长字段中的条目数. 问题数说明查询问题字段中的条目数; 资源记录数则说明回答字段中的条目数. 对于一个DNS查询报文, 问题数通常是1. 对于应答报文, 回答数至少是1.

查询
首部以下是四个变长字段, 本文所关心的是查询问题字段和回答字段.
查询问题字段可以包含多个查询问题, 每个问题的格式如图2 所示.
图二
其中, 查询名一项存储着要查找的名字. 它长度可变并以一种特殊的格式存储. 程序可以通过其中存储的内容确定其长度. 具体获得其中存储内容的方法, 将在下一节中进行详细讲解. 每一个问题有一个查询类型, 每个响应(下文中将会提到)也同样有一个类型. 常用的类型有: A类型---表示期望获得查询名的IP地址; PTR查询---表示期望获得一个IP地址对应的域名; MX查询---邮件交换查询(关于MX查询的具体内容, 下文会提到). 查询类指定了所使用的协议簇, 通常是1, 表示Internet地址.

回答
回答字段可以包含多个条目. 每个回答字段是以一种叫做资源记录(Resource Record, RR)的格式存储的. ( 授权字段和额外信息字段也同样以资源记录的格式存储信息). 资源记录的格式如图3 所示.
图三域名是记录中资源数据对应的名字. 它的格式和前面介绍的查询名字段格式相同. 类型和类字段和前面介绍的查询类型, 查询类字段的功能一样. 类字段的取值通常是1, 表示Internet地址. 生存时间字段是客户程序保留该资源记录的秒数. 资源数据长度说明资源数据包含的字节数. 资源数据则根据类型字段的值有不同的格式. 对于A类型, 资源数据是IP地址. 对于MX查询, 资源数据是优先值和域名, 域名的格式与查询名字段格式相同(MX记录的具体内容下文会有介绍).



















阅读(315) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~