根据DNS协议发送UDP请求,然后获取IP地址
头文件:
#ifndef __DNS__
#define __DNS__ #include <stdio.h>
#include <stdlib.h>
#include <string>
#include <winsock.h> using namespace std; /**
* 查询类型
*/
#define DNS_TYPE_A 0x01
#define DNS_TYPE_NS 0x02
#define DNS_TYPE_CNAME 0x05
#define DNS_TYPE_SOA 0x06
#define DNS_TYPE_WKS 0x0B
#define DNS_TYPE_PTR 0x0C
#define DNS_TYPE_HINFO 0x0D
#define DNS_TYPE_MX 0x0E
#define DNS_TYPE_AAAA 0x1C
#define DNS_TYPE_AXFR 0xFC
#define DNS_TYPE_ANY 0xFF /**
* 查询类别
*/
#define DNS_CATEGORY_A 0x01
#define DNS_CATEGORY_CSNET 0x02
#define DNS_CATEGORY_CS 0x03
#define DNS_CATEGORY_HS 0x04 // 发送DNS请求的key
static u_short _dnsKey = 0x0000;
// DNS域名服务器地址,这里是通过网卡的属性得到的
static string DNSServerIPAddr = "192.168.105.1";
// DNS域名服务器端口,默认53
static int DNSServerPort = ; /**
* 获取发送的key
*/
u_short getDNSKey(); /**
* 生成请求数据
*/
void generateDNSRequset(string url, string* requestData); /**
* 解析记录中的名字
*/
void parseDNSName(unsigned char* buff, unsigned char* pBuff, unsigned char* name, int* offset); /**
* 解析DNS响应数据
*/
void parseDNSResponse(unsigned char buff, string* ip); /**
* 发送DNS请求
*/
bool sendDNSRequest(int socketId, struct sockaddr* address, char* sendBuff, int buffLen); /**
* 接受DNS数据
*/
bool recvDNSRequest(int socketId, struct sockaddr* address, char* recvBuff, int buffLen); /**
* 通过DNS请求,获取ip地址的点格式
*/
bool getIPAddrByDNS(string url, string* ip); #endif
代码文件:
#include "DNS.h" /**
* 获取发送的key
*/
unsigned short getDNSKey()
{
if (_dnsKey == ) {
_dnsKey = ;
}
return ++_dnsKey;
} /**
* 生成请求数据
*/
void generateDNSRequset(string url, string* requestData)
{
unsigned char request[];
unsigned char* pRequest = request; // key
*((unsigned short*)pRequest) = htons( getDNSKey() );
pRequest += ;
// 标志
*(pRequest++) = 0x01;
*(pRequest++) = 0x00;
// 查询记录数
*((unsigned short*)pRequest) = htons(0x0001);
pRequest += ;
// 资源记录数
*((unsigned short*)pRequest) = htons(0x0000);
pRequest += ;
// 授权资源记录数
*((unsigned short*)pRequest) = htons(0x0000);
pRequest += ;
// 额外资源记录数
*((unsigned short*)pRequest) = htons(0x0000);
pRequest += ; // 填充查询名字
unsigned char* pCount = pRequest++;
int count = ;
for (int i = , len = url.length(); i < len; i++) {
unsigned char ch = url.at(i); if (ch != '.') {
*(pRequest++) = ch;
count++;
}
else {
*pCount = count;
pCount = (pRequest++); count = ;
}
}
*pCount = count;
*(pRequest++) = ; // 查询类型
*((unsigned short*)pRequest) = htons(0x0001);
pRequest += ;
// 查询类别
*((unsigned short*)pRequest) = htons(0x0001);
pRequest += ; int requestLen = pRequest - request;
// 将char数组转换成string
for (int i = ; i<requestLen; i++) {
requestData->push_back(request[i]);
}
} /**
* 解析记录中的名字
*/
void parseDNSName(unsigned char* buff, unsigned char* pBuff, unsigned char* name, int* offset)
{
unsigned char flag;
unsigned char* pName = name + (*offset); do {
flag = *pBuff; if ((flag & 0xC0) == 0xC0) {
unsigned char _offset = *(pBuff + );
pBuff = buff + _offset; parseDNSName(buff, pBuff, name, offset); break;
}
else {
unsigned char _count = *(pBuff++); memcpy(pName, pBuff, _count); pBuff += _count;
pName += _count;
*offset += _count; if (*pBuff != ) {
*(pName++) = '.';
*offset += ;
}
}
}
while (flag != );
} /**
* 解析DNS响应数据
*/
void parseDNSResponse(unsigned char* buff, string* ip)
{
unsigned char* pBuff = buff; // key
unsigned short key = ntohs(*((unsigned short*)pBuff));
pBuff += ;
// 标志
unsigned short remarkLeft = *(pBuff++);
unsigned short remarkRight = *(pBuff++);
unsigned char QR = (remarkLeft & 0x80) >> ;
unsigned char OpCode = (remarkLeft & 0x78) >> ;
unsigned char AA = (remarkLeft & 0x04) >> ;
unsigned char TC = (remarkLeft & 0x02) >> ;
unsigned char RD = (remarkLeft & 0x01);
unsigned char RA = (remarkRight & 0x80) >> ;
unsigned char ZERO = (remarkRight & 0x70) >> ;
unsigned char rCode = (remarkRight & 0x0F);
// 问题记录数
unsigned short questionCount = ntohs(*(unsigned short*)pBuff);
pBuff += ;
// 回答记录数
unsigned short answerCount = ntohs(*(unsigned short*)pBuff);
pBuff += ;
// 授权记录数
unsigned short authCount = ntohs(*(unsigned short*)pBuff);
pBuff += ;
// 附加记录数
unsigned short addiCount = ntohs(*(unsigned short*)pBuff);
pBuff += ; // 名字
for (int i = ; i<questionCount; i++) {
unsigned char name[];
int nameLen = ; parseDNSName(buff, pBuff, name, &nameLen);
pBuff += nameLen;
pBuff += ; // 查询类型
unsigned short queryType = ntohs(*((unsigned short*)pBuff));
pBuff += ;
// 查询类别
unsigned short queryClass = ntohs(*((unsigned short*)pBuff));
pBuff += ;
} // 回答资源记录
for (int i = ; i<answerCount; i++) {
unsigned char name[];
int nameLen = ; parseDNSName(buff, pBuff, name, &nameLen);
pBuff += ; unsigned short queryType = ntohs(*((unsigned short*)pBuff));
pBuff += ;
unsigned short queryClass = ntohs(*((unsigned short*)pBuff));
pBuff += ;
unsigned int resTTL = ntohl(*((unsigned int*)pBuff));
pBuff += ;
unsigned short resLen = ntohs(*((unsigned short*)pBuff));
pBuff += ; if (queryType == DNS_TYPE_CNAME) {
unsigned char cname[];
int cnameLen = ; parseDNSName(buff , pBuff , cname , &cnameLen);
}
else if (queryType == DNS_TYPE_A) {
unsigned char ipData[];
memset(ipData ,, sizeof(ipData)); if (resLen == ) {
memcpy(ipData , pBuff , resLen); in_addr _addr;
_addr.S_un.S_un_b.s_b1 = ipData[];
_addr.S_un.S_un_b.s_b2 = ipData[];
_addr.S_un.S_un_b.s_b3 = ipData[];
_addr.S_un.S_un_b.s_b4 = ipData[]; string _ip = inet_ntoa(_addr);
ip->clear();
ip->insert(, _ip);
}
}
pBuff += resLen;
}
} /**
* 发送DNS请求
*/
bool sendDNSRequest(int socketId, struct sockaddr* address, char* sendBuff, int buffLen)
{
// 发送请求
int sendBtyes = sendto(socketId, sendBuff, buffLen, , address, sizeof(struct sockaddr));
return sendBtyes >= ;
} /**
* 接受DNS数据
*/
bool recvDNSRequest(int socketId, struct sockaddr* address, char* recvBuff, int buffLen)
{
// 接受响应数据
int fromLen = sizeof(struct sockaddr);
int recvBytes = recvfrom(socketId, recvBuff, buffLen, , address, &fromLen);
return recvBytes >= ;
} /**
* 通过DNS请求,获取ip地址的点格式
*/
bool getIPAddrByDNS(string url, string* ip)
{
int socketId = socket(AF_INET, SOCK_DGRAM, );
if (socketId == INVALID_SOCKET) {
return false;
} // 生成请求文本
string requestData;
generateDNSRequset(url, &requestData); // 初始化DNS服务器的套接字地址
struct sockaddr_in serverAddr;
memset(&serverAddr, , sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.S_un.S_addr = inet_addr(DNSServerIPAddr.c_str());
serverAddr.sin_port = htons(DNSServerPort); // 发送请求
if (!sendDNSRequest(socketId, (struct sockaddr*)&serverAddr, (char *)requestData.c_str(), requestData.length())) {
return false;
} // 接受响应
unsigned char recvBuff[];
if (!recvDNSRequest(socketId, (struct sockaddr*)&serverAddr, (char *)recvBuff, sizeof(recvBuff))) {
return false;
} // 解析响应数据
parseDNSResponse(recvBuff, ip);
return true;
}
使用方法:
// 获取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;
}