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

DNS协议 实践的更多相关文章

  1. 美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

    本文引用了颜向群发表于高可用架构公众号上的文章<聊聊HTTPS环境DNS优化:美图App请求耗时节约近半案例>的部分内容,感谢原作者. 1.引言 移动互联网时代,APP 厂商之间的竞争非常 ...

  2. 利用WireShark进行DNS协议分析

    一.准备工作 系统是Windows 8.1Pro 分析工具是WireShark1.10.8 Stable Version 使用系统Ping命令发送ICMP报文. 二.开始工作 打开CMD.exe键入: ...

  3. 计算机网络——DNS协议的学习与实现

    1. 主要内容 不说废话,直接进入正题.先说说本文本文的主要内容,好让你决定是否看下去: 介绍DNS是干什么的: 介绍DNS是如何工作的: 介绍DNS请求与响应的消息格式: 编程实现一个简单的DNS服 ...

  4. 网络协议 16 - DNS 协议:网络世界的地址簿

    [前五篇]系列文章传送门: 网络协议 11 - Socket 编程(下):眼见为实耳听为虚 网络协议 12 - HTTP 协议:常用而不简单 网络协议 13 - HTTPS 协议:加密路上无尽头 网络 ...

  5. IP、TCP、DNS协议

    ·······················································IP协议························· 位于网络层,作用是把数据包传送 ...

  6. 简单谈谈DNS协议

    DNS协议也可以称为DNS服务,全称是Domain Name System,即域名系统,和HTTP协议一样,也是一个位于应用层的协议(服务),它是基于运输层的UDP协议的,关于网络协议的分层介绍,见这 ...

  7. DNS协议工作过程;DNS的安全隐患

    DNS协议工作过程   下面以域名为m.xyz.com的主机欲通过另一个主机的域名y.abc.com的IP地址为例,简述DNS协议过程. 主机m.xyz.com先向其本地服务器dns.xyz.com进 ...

  8. DNS协议详解

    DNS协议详解 简介 DNS(Domain Name System)域名系统,主要实现的功能是将域名转换成ip地址的一个服务.它是由一个分层的DNS服务器实现的分布式数据库,同时.他也是一个使得主机能 ...

  9. 应用层协议FTP、DNS协议、HTTP协议分析

    分析所用软件下载:Wireshark-win32-1.10.2.exe 一.阅读导览 1.分析FTP协议 2.分析DNS协议 3. 分析HTTP协议 二.分析要求 (1)ftp部分: 学习 Serv- ...

随机推荐

  1. windows mobile仿真器内存调整

    1.打开VS,进入工具,选项. 2.点击设备,在右侧选中要调整的模拟器,点属性. 3.点击仿真器选项. 4.勾选 指定RAM大小. 5.重启仿真管理器.

  2. TMS320C54x系列DSP的CPU与外设——第5章 数据寻址

    第5章 数据寻址 C54x DSP提供7种基本寻址方式. ■ Immediate addressing uses the instruction to encode a fixed value.    ...

  3. [OpenGL ES 03]3D变换:模型,视图,投影与Viewport

    [OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循“署名-非商业用途-保持一致”创作公用协议 系列 ...

  4. c++101rule

    组织策略0,不拘于小结缩进, 行的长度,命名,注释,空格,制表,1-4,高警告级别干净利落地进行编译,使用构建系统,使用版本控制,代码审查风格5,一个实体应该只有一个紧凑的职责. (依赖性管理,继承, ...

  5. Form_Form与OAF页面互相调用(案例)

    2014-12-27 Created By BaoXinjian

  6. CF 219D Choosing Capital for Treeland 树形DP 好题

    一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) ...

  7. python深入走路

    Python描述符(descriptor)解密 http://www.geekfan.net/7862/

  8. linux命令(4):top 命令(性能分析工具)

    linux 的top命令详解 简介 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器. top显示系统当前的进程和其他状况,是一个 ...

  9. 你应该知道的jQuery技巧

    帮助提高你jQuery应用的简单小技巧. 回到顶部按钮 图片预加载 判断图片是否加载完 自动修补破损图像 Hover切换class类 禁用输入 停止正在加载的链接 toggle fade/slide ...

  10. label 行距

    NSMutableAttributedString * attributedString1 = [[NSMutableAttributedString alloc] initWithString:te ...