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 #ifndef GENERIC_CAA_257_C
15 #define GENERIC_CAA_257_C 1
16
17 #define RRTYPE_CAA_ATTRIBUTES (0)
18
19 static unsigned char const alphanumeric[256] = {
20 /* 0x00-0x0f */ 0,
21 0,
22 0,
23 0,
24 0,
25 0,
26 0,
27 0,
28 0,
29 0,
30 0,
31 0,
32 0,
33 0,
34 0,
35 0,
36 /* 0x10-0x1f */ 0,
37 0,
38 0,
39 0,
40 0,
41 0,
42 0,
43 0,
44 0,
45 0,
46 0,
47 0,
48 0,
49 0,
50 0,
51 0,
52 /* 0x20-0x2f */ 0,
53 0,
54 0,
55 0,
56 0,
57 0,
58 0,
59 0,
60 0,
61 0,
62 0,
63 0,
64 0,
65 0,
66 0,
67 0,
68 /* 0x30-0x3f */ 1,
69 1,
70 1,
71 1,
72 1,
73 1,
74 1,
75 1,
76 1,
77 1,
78 0,
79 0,
80 0,
81 0,
82 0,
83 0,
84 /* 0x40-0x4f */ 0,
85 1,
86 1,
87 1,
88 1,
89 1,
90 1,
91 1,
92 1,
93 1,
94 1,
95 1,
96 1,
97 1,
98 1,
99 1,
100 /* 0x50-0x5f */ 1,
101 1,
102 1,
103 1,
104 1,
105 1,
106 1,
107 1,
108 1,
109 1,
110 1,
111 0,
112 0,
113 0,
114 0,
115 0,
116 /* 0x60-0x6f */ 0,
117 1,
118 1,
119 1,
120 1,
121 1,
122 1,
123 1,
124 1,
125 1,
126 1,
127 1,
128 1,
129 1,
130 1,
131 1,
132 /* 0x70-0x7f */ 1,
133 1,
134 1,
135 1,
136 1,
137 1,
138 1,
139 1,
140 1,
141 1,
142 1,
143 0,
144 0,
145 0,
146 0,
147 0,
148 /* 0x80-0x8f */ 0,
149 0,
150 0,
151 0,
152 0,
153 0,
154 0,
155 0,
156 0,
157 0,
158 0,
159 0,
160 0,
161 0,
162 0,
163 0,
164 /* 0x90-0x9f */ 0,
165 0,
166 0,
167 0,
168 0,
169 0,
170 0,
171 0,
172 0,
173 0,
174 0,
175 0,
176 0,
177 0,
178 0,
179 0,
180 /* 0xa0-0xaf */ 0,
181 0,
182 0,
183 0,
184 0,
185 0,
186 0,
187 0,
188 0,
189 0,
190 0,
191 0,
192 0,
193 0,
194 0,
195 0,
196 /* 0xb0-0xbf */ 0,
197 0,
198 0,
199 0,
200 0,
201 0,
202 0,
203 0,
204 0,
205 0,
206 0,
207 0,
208 0,
209 0,
210 0,
211 0,
212 /* 0xc0-0xcf */ 0,
213 0,
214 0,
215 0,
216 0,
217 0,
218 0,
219 0,
220 0,
221 0,
222 0,
223 0,
224 0,
225 0,
226 0,
227 0,
228 /* 0xd0-0xdf */ 0,
229 0,
230 0,
231 0,
232 0,
233 0,
234 0,
235 0,
236 0,
237 0,
238 0,
239 0,
240 0,
241 0,
242 0,
243 0,
244 /* 0xe0-0xef */ 0,
245 0,
246 0,
247 0,
248 0,
249 0,
250 0,
251 0,
252 0,
253 0,
254 0,
255 0,
256 0,
257 0,
258 0,
259 0,
260 /* 0xf0-0xff */ 0,
261 0,
262 0,
263 0,
264 0,
265 0,
266 0,
267 0,
268 0,
269 0,
270 0,
271 0,
272 0,
273 0,
274 0,
275 0,
276 };
277
278 static inline isc_result_t
fromtext_caa(ARGS_FROMTEXT)279 fromtext_caa(ARGS_FROMTEXT) {
280 isc_token_t token;
281 isc_textregion_t tr;
282 uint8_t flags;
283 unsigned int i;
284
285 REQUIRE(type == dns_rdatatype_caa);
286
287 UNUSED(type);
288 UNUSED(rdclass);
289 UNUSED(origin);
290 UNUSED(options);
291 UNUSED(callbacks);
292
293 /* Flags. */
294 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
295 false));
296 if (token.value.as_ulong > 255U) {
297 RETTOK(ISC_R_RANGE);
298 }
299 flags = (uint8_t)(token.value.as_ulong & 255U);
300 RETERR(uint8_tobuffer(flags, target));
301
302 /*
303 * Tag
304 */
305 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
306 false));
307 tr = token.value.as_textregion;
308 for (i = 0; i < tr.length; i++) {
309 if (!alphanumeric[(unsigned char)tr.base[i]]) {
310 RETTOK(DNS_R_SYNTAX);
311 }
312 }
313 RETERR(uint8_tobuffer(tr.length, target));
314 RETERR(mem_tobuffer(target, tr.base, tr.length));
315
316 /*
317 * Value
318 */
319 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
320 false));
321 if (token.type != isc_tokentype_qstring &&
322 token.type != isc_tokentype_string) {
323 RETERR(DNS_R_SYNTAX);
324 }
325 RETERR(multitxt_fromtext(&token.value.as_textregion, target));
326 return (ISC_R_SUCCESS);
327 }
328
329 static inline isc_result_t
totext_caa(ARGS_TOTEXT)330 totext_caa(ARGS_TOTEXT) {
331 isc_region_t region;
332 uint8_t flags;
333 char buf[256];
334
335 UNUSED(tctx);
336
337 REQUIRE(rdata->type == dns_rdatatype_caa);
338 REQUIRE(rdata->length >= 3U);
339 REQUIRE(rdata->data != NULL);
340
341 dns_rdata_toregion(rdata, ®ion);
342
343 /*
344 * Flags
345 */
346 flags = uint8_consume_fromregion(®ion);
347 snprintf(buf, sizeof(buf), "%u ", flags);
348 RETERR(str_totext(buf, target));
349
350 /*
351 * Tag
352 */
353 RETERR(txt_totext(®ion, false, target));
354 RETERR(str_totext(" ", target));
355
356 /*
357 * Value
358 */
359 RETERR(multitxt_totext(®ion, target));
360 return (ISC_R_SUCCESS);
361 }
362
363 static inline isc_result_t
fromwire_caa(ARGS_FROMWIRE)364 fromwire_caa(ARGS_FROMWIRE) {
365 isc_region_t sr;
366 unsigned int len, i;
367
368 REQUIRE(type == dns_rdatatype_caa);
369
370 UNUSED(type);
371 UNUSED(rdclass);
372 UNUSED(dctx);
373 UNUSED(options);
374
375 /*
376 * Flags
377 */
378 isc_buffer_activeregion(source, &sr);
379 if (sr.length < 2) {
380 return (ISC_R_UNEXPECTEDEND);
381 }
382
383 /*
384 * Flags, tag length
385 */
386 RETERR(mem_tobuffer(target, sr.base, 2));
387 len = sr.base[1];
388 isc_region_consume(&sr, 2);
389 isc_buffer_forward(source, 2);
390
391 /*
392 * Zero length tag fields are illegal.
393 */
394 if (sr.length < len || len == 0) {
395 RETERR(DNS_R_FORMERR);
396 }
397
398 /* Check the Tag's value */
399 for (i = 0; i < len; i++) {
400 if (!alphanumeric[sr.base[i]]) {
401 RETERR(DNS_R_FORMERR);
402 /*
403 * Tag + Value
404 */
405 }
406 }
407 /*
408 * Tag + Value
409 */
410 isc_buffer_forward(source, sr.length);
411 return (mem_tobuffer(target, sr.base, sr.length));
412 }
413
414 static inline isc_result_t
towire_caa(ARGS_TOWIRE)415 towire_caa(ARGS_TOWIRE) {
416 isc_region_t region;
417
418 REQUIRE(rdata->type == dns_rdatatype_caa);
419 REQUIRE(rdata->length >= 3U);
420 REQUIRE(rdata->data != NULL);
421
422 UNUSED(cctx);
423
424 dns_rdata_toregion(rdata, ®ion);
425 return (mem_tobuffer(target, region.base, region.length));
426 }
427
428 static inline int
compare_caa(ARGS_COMPARE)429 compare_caa(ARGS_COMPARE) {
430 isc_region_t r1, r2;
431
432 REQUIRE(rdata1->type == rdata2->type);
433 REQUIRE(rdata1->rdclass == rdata2->rdclass);
434 REQUIRE(rdata1->type == dns_rdatatype_caa);
435 REQUIRE(rdata1->length >= 3U);
436 REQUIRE(rdata2->length >= 3U);
437 REQUIRE(rdata1->data != NULL);
438 REQUIRE(rdata2->data != NULL);
439
440 dns_rdata_toregion(rdata1, &r1);
441 dns_rdata_toregion(rdata2, &r2);
442 return (isc_region_compare(&r1, &r2));
443 }
444
445 static inline isc_result_t
fromstruct_caa(ARGS_FROMSTRUCT)446 fromstruct_caa(ARGS_FROMSTRUCT) {
447 dns_rdata_caa_t *caa = source;
448 isc_region_t region;
449 unsigned int i;
450
451 REQUIRE(type == dns_rdatatype_caa);
452 REQUIRE(caa != NULL);
453 REQUIRE(caa->common.rdtype == type);
454 REQUIRE(caa->common.rdclass == rdclass);
455 REQUIRE(caa->tag != NULL && caa->tag_len != 0);
456 REQUIRE(caa->value != NULL);
457
458 UNUSED(type);
459 UNUSED(rdclass);
460
461 /*
462 * Flags
463 */
464 RETERR(uint8_tobuffer(caa->flags, target));
465
466 /*
467 * Tag length
468 */
469 RETERR(uint8_tobuffer(caa->tag_len, target));
470
471 /*
472 * Tag
473 */
474 region.base = caa->tag;
475 region.length = caa->tag_len;
476 for (i = 0; i < region.length; i++) {
477 if (!alphanumeric[region.base[i]]) {
478 RETERR(DNS_R_SYNTAX);
479 }
480 }
481 RETERR(isc_buffer_copyregion(target, ®ion));
482
483 /*
484 * Value
485 */
486 region.base = caa->value;
487 region.length = caa->value_len;
488 return (isc_buffer_copyregion(target, ®ion));
489 }
490
491 static inline isc_result_t
tostruct_caa(ARGS_TOSTRUCT)492 tostruct_caa(ARGS_TOSTRUCT) {
493 dns_rdata_caa_t *caa = target;
494 isc_region_t sr;
495
496 REQUIRE(rdata->type == dns_rdatatype_caa);
497 REQUIRE(caa != NULL);
498 REQUIRE(rdata->length >= 3U);
499 REQUIRE(rdata->data != NULL);
500
501 caa->common.rdclass = rdata->rdclass;
502 caa->common.rdtype = rdata->type;
503 ISC_LINK_INIT(&caa->common, link);
504
505 dns_rdata_toregion(rdata, &sr);
506
507 /*
508 * Flags
509 */
510 if (sr.length < 1) {
511 return (ISC_R_UNEXPECTEDEND);
512 }
513 caa->flags = uint8_fromregion(&sr);
514 isc_region_consume(&sr, 1);
515
516 /*
517 * Tag length
518 */
519 if (sr.length < 1) {
520 return (ISC_R_UNEXPECTEDEND);
521 }
522 caa->tag_len = uint8_fromregion(&sr);
523 isc_region_consume(&sr, 1);
524
525 /*
526 * Tag
527 */
528 if (sr.length < caa->tag_len) {
529 return (ISC_R_UNEXPECTEDEND);
530 }
531 caa->tag = mem_maybedup(mctx, sr.base, caa->tag_len);
532 if (caa->tag == NULL) {
533 return (ISC_R_NOMEMORY);
534 }
535 isc_region_consume(&sr, caa->tag_len);
536
537 /*
538 * Value
539 */
540 caa->value_len = sr.length;
541 caa->value = mem_maybedup(mctx, sr.base, sr.length);
542 if (caa->value == NULL) {
543 return (ISC_R_NOMEMORY);
544 }
545
546 caa->mctx = mctx;
547 return (ISC_R_SUCCESS);
548 }
549
550 static inline void
freestruct_caa(ARGS_FREESTRUCT)551 freestruct_caa(ARGS_FREESTRUCT) {
552 dns_rdata_caa_t *caa = (dns_rdata_caa_t *)source;
553
554 REQUIRE(caa != NULL);
555 REQUIRE(caa->common.rdtype == dns_rdatatype_caa);
556
557 if (caa->mctx == NULL) {
558 return;
559 }
560
561 if (caa->tag != NULL) {
562 isc_mem_free(caa->mctx, caa->tag);
563 }
564 if (caa->value != NULL) {
565 isc_mem_free(caa->mctx, caa->value);
566 }
567 caa->mctx = NULL;
568 }
569
570 static inline isc_result_t
additionaldata_caa(ARGS_ADDLDATA)571 additionaldata_caa(ARGS_ADDLDATA) {
572 REQUIRE(rdata->type == dns_rdatatype_caa);
573 REQUIRE(rdata->data != NULL);
574 REQUIRE(rdata->length >= 3U);
575
576 UNUSED(rdata);
577 UNUSED(add);
578 UNUSED(arg);
579
580 return (ISC_R_SUCCESS);
581 }
582
583 static inline isc_result_t
digest_caa(ARGS_DIGEST)584 digest_caa(ARGS_DIGEST) {
585 isc_region_t r;
586
587 REQUIRE(rdata->type == dns_rdatatype_caa);
588 REQUIRE(rdata->data != NULL);
589 REQUIRE(rdata->length >= 3U);
590
591 dns_rdata_toregion(rdata, &r);
592
593 return ((digest)(arg, &r));
594 }
595
596 static inline bool
checkowner_caa(ARGS_CHECKOWNER)597 checkowner_caa(ARGS_CHECKOWNER) {
598 REQUIRE(type == dns_rdatatype_caa);
599
600 UNUSED(name);
601 UNUSED(type);
602 UNUSED(rdclass);
603 UNUSED(wildcard);
604
605 return (true);
606 }
607
608 static inline bool
checknames_caa(ARGS_CHECKNAMES)609 checknames_caa(ARGS_CHECKNAMES) {
610 REQUIRE(rdata->type == dns_rdatatype_caa);
611 REQUIRE(rdata->data != NULL);
612 REQUIRE(rdata->length >= 3U);
613
614 UNUSED(rdata);
615 UNUSED(owner);
616 UNUSED(bad);
617
618 return (true);
619 }
620
621 static inline int
casecompare_caa(ARGS_COMPARE)622 casecompare_caa(ARGS_COMPARE) {
623 return (compare_caa(rdata1, rdata2));
624 }
625
626 #endif /* GENERIC_CAA_257_C */
627