DNS协议解析

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值