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