解析DNS中的CNAME,NS答案

时间:2018-10-12 10:48:56

标签: c dns compression cname

我有以下代码检查DNS响应中的查询类型,然后进一步进行相应打印。我需要一种使用给定参数解析CNAME和NS的方法,但无法这样做。这里的tmp是一个变量,定义为tmp = (u_char *)(dpkt->payload + 12);,而dns_label_to_str是一个函数,用于将字符串形式的DNS名称转换为:*dns_label_to_str(u_char **label, u_char *dest,size_t dest_size,const u_char *payload,const u_char *end)

代码:

   switch (qtype) {
            case 1: /* A */
                    data = inet_ntop(AF_INET, tmp, dbuf, BUFSIZ);
            break;
            case 2:  /* NS */
            case 5:  /* CNAME */
            case 12: /* PTR */
                    data = (char *)dns_label_to_str(
                            &tmp, (u_char *)dbuf, BUFSIZ,
                            dpkt->payload, tmp + len
                    );
            break;
            case 10: /* NULL */
                    data = "NULL";
            break;
            case 15: /* MX (16-bit priority / label) */
                    i = snprintf(dbuf, 7, "%u ", ntohs(*(uint16_t *)tmp));
                    tmp += 2;
                    data = (char *)dns_label_to_str(
                            &tmp, (u_char *)(dbuf + i), BUFSIZ - i,
                            dpkt->payload, tmp + len - 2
                    );
                    data = dbuf;
            break;
            case 16: /* TXT (1 byte text length / text) */
                    if (*tmp <= len && tmp + len < end) {
                            memcpy(dbuf, tmp+1, *tmp);
                            dbuf[*tmp+1] = '\0';
                    } else *dbuf = '\0';
                    data = dbuf;
            break;
            case 17: /* AAAA */
                    data = inet_ntop(AF_INET6, tmp, dbuf, BUFSIZ);
            break;
            default:
                    /* Ignore unhandled RR types */
                    *dbuf = '\0';
                    data = dbuf;
    }

    /* Print the output. */
    printf("%ld %-5s %-30s %s\n", hdr->ts.tv_sec,
           dns_types[qtype], label, data);

ret:
    return 0;
}

如果在qtype == 5时有人可以帮助我获取CNAME会有所帮助。预先感谢。

2 个答案:

答案 0 :(得分:1)

我尚不完全清楚dns_label_to_str函数的作用,但是参数最可能的含义是:

  • label :指向指针的指针。 *label最初指向数据包中名称的开头,并更新为指向数据包中名称之后的下一个字节。
  • dest :目标缓冲区的地址。 (这可以是字符串(文本格式)或未压缩的名称(有线格式)。
  • dest :目标缓冲区的长度。根据函数的输出格式,此值应至少为256(有线格式)或至少1024(文本格式,由于转义)。当然,目标缓冲区必须足够大。
  • payload :指向整个 DNS数据包开始的指针(不是当前资源记录的数据!) 。
  • end :指向整个DNS数据包中最后一个字节之后的指针。

之类的dns_label_to_str之类的功能需要引用整个数据包的原因是DNS标签压缩:名称可以包含一个压缩引用,该引用指向数据包中的另一个较早的位置,从而在数据包中重用另一个名称的结尾。包,以较小的偏移量。这些引用绝不会指向资源记录数据,因为对于CNAME记录,它仅包含一个名称:如果使用压缩,则名称tail必须来自其他位置。

编辑在有关前向压缩指针的评论中,我们存在一些争论。 BIND 9拒绝了它们,但是其他许多实现也接受了它们。

答案 1 :(得分:1)

dpkt->payload + 12处的数据是问题部分,即原始请求中内容的副本,并将包含一个(未压缩的)标签,称为QNAME,后跟16位QTYPEQCLASS字段。

此后,您才开始查找响应数据,其每个记录都遵循RFC 1035,第4节的结构,强烈建议您先阅读以下内容:

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                                               |
/                                               /
/                      NAME                     /
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TYPE                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                     CLASS                     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      TTL                      |
|                                               |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                   RDLENGTH                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/                     RDATA                     /
/                                               /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

请注意,“问题”部分中的数据结构与上面的前三个字段相同。