#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <errno.h>
#include <string.h>
#include <iostream>
using namespace std;
char g_testDomain[32] = "www.baidu.com.";
int g_dstPort = 53;
struct IPHeader
{
unsigned char headerLen:4;
unsigned char version:4;
unsigned char tos; //服务类型
unsigned short totalLen; //总长度
unsigned short id; //标识
unsigned short flagOffset; //3位标志+13位片偏移
unsigned char ttl; //TTL
unsigned char protocol; //协议
unsigned short checksum; //首部检验和
unsigned int srcIP; //源IP地址
unsigned int dstIP; //目的IP地址
};
struct UDPHeader //定义UDP首部
{
unsigned short srcPort; //16位源端口
unsigned short dstPort; //16位目的端口
unsigned short dataLen;//16位UDP包长度
unsigned short checksum;//16位校验和
};
struct DNSHeader
{
unsigned short id;//
unsigned short bitHeader; //协议头
unsigned short questionCount;//请求问题总数
unsigned short answerCount;//回答总数
unsigned short authorityCount;//授权总数
unsigned short additionalCount;//附加总数
};
struct DNSQuery
{
unsigned short queryType; //查询的资源记录类型。
unsigned short queryClass; //指定信息的协议组。
};
struct DNS
{
DNSHeader header;
char* domainStr;
DNSQuery query;
};
enum DNSType //查询的资源记录类型。
{
DNSType_A=0x01,//指定计算机 IP 地址
DNSType_NS=0x02, //指定用于命名区域的 DNS 名称服务器。
DNSType_MD=0x03, //指定邮件接收站(此类型已经过时了,使用MX代替)
DNSType_MF=0x04, //指定邮件中转站(此类型已经过时了,使用MX代替)
DNSType_CNAME=0x05, //指定用于别名的规范名称。
DNSType_SOA=0x06, //指定用于 DNS 区域的“起始授权机构”。
DNSType_MB=0x07, //指定邮箱域名。
DNSType_MG=0x08, //指定邮件组成员。
DNSType_MR=0x09, //指定邮件重命名域名。
DNSType_NULL=0x0A, //指定空的资源记录
DNSType_WKS=0x0B, //描述已知服务。
DNSType_PTR=0x0C, //如果查询是 IP 地址,则指定计算机名;否则指定指向其它信息的指针。
DNSType_HINFO=0x0D, //指定计算机 CPU 以及操作系统类型。
DNSType_MINFO=0x0E, //指定邮箱或邮件列表信息。
DNSType_MX=0x0F, //指定邮件交换器。
DNSType_TXT=0x10, //指定文本信息。
DNSType_UINFO=0x64, //指定用户信息。
DNSType_UID=0x65, //指定用户标识符。
DNSType_GID=0x66, //指定组名的组标识符。
DNSType_ANY=0xFF //指定所有数据类型。
};
enum DNSClass //指定信息的协议组。
{
DNSClass_IN=0x01, //指定 Internet 类别。
DNSClass_CSNET=0x02, //指定 CSNET 类别。(已过时)
DNSClass_CHAOS=0x03, //指定 Chaos 类别。
DNSClass_HESIOD=004,//指定 MIT Athena Hesiod 类别。
DNSClass_ANY=0xFF //指定任何以前列出的通配符。
};
//udp校验和
unsigned short udpChecksum(unsigned short* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;
size -= sizeof(unsigned short);
}
if(size)
{
cksum += *(unsigned char*)buffer;
}
cksum = (cksum>>16) + (cksum&0xffff); //将高16bit与低16bit相加
cksum += (cksum>>16); //将进位到高位的16bit与低16bit 再相加
return (unsigned short)(~cksum);
}
//ip数字转字符串
void ipLLToStr(long long ip_num,char* ip_str)
{
unsigned int iptok1 = (ip_num & 0xFF000000) >> 24;
unsigned int iptok2 = (ip_num & 0x00FF0000) >> 16;
unsigned int iptok3 = (ip_num & 0x0000FF00) >> 8;
unsigned int iptok4 = ip_num & 0x000000FF;
char ip[32];
bzero(ip,sizeof(ip));
snprintf(ip,sizeof(ip),"%d.%d.%d.%d",iptok1,iptok2,iptok3,iptok4);
strcpy(ip_str,ip);
}
//发送DNS报文
void sendDnsPacket(int sockfd,sockaddr_in* dstAddr,bool useEDns)
{
char sendBuf[1024] = "";
DNS requestDNS;
bzero(&requestDNS,sizeof(requestDNS));
int domainLen = strlen(g_testDomain)+1;
int dnsDataLen = sizeof(requestDNS.header)+sizeof(requestDNS.query)+domainLen;
int totalLen = sizeof(IPHeader) + sizeof(UDPHeader) + dnsDataLen;
int pos = 0;
IPHeader* ipHeader = (IPHeader *)sendBuf;
ipHeader->headerLen = sizeof(IPHeader)>>2;
ipHeader->version = IPVERSION;
//服务类型
ipHeader->tos = 0;
ipHeader->totalLen = totalLen;
ipHeader->id=0;
//设置flag标记为0
ipHeader->flagOffset=0;
//运用的协议为DNS协议
ipHeader->protocol=IPPROTO_UDP;
//一个封包在网络上可以存活的时间
ipHeader->ttl=64;
//目的地址
//ipHeader->srcIP = inet_addr("1.1.1.1"); //如果想要伪造源IP的话...
ipHeader->dstIP = dstAddr->sin_addr.s_addr;
pos = sizeof(IPHeader);
UDPHeader* udpHeader = (UDPHeader*)(sendBuf+pos);
udpHeader->srcPort = htons(21000);
udpHeader->dstPort = htons(g_dstPort);
udpHeader->dataLen = htons(totalLen-sizeof(IPHeader));
pos+= sizeof(UDPHeader);
requestDNS.header.id = 10;
requestDNS.header.bitHeader = htons(0x0100);
requestDNS.header.questionCount = htons(1);
if(useEDns){
requestDNS.header.additionalCount = htons(1);
}
requestDNS.domainStr = new char[domainLen];
bzero(requestDNS.domainStr,domainLen);
char *priorPtr = g_testDomain;
char *currPtr = strstr(g_testDomain,".");
int dotPos = 0;
while(currPtr!=NULL)
{
int size = currPtr - priorPtr;
requestDNS.domainStr[dotPos] = size;
dotPos++;
memcpy(requestDNS.domainStr+dotPos,priorPtr,size);
dotPos += size;
currPtr++;
priorPtr = currPtr;
currPtr = strstr(g_testDomain+dotPos,".");
if(currPtr==NULL)
{
size = strlen(g_testDomain) - dotPos;
requestDNS.domainStr[dotPos] = size;
dotPos++;
memcpy(requestDNS.domainStr+dotPos,priorPtr,size);
requestDNS.domainStr[domainLen-1] = '\0';
}
}
requestDNS.query.queryType = htons(1);
requestDNS.query.queryClass = htons(1);
memcpy(sendBuf+pos,&requestDNS.header,sizeof(requestDNS.header));
pos += sizeof(requestDNS.header);
memcpy(sendBuf+pos,requestDNS.domainStr,domainLen);
pos += domainLen;
memcpy(sendBuf+pos,&requestDNS.query,sizeof(requestDNS.query));
udpHeader->checksum = udpChecksum((unsigned short*)(sendBuf+sizeof(IPHeader) + sizeof(UDPHeader)), dnsDataLen);
if(sendto(sockfd,sendBuf,totalLen,0,(struct sockaddr *)dstAddr,sizeof(*dstAddr))<0){
perror("sendto error");
}
}
//解析dns result
bool decodeDNSResult(const char *buf, int& index,char* dst)
{
if (buf == NULL){
return false;
}
int i = 0;
unsigned char len = 0;
bool skip0x = true;
while ( (len = buf[index]) != 0x00)
{
if ((len & 0xc0) == 0) //普通格式,LabelDataLen + Label
{
index++;//跳过len
memcpy(dst+i,buf+index,len);
i += len;
index += len;
strcat(dst,".");
i++;
continue;
}
//消息压缩格式,11000000 00000000,两个字节,前2位为跳转标志,后14位为跳转的偏移
short test = 0;
memcpy(&test,buf+index,2);
int jumpIndex = ntohs(test) & 0x3fff;
index++;
index++;//跳过len
skip0x = false;
if (!decodeDNSResult(buf,jumpIndex,dst+i)){
return false;
}
break;
}
if(skip0x){
index++;//跳过0x00
}
return true;
}
//解析dns question
void parseDNSQuestion(const char* recvBuf,int& pos,int questionCount)
{
char contentStr[2048] = "";
for(int i = 0;i<questionCount;i++)
{
//domain
char tmp[512];
bzero(tmp,sizeof(tmp));
decodeDNSResult(recvBuf,pos,tmp);
//query type
unsigned short queryType = 0;
memcpy(&queryType,recvBuf+pos,sizeof(queryType));
pos += sizeof(queryType);
queryType = ntohs(queryType);
//query class
unsigned short queryClass = 0;
memcpy(&queryClass,recvBuf+pos,sizeof(queryClass));
pos += sizeof(queryClass);
queryClass = ntohs(queryClass);
char tmpStr[1024] = "";
snprintf(tmpStr,sizeof(tmpStr),"%s type:%d class:%d\n",tmp,queryType,queryClass);
strcat(contentStr,tmpStr);
}
if(questionCount>0){
cout << contentStr << endl;
}
}
//解析dns结果
void parseResult( const char *recvBuf, int &pos,int count)
{
char contentStr[2048] = "";
for(int i=0;i<count;i++)
{
//domain
char domainStr[512];
bzero(domainStr,sizeof(domainStr));
decodeDNSResult(recvBuf,pos,domainStr);
//answer type
unsigned short dnsType = 0;
memcpy(&dnsType,recvBuf+pos,sizeof(dnsType));
pos += sizeof(dnsType);
dnsType = ntohs(dnsType);
//answer class
unsigned short dnsClass = 0;
memcpy(&dnsClass,recvBuf+pos,sizeof(dnsClass));
pos += sizeof(dnsClass);
dnsClass = ntohs(dnsClass);
//answer ttl
int dnsTTL = 0;
memcpy(&dnsTTL,recvBuf+pos,sizeof(dnsTTL));
pos += sizeof(dnsTTL);
dnsTTL = ntohl(dnsTTL);
//answer data len
unsigned short answerDataLen = 0;
memcpy(&answerDataLen,recvBuf+pos,sizeof(answerDataLen));
pos += sizeof(answerDataLen);
answerDataLen = ntohs(answerDataLen);
//ip cname
char tmpStr[1024] = "";
if(dnsType==DNSType_A)
{
unsigned long ip = 0;
memcpy(&ip,recvBuf+pos,sizeof(ip));
pos += sizeof(ip);
ip = ntohl(ip);
char ipStr[32];
bzero(ipStr,sizeof(ipStr));
ipLLToStr(ip,ipStr);
snprintf(tmpStr,sizeof(tmpStr),"%s ttl:%d type:%d class:%d %s\n",domainStr,dnsTTL,dnsType,dnsClass,ipStr);
strcat(contentStr,tmpStr);
}else if(dnsType==DNSType_CNAME||dnsType==DNSType_NS)
{
char cname[512];
bzero(cname,sizeof(cname));
decodeDNSResult(recvBuf,pos,cname);
snprintf(tmpStr,sizeof(tmpStr),"%s ttl:%d type:%d class:%d %s\n",domainStr,dnsTTL,dnsType,dnsClass,cname);
strcat(contentStr,tmpStr);
}
}
if(count>0){
cout << contentStr << endl;
}
}
//解析dns包
void parseDnsPacket(int sockfd,sockaddr_in* dstAddr)
{
char recvBuf[10240] = "";
socklen_t cliLen = sizeof(dstAddr);
int recvLen = recvfrom(sockfd,recvBuf,sizeof(recvBuf),0,(sockaddr*)&dstAddr,&cliLen);
if( recvLen > 0)
{
int pos = 0;
IPHeader* ipHeader = (IPHeader *)recvBuf;
pos += sizeof(IPHeader);
char srcIPStr[64] = "",dstIPStr[64]="";
ipLLToStr(ntohl(ipHeader->srcIP),srcIPStr);
ipLLToStr(ntohl(ipHeader->dstIP),dstIPStr);
int totalLen = ntohs(ipHeader->totalLen);
char ipHeaderStr[256] = "";
snprintf(ipHeaderStr,sizeof(ipHeaderStr),"response ip header info: version:%d,tos:%d,protocol:%d,ttl:%d,srcIP:%s,dstIP:%s,totalLen:%d"
,ipHeader->version,ipHeader->tos,ipHeader->protocol,ipHeader->ttl,srcIPStr,dstIPStr,totalLen);
cout << ipHeaderStr << endl;
UDPHeader* udpHeader = (UDPHeader*)(recvBuf+pos);
pos += sizeof(UDPHeader);
unsigned short udpSrcPort = ntohs(udpHeader->srcPort);
unsigned short udpDstPort = ntohs(udpHeader->dstPort);
unsigned short udpLen = ntohs(udpHeader->dataLen);
char udpHeaderStr[256] = "";
snprintf(udpHeaderStr,sizeof(udpHeaderStr),"response udp header:srcPort:%d,dstPort:%d,udpLen:%d",udpSrcPort,udpDstPort,udpLen);
cout << udpHeaderStr << endl;
DNSHeader* dnsHeader = (DNSHeader*)(recvBuf+pos);
dnsHeader->bitHeader = ntohs(dnsHeader->bitHeader);
dnsHeader->answerCount = ntohs(dnsHeader->answerCount);
dnsHeader->additionalCount = ntohs(dnsHeader->additionalCount);
dnsHeader->authorityCount = ntohs(dnsHeader->authorityCount);
dnsHeader->questionCount = ntohs(dnsHeader->questionCount);
int dnsStartPos = sizeof(DNSHeader);
//解析question
parseDNSQuestion(recvBuf+pos,dnsStartPos,dnsHeader->questionCount);
//解析answer
parseResult(recvBuf+pos,dnsStartPos,dnsHeader->answerCount);
//解析授权
parseResult(recvBuf+pos,dnsStartPos,dnsHeader->authorityCount);
//解析additional
parseResult(recvBuf+pos,dnsStartPos,dnsHeader->additionalCount);
}
}
int main()
{
int sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
if( sockfd < 0)
{
cout << strerror(errno) << endl;
return -1;
}
int bufSize=50*1024;
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&bufSize,sizeof(bufSize) );
//IPPROTO_TP说明用户自己填写IP报文
//IP_HDRINCL表示由内核来计算IP报文的头部校验和,和填充那个IP的id
int on = 1;
setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
char dstStr[32] = "114.114.114.114";
sockaddr_in dstAddr;
bzero(&dstAddr,sizeof(dstAddr));
dstAddr.sin_family=AF_INET;
dstAddr.sin_addr.s_addr = inet_addr(dstStr);
dstAddr.sin_port = htons(g_dstPort);
sendDnsPacket(sockfd,&dstAddr,false);
parseDnsPacket(sockfd,&dstAddr);
close(sockfd);
return 0;
}
response ip header info: version:4,tos:0,protocol:17,ttl:142,srcIP:114.114.114.114,dstIP:172.16.96.52,totalLen:118
response udp header:srcPort:53,dstPort:21000,udpLen:98
www.baidu.com. type:1 class:1
www.baidu.com. ttl:0 type:5 class:1 www.a.shifen.com.
www.a.shifen.com. ttl:164 type:1 class:1 220.181.112.244
www.a.shifen.com. ttl:164 type:1 class:1 220.181.111.188
分享到:
相关推荐
| | |---EXAM12: C示例源程序,CH395 演示ICMP PING 功能,主动发送PING包以及回复PING包 | | |---EXAM15: C示例源程序,CH395 演示搜索配置功能,配合上位机软件CH395CFG.exe,演示CH395模块搜索配置过程 | | | ...
� Google 提供了一套 Java 核心包 (J2SE 5,J2SE 6) 的有限子集,尚不承诺遵守 Java 任何 Java 规范 , 可能会造 成J ava 阵营的进一步分裂。 � 现有应用完善度不太够,需要的开发工作量较大。--------------------...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
14.3.2 DNS响应报文中的资源记录部分 147 14.4 一个简单的例子 147 14.5 指针查询 150 14.5.1 举例 151 14.5.2 主机名检查 151 14.6 资源记录 152 14.7 高速缓存 153 14.8 用UDP还是用TCP 156 14.9 另一个例子 156 ...
如果发行版安装了自动挂装包,那么这个步骤可自动进行。在Linux中,如果要使用硬盘、光驱等储存设备,就得先将它加载,当储存设备挂上了之后,就可以把它当成一个目录来访问。挂上一个设备使用mount命令。在使用...