dns解析host和IP

dns.h

#ifndef _DNS_H_
#define _DNS_H_

#define DBG_PRINT 0
#define DNS_PORT   53
#define MAX_DOMAIN 256

#define DNS_TYPE_A      1       //ipv4
#define DNS_TYPE_CNAME  5       //cname
#define DNS_TYPE_AAAA   28      //ipv6
#define DNS_MAX_IPNUM   10

typedef struct{
    unsigned short id;
    unsigned short flags;
    unsigned short qry_cnt;
    unsigned short ans_cnt;
    unsigned short auth_cnt;
    unsigned short add_cnt;
}dns_hdr;

int dns_parse(Packet *p);

int dns_parse_query(Flow* f, unsigned char* pdata, unsigned short int pktlen, dns_hdr dnsh);

int dns_parse_response(Flow* f, unsigned char* pdata, unsigned short int pktlen, dns_hdr dnsh);

dns.c

#include "dns.h"
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int dns_parse(Packet *p)
{
    unsigned char* pdata = p->payload;
    unsigned short int pktlen = p->payload_len;
	Flow* f = p->flow; 
	int ret;
    dns_hdr dnsh;
    unsigned char qrtype;
    unsigned char opcode;
    unsigned char zflag;
	unsigned char rcode;

    if (f == NULL)
    {
        if (DBG_PRINT) printf("The Dns Packet has no flow!\n");
        return -1;
    }

    if (pktlen < 20)
    {
        if (DBG_PRINT) printf("The Dns Packet is too small!\n");
        return -1;
    }

    dnsh.id = ntohs(*((unsigned short *)(pdata)));
    dnsh.flags = ntohs(*((unsigned short *)(pdata + 2)));
    dnsh.qry_cnt = ntohs(*((unsigned short *)(pdata + 4)));
    dnsh.ans_cnt = ntohs(*((unsigned short *)(pdata + 6)));

    qrtype = dnsh.flags & 0x8000;
    opcode = dnsh.flags & 0x7800;
	zflag = dnsh.flags & 0x0040;
	rcode = dnsh.flags & 0x000f;

    if (opcode != 0)
    {
        if (DBG_PRINT) printf("The Dns Packet is not a standard query!\n");
        return -1;
    }

    if (zflag ! = 0)
    {
        if (DBG_PRINT) printf("The Dns Packet Z flag is not zero!\n");
        return -1;
    }

    if (qrtype == 0)    //dns request 
    {
        ret = dns_parse_query(f, pdata, pktlen, dnsh);
    }

    if (qrtype == 1 && rcode == 0)    //dns response
    {
        ret = dns_parse_response(f, pdata, pktlen, dnsh);
    }

    return ret;
}

int dns_parse_query(Flow* f, unsigned char* pdata, unsigned short int pktlen, dns_hdr dnsh)
{
    unsigned char* pquery;
	char domain[MAX_DOMAIN];
    unsigned short int qrylen = 0;
	unsigned short int offset = 0;
	unsigned char dmlen = 0;
	unsigned short int qry_type = 0;
	unsigned short int qry_class = 0;

    memset(domain, 0 , MAX_DOMAIN);
    pquery = pdata + 12;    // 12 is dns_hdr length
	qrylen = qrylen + 12;

    if (dnsh.qry_cnt != 1)
    {
        if (DBG_PRINT) printf("The Dns Packet has too many querys!\n");
        return -1;
    }

    /* parse dns request domain name */
    while ((*pquery != 0) && (qrylen < pktlen))
    {
        if (*pquery > 63)
        {
            if (DBG_PRINT) printf("The Dns Packet domain length must lowwer than 63!\n");
            return -1;
        }

        dmlen = *pquery;
        if (qrylen + dmlen + 1 > pktlen)
        {
            if (DBG_PRINT) printf("The Dns Packet domain length too long!\n");
            return -1;
        }

        pquery++;
		qrylen++;
		if ((offset + dmlen + 1) < MAX_DOMAIN)
        {
            memcpy(domain + offset, pquery, dmlen);
            offset += dmlen;
            domain[offset++] = '.';
        }
        else
        {
            if (DBG_PRINT) printf("The Dns Packet domain length must lowwer than 255!\n");
            return -1;
        }

        pquery += dmlen;
        qrylen += dmlen;
    }

    domain[offset - 1] = '\0';
    pquery++;
	qrylen++;
    if (qrylen + 4 > pktlen)
    {
        if (DBG_PRINT) printf("The Dns Packet domain has no type and class!\n");
        return -1;
    }
	/* parse dns request type and class */
    qry_type = ntohs(*((unsigned short *)(pquery)));
    qry_class = ntohs(*((unsigned short *)(pquery + 2)));
    if (qry_type != 1 || qry_class != 1)
    {
        if (DBG_PRINT) printf("The Dns Packet type or class is wrong!\n");
        return -1;
    }
    /* store dns request state in Flow node, we can check the state with response packet */
    f->dns_id = dnsh.id;
	f->dns_domain = (unsigned char *)malloc(MAX_DOMAIN);
    memcpy(f->dns_domain, domain, offset);
	f->dns_dmlen = offset;

    return 0;
}

