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