diff options
Diffstat (limited to 'src/resolve/resolved-dns-packet.c')
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 95 |
1 files changed, 64 insertions, 31 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 4e069ab4cb..14faf9e4ab 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -80,7 +80,7 @@ void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool trun h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, 0 /* opcode */, 0 /* c */, - 0/* tc */, + 0 /* tc */, 0 /* t */, 0 /* ra */, 0 /* ad */, @@ -438,10 +438,15 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ return 0; } -int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) { +int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, bool canonical_candidate, size_t *start) { uint8_t *w; int r; + /* Append a label to a packet. Optionally, does this in DNSSEC + * canonical form, if this label is marked as a candidate for + * it, and the canonical form logic is enabled for the + * packet */ + assert(p); assert(d); @@ -454,7 +459,7 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start *(w++) = (uint8_t) l; - if (p->canonical_form) { + if (p->canonical_form && canonical_candidate) { size_t i; /* Generate in canonical form, as defined by DNSSEC @@ -479,6 +484,7 @@ int dns_packet_append_name( DnsPacket *p, const char *name, bool allow_compression, + bool canonical_candidate, size_t *start) { size_t saved_size; @@ -533,7 +539,7 @@ int dns_packet_append_name( if (k > 0) r = k; - r = dns_packet_append_label(p, label, r, &n); + r = dns_packet_append_label(p, label, r, canonical_candidate, &n); if (r < 0) goto fail; @@ -574,7 +580,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) saved_size = p->size; - r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL); + r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL); if (r < 0) goto fail; @@ -596,7 +602,7 @@ fail: return r; } -static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) { +static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, const uint8_t *types, size_t *start) { size_t saved_size; int r; @@ -653,15 +659,16 @@ static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) { } window = n >> 8; - entry = n & 255; bitmaps[entry / 8] |= 1 << (7 - (entry % 8)); } - r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL); - if (r < 0) - goto fail; + if (bitmaps[entry / 8] != 0) { + r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL); + if (r < 0) + goto fail; + } if (start) *start = saved_size; @@ -762,14 +769,14 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->srv.name, true, NULL); + r = dns_packet_append_name(p, rr->srv.name, true, false, NULL); break; case DNS_TYPE_PTR: case DNS_TYPE_NS: case DNS_TYPE_CNAME: case DNS_TYPE_DNAME: - r = dns_packet_append_name(p, rr->ptr.name, true, NULL); + r = dns_packet_append_name(p, rr->ptr.name, true, false, NULL); break; case DNS_TYPE_HINFO: @@ -812,11 +819,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_SOA: - r = dns_packet_append_name(p, rr->soa.mname, true, NULL); + r = dns_packet_append_name(p, rr->soa.mname, true, false, NULL); if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->soa.rname, true, NULL); + r = dns_packet_append_name(p, rr->soa.rname, true, false, NULL); if (r < 0) goto fail; @@ -844,7 +851,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->mx.exchange, true, NULL); + r = dns_packet_append_name(p, rr->mx.exchange, true, false, NULL); break; case DNS_TYPE_LOC: @@ -948,7 +955,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL); + r = dns_packet_append_name(p, rr->rrsig.signer, false, true, NULL); if (r < 0) goto fail; @@ -956,7 +963,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_NSEC: - r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL); + r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, false, NULL); if (r < 0) goto fail; @@ -1448,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; @@ -1476,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); @@ -1488,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; @@ -1508,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); @@ -1520,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; @@ -1848,7 +1856,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { case DNS_TYPE_NSEC: { /* - * RFC6762, section 18.14 explicly states mDNS should use name compression. + * RFC6762, section 18.14 explictly states mDNS should use name compression. * This contradicts RFC3845, section 2.1.1 */ @@ -1932,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; @@ -1964,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; @@ -1990,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; @@ -2011,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; } |