域名解析-vs2010代码示例

头文件的内容dns.h

/**
 * file dns.h
 * Define the DNS request packet header format.
 * Author : Wen Shifang
 * 2015.8.20
 */

#ifndef __DNS_H__
#define __DNS_H__

#define PLATFORM_WINDOWS   

/* 域名查询请求报文头定义,1字节对齐*/
#if defined(PLATFORM_WINDOWS)
#pragma  pack(push)
#pragma  pack(1)
#endif

struct DnsHeader{
    unsigned short id;

    unsigned char rd:1; /*期望递归解析*/
    unsigned char tc:1;   /*报文未截断 */
    unsigned char aa:1;   /*授权解析服务器 */
    unsigned char opcode:4;/*标准查询 */
    unsigned char qr:1;   /*0:查询,1:响应 */

    unsigned char rcode:4;/*响应吗:0没有出错 */
    unsigned char z:3;    /*保留将来使用 */
    unsigned char ra:1;   /*DNS服务器是否支持递归解析 */

    unsigned short qdCount; /* 问题数*/
    unsigned short anCount; /* 应答数*/
    unsigned short nsCount; /* 授权机构数 */
    unsigned short arCount; /* 附加信息数 */
}
#if defined (PLATFORM_LINUX)
__attribute__(("packed"))
#endif
;

#if defined(PLATFORM_WINDOWS)
#pragma  pack(pop)
#endif

#define COMMENT_MAX 64
#define SYMBOL_MAX  8
struct QueryType
{
    unsigned short q_class;
    unsigned char mnemonic_symbol[SYMBOL_MAX];
    unsigned char comment[COMMENT_MAX];
};

#endif

主文件内容main.c

#include <stdio.h>  
#include <winsock2.h>  
#include "dns.h"

#pragma comment(lib,"ws2_32.lib")  

#define DNS_ADDR  "202.96.134.33"
#define SERVER_PORT 53
#define MAX_TRY_CNT  3

static unsigned short packet_id = 0x55AA;

/* 交换字节序 */
void exchangeByteOrder(unsigned char *byte)
{
    unsigned char temp;

    temp = byte[0];
    byte[0] = byte[1];
    byte[1] = temp;
}

/* 交换一个字的字节顺序 */
void exchangeWordOrder(unsigned int *word)
{
    unsigned char temp;
    unsigned char *ptr[4];

    ptr[0] = (unsigned char *)(word);
    ptr[1] = ((unsigned char *)(word))+1;
    ptr[2] = ((unsigned char *)(word))+2;
    ptr[3] = ((unsigned char *)(word))+3;

    temp = *ptr[0];
    *ptr[0] = *ptr[3];
    *ptr[3] = temp;

    temp = *ptr[1];
    *ptr[1] = *ptr[2];
    *ptr[2] = temp;
}

/* 构造 DNS 请求报文包头(12 bytes) */
int dns_packet_hdr_construct(struct DnsHeader *header)
{
    /* 定义DNS查询报文请求头,没有使用的字段必须设置为0 */
    header->id = packet_id;     /* ID ,由进程任意指定,以作标识 */
    header->rd = 1;             /*期望递归解析*/
    header->tc = 0;
    header->aa = 0;
    header->opcode = 0;         /*标准查询 */
    header->qr = 0;
    header->rcode = 0;
    header->z = 0;
    header->ra = 0;
    header->qdCount = 1;        /*问题数量 */
    header->anCount = 0;
    header->nsCount = 0;
    header->arCount = 0;

    /* 16 bits 的本地格式转换为网络格式 */
    exchangeByteOrder((unsigned char *)&header->anCount);
    exchangeByteOrder((unsigned char *)&header->qdCount);
    exchangeByteOrder((unsigned char *)&header->nsCount);
    exchangeByteOrder((unsigned char *)&header->arCount);

    return sizeof(struct DnsHeader);
}

/* 构造 NDS 请求报文内容 */
int dns_packet_body_construct(char *packet_body, const char *buf)
{
    const char *domain_ptr = buf ;
    int i = 0, j = 0;

    while(*domain_ptr != '\0'){
        if(*domain_ptr != '.'){
            packet_body[i+1] = *domain_ptr;
            j++;
        }else{
            packet_body[i-j] = j;
            j = 0;
        }
        i++; domain_ptr++;
    }
    packet_body[i-j] = j;

    packet_body[++i] = 0;           /* null */
    packet_body[++i] = 0x00;
    packet_body[++i] = 0x01;        /* 查询类型  为 1 : IPv4地址 */

    packet_body[++i] = 0x00;        /* 查询类 为 1 : Inetnet数据 */
    packet_body[++i] = 0x01;

    return i;
}

/**
 * 解析 问题
 * packet:数据包头部指针
 * body:  指向问题域开始部分
 */
