#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
rawsocket发送dns包
猜你喜欢
转载自xiangjie88.iteye.com/blog/2393233
今日推荐
周排行