• DNS协议 实践


    根据DNS协议发送UDP请求,然后获取IP地址

    头文件:

     1 #ifndef __DNS__
     2 #define __DNS__
     3 
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string>
     7 #include <winsock.h>
     8 
     9 using namespace std;
    10 
    11 /**
    12  * 查询类型
    13  */
    14 #define DNS_TYPE_A     0x01
    15 #define DNS_TYPE_NS    0x02
    16 #define DNS_TYPE_CNAME 0x05
    17 #define DNS_TYPE_SOA   0x06
    18 #define DNS_TYPE_WKS   0x0B
    19 #define DNS_TYPE_PTR   0x0C
    20 #define DNS_TYPE_HINFO 0x0D
    21 #define DNS_TYPE_MX    0x0E
    22 #define DNS_TYPE_AAAA  0x1C
    23 #define DNS_TYPE_AXFR  0xFC
    24 #define DNS_TYPE_ANY   0xFF
    25 
    26 /**
    27  * 查询类别
    28  */
    29 #define DNS_CATEGORY_A      0x01
    30 #define DNS_CATEGORY_CSNET  0x02
    31 #define DNS_CATEGORY_CS     0x03
    32 #define DNS_CATEGORY_HS     0x04
    33 
    34 // 发送DNS请求的key
    35 static u_short _dnsKey = 0x0000;
    36 // DNS域名服务器地址,这里是通过网卡的属性得到的
    37 static string DNSServerIPAddr = "192.168.105.1";
    38 // DNS域名服务器端口,默认53
    39 static int DNSServerPort = 53;
    40 
    41 /**
    42  * 获取发送的key
    43  */
    44 u_short getDNSKey();
    45 
    46 /**
    47  * 生成请求数据
    48  */
    49 void generateDNSRequset(string url, string* requestData);
    50 
    51 /**
    52  * 解析记录中的名字
    53  */
    54 void parseDNSName(unsigned char* buff, unsigned char* pBuff, unsigned char* name, int* offset);
    55 
    56 /**
    57  * 解析DNS响应数据
    58  */
    59 void parseDNSResponse(unsigned char buff, string* ip);
    60 
    61 /**
    62  * 发送DNS请求
    63  */
    64 bool sendDNSRequest(int socketId, struct sockaddr* address, char* sendBuff, int buffLen);
    65 
    66 /**
    67  * 接受DNS数据
    68  */
    69 bool recvDNSRequest(int socketId, struct sockaddr* address, char* recvBuff, int buffLen);
    70 
    71 /**
    72  * 通过DNS请求,获取ip地址的点格式
    73  */
    74 bool getIPAddrByDNS(string url, string* ip);
    75 
    76 #endif

    代码文件:

      1 #include "DNS.h"
      2 
      3 /**
      4  * 获取发送的key
      5  */
      6 unsigned short getDNSKey()
      7 {
      8     if (_dnsKey == 65535) {
      9         _dnsKey = 0;
     10     }
     11     return ++_dnsKey;
     12 }
     13 
     14 /**
     15  * 生成请求数据
     16  */
     17 void generateDNSRequset(string url, string* requestData)
     18 {
     19     unsigned char  request[256];
     20     unsigned char* pRequest = request;
     21 
     22     // key
     23     *((unsigned short*)pRequest) = htons( getDNSKey() );
     24     pRequest += 2;
     25     // 标志
     26     *(pRequest++) = 0x01;
     27     *(pRequest++) = 0x00;
     28     // 查询记录数
     29     *((unsigned short*)pRequest) = htons(0x0001);
     30     pRequest += 2;
     31     // 资源记录数
     32     *((unsigned short*)pRequest) = htons(0x0000);
     33     pRequest += 2;
     34     // 授权资源记录数
     35     *((unsigned short*)pRequest) = htons(0x0000);
     36     pRequest += 2;
     37     // 额外资源记录数
     38     *((unsigned short*)pRequest) = htons(0x0000);
     39     pRequest += 2;
     40 
     41     // 填充查询名字
     42     unsigned char* pCount = pRequest++;
     43     int count = 0;
     44     for (int i = 0, len = url.length(); i < len; i++) {
     45         unsigned char ch = url.at(i);
     46 
     47         if (ch != '.') {
     48             *(pRequest++) = ch;
     49             count++;
     50         }
     51         else {
     52             *pCount = count;
     53             pCount = (pRequest++);
     54 
     55             count = 0;
     56         }
     57     }
     58     *pCount = count;
     59     *(pRequest++) = 0;
     60 
     61     // 查询类型
     62     *((unsigned short*)pRequest) = htons(0x0001);
     63     pRequest += 2;
     64     // 查询类别
     65     *((unsigned short*)pRequest) = htons(0x0001);
     66     pRequest += 2;
     67 
     68     int requestLen = pRequest - request;
     69     // 将char数组转换成string
     70     for (int i = 0; i<requestLen; i++) {
     71         requestData->push_back(request[i]);
     72     }
     73 }
     74 
     75 /**
     76  * 解析记录中的名字
     77  */
     78 void parseDNSName(unsigned char* buff, unsigned char* pBuff, unsigned char* name, int* offset)
     79 {
     80     unsigned char flag;
     81     unsigned char* pName = name + (*offset);
     82 
     83     do {
     84         flag = *pBuff;
     85 
     86 
     87         if ((flag & 0xC0) == 0xC0) {
     88             unsigned char _offset = *(pBuff + 1);
     89             pBuff = buff + _offset;
     90 
     91             parseDNSName(buff, pBuff, name, offset);
     92 
     93             break;
     94         }
     95         else {
     96             unsigned char _count = *(pBuff++);
     97 
     98             memcpy(pName, pBuff, _count);
     99 
    100             pBuff += _count;
    101             pName += _count;
    102             *offset += _count;
    103 
    104             if (*pBuff != 0) {
    105                 *(pName++) = '.';
    106                 *offset += 1;
    107             }
    108         }
    109     }
    110     while (flag != 0);
    111 }
    112 
    113 /**
    114  * 解析DNS响应数据
    115  */
    116 void parseDNSResponse(unsigned char* buff, string* ip)
    117 {
    118     unsigned char* pBuff = buff;
    119 
    120     // key
    121     unsigned short key = ntohs(*((unsigned short*)pBuff));
    122     pBuff += 2;
    123     // 标志
    124     unsigned short remarkLeft  = *(pBuff++);
    125     unsigned short remarkRight = *(pBuff++);
    126     unsigned char  QR      = (remarkLeft & 0x80) >> 7;
    127     unsigned char  OpCode = (remarkLeft & 0x78) >> 4;
    128     unsigned char  AA     = (remarkLeft & 0x04) >> 3;
    129     unsigned char  TC     = (remarkLeft & 0x02) >> 2;
    130     unsigned char  RD     = (remarkLeft & 0x01);
    131     unsigned char  RA     = (remarkRight & 0x80) >> 7;
    132     unsigned char  ZERO   = (remarkRight & 0x70) >> 4;
    133     unsigned char  rCode  = (remarkRight & 0x0F);
    134     // 问题记录数
    135     unsigned short questionCount = ntohs(*(unsigned short*)pBuff);
    136     pBuff += 2;
    137     // 回答记录数
    138     unsigned short answerCount = ntohs(*(unsigned short*)pBuff);
    139     pBuff += 2;
    140     // 授权记录数
    141     unsigned short authCount = ntohs(*(unsigned short*)pBuff);
    142     pBuff += 2;
    143     // 附加记录数
    144     unsigned short addiCount = ntohs(*(unsigned short*)pBuff);
    145     pBuff += 2;
    146 
    147     // 名字
    148     for (int i = 0; i<questionCount; i++) {
    149         unsigned char name[256];
    150         int nameLen = 0;
    151 
    152         parseDNSName(buff, pBuff, name, &nameLen);
    153         pBuff += nameLen;
    154         pBuff += 2;
    155 
    156         // 查询类型
    157         unsigned short queryType = ntohs(*((unsigned short*)pBuff));
    158         pBuff += 2;
    159         // 查询类别
    160         unsigned short queryClass = ntohs(*((unsigned short*)pBuff));
    161         pBuff += 2;
    162     }
    163 
    164     // 回答资源记录
    165     for (int i = 0; i<answerCount; i++) {
    166         unsigned char name[256];
    167         int nameLen = 0;
    168 
    169         parseDNSName(buff, pBuff, name, &nameLen);
    170         pBuff += 2;
    171 
    172         unsigned short queryType = ntohs(*((unsigned short*)pBuff));
    173         pBuff += 2;
    174         unsigned short queryClass = ntohs(*((unsigned short*)pBuff));
    175         pBuff += 2;
    176         unsigned int resTTL = ntohl(*((unsigned int*)pBuff));
    177         pBuff += 4;
    178         unsigned short resLen = ntohs(*((unsigned short*)pBuff));
    179         pBuff += 2;
    180 
    181         if (queryType == DNS_TYPE_CNAME) {
    182             unsigned char cname[256];
    183             int cnameLen = 0;
    184 
    185             parseDNSName(buff , pBuff , cname , &cnameLen);
    186         }
    187         else if (queryType == DNS_TYPE_A) {
    188             unsigned char ipData[4];
    189             memset(ipData ,0, sizeof(ipData));
    190 
    191             if (resLen == 4) { 
    192                 memcpy(ipData , pBuff , resLen);
    193 
    194                 in_addr _addr;
    195                 _addr.S_un.S_un_b.s_b1 = ipData[0];
    196                 _addr.S_un.S_un_b.s_b2 = ipData[1];
    197                 _addr.S_un.S_un_b.s_b3 = ipData[2];
    198                 _addr.S_un.S_un_b.s_b4 = ipData[3];
    199 
    200                 string _ip = inet_ntoa(_addr);
    201                 ip->clear();
    202                 ip->insert(0, _ip);
    203             }
    204         }
    205         pBuff += resLen;
    206     }
    207 }
    208 
    209 /**
    210  * 发送DNS请求
    211  */
    212 bool sendDNSRequest(int socketId, struct sockaddr* address, char* sendBuff, int buffLen)
    213 {
    214     // 发送请求
    215     int sendBtyes = sendto(socketId, sendBuff, buffLen, 0, address, sizeof(struct sockaddr));
    216     return sendBtyes >= 0;
    217 }
    218 
    219 /**
    220  * 接受DNS数据
    221  */
    222 bool recvDNSRequest(int socketId, struct sockaddr* address, char* recvBuff, int buffLen)
    223 {
    224     // 接受响应数据
    225     int fromLen = sizeof(struct sockaddr);
    226     int recvBytes = recvfrom(socketId, recvBuff, buffLen, 0, address, &fromLen);
    227     return recvBytes >= 0;
    228 }
    229 
    230 /**
    231  * 通过DNS请求,获取ip地址的点格式
    232  */
    233 bool getIPAddrByDNS(string url, string* ip)
    234 {
    235     int socketId = socket(AF_INET, SOCK_DGRAM, 0);
    236     if (socketId == INVALID_SOCKET) {
    237         return false;
    238     }
    239 
    240     // 生成请求文本
    241     string requestData;
    242     generateDNSRequset(url, &requestData);
    243 
    244     // 初始化DNS服务器的套接字地址
    245     struct sockaddr_in serverAddr;
    246     memset(&serverAddr, 0, sizeof(serverAddr));
    247     serverAddr.sin_family = AF_INET;
    248     serverAddr.sin_addr.S_un.S_addr = inet_addr(DNSServerIPAddr.c_str());
    249     serverAddr.sin_port = htons(DNSServerPort);
    250 
    251     // 发送请求
    252     if (!sendDNSRequest(socketId, (struct sockaddr*)&serverAddr, (char *)requestData.c_str(), requestData.length())) {
    253         return false;
    254     }
    255     
    256     // 接受响应
    257     unsigned char recvBuff[1024];
    258     if (!recvDNSRequest(socketId, (struct sockaddr*)&serverAddr, (char *)recvBuff, sizeof(recvBuff))) {
    259         return false;
    260     }
    261 
    262     // 解析响应数据
    263     parseDNSResponse(recvBuff, ip);
    264     return true;
    265 }

    使用方法:

    // 获取DNS信息
    string host = "www.xiami.com";
    string ip;
     if (!getIPAddrByDNS(host, &ip)) {
        printf("Get ip(%s) from DNS server failed
    ", host.c_str());
        return false;
    }
  • 相关阅读:
    京东饭粒捡漏V1.15
    京东饭粒捡漏V1.14
    京东饭粒捡漏V1.13
    京东饭粒捡漏V1.1.0
    京东饭粒捡漏V1.0.8
    京东饭粒捡漏V1.0.7
    性能瓶颈分析总结
    Jmeter循环控制
    HttpClient接口测试之会话保持
    Jenkins自动部署Tomcat项目
  • 原文地址:https://www.cnblogs.com/iRidescent-ZONE/p/4169348.html
Copyright © 2020-2023  润新知