diff options
-rw-r--r-- | src/resolve/resolved-dns-packet.c | 40 | ||||
-rw-r--r-- | src/resolve/resolved-dns-packet.h | 8 | ||||
-rw-r--r-- | src/resolve/resolved-dns-rr.c | 46 | ||||
-rw-r--r-- | src/resolve/resolved-dns-rr.h | 8 | ||||
-rw-r--r-- | src/resolve/resolved-dns-scope.c | 6 |
5 files changed, 94 insertions, 14 deletions
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 06464324d2..75f31b80f6 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -108,6 +108,8 @@ DnsPacket *dns_packet_ref(DnsPacket *p) { if (!p) return NULL; + assert(!p->on_stack); + assert(p->n_ref > 0); p->n_ref++; return p; @@ -126,7 +128,9 @@ static void dns_packet_free(DnsPacket *p) { hashmap_free(p->names); free(p->_data); - free(p); + + if (!p->on_stack) + free(p); } DnsPacket *dns_packet_unref(DnsPacket *p) { @@ -380,7 +384,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ } int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) { - void *w; + uint8_t *w; int r; assert(p); @@ -389,12 +393,29 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start if (l > DNS_LABEL_MAX) return -E2BIG; - r = dns_packet_extend(p, 1 + l, &w, start); + r = dns_packet_extend(p, 1 + l, (void**) &w, start); if (r < 0) return r; - ((uint8_t*) w)[0] = (uint8_t) l; - memcpy(((uint8_t*) w) + 1, d, l); + *(w++) = (uint8_t) l; + + if (p->canonical_form) { + size_t i; + + /* Generate in canonical form, as defined by DNSSEC + * RFC 4034, Section 6.2, i.e. all lower-case. */ + + for (i = 0; i < l; i++) { + if (d[i] >= 'A' && d[i] <= 'Z') + w[i] = (uint8_t) (d[i] - 'A' + 'a'); + else + w[i] = (uint8_t) d[i]; + } + } else + /* Otherwise, just copy the string unaltered. This is + * essential for DNS-SD, where the casing of labels + * matters and needs to be retained. */ + memcpy(w, d, l); return 0; } @@ -647,8 +668,8 @@ fail: return r; } -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) { - size_t saved_size, rdlength_offset, end, rdlength; +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) { + size_t saved_size, rdlength_offset, end, rdlength, rds; int r; assert(p); @@ -669,6 +690,8 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; + rds = p->size - saved_size; + switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { case DNS_TYPE_SRV: @@ -947,6 +970,9 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (start) *start = saved_size; + if (rdata_start) + *rdata_start = rds; + return 0; fail: diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index b236333f61..853c94fe76 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -88,8 +88,10 @@ struct DnsPacket { uint16_t sender_port, destination_port; uint32_t ttl; - bool extracted; - bool refuse_compression; + bool on_stack:1; + bool extracted:1; + bool refuse_compression:1; + bool canonical_form:1; }; static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { @@ -162,7 +164,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start); int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start); +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start); int dns_packet_append_opt_rr(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start); void dns_packet_truncate(DnsPacket *p, size_t sz); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 09fe9725a2..1224eeaf25 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -416,6 +416,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { free(rr->generic.data); } + free(rr->wire_format); dns_resource_key_unref(rr->key); } @@ -994,6 +995,51 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { return 0; } +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { + + DnsPacket packet = { + .n_ref = 1, + .protocol = DNS_PROTOCOL_DNS, + .on_stack = true, + .refuse_compression = true, + .canonical_form = canonical, + }; + + size_t start, rds; + int r; + + assert(rr); + + /* Generates the RR in wire-format, optionally in the + * canonical form as discussed in the DNSSEC RFC 4034, Section + * 6.2. We allocate a throw-away DnsPacket object on the stack + * here, because we need some book-keeping for memory + * management, and can reuse the DnsPacket serializer, that + * can generate the canonical form, too, but also knows label + * compression and suchlike. */ + + if (rr->wire_format && rr->wire_format_canonical == canonical) + return 0; + + r = dns_packet_append_rr(&packet, rr, &start, &rds); + if (r < 0) + return r; + + assert(start == 0); + assert(packet._data); + + free(rr->wire_format); + rr->wire_format = packet._data; + rr->wire_format_size = packet.size; + rr->wire_format_rdata_offset = rds; + rr->wire_format_canonical = canonical; + + packet._data = NULL; + dns_packet_unref(&packet); + + return 0; +} + const char *dns_class_to_string(uint16_t class) { switch (class) { diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index ac4256b882..c51419cb94 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -57,7 +57,11 @@ struct DnsResourceRecord { unsigned n_ref; DnsResourceKey *key; uint32_t ttl; - bool unparseable; + bool unparseable:1; + bool wire_format_canonical:1; + void *wire_format; + size_t wire_format_size; + size_t wire_format_rdata_offset; union { struct { void *data; @@ -209,6 +213,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical); + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 09e6872d26..846280e8b8 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -549,7 +549,7 @@ static int dns_scope_make_reply_packet( if (answer) { for (i = 0; i < answer->n_rrs; i++) { - r = dns_packet_append_rr(p, answer->items[i].rr, NULL); + r = dns_packet_append_rr(p, answer->items[i].rr, NULL, NULL); if (r < 0) return r; } @@ -559,7 +559,7 @@ static int dns_scope_make_reply_packet( if (soa) { for (i = 0; i < soa->n_rrs; i++) { - r = dns_packet_append_rr(p, soa->items[i].rr, NULL); + r = dns_packet_append_rr(p, soa->items[i].rr, NULL, NULL); if (r < 0) return r; } @@ -733,7 +733,7 @@ static int dns_scope_make_conflict_packet( if (r < 0) return r; - r = dns_packet_append_rr(p, rr, NULL); + r = dns_packet_append_rr(p, rr, NULL, NULL); if (r < 0) return r; |