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, &region);
342 
343 	/*
344 	 * Flags
345 	 */
346 	flags = uint8_consume_fromregion(&region);
347 	snprintf(buf, sizeof(buf), "%u ", flags);
348 	RETERR(str_totext(buf, target));
349 
350 	/*
351 	 * Tag
352 	 */
353 	RETERR(txt_totext(&region, false, target));
354 	RETERR(str_totext(" ", target));
355 
356 	/*
357 	 * Value
358 	 */
359 	RETERR(multitxt_totext(&region, 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, &region);
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, &region));
482 
483 	/*
484 	 * Value
485 	 */
486 	region.base = caa->value;
487 	region.length = caa->value_len;
488 	return (isc_buffer_copyregion(target, &region));
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