C libpcap API提取DNS查询

时间:2018-07-17 08:27:46

标签: c libpcap

我正在尝试使用libpcap api从捕获的DNS数据包中提取DNS查询,但是我的结构必须存在问题,在最后一次强制转换(使用结构问题)之后,char* name指针指向< strong>正确的地址,查询名称的开头,但是仅包含

42 45 20 00

但应该

20 45 48 45 50 45 50 45 48 45 4d 45 46 43 4f 45 44 45 50 45 4e 43 41 43 41 43
41 43 41 43 41 41 41 00 00 20 00 01

代码在这里

struct dnshdr{
    uint16_t id;
    uint16_t flags;
    uint16_t ques;
    uint16_t anRR;
    uint16_t auRR;
    uint16_t addRR;
};

struct question{
    char * name;
    uint16_t type;
    uint16_t cls;
};



void packetProc(u_char *args, const struct pcap_pkthdr *header,const u_char *packet){
   struct iphdr *IP_header;
   struct udphdr *UDP_header;
   struct dnshdr *DNS_header;
   struct question *ques;

   IP_header =  (struct iphdr*)    (packet + sizeof(struct ethhdr));
   UDP_header = (struct udphdr*)   (packet + sizeof(struct iphdr)  + sizeof(struct ethhdr));
   DNS_header = (struct dnshdr*)   (packet + sizeof(struct iphdr)  + sizeof(struct ethhdr)  +  sizeof(struct udphdr) );
   ques =       (struct question*) (packet + sizeof(struct ethhdr) + sizeof(struct iphdr)   +  sizeof(struct udphdr) + sizeof(struct dnshdr)-1 ); //fatal       
}

老实说,我不知道该怎么办

1 个答案:

答案 0 :(得分:1)

struct question{
    char * name;
    uint16_t type;
    uint16_t cls;
};

您使用此结构的方式无效。 char *是指向包含字符的内存位置的指针。 DNS查询没有指向包含字符的计算机内存位置的指针值,该查询包含这些字符。但是,DNS查询名称(即char name[how much should be put here])的长度是根据udp消息的长度计算得出的。您可以:

struct question_after_name_s { 
        uint16_t type;
        uint16_t cls;
};

...
const size_t namepos = 2*6; // name position in bytes form the beginning of the DNS query, this should be equal to 'sizeof(struct ethhdr) + sizeof(struct iphdr)   +  sizeof(struct udphdr) + sizeof(struct dnshdr)-1 ' from your code
char *name = (char*)&packet[namepos]; // the pointer name should point to the location in packet after namepos bytes
const size_t packetlen = header->len; // I guess this is received DNS query length obtained from libcap
const size_t querytypeandclasslen = 2*2; // length of the query type and query class, should be equal to sizeof(struct question_after_name_s)
const size_t namelen = packetlen - namepos - querytypeandclasslen;
printf("DNS query name = '%.*s'\n", namelen, name);
struct question_after_name_s *ptr = (void*)&packet[namepos + namelen];
//or
struct question_after_name_s *ptr = (void*)&packet[];

当然,仅当您的编译器未在结构成员之间插入任何填充时,这种转换才是正确的(希望您在这些结构上使用带有attribute((packed))的gcc编译器)并调用ntohl系列函数或be16toh系列功能可在数据包的字节序和主机的字节序之间进行转换。