X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fresolve%2Fresolved-dns-packet.c;h=cf5b6189c571daa01de3465d970fa71382fdd9f7;hb=0eb3cc88504b5d8f740764047ac5162b67992386;hp=b97fd17963201e75614c1895dd7730625574be01;hpb=151226ab4bf276d60d51864330a99f886b923697;p=elogind.git diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index b97fd1796..cf5b6189c 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -22,6 +22,7 @@ #include "utf8.h" #include "util.h" #include "strv.h" +#include "unaligned.h" #include "resolved-dns-domain.h" #include "resolved-dns-packet.h" @@ -311,8 +312,7 @@ int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) { if (r < 0) return r; - ((uint8_t*) d)[0] = (uint8_t) (v >> 8); - ((uint8_t*) d)[1] = (uint8_t) v; + unaligned_write_be16(d, v); return 0; } @@ -327,10 +327,7 @@ int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) { if (r < 0) return r; - ((uint8_t*) d)[0] = (uint8_t) (v >> 24); - ((uint8_t*) d)[1] = (uint8_t) (v >> 16); - ((uint8_t*) d)[2] = (uint8_t) (v >> 8); - ((uint8_t*) d)[3] = (uint8_t) v; + unaligned_write_be32(d, v); return 0; } @@ -433,9 +430,7 @@ int dns_packet_append_name(DnsPacket *p, const char *name, goto fail; if (allow_compression) { - r = hashmap_ensure_allocated(&p->names, - dns_name_hash_func, - dns_name_compare_func); + r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops); if (r < 0) goto fail; @@ -552,10 +547,19 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star case DNS_TYPE_TXT: { char **s; - STRV_FOREACH(s, rr->txt.strings) { - r = dns_packet_append_string(p, *s, NULL); + if (strv_isempty(rr->txt.strings)) { + /* RFC 6763, section 6.1 suggests to generate + * single empty string for an empty array. */ + + r = dns_packet_append_string(p, "", NULL); if (r < 0) goto fail; + } else { + STRV_FOREACH(s, rr->txt.strings) { + r = dns_packet_append_string(p, *s, NULL); + if (r < 0) + goto fail; + } } r = 0; @@ -795,8 +799,8 @@ int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) { if (r < 0) return r; - *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) | - ((uint16_t) ((uint8_t*) d)[1]); + *ret = unaligned_read_be16(d); + return 0; } @@ -810,10 +814,7 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) { if (r < 0) return r; - *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) | - (((uint32_t) ((uint8_t*) d)[1]) << 16) | - (((uint32_t) ((uint8_t*) d)[2]) << 8) | - ((uint32_t) ((uint8_t*) d)[3]); + *ret = unaligned_read_be32(d); return 0; } @@ -868,7 +869,7 @@ fail: int dns_packet_read_name(DnsPacket *p, char **_ret, bool allow_compression, size_t *start) { - size_t saved_rindex, after_rindex = 0; + size_t saved_rindex, after_rindex = 0, jump_barrier; _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; bool first = true; @@ -878,6 +879,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, assert(_ret); saved_rindex = p->rindex; + jump_barrier = p->rindex; for (;;) { uint8_t c, d; @@ -924,7 +926,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, goto fail; ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) { + if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) { r = -EBADMSG; goto fail; } @@ -932,9 +934,13 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, if (after_rindex == 0) after_rindex = p->rindex; + /* Jumps are limited to a "prior occurence" (RFC-1035 4.1.4) */ + jump_barrier = ptr; p->rindex = ptr; - } else + } else { + r = -EBADMSG; goto fail; + } } if (!GREEDY_REALLOC(ret, allocated, n + 1)) { @@ -1029,6 +1035,8 @@ static bool loc_size_ok(uint8_t size) { } static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) { + assert(rr); + if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY)) return -EBADMSG; @@ -1112,22 +1120,31 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; case DNS_TYPE_SPF: /* exactly the same as TXT */ - case DNS_TYPE_TXT: { - char *s; + case DNS_TYPE_TXT: + if (rdlength <= 0) { + /* RFC 6763, section 6.1 suggests to treat + * empty TXT RRs as equivalent to a TXT record + * with a single empty string. */ - while (p->rindex < offset + rdlength) { - r = dns_packet_read_string(p, &s, NULL); + r = strv_extend(&rr->txt.strings, ""); if (r < 0) goto fail; + } else { + while (p->rindex < offset + rdlength) { + char *s; - r = strv_consume(&rr->txt.strings, s); - if (r < 0) - goto fail; + r = dns_packet_read_string(p, &s, NULL); + if (r < 0) + goto fail; + + r = strv_consume(&rr->txt.strings, s); + if (r < 0) + goto fail; + } } r = 0; break; - } case DNS_TYPE_A: r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL); @@ -1356,6 +1373,9 @@ int dns_packet_extract(DnsPacket *p) { unsigned n, i; int r; + if (p->extracted) + return 0; + saved_rindex = p->rindex; dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE); @@ -1407,6 +1427,8 @@ int dns_packet_extract(DnsPacket *p) { p->answer = answer; answer = NULL; + p->extracted = true; + r = 0; finish: