`

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
分享到:
评论

相关推荐

    Go-raw-能够读写设备驱动程序级别网络接口的数据

    Go标准库中的`syscall`包提供了对操作系统系统调用的直接访问,`raw`包则基于`syscall`提供了对Raw Socket的封装。使用`raw`包,开发者可以创建并接收特定协议(如IP、ICMP等)的数据包。 1. 创建Raw Socket 创建...

    网关基础知识 socket-raw IP-Helper IPv4报头的校验和

    本文将深入探讨网关的基本概念,以及与之相关的socket-raw编程和IP-Helper功能,特别是如何计算IPv4报头的校验和,设置UDP的源端口,以及在Windows系统中捕获IP包。 首先,网关是网络层的一个设备,允许两个不同的...

    基于PHP的DNS检测查询记录php版源码.zip

    dns_get_record($hostname, $type = DNS_ALL, &$authns = NULL, &$addtl = NULL, $raw = false); ``` 其中,$hostname 是要查询的域名,$type 指定要查询的记录类型,DNS_ALL 将获取所有类型的记录。 例如,要查询...

    计算机网络课程设计之Ping程序(含C++原代码和实验报告)

    在RAW模式下,SOCKET可以创建和发送ICMP报文,实现ping功能。 4. **Ping程序的实现**:Ping程序的基本流程包括创建RAW SOCKET,构造ICMP回显请求报文,填充必要的头部信息(如类型、代码、标识符和序列号),然后将...

    [C#通信二]C#.net同步异步SOCKET通讯和多线程总结

    - Raw Socket(原始套接字):允许访问底层协议,具有更大的灵活性。 ### 5. 定义和解析主机 在C#.NET中,可以使用`Dns.Resolve()`或`Dns.GetHostByName()`方法解析主机名,获取`IPHostEntry`对象,其中包含IP地址...

    计算机网络实验题目.pdf

    - 实现DNS解析需要理解DNS报文格式,通过Socket编程发送DNS查询并处理响应。 实验九:仿真telnet - telnet是一个远程登录协议,允许用户通过网络控制远程主机。 - 仿真telnet需要实现实时的字符传输和命令执行,...

    Windows Socket 学习笔记.doc

    3. **原始套接字 (SOCK_RAW)**:原始Socket允许程序员访问网络层,可以接收完整的IP头,包括协议头信息,用于网络诊断、数据分析或实现自定义协议。它可以用来创建TCP、UDP之外的协议,比如ICMP。 在Windows上开发...

    Linux Socket Programming

    - **原始套接字**(Raw Sockets):直接访问底层IP协议,用于发送ICMP或IGMP等特殊类型的包。 3. **地址方案**: - **IPv4**:使用32位地址表示,是当前互联网的主要地址体系。 - **IPv6**:使用128位地址表示,...

    linux/unix抓包工具tcpdump

    首先,tcpdump的工作原理基于网络层的嗅探,它可以捕获通过网络接口发送和接收的所有数据包。通过读取网络设备的原始套接字(raw sockets),tcpdump能够解析并显示不同协议层(如IP、TCP、UDP、ICMP等)的信息。 ...

    通过类调用socket API方法ping远程机器源代码

    self.socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP) ``` 然后,我们需要构建`Echo Request`报文。`ICMP`报文由两部分组成:一个8字节的头部和可变长度的数据部分。对于`ping`,...

    socket总结资料(Linux)

    在实际编程中,我们通常会使用`socket()`函数创建套接字,`bind()`函数绑定本地地址,`listen()`函数等待连接,`accept()`函数接收连接请求,`connect()`函数用于客户端建立连接,`send()`和`recv()`函数用于发送和...

    C#截获本机数据包方法

    在C#中,我们可以使用`System.Net.Sockets.Socket`类来创建原始套接字(Raw Socket),这种类型的套接字允许我们直接与网络层交互,从而能够捕获和发送IP数据包。以下是一个创建原始套接字的基本步骤: 1. 实例化一...

    C++ 实现 ping 功能解析实际 IP地址.rar_ip地址_ping_shinningr77_vc++_域名

    1. 创建一个套接字并将其设置为RAW模式,以便发送ICMP报文。 2. 编组ping请求报文,包括ICMP头部和数据部分。 3. 使用套接字将报文发送到目标IP或通过DNS解析的IP地址。 4. 开始监听回显应答,捕获并解析ICMP回应...

    使用C进行#通讯编程

    - **原始Socket (Raw)**:提供底层网络访问功能,主要用于开发特殊的网络应用。 #### 3. Socket工作流程 1. **创建Socket对象**:根据不同的网络协议选择合适的Socket类型。 2. **绑定地址**:使用`Bind()`方法将...

    NMap使用详解pdf文档

    然而,由于一些底层接口(如raw socket)的限制,完全发挥NMap的潜力仍需root权限。 #### 五、扫描结果解读 NMap扫描后会呈现一份详细的报告,其中包含主机的端口列表及其状态,如open(开放)、filtered(过滤)...

    lwip+udp项目实例

    2. **创建UDP套接字**:通过调用` lwip_socket `函数创建一个套接字,指定协议为` SOCK_DGRAM `(对应UDP)。 3. **绑定端口**:使用` bind `函数将套接字与本地IP地址和端口号关联,以便接收来自特定端口的数据。 ...

    C语言实的串行通信接口程序

    3. Raw Sockets:允许直接访问底层协议,如IP和ICMP,通常用于网络协议的测试和开发。 **面向连接的Socket通信流程** 典型的Socket通信过程包括以下步骤: 1. 客户端和服务器分别创建Socket。 2. 服务器调用bind()...

    ICMP类定义[归类].pdf

    4. 创建一个`Socket`对象,设置为原始套接字(SocketType.Raw),以允许直接操作ICMP数据包。 5. 如果无法解析主机信息,则向`listBox1`添加一条错误消息。 6. 使用`Dns.GetHostEntry`再次获取客户端的主机信息,...

    Ping应用程序实现代码共9页.pdf.zip

    2. **套接字编程**:在大多数操作系统中,Ping 实现通常涉及使用套接字(socket)API,创建一个 RAW 类型的套接字来直接操作 IP 层的数据包。 3. **数据包构造**:编码 ICMP 报文,包括设置正确的类型、代码、校验...

    w5500-5.3.zip

    W5500是一款专为嵌入式系统设计的以太网接口芯片,它内置了SPI(Serial Peripheral Interface)通信接口,支持全双工10/100Mbps以太网速度,具备8个独立的Socket,每个Socket可分别运行TCP、UDP、ICMP和RAW等不同...

Global site tag (gtag.js) - Google Analytics