diff options
Diffstat (limited to 'src/resolve/resolved-dns-packet.c')
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index c34ecc44f8..14faf9e4ab 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1455,9 +1455,9 @@ fail: return r; } -int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { +int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) { _cleanup_free_ char *name = NULL; - bool cache_flush = true; + bool cache_flush = false; uint16_t class, type; DnsResourceKey *key; size_t saved_rindex; @@ -1483,10 +1483,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { if (p->protocol == DNS_PROTOCOL_MDNS) { /* See RFC6762, Section 10.2 */ - if (class & MDNS_RR_CACHE_FLUSH) + if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH)) { class &= ~MDNS_RR_CACHE_FLUSH; - else - cache_flush = false; + cache_flush = true; + } } key = dns_resource_key_new_consume(class, type, name); @@ -1495,11 +1495,11 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { goto fail; } - key->cache_flush = cache_flush; - name = NULL; *ret = key; + if (ret_cache_flush) + *ret_cache_flush = cache_flush; if (start) *start = saved_rindex; @@ -1515,11 +1515,12 @@ static bool loc_size_ok(uint8_t size) { return m <= 9 && e <= 9 && (m > 0 || e == 0); } -int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { +int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; size_t saved_rindex, offset; uint16_t rdlength; + bool cache_flush; int r; assert(p); @@ -1527,11 +1528,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { saved_rindex = p->rindex; - r = dns_packet_read_key(p, &key, NULL); + r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) goto fail; - if (key->class == DNS_CLASS_ANY || + if (!dns_class_is_valid_rr(key->class)|| !dns_type_is_valid_rr(key->type)) { r = -EBADMSG; goto fail; @@ -1939,6 +1940,8 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { *ret = rr; rr = NULL; + if (ret_cache_flush) + *ret_cache_flush = cache_flush; if (start) *start = saved_rindex; @@ -1971,11 +1974,17 @@ int dns_packet_extract(DnsPacket *p) { for (i = 0; i < n; i++) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + bool cache_flush; - r = dns_packet_read_key(p, &key, NULL); + r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) goto finish; + if (cache_flush) { + r = -EBADMSG; + goto finish; + } + if (!dns_type_is_valid_query(key->type)) { r = -EBADMSG; goto finish; @@ -1997,13 +2006,19 @@ int dns_packet_extract(DnsPacket *p) { for (i = 0; i < n; i++) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + bool cache_flush; - r = dns_packet_read_rr(p, &rr, NULL); + r = dns_packet_read_rr(p, &rr, &cache_flush, NULL); if (r < 0) goto finish; if (rr->key->type == DNS_TYPE_OPT) { + if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) { + r = -EBADMSG; + goto finish; + } + /* The OPT RR is only valid in the Additional section */ if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) { r = -EBADMSG; @@ -2018,7 +2033,18 @@ int dns_packet_extract(DnsPacket *p) { p->opt = dns_resource_record_ref(rr); } else { - r = dns_answer_add(answer, rr, p->ifindex); + + /* According to RFC 4795, section + * 2.9. only the RRs from the Answer + * section shall be cached. Hence mark + * only those RRs as cacheable by + * default, but not the ones from the + * Additional or Authority + * sections. */ + + r = dns_answer_add(answer, rr, p->ifindex, + (i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) | + (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0)); if (r < 0) goto finish; } |