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, ®ion);
76 isc_region_consume(®ion, 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(®ion, 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, ®ion);
631
632 /*
633 * SvcPriority.
634 */
635 num = uint16_fromregion(®ion);
636 isc_region_consume(®ion, 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, ®ion);
645 isc_region_consume(®ion, 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(®ion);
657 isc_region_consume(®ion, 2);
658 RETERR(str_totext(svcparamkey(num, &encoding, buf, sizeof(buf)),
659 target));
660
661 INSIST(region.length >= 2);
662 num = uint16_fromregion(®ion);
663 isc_region_consume(®ion, 2);
664
665 INSIST(region.length >= num);
666 r = region;
667 r.length = num;
668 isc_region_consume(®ion, 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, ®ion);
773 if (region.length < 2) {
774 return (ISC_R_UNEXPECTEDEND);
775 }
776 RETERR(mem_tobuffer(target, region.base, 2));
777 alias = uint16_fromregion(®ion) == 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, ®ion);
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(®ion);
805 isc_region_consume(®ion, 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(®ion);
853 isc_region_consume(®ion, 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(®ion, 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, ®ion);
919 RETERR(mem_tobuffer(target, region.base, 2));
920 isc_region_consume(®ion, 2);
921
922 /*
923 * TargetName.
924 */
925 dns_name_init(&name, offsets);
926 dns_name_fromregion(&name, ®ion);
927 RETERR(dns_name_towire(&name, cctx, target));
928 isc_region_consume(®ion, 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, ®ion1);
957 dns_rdata_toregion(rdata2, ®ion2);
958
959 return (isc_region_compare(®ion1, ®ion2));
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, ®ion);
976 RETERR(isc_buffer_copyregion(target, ®ion));
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, ®ion);
1008
1009 svcb->priority = uint16_fromregion(®ion);
1010 isc_region_consume(®ion, 2);
1011
1012 dns_name_init(&svcb->svcdomain, NULL);
1013 dns_name_init(&name, NULL);
1014 dns_name_fromregion(&name, ®ion);
1015 isc_region_consume(®ion, 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, ®ion1);
1097 return ((digest)(arg, ®ion1));
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, ®ion);
1122 INSIST(region.length > 1);
1123 alias = uint16_fromregion(®ion) == 0;
1124 isc_region_consume(®ion, 2);
1125 dns_name_init(&name, NULL);
1126 dns_name_fromregion(&name, ®ion);
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(®ion, 2);
1171 len = uint16_fromregion(®ion);
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