C实现DNS协议(MacOS & Linux)


#include <stdio.h>

#include <sys/socket.h>

#include <stdlib.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <string.h>

/*

typedef unsigned char        __uint8_t;

typedef    short            __int16_t;

typedef    unsigned short        __uint16_t;

typedef int            __int32_t;

typedef unsigned int        __uint32_t;

typedef long long        __int64_t;

typedef unsigned long long    __uint64_t;

typedef long            __darwin_intptr_t;

typedef unsigned int        __darwin_natural_t;

 */

struct DNS{

    unsigned short tranID;//16

    unsigned short flags;

    unsigned short questionsnum;

    unsigned short answerNum;

    unsigned short authorityNum;

    unsigned short additionalNum;

};

int fillInDns(char * newInput,char * input){

    char * tmp = input;

    char * oldTmp = input;

    char * tmp_new = newInput;

    int count = 0;

    int len=0;

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

        if (*tmp == '.') {

            *tmp_new = (unsigned char)count;//int to char

            tmp_new+=1;

            memcpy(tmp_new, oldTmp, count);

            oldTmp = oldTmp+count+1;

            tmp_new = tmp_new+count;

            len = len + count + 1;

            count = 0;

        }else{

            count+=1;

        }

        tmp = tmp+1;

    }

    //因为最后没有'.',所以需要在进行一次赋值:

    *tmp_new = (unsigned char)count;//int to char

    tmp_new+=1;

    memcpy(tmp_new, oldTmp, count);

    *(tmp_new+count) = (unsigned char)0;

    len = len+count+1;

    return len;

}

int sendToLocalDns(int sock,struct sockaddr_in * dnsAddr,char * input,char * in){

    char sendBuf[1024];

    memset(sendBuf, 0, sizeof(sendBuf));//清零sendBuf

    //1.填充DNS报文头部:

    struct DNS *dns = (struct DNS*)malloc(sizeof(struct DNS));

    char * dnsC = (char *)dns;

    dns->tranID = htons(0xff00);

    dns->flags = htons(0x0100);

    dns->questionsnum = htons(1);

    dns->answerNum = htons(0);

    dns->authorityNum = htons(0);

    dns->additionalNum = htons(0);

    //2.填充DNS报文正文:

    char input_send[50];

    int input_send_len;

    int input_send_real_len;

    memset(input_send, 0, sizeof(input_send));//清零

    input_send_len = fillInDns(input_send,input);//更改域名格式

    memcpy(sendBuf, dnsC, 12);//头部copy

    memcpy(sendBuf+12, input_send, input_send_len);//正文域名copy

    input_send_real_len = ((input_send_len/4)+1)*4;//以4Byte对齐

    memcpy(in, input_send, input_send_real_len);//本地保存,接收报文时用

    memset(sendBuf+12+input_send_real_len, 1, 1);//尾部赋值 Type

    memset(sendBuf+12+input_send_real_len+2, 1, 1);//尾部赋值 Class

    //3.发送:

    if (sendto(sock, sendBuf, sizeof(sendBuf), 0, (struct sockaddr*)dnsAddr, sizeof(struct sockaddr))==-1) {

        printf("send error!\n");

        exit(1);

    }

    free(dns);

    return input_send_real_len;

}

void recFromLocalDns(int sock,int input_send_real_len,char * in){

    char recBuf[1024];//接收缓冲

    memset(recBuf, 0, sizeof(recBuf));//清零recBuf

    struct sockaddr_in srcAddr;

    socklen_t srcAddrLen = sizeof(struct sockaddr_in);

    if (recvfrom(sock, recBuf, sizeof(recBuf), 0, (struct sockaddr*)&srcAddr, &srcAddrLen) == -1) {

        printf("rec error!\n");

        exit(1);

    }

//    printf("%p\n",recBuf);

    char * type = recBuf+12+input_send_real_len;

    type = type+5;

    int typeInt = ntohs(*(unsigned short*)type);

    int ttl = ntohl(*(unsigned int*)(type+4));

    int lenOfIp = ntohs(*(unsigned short*)(type+8));

    char * ip = type+10;

    

    char ipChar[50];//用来存放ip地址

    char ipPrint[50];

    memset(ipChar, 0, sizeof(ipChar));

    memset(ipPrint, 0, sizeof(ipPrint));

    if ((strncmp(recBuf+12, in, input_send_real_len)==0)&&(typeInt==1)) {

        memcpy(ipChar, ip, lenOfIp);

        inet_ntop(AF_INET, ipChar, ipPrint, sizeof(ipPrint));

        printf("ip is %s,ttl is %d\n",ipPrint,ttl);

    }

}

int main(int argc, const char * argv[]) {

    //创建套接字:

    int sock;

    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {

        printf("socket error!\n");

        exit(1);

    }

    //创建DNS本地服务器地址:

    struct sockaddr_in dnsAddr;

    dnsAddr.sin_family = AF_INET;

    dnsAddr.sin_port = htons(53);

    dnsAddr.sin_addr.s_addr = inet_addr("192.168.1.1");

    //输入要查询的域名:

    char input[50];

    printf("请输入要查询的域名:\n");

    scanf("%s",input);

    //发送dns请求到dns本地服务器:

    int input_send_len;

    char in[50];

    input_send_len = sendToLocalDns(sock, &dnsAddr,input,in);

    //接收dns回应:

    recFromLocalDns(sock,input_send_len,in);

    return 0;

}


猜你喜欢

转载自blog.csdn.net/guozirong123/article/details/78866070