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\n", host.c_str());
    return false;
}

 

转载于:https://www.cnblogs.com/iRidescent-ZONE/p/4169348.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值