DNS协议 实践
根据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协议 实践的更多相关文章
- 美图App的移动端DNS优化实践:HTTPS请求耗时减小近半
本文引用了颜向群发表于高可用架构公众号上的文章<聊聊HTTPS环境DNS优化:美图App请求耗时节约近半案例>的部分内容,感谢原作者. 1.引言 移动互联网时代,APP 厂商之间的竞争非常 ...
- 利用WireShark进行DNS协议分析
一.准备工作 系统是Windows 8.1Pro 分析工具是WireShark1.10.8 Stable Version 使用系统Ping命令发送ICMP报文. 二.开始工作 打开CMD.exe键入: ...
- 计算机网络——DNS协议的学习与实现
1. 主要内容 不说废话,直接进入正题.先说说本文本文的主要内容,好让你决定是否看下去: 介绍DNS是干什么的: 介绍DNS是如何工作的: 介绍DNS请求与响应的消息格式: 编程实现一个简单的DNS服 ...
- 网络协议 16 - DNS 协议:网络世界的地址簿
[前五篇]系列文章传送门: 网络协议 11 - Socket 编程(下):眼见为实耳听为虚 网络协议 12 - HTTP 协议:常用而不简单 网络协议 13 - HTTPS 协议:加密路上无尽头 网络 ...
- IP、TCP、DNS协议
·······················································IP协议························· 位于网络层,作用是把数据包传送 ...
- 简单谈谈DNS协议
DNS协议也可以称为DNS服务,全称是Domain Name System,即域名系统,和HTTP协议一样,也是一个位于应用层的协议(服务),它是基于运输层的UDP协议的,关于网络协议的分层介绍,见这 ...
- DNS协议工作过程;DNS的安全隐患
DNS协议工作过程 下面以域名为m.xyz.com的主机欲通过另一个主机的域名y.abc.com的IP地址为例,简述DNS协议过程. 主机m.xyz.com先向其本地服务器dns.xyz.com进 ...
- DNS协议详解
DNS协议详解 简介 DNS(Domain Name System)域名系统,主要实现的功能是将域名转换成ip地址的一个服务.它是由一个分层的DNS服务器实现的分布式数据库,同时.他也是一个使得主机能 ...
- 应用层协议FTP、DNS协议、HTTP协议分析
分析所用软件下载:Wireshark-win32-1.10.2.exe 一.阅读导览 1.分析FTP协议 2.分析DNS协议 3. 分析HTTP协议 二.分析要求 (1)ftp部分: 学习 Serv- ...
随机推荐
- .NET常用方法——邮件发送
邮件发送类文件,可直接使用: 调用方法(实例化.静态调用): 实例化: string exception = ""; SendEmail.SendEmail SE = new Se ...
- oracle imp导入数据到另一个表空间
http://blog.163.com/darlingchenlin@126/blog/static/7156283420100531431855/ 1.在第一个数据库导出数据:qlyg_xs_db_ ...
- TMS320C54x系列DSP的CPU与外设——第2章 TMS320C54x DSP体系结构总体介绍
第2章 TMS320C54x DSP体系结构总体介绍 本章介绍TMS320C54x DSP体系结构的概况,包括中央处理单元(CPU).存在器和片内外设. C54x DSP采用了高级的改进哈佛结构,用8 ...
- onNewIntent调用时机
在IntentActivity中重写下列方法:onCreate onStart onRestart onResume onPause onStop onDestroy onNewIntent 一 ...
- Java AES加密
Java AES 加密 加密 /** * * @description 加密 * * @param content 需要加密的内容 * @param password 加密密码 * @return * ...
- C# 多线程网络通信
博客园 :梦工厂2012 本月由于事情太多,没能有太多的时间去写博客.不过还好在月底抽时间写了这个多线程网络通信的程序 .程序说明:控制端 创建一个写线程threadWrite和一个读线程thread ...
- Top 6 Programming Languages for Mobile App Development
Mobile application development industry in the last five years have multiplied in leaps and bounds, ...
- java学习日志(1):命令行and小程序
1.dos命令行,常见的命令 dir:列出当前目录下的文件以及文件夹md:创建目录rd:删除目录(必须空)cd:进入指定目录cd.. :退回到上一级目录cd/:退回到根目录del:删除文件exit:退 ...
- UCOS-信号标志组(学习笔记)
信号标志组即根据各任务的信号进行逻辑运算,根据逻辑运算的结果决定是否进行.发送方指定向那个标志组的哪一位(响应位等于1表明向哪一位发)发1还是0.等待逻辑结果的任务指定等待那个标志组的哪几位.这几位按 ...
- 为FaceBook审核提交模拟器包及自己验证模拟器包
为FaceBook审核提交模拟器包及自己验证模拟器包折腾了一番,因为我的项目是用cocoapods管理的,所以跟普通直接运行name.xcodeproj项目有所不同. 切入正题 1.先设置 relea ...