const char *dns_packet_question_resovle(const struct DnsHeader *packet, const char *body)
{
    const char *ptr;
    unsigned char cnt = 0;
    unsigned char len = 0;

    printf("the queston:");

    ptr = body;
    while(*ptr != '\0'){
        cnt = *ptr++;
        while(cnt--){
            printf("%c", *ptr);
            ptr++;
        }
        if(*ptr != '\0'){
            printf(".");
        }
    }
    printf("\n");

    ptr++;  /* skip null */
    printf("Type : ");
    if(*ptr == 0x0 && *(ptr+1) == 0x1){
        printf("Host Address\n");
    }else{
        printf("%02x%02x\n",*ptr, *(ptr+1));
    }

    ptr += 2; /* skip Type area */
    printf("Class : ");
    if(*ptr == 0x0 && *(ptr+1) == 0x01){
        printf("IN\n");
    }else{
        printf("%02x%02x\n");
    }

    ptr += 2;  /* skip Class area */

    return ptr;
}

/* 解析名字 */
const char *dns_packet_name_resovle(const struct DnsHeader *packet, const  char *name)
{
    const char *p;
    unsigned char cnt,len;

    p = name;
    len = 0;

    while(*p != '\0'){

        if(((*p & 0xC0) >> 6) == 0x3){

            p = (const char *)packet + (((*p & 0x3F)<<8) | *(p+1)); 

            p = dns_packet_name_resovle(packet, p);

        }else{

            cnt = *p++;
            while(cnt--){
                printf("%c",*p++);
            }

            if(*p != '\0'){
                printf(".");
            }
        }
    }

    return  p;
}

/* 解析资源数据 */
const char *dns_packet_rr_resovle(const struct DnsHeader *packet, const  char *rr, unsigned short rlen)
{
    const char *p;
    unsigned char cnt = 0;

    if(rlen == 0x4){        /* IP addr */
        printf("%d.%d.%d.%d\n", (unsigned char)rr[0],(unsigned char)rr[1],
            (unsigned char)rr[2],(unsigned char)rr[3]);
        return (rr += 4);
    }

    while(rlen > 0){

        if(((*rr & 0xC0) >> 6) == 0x3){
            p = (const char *)packet + ((*rr & 0x3F)<<8 | (*(rr+1)));
            rlen -= 2;
            cnt = *p++;
            rr +=  2;
        }else{
            p = rr;
            cnt = *p++;
            rlen -= ( cnt + 1 );
            rr += ( cnt + 1 );
        }

        while(cnt--){
            printf("%c", *p);
            p++;
        }

        if(rlen != 0){
            printf(".");
        }
    }

    printf("\n");

    return rr;
}

/**
 * 解析 应答
 * packet:数据包头部指针
 * body:  指向应答域开始部分
 */
const char *dns_packet_response_resovle(const struct DnsHeader *packet, const char *body)
{
    const char *ptr;
    unsigned char cnt = 0;
    unsigned char len = 0;
    unsigned int  ttl = 0;
    unsigned short rs_len = 0;

    printf("\nthe answer:\nName : ");

    ptr = dns_packet_name_resovle(packet, body);

    printf("%\n");

    ptr = body + 2;  /* skip null ,Get Type (2 bytes) */
    printf("Type : ");
    if((*ptr == 0x0) && (*(ptr+1) == 0x1)){
        printf("Host Address\n");
    }else if((*ptr == 0x0) && (*(ptr+1) == 0x5)){
        printf("CNAME (Canonical name for an alias)\n");
    }else{
        printf("%02x%02x\n",*ptr, *(ptr+1));
    }

    ptr += 2; /* skip Type area , Get Class (2 bytes) */
    printf("Class : ");
    if(*ptr == 0x0 && *(ptr+1) == 0x01){
        printf("IN\n");
    }else{
        printf("%02x%02x\n");
    }

    ptr += 2;  /* skip Class area ,Get TTL(4 bytes) */
    ttl = *(unsigned int *)(ptr);
    exchangeWordOrder(&ttl);

    printf("TTL(Time To live) :");
    printf("%d\n",ttl);

    ptr += 4;  /* skip TTL area , Get Resource length (2 bytes) */
    rs_len =  *(unsigned short*)(ptr);
    exchangeByteOrder((unsigned char *)&rs_len);
    printf("Data length :");
    printf("%d\n",rs_len );

    ptr += 2;   /* skip Resource length area ,Get Resource Records */
    printf("Data : ");
    ptr = dns_packet_rr_resovle(packet, ptr, rs_len);

    return ptr;
}

/**
 * 解析 授权机构
 * packet:数据包头部指针
 * body:  指向授权机构开始部分
 */
const char * dns_packet_authority_resovle(const struct DnsHeader *packet, const char *body)
{
    return 0;
}

/**
 * 解析 附加信息
 * packet:数据包头部指针
 * body:  指向附加信息域开始部分
 */
