xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/in_1/svcb_64.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: svcb_64.c,v 1.6 2025/01/26 16:25:35 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 /* draft-ietf-dnsop-svcb-https-02 */
17 
18 #ifndef RDATA_IN_1_SVCB_64_C
19 #define RDATA_IN_1_SVCB_64_C
20 
21 #define RRTYPE_SVCB_ATTRIBUTES (DNS_RDATATYPEATTR_FOLLOWADDITIONAL)
22 
23 #define SVCB_MAN_KEY		 0
24 #define SVCB_ALPN_KEY		 1
25 #define SVCB_NO_DEFAULT_ALPN_KEY 2
26 #define SVCB_DOHPATH_KEY	 7
27 #define MAX_CNAMES		 16 /* See ns/query.c MAX_RESTARTS */
28 
29 /*
30  * Service Binding Parameter Registry
31  */
32 enum encoding {
33 	sbpr_text,
34 	sbpr_port,
35 	sbpr_ipv4s,
36 	sbpr_ipv6s,
37 	sbpr_base64,
38 	sbpr_empty,
39 	sbpr_alpn,
40 	sbpr_keylist,
41 	sbpr_dohpath
42 };
43 static const struct {
44 	const char *name; /* Restricted to lowercase LDH by registry. */
45 	unsigned int value;
46 	enum encoding encoding;
47 	bool initial; /* Part of the first defined set of encodings. */
48 } sbpr[] = {
49 	{ "mandatory", 0, sbpr_keylist, true },
50 	{ "alpn", 1, sbpr_alpn, true },
51 	{ "no-default-alpn", 2, sbpr_empty, true },
52 	{ "port", 3, sbpr_port, true },
53 	{ "ipv4hint", 4, sbpr_ipv4s, true },
54 	{ "ech", 5, sbpr_base64, true },
55 	{ "ipv6hint", 6, sbpr_ipv6s, true },
56 	{ "dohpath", 7, sbpr_dohpath, false },
57 };
58 
59 static isc_result_t
60 alpn_fromtxt(isc_textregion_t *source, isc_buffer_t *target) {
61 	isc_textregion_t source0 = *source;
62 	do {
63 		RETERR(commatxt_fromtext(&source0, true, target));
64 	} while (source0.length != 0);
65 	return ISC_R_SUCCESS;
66 }
67 
68 static int
69 svckeycmp(const void *a1, const void *a2) {
70 	const unsigned char *u1 = a1, *u2 = a2;
71 	if (*u1 != *u2) {
72 		return *u1 - *u2;
73 	}
74 	return *(++u1) - *(++u2);
75 }
76 
77 static isc_result_t
78 svcsortkeylist(isc_buffer_t *target, unsigned int used) {
79 	isc_region_t region;
80 
81 	isc_buffer_usedregion(target, &region);
82 	isc_region_consume(&region, used);
83 	INSIST(region.length > 0U);
84 	qsort(region.base, region.length / 2, 2, svckeycmp);
85 	/* Reject duplicates. */
86 	while (region.length >= 4) {
87 		if (region.base[0] == region.base[2] &&
88 		    region.base[1] == region.base[3])
89 		{
90 			return DNS_R_SYNTAX;
91 		}
92 		isc_region_consume(&region, 2);
93 	}
94 	return ISC_R_SUCCESS;
95 }
96 
97 static isc_result_t
98 svcb_validate(uint16_t key, isc_region_t *region) {
99 	size_t i;
100 
101 	for (i = 0; i < ARRAY_SIZE(sbpr); i++) {
102 		if (sbpr[i].value == key) {
103 			switch (sbpr[i].encoding) {
104 			case sbpr_port:
105 				if (region->length != 2) {
106 					return DNS_R_FORMERR;
107 				}
108 				break;
109 			case sbpr_ipv4s:
110 				if ((region->length % 4) != 0 ||
111 				    region->length == 0)
112 				{
113 					return DNS_R_FORMERR;
114 				}
115 				break;
116 			case sbpr_ipv6s:
117 				if ((region->length % 16) != 0 ||
118 				    region->length == 0)
119 				{
120 					return DNS_R_FORMERR;
121 				}
122 				break;
123 			case sbpr_alpn: {
124 				if (region->length == 0) {
125 					return DNS_R_FORMERR;
126 				}
127 				while (region->length != 0) {
128 					size_t l = *region->base + 1;
129 					if (l == 1U || l > region->length) {
130 						return DNS_R_FORMERR;
131 					}
132 					isc_region_consume(region, l);
133 				}
134 				break;
135 			}
136 			case sbpr_keylist: {
137 				if ((region->length % 2) != 0 ||
138 				    region->length == 0)
139 				{
140 					return DNS_R_FORMERR;
141 				}
142 				/* In order? */
143 				while (region->length >= 4) {
144 					if (region->base[0] > region->base[2] ||
145 					    (region->base[0] ==
146 						     region->base[2] &&
147 					     region->base[1] >=
148 						     region->base[3]))
149 					{
150 						return DNS_R_FORMERR;
151 					}
152 					isc_region_consume(region, 2);
153 				}
154 				break;
155 			}
156 			case sbpr_text:
157 			case sbpr_base64:
158 				break;
159 			case sbpr_dohpath:
160 				if (!validate_dohpath(region)) {
161 					return DNS_R_FORMERR;
162 				}
163 				break;
164 			case sbpr_empty:
165 				if (region->length != 0) {
166 					return DNS_R_FORMERR;
167 				}
168 				break;
169 			}
170 		}
171 	}
172 	return ISC_R_SUCCESS;
173 }
174 
175 /*
176  * Parse keyname from region.
177  */
178 static isc_result_t
179 svc_keyfromregion(isc_textregion_t *region, char sep, uint16_t *value,
180 		  isc_buffer_t *target) {
181 	char *e = NULL;
182 	size_t i;
183 	unsigned long ul;
184 
185 	/* Look for known key names.  */
186 	for (i = 0; i < ARRAY_SIZE(sbpr); i++) {
187 		size_t len = strlen(sbpr[i].name);
188 		if (strncasecmp(region->base, sbpr[i].name, len) != 0 ||
189 		    (region->base[len] != 0 && region->base[len] != sep))
190 		{
191 			continue;
192 		}
193 		isc_textregion_consume(region, len);
194 		ul = sbpr[i].value;
195 		goto finish;
196 	}
197 	/* Handle keyXXXXX form. */
198 	if (strncmp(region->base, "key", 3) != 0) {
199 		return DNS_R_SYNTAX;
200 	}
201 	isc_textregion_consume(region, 3);
202 	/* Disallow [+-]XXXXX which is allowed by strtoul. */
203 	if (region->length == 0 || *region->base == '-' || *region->base == '+')
204 	{
205 		return DNS_R_SYNTAX;
206 	}
207 	/* No zero padding. */
208 	if (region->length > 1 && *region->base == '0' &&
209 	    region->base[1] != sep)
210 	{
211 		return DNS_R_SYNTAX;
212 	}
213 	ul = strtoul(region->base, &e, 10);
214 	/* Valid number? */
215 	if (e == region->base || (*e != sep && *e != 0)) {
216 		return DNS_R_SYNTAX;
217 	}
218 	if (ul > 0xffff) {
219 		return ISC_R_RANGE;
220 	}
221 	isc_textregion_consume(region, e - region->base);
222 finish:
223 	if (sep == ',' && region->length == 1) {
224 		return DNS_R_SYNTAX;
225 	}
226 	/* Consume separator. */
227 	if (region->length != 0) {
228 		isc_textregion_consume(region, 1);
229 	}
230 	RETERR(uint16_tobuffer(ul, target));
231 	SET_IF_NOT_NULL(value, ul);
232 	return ISC_R_SUCCESS;
233 }
234 
235 static isc_result_t
236 svc_fromtext(isc_textregion_t *region, isc_buffer_t *target) {
237 	char *e = NULL;
238 	char abuf[16];
239 	char tbuf[sizeof("aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:255.255.255.255,")];
240 	isc_buffer_t sb;
241 	isc_region_t keyregion;
242 	size_t len;
243 	uint16_t key;
244 	unsigned int i;
245 	unsigned int used;
246 	unsigned long ul;
247 
248 	for (i = 0; i < ARRAY_SIZE(sbpr); i++) {
249 		len = strlen(sbpr[i].name);
250 		if (strncmp(region->base, sbpr[i].name, len) != 0 ||
251 		    (region->base[len] != 0 && region->base[len] != '='))
252 		{
253 			continue;
254 		}
255 
256 		if (region->base[len] == '=') {
257 			len++;
258 		}
259 
260 		RETERR(uint16_tobuffer(sbpr[i].value, target));
261 		isc_textregion_consume(region, len);
262 
263 		sb = *target;
264 		RETERR(uint16_tobuffer(0, target)); /* length */
265 
266 		switch (sbpr[i].encoding) {
267 		case sbpr_text:
268 		case sbpr_dohpath:
269 			RETERR(multitxt_fromtext(region, target));
270 			break;
271 		case sbpr_alpn:
272 			RETERR(alpn_fromtxt(region, target));
273 			break;
274 		case sbpr_port:
275 			if (!isdigit((unsigned char)*region->base)) {
276 				return DNS_R_SYNTAX;
277 			}
278 			ul = strtoul(region->base, &e, 10);
279 			if (*e != '\0') {
280 				return DNS_R_SYNTAX;
281 			}
282 			if (ul > 0xffff) {
283 				return ISC_R_RANGE;
284 			}
285 			RETERR(uint16_tobuffer(ul, target));
286 			break;
287 		case sbpr_ipv4s:
288 			do {
289 				snprintf(tbuf, sizeof(tbuf), "%*s",
290 					 (int)(region->length), region->base);
291 				e = strchr(tbuf, ',');
292 				if (e != NULL) {
293 					*e++ = 0;
294 					isc_textregion_consume(region,
295 							       e - tbuf);
296 				}
297 				if (inet_pton(AF_INET, tbuf, abuf) != 1) {
298 					return DNS_R_SYNTAX;
299 				}
300 				mem_tobuffer(target, abuf, 4);
301 			} while (e != NULL);
302 			break;
303 		case sbpr_ipv6s:
304 			do {
305 				snprintf(tbuf, sizeof(tbuf), "%*s",
306 					 (int)(region->length), region->base);
307 				e = strchr(tbuf, ',');
308 				if (e != NULL) {
309 					*e++ = 0;
310 					isc_textregion_consume(region,
311 							       e - tbuf);
312 				}
313 				if (inet_pton(AF_INET6, tbuf, abuf) != 1) {
314 					return DNS_R_SYNTAX;
315 				}
316 				mem_tobuffer(target, abuf, 16);
317 			} while (e != NULL);
318 			break;
319 		case sbpr_base64:
320 			RETERR(isc_base64_decodestring(region->base, target));
321 			break;
322 		case sbpr_empty:
323 			if (region->length != 0) {
324 				return DNS_R_SYNTAX;
325 			}
326 			break;
327 		case sbpr_keylist:
328 			if (region->length == 0) {
329 				return DNS_R_SYNTAX;
330 			}
331 			used = isc_buffer_usedlength(target);
332 			while (region->length != 0) {
333 				RETERR(svc_keyfromregion(region, ',', NULL,
334 							 target));
335 			}
336 			RETERR(svcsortkeylist(target, used));
337 			break;
338 		default:
339 			UNREACHABLE();
340 		}
341 
342 		len = isc_buffer_usedlength(target) -
343 		      isc_buffer_usedlength(&sb) - 2;
344 		RETERR(uint16_tobuffer(len, &sb)); /* length */
345 		switch (sbpr[i].encoding) {
346 		case sbpr_dohpath:
347 			/*
348 			 * Apply constraints not applied by multitxt_fromtext.
349 			 */
350 			keyregion.base = isc_buffer_used(&sb);
351 			keyregion.length = isc_buffer_usedlength(target) -
352 					   isc_buffer_usedlength(&sb);
353 			RETERR(svcb_validate(sbpr[i].value, &keyregion));
354 			break;
355 		default:
356 			break;
357 		}
358 		return ISC_R_SUCCESS;
359 	}
360 
361 	RETERR(svc_keyfromregion(region, '=', &key, target));
362 	if (region->length == 0) {
363 		RETERR(uint16_tobuffer(0, target)); /* length */
364 		/* Sanity check keyXXXXX form. */
365 		keyregion.base = isc_buffer_used(target);
366 		keyregion.length = 0;
367 		return svcb_validate(key, &keyregion);
368 	}
369 	sb = *target;
370 	RETERR(uint16_tobuffer(0, target)); /* dummy length */
371 	RETERR(multitxt_fromtext(region, target));
372 	len = isc_buffer_usedlength(target) - isc_buffer_usedlength(&sb) - 2;
373 	RETERR(uint16_tobuffer(len, &sb)); /* length */
374 	/* Sanity check keyXXXXX form. */
375 	keyregion.base = isc_buffer_used(&sb);
376 	keyregion.length = len;
377 	return svcb_validate(key, &keyregion);
378 }
379 
380 static const char *
381 svcparamkey(unsigned short value, enum encoding *encoding, char *buf,
382 	    size_t len) {
383 	size_t i;
384 	int n;
385 
386 	for (i = 0; i < ARRAY_SIZE(sbpr); i++) {
387 		if (sbpr[i].value == value && sbpr[i].initial) {
388 			*encoding = sbpr[i].encoding;
389 			return sbpr[i].name;
390 		}
391 	}
392 	n = snprintf(buf, len, "key%u", value);
393 	INSIST(n > 0 && (unsigned int)n < len);
394 	*encoding = sbpr_text;
395 	return buf;
396 }
397 
398 static isc_result_t
399 svcsortkeys(isc_buffer_t *target, unsigned int used) {
400 	isc_region_t r1, r2, man = { .base = NULL, .length = 0 };
401 	unsigned char buf[1024];
402 	uint16_t mankey = 0;
403 	bool have_alpn = false;
404 
405 	if (isc_buffer_usedlength(target) == used) {
406 		return ISC_R_SUCCESS;
407 	}
408 
409 	/*
410 	 * Get the parameters into r1.
411 	 */
412 	isc_buffer_usedregion(target, &r1);
413 	isc_region_consume(&r1, used);
414 
415 	while (1) {
416 		uint16_t key1, len1, key2, len2;
417 		unsigned char *base1, *base2;
418 
419 		r2 = r1;
420 
421 		/*
422 		 * Get the first parameter.
423 		 */
424 		base1 = r1.base;
425 		key1 = uint16_fromregion(&r1);
426 		isc_region_consume(&r1, 2);
427 		len1 = uint16_fromregion(&r1);
428 		isc_region_consume(&r1, 2);
429 		isc_region_consume(&r1, len1);
430 
431 		/*
432 		 * Was there only one key left?
433 		 */
434 		if (r1.length == 0) {
435 			if (mankey != 0) {
436 				/* Is this the last mandatory key? */
437 				if (key1 != mankey || man.length != 0) {
438 					return DNS_R_INCONSISTENTRR;
439 				}
440 			} else if (key1 == SVCB_MAN_KEY) {
441 				/* Lone mandatory field. */
442 				return DNS_R_DISALLOWED;
443 			} else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY &&
444 				   !have_alpn)
445 			{
446 				/* Missing required ALPN field. */
447 				return DNS_R_DISALLOWED;
448 			}
449 			return ISC_R_SUCCESS;
450 		}
451 
452 		/*
453 		 * Find the smallest parameter.
454 		 */
455 		while (r1.length != 0) {
456 			base2 = r1.base;
457 			key2 = uint16_fromregion(&r1);
458 			isc_region_consume(&r1, 2);
459 			len2 = uint16_fromregion(&r1);
460 			isc_region_consume(&r1, 2);
461 			isc_region_consume(&r1, len2);
462 			if (key2 == key1) {
463 				return DNS_R_DUPLICATE;
464 			}
465 			if (key2 < key1) {
466 				base1 = base2;
467 				key1 = key2;
468 				len1 = len2;
469 			}
470 		}
471 
472 		/*
473 		 * Do we need to move the smallest parameter to the start?
474 		 */
475 		if (base1 != r2.base) {
476 			size_t offset = 0;
477 			size_t bytes = len1 + 4;
478 			size_t length = base1 - r2.base;
479 
480 			/*
481 			 * Move the smallest parameter to the start.
482 			 */
483 			while (bytes > 0) {
484 				size_t count;
485 
486 				if (bytes > sizeof(buf)) {
487 					count = sizeof(buf);
488 				} else {
489 					count = bytes;
490 				}
491 				memmove(buf, base1, count);
492 				memmove(r2.base + offset + count,
493 					r2.base + offset, length);
494 				memmove(r2.base + offset, buf, count);
495 				base1 += count;
496 				bytes -= count;
497 				offset += count;
498 			}
499 		}
500 
501 		/*
502 		 * Check ALPN is present when NO-DEFAULT-ALPN is set.
503 		 */
504 		if (key1 == SVCB_ALPN_KEY) {
505 			have_alpn = true;
506 		} else if (key1 == SVCB_NO_DEFAULT_ALPN_KEY && !have_alpn) {
507 			/* Missing required ALPN field. */
508 			return DNS_R_DISALLOWED;
509 		}
510 
511 		/*
512 		 * Check key against mandatory key list.
513 		 */
514 		if (mankey != 0) {
515 			if (key1 > mankey) {
516 				return DNS_R_INCONSISTENTRR;
517 			}
518 			if (key1 == mankey) {
519 				if (man.length >= 2) {
520 					mankey = uint16_fromregion(&man);
521 					isc_region_consume(&man, 2);
522 				} else {
523 					mankey = 0;
524 				}
525 			}
526 		}
527 
528 		/*
529 		 * Is this the mandatory key?
530 		 */
531 		if (key1 == SVCB_MAN_KEY) {
532 			man = r2;
533 			man.length = len1 + 4;
534 			isc_region_consume(&man, 4);
535 			if (man.length >= 2) {
536 				mankey = uint16_fromregion(&man);
537 				isc_region_consume(&man, 2);
538 				if (mankey == SVCB_MAN_KEY) {
539 					return DNS_R_DISALLOWED;
540 				}
541 			} else {
542 				return DNS_R_SYNTAX;
543 			}
544 		}
545 
546 		/*
547 		 * Consume the smallest parameter.
548 		 */
549 		isc_region_consume(&r2, len1 + 4);
550 		r1 = r2;
551 	}
552 }
553 
554 static isc_result_t
555 generic_fromtext_in_svcb(ARGS_FROMTEXT) {
556 	isc_token_t token;
557 	dns_name_t name;
558 	isc_buffer_t buffer;
559 	bool alias;
560 	bool ok = true;
561 	unsigned int used;
562 
563 	UNUSED(type);
564 	UNUSED(rdclass);
565 	UNUSED(callbacks);
566 
567 	/*
568 	 * SvcPriority.
569 	 */
570 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
571 				      false));
572 	if (token.value.as_ulong > 0xffffU) {
573 		RETTOK(ISC_R_RANGE);
574 	}
575 	RETERR(uint16_tobuffer(token.value.as_ulong, target));
576 
577 	alias = token.value.as_ulong == 0;
578 
579 	/*
580 	 * TargetName.
581 	 */
582 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
583 				      false));
584 	dns_name_init(&name, NULL);
585 	buffer_fromregion(&buffer, &token.value.as_region);
586 	if (origin == NULL) {
587 		origin = dns_rootname;
588 	}
589 	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
590 	if (!alias && (options & DNS_RDATA_CHECKNAMES) != 0) {
591 		ok = dns_name_ishostname(&name, false);
592 	}
593 	if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) {
594 		RETTOK(DNS_R_BADNAME);
595 	}
596 	if (!ok && callbacks != NULL) {
597 		warn_badname(&name, lexer, callbacks);
598 	}
599 
600 	/*
601 	 * SvcParams
602 	 */
603 	used = isc_buffer_usedlength(target);
604 	while (1) {
605 		RETERR(isc_lex_getmastertoken(lexer, &token,
606 					      isc_tokentype_qvpair, true));
607 		if (token.type == isc_tokentype_eol ||
608 		    token.type == isc_tokentype_eof)
609 		{
610 			isc_lex_ungettoken(lexer, &token);
611 			return svcsortkeys(target, used);
612 		}
613 
614 		if (token.type != isc_tokentype_string && /* key only */
615 		    token.type != isc_tokentype_qvpair &&
616 		    token.type != isc_tokentype_vpair)
617 		{
618 			RETTOK(DNS_R_SYNTAX);
619 		}
620 		RETTOK(svc_fromtext(&token.value.as_textregion, target));
621 	}
622 }
623 
624 static isc_result_t
625 fromtext_in_svcb(ARGS_FROMTEXT) {
626 	REQUIRE(type == dns_rdatatype_svcb);
627 	REQUIRE(rdclass == dns_rdataclass_in);
628 	UNUSED(type);
629 	UNUSED(rdclass);
630 	UNUSED(callbacks);
631 
632 	return generic_fromtext_in_svcb(CALL_FROMTEXT);
633 }
634 
635 static isc_result_t
636 generic_totext_in_svcb(ARGS_TOTEXT) {
637 	isc_region_t region;
638 	dns_name_t name;
639 	dns_name_t prefix;
640 	unsigned int opts;
641 	char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
642 	unsigned short num;
643 	int n;
644 
645 	REQUIRE(rdata->length != 0);
646 
647 	dns_name_init(&name, NULL);
648 	dns_name_init(&prefix, NULL);
649 
650 	dns_rdata_toregion(rdata, &region);
651 
652 	/*
653 	 * SvcPriority.
654 	 */
655 	num = uint16_fromregion(&region);
656 	isc_region_consume(&region, 2);
657 	n = snprintf(buf, sizeof(buf), "%u ", num);
658 	INSIST(n > 0 && (unsigned int)n < sizeof(buf));
659 	RETERR(str_totext(buf, target));
660 
661 	/*
662 	 * TargetName.
663 	 */
664 	dns_name_fromregion(&name, &region);
665 	isc_region_consume(&region, name_length(&name));
666 	opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT
667 							 : 0;
668 	RETERR(dns_name_totext(&prefix, opts, target));
669 
670 	while (region.length > 0) {
671 		isc_region_t r;
672 		enum encoding encoding;
673 
674 		RETERR(str_totext(" ", target));
675 
676 		INSIST(region.length >= 2);
677 		num = uint16_fromregion(&region);
678 		isc_region_consume(&region, 2);
679 		RETERR(str_totext(svcparamkey(num, &encoding, buf, sizeof(buf)),
680 				  target));
681 
682 		INSIST(region.length >= 2);
683 		num = uint16_fromregion(&region);
684 		isc_region_consume(&region, 2);
685 
686 		INSIST(region.length >= num);
687 		r = region;
688 		r.length = num;
689 		isc_region_consume(&region, num);
690 		if (num == 0) {
691 			continue;
692 		}
693 		if (encoding != sbpr_empty) {
694 			RETERR(str_totext("=", target));
695 		}
696 		switch (encoding) {
697 		case sbpr_text:
698 			RETERR(multitxt_totext(&r, target));
699 			break;
700 		case sbpr_port:
701 			num = uint16_fromregion(&r);
702 			isc_region_consume(&r, 2);
703 			n = snprintf(buf, sizeof(buf), "%u", num);
704 			INSIST(n > 0 && (unsigned int)n < sizeof(buf));
705 			RETERR(str_totext(buf, target));
706 			INSIST(r.length == 0U);
707 			break;
708 		case sbpr_ipv4s:
709 			while (r.length > 0U) {
710 				INSIST(r.length >= 4U);
711 				inet_ntop(AF_INET, r.base, buf, sizeof(buf));
712 				RETERR(str_totext(buf, target));
713 				isc_region_consume(&r, 4);
714 				if (r.length != 0U) {
715 					RETERR(str_totext(",", target));
716 				}
717 			}
718 			break;
719 		case sbpr_ipv6s:
720 			while (r.length > 0U) {
721 				INSIST(r.length >= 16U);
722 				inet_ntop(AF_INET6, r.base, buf, sizeof(buf));
723 				RETERR(str_totext(buf, target));
724 				isc_region_consume(&r, 16);
725 				if (r.length != 0U) {
726 					RETERR(str_totext(",", target));
727 				}
728 			}
729 			break;
730 		case sbpr_base64:
731 			RETERR(isc_base64_totext(&r, 0, "", target));
732 			break;
733 		case sbpr_alpn:
734 			INSIST(r.length != 0U);
735 			RETERR(str_totext("\"", target));
736 			while (r.length != 0) {
737 				commatxt_totext(&r, false, true, target);
738 				if (r.length != 0) {
739 					RETERR(str_totext(",", target));
740 				}
741 			}
742 			RETERR(str_totext("\"", target));
743 			break;
744 		case sbpr_empty:
745 			INSIST(r.length == 0U);
746 			break;
747 		case sbpr_keylist:
748 			while (r.length > 0) {
749 				num = uint16_fromregion(&r);
750 				isc_region_consume(&r, 2);
751 				RETERR(str_totext(svcparamkey(num, &encoding,
752 							      buf, sizeof(buf)),
753 						  target));
754 				if (r.length != 0) {
755 					RETERR(str_totext(",", target));
756 				}
757 			}
758 			break;
759 		default:
760 			UNREACHABLE();
761 		}
762 	}
763 	return ISC_R_SUCCESS;
764 }
765 
766 static isc_result_t
767 totext_in_svcb(ARGS_TOTEXT) {
768 	REQUIRE(rdata->type == dns_rdatatype_svcb);
769 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
770 	REQUIRE(rdata->length != 0);
771 
772 	return generic_totext_in_svcb(CALL_TOTEXT);
773 }
774 
775 static isc_result_t
776 generic_fromwire_in_svcb(ARGS_FROMWIRE) {
777 	dns_name_t name;
778 	isc_region_t region, man = { .base = NULL, .length = 0 };
779 	bool first = true, have_alpn = false;
780 	uint16_t lastkey = 0, mankey = 0;
781 
782 	UNUSED(type);
783 	UNUSED(rdclass);
784 
785 	dctx = dns_decompress_setpermitted(dctx, false);
786 
787 	dns_name_init(&name, NULL);
788 
789 	/*
790 	 * SvcPriority.
791 	 */
792 	isc_buffer_activeregion(source, &region);
793 	if (region.length < 2) {
794 		return ISC_R_UNEXPECTEDEND;
795 	}
796 	RETERR(mem_tobuffer(target, region.base, 2));
797 	isc_buffer_forward(source, 2);
798 
799 	/*
800 	 * TargetName.
801 	 */
802 	RETERR(dns_name_fromwire(&name, source, dctx, target));
803 
804 	/*
805 	 * SvcParams.
806 	 */
807 	isc_buffer_activeregion(source, &region);
808 	while (region.length > 0U) {
809 		isc_region_t keyregion;
810 		uint16_t key, len;
811 
812 		/*
813 		 * SvcParamKey
814 		 */
815 		if (region.length < 2U) {
816 			return ISC_R_UNEXPECTEDEND;
817 		}
818 		RETERR(mem_tobuffer(target, region.base, 2));
819 		key = uint16_fromregion(&region);
820 		isc_region_consume(&region, 2);
821 
822 		/*
823 		 * Keys must be unique and in order.
824 		 */
825 		if (!first && key <= lastkey) {
826 			return DNS_R_FORMERR;
827 		}
828 
829 		/*
830 		 * Check mandatory keys.
831 		 */
832 		if (mankey != 0) {
833 			/* Missing mandatory key? */
834 			if (key > mankey) {
835 				return DNS_R_FORMERR;
836 			}
837 			if (key == mankey) {
838 				/* Get next mandatory key. */
839 				if (man.length >= 2) {
840 					mankey = uint16_fromregion(&man);
841 					isc_region_consume(&man, 2);
842 				} else {
843 					mankey = 0;
844 				}
845 			}
846 		}
847 
848 		/*
849 		 * Check alpn present when no-default-alpn is set.
850 		 */
851 		if (key == SVCB_ALPN_KEY) {
852 			have_alpn = true;
853 		} else if (key == SVCB_NO_DEFAULT_ALPN_KEY && !have_alpn) {
854 			return DNS_R_FORMERR;
855 		}
856 
857 		first = false;
858 		lastkey = key;
859 
860 		/*
861 		 * SvcParamValue length.
862 		 */
863 		if (region.length < 2U) {
864 			return ISC_R_UNEXPECTEDEND;
865 		}
866 		RETERR(mem_tobuffer(target, region.base, 2));
867 		len = uint16_fromregion(&region);
868 		isc_region_consume(&region, 2);
869 
870 		/*
871 		 * SvcParamValue.
872 		 */
873 		if (region.length < len) {
874 			return ISC_R_UNEXPECTEDEND;
875 		}
876 
877 		/*
878 		 * Remember manatory key.
879 		 */
880 		if (key == SVCB_MAN_KEY) {
881 			man = region;
882 			man.length = len;
883 			/* Get first mandatory key */
884 			if (man.length >= 2) {
885 				mankey = uint16_fromregion(&man);
886 				isc_region_consume(&man, 2);
887 				if (mankey == SVCB_MAN_KEY) {
888 					return DNS_R_FORMERR;
889 				}
890 			} else {
891 				return DNS_R_FORMERR;
892 			}
893 		}
894 		keyregion = region;
895 		keyregion.length = len;
896 		RETERR(svcb_validate(key, &keyregion));
897 		RETERR(mem_tobuffer(target, region.base, len));
898 		isc_region_consume(&region, len);
899 		isc_buffer_forward(source, len + 4);
900 	}
901 
902 	/*
903 	 * Do we have an outstanding mandatory key?
904 	 */
905 	if (mankey != 0) {
906 		return DNS_R_FORMERR;
907 	}
908 
909 	return ISC_R_SUCCESS;
910 }
911 
912 static isc_result_t
913 fromwire_in_svcb(ARGS_FROMWIRE) {
914 	REQUIRE(type == dns_rdatatype_svcb);
915 	REQUIRE(rdclass == dns_rdataclass_in);
916 
917 	return generic_fromwire_in_svcb(CALL_FROMWIRE);
918 }
919 
920 static isc_result_t
921 generic_towire_in_svcb(ARGS_TOWIRE) {
922 	dns_name_t name;
923 	dns_offsets_t offsets;
924 	isc_region_t region;
925 
926 	REQUIRE(rdata->length != 0);
927 
928 	dns_compress_setpermitted(cctx, false);
929 
930 	/*
931 	 * SvcPriority.
932 	 */
933 	dns_rdata_toregion(rdata, &region);
934 	RETERR(mem_tobuffer(target, region.base, 2));
935 	isc_region_consume(&region, 2);
936 
937 	/*
938 	 * TargetName.
939 	 */
940 	dns_name_init(&name, offsets);
941 	dns_name_fromregion(&name, &region);
942 	RETERR(dns_name_towire(&name, cctx, target, NULL));
943 	isc_region_consume(&region, name_length(&name));
944 
945 	/*
946 	 * SvcParams.
947 	 */
948 	return mem_tobuffer(target, region.base, region.length);
949 }
950 
951 static isc_result_t
952 towire_in_svcb(ARGS_TOWIRE) {
953 	REQUIRE(rdata->type == dns_rdatatype_svcb);
954 	REQUIRE(rdata->length != 0);
955 
956 	return generic_towire_in_svcb(CALL_TOWIRE);
957 }
958 
959 static int
960 compare_in_svcb(ARGS_COMPARE) {
961 	isc_region_t region1;
962 	isc_region_t region2;
963 
964 	REQUIRE(rdata1->type == rdata2->type);
965 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
966 	REQUIRE(rdata1->type == dns_rdatatype_svcb);
967 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
968 	REQUIRE(rdata1->length != 0);
969 	REQUIRE(rdata2->length != 0);
970 
971 	dns_rdata_toregion(rdata1, &region1);
972 	dns_rdata_toregion(rdata2, &region2);
973 
974 	return isc_region_compare(&region1, &region2);
975 }
976 
977 static isc_result_t
978 generic_fromstruct_in_svcb(ARGS_FROMSTRUCT) {
979 	dns_rdata_in_svcb_t *svcb = source;
980 	isc_region_t region;
981 
982 	REQUIRE(svcb != NULL);
983 	REQUIRE(svcb->common.rdtype == type);
984 	REQUIRE(svcb->common.rdclass == rdclass);
985 
986 	UNUSED(type);
987 	UNUSED(rdclass);
988 
989 	RETERR(uint16_tobuffer(svcb->priority, target));
990 	dns_name_toregion(&svcb->svcdomain, &region);
991 	RETERR(isc_buffer_copyregion(target, &region));
992 
993 	return mem_tobuffer(target, svcb->svc, svcb->svclen);
994 }
995 
996 static isc_result_t
997 fromstruct_in_svcb(ARGS_FROMSTRUCT) {
998 	dns_rdata_in_svcb_t *svcb = source;
999 
1000 	REQUIRE(type == dns_rdatatype_svcb);
1001 	REQUIRE(rdclass == dns_rdataclass_in);
1002 	REQUIRE(svcb != NULL);
1003 	REQUIRE(svcb->common.rdtype == type);
1004 	REQUIRE(svcb->common.rdclass == rdclass);
1005 
1006 	return generic_fromstruct_in_svcb(CALL_FROMSTRUCT);
1007 }
1008 
1009 static isc_result_t
1010 generic_tostruct_in_svcb(ARGS_TOSTRUCT) {
1011 	isc_region_t region;
1012 	dns_rdata_in_svcb_t *svcb = target;
1013 	dns_name_t name;
1014 
1015 	REQUIRE(svcb != NULL);
1016 	REQUIRE(rdata->length != 0);
1017 
1018 	svcb->common.rdclass = rdata->rdclass;
1019 	svcb->common.rdtype = rdata->type;
1020 	ISC_LINK_INIT(&svcb->common, link);
1021 
1022 	dns_rdata_toregion(rdata, &region);
1023 
1024 	svcb->priority = uint16_fromregion(&region);
1025 	isc_region_consume(&region, 2);
1026 
1027 	dns_name_init(&svcb->svcdomain, NULL);
1028 	dns_name_init(&name, NULL);
1029 	dns_name_fromregion(&name, &region);
1030 	isc_region_consume(&region, name_length(&name));
1031 
1032 	name_duporclone(&name, mctx, &svcb->svcdomain);
1033 	svcb->svclen = region.length;
1034 	svcb->svc = mem_maybedup(mctx, region.base, region.length);
1035 
1036 	svcb->offset = 0;
1037 	svcb->mctx = mctx;
1038 
1039 	return ISC_R_SUCCESS;
1040 }
1041 
1042 static isc_result_t
1043 tostruct_in_svcb(ARGS_TOSTRUCT) {
1044 	dns_rdata_in_svcb_t *svcb = target;
1045 
1046 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
1047 	REQUIRE(rdata->type == dns_rdatatype_svcb);
1048 	REQUIRE(svcb != NULL);
1049 	REQUIRE(rdata->length != 0);
1050 
1051 	return generic_tostruct_in_svcb(CALL_TOSTRUCT);
1052 }
1053 
1054 static void
1055 generic_freestruct_in_svcb(ARGS_FREESTRUCT) {
1056 	dns_rdata_in_svcb_t *svcb = source;
1057 
1058 	REQUIRE(svcb != NULL);
1059 
1060 	if (svcb->mctx == NULL) {
1061 		return;
1062 	}
1063 
1064 	dns_name_free(&svcb->svcdomain, svcb->mctx);
1065 	isc_mem_free(svcb->mctx, svcb->svc);
1066 	svcb->mctx = NULL;
1067 }
1068 
1069 static void
1070 freestruct_in_svcb(ARGS_FREESTRUCT) {
1071 	dns_rdata_in_svcb_t *svcb = source;
1072 
1073 	REQUIRE(svcb != NULL);
1074 	REQUIRE(svcb->common.rdclass == dns_rdataclass_in);
1075 	REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb);
1076 
1077 	generic_freestruct_in_svcb(CALL_FREESTRUCT);
1078 }
1079 
1080 static isc_result_t
1081 generic_additionaldata_in_svcb(ARGS_ADDLDATA) {
1082 	bool alias, done = false;
1083 	dns_fixedname_t fixed;
1084 	dns_name_t name, *fname = NULL;
1085 	dns_offsets_t offsets;
1086 	dns_rdataset_t rdataset;
1087 	isc_region_t region;
1088 	unsigned int cnames = 0;
1089 
1090 	dns_name_init(&name, offsets);
1091 	dns_rdata_toregion(rdata, &region);
1092 	alias = uint16_fromregion(&region) == 0;
1093 	isc_region_consume(&region, 2);
1094 
1095 	dns_name_fromregion(&name, &region);
1096 
1097 	if (dns_name_equal(&name, dns_rootname)) {
1098 		/*
1099 		 * "." only means owner name in service form.
1100 		 */
1101 		if (alias || dns_name_equal(owner, dns_rootname) ||
1102 		    !dns_name_ishostname(owner, false))
1103 		{
1104 			return ISC_R_SUCCESS;
1105 		}
1106 		/* Only lookup address records */
1107 		return (add)(arg, owner, dns_rdatatype_a,
1108 			     NULL DNS__DB_FILELINE);
1109 	}
1110 
1111 	/*
1112 	 * Follow CNAME chains when processing HTTPS and SVCB records.
1113 	 */
1114 	dns_rdataset_init(&rdataset);
1115 	fname = dns_fixedname_initname(&fixed);
1116 	do {
1117 		RETERR((add)(arg, &name, dns_rdatatype_cname,
1118 			     &rdataset DNS__DB_FILELINE));
1119 		if (dns_rdataset_isassociated(&rdataset)) {
1120 			isc_result_t result;
1121 			result = dns_rdataset_first(&rdataset);
1122 			if (result == ISC_R_SUCCESS) {
1123 				dns_rdata_t current = DNS_RDATA_INIT;
1124 				dns_rdata_cname_t cname;
1125 
1126 				dns_rdataset_current(&rdataset, &current);
1127 
1128 				result = dns_rdata_tostruct(&current, &cname,
1129 							    NULL);
1130 				RUNTIME_CHECK(result == ISC_R_SUCCESS);
1131 				dns_name_copy(&cname.cname, fname);
1132 				dns_name_clone(fname, &name);
1133 			} else {
1134 				done = true;
1135 			}
1136 			dns_rdataset_disassociate(&rdataset);
1137 		} else {
1138 			done = true;
1139 		}
1140 		/*
1141 		 * Stop following a potentially infinite CNAME chain.
1142 		 */
1143 		if (!done && cnames++ > MAX_CNAMES) {
1144 			return ISC_R_SUCCESS;
1145 		}
1146 	} while (!done);
1147 
1148 	/*
1149 	 * Look up HTTPS/SVCB records when processing the alias form.
1150 	 */
1151 	if (alias) {
1152 		RETERR((add)(arg, &name, rdata->type,
1153 			     &rdataset DNS__DB_FILELINE));
1154 		/*
1155 		 * Don't return A or AAAA if this is not the last element
1156 		 * in the HTTP / SVCB chain.
1157 		 */
1158 		if (dns_rdataset_isassociated(&rdataset)) {
1159 			dns_rdataset_disassociate(&rdataset);
1160 			return ISC_R_SUCCESS;
1161 		}
1162 	}
1163 	return (add)(arg, &name, dns_rdatatype_a, NULL DNS__DB_FILELINE);
1164 }
1165 
1166 static isc_result_t
1167 additionaldata_in_svcb(ARGS_ADDLDATA) {
1168 	REQUIRE(rdata->type == dns_rdatatype_svcb);
1169 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
1170 
1171 	return generic_additionaldata_in_svcb(CALL_ADDLDATA);
1172 }
1173 
1174 static isc_result_t
1175 digest_in_svcb(ARGS_DIGEST) {
1176 	isc_region_t region1;
1177 
1178 	REQUIRE(rdata->type == dns_rdatatype_svcb);
1179 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
1180 
1181 	dns_rdata_toregion(rdata, &region1);
1182 	return (digest)(arg, &region1);
1183 }
1184 
1185 static bool
1186 checkowner_in_svcb(ARGS_CHECKOWNER) {
1187 	REQUIRE(type == dns_rdatatype_svcb);
1188 	REQUIRE(rdclass == dns_rdataclass_in);
1189 
1190 	UNUSED(name);
1191 	UNUSED(type);
1192 	UNUSED(rdclass);
1193 	UNUSED(wildcard);
1194 
1195 	return true;
1196 }
1197 
1198 static bool
1199 generic_checknames_in_svcb(ARGS_CHECKNAMES) {
1200 	isc_region_t region;
1201 	dns_name_t name;
1202 	bool alias;
1203 
1204 	UNUSED(owner);
1205 
1206 	dns_rdata_toregion(rdata, &region);
1207 	INSIST(region.length > 1);
1208 	alias = uint16_fromregion(&region) == 0;
1209 	isc_region_consume(&region, 2);
1210 	dns_name_init(&name, NULL);
1211 	dns_name_fromregion(&name, &region);
1212 	if (!alias && !dns_name_ishostname(&name, false)) {
1213 		if (bad != NULL) {
1214 			dns_name_clone(&name, bad);
1215 		}
1216 		return false;
1217 	}
1218 	return true;
1219 }
1220 
1221 static bool
1222 checknames_in_svcb(ARGS_CHECKNAMES) {
1223 	REQUIRE(rdata->type == dns_rdatatype_svcb);
1224 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
1225 
1226 	return generic_checknames_in_svcb(CALL_CHECKNAMES);
1227 }
1228 
1229 static int
1230 casecompare_in_svcb(ARGS_COMPARE) {
1231 	return compare_in_svcb(rdata1, rdata2);
1232 }
1233 
1234 static isc_result_t
1235 generic_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) {
1236 	if (svcb->svclen == 0) {
1237 		return ISC_R_NOMORE;
1238 	}
1239 	svcb->offset = 0;
1240 	return ISC_R_SUCCESS;
1241 }
1242 
1243 static isc_result_t
1244 generic_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) {
1245 	isc_region_t region;
1246 	size_t len;
1247 
1248 	if (svcb->offset >= svcb->svclen) {
1249 		return ISC_R_NOMORE;
1250 	}
1251 
1252 	region.base = svcb->svc + svcb->offset;
1253 	region.length = svcb->svclen - svcb->offset;
1254 	INSIST(region.length >= 4);
1255 	isc_region_consume(&region, 2);
1256 	len = uint16_fromregion(&region);
1257 	INSIST(region.length >= len + 2);
1258 	svcb->offset += len + 4;
1259 	return svcb->offset >= svcb->svclen ? ISC_R_NOMORE : ISC_R_SUCCESS;
1260 }
1261 
1262 static void
1263 generic_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) {
1264 	size_t len;
1265 
1266 	INSIST(svcb->offset <= svcb->svclen);
1267 
1268 	region->base = svcb->svc + svcb->offset;
1269 	region->length = svcb->svclen - svcb->offset;
1270 	INSIST(region->length >= 4);
1271 	isc_region_consume(region, 2);
1272 	len = uint16_fromregion(region);
1273 	INSIST(region->length >= len + 2);
1274 	region->base = svcb->svc + svcb->offset;
1275 	region->length = len + 4;
1276 }
1277 
1278 isc_result_t
1279 dns_rdata_in_svcb_first(dns_rdata_in_svcb_t *svcb) {
1280 	REQUIRE(svcb != NULL);
1281 	REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb);
1282 	REQUIRE(svcb->common.rdclass == dns_rdataclass_in);
1283 
1284 	return generic_rdata_in_svcb_first(svcb);
1285 }
1286 
1287 isc_result_t
1288 dns_rdata_in_svcb_next(dns_rdata_in_svcb_t *svcb) {
1289 	REQUIRE(svcb != NULL);
1290 	REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb);
1291 	REQUIRE(svcb->common.rdclass == dns_rdataclass_in);
1292 
1293 	return generic_rdata_in_svcb_next(svcb);
1294 }
1295 
1296 void
1297 dns_rdata_in_svcb_current(dns_rdata_in_svcb_t *svcb, isc_region_t *region) {
1298 	REQUIRE(svcb != NULL);
1299 	REQUIRE(svcb->common.rdtype == dns_rdatatype_svcb);
1300 	REQUIRE(svcb->common.rdclass == dns_rdataclass_in);
1301 	REQUIRE(region != NULL);
1302 
1303 	generic_rdata_in_svcb_current(svcb, region);
1304 }
1305 
1306 #endif /* RDATA_IN_1_SVCB_64_C */
1307