Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: rdata.c,v 1.19 2026/01/29 18:37:49 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <ctype.h>
     19 #include <inttypes.h>
     20 #include <stdbool.h>
     21 
     22 #include <openssl/err.h>
     23 #include <openssl/objects.h>
     24 
     25 #include <isc/ascii.h>
     26 #include <isc/base64.h>
     27 #include <isc/hex.h>
     28 #include <isc/lex.h>
     29 #include <isc/mem.h>
     30 #include <isc/parseint.h>
     31 #include <isc/result.h>
     32 #include <isc/string.h>
     33 #include <isc/utf8.h>
     34 #include <isc/util.h>
     35 
     36 #include <dns/callbacks.h>
     37 #include <dns/cert.h>
     38 #include <dns/compress.h>
     39 #include <dns/db.h>
     40 #include <dns/dsdigest.h>
     41 #include <dns/enumtype.h>
     42 #include <dns/fixedname.h>
     43 #include <dns/keyflags.h>
     44 #include <dns/keyvalues.h>
     45 #include <dns/message.h>
     46 #include <dns/rcode.h>
     47 #include <dns/rdata.h>
     48 #include <dns/rdataclass.h>
     49 #include <dns/rdataset.h>
     50 #include <dns/rdatastruct.h>
     51 #include <dns/rdatatype.h>
     52 #include <dns/secalg.h>
     53 #include <dns/secproto.h>
     54 #include <dns/time.h>
     55 #include <dns/ttl.h>
     56 
     57 #define RETTOK(x)                                          \
     58 	do {                                               \
     59 		isc_result_t _r = (x);                     \
     60 		if (_r != ISC_R_SUCCESS) {                 \
     61 			isc_lex_ungettoken(lexer, &token); \
     62 			return (_r);                       \
     63 		}                                          \
     64 	} while (0)
     65 
     66 #define CHECKTOK(op)                                       \
     67 	do {                                               \
     68 		result = (op);                             \
     69 		if (result != ISC_R_SUCCESS) {             \
     70 			isc_lex_ungettoken(lexer, &token); \
     71 			goto cleanup;                      \
     72 		}                                          \
     73 	} while (0)
     74 
     75 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
     76 
     77 #define ARGS_FROMTEXT                                           \
     78 	int rdclass, dns_rdatatype_t type, isc_lex_t *lexer,    \
     79 		const dns_name_t *origin, unsigned int options, \
     80 		isc_buffer_t *target, dns_rdatacallbacks_t *callbacks
     81 
     82 #define CALL_FROMTEXT rdclass, type, lexer, origin, options, target, callbacks
     83 
     84 #define ARGS_TOTEXT \
     85 	dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target
     86 
     87 #define CALL_TOTEXT rdata, tctx, target
     88 
     89 #define ARGS_FROMWIRE                                            \
     90 	int rdclass, dns_rdatatype_t type, isc_buffer_t *source, \
     91 		dns_decompress_t dctx, isc_buffer_t *target
     92 
     93 #define CALL_FROMWIRE rdclass, type, source, dctx, target
     94 
     95 #define ARGS_TOWIRE \
     96 	dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target
     97 
     98 #define CALL_TOWIRE rdata, cctx, target
     99 
    100 #define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
    101 
    102 #define CALL_COMPARE rdata1, rdata2
    103 
    104 #define ARGS_FROMSTRUCT \
    105 	int rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target
    106 
    107 #define CALL_FROMSTRUCT rdclass, type, source, target
    108 
    109 #define ARGS_TOSTRUCT const dns_rdata_t *rdata, void *target, isc_mem_t *mctx
    110 
    111 #define CALL_TOSTRUCT rdata, target, mctx
    112 
    113 #define ARGS_FREESTRUCT void *source
    114 
    115 #define CALL_FREESTRUCT source
    116 
    117 #define ARGS_ADDLDATA                                \
    118 	dns_rdata_t *rdata, const dns_name_t *owner, \
    119 		dns_additionaldatafunc_t add, void *arg
    120 
    121 #define CALL_ADDLDATA rdata, owner, add, arg
    122 
    123 #define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
    124 
    125 #define CALL_DIGEST rdata, digest, arg
    126 
    127 #define ARGS_CHECKOWNER                                   \
    128 	const dns_name_t *name, dns_rdataclass_t rdclass, \
    129 		dns_rdatatype_t type, bool wildcard
    130 
    131 #define CALL_CHECKOWNER name, rdclass, type, wildcard
    132 
    133 #define ARGS_CHECKNAMES \
    134 	dns_rdata_t *rdata, const dns_name_t *owner, dns_name_t *bad
    135 
    136 #define CALL_CHECKNAMES rdata, owner, bad
    137 
    138 /*%
    139  * Context structure for the totext_ functions.
    140  * Contains formatting options for rdata-to-text
    141  * conversion.
    142  */
    143 typedef struct dns_rdata_textctx {
    144 	const dns_name_t *origin;      /*%< Current origin, or NULL. */
    145 	dns_masterstyle_flags_t flags; /*%< DNS_STYLEFLAG_*  */
    146 	unsigned int width;	       /*%< Width of rdata column. */
    147 	const char *linebreak;	       /*%< Line break string. */
    148 } dns_rdata_textctx_t;
    149 
    150 static isc_result_t
    151 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target);
    152 
    153 static isc_result_t
    154 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
    155 
    156 static isc_result_t
    157 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
    158 
    159 static isc_result_t
    160 commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target);
    161 
    162 static isc_result_t
    163 commatxt_totext(isc_region_t *source, bool quote, bool comma,
    164 		isc_buffer_t *target);
    165 
    166 static isc_result_t
    167 multitxt_totext(isc_region_t *source, isc_buffer_t *target);
    168 
    169 static isc_result_t
    170 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
    171 
    172 static bool
    173 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target);
    174 
    175 static unsigned int
    176 name_length(const dns_name_t *name);
    177 
    178 static isc_result_t
    179 str_totext(const char *source, isc_buffer_t *target);
    180 
    181 static isc_result_t
    182 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target);
    183 
    184 static bool
    185 buffer_empty(isc_buffer_t *source);
    186 
    187 static void
    188 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
    189 
    190 static isc_result_t
    191 uint32_tobuffer(uint32_t, isc_buffer_t *target);
    192 
    193 static isc_result_t
    194 uint16_tobuffer(uint32_t, isc_buffer_t *target);
    195 
    196 static isc_result_t
    197 uint8_tobuffer(uint32_t, isc_buffer_t *target);
    198 
    199 static isc_result_t
    200 name_tobuffer(const dns_name_t *name, isc_buffer_t *target);
    201 
    202 static uint32_t
    203 uint32_fromregion(isc_region_t *region);
    204 
    205 static uint16_t
    206 uint16_fromregion(isc_region_t *region);
    207 
    208 static uint8_t
    209 uint8_fromregion(isc_region_t *region);
    210 
    211 static uint8_t
    212 uint8_consume_fromregion(isc_region_t *region);
    213 
    214 static isc_result_t
    215 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
    216 
    217 static int
    218 hexvalue(char value);
    219 
    220 static int
    221 decvalue(char value);
    222 
    223 static void
    224 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
    225 	ISC_FORMAT_PRINTF(2, 3);
    226 
    227 static void
    228 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
    229 	       dns_rdatacallbacks_t *callbacks, const char *name,
    230 	       unsigned long line, isc_token_t *token, isc_result_t result);
    231 
    232 static void
    233 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
    234 
    235 static isc_result_t
    236 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
    237 	     isc_buffer_t *target);
    238 
    239 static void
    240 warn_badname(const dns_name_t *name, isc_lex_t *lexer,
    241 	     dns_rdatacallbacks_t *callbacks);
    242 
    243 static void
    244 warn_badmx(isc_token_t *token, isc_lex_t *lexer,
    245 	   dns_rdatacallbacks_t *callbacks);
    246 
    247 static uint16_t
    248 uint16_consume_fromregion(isc_region_t *region);
    249 
    250 static isc_result_t
    251 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
    252 	       isc_buffer_t *target);
    253 
    254 static isc_result_t generic_fromtext_key(ARGS_FROMTEXT);
    255 
    256 static isc_result_t generic_totext_key(ARGS_TOTEXT);
    257 
    258 static isc_result_t generic_fromwire_key(ARGS_FROMWIRE);
    259 
    260 static isc_result_t generic_fromstruct_key(ARGS_FROMSTRUCT);
    261 
    262 static isc_result_t generic_tostruct_key(ARGS_TOSTRUCT);
    263 
    264 static void generic_freestruct_key(ARGS_FREESTRUCT);
    265 
    266 static isc_result_t generic_fromtext_txt(ARGS_FROMTEXT);
    267 
    268 static isc_result_t generic_totext_txt(ARGS_TOTEXT);
    269 
    270 static isc_result_t generic_fromwire_txt(ARGS_FROMWIRE);
    271 
    272 static isc_result_t generic_fromstruct_txt(ARGS_FROMSTRUCT);
    273 
    274 static isc_result_t generic_tostruct_txt(ARGS_TOSTRUCT);
    275 
    276 static void generic_freestruct_txt(ARGS_FREESTRUCT);
    277 
    278 static isc_result_t
    279 generic_txt_first(dns_rdata_txt_t *txt);
    280 
    281 static isc_result_t
    282 generic_txt_next(dns_rdata_txt_t *txt);
    283 
    284 static isc_result_t
    285 generic_txt_current(dns_rdata_txt_t *txt, dns_rdata_txt_string_t *string);
    286 
    287 static isc_result_t generic_totext_ds(ARGS_TOTEXT);
    288 
    289 static isc_result_t generic_tostruct_ds(ARGS_TOSTRUCT);
    290 
    291 static isc_result_t generic_fromtext_ds(ARGS_FROMTEXT);
    292 
    293 static isc_result_t generic_fromwire_ds(ARGS_FROMWIRE);
    294 
    295 static isc_result_t generic_fromstruct_ds(ARGS_FROMSTRUCT);
    296 
    297 static isc_result_t generic_fromtext_tlsa(ARGS_FROMTEXT);
    298 
    299 static isc_result_t generic_totext_tlsa(ARGS_TOTEXT);
    300 
    301 static isc_result_t generic_fromwire_tlsa(ARGS_FROMWIRE);
    302 
    303 static isc_result_t generic_fromstruct_tlsa(ARGS_FROMSTRUCT);
    304 
    305 static isc_result_t generic_tostruct_tlsa(ARGS_TOSTRUCT);
    306 
    307 static void generic_freestruct_tlsa(ARGS_FREESTRUCT);
    308 
    309 static isc_result_t generic_fromtext_in_svcb(ARGS_FROMTEXT);
    310 static isc_result_t generic_totext_in_svcb(ARGS_TOTEXT);
    311 static isc_result_t generic_fromwire_in_svcb(ARGS_FROMWIRE);
    312 static isc_result_t generic_towire_in_svcb(ARGS_TOWIRE);
    313 static isc_result_t generic_fromstruct_in_svcb(ARGS_FROMSTRUCT);
    314 static isc_result_t generic_tostruct_in_svcb(ARGS_TOSTRUCT);
    315 static void generic_freestruct_in_svcb(ARGS_FREESTRUCT);
    316 static isc_result_t generic_additionaldata_in_svcb(ARGS_ADDLDATA);
    317 static bool generic_checknames_in_svcb(ARGS_CHECKNAMES);
    318 static isc_result_t
    319 generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *);
    320 static isc_result_t
    321 generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *);
    322 static void
    323 generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *, isc_region_t *);
    324 
    325 /*% INT16 Size */
    326 #define NS_INT16SZ 2
    327 /*% IPv6 Address Size */
    328 #define NS_LOCATORSZ 8
    329 
    330 /*
    331  * Active Directory gc._msdcs.<forest> prefix.
    332  */
    333 static unsigned char gc_msdcs_data[] = "\002gc\006_msdcs";
    334 static unsigned char gc_msdcs_offset[] = { 0, 3 };
    335 
    336 static dns_name_t const gc_msdcs = DNS_NAME_INITNONABSOLUTE(gc_msdcs_data,
    337 							    gc_msdcs_offset);
    338 
    339 /*%
    340  *	convert presentation level address to network order binary form.
    341  * \return
    342  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
    343  * \note
    344  *	(1) does not touch `dst' unless it's returning 1.
    345  */
    346 static int
    347 locator_pton(const char *src, unsigned char *dst) {
    348 	unsigned char tmp[NS_LOCATORSZ];
    349 	unsigned char *tp = tmp, *endp;
    350 	int ch, seen_xdigits;
    351 	unsigned int val, hexval;
    352 
    353 	memset(tp, '\0', NS_LOCATORSZ);
    354 	endp = tp + NS_LOCATORSZ;
    355 	seen_xdigits = 0;
    356 	val = 0;
    357 	while ((ch = *src++) != '\0') {
    358 		hexval = isc_hex_char(ch);
    359 		if (hexval != 0) {
    360 			val <<= 4;
    361 			val |= (ch - hexval);
    362 			if (++seen_xdigits > 4) {
    363 				return 0;
    364 			}
    365 			continue;
    366 		}
    367 		if (ch == ':') {
    368 			if (!seen_xdigits) {
    369 				return 0;
    370 			}
    371 			if (tp + NS_INT16SZ > endp) {
    372 				return 0;
    373 			}
    374 			*tp++ = (unsigned char)(val >> 8) & 0xff;
    375 			*tp++ = (unsigned char)val & 0xff;
    376 			seen_xdigits = 0;
    377 			val = 0;
    378 			continue;
    379 		}
    380 		return 0;
    381 	}
    382 	if (seen_xdigits) {
    383 		if (tp + NS_INT16SZ > endp) {
    384 			return 0;
    385 		}
    386 		*tp++ = (unsigned char)(val >> 8) & 0xff;
    387 		*tp++ = (unsigned char)val & 0xff;
    388 	}
    389 	if (tp != endp) {
    390 		return 0;
    391 	}
    392 	memmove(dst, tmp, NS_LOCATORSZ);
    393 	return 1;
    394 }
    395 
    396 static void
    397 name_duporclone(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
    398 	if (mctx != NULL) {
    399 		dns_name_dup(source, mctx, target);
    400 	} else {
    401 		dns_name_clone(source, target);
    402 	}
    403 }
    404 
    405 static void *
    406 mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
    407 	void *copy = NULL;
    408 
    409 	REQUIRE(source != NULL);
    410 
    411 	if (mctx == NULL) {
    412 		return source;
    413 	}
    414 
    415 	copy = isc_mem_allocate(mctx, length);
    416 	memmove(copy, source, length);
    417 
    418 	return copy;
    419 }
    420 
    421 static isc_result_t
    422 typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, bool allow_empty) {
    423 	isc_token_t token;
    424 	unsigned char bm[8 * 1024]; /* 64k bits */
    425 	dns_rdatatype_t covered, max_used;
    426 	int octet;
    427 	unsigned int max_octet, newend, end;
    428 	int window;
    429 	bool first = true;
    430 
    431 	max_used = 0;
    432 	bm[0] = 0;
    433 	end = 0;
    434 
    435 	do {
    436 		RETERR(isc_lex_getmastertoken(lexer, &token,
    437 					      isc_tokentype_string, true));
    438 		if (token.type != isc_tokentype_string) {
    439 			break;
    440 		}
    441 		RETTOK(dns_rdatatype_fromtext(&covered,
    442 					      &token.value.as_textregion));
    443 		if (covered > max_used) {
    444 			newend = covered / 8;
    445 			if (newend > end) {
    446 				memset(&bm[end + 1], 0, newend - end);
    447 				end = newend;
    448 			}
    449 			max_used = covered;
    450 		}
    451 		bm[covered / 8] |= (0x80 >> (covered % 8));
    452 		first = false;
    453 	} while (1);
    454 	isc_lex_ungettoken(lexer, &token);
    455 	if (!allow_empty && first) {
    456 		return DNS_R_FORMERR;
    457 	}
    458 
    459 	for (window = 0; window < 256; window++) {
    460 		if (max_used < window * 256) {
    461 			break;
    462 		}
    463 
    464 		max_octet = max_used - (window * 256);
    465 		if (max_octet >= 256) {
    466 			max_octet = 31;
    467 		} else {
    468 			max_octet /= 8;
    469 		}
    470 
    471 		/*
    472 		 * Find if we have a type in this window.
    473 		 */
    474 		for (octet = max_octet; octet >= 0; octet--) {
    475 			if (bm[window * 32 + octet] != 0) {
    476 				break;
    477 			}
    478 		}
    479 		if (octet < 0) {
    480 			continue;
    481 		}
    482 		RETERR(uint8_tobuffer(window, target));
    483 		RETERR(uint8_tobuffer(octet + 1, target));
    484 		RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
    485 	}
    486 	return ISC_R_SUCCESS;
    487 }
    488 
    489 static isc_result_t
    490 typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx,
    491 	       isc_buffer_t *target) {
    492 	unsigned int i, j, k;
    493 	unsigned int window, len;
    494 	bool first = true;
    495 
    496 	for (i = 0; i < sr->length; i += len) {
    497 		if (tctx != NULL &&
    498 		    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
    499 		{
    500 			RETERR(str_totext(tctx->linebreak, target));
    501 			first = true;
    502 		}
    503 		INSIST(i + 2 <= sr->length);
    504 		window = sr->base[i];
    505 		len = sr->base[i + 1];
    506 		INSIST(len > 0 && len <= 32);
    507 		i += 2;
    508 		INSIST(i + len <= sr->length);
    509 		for (j = 0; j < len; j++) {
    510 			dns_rdatatype_t t;
    511 			if (sr->base[i + j] == 0) {
    512 				continue;
    513 			}
    514 			for (k = 0; k < 8; k++) {
    515 				if ((sr->base[i + j] & (0x80 >> k)) == 0) {
    516 					continue;
    517 				}
    518 				t = window * 256 + j * 8 + k;
    519 				if (!first) {
    520 					RETERR(str_totext(" ", target));
    521 				}
    522 				first = false;
    523 				if (dns_rdatatype_isknown(t)) {
    524 					RETERR(dns_rdatatype_totext(t, target));
    525 				} else {
    526 					char buf[sizeof("TYPE65535")];
    527 					snprintf(buf, sizeof(buf), "TYPE%u", t);
    528 					RETERR(str_totext(buf, target));
    529 				}
    530 			}
    531 		}
    532 	}
    533 	return ISC_R_SUCCESS;
    534 }
    535 
    536 static isc_result_t
    537 typemap_test(isc_region_t *sr, bool allow_empty) {
    538 	unsigned int window, lastwindow = 0;
    539 	unsigned int len;
    540 	bool first = true;
    541 	unsigned int i;
    542 
    543 	for (i = 0; i < sr->length; i += len) {
    544 		/*
    545 		 * Check for overflow.
    546 		 */
    547 		if (i + 2 > sr->length) {
    548 			RETERR(DNS_R_FORMERR);
    549 		}
    550 		window = sr->base[i];
    551 		len = sr->base[i + 1];
    552 		i += 2;
    553 		/*
    554 		 * Check that bitmap windows are in the correct order.
    555 		 */
    556 		if (!first && window <= lastwindow) {
    557 			RETERR(DNS_R_FORMERR);
    558 		}
    559 		/*
    560 		 * Check for legal lengths.
    561 		 */
    562 		if (len < 1 || len > 32) {
    563 			RETERR(DNS_R_FORMERR);
    564 		}
    565 		/*
    566 		 * Check for overflow.
    567 		 */
    568 		if (i + len > sr->length) {
    569 			RETERR(DNS_R_FORMERR);
    570 		}
    571 		/*
    572 		 * The last octet of the bitmap must be non zero.
    573 		 */
    574 		if (sr->base[i + len - 1] == 0) {
    575 			RETERR(DNS_R_FORMERR);
    576 		}
    577 		lastwindow = window;
    578 		first = false;
    579 	}
    580 	if (i != sr->length) {
    581 		return DNS_R_EXTRADATA;
    582 	}
    583 	if (!allow_empty && first) {
    584 		RETERR(DNS_R_FORMERR);
    585 	}
    586 	return ISC_R_SUCCESS;
    587 }
    588 
    589 static isc_result_t
    590 check_private(isc_buffer_t *source, dns_secalg_t alg) {
    591 	isc_region_t sr;
    592 	if (alg == DNS_KEYALG_PRIVATEDNS) {
    593 		dns_fixedname_t fixed;
    594 
    595 		RETERR(dns_name_fromwire(dns_fixedname_initname(&fixed), source,
    596 					 DNS_DECOMPRESS_DEFAULT, NULL));
    597 	} else if (alg == DNS_KEYALG_PRIVATEOID) {
    598 		/*
    599 		 * Check that we can extract the OID from the start of the
    600 		 * key data. We have a length byte followed by the OID BER
    601 		 * encoded.
    602 		 */
    603 		const unsigned char *in = NULL;
    604 		ASN1_OBJECT *obj = NULL;
    605 
    606 		isc_buffer_activeregion(source, &sr);
    607 		if (sr.length < 1 || (unsigned int)*sr.base + 1 > sr.length) {
    608 			RETERR(DNS_R_FORMERR);
    609 		}
    610 		in = sr.base + 1;
    611 		obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
    612 		if (obj == NULL) {
    613 			ERR_clear_error();
    614 			RETERR(DNS_R_FORMERR);
    615 		}
    616 		ASN1_OBJECT_free(obj);
    617 		if ((in - sr.base) != (*sr.base + 1)) {
    618 			RETERR(DNS_R_FORMERR);
    619 		}
    620 	}
    621 	return ISC_R_SUCCESS;
    622 }
    623 
    624 /*
    625  * A relative URI template that has a "dns" variable.
    626  */
    627 static bool
    628 validate_dohpath(isc_region_t *region) {
    629 	const unsigned char *p;
    630 	const unsigned char *v = NULL;
    631 	const unsigned char *n = NULL;
    632 	unsigned char c;
    633 	bool dns = false;
    634 	bool wasop = false;
    635 	enum {
    636 		path,
    637 		variable,
    638 		percent1,
    639 		percent2,
    640 		variable_percent1,
    641 		variable_percent2,
    642 		prefix,
    643 		explode
    644 	} state = path;
    645 
    646 	if (region->length == 0 || *region->base != '/' ||
    647 	    !isc_utf8_valid(region->base, region->length))
    648 	{
    649 		return false;
    650 	}
    651 
    652 	/*
    653 	 * RFC 6570 URI Template check + "dns" variable.
    654 	 */
    655 	p = region->base;
    656 	while (p < region->base + region->length) {
    657 		switch (state) {
    658 		case path:
    659 			switch (*p++) {
    660 			case '{': /*}*/
    661 				state = variable;
    662 				wasop = false;
    663 				v = p;
    664 				break;
    665 			case '%':
    666 				state = percent1;
    667 				break;
    668 			default:
    669 				break;
    670 			}
    671 			break;
    672 		case variable:
    673 			c = *p++;
    674 			switch (c) {
    675 			case '+':
    676 			case '#':
    677 			case '.':
    678 			case '/':
    679 			case ';':
    680 			case '?':
    681 			case '&':
    682 				/* Operators. */
    683 				if (p != v + 1 || wasop) {
    684 					return false;
    685 				}
    686 				wasop = true;
    687 				v = p;
    688 				break;
    689 			case '=':
    690 			case '!':
    691 			case '@':
    692 			case '|':
    693 				/* Reserved operators. */
    694 				return false;
    695 			case '*':
    696 			case ':':
    697 			case '}':
    698 			case ',':
    699 				/* Found the end of the variable name. */
    700 				if (p == (v + 1)) {
    701 					return false;
    702 				}
    703 				/* 'p' has been incremented so 4 not 3 */
    704 				if ((p - v) == 4 && memcmp(v, "dns", 3) == 0) {
    705 					dns = true;
    706 				}
    707 				switch (c) {
    708 				case ':':
    709 					state = prefix;
    710 					n = p;
    711 					break;
    712 				case /*{*/ '}':
    713 					state = path;
    714 					break;
    715 				case '*':
    716 					state = explode;
    717 					break;
    718 				case ',':
    719 					wasop = false;
    720 					v = p;
    721 					break;
    722 				}
    723 				break;
    724 			case '%':
    725 				/* Percent encoded variable name. */
    726 				state = variable_percent1;
    727 				break;
    728 			default:
    729 				/* Valid variable name character? */
    730 				if (c != '_' && !isalnum(c)) {
    731 					return false;
    732 				}
    733 				break;
    734 			}
    735 			break;
    736 		case explode:
    737 			switch (*p++) {
    738 			case ',':
    739 				state = variable;
    740 				wasop = false;
    741 				v = p;
    742 				break;
    743 			case /*}*/ '}':
    744 				state = path;
    745 				break;
    746 			default:
    747 				return false;
    748 			}
    749 			break;
    750 		/* Check % encoding */
    751 		case percent1:
    752 		case percent2:
    753 		case variable_percent1:
    754 		case variable_percent2:
    755 			/* bad percent encoding? */
    756 			if (!isxdigit(*p++)) {
    757 				return false;
    758 			}
    759 			if (state == percent1) {
    760 				state = percent2;
    761 			} else if (state == percent2) {
    762 				state = path;
    763 			} else if (state == variable_percent1) {
    764 				state = variable_percent2;
    765 			} else {
    766 				state = variable;
    767 			}
    768 			break;
    769 		case prefix:
    770 			c = *p++;
    771 			if (!isdigit(c)) {
    772 				/* valid number range [1..9999] */
    773 				if ((p == n + 1) || (p - n) > 5 || *n == '0') {
    774 					return false;
    775 				}
    776 				switch (c) {
    777 				case ',':
    778 					state = variable;
    779 					wasop = false;
    780 					break;
    781 				case /*{*/ '}':
    782 					state = path;
    783 					break;
    784 				default:
    785 					return false;
    786 				}
    787 			}
    788 			break;
    789 		}
    790 	}
    791 	return state == path && dns;
    792 }
    793 
    794 #include "code.h"
    795 
    796 #define META	 0x0001
    797 #define RESERVED 0x0002
    798 
    799 /***
    800  *** Initialization
    801  ***/
    802 
    803 void
    804 dns_rdata_init(dns_rdata_t *rdata) {
    805 	REQUIRE(rdata != NULL);
    806 
    807 	rdata->data = NULL;
    808 	rdata->length = 0;
    809 	rdata->rdclass = 0;
    810 	rdata->type = 0;
    811 	rdata->flags = 0;
    812 	ISC_LINK_INIT(rdata, link);
    813 	/* ISC_LIST_INIT(rdata->list); */
    814 }
    815 
    816 void
    817 dns_rdata_reset(dns_rdata_t *rdata) {
    818 	REQUIRE(rdata != NULL);
    819 
    820 	REQUIRE(!ISC_LINK_LINKED(rdata, link));
    821 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
    822 
    823 	rdata->data = NULL;
    824 	rdata->length = 0;
    825 	rdata->rdclass = 0;
    826 	rdata->type = 0;
    827 	rdata->flags = 0;
    828 }
    829 
    830 /***
    831  ***
    832  ***/
    833 
    834 void
    835 dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
    836 	REQUIRE(src != NULL);
    837 	REQUIRE(target != NULL);
    838 
    839 	REQUIRE(DNS_RDATA_INITIALIZED(target));
    840 
    841 	REQUIRE(DNS_RDATA_VALIDFLAGS(src));
    842 	REQUIRE(DNS_RDATA_VALIDFLAGS(target));
    843 
    844 	target->data = src->data;
    845 	target->length = src->length;
    846 	target->rdclass = src->rdclass;
    847 	target->type = src->type;
    848 	target->flags = src->flags;
    849 }
    850 
    851 /***
    852  *** Comparisons
    853  ***/
    854 
    855 int
    856 dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
    857 	int result = 0;
    858 	bool use_default = false;
    859 
    860 	REQUIRE(rdata1 != NULL);
    861 	REQUIRE(rdata2 != NULL);
    862 	REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
    863 	REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
    864 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
    865 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
    866 
    867 	if (rdata1->rdclass != rdata2->rdclass) {
    868 		return rdata1->rdclass < rdata2->rdclass ? -1 : 1;
    869 	}
    870 
    871 	if (rdata1->type != rdata2->type) {
    872 		return rdata1->type < rdata2->type ? -1 : 1;
    873 	}
    874 
    875 	COMPARESWITCH
    876 
    877 	if (use_default) {
    878 		isc_region_t r1;
    879 		isc_region_t r2;
    880 
    881 		dns_rdata_toregion(rdata1, &r1);
    882 		dns_rdata_toregion(rdata2, &r2);
    883 		result = isc_region_compare(&r1, &r2);
    884 	}
    885 	return result;
    886 }
    887 
    888 int
    889 dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
    890 	int result = 0;
    891 	bool use_default = false;
    892 
    893 	REQUIRE(rdata1 != NULL);
    894 	REQUIRE(rdata2 != NULL);
    895 	REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
    896 	REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
    897 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
    898 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
    899 
    900 	if (rdata1->rdclass != rdata2->rdclass) {
    901 		return rdata1->rdclass < rdata2->rdclass ? -1 : 1;
    902 	}
    903 
    904 	if (rdata1->type != rdata2->type) {
    905 		return rdata1->type < rdata2->type ? -1 : 1;
    906 	}
    907 
    908 	CASECOMPARESWITCH
    909 
    910 	if (use_default) {
    911 		isc_region_t r1;
    912 		isc_region_t r2;
    913 
    914 		dns_rdata_toregion(rdata1, &r1);
    915 		dns_rdata_toregion(rdata2, &r2);
    916 		result = isc_region_compare(&r1, &r2);
    917 	}
    918 	return result;
    919 }
    920 
    921 /***
    922  *** Conversions
    923  ***/
    924 
    925 void
    926 dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
    927 		     dns_rdatatype_t type, isc_region_t *r) {
    928 	REQUIRE(rdata != NULL);
    929 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
    930 	REQUIRE(r != NULL);
    931 
    932 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
    933 
    934 	rdata->data = r->base;
    935 	rdata->length = r->length;
    936 	rdata->rdclass = rdclass;
    937 	rdata->type = type;
    938 	rdata->flags = 0;
    939 }
    940 
    941 void
    942 dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
    943 	REQUIRE(rdata != NULL);
    944 	REQUIRE(r != NULL);
    945 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
    946 
    947 	r->base = rdata->data;
    948 	r->length = rdata->length;
    949 }
    950 
    951 isc_result_t
    952 dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
    953 		   dns_rdatatype_t type, isc_buffer_t *source,
    954 		   dns_decompress_t dctx, isc_buffer_t *target) {
    955 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
    956 	isc_region_t region;
    957 	isc_buffer_t ss;
    958 	isc_buffer_t st;
    959 	bool use_default = false;
    960 	uint32_t activelength;
    961 	unsigned int length;
    962 
    963 	if (rdata != NULL) {
    964 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
    965 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
    966 	}
    967 	REQUIRE(source != NULL);
    968 	REQUIRE(target != NULL);
    969 
    970 	if (type == 0) {
    971 		return DNS_R_FORMERR;
    972 	}
    973 
    974 	ss = *source;
    975 	st = *target;
    976 
    977 	activelength = isc_buffer_activelength(source);
    978 	INSIST(activelength < 65536);
    979 
    980 	FROMWIRESWITCH
    981 
    982 	if (use_default) {
    983 		if (activelength > isc_buffer_availablelength(target)) {
    984 			result = ISC_R_NOSPACE;
    985 		} else {
    986 			isc_buffer_putmem(target, isc_buffer_current(source),
    987 					  activelength);
    988 			isc_buffer_forward(source, activelength);
    989 			result = ISC_R_SUCCESS;
    990 		}
    991 	}
    992 
    993 	/*
    994 	 * Reject any rdata that expands out to more than DNS_RDATA_MAXLENGTH
    995 	 * as we cannot transmit it.
    996 	 */
    997 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
    998 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
    999 		result = DNS_R_FORMERR;
   1000 	}
   1001 
   1002 	/*
   1003 	 * We should have consumed all of our buffer.
   1004 	 */
   1005 	if (result == ISC_R_SUCCESS && !buffer_empty(source)) {
   1006 		result = DNS_R_EXTRADATA;
   1007 	}
   1008 
   1009 	if (rdata != NULL && result == ISC_R_SUCCESS) {
   1010 		region.base = isc_buffer_used(&st);
   1011 		region.length = length;
   1012 		dns_rdata_fromregion(rdata, rdclass, type, &region);
   1013 	}
   1014 
   1015 	if (result != ISC_R_SUCCESS) {
   1016 		*source = ss;
   1017 		*target = st;
   1018 	}
   1019 	return result;
   1020 }
   1021 
   1022 isc_result_t
   1023 dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
   1024 		 isc_buffer_t *target) {
   1025 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1026 	bool use_default = false;
   1027 	isc_region_t tr;
   1028 	isc_buffer_t st;
   1029 
   1030 	REQUIRE(rdata != NULL);
   1031 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1032 
   1033 	/*
   1034 	 * Some DynDNS meta-RRs have empty rdata.
   1035 	 */
   1036 	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
   1037 		INSIST(rdata->length == 0);
   1038 		return ISC_R_SUCCESS;
   1039 	}
   1040 
   1041 	st = *target;
   1042 
   1043 	TOWIRESWITCH
   1044 
   1045 	if (use_default) {
   1046 		isc_buffer_availableregion(target, &tr);
   1047 		if (tr.length < rdata->length) {
   1048 			return ISC_R_NOSPACE;
   1049 		}
   1050 		memmove(tr.base, rdata->data, rdata->length);
   1051 		isc_buffer_add(target, rdata->length);
   1052 		return ISC_R_SUCCESS;
   1053 	}
   1054 	if (result != ISC_R_SUCCESS) {
   1055 		*target = st;
   1056 		dns_compress_rollback(cctx, target->used);
   1057 	}
   1058 	return result;
   1059 }
   1060 
   1061 /*
   1062  * If the binary data in 'src' is valid uncompressed wire format
   1063  * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
   1064  * and copy the validated rdata to 'dest'.  Otherwise return an error.
   1065  */
   1066 static isc_result_t
   1067 rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
   1068 	       dns_rdatatype_t type) {
   1069 	isc_result_t result;
   1070 
   1071 	isc_buffer_setactive(src, isc_buffer_usedlength(src));
   1072 	result = dns_rdata_fromwire(NULL, rdclass, type, src,
   1073 				    DNS_DECOMPRESS_NEVER, dest);
   1074 
   1075 	return result;
   1076 }
   1077 
   1078 static isc_result_t
   1079 unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
   1080 		 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) {
   1081 	isc_result_t result;
   1082 	isc_buffer_t *buf = NULL;
   1083 	isc_token_t token;
   1084 
   1085 	if (type == 0 || dns_rdatatype_ismeta(type)) {
   1086 		return DNS_R_METATYPE;
   1087 	}
   1088 
   1089 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
   1090 				      false));
   1091 	if (token.value.as_ulong > 65535U) {
   1092 		return ISC_R_RANGE;
   1093 	}
   1094 	isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
   1095 
   1096 	if (token.value.as_ulong != 0U) {
   1097 		result = isc_hex_tobuffer(lexer, buf,
   1098 					  (unsigned int)token.value.as_ulong);
   1099 		if (result != ISC_R_SUCCESS) {
   1100 			goto failure;
   1101 		}
   1102 		if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
   1103 			result = ISC_R_UNEXPECTEDEND;
   1104 			goto failure;
   1105 		}
   1106 	}
   1107 
   1108 	if (dns_rdatatype_isknown(type)) {
   1109 		result = rdata_validate(buf, target, rdclass, type);
   1110 	} else {
   1111 		isc_region_t r;
   1112 		isc_buffer_usedregion(buf, &r);
   1113 		result = isc_buffer_copyregion(target, &r);
   1114 	}
   1115 	if (result != ISC_R_SUCCESS) {
   1116 		goto failure;
   1117 	}
   1118 
   1119 	isc_buffer_free(&buf);
   1120 	return ISC_R_SUCCESS;
   1121 
   1122 failure:
   1123 	isc_buffer_free(&buf);
   1124 	return result;
   1125 }
   1126 
   1127 isc_result_t
   1128 dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
   1129 		   dns_rdatatype_t type, isc_lex_t *lexer,
   1130 		   const dns_name_t *origin, unsigned int options,
   1131 		   isc_mem_t *mctx, isc_buffer_t *target,
   1132 		   dns_rdatacallbacks_t *callbacks) {
   1133 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1134 	isc_region_t region;
   1135 	isc_buffer_t st;
   1136 	isc_token_t token;
   1137 	unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
   1138 				  ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
   1139 	char *name;
   1140 	unsigned long line;
   1141 	void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
   1142 	isc_result_t tresult;
   1143 	unsigned int length;
   1144 	bool unknown;
   1145 
   1146 	REQUIRE(origin == NULL || dns_name_isabsolute(origin));
   1147 	if (rdata != NULL) {
   1148 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   1149 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1150 	}
   1151 	if (callbacks != NULL) {
   1152 		REQUIRE(callbacks->warn != NULL);
   1153 		REQUIRE(callbacks->error != NULL);
   1154 	}
   1155 
   1156 	st = *target;
   1157 
   1158 	if (callbacks != NULL) {
   1159 		callback = callbacks->error;
   1160 	} else {
   1161 		callback = default_fromtext_callback;
   1162 	}
   1163 
   1164 	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
   1165 					true);
   1166 	if (result != ISC_R_SUCCESS) {
   1167 		name = isc_lex_getsourcename(lexer);
   1168 		line = isc_lex_getsourceline(lexer);
   1169 		fromtext_error(callback, callbacks, name, line, NULL, result);
   1170 		return result;
   1171 	}
   1172 
   1173 	unknown = false;
   1174 	if (token.type == isc_tokentype_string &&
   1175 	    strcmp(DNS_AS_STR(token), "\\#") == 0)
   1176 	{
   1177 		/*
   1178 		 * If this is a TXT record '\#' could be a escaped '#'.
   1179 		 * Look to see if the next token is a number and if so
   1180 		 * treat it as a unknown record format.
   1181 		 */
   1182 		if (type == dns_rdatatype_txt) {
   1183 			result = isc_lex_getmastertoken(
   1184 				lexer, &token, isc_tokentype_number, false);
   1185 			if (result == ISC_R_SUCCESS) {
   1186 				isc_lex_ungettoken(lexer, &token);
   1187 			}
   1188 		}
   1189 
   1190 		if (result == ISC_R_SUCCESS) {
   1191 			unknown = true;
   1192 			result = unknown_fromtext(rdclass, type, lexer, mctx,
   1193 						  target);
   1194 		} else {
   1195 			options |= DNS_RDATA_UNKNOWNESCAPE;
   1196 		}
   1197 	} else {
   1198 		isc_lex_ungettoken(lexer, &token);
   1199 	}
   1200 
   1201 	if (!unknown) {
   1202 		FROMTEXTSWITCH
   1203 
   1204 		/*
   1205 		 * Consume to end of line / file.
   1206 		 * If not at end of line initially set error code.
   1207 		 * Call callback via fromtext_error once if there was an error.
   1208 		 */
   1209 	}
   1210 	do {
   1211 		name = isc_lex_getsourcename(lexer);
   1212 		line = isc_lex_getsourceline(lexer);
   1213 		tresult = isc_lex_gettoken(lexer, lexoptions, &token);
   1214 		if (tresult != ISC_R_SUCCESS) {
   1215 			if (result == ISC_R_SUCCESS) {
   1216 				result = tresult;
   1217 			}
   1218 			if (callback != NULL) {
   1219 				fromtext_error(callback, callbacks, name, line,
   1220 					       NULL, result);
   1221 			}
   1222 			break;
   1223 		} else if (token.type != isc_tokentype_eol &&
   1224 			   token.type != isc_tokentype_eof)
   1225 		{
   1226 			if (result == ISC_R_SUCCESS) {
   1227 				result = DNS_R_EXTRATOKEN;
   1228 			}
   1229 			if (callback != NULL) {
   1230 				fromtext_error(callback, callbacks, name, line,
   1231 					       &token, result);
   1232 				callback = NULL;
   1233 			}
   1234 		} else if (result != ISC_R_SUCCESS && callback != NULL) {
   1235 			fromtext_error(callback, callbacks, name, line, &token,
   1236 				       result);
   1237 			break;
   1238 		} else {
   1239 			if (token.type == isc_tokentype_eof) {
   1240 				fromtext_warneof(lexer, callbacks);
   1241 			}
   1242 			break;
   1243 		}
   1244 	} while (1);
   1245 
   1246 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
   1247 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
   1248 		result = ISC_R_NOSPACE;
   1249 	}
   1250 
   1251 	if (rdata != NULL && result == ISC_R_SUCCESS) {
   1252 		region.base = isc_buffer_used(&st);
   1253 		region.length = length;
   1254 		dns_rdata_fromregion(rdata, rdclass, type, &region);
   1255 	}
   1256 	if (result != ISC_R_SUCCESS) {
   1257 		*target = st;
   1258 	}
   1259 	return result;
   1260 }
   1261 
   1262 static isc_result_t
   1263 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
   1264 	       isc_buffer_t *target) {
   1265 	isc_result_t result;
   1266 	char buf[sizeof("65535")];
   1267 	isc_region_t sr;
   1268 
   1269 	strlcpy(buf, "\\# ", sizeof(buf));
   1270 	result = str_totext(buf, target);
   1271 	if (result != ISC_R_SUCCESS) {
   1272 		return result;
   1273 	}
   1274 
   1275 	dns_rdata_toregion(rdata, &sr);
   1276 	INSIST(sr.length < 65536);
   1277 	snprintf(buf, sizeof(buf), "%u", sr.length);
   1278 	result = str_totext(buf, target);
   1279 	if (result != ISC_R_SUCCESS) {
   1280 		return result;
   1281 	}
   1282 
   1283 	if (sr.length != 0U) {
   1284 		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
   1285 			result = str_totext(" ( ", target);
   1286 		} else {
   1287 			result = str_totext(" ", target);
   1288 		}
   1289 
   1290 		if (result != ISC_R_SUCCESS) {
   1291 			return result;
   1292 		}
   1293 
   1294 		if (tctx->width == 0) { /* No splitting */
   1295 			result = isc_hex_totext(&sr, 0, "", target);
   1296 		} else {
   1297 			result = isc_hex_totext(&sr, tctx->width - 2,
   1298 						tctx->linebreak, target);
   1299 		}
   1300 		if (result == ISC_R_SUCCESS &&
   1301 		    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
   1302 		{
   1303 			result = str_totext(" )", target);
   1304 		}
   1305 	}
   1306 	return result;
   1307 }
   1308 
   1309 static isc_result_t
   1310 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
   1311 	     isc_buffer_t *target) {
   1312 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1313 	bool use_default = false;
   1314 	unsigned int cur;
   1315 
   1316 	REQUIRE(rdata != NULL);
   1317 	REQUIRE(tctx->origin == NULL || dns_name_isabsolute(tctx->origin));
   1318 
   1319 	/*
   1320 	 * Some DynDNS meta-RRs have empty rdata.
   1321 	 */
   1322 	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
   1323 		INSIST(rdata->length == 0);
   1324 		return ISC_R_SUCCESS;
   1325 	}
   1326 
   1327 	if ((tctx->flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0) {
   1328 		return unknown_totext(rdata, tctx, target);
   1329 	}
   1330 
   1331 	cur = isc_buffer_usedlength(target);
   1332 
   1333 	TOTEXTSWITCH
   1334 
   1335 	if (use_default || (result == ISC_R_NOTIMPLEMENTED)) {
   1336 		unsigned int u = isc_buffer_usedlength(target);
   1337 
   1338 		INSIST(u >= cur);
   1339 		isc_buffer_subtract(target, u - cur);
   1340 		result = unknown_totext(rdata, tctx, target);
   1341 	}
   1342 
   1343 	return result;
   1344 }
   1345 
   1346 isc_result_t
   1347 dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin,
   1348 		 isc_buffer_t *target) {
   1349 	dns_rdata_textctx_t tctx;
   1350 
   1351 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1352 
   1353 	/*
   1354 	 * Set up formatting options for single-line output.
   1355 	 */
   1356 	tctx.origin = origin;
   1357 	tctx.flags = 0;
   1358 	tctx.width = 60;
   1359 	tctx.linebreak = " ";
   1360 	return rdata_totext(rdata, &tctx, target);
   1361 }
   1362 
   1363 isc_result_t
   1364 dns_rdata_tofmttext(dns_rdata_t *rdata, const dns_name_t *origin,
   1365 		    dns_masterstyle_flags_t flags, unsigned int width,
   1366 		    unsigned int split_width, const char *linebreak,
   1367 		    isc_buffer_t *target) {
   1368 	dns_rdata_textctx_t tctx;
   1369 
   1370 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1371 
   1372 	/*
   1373 	 * Set up formatting options for formatted output.
   1374 	 */
   1375 	tctx.origin = origin;
   1376 	tctx.flags = flags;
   1377 	if (split_width == 0xffffffff) {
   1378 		tctx.width = width;
   1379 	} else {
   1380 		tctx.width = split_width;
   1381 	}
   1382 
   1383 	if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
   1384 		tctx.linebreak = linebreak;
   1385 	} else {
   1386 		if (split_width == 0xffffffff) {
   1387 			tctx.width = 60; /* Used for hex word length only. */
   1388 		}
   1389 		tctx.linebreak = " ";
   1390 	}
   1391 	return rdata_totext(rdata, &tctx, target);
   1392 }
   1393 
   1394 isc_result_t
   1395 dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
   1396 		     dns_rdatatype_t type, void *source, isc_buffer_t *target) {
   1397 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1398 	isc_buffer_t st;
   1399 	isc_region_t region;
   1400 	bool use_default = false;
   1401 	unsigned int length;
   1402 
   1403 	REQUIRE(source != NULL);
   1404 	if (rdata != NULL) {
   1405 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   1406 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1407 	}
   1408 
   1409 	st = *target;
   1410 
   1411 	FROMSTRUCTSWITCH
   1412 
   1413 	if (use_default) {
   1414 		(void)NULL;
   1415 	}
   1416 
   1417 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
   1418 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
   1419 		result = ISC_R_NOSPACE;
   1420 	}
   1421 
   1422 	if (rdata != NULL && result == ISC_R_SUCCESS) {
   1423 		region.base = isc_buffer_used(&st);
   1424 		region.length = length;
   1425 		dns_rdata_fromregion(rdata, rdclass, type, &region);
   1426 	}
   1427 	if (result != ISC_R_SUCCESS) {
   1428 		*target = st;
   1429 	}
   1430 	return result;
   1431 }
   1432 
   1433 isc_result_t
   1434 dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
   1435 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1436 	bool use_default = false;
   1437 
   1438 	REQUIRE(rdata != NULL);
   1439 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1440 	REQUIRE((rdata->flags & DNS_RDATA_UPDATE) == 0);
   1441 
   1442 	TOSTRUCTSWITCH
   1443 
   1444 	if (use_default) {
   1445 		(void)NULL;
   1446 	}
   1447 
   1448 	return result;
   1449 }
   1450 
   1451 void
   1452 dns_rdata_freestruct(void *source) {
   1453 	dns_rdatacommon_t *common = source;
   1454 	REQUIRE(common != NULL);
   1455 
   1456 	FREESTRUCTSWITCH
   1457 }
   1458 
   1459 isc_result_t
   1460 dns_rdata_additionaldata(dns_rdata_t *rdata, const dns_name_t *owner,
   1461 			 dns_additionaldatafunc_t add, void *arg) {
   1462 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1463 	bool use_default = false;
   1464 
   1465 	/*
   1466 	 * Call 'add' for each name and type from 'rdata' which is subject to
   1467 	 * additional section processing.
   1468 	 */
   1469 
   1470 	REQUIRE(rdata != NULL);
   1471 	REQUIRE(add != NULL);
   1472 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1473 
   1474 	ADDITIONALDATASWITCH
   1475 
   1476 	/* No additional processing for unknown types */
   1477 	if (use_default) {
   1478 		result = ISC_R_SUCCESS;
   1479 	}
   1480 
   1481 	return result;
   1482 }
   1483 
   1484 isc_result_t
   1485 dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
   1486 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
   1487 	bool use_default = false;
   1488 	isc_region_t r;
   1489 
   1490 	/*
   1491 	 * Send 'rdata' in DNSSEC canonical form to 'digest'.
   1492 	 */
   1493 
   1494 	REQUIRE(rdata != NULL);
   1495 	REQUIRE(digest != NULL);
   1496 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   1497 
   1498 	DIGESTSWITCH
   1499 
   1500 	if (use_default) {
   1501 		dns_rdata_toregion(rdata, &r);
   1502 		result = (digest)(arg, &r);
   1503 	}
   1504 
   1505 	return result;
   1506 }
   1507 
   1508 bool
   1509 dns_rdata_checkowner(const dns_name_t *name, dns_rdataclass_t rdclass,
   1510 		     dns_rdatatype_t type, bool wildcard) {
   1511 	bool result;
   1512 
   1513 	CHECKOWNERSWITCH
   1514 	return result;
   1515 }
   1516 
   1517 bool
   1518 dns_rdata_checknames(dns_rdata_t *rdata, const dns_name_t *owner,
   1519 		     dns_name_t *bad) {
   1520 	bool result;
   1521 
   1522 	CHECKNAMESSWITCH
   1523 	return result;
   1524 }
   1525 
   1526 unsigned int
   1527 dns_rdatatype_attributes(dns_rdatatype_t type) {
   1528 	RDATATYPE_ATTRIBUTE_SW
   1529 	if (type >= (dns_rdatatype_t)128 && type <= (dns_rdatatype_t)255) {
   1530 		return DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META;
   1531 	}
   1532 	return DNS_RDATATYPEATTR_UNKNOWN;
   1533 }
   1534 
   1535 isc_result_t
   1536 dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
   1537 	unsigned int hash;
   1538 	unsigned int n;
   1539 	unsigned char a, b;
   1540 
   1541 	n = source->length;
   1542 
   1543 	if (n == 0) {
   1544 		return DNS_R_UNKNOWN;
   1545 	}
   1546 
   1547 	a = isc_ascii_tolower(source->base[0]);
   1548 	b = isc_ascii_tolower(source->base[n - 1]);
   1549 
   1550 	hash = ((a + n) * b) % 256;
   1551 
   1552 	/*
   1553 	 * This switch block is inlined via \#define, and will use "return"
   1554 	 * to return a result to the caller if it is a valid (known)
   1555 	 * rdatatype name.
   1556 	 */
   1557 	RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
   1558 
   1559 	if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
   1560 	    strncasecmp("type", source->base, 4) == 0)
   1561 	{
   1562 		char buf[sizeof("65000")];
   1563 		char *endp;
   1564 		unsigned int val;
   1565 
   1566 		/*
   1567 		 * source->base is not required to be NUL terminated.
   1568 		 * Copy up to remaining bytes and NUL terminate.
   1569 		 */
   1570 		snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4),
   1571 			 source->base + 4);
   1572 		val = strtoul(buf, &endp, 10);
   1573 		if (*endp == '\0' && val <= 0xffff) {
   1574 			*typep = (dns_rdatatype_t)val;
   1575 			return ISC_R_SUCCESS;
   1576 		}
   1577 	}
   1578 
   1579 	return DNS_R_UNKNOWN;
   1580 }
   1581 
   1582 isc_result_t
   1583 dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
   1584 	RDATATYPE_TOTEXT_SW
   1585 
   1586 	return dns_rdatatype_tounknowntext(type, target);
   1587 }
   1588 
   1589 isc_result_t
   1590 dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target) {
   1591 	char buf[sizeof("TYPE65535")];
   1592 
   1593 	snprintf(buf, sizeof(buf), "TYPE%u", type);
   1594 	return str_totext(buf, target);
   1595 }
   1596 
   1597 void
   1598 dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size) {
   1599 	isc_result_t result;
   1600 	isc_buffer_t buf;
   1601 
   1602 	if (size == 0U) {
   1603 		return;
   1604 	}
   1605 
   1606 	isc_buffer_init(&buf, array, size);
   1607 	result = dns_rdatatype_totext(rdtype, &buf);
   1608 	/*
   1609 	 * Null terminate.
   1610 	 */
   1611 	if (result == ISC_R_SUCCESS) {
   1612 		if (isc_buffer_availablelength(&buf) >= 1) {
   1613 			isc_buffer_putuint8(&buf, 0);
   1614 		} else {
   1615 			result = ISC_R_NOSPACE;
   1616 		}
   1617 	}
   1618 	if (result != ISC_R_SUCCESS) {
   1619 		strlcpy(array, "<unknown>", size);
   1620 	}
   1621 }
   1622 
   1623 /*
   1624  * Private function.
   1625  */
   1626 
   1627 static unsigned int
   1628 name_length(const dns_name_t *name) {
   1629 	return name->length;
   1630 }
   1631 
   1632 static isc_result_t
   1633 commatxt_totext(isc_region_t *source, bool quote, bool comma,
   1634 		isc_buffer_t *target) {
   1635 	unsigned int tl;
   1636 	unsigned int n;
   1637 	unsigned char *sp;
   1638 	char *tp;
   1639 	isc_region_t region;
   1640 
   1641 	isc_buffer_availableregion(target, &region);
   1642 	sp = source->base;
   1643 	tp = (char *)region.base;
   1644 	tl = region.length;
   1645 
   1646 	n = *sp++;
   1647 
   1648 	REQUIRE(n + 1 <= source->length);
   1649 	if (n == 0U) {
   1650 		REQUIRE(quote);
   1651 	}
   1652 
   1653 	if (quote) {
   1654 		if (tl < 1) {
   1655 			return ISC_R_NOSPACE;
   1656 		}
   1657 		*tp++ = '"';
   1658 		tl--;
   1659 	}
   1660 	while (n--) {
   1661 		/*
   1662 		 * \DDD space (0x20) if not quoting.
   1663 		 */
   1664 		if (*sp < (quote ? ' ' : '!') || *sp >= 0x7f) {
   1665 			if (tl < 4) {
   1666 				return ISC_R_NOSPACE;
   1667 			}
   1668 			*tp++ = '\\';
   1669 			*tp++ = '0' + ((*sp / 100) % 10);
   1670 			*tp++ = '0' + ((*sp / 10) % 10);
   1671 			*tp++ = '0' + (*sp % 10);
   1672 			sp++;
   1673 			tl -= 4;
   1674 			continue;
   1675 		}
   1676 		/*
   1677 		 * Escape double quote and backslash.  If we are not
   1678 		 * enclosing the string in double quotes, also escape
   1679 		 * at sign (@) and semicolon (;) unless comma is set.
   1680 		 * If comma is set, then only escape commas (,).
   1681 		 */
   1682 		if (*sp == '"' || *sp == '\\' || (comma && *sp == ',') ||
   1683 		    (!comma && !quote && (*sp == '@' || *sp == ';')))
   1684 		{
   1685 			if (tl < 2) {
   1686 				return ISC_R_NOSPACE;
   1687 			}
   1688 			*tp++ = '\\';
   1689 			tl--;
   1690 			/*
   1691 			 * Perform comma escape processing.
   1692 			 * ',' => '\\,'
   1693 			 * '\' => '\\\\'
   1694 			 */
   1695 			if (comma && (*sp == ',' || *sp == '\\')) {
   1696 				if (tl < ((*sp == '\\') ? 3 : 2)) {
   1697 					return ISC_R_NOSPACE;
   1698 				}
   1699 				*tp++ = '\\';
   1700 				tl--;
   1701 				if (*sp == '\\') {
   1702 					*tp++ = '\\';
   1703 					tl--;
   1704 				}
   1705 			}
   1706 		}
   1707 		if (tl < 1) {
   1708 			return ISC_R_NOSPACE;
   1709 		}
   1710 		*tp++ = *sp++;
   1711 		tl--;
   1712 	}
   1713 	if (quote) {
   1714 		if (tl < 1) {
   1715 			return ISC_R_NOSPACE;
   1716 		}
   1717 		*tp++ = '"';
   1718 		tl--;
   1719 		POST(tl);
   1720 	}
   1721 	isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
   1722 	isc_region_consume(source, *source->base + 1);
   1723 	return ISC_R_SUCCESS;
   1724 }
   1725 
   1726 static isc_result_t
   1727 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) {
   1728 	return commatxt_totext(source, quote, false, target);
   1729 }
   1730 
   1731 static isc_result_t
   1732 commatxt_fromtext(isc_textregion_t *source, bool comma, isc_buffer_t *target) {
   1733 	isc_region_t tregion;
   1734 	bool escape = false, comma_escape = false, seen_comma = false;
   1735 	unsigned int n, nrem;
   1736 	char *s;
   1737 	unsigned char *t;
   1738 	int d;
   1739 	int c;
   1740 
   1741 	isc_buffer_availableregion(target, &tregion);
   1742 	s = source->base;
   1743 	n = source->length;
   1744 	t = tregion.base;
   1745 	nrem = tregion.length;
   1746 	if (nrem < 1) {
   1747 		return ISC_R_NOSPACE;
   1748 	}
   1749 	/*
   1750 	 * Length byte.
   1751 	 */
   1752 	nrem--;
   1753 	t++;
   1754 	/*
   1755 	 * Maximum text string length.
   1756 	 */
   1757 	if (nrem > 255) {
   1758 		nrem = 255;
   1759 	}
   1760 	while (n-- != 0) {
   1761 		c = (*s++) & 0xff;
   1762 		if (escape && (d = decvalue((char)c)) != -1) {
   1763 			c = d;
   1764 			if (n == 0) {
   1765 				return DNS_R_SYNTAX;
   1766 			}
   1767 			n--;
   1768 			if ((d = decvalue(*s++)) != -1) {
   1769 				c = c * 10 + d;
   1770 			} else {
   1771 				return DNS_R_SYNTAX;
   1772 			}
   1773 			if (n == 0) {
   1774 				return DNS_R_SYNTAX;
   1775 			}
   1776 			n--;
   1777 			if ((d = decvalue(*s++)) != -1) {
   1778 				c = c * 10 + d;
   1779 			} else {
   1780 				return DNS_R_SYNTAX;
   1781 			}
   1782 			if (c > 255) {
   1783 				return DNS_R_SYNTAX;
   1784 			}
   1785 		} else if (!escape && c == '\\') {
   1786 			escape = true;
   1787 			continue;
   1788 		}
   1789 		escape = false;
   1790 		/*
   1791 		 * Level 1 escape processing complete.
   1792 		 * If comma is set perform comma escape processing.
   1793 		 *
   1794 		 * Level 1	Level 2		ALPN's
   1795 		 * h1\,h2   =>	h1,h2   =>	h1 and h2
   1796 		 * h1\\,h2  =>	h1\,h2  =>	h1,h2
   1797 		 * h1\\h2   =>	h1\h2   =>	h1h2
   1798 		 * h1\\\\h2 =>	h1\\h2  =>	h1\h2
   1799 		 */
   1800 		if (comma && !comma_escape && c == ',') {
   1801 			seen_comma = true;
   1802 			break;
   1803 		}
   1804 		if (comma && !comma_escape && c == '\\') {
   1805 			comma_escape = true;
   1806 			continue;
   1807 		}
   1808 		comma_escape = false;
   1809 		if (nrem == 0) {
   1810 			return (tregion.length <= 256U) ? ISC_R_NOSPACE
   1811 							: DNS_R_SYNTAX;
   1812 		}
   1813 		*t++ = c;
   1814 		nrem--;
   1815 	}
   1816 
   1817 	/*
   1818 	 * Incomplete escape processing?
   1819 	 */
   1820 	if (escape || (comma && comma_escape)) {
   1821 		return DNS_R_SYNTAX;
   1822 	}
   1823 
   1824 	if (comma) {
   1825 		/*
   1826 		 * Disallow empty ALPN at start (",h1" or "\,h1") or
   1827 		 * in the middle ("h1,,h2" or "h1\,\,h2").
   1828 		 */
   1829 		if ((t - tregion.base - 1) == 0) {
   1830 			return DNS_R_SYNTAX;
   1831 		}
   1832 
   1833 		/*
   1834 		 * Consume this ALPN and possible ending comma.
   1835 		 */
   1836 		isc_textregion_consume(source, s - source->base);
   1837 
   1838 		/*
   1839 		 * Disallow empty ALPN at end ("h1," or "h1\,").
   1840 		 */
   1841 		if (seen_comma && source->length == 0) {
   1842 			return DNS_R_SYNTAX;
   1843 		}
   1844 	}
   1845 
   1846 	*tregion.base = (unsigned char)(t - tregion.base - 1);
   1847 	isc_buffer_add(target, *tregion.base + 1);
   1848 	return ISC_R_SUCCESS;
   1849 }
   1850 
   1851 static isc_result_t
   1852 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
   1853 	return commatxt_fromtext(source, false, target);
   1854 }
   1855 
   1856 static isc_result_t
   1857 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
   1858 	unsigned int n;
   1859 	isc_region_t sregion;
   1860 	isc_region_t tregion;
   1861 
   1862 	isc_buffer_activeregion(source, &sregion);
   1863 	if (sregion.length == 0) {
   1864 		return ISC_R_UNEXPECTEDEND;
   1865 	}
   1866 	n = *sregion.base + 1;
   1867 	if (n > sregion.length) {
   1868 		return ISC_R_UNEXPECTEDEND;
   1869 	}
   1870 
   1871 	isc_buffer_availableregion(target, &tregion);
   1872 	if (n > tregion.length) {
   1873 		return ISC_R_NOSPACE;
   1874 	}
   1875 
   1876 	if (tregion.base != sregion.base) {
   1877 		memmove(tregion.base, sregion.base, n);
   1878 	}
   1879 	isc_buffer_forward(source, n);
   1880 	isc_buffer_add(target, n);
   1881 	return ISC_R_SUCCESS;
   1882 }
   1883 
   1884 /*
   1885  * Conversion of TXT-like rdata fields without length limits.
   1886  */
   1887 static isc_result_t
   1888 multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
   1889 	unsigned int tl;
   1890 	unsigned int n0, n;
   1891 	unsigned char *sp;
   1892 	char *tp;
   1893 	isc_region_t region;
   1894 
   1895 	isc_buffer_availableregion(target, &region);
   1896 	sp = source->base;
   1897 	tp = (char *)region.base;
   1898 	tl = region.length;
   1899 
   1900 	if (tl < 1) {
   1901 		return ISC_R_NOSPACE;
   1902 	}
   1903 	*tp++ = '"';
   1904 	tl--;
   1905 	do {
   1906 		n = source->length;
   1907 		n0 = source->length - 1;
   1908 
   1909 		while (n--) {
   1910 			if (*sp < ' ' || *sp >= 0x7f) {
   1911 				if (tl < 4) {
   1912 					return ISC_R_NOSPACE;
   1913 				}
   1914 				*tp++ = '\\';
   1915 				*tp++ = '0' + ((*sp / 100) % 10);
   1916 				*tp++ = '0' + ((*sp / 10) % 10);
   1917 				*tp++ = '0' + (*sp % 10);
   1918 				sp++;
   1919 				tl -= 4;
   1920 				continue;
   1921 			}
   1922 			/* double quote, backslash */
   1923 			if (*sp == '"' || *sp == '\\') {
   1924 				if (tl < 2) {
   1925 					return ISC_R_NOSPACE;
   1926 				}
   1927 				*tp++ = '\\';
   1928 				tl--;
   1929 			}
   1930 			if (tl < 1) {
   1931 				return ISC_R_NOSPACE;
   1932 			}
   1933 			*tp++ = *sp++;
   1934 			tl--;
   1935 		}
   1936 		isc_region_consume(source, n0 + 1);
   1937 	} while (source->length != 0);
   1938 	if (tl < 1) {
   1939 		return ISC_R_NOSPACE;
   1940 	}
   1941 	*tp++ = '"';
   1942 	tl--;
   1943 	POST(tl);
   1944 	isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
   1945 	return ISC_R_SUCCESS;
   1946 }
   1947 
   1948 static isc_result_t
   1949 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
   1950 	isc_region_t tregion;
   1951 	bool escape;
   1952 	unsigned int n, nrem;
   1953 	char *s;
   1954 	unsigned char *t0, *t;
   1955 	int d;
   1956 	int c;
   1957 
   1958 	s = source->base;
   1959 	n = source->length;
   1960 	escape = false;
   1961 
   1962 	do {
   1963 		isc_buffer_availableregion(target, &tregion);
   1964 		t0 = t = tregion.base;
   1965 		nrem = tregion.length;
   1966 		if (nrem < 1) {
   1967 			return ISC_R_NOSPACE;
   1968 		}
   1969 
   1970 		while (n != 0) {
   1971 			--n;
   1972 			c = (*s++) & 0xff;
   1973 			if (escape && (d = decvalue((char)c)) != -1) {
   1974 				c = d;
   1975 				if (n == 0) {
   1976 					return DNS_R_SYNTAX;
   1977 				}
   1978 				n--;
   1979 				if ((d = decvalue(*s++)) != -1) {
   1980 					c = c * 10 + d;
   1981 				} else {
   1982 					return DNS_R_SYNTAX;
   1983 				}
   1984 				if (n == 0) {
   1985 					return DNS_R_SYNTAX;
   1986 				}
   1987 				n--;
   1988 				if ((d = decvalue(*s++)) != -1) {
   1989 					c = c * 10 + d;
   1990 				} else {
   1991 					return DNS_R_SYNTAX;
   1992 				}
   1993 				if (c > 255) {
   1994 					return DNS_R_SYNTAX;
   1995 				}
   1996 			} else if (!escape && c == '\\') {
   1997 				escape = true;
   1998 				continue;
   1999 			}
   2000 			escape = false;
   2001 			*t++ = c;
   2002 			nrem--;
   2003 			if (nrem == 0) {
   2004 				break;
   2005 			}
   2006 		}
   2007 		if (escape) {
   2008 			return DNS_R_SYNTAX;
   2009 		}
   2010 
   2011 		isc_buffer_add(target, (unsigned int)(t - t0));
   2012 	} while (n != 0);
   2013 	return ISC_R_SUCCESS;
   2014 }
   2015 
   2016 static bool
   2017 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target) {
   2018 	int l1, l2;
   2019 
   2020 	if (origin == NULL) {
   2021 		goto return_false;
   2022 	}
   2023 
   2024 	if (dns_name_compare(origin, dns_rootname) == 0) {
   2025 		goto return_false;
   2026 	}
   2027 
   2028 	if (!dns_name_issubdomain(name, origin)) {
   2029 		goto return_false;
   2030 	}
   2031 
   2032 	l1 = dns_name_countlabels(name);
   2033 	l2 = dns_name_countlabels(origin);
   2034 
   2035 	if (l1 == l2) {
   2036 		goto return_false;
   2037 	}
   2038 
   2039 	/* Master files should be case preserving. */
   2040 	dns_name_getlabelsequence(name, l1 - l2, l2, target);
   2041 	if (!dns_name_caseequal(origin, target)) {
   2042 		goto return_false;
   2043 	}
   2044 
   2045 	dns_name_getlabelsequence(name, 0, l1 - l2, target);
   2046 	return true;
   2047 
   2048 return_false:
   2049 	*target = *name;
   2050 	return false;
   2051 }
   2052 
   2053 static isc_result_t
   2054 str_totext(const char *source, isc_buffer_t *target) {
   2055 	unsigned int l;
   2056 	isc_region_t region;
   2057 
   2058 	isc_buffer_availableregion(target, &region);
   2059 	l = strlen(source);
   2060 
   2061 	if (l > region.length) {
   2062 		return ISC_R_NOSPACE;
   2063 	}
   2064 
   2065 	memmove(region.base, source, l);
   2066 	isc_buffer_add(target, l);
   2067 	return ISC_R_SUCCESS;
   2068 }
   2069 
   2070 static isc_result_t
   2071 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target) {
   2072 	char tmpbuf[64];
   2073 
   2074 	/* Note - inet_ntop doesn't do size checking on its input. */
   2075 	if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) {
   2076 		return ISC_R_NOSPACE;
   2077 	}
   2078 	if (strlen(tmpbuf) > isc_buffer_availablelength(target)) {
   2079 		return ISC_R_NOSPACE;
   2080 	}
   2081 	isc_buffer_putstr(target, tmpbuf);
   2082 
   2083 	/*
   2084 	 * An IPv6 address ending in "::" breaks YAML
   2085 	 * parsing, so append 0 in that case.
   2086 	 */
   2087 	if (af == AF_INET6 && (flags & DNS_STYLEFLAG_YAML) != 0) {
   2088 		isc_region_t r;
   2089 		isc_buffer_usedregion(target, &r);
   2090 		if (r.length > 0 && r.base[r.length - 1] == ':') {
   2091 			if (isc_buffer_availablelength(target) == 0) {
   2092 				return ISC_R_NOSPACE;
   2093 			}
   2094 			isc_buffer_putmem(target, (const unsigned char *)"0",
   2095 					  1);
   2096 		}
   2097 	}
   2098 
   2099 	return ISC_R_SUCCESS;
   2100 }
   2101 
   2102 static bool
   2103 buffer_empty(isc_buffer_t *source) {
   2104 	return (source->current == source->active) ? true : false;
   2105 }
   2106 
   2107 static void
   2108 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
   2109 	isc_buffer_init(buffer, region->base, region->length);
   2110 	isc_buffer_add(buffer, region->length);
   2111 	isc_buffer_setactive(buffer, region->length);
   2112 }
   2113 
   2114 static isc_result_t
   2115 uint32_tobuffer(uint32_t value, isc_buffer_t *target) {
   2116 	isc_region_t region;
   2117 
   2118 	isc_buffer_availableregion(target, &region);
   2119 	if (region.length < 4) {
   2120 		return ISC_R_NOSPACE;
   2121 	}
   2122 	isc_buffer_putuint32(target, value);
   2123 	return ISC_R_SUCCESS;
   2124 }
   2125 
   2126 static isc_result_t
   2127 uint16_tobuffer(uint32_t value, isc_buffer_t *target) {
   2128 	isc_region_t region;
   2129 
   2130 	if (value > 0xffff) {
   2131 		return ISC_R_RANGE;
   2132 	}
   2133 	isc_buffer_availableregion(target, &region);
   2134 	if (region.length < 2) {
   2135 		return ISC_R_NOSPACE;
   2136 	}
   2137 	isc_buffer_putuint16(target, (uint16_t)value);
   2138 	return ISC_R_SUCCESS;
   2139 }
   2140 
   2141 static isc_result_t
   2142 uint8_tobuffer(uint32_t value, isc_buffer_t *target) {
   2143 	isc_region_t region;
   2144 
   2145 	if (value > 0xff) {
   2146 		return ISC_R_RANGE;
   2147 	}
   2148 	isc_buffer_availableregion(target, &region);
   2149 	if (region.length < 1) {
   2150 		return ISC_R_NOSPACE;
   2151 	}
   2152 	isc_buffer_putuint8(target, (uint8_t)value);
   2153 	return ISC_R_SUCCESS;
   2154 }
   2155 
   2156 static isc_result_t
   2157 name_tobuffer(const dns_name_t *name, isc_buffer_t *target) {
   2158 	isc_region_t r;
   2159 	dns_name_toregion(name, &r);
   2160 	return isc_buffer_copyregion(target, &r);
   2161 }
   2162 
   2163 static uint32_t
   2164 uint32_fromregion(isc_region_t *region) {
   2165 	uint32_t value;
   2166 
   2167 	REQUIRE(region->length >= 4);
   2168 	value = (uint32_t)region->base[0] << 24;
   2169 	value |= (uint32_t)region->base[1] << 16;
   2170 	value |= (uint32_t)region->base[2] << 8;
   2171 	value |= (uint32_t)region->base[3];
   2172 	return value;
   2173 }
   2174 
   2175 static uint16_t
   2176 uint16_consume_fromregion(isc_region_t *region) {
   2177 	uint16_t r = uint16_fromregion(region);
   2178 
   2179 	isc_region_consume(region, 2);
   2180 	return r;
   2181 }
   2182 
   2183 static uint16_t
   2184 uint16_fromregion(isc_region_t *region) {
   2185 	REQUIRE(region->length >= 2);
   2186 
   2187 	return (region->base[0] << 8) | region->base[1];
   2188 }
   2189 
   2190 static uint8_t
   2191 uint8_fromregion(isc_region_t *region) {
   2192 	REQUIRE(region->length >= 1);
   2193 
   2194 	return region->base[0];
   2195 }
   2196 
   2197 static uint8_t
   2198 uint8_consume_fromregion(isc_region_t *region) {
   2199 	uint8_t r = uint8_fromregion(region);
   2200 
   2201 	isc_region_consume(region, 1);
   2202 	return r;
   2203 }
   2204 
   2205 static isc_result_t
   2206 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
   2207 	isc_region_t tr;
   2208 
   2209 	if (length == 0U) {
   2210 		return ISC_R_SUCCESS;
   2211 	}
   2212 
   2213 	isc_buffer_availableregion(target, &tr);
   2214 	if (length > tr.length) {
   2215 		return ISC_R_NOSPACE;
   2216 	}
   2217 	if (tr.base != base) {
   2218 		memmove(tr.base, base, length);
   2219 	}
   2220 	isc_buffer_add(target, length);
   2221 	return ISC_R_SUCCESS;
   2222 }
   2223 
   2224 static int
   2225 hexvalue(char value) {
   2226 	int hexval = isc_hex_char(value);
   2227 	if (hexval == 0) {
   2228 		return -1;
   2229 	} else {
   2230 		return value - hexval;
   2231 	}
   2232 }
   2233 
   2234 static int
   2235 decvalue(char value) {
   2236 	if (isdigit((unsigned char)value)) {
   2237 		return value - '0';
   2238 	} else {
   2239 		return -1;
   2240 	}
   2241 }
   2242 
   2243 static void
   2244 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
   2245 			  ...) {
   2246 	va_list ap;
   2247 
   2248 	UNUSED(callbacks);
   2249 
   2250 	va_start(ap, fmt);
   2251 	vfprintf(stderr, fmt, ap);
   2252 	va_end(ap);
   2253 	fprintf(stderr, "\n");
   2254 }
   2255 
   2256 static void
   2257 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
   2258 	if (isc_lex_isfile(lexer) && callbacks != NULL) {
   2259 		const char *name = isc_lex_getsourcename(lexer);
   2260 		if (name == NULL) {
   2261 			name = "UNKNOWN";
   2262 		}
   2263 		(*callbacks->warn)(callbacks,
   2264 				   "%s:%lu: file does not end with newline",
   2265 				   name, isc_lex_getsourceline(lexer));
   2266 	}
   2267 }
   2268 
   2269 static void
   2270 warn_badmx(isc_token_t *token, isc_lex_t *lexer,
   2271 	   dns_rdatacallbacks_t *callbacks) {
   2272 	const char *file;
   2273 	unsigned long line;
   2274 
   2275 	if (lexer != NULL) {
   2276 		file = isc_lex_getsourcename(lexer);
   2277 		line = isc_lex_getsourceline(lexer);
   2278 		(*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", file,
   2279 				   line, DNS_AS_STR(*token),
   2280 				   isc_result_totext(DNS_R_MXISADDRESS));
   2281 	}
   2282 }
   2283 
   2284 static void
   2285 warn_badname(const dns_name_t *name, isc_lex_t *lexer,
   2286 	     dns_rdatacallbacks_t *callbacks) {
   2287 	const char *file;
   2288 	unsigned long line;
   2289 	char namebuf[DNS_NAME_FORMATSIZE];
   2290 
   2291 	if (lexer != NULL) {
   2292 		file = isc_lex_getsourcename(lexer);
   2293 		line = isc_lex_getsourceline(lexer);
   2294 		dns_name_format(name, namebuf, sizeof(namebuf));
   2295 		(*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file,
   2296 				   line, namebuf,
   2297 				   isc_result_totext(DNS_R_BADNAME));
   2298 	}
   2299 }
   2300 
   2301 static void
   2302 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
   2303 	       dns_rdatacallbacks_t *callbacks, const char *name,
   2304 	       unsigned long line, isc_token_t *token, isc_result_t result) {
   2305 	if (name == NULL) {
   2306 		name = "UNKNOWN";
   2307 	}
   2308 
   2309 	if (token != NULL) {
   2310 		switch (token->type) {
   2311 		case isc_tokentype_eol:
   2312 			(*callback)(callbacks, "%s: %s:%lu: near eol: %s",
   2313 				    "dns_rdata_fromtext", name, line,
   2314 				    isc_result_totext(result));
   2315 			break;
   2316 		case isc_tokentype_eof:
   2317 			(*callback)(callbacks, "%s: %s:%lu: near eof: %s",
   2318 				    "dns_rdata_fromtext", name, line,
   2319 				    isc_result_totext(result));
   2320 			break;
   2321 		case isc_tokentype_number:
   2322 			(*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
   2323 				    "dns_rdata_fromtext", name, line,
   2324 				    token->value.as_ulong,
   2325 				    isc_result_totext(result));
   2326 			break;
   2327 		case isc_tokentype_string:
   2328 		case isc_tokentype_qstring:
   2329 			(*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
   2330 				    "dns_rdata_fromtext", name, line,
   2331 				    DNS_AS_STR(*token),
   2332 				    isc_result_totext(result));
   2333 			break;
   2334 		default:
   2335 			(*callback)(callbacks, "%s: %s:%lu: %s",
   2336 				    "dns_rdata_fromtext", name, line,
   2337 				    isc_result_totext(result));
   2338 			break;
   2339 		}
   2340 	} else {
   2341 		(*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", name,
   2342 			    line, isc_result_totext(result));
   2343 	}
   2344 }
   2345 
   2346 dns_rdatatype_t
   2347 dns_rdata_covers(dns_rdata_t *rdata) {
   2348 	if (rdata->type == dns_rdatatype_rrsig) {
   2349 		return covers_rrsig(rdata);
   2350 	}
   2351 	return covers_sig(rdata);
   2352 }
   2353 
   2354 bool
   2355 dns_rdatatype_ismeta(dns_rdatatype_t type) {
   2356 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0) {
   2357 		return true;
   2358 	}
   2359 	return false;
   2360 }
   2361 
   2362 bool
   2363 dns_rdatatype_issingleton(dns_rdatatype_t type) {
   2364 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) != 0)
   2365 	{
   2366 		return true;
   2367 	}
   2368 	return false;
   2369 }
   2370 
   2371 bool
   2372 dns_rdatatype_notquestion(dns_rdatatype_t type) {
   2373 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION) !=
   2374 	    0)
   2375 	{
   2376 		return true;
   2377 	}
   2378 	return false;
   2379 }
   2380 
   2381 bool
   2382 dns_rdatatype_questiononly(dns_rdatatype_t type) {
   2383 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY) !=
   2384 	    0)
   2385 	{
   2386 		return true;
   2387 	}
   2388 	return false;
   2389 }
   2390 
   2391 bool
   2392 dns_rdatatype_atcname(dns_rdatatype_t type) {
   2393 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATCNAME) != 0) {
   2394 		return true;
   2395 	}
   2396 	return false;
   2397 }
   2398 
   2399 bool
   2400 dns_rdatatype_atparent(dns_rdatatype_t type) {
   2401 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
   2402 	{
   2403 		return true;
   2404 	}
   2405 	return false;
   2406 }
   2407 
   2408 bool
   2409 dns_rdatatype_followadditional(dns_rdatatype_t type) {
   2410 	if ((dns_rdatatype_attributes(type) &
   2411 	     DNS_RDATATYPEATTR_FOLLOWADDITIONAL) != 0)
   2412 	{
   2413 		return true;
   2414 	}
   2415 	return false;
   2416 }
   2417 
   2418 bool
   2419 dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
   2420 	if (rdclass == dns_rdataclass_reserved0 ||
   2421 	    rdclass == dns_rdataclass_none || rdclass == dns_rdataclass_any)
   2422 	{
   2423 		return true;
   2424 	}
   2425 
   2426 	return false; /* Assume it is not a meta class. */
   2427 }
   2428 
   2429 bool
   2430 dns_rdatatype_isdnssec(dns_rdatatype_t type) {
   2431 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0) {
   2432 		return true;
   2433 	}
   2434 	return false;
   2435 }
   2436 
   2437 bool
   2438 dns_rdatatype_iskeymaterial(dns_rdatatype_t type) {
   2439 	return type == dns_rdatatype_dnskey || type == dns_rdatatype_cdnskey ||
   2440 	       type == dns_rdatatype_cds;
   2441 }
   2442 
   2443 bool
   2444 dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
   2445 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ZONECUTAUTH) !=
   2446 	    0)
   2447 	{
   2448 		return true;
   2449 	}
   2450 	return false;
   2451 }
   2452 
   2453 bool
   2454 dns_rdatatype_isknown(dns_rdatatype_t type) {
   2455 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) == 0) {
   2456 		return true;
   2457 	}
   2458 	return false;
   2459 }
   2460 
   2461 void
   2462 dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) {
   2463 	REQUIRE(rdata != NULL);
   2464 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   2465 
   2466 	rdata->data = NULL;
   2467 	rdata->length = 0;
   2468 	rdata->flags = DNS_RDATA_UPDATE;
   2469 	rdata->type = type;
   2470 	rdata->rdclass = dns_rdataclass_any;
   2471 }
   2472 
   2473 void
   2474 dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type) {
   2475 	REQUIRE(rdata != NULL);
   2476 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   2477 
   2478 	rdata->data = NULL;
   2479 	rdata->length = 0;
   2480 	rdata->flags = DNS_RDATA_UPDATE;
   2481 	rdata->type = type;
   2482 	rdata->rdclass = dns_rdataclass_none;
   2483 }
   2484 
   2485 void
   2486 dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type) {
   2487 	REQUIRE(rdata != NULL);
   2488 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   2489 
   2490 	rdata->data = NULL;
   2491 	rdata->length = 0;
   2492 	rdata->flags = DNS_RDATA_UPDATE;
   2493 	rdata->type = type;
   2494 	rdata->rdclass = dns_rdataclass_any;
   2495 }
   2496 
   2497 void
   2498 dns_rdata_makedelete(dns_rdata_t *rdata) {
   2499 	REQUIRE(rdata != NULL);
   2500 
   2501 	rdata->rdclass = dns_rdataclass_none;
   2502 }
   2503 
   2504 const char *
   2505 dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) {
   2506 	REQUIRE(rdata != NULL);
   2507 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
   2508 
   2509 	switch (section) {
   2510 	case DNS_SECTION_PREREQUISITE:
   2511 		switch (rdata->rdclass) {
   2512 		case dns_rdataclass_none:
   2513 			switch (rdata->type) {
   2514 			case dns_rdatatype_any:
   2515 				return "domain doesn't exist";
   2516 			default:
   2517 				return "rrset doesn't exist";
   2518 			}
   2519 		case dns_rdataclass_any:
   2520 			switch (rdata->type) {
   2521 			case dns_rdatatype_any:
   2522 				return "domain exists";
   2523 			default:
   2524 				return "rrset exists (value independent)";
   2525 			}
   2526 		default:
   2527 			return "rrset exists (value dependent)";
   2528 		}
   2529 	case DNS_SECTION_UPDATE:
   2530 		switch (rdata->rdclass) {
   2531 		case dns_rdataclass_none:
   2532 			return "delete";
   2533 		case dns_rdataclass_any:
   2534 			switch (rdata->type) {
   2535 			case dns_rdatatype_any:
   2536 				return "delete all rrsets";
   2537 			default:
   2538 				return "delete rrset";
   2539 			}
   2540 		default:
   2541 			return "add";
   2542 		}
   2543 	}
   2544 	return "invalid";
   2545 }
   2546 
   2547 static bool
   2548 svcb_ishttp(const char *s, size_t len) {
   2549 	/*
   2550 	 * HTTP entries from:
   2551 	 *
   2552 	 * https://www.iana.org/assignments/tls-extensiontype-values/\
   2553 	 * tls-extensiontype-values.xhtml#alpn-protocol-ids
   2554 	 */
   2555 	struct {
   2556 		size_t len;
   2557 		const char *value;
   2558 	} http[] = { { 8, "http/0.9" }, { 8, "http/1.0" }, { 8, "http/1.1" },
   2559 		     { 2, "h2" },	{ 3, "h2c" },	   { 2, "h3" } };
   2560 
   2561 	for (size_t i = 0; i < ARRAY_SIZE(http); i++) {
   2562 		if (len == http[i].len && memcmp(s, http[i].value, len) == 0) {
   2563 			return true;
   2564 		}
   2565 	}
   2566 	return false;
   2567 }
   2568 
   2569 static bool
   2570 svcb_hashttp(isc_textregion_t *alpn) {
   2571 	while (alpn->length > 0) {
   2572 		char c, *s;
   2573 		unsigned char len = *alpn->base;
   2574 
   2575 		isc_textregion_consume(alpn, 1);
   2576 
   2577 		/*
   2578 		 * This has to detect "http/1.1", "h2" and "h3", etc.
   2579 		 * in a comma list.
   2580 		 */
   2581 		s = alpn->base;
   2582 		while (len-- > 0) {
   2583 			c = *alpn->base;
   2584 			isc_textregion_consume(alpn, 1);
   2585 			if (c == ',') {
   2586 				if (svcb_ishttp(s, (alpn->base - s) - 1)) {
   2587 					return true;
   2588 				}
   2589 				s = alpn->base;
   2590 			}
   2591 		}
   2592 		if (svcb_ishttp(s, alpn->base - s)) {
   2593 			return true;
   2594 		}
   2595 	}
   2596 	return false;
   2597 }
   2598 
   2599 isc_result_t
   2600 dns_rdata_checksvcb(const dns_name_t *owner, const dns_rdata_t *rdata) {
   2601 	dns_rdata_in_svcb_t svcb;
   2602 	isc_result_t result;
   2603 
   2604 	REQUIRE(owner != NULL);
   2605 	REQUIRE(rdata != NULL);
   2606 	REQUIRE(rdata->type == dns_rdatatype_svcb);
   2607 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
   2608 
   2609 	result = dns_rdata_tostruct(rdata, &svcb, NULL);
   2610 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2611 
   2612 	/*
   2613 	 * Check that Alias Mode records don't have SvcParamKeys.
   2614 	 */
   2615 	if (svcb.priority == 0 && svcb.svclen != 0) {
   2616 		return DNS_R_HAVEPARMKEYS;
   2617 	}
   2618 
   2619 	if (dns_name_isdnssvcb(owner)) {
   2620 		isc_region_t r = { .base = svcb.svc, .length = svcb.svclen };
   2621 		isc_textregion_t alpn;
   2622 		uint16_t key = 0, len = 0;
   2623 
   2624 		/* Check for ALPN (key1) */
   2625 		while (r.length > 0) {
   2626 			key = uint16_fromregion(&r);
   2627 			isc_region_consume(&r, 2);
   2628 			len = uint16_fromregion(&r);
   2629 			isc_region_consume(&r, 2);
   2630 			if (key >= SVCB_ALPN_KEY) {
   2631 				break;
   2632 			}
   2633 			isc_region_consume(&r, len);
   2634 		}
   2635 		if (key != SVCB_ALPN_KEY) {
   2636 			return DNS_R_NOALPN;
   2637 		}
   2638 		alpn = (isc_textregion_t){ .base = (char *)r.base,
   2639 					   .length = len };
   2640 		isc_region_consume(&r, len);
   2641 		if (svcb_hashttp(&alpn)) {
   2642 			/* Check for DOHPATH (key7) */
   2643 			while (r.length > 0) {
   2644 				key = uint16_fromregion(&r);
   2645 				isc_region_consume(&r, 2);
   2646 				len = uint16_fromregion(&r);
   2647 				isc_region_consume(&r, 2);
   2648 				if (key >= SVCB_DOHPATH_KEY) {
   2649 					break;
   2650 				}
   2651 				isc_region_consume(&r, len);
   2652 			}
   2653 			if (key != SVCB_DOHPATH_KEY) {
   2654 				return DNS_R_NODOHPATH;
   2655 			}
   2656 		}
   2657 	}
   2658 	return ISC_R_SUCCESS;
   2659 }
   2660