DNS协议解析

来源:互联网 发布:绿榴莲网络班价格 编辑:程序博客网 时间:2024/06/05 17:43

DNS协议解析

项目需要,所以要多DNS协议的报文进行解析。读了《TCP/IP详解 卷1》的关于DNS部分的内容后,开始写代码做解析。

参考资料:

http://blog.163.com/libo_5/blog/static/1569685201031433013508/
http://libo.deng.blog.163.com/blog/static/401574222007850244930/

代码:

void GetDNSHost(unsigned char * pDataChar, int begin, char *host){    unsigned char *p = pDataChar+begin;    int len = *p;    while(len) {        if ((*p & 0xC0) == 0xC0)  // 如果是一个压缩指针        {            len = ntohs(*(unsigned short *) p);            len = len & 0x03FFF;            GetDNSHost(pDataChar, len, host);            break;        }        else {            len = *p;            strncpy(host, (char*)p+1, len);            strcpy(host+len, "."); // 将数字替换为点。 这样简单处理的后果是域名最后会有一个点。            p = p + len +1 ;            host = host + len + 1;        }        len = *p;    }}

主代码,不是完整代码,只是项目代码一部分的简化版本

// dns    if( (sport == 53 || dport == 53) && (pTransPacket->nPacketType == IPPROTO_UDP) ) {        if (pTransPacket->nDataLen <= 12)            return 0;        // 分析报文头部        unsigned char *pDataChar = pTransPacket->pDataChar; // 报文数据        DNSPacket *dnsPacket = (DNSPacket * )(pDataChar);        unsigned short id = ntohs(dnsPacket->id);        unsigned short sign = ntohs(dnsPacket->sign);        unsigned short qdCount = ntohs(dnsPacket->qdCount); // 问题数        unsigned short anCount = ntohs(dnsPacket->anCount); // 回答数        unsigned short nsCount = ntohs(dnsPacket->nsCount); // 授权资源记录数        unsigned short arCount = ntohs(dnsPacket->arCount); // 额外资源记录数        int curLen = 12; // 当前分析位置, 头部分析完成,共12字节        if ((sign & 0x8000) == 0)  // 查询报文        {            // 分析第一个问题,一般都只有一个问题            char hostname[256];            GetDNSHost(pDataChar, curLen, hostname);            // debug info            {                printf("DNS REQUEST:\n");                printf("id: %4X\nsign:%4X\n问题数:%u\n回答数:%u\n授权资源记录数:%u\n额外资源记录书:%u\n", id, sign, qdCount, anCount,                       nsCount, anCount);                printf("询问host: %s\n\n", hostname);            }        }        else  // 响应报文        {/*            // 调试使用,将所有响应报文打印出来            {                printf("响应报文内容:\n");                for(int i = 0;i<pTransPacket->nDataLen;i++)                {                    if(i%4==0 && i!=0)                        printf("\n");                    printf("%02X ",pTransPacket->pDataChar[i]);                }                printf("\n");            }*/            // debug info            {                printf("DNS RESPONSE:\n");                printf("id: %4X\nsign:%4X\n问题数:%u\n回答数:%u\n授权资源记录数:%u\n额外资源记录书:%u\n", id, sign, qdCount, anCount,                       nsCount, anCount);            }            // 响应报文的查询问题            {                // 查询问题字段格式: 查询名 + 查询类型(2字节)+ 查询类(2字节)                char hostname[256];                GetDNSHost(pDataChar, curLen, hostname);                printf("响应问题: %s\n", hostname);                curLen += strlen(hostname) + 1 + 4; // 响应报文的查新问题字段一般不会又压缩的,内容长度为 host长度+1 +查询类型(2字节)+查询类(2字节)            }            // 响应报文的回答格式            // 域名(不定字节) + 查询类型(2字节)+ 查询类(2字节)+ 生存时间(4字节)+ 资源数据长度(2字节)+ 资源数据(长度由前一个字段确定)            // 其中域名一般为压缩方式,指向上一个问题或者回答的域名,一般2个字节            {                for (int i = 0; i < anCount; i++) // 分析每一个回答                {                    // 域名                    char hostname[256];                    GetDNSHost(pDataChar, curLen, hostname);                    printf("回答%d: %s----", i, hostname);                    uint16_t dns_type = ntohs(*(unsigned short *) (pDataChar + curLen + 2));                    uint16_t dns_class = ntohs(*(unsigned short *) (pDataChar + curLen + 2 + 2));                    uint16_t dns_len = ntohs(*(unsigned short *) (pDataChar + curLen + 2 + 2 + 2 + 4));                    if (dns_type == 1) // 查询类型为A, 是一个4个字节的ip地址                    {                        struct in_addr addr;                        addr.s_addr = *(unsigned int *) (pDataChar + curLen + 2 + 2 + 2 + 4 + 2);                        char *ip = inet_ntoa(addr);                        curLen += 2 + 2 + 2 + 4 + 2 + 4;                        printf("A----ip:%s\n", ip);                    }                    else if (dns_type == 5) // 查询类型为 CNAME, 一个域名                    {                        char hostname[256];                        GetDNSHost(pDataChar, curLen + 2 + 2 + 2 + 4 + 2, hostname);                        printf("CNAME----host: %s\n", hostname);                        curLen += 12 + dns_len;                    }                }                printf("\n");            }        }    }
0 0