resolved: when parsing DNS packets, handle OPT RR specially

As soon as we encounter the OPT RR while parsing, store it in a special
field in the DnsPacket structure. That way, we won't be confused if we
iterate through RRs, and can check that there's really only one of these
RRs around.
This commit is contained in:
Lennart Poettering 2015-12-09 17:43:24 +01:00
parent c296dd2eea
commit d75acfb059
3 changed files with 21 additions and 8 deletions

View file

@ -153,6 +153,7 @@ static void dns_packet_free(DnsPacket *p) {
dns_question_unref(p->question);
dns_answer_unref(p->answer);
dns_resource_record_unref(p->opt);
while ((s = hashmap_steal_first_key(p->names)))
free(s);
@ -209,6 +210,7 @@ int dns_packet_validate_reply(DnsPacket *p) {
return -EBADMSG;
switch (p->protocol) {
case DNS_PROTOCOL_LLMNR:
/* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
if (DNS_PACKET_QDCOUNT(p) != 1)
@ -249,6 +251,7 @@ int dns_packet_validate_query(DnsPacket *p) {
return -EBADMSG;
switch (p->protocol) {
case DNS_PROTOCOL_LLMNR:
/* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
if (DNS_PACKET_QDCOUNT(p) != 1)
@ -963,6 +966,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
goto fail;
break;
case DNS_TYPE_NSEC3:
r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL);
if (r < 0)
@ -997,6 +1001,8 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
goto fail;
break;
case DNS_TYPE_OPT:
case _DNS_TYPE_INVALID: /* unparseable */
default:
@ -1568,10 +1574,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
break;
case DNS_TYPE_OPT: /* we only care about the header */
r = 0;
break;
case DNS_TYPE_HINFO:
r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
if (r < 0)
@ -1749,6 +1751,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
}
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
if (r < 0)
@ -1911,6 +1914,8 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
break;
}
case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */
default:
unparseable:
r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL);
@ -1986,9 +1991,16 @@ int dns_packet_extract(DnsPacket *p) {
if (r < 0)
goto finish;
r = dns_answer_add(answer, rr, p->ifindex);
if (r < 0)
goto finish;
if (rr->key->type == DNS_TYPE_OPT) {
if (p->opt)
return -EBADMSG;
p->opt = dns_resource_record_ref(rr);
} else {
r = dns_answer_add(answer, rr, p->ifindex);
if (r < 0)
goto finish;
}
}
}

View file

@ -80,6 +80,7 @@ struct DnsPacket {
/* Parsed data */
DnsQuestion *question;
DnsAnswer *answer;
DnsResourceRecord *opt;
/* Packet reception metadata */
int ifindex;

View file

@ -114,7 +114,7 @@ struct DnsResourceRecord {
struct {
void *data;
size_t size;
} generic;
} generic, opt;
struct {
uint16_t priority;