解析 CNAME,DNS 中的 NS 答案
Parsing CNAME, NS in DNS answer
我有以下代码检查 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] = '[=10=]';
} else *dbuf = '[=10=]';
data = dbuf;
break;
case 17: /* AAAA */
data = inet_ntop(AF_INET6, tmp, dbuf, BUFSIZ);
break;
default:
/* Ignore unhandled RR types */
*dbuf = '[=10=]';
data = dbuf;
}
/* Print the output. */
printf("%ld %-5s %-30s %s\n", hdr->ts.tv_sec,
dns_types[qtype], label, data);
ret:
return 0;
}
如果有人可以帮助我如何获得 CNAME,qtype == 5
会有所帮助。提前致谢。
我不完全清楚 dns_label_to_str
函数的作用,但参数的最可能含义是:
label
:指向指针的指针。 *label
最初指向数据包中名称的开头,并更新为指向数据包中名称之后的下一个字节。
dest
:目标缓冲区的地址。 (这可以是字符串(文本格式)或未压缩的名称(有线格式)。
dest
:目标缓冲区的长度。根据函数的输出格式,这应该至少为 256(有线格式)或至少 1024(文本格式,由于转义)。当然,目标缓冲区也必须足够大。
payload
:指向整个 DNS数据包开始的指针(不是当前资源记录的数据!)。
end
:指向整个 DNS 数据包中最后一个字节的指针。
dns_label_to_str
等函数需要引用整个数据包的原因是 DNS 标签压缩:名称可以包含指向另一个数据包中较早位置的压缩引用,重用另一个名称的尾部在数据包中,偏移量较小。这些引用永远不会指向资源记录数据,因为对于 CNAME 记录,它只包含一个名称:如果使用压缩,名称 tail 必须来自其他地方。
EDIT 我们在关于前向压缩指针的评论中有一些争论。 BIND 9 拒绝它们,但许多其他实现接受它们。
dpkt->payload + 12
处的数据是 问题部分 ,即原始请求中内容的副本,并将包含一个(未压缩的)标签,称为 QNAME
然后是 16 位 QTYPE
和 QCLASS
字段。
只有在那之后你才会开始查找响应数据,其中的每条记录都遵循 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 /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
请注意,问题部分的数据结构与上面的前三个字段相同。
我有以下代码检查 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] = '[=10=]';
} else *dbuf = '[=10=]';
data = dbuf;
break;
case 17: /* AAAA */
data = inet_ntop(AF_INET6, tmp, dbuf, BUFSIZ);
break;
default:
/* Ignore unhandled RR types */
*dbuf = '[=10=]';
data = dbuf;
}
/* Print the output. */
printf("%ld %-5s %-30s %s\n", hdr->ts.tv_sec,
dns_types[qtype], label, data);
ret:
return 0;
}
如果有人可以帮助我如何获得 CNAME,qtype == 5
会有所帮助。提前致谢。
我不完全清楚 dns_label_to_str
函数的作用,但参数的最可能含义是:
label
:指向指针的指针。*label
最初指向数据包中名称的开头,并更新为指向数据包中名称之后的下一个字节。dest
:目标缓冲区的地址。 (这可以是字符串(文本格式)或未压缩的名称(有线格式)。dest
:目标缓冲区的长度。根据函数的输出格式,这应该至少为 256(有线格式)或至少 1024(文本格式,由于转义)。当然,目标缓冲区也必须足够大。payload
:指向整个 DNS数据包开始的指针(不是当前资源记录的数据!)。end
:指向整个 DNS 数据包中最后一个字节的指针。
dns_label_to_str
等函数需要引用整个数据包的原因是 DNS 标签压缩:名称可以包含指向另一个数据包中较早位置的压缩引用,重用另一个名称的尾部在数据包中,偏移量较小。这些引用永远不会指向资源记录数据,因为对于 CNAME 记录,它只包含一个名称:如果使用压缩,名称 tail 必须来自其他地方。
EDIT 我们在关于前向压缩指针的评论中有一些争论。 BIND 9 拒绝它们,但许多其他实现接受它们。
dpkt->payload + 12
处的数据是 问题部分 ,即原始请求中内容的副本,并将包含一个(未压缩的)标签,称为 QNAME
然后是 16 位 QTYPE
和 QCLASS
字段。
只有在那之后你才会开始查找响应数据,其中的每条记录都遵循 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 /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
请注意,问题部分的数据结构与上面的前三个字段相同。