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- ...
随机推荐
- SVN设置实例
D:\scmserver\SVNROOT\safeControl,该SVN项目下,有erSystem和hcSystem两个项目.现在人员有两种类型的人,一个内部人员,一个是佰钧成人员. 设置要求: 1 ...
- 兼容所有浏览器---无缝上下左右交叉运动----原生js+css
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Akka(一) - akka的wordcount
1. 启动类 object Application extends App{ val _system = ActorSystem("HelloAkka") //构建akka容器 v ...
- MVC controller and View
actionresult,jsonresult redirectresult partialview, viewdata, tempdata filter viewdata,只能在当前action中有 ...
- solr基于tomcat增加主界面登录权限
tomcat-user.xml增加下面标签(用户名,密码,角色)<user username="admin" password="new-password" ...
- Shell_Oracle Erp基于主机文件Host开发详解(案例)
2014-06-20 Created By BaoXinjian
- CF 120F Spider 树的直径 简单题
一个男孩有n只玩具蜘蛛,每只蜘蛛都是一个树的结构,现在男孩准备把这n只小蜘蛛通过粘贴节点接在一起,形成一只大的蜘蛛.大的蜘蛛也依然是树的结构.输出大的蜘蛛的直径. 知识: 树的直径是指树上的最长简单路 ...
- [实变函数]5.1 Riemann 积分的局限性, Lebesgue 积分简介
1 Riemann 积分的局限性 (1) Riemann 积分与极限的条件太严: $$\bex f_k\rightrightarrows f\ra \lim \int_a^b f_k ...
- 图片--android 图片占用内存与什么有关
原文链接:http://blog.csdn.net/zjl5211314/article/details/7041813 在开发手机应用的时候,内存是有限的,那使用的时候,就要合理的运用和释放. 那么 ...
- JAVA取随机数,石头剪刀布实例
一.取随机数: import java.util.Random; //导入随机数 public class Test{ public static void main(String[] args){ ...