const char * dns_packet_addtional_resovle(const struct DnsHeader *packet, const char *body)
{
    return 0;
}


/* 解析 DNS 响应内容 */
int dns_packet_body_resolve(const char *packet)
{
    const struct DnsHeader *header;
    const char *ptr;
    unsigned short cnt;

    header = (struct DnsHeader *)packet;
    ptr = (const char *)header+sizeof(struct DnsHeader);

    printf("Queston count is %d\n", header->qdCount);
    printf("Answer count is %d\n", header->anCount);
    printf("Authoritative count is %d\n", header->nsCount);
    printf("Addtional count is %d\n", header->arCount);

    /* 如果问题数量不为0,则解析问题域 */
    if(header->qdCount > 0){

        cnt = header->qdCount;
        while(cnt--){   
            ptr = dns_packet_question_resovle(header, ptr);
        }
    }

    /* 如果回答数量不为零,则解析回答域 */
    if(header->anCount > 0){

        cnt = header->anCount;
        while(cnt--){
            ptr = dns_packet_response_resovle(header, ptr);
        }
    }

    /* 如果授权机构数不为零,则解析授权机构 */
    if(header->nsCount > 0){


        cnt = header->nsCount;
        while(cnt--){
            ptr = dns_packet_authority_resovle(header, ptr);
        }
    }

    /* 如果附加信息数不为0,则解析附加信息 */
    if(header->arCount > 0){

        cnt = header->arCount;
        while(1){
            ptr = dns_packet_addtional_resovle(header, ptr);
        }
    }

    return 0;
}

/* 解析 DNS 响应报文头 */
int dns_packet_hdr_resolve(char *rbuf, int rlen)
{
    struct DnsHeader *header;

    header = (struct DnsHeader *)(rbuf);

    if(header->id != packet_id){
        printf("Packet don't match us\n");
        return -1;
    }

    if(header->qr != 1){
        printf("Not a response packet\n");
        return -1;
    }

    /* 16 bits 的网络格式转换为 本地格式*/
    exchangeByteOrder((unsigned char *)&header->anCount);
    exchangeByteOrder((unsigned char *)&header->qdCount);
    exchangeByteOrder((unsigned char *)&header->nsCount);
    exchangeByteOrder((unsigned char *)&header->arCount);

    if(header->anCount == 0){
        printf("Answer count is zero\n");
        return -1;
    }

    printf("Now ,we get a valid DNS response\n");
    printf("Resovle Now.......\n");

    dns_packet_body_resolve((char *)header);

    return 0;
}

int main(int argc, char *argv[])  
{  
    SOCKET soc;  
    SOCKADDR_IN addr,raddr; 
    char rbuf[BUFSIZ],sbuf[BUFSIZ];  
    struct DnsHeader header;
    WSADATA wsa;  
    int i = 0,j = 0;
    int rlen = 0, addr_len,try_cnt = 0;

    if(argc != 2){
        printf("usage   : dns_request domain_name\n");
        printf("example : dns_requst www.baidu.com");
        return -1;
    }

    /* Initial Ws2_32.dll by a process */
    if(WSAStartup(MAKEWORD(2,2), &wsa) != 0){
        printf("WSAStartup : Error code %d\n",WSAGetLastError());
        return -1;
    }  

    if((soc = socket(AF_INET,SOCK_DGRAM,0)) <= 0)  
    {  
        printf("Create socket fail!\n");  
        return -1;  
    }  

    addr_len = sizeof(raddr);
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;  
    addr.sin_addr.s_addr = inet_addr(DNS_ADDR);  
    addr.sin_port = htons(SERVER_PORT);  

    /* fill domain name field */

    dns_packet_hdr_construct(&header);
    memcpy(sbuf, (char *)&header, sizeof(header));

    i = dns_packet_body_construct(sbuf + sizeof(header), argv[1]);

    while(1) {  

        printf("try to request DNS(%s) to resolve the %s\n", DNS_ADDR, argv[1]);
        if(sendto(soc, sbuf, i + sizeof(header) + 1, 0, (struct sockaddr *)&addr, sizeof(addr))< 0){
            printf("sendto Error\n", WSAGetLastError());
            break;
        }

        printf("waiting to response...");
        if((rlen = recvfrom(soc, rbuf, BUFSIZ, 0, (struct sockaddr *)&raddr, &addr_len)) < 0){
            printf("recvfrom Error Err %d\n", WSAGetLastError());
            break;
        }else{

            if(dns_packet_hdr_resolve(rbuf, rlen)  == 0){
                printf("ok DNS request successfully\n");
                break;
            }

        }

        if(++try_cnt >= MAX_TRY_CNT){
            printf("try %d times total, but still can't resolve the %s\n", MAX_TRY_CNT,argv[1]);
            break;
        }
    }  

    WSACleanup();   //clean up Ws2_32.dll  

    return 0;  
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值