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;
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;
assert(_ret);
saved_rindex = p->rindex;
+ jump_barrier = p->rindex;
for (;;) {
uint8_t c, d;
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;
}
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)) {
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);