2016-02-24 4 views
0

Я пишу клиент DNS-запроса и не могу понять, как отправляются мои данные и как заставить его работать правильно.Отправка структур через сокет C

В Wireshark я получаю много случайных данных с предупреждениями MALFORMED PACKET и без ответа от DNS-сервера, с которым я тестирую. (В настоящее время DNS от Google ... 8.8.8.8)

Отрывок ...

typedef struct DNS_HEADER { 

    // id to identify the request 
    int16_t id; 

    // query or response flag; default is 0 
    uint8_t qr :1; 

    // type of query; default is 0 
    uint8_t opcode :4; 

    // authoritative answer 
    uint8_t aa :1; 

    // message was truncated 
    uint8_t tc :1; 

    // recursion desired; default is yes 
    uint8_t rd :1; 

    // recursion available 
    uint8_t ra :1; 

    // unused 
    uint8_t z :1; 

    // response code 
    uint8_t rcode :4; 

    // entries in the question section; default is 1 
    uint16_t qdcount; 

    // resource records 
    uint16_t ancount; 

    // server resource records (in the authority section) 
    uint16_t nscount; 

    // resource records (in addl. section) 
    uint16_t arcount; 

} dns_h; 

header->qr = 0; 
header->opcode = 0; 
... 
header->qdcount = htons(1); 
... 

И мой SendTo ...

char buffer[sizeof(*header) * sizeof(*question) * 2]; 
int offset = 0; 
memcpy(buffer, header, sizeof(*header)); 
offset += sizeof(*header); 
memcpy(buffer + offset, question, sizeof(*question)); 

ssize_t sent = sendto(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)addr, sizeof(*addr)); 

Что я делаю неправильно? Является ли это рекомендуемым способом отправки структуры через сокет? Я настроил большинство полей в заголовке на 0 и все, что я установил на 1 Я использовал htons

+0

Ну, для начала вы отправляете в два раза больше данных, чем вы имели в виду, а вторая половина - неинициализированный мусор. – immibis

+0

С другой стороны, у вас есть бит битов на 14 бит, поэтому компилятор добавит дополнительные биты дополнений, которые могут быть не такими, как вы ожидали. – immibis

ответ

1

Две проблемы с заголовком структуры:

  • Поле z составляет 3 бита, а не 1 Таким образом, поле rcode - это два бита слева от того места, где оно должно быть.
  • Тот факт, что вы используете битполы вообще. Чтобы получить это право, вам нужно знать конечность во время компиляции, и нет никакого переносного способа сделать это. Вам лучше объявить одно 16-битовое поле (или 2 8-битные поля) для всего и смещение бит для чтения/записи правильных значений.

Вы не показываете код, в котором вы создаете заголовок, но убедитесь, что вы используете htons при настройке поля так, что значения в сетевом порядке байт.

Также внимательно ознакомьтесь с бинарными данными в пакете в Wireshark. Сравните это со значениями, которые вы указали, чтобы увидеть, что неуместно.

+0

Спасибо @dbush - определенно помогли. Как бы вы указали имя домена в пакете запросов DNS? Я объявил 'char qname [50]' просто проверить и продолжать получать «Домен не найден» с DNS-сервера. Нужно ли мне делать что-то другое? – sheppardzw

+0

Формат проводов DNS намного сложнее, чем простая структура данных C. Например, имя кодируется как серия меток, где каждая метка является байтом, где два верхних бита являются флагами и младшими шестью битами являются количество байтов последующих байтов, составляющих содержание метки (полное имя заканчивается с меткой нулевой длины). Но это позволяет просто кодировать простое имя, если вы хотите прочитать ответ, вы должны знать, как обращаться с разными типами RR и сжатием имен DNS. –