X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fresolve%2Fresolved-dns-packet.c;h=21756f566fb0674b8c6948f07de98a8c6e460acf;hp=4f9503803be53b66c02b06cbeb151cf779554663;hb=f131770b1465fbf423881f16ba85523a05f846fe;hpb=3ef77d0476046a660c1b4704140797c447e6ce3a diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 4f9503803..21756f566 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 occurrence" (RFC-1035 4.1.4) */ + jump_barrier = ptr; p->rindex = ptr; - } else + } else { + r = -EBADMSG; goto fail; + } } if (!GREEDY_REALLOC(ret, allocated, n + 1)) { @@ -1114,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); @@ -1358,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); @@ -1409,6 +1427,8 @@ int dns_packet_extract(DnsPacket *p) { p->answer = answer; answer = NULL; + p->extracted = true; + r = 0; finish: