根据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; }