rawsocket发送dns包


#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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值