【问题标题】:C libpcap API extracting DNS queryC libpcap API 提取 DNS 查询
【发布时间】:2018-07-17 08:27:45
【问题描述】:

我正在尝试使用 libpcap api 从捕获的 DNS 数据包中提取 DNS 查询,但是我的结构一定有问题,在最后一次转换之后(使用结构问题)char* name 指针指向 正确的地址,查询名称的开始,但它只包含

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       
}

我真的很困惑在这里做什么

【问题讨论】:

  • 我们可以重现这个问题吗? packetProc 函数的参数是什么,所以我可以得到和你一样的结果?我猜u_charunsigned char?你确定你的结构中没有填充吗?你能发布struct iphdrstruct ethhdrstruct udphdr、....的sizeofs吗?为什么你有struct questionchar * name 指针,你确定在包装中有一个char * 指向某个位置的指针吗?
  • 另一点:您不能假设 IP 标头具有固定大小,可能存在扩大标头的 IP 选项。确定大小的正确方法是IP_header->ihl * 4,而不是sizeof(struct iphdr)。当然,您必须检查您没有超出任何数据包边界,因为该字段由远程对等方填充。

标签: c libpcap


【解决方案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用于在数据包字节序和主机字节序之间进行转换的系列函数。

【讨论】:

    猜你喜欢
    • 2014-08-20
    • 2015-08-05
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多