从DNS响应中获取IP

时间:2011-03-12 03:25:04

标签: c dns

我正在尝试编写一个程序,在不使用c中的任何DNS功能的情况下从DNS回复中删除一个IP地址。出于某种原因,此代码可用,但仅适用于谷歌,脸书和imgur.com。同样,如果我输入“www.facebook.com”,它会提供正确的IP地址,并且与其他两个站点相同,但输入的任何其他站点都会提供错误的IP地址。有谁知道我做错了什么?

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>

#define PORT 53
#define SITEMAXLEN 40
#define QUERYMAXLEN SITEMAXLEN + 16
#define DNSRESULTMAXLEN 100
#define IPARRAYLEN 20

typedef unsigned char char_type;

void enter_record(char_type* query, char_type* site, int* let_set);
void print_query(char_type* query, int len);
void send_query(char_type* query, char_type* result, int len, int* answer_set);
char_type* parse_result(char_type* result, int query_len, char_type* ip);
void print_ip(int* ip);

int sock;
struct sockaddr_in server_addr;
struct sockaddr_in from_addr;
int main(int argc, char_type** argv) {
    char_type* site;
    char_type* query;
    char_type* dns_result;
    char_type* ip;

    int query_len;
    int answer_len;

    site = (char_type*)malloc(SITEMAXLEN * sizeof(char_type));
    query = (char_type*)malloc((QUERYMAXLEN) * sizeof(char_type));
    dns_result = (char_type*)malloc(DNSRESULTMAXLEN * sizeof(char_type));
    ip = (char_type*)malloc(IPARRAYLEN * sizeof(char_type));

    if((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
        fprintf(stderr, "error creating socket to the name server\n");
        return 1;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr("208.67.220.220");
    server_addr.sin_port = htons(PORT);

    printf("enter in website name\n");
    scanf("%s", site);

    enter_record(query, site, &query_len);
    print_query(query, query_len);
    send_query(query, dns_result, query_len, &answer_len);
    printf("\n\nresult is\n");
    print_query(dns_result, answer_len);
    parse_result(dns_result, query_len, ip);
    printf("\n\nip address is: %s", ip);

    return 0;
}

void enter_record(char_type* query, char_type* site, int* len_set) {
    char_type* loc;
    char_type* len;
    char_type* tld;
    int query_end;

    loc = strchr(site, '.'); //. after www
    len = strchr(loc + 1, '.'); //. after the hostname
    *loc = (char_type)(len - loc - 1);
    *len = (char_type)0x0003;

    query[0] = 'B';
    query[1] = 'L';
    query[2] = (char_type)0x0001;
    query[3] = (char_type)0x0000;
    query[4] = (char_type)0x0000;
    query[5] = (char_type)0x0001;
    query[6] = (char_type)0x0000;
    query[7] = (char_type)0x0000;
    query[8] = (char_type)0x0000;
    query[9] = (char_type)0x0000;
    query[10] = (char_type)0x0000;
    query[11] = (char_type)0x0000;
    query[12] = (char_type)0x0003;
    strncat(query + 13, site, strlen(site));

    query_end = 13 + strlen(site);
    query[query_end] = 0x0000;
    query[query_end + 1] = 0x0000;
    query[query_end + 2] = 0x0001;
    query[query_end + 3] = 0x0000;
    query[query_end + 4] = 0x0001;

    *len_set = query_end + 5;
}

void print_query(char_type* query, int len) {
    int i;

    printf("in hex\n");
    for(i = 0; i < len; i++) {
        printf("%02hhX ", query[i]);

        if(i % 16 == 0 && i != 0) {
            printf("\n");
        }
    }
    printf("\nin ascii\n");

    for(i = 0; i < len; i++) {
        printf("%c ", query[i] < (char_type)0x21 ? '.' : query[i]);

        if(i % 16 == 0 && i != 0) {
            printf("\n");
        }
    }
    printf("\n");
}

void send_query(char_type* query, char_type* result, int len, int* set_len) {
    int from_size;
    int response_len;

    if(sendto(sock, query, len, 0,
    (struct sockaddr*)&server_addr, sizeof(server_addr)) != len) {
        //message couldn't be sent
        fprintf(stderr, "couldn't send the query\n");
        return;
    }

    from_size = sizeof(from_addr);
    while((response_len = recvfrom(sock, result, DNSRESULTMAXLEN, 0,
    (struct sockaddr*)&from_addr, &from_size)) < 0) {
    }

    //null terminate the buffer
    //printf("%d\n", response_len);
    //result[response_len] = '\0';

    *set_len = response_len;
}

char_type* parse_result(char_type* result, int query_len, char_type* ip) {
    /*int offset = -1;

    //offset = query_len + 32;
    int count = 0;
    while(count < 3) {
        offset++;
        if(result[offset] == 0x00C0) {
            count++;
        }
    }

    offset += 32;*/

    int offset = -1;
    int found = 0;
    while(found == 0) {
        offset++;
        if(result[offset] == 0x00C0) {
            if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
                offset = offset + result[offset + 1];
                found = 1;
            }
        }
    }

    sprintf(ip, "%d.%d.%d.%d\n", 
    result[offset], result[offset + 1], 
    result[offset + 2], result[offset + 3]);

    return ip;
}

1 个答案:

答案 0 :(得分:0)

parse_result()中,而不是跳跃result[offset + 1]个字节,跳转12个字节。

            if(result[offset + 3] == 0x0001 && result[offset + 2] == 0x0000) {
                /* ********
                offset = offset + result[offset + 1];
                ******** */
                offset = offset + 12;
                found = 1;
            }

result [offset + 1]的值是从消息开头到名称的偏移量,而不是ip地址。在雅虎的情况下,偏移量最终指向"any-fp.wa1.b.yahoo.com"


它适用于facebook(及其他人),因为答案中名称的偏移量为12.当问题中的名称与答案中的名称相同时,偏移量为12。


<强>更新

并非所有DNS答案都会使用指针(0xC0 0x??)启动每个答案部分。他们可能会有一个标签而你的程序会失败。即使指针的第一个字节也不需要0xC0:要求设置前2位。