int dns_parse_response(Flow* f, unsigned char* pdata, unsigned short int pktlen, dns_hdr dnsh)
{
    unsigned char* pquery;
	char domain[MAX_DOMAIN];
    unsigned short int qrylen = 0;
	unsigned short int offset = 0;
	unsigned char dmlen = 0;
	unsigned short int qry_type = 0;
	unsigned short int qry_class = 0;
	unsigned short int q = 0;
	unsigned short int ans_type = 0;
	unsigned short int ans_class = 0;
	unsigned int ans_ttl = 0;
	unsigned short int ans_len = 0;

	if (dnsh.id != f->dns_id)
	{
        if (DBG_PRINT) printf("The Dns request txid is different with response txid!\n");
        return -1;
	}

    memset(domain, 0 , MAX_DOMAIN);
    pquery = pdata + 12;    // 12 is dns_hdr length
	qrylen = qrylen + 12;

    if (dnsh.qry_cnt != 1)
    {
        if (DBG_PRINT) printf("The Dns Packet has too many querys!\n");
        return -1;
    }

    /* parse dns request domain name */
    while ((*pquery != 0) && (qrylen < pktlen))
    {
        if (*pquery > 63)
        {
            if (DBG_PRINT) printf("The Dns Packet domain length must lowwer than 63!\n");
            return -1;
        }

        dmlen = *pquery;
        if (qrylen + dmlen + 1 > pktlen)
        {
            if (DBG_PRINT) printf("The Dns Packet domain length too long!\n");
            return -1;
        }

        pquery++;
		qrylen++;
		if ((offset + dmlen + 1) < MAX_DOMAIN)
        {
            memcpy(domain + offset, pquery, dmlen);
            offset += dmlen;
            domain[offset++] = '.';
        }
        else
        {
            if (DBG_PRINT) printf("The Dns Packet domain length must lowwer than 255!\n");
            return -1;
        }

        pquery += dmlen;
        qrylen += dmlen;
    }

    domain[offset - 1] = '\0';
    pquery++;
	qrylen++;
    if (qrylen + 4 > pktlen)
    {
        if (DBG_PRINT) printf("The Dns Packet domain has no type and class!\n");
        return -1;
    }
	/* parse dns request type and class */
    qry_type = ntohs(*((unsigned short *)(pquery)));
    qry_class = ntohs(*((unsigned short *)(pquery + 2)));
    if (qry_type != 1 || qry_class != 1)
    {
        if (DBG_PRINT) printf("The Dns Packet type or class is wrong!\n");
        return -1;
    }

    pquery += 4;
	qrylen += 4;
    /* parse dns response domain IP address */
    for (q = 0; q < dnsh.ans_cnt && q < DNS_MAX_IPNUM; q++)
    {
        if (qrylen + 2 > pktlen)
        {
            if (DBG_PRINT) printf("The Dns Packet response answer domain name is too small!\n");
            return -1;
        }

        if (*pquery != 0xc0))
        {
            if (DBG_PRINT) printf("The Dns Packet response answer domain name is wrong!\n");
            return -1;
        }

		pquery += 2;
        qrylen += 2;
        if (qrylen + 10 > pktlen)
        {
            if (DBG_PRINT) printf("The Dns Packet response answer has no RR header!\n");
            return -1;
        }

        ans_type = ntohs(*((unsigned short *)(pquery)));
        ans_class = ntohs(*((unsigned short *)(pquery + 2)));
        ans_ttl = ntohl(*((unsigned int *)(pquery + 4)));
        ans_len = ntohs(*((unsigned short *)(pquery + 8)));

		if (ans_class != 1)
        {
            if (DBG_PRINT) printf("The Dns Packet response class is wrong!\n");
            return -1;
        }

		pquery += 10;
        qrylen += 10;
        if (qrylen + ans_len > pktlen)
        {
            if (DBG_PRINT) printf("The Dns Packet response answer RR length is too small!\n");
            return -1;
        }

        if (ans_type == 1 && ans_len == 4)
        {
            f->dns_ip[q] = ntohl(*((unsigned int *)(pquery)));
        }

        pquery += ans_len;
        qrylen += ans_len;
    }

    return 0;
}



猜你喜欢

转载自blog.csdn.net/superbfly/article/details/80307196