xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata.c (revision b5c47949a45ac972130c38cf13dfd8afb1f09285)
1 /*	$NetBSD: rdata.c,v 1.9 2021/02/19 16:42:16 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
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 /*! \file */
15 
16 #include <ctype.h>
17 #include <inttypes.h>
18 #include <stdbool.h>
19 
20 #include <isc/base64.h>
21 #include <isc/hex.h>
22 #include <isc/lex.h>
23 #include <isc/mem.h>
24 #include <isc/parseint.h>
25 #include <isc/print.h>
26 #include <isc/string.h>
27 #include <isc/util.h>
28 
29 #include <dns/callbacks.h>
30 #include <dns/cert.h>
31 #include <dns/compress.h>
32 #include <dns/dsdigest.h>
33 #include <dns/enumtype.h>
34 #include <dns/keyflags.h>
35 #include <dns/keyvalues.h>
36 #include <dns/message.h>
37 #include <dns/rcode.h>
38 #include <dns/rdata.h>
39 #include <dns/rdataclass.h>
40 #include <dns/rdatastruct.h>
41 #include <dns/rdatatype.h>
42 #include <dns/result.h>
43 #include <dns/secalg.h>
44 #include <dns/secproto.h>
45 #include <dns/time.h>
46 #include <dns/ttl.h>
47 
48 #define RETERR(x)                        \
49 	do {                             \
50 		isc_result_t _r = (x);   \
51 		if (_r != ISC_R_SUCCESS) \
52 			return ((_r));   \
53 	} while (/*CONSTCOND*/0)
54 
55 #define RETTOK(x)                                          \
56 	do {                                               \
57 		isc_result_t _r = (x);                     \
58 		if (_r != ISC_R_SUCCESS) {                 \
59 			isc_lex_ungettoken(lexer, &token); \
60 			return (_r);                       \
61 		}                                          \
62 	} while (/*CONSTCOND*/0)
63 
64 #define CHECK(op)                            \
65 	do {                                 \
66 		result = (op);               \
67 		if (result != ISC_R_SUCCESS) \
68 			goto cleanup;        \
69 	} while (/*CONSTCOND*/0)
70 
71 #define CHECKTOK(op)                                       \
72 	do {                                               \
73 		result = (op);                             \
74 		if (result != ISC_R_SUCCESS) {             \
75 			isc_lex_ungettoken(lexer, &token); \
76 			goto cleanup;                      \
77 		}                                          \
78 	} while (/*CONSTCOND*/0)
79 
80 #define DNS_AS_STR(t) ((t).value.as_textregion.base)
81 
82 #define ARGS_FROMTEXT                                           \
83 	int rdclass, dns_rdatatype_t type, isc_lex_t *lexer,    \
84 		const dns_name_t *origin, unsigned int options, \
85 		isc_buffer_t *target, dns_rdatacallbacks_t *callbacks
86 
87 #define ARGS_TOTEXT \
88 	dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target
89 
90 #define ARGS_FROMWIRE                                            \
91 	int rdclass, dns_rdatatype_t type, isc_buffer_t *source, \
92 		dns_decompress_t *dctx, unsigned int options,    \
93 		isc_buffer_t *target
94 
95 #define ARGS_TOWIRE \
96 	dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target
97 
98 #define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
99 
100 #define ARGS_FROMSTRUCT \
101 	int rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target
102 
103 #define ARGS_TOSTRUCT const dns_rdata_t *rdata, void *target, isc_mem_t *mctx
104 
105 #define ARGS_FREESTRUCT void *source
106 
107 #define ARGS_ADDLDATA \
108 	dns_rdata_t *rdata, dns_additionaldatafunc_t add, void *arg
109 
110 #define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
111 
112 #define ARGS_CHECKOWNER                                   \
113 	const dns_name_t *name, dns_rdataclass_t rdclass, \
114 		dns_rdatatype_t type, bool wildcard
115 
116 #define ARGS_CHECKNAMES \
117 	dns_rdata_t *rdata, const dns_name_t *owner, dns_name_t *bad
118 
119 /*%
120  * Context structure for the totext_ functions.
121  * Contains formatting options for rdata-to-text
122  * conversion.
123  */
124 typedef struct dns_rdata_textctx {
125 	const dns_name_t *origin;      /*%< Current origin, or NULL. */
126 	dns_masterstyle_flags_t flags; /*%< DNS_STYLEFLAG_*  */
127 	unsigned int width;	       /*%< Width of rdata column. */
128 	const char *linebreak;	       /*%< Line break string. */
129 } dns_rdata_textctx_t;
130 
131 static isc_result_t
132 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target);
133 
134 static isc_result_t
135 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
136 
137 static isc_result_t
138 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
139 
140 static isc_result_t
141 multitxt_totext(isc_region_t *source, isc_buffer_t *target);
142 
143 static isc_result_t
144 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
145 
146 static bool
147 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target);
148 
149 static unsigned int
150 name_length(const dns_name_t *name);
151 
152 static isc_result_t
153 str_totext(const char *source, isc_buffer_t *target);
154 
155 static isc_result_t
156 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target);
157 
158 static bool
159 buffer_empty(isc_buffer_t *source);
160 
161 static void
162 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
163 
164 static isc_result_t
165 uint32_tobuffer(uint32_t, isc_buffer_t *target);
166 
167 static isc_result_t
168 uint16_tobuffer(uint32_t, isc_buffer_t *target);
169 
170 static isc_result_t
171 uint8_tobuffer(uint32_t, isc_buffer_t *target);
172 
173 static isc_result_t
174 name_tobuffer(const dns_name_t *name, isc_buffer_t *target);
175 
176 static uint32_t
177 uint32_fromregion(isc_region_t *region);
178 
179 static uint16_t
180 uint16_fromregion(isc_region_t *region);
181 
182 static uint8_t
183 uint8_fromregion(isc_region_t *region);
184 
185 static uint8_t
186 uint8_consume_fromregion(isc_region_t *region);
187 
188 static isc_result_t
189 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
190 
191 static int
192 hexvalue(char value);
193 
194 static int
195 decvalue(char value);
196 
197 static void
198 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
199 	ISC_FORMAT_PRINTF(2, 3);
200 
201 static void
202 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
203 	       dns_rdatacallbacks_t *callbacks, const char *name,
204 	       unsigned long line, isc_token_t *token, isc_result_t result);
205 
206 static void
207 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
208 
209 static isc_result_t
210 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
211 	     isc_buffer_t *target);
212 
213 static void
214 warn_badname(const dns_name_t *name, isc_lex_t *lexer,
215 	     dns_rdatacallbacks_t *callbacks);
216 
217 static void
218 warn_badmx(isc_token_t *token, isc_lex_t *lexer,
219 	   dns_rdatacallbacks_t *callbacks);
220 
221 static uint16_t
222 uint16_consume_fromregion(isc_region_t *region);
223 
224 static isc_result_t
225 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
226 	       isc_buffer_t *target);
227 
228 static inline isc_result_t generic_fromtext_key(ARGS_FROMTEXT);
229 
230 static inline isc_result_t generic_totext_key(ARGS_TOTEXT);
231 
232 static inline isc_result_t generic_fromwire_key(ARGS_FROMWIRE);
233 
234 static inline isc_result_t generic_fromstruct_key(ARGS_FROMSTRUCT);
235 
236 static inline isc_result_t generic_tostruct_key(ARGS_TOSTRUCT);
237 
238 static inline void generic_freestruct_key(ARGS_FREESTRUCT);
239 
240 static isc_result_t generic_fromtext_txt(ARGS_FROMTEXT);
241 
242 static isc_result_t generic_totext_txt(ARGS_TOTEXT);
243 
244 static isc_result_t generic_fromwire_txt(ARGS_FROMWIRE);
245 
246 static isc_result_t generic_fromstruct_txt(ARGS_FROMSTRUCT);
247 
248 static isc_result_t generic_tostruct_txt(ARGS_TOSTRUCT);
249 
250 static void generic_freestruct_txt(ARGS_FREESTRUCT);
251 
252 static isc_result_t
253 generic_txt_first(dns_rdata_txt_t *txt);
254 
255 static isc_result_t
256 generic_txt_next(dns_rdata_txt_t *txt);
257 
258 static isc_result_t
259 generic_txt_current(dns_rdata_txt_t *txt, dns_rdata_txt_string_t *string);
260 
261 static isc_result_t generic_totext_ds(ARGS_TOTEXT);
262 
263 static isc_result_t generic_tostruct_ds(ARGS_TOSTRUCT);
264 
265 static isc_result_t generic_fromtext_ds(ARGS_FROMTEXT);
266 
267 static isc_result_t generic_fromwire_ds(ARGS_FROMWIRE);
268 
269 static isc_result_t generic_fromstruct_ds(ARGS_FROMSTRUCT);
270 
271 static isc_result_t generic_fromtext_tlsa(ARGS_FROMTEXT);
272 
273 static isc_result_t generic_totext_tlsa(ARGS_TOTEXT);
274 
275 static isc_result_t generic_fromwire_tlsa(ARGS_FROMWIRE);
276 
277 static isc_result_t generic_fromstruct_tlsa(ARGS_FROMSTRUCT);
278 
279 static isc_result_t generic_tostruct_tlsa(ARGS_TOSTRUCT);
280 
281 static void generic_freestruct_tlsa(ARGS_FREESTRUCT);
282 
283 /*% INT16 Size */
284 #define NS_INT16SZ 2
285 /*% IPv6 Address Size */
286 #define NS_LOCATORSZ 8
287 
288 /*
289  * Active Directory gc._msdcs.<forest> prefix.
290  */
291 static unsigned char gc_msdcs_data[] = "\002gc\006_msdcs";
292 static unsigned char gc_msdcs_offset[] = { 0, 3 };
293 
294 static dns_name_t const gc_msdcs = DNS_NAME_INITNONABSOLUTE(gc_msdcs_data,
295 							    gc_msdcs_offset);
296 
297 /*%
298  *	convert presentation level address to network order binary form.
299  * \return
300  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
301  * \note
302  *	(1) does not touch `dst' unless it's returning 1.
303  */
304 static inline int
305 locator_pton(const char *src, unsigned char *dst) {
306 	static const char xdigits_l[] = "0123456789abcdef",
307 			  xdigits_u[] = "0123456789ABCDEF";
308 	unsigned char tmp[NS_LOCATORSZ];
309 	unsigned char *tp = tmp, *endp;
310 	const char *xdigits;
311 	int ch, seen_xdigits;
312 	unsigned int val;
313 
314 	memset(tp, '\0', NS_LOCATORSZ);
315 	endp = tp + NS_LOCATORSZ;
316 	seen_xdigits = 0;
317 	val = 0;
318 	while ((ch = *src++) != '\0') {
319 		const char *pch;
320 
321 		pch = strchr((xdigits = xdigits_l), ch);
322 		if (pch == NULL) {
323 			pch = strchr((xdigits = xdigits_u), ch);
324 		}
325 		if (pch != NULL) {
326 			val <<= 4;
327 			val |= (pch - xdigits);
328 			if (++seen_xdigits > 4) {
329 				return (0);
330 			}
331 			continue;
332 		}
333 		if (ch == ':') {
334 			if (!seen_xdigits) {
335 				return (0);
336 			}
337 			if (tp + NS_INT16SZ > endp) {
338 				return (0);
339 			}
340 			*tp++ = (unsigned char)(val >> 8) & 0xff;
341 			*tp++ = (unsigned char)val & 0xff;
342 			seen_xdigits = 0;
343 			val = 0;
344 			continue;
345 		}
346 		return (0);
347 	}
348 	if (seen_xdigits) {
349 		if (tp + NS_INT16SZ > endp) {
350 			return (0);
351 		}
352 		*tp++ = (unsigned char)(val >> 8) & 0xff;
353 		*tp++ = (unsigned char)val & 0xff;
354 	}
355 	if (tp != endp) {
356 		return (0);
357 	}
358 	memmove(dst, tmp, NS_LOCATORSZ);
359 	return (1);
360 }
361 
362 static inline isc_result_t
363 name_duporclone(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
364 	if (mctx != NULL) {
365 		dns_name_dup(source, mctx, target);
366 	} else {
367 		dns_name_clone(source, target);
368 	}
369 	return (ISC_R_SUCCESS);
370 }
371 
372 static inline void *
373 mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
374 	void *copy;
375 
376 	if (mctx == NULL) {
377 		return (source);
378 	}
379 	copy = isc_mem_allocate(mctx, length);
380 	memmove(copy, source, length);
381 
382 	return (copy);
383 }
384 
385 static inline isc_result_t
386 typemap_fromtext(isc_lex_t *lexer, isc_buffer_t *target, bool allow_empty) {
387 	isc_token_t token;
388 	unsigned char bm[8 * 1024]; /* 64k bits */
389 	dns_rdatatype_t covered, max_used;
390 	int octet;
391 	unsigned int max_octet, newend, end;
392 	int window;
393 	bool first = true;
394 
395 	max_used = 0;
396 	bm[0] = 0;
397 	end = 0;
398 
399 	do {
400 		RETERR(isc_lex_getmastertoken(lexer, &token,
401 					      isc_tokentype_string, true));
402 		if (token.type != isc_tokentype_string) {
403 			break;
404 		}
405 		RETTOK(dns_rdatatype_fromtext(&covered,
406 					      &token.value.as_textregion));
407 		if (covered > max_used) {
408 			newend = covered / 8;
409 			if (newend > end) {
410 				memset(&bm[end + 1], 0, newend - end);
411 				end = newend;
412 			}
413 			max_used = covered;
414 		}
415 		bm[covered / 8] |= (0x80 >> (covered % 8));
416 		first = false;
417 	} while (1);
418 	isc_lex_ungettoken(lexer, &token);
419 	if (!allow_empty && first) {
420 		return (DNS_R_FORMERR);
421 	}
422 
423 	for (window = 0; window < 256; window++) {
424 		if (max_used < window * 256) {
425 			break;
426 		}
427 
428 		max_octet = max_used - (window * 256);
429 		if (max_octet >= 256) {
430 			max_octet = 31;
431 		} else {
432 			max_octet /= 8;
433 		}
434 
435 		/*
436 		 * Find if we have a type in this window.
437 		 */
438 		for (octet = max_octet; octet >= 0; octet--) {
439 			if (bm[window * 32 + octet] != 0) {
440 				break;
441 			}
442 		}
443 		if (octet < 0) {
444 			continue;
445 		}
446 		RETERR(uint8_tobuffer(window, target));
447 		RETERR(uint8_tobuffer(octet + 1, target));
448 		RETERR(mem_tobuffer(target, &bm[window * 32], octet + 1));
449 	}
450 	return (ISC_R_SUCCESS);
451 }
452 
453 static inline isc_result_t
454 typemap_totext(isc_region_t *sr, dns_rdata_textctx_t *tctx,
455 	       isc_buffer_t *target) {
456 	unsigned int i, j, k;
457 	unsigned int window, len;
458 	bool first = true;
459 
460 	for (i = 0; i < sr->length; i += len) {
461 		if (tctx != NULL &&
462 		    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
463 			RETERR(str_totext(tctx->linebreak, target));
464 			first = true;
465 		}
466 		INSIST(i + 2 <= sr->length);
467 		window = sr->base[i];
468 		len = sr->base[i + 1];
469 		INSIST(len > 0 && len <= 32);
470 		i += 2;
471 		INSIST(i + len <= sr->length);
472 		for (j = 0; j < len; j++) {
473 			dns_rdatatype_t t;
474 			if (sr->base[i + j] == 0) {
475 				continue;
476 			}
477 			for (k = 0; k < 8; k++) {
478 				if ((sr->base[i + j] & (0x80 >> k)) == 0) {
479 					continue;
480 				}
481 				t = window * 256 + j * 8 + k;
482 				if (!first) {
483 					RETERR(str_totext(" ", target));
484 				}
485 				first = false;
486 				if (dns_rdatatype_isknown(t)) {
487 					RETERR(dns_rdatatype_totext(t, target));
488 				} else {
489 					char buf[sizeof("TYPE65535")];
490 					snprintf(buf, sizeof(buf), "TYPE%u", t);
491 					RETERR(str_totext(buf, target));
492 				}
493 			}
494 		}
495 	}
496 	return (ISC_R_SUCCESS);
497 }
498 
499 static isc_result_t
500 typemap_test(isc_region_t *sr, bool allow_empty) {
501 	unsigned int window, lastwindow = 0;
502 	unsigned int len;
503 	bool first = true;
504 	unsigned int i;
505 
506 	for (i = 0; i < sr->length; i += len) {
507 		/*
508 		 * Check for overflow.
509 		 */
510 		if (i + 2 > sr->length) {
511 			RETERR(DNS_R_FORMERR);
512 		}
513 		window = sr->base[i];
514 		len = sr->base[i + 1];
515 		i += 2;
516 		/*
517 		 * Check that bitmap windows are in the correct order.
518 		 */
519 		if (!first && window <= lastwindow) {
520 			RETERR(DNS_R_FORMERR);
521 		}
522 		/*
523 		 * Check for legal lengths.
524 		 */
525 		if (len < 1 || len > 32) {
526 			RETERR(DNS_R_FORMERR);
527 		}
528 		/*
529 		 * Check for overflow.
530 		 */
531 		if (i + len > sr->length) {
532 			RETERR(DNS_R_FORMERR);
533 		}
534 		/*
535 		 * The last octet of the bitmap must be non zero.
536 		 */
537 		if (sr->base[i + len - 1] == 0) {
538 			RETERR(DNS_R_FORMERR);
539 		}
540 		lastwindow = window;
541 		first = false;
542 	}
543 	if (i != sr->length) {
544 		return (DNS_R_EXTRADATA);
545 	}
546 	if (!allow_empty && first) {
547 		RETERR(DNS_R_FORMERR);
548 	}
549 	return (ISC_R_SUCCESS);
550 }
551 
552 static const char hexdigits[] = "0123456789abcdef";
553 static const char decdigits[] = "0123456789";
554 
555 #include "code.h"
556 
557 #define META	 0x0001
558 #define RESERVED 0x0002
559 
560 /***
561  *** Initialization
562  ***/
563 
564 void
565 dns_rdata_init(dns_rdata_t *rdata) {
566 	REQUIRE(rdata != NULL);
567 
568 	rdata->data = NULL;
569 	rdata->length = 0;
570 	rdata->rdclass = 0;
571 	rdata->type = 0;
572 	rdata->flags = 0;
573 	ISC_LINK_INIT(rdata, link);
574 	/* ISC_LIST_INIT(rdata->list); */
575 }
576 
577 void
578 dns_rdata_reset(dns_rdata_t *rdata) {
579 	REQUIRE(rdata != NULL);
580 
581 	REQUIRE(!ISC_LINK_LINKED(rdata, link));
582 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
583 
584 	rdata->data = NULL;
585 	rdata->length = 0;
586 	rdata->rdclass = 0;
587 	rdata->type = 0;
588 	rdata->flags = 0;
589 }
590 
591 /***
592  ***
593  ***/
594 
595 void
596 dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
597 	REQUIRE(src != NULL);
598 	REQUIRE(target != NULL);
599 
600 	REQUIRE(DNS_RDATA_INITIALIZED(target));
601 
602 	REQUIRE(DNS_RDATA_VALIDFLAGS(src));
603 	REQUIRE(DNS_RDATA_VALIDFLAGS(target));
604 
605 	target->data = src->data;
606 	target->length = src->length;
607 	target->rdclass = src->rdclass;
608 	target->type = src->type;
609 	target->flags = src->flags;
610 }
611 
612 /***
613  *** Comparisons
614  ***/
615 
616 int
617 dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
618 	int result = 0;
619 	bool use_default = false;
620 
621 	REQUIRE(rdata1 != NULL);
622 	REQUIRE(rdata2 != NULL);
623 	REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
624 	REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
625 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
626 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
627 
628 	if (rdata1->rdclass != rdata2->rdclass) {
629 		return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
630 	}
631 
632 	if (rdata1->type != rdata2->type) {
633 		return (rdata1->type < rdata2->type ? -1 : 1);
634 	}
635 
636 	COMPARESWITCH
637 
638 	if (use_default) {
639 		isc_region_t r1;
640 		isc_region_t r2;
641 
642 		dns_rdata_toregion(rdata1, &r1);
643 		dns_rdata_toregion(rdata2, &r2);
644 		result = isc_region_compare(&r1, &r2);
645 	}
646 	return (result);
647 }
648 
649 int
650 dns_rdata_casecompare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
651 	int result = 0;
652 	bool use_default = false;
653 
654 	REQUIRE(rdata1 != NULL);
655 	REQUIRE(rdata2 != NULL);
656 	REQUIRE(rdata1->length == 0 || rdata1->data != NULL);
657 	REQUIRE(rdata2->length == 0 || rdata2->data != NULL);
658 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
659 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
660 
661 	if (rdata1->rdclass != rdata2->rdclass) {
662 		return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
663 	}
664 
665 	if (rdata1->type != rdata2->type) {
666 		return (rdata1->type < rdata2->type ? -1 : 1);
667 	}
668 
669 	CASECOMPARESWITCH
670 
671 	if (use_default) {
672 		isc_region_t r1;
673 		isc_region_t r2;
674 
675 		dns_rdata_toregion(rdata1, &r1);
676 		dns_rdata_toregion(rdata2, &r2);
677 		result = isc_region_compare(&r1, &r2);
678 	}
679 	return (result);
680 }
681 
682 /***
683  *** Conversions
684  ***/
685 
686 void
687 dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
688 		     dns_rdatatype_t type, isc_region_t *r) {
689 	REQUIRE(rdata != NULL);
690 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
691 	REQUIRE(r != NULL);
692 
693 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
694 
695 	rdata->data = r->base;
696 	rdata->length = r->length;
697 	rdata->rdclass = rdclass;
698 	rdata->type = type;
699 	rdata->flags = 0;
700 }
701 
702 void
703 dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
704 	REQUIRE(rdata != NULL);
705 	REQUIRE(r != NULL);
706 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
707 
708 	r->base = rdata->data;
709 	r->length = rdata->length;
710 }
711 
712 isc_result_t
713 dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
714 		   dns_rdatatype_t type, isc_buffer_t *source,
715 		   dns_decompress_t *dctx, unsigned int options,
716 		   isc_buffer_t *target) {
717 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
718 	isc_region_t region;
719 	isc_buffer_t ss;
720 	isc_buffer_t st;
721 	bool use_default = false;
722 	uint32_t activelength;
723 	unsigned int length;
724 
725 	REQUIRE(dctx != NULL);
726 	if (rdata != NULL) {
727 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
728 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
729 	}
730 	REQUIRE(source != NULL);
731 	REQUIRE(target != NULL);
732 
733 	if (type == 0) {
734 		return (DNS_R_FORMERR);
735 	}
736 
737 	ss = *source;
738 	st = *target;
739 
740 	activelength = isc_buffer_activelength(source);
741 	INSIST(activelength < 65536);
742 
743 	FROMWIRESWITCH
744 
745 	if (use_default) {
746 		if (activelength > isc_buffer_availablelength(target)) {
747 			result = ISC_R_NOSPACE;
748 		} else {
749 			isc_buffer_putmem(target, isc_buffer_current(source),
750 					  activelength);
751 			isc_buffer_forward(source, activelength);
752 			result = ISC_R_SUCCESS;
753 		}
754 	}
755 
756 	/*
757 	 * Reject any rdata that expands out to more than DNS_RDATA_MAXLENGTH
758 	 * as we cannot transmit it.
759 	 */
760 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
761 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
762 		result = DNS_R_FORMERR;
763 	}
764 
765 	/*
766 	 * We should have consumed all of our buffer.
767 	 */
768 	if (result == ISC_R_SUCCESS && !buffer_empty(source)) {
769 		result = DNS_R_EXTRADATA;
770 	}
771 
772 	if (rdata != NULL && result == ISC_R_SUCCESS) {
773 		region.base = isc_buffer_used(&st);
774 		region.length = length;
775 		dns_rdata_fromregion(rdata, rdclass, type, &region);
776 	}
777 
778 	if (result != ISC_R_SUCCESS) {
779 		*source = ss;
780 		*target = st;
781 	}
782 	return (result);
783 }
784 
785 isc_result_t
786 dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
787 		 isc_buffer_t *target) {
788 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
789 	bool use_default = false;
790 	isc_region_t tr;
791 	isc_buffer_t st;
792 
793 	REQUIRE(rdata != NULL);
794 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
795 
796 	/*
797 	 * Some DynDNS meta-RRs have empty rdata.
798 	 */
799 	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
800 		INSIST(rdata->length == 0);
801 		return (ISC_R_SUCCESS);
802 	}
803 
804 	st = *target;
805 
806 	TOWIRESWITCH
807 
808 	if (use_default) {
809 		isc_buffer_availableregion(target, &tr);
810 		if (tr.length < rdata->length) {
811 			return (ISC_R_NOSPACE);
812 		}
813 		memmove(tr.base, rdata->data, rdata->length);
814 		isc_buffer_add(target, rdata->length);
815 		return (ISC_R_SUCCESS);
816 	}
817 	if (result != ISC_R_SUCCESS) {
818 		*target = st;
819 		INSIST(target->used < 65536);
820 		dns_compress_rollback(cctx, (uint16_t)target->used);
821 	}
822 	return (result);
823 }
824 
825 /*
826  * If the binary data in 'src' is valid uncompressed wire format
827  * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
828  * and copy the validated rdata to 'dest'.  Otherwise return an error.
829  */
830 static isc_result_t
831 rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
832 	       dns_rdatatype_t type) {
833 	dns_decompress_t dctx;
834 	isc_result_t result;
835 
836 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
837 	isc_buffer_setactive(src, isc_buffer_usedlength(src));
838 	result = dns_rdata_fromwire(NULL, rdclass, type, src, &dctx, 0, dest);
839 	dns_decompress_invalidate(&dctx);
840 
841 	return (result);
842 }
843 
844 static isc_result_t
845 unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
846 		 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) {
847 	isc_result_t result;
848 	isc_buffer_t *buf = NULL;
849 	isc_token_t token;
850 
851 	if (type == 0 || dns_rdatatype_ismeta(type)) {
852 		return (DNS_R_METATYPE);
853 	}
854 
855 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
856 				      false));
857 	if (token.value.as_ulong > 65535U) {
858 		return (ISC_R_RANGE);
859 	}
860 	isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
861 
862 	if (token.value.as_ulong != 0U) {
863 		result = isc_hex_tobuffer(lexer, buf,
864 					  (unsigned int)token.value.as_ulong);
865 		if (result != ISC_R_SUCCESS) {
866 			goto failure;
867 		}
868 		if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
869 			result = ISC_R_UNEXPECTEDEND;
870 			goto failure;
871 		}
872 	}
873 
874 	if (dns_rdatatype_isknown(type)) {
875 		result = rdata_validate(buf, target, rdclass, type);
876 	} else {
877 		isc_region_t r;
878 		isc_buffer_usedregion(buf, &r);
879 		result = isc_buffer_copyregion(target, &r);
880 	}
881 	if (result != ISC_R_SUCCESS) {
882 		goto failure;
883 	}
884 
885 	isc_buffer_free(&buf);
886 	return (ISC_R_SUCCESS);
887 
888 failure:
889 	isc_buffer_free(&buf);
890 	return (result);
891 }
892 
893 isc_result_t
894 dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
895 		   dns_rdatatype_t type, isc_lex_t *lexer,
896 		   const dns_name_t *origin, unsigned int options,
897 		   isc_mem_t *mctx, isc_buffer_t *target,
898 		   dns_rdatacallbacks_t *callbacks) {
899 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
900 	isc_region_t region;
901 	isc_buffer_t st;
902 	isc_token_t token;
903 	unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
904 				  ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
905 	char *name;
906 	unsigned long line;
907 	void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
908 	isc_result_t tresult;
909 	unsigned int length;
910 	bool unknown;
911 
912 	REQUIRE(origin == NULL || dns_name_isabsolute(origin));
913 	if (rdata != NULL) {
914 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
915 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
916 	}
917 	if (callbacks != NULL) {
918 		REQUIRE(callbacks->warn != NULL);
919 		REQUIRE(callbacks->error != NULL);
920 	}
921 
922 	st = *target;
923 
924 	if (callbacks != NULL) {
925 		callback = callbacks->error;
926 	} else {
927 		callback = default_fromtext_callback;
928 	}
929 
930 	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
931 					true);
932 	if (result != ISC_R_SUCCESS) {
933 		name = isc_lex_getsourcename(lexer);
934 		line = isc_lex_getsourceline(lexer);
935 		fromtext_error(callback, callbacks, name, line, NULL, result);
936 		return (result);
937 	}
938 
939 	unknown = false;
940 	if (token.type == isc_tokentype_string &&
941 	    strcmp(DNS_AS_STR(token), "\\#") == 0) {
942 		/*
943 		 * If this is a TXT record '\#' could be a escaped '#'.
944 		 * Look to see if the next token is a number and if so
945 		 * treat it as a unknown record format.
946 		 */
947 		if (type == dns_rdatatype_txt) {
948 			result = isc_lex_getmastertoken(
949 				lexer, &token, isc_tokentype_number, false);
950 			if (result == ISC_R_SUCCESS) {
951 				isc_lex_ungettoken(lexer, &token);
952 			}
953 		}
954 
955 		if (result == ISC_R_SUCCESS) {
956 			unknown = true;
957 			result = unknown_fromtext(rdclass, type, lexer, mctx,
958 						  target);
959 		} else {
960 			options |= DNS_RDATA_UNKNOWNESCAPE;
961 		}
962 	} else {
963 		isc_lex_ungettoken(lexer, &token);
964 	}
965 
966 	if (!unknown) {
967 		FROMTEXTSWITCH
968 
969 		/*
970 		 * Consume to end of line / file.
971 		 * If not at end of line initially set error code.
972 		 * Call callback via fromtext_error once if there was an error.
973 		 */
974 	}
975 	do {
976 		name = isc_lex_getsourcename(lexer);
977 		line = isc_lex_getsourceline(lexer);
978 		tresult = isc_lex_gettoken(lexer, lexoptions, &token);
979 		if (tresult != ISC_R_SUCCESS) {
980 			if (result == ISC_R_SUCCESS) {
981 				result = tresult;
982 			}
983 			if (callback != NULL) {
984 				fromtext_error(callback, callbacks, name, line,
985 					       NULL, result);
986 			}
987 			break;
988 		} else if (token.type != isc_tokentype_eol &&
989 			   token.type != isc_tokentype_eof) {
990 			if (result == ISC_R_SUCCESS) {
991 				result = DNS_R_EXTRATOKEN;
992 			}
993 			if (callback != NULL) {
994 				fromtext_error(callback, callbacks, name, line,
995 					       &token, result);
996 				callback = NULL;
997 			}
998 		} else if (result != ISC_R_SUCCESS && callback != NULL) {
999 			fromtext_error(callback, callbacks, name, line, &token,
1000 				       result);
1001 			break;
1002 		} else {
1003 			if (token.type == isc_tokentype_eof) {
1004 				fromtext_warneof(lexer, callbacks);
1005 			}
1006 			break;
1007 		}
1008 	} while (1);
1009 
1010 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
1011 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
1012 		result = ISC_R_NOSPACE;
1013 	}
1014 
1015 	if (rdata != NULL && result == ISC_R_SUCCESS) {
1016 		region.base = isc_buffer_used(&st);
1017 		region.length = length;
1018 		dns_rdata_fromregion(rdata, rdclass, type, &region);
1019 	}
1020 	if (result != ISC_R_SUCCESS) {
1021 		*target = st;
1022 	}
1023 	return (result);
1024 }
1025 
1026 static isc_result_t
1027 unknown_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1028 	       isc_buffer_t *target) {
1029 	isc_result_t result;
1030 	char buf[sizeof("65535")];
1031 	isc_region_t sr;
1032 
1033 	strlcpy(buf, "\\# ", sizeof(buf));
1034 	result = str_totext(buf, target);
1035 	if (result != ISC_R_SUCCESS) {
1036 		return (result);
1037 	}
1038 
1039 	dns_rdata_toregion(rdata, &sr);
1040 	INSIST(sr.length < 65536);
1041 	snprintf(buf, sizeof(buf), "%u", sr.length);
1042 	result = str_totext(buf, target);
1043 	if (result != ISC_R_SUCCESS) {
1044 		return (result);
1045 	}
1046 
1047 	if (sr.length != 0U) {
1048 		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1049 			result = str_totext(" ( ", target);
1050 		} else {
1051 			result = str_totext(" ", target);
1052 		}
1053 
1054 		if (result != ISC_R_SUCCESS) {
1055 			return (result);
1056 		}
1057 
1058 		if (tctx->width == 0) { /* No splitting */
1059 			result = isc_hex_totext(&sr, 0, "", target);
1060 		} else {
1061 			result = isc_hex_totext(&sr, tctx->width - 2,
1062 						tctx->linebreak, target);
1063 		}
1064 		if (result == ISC_R_SUCCESS &&
1065 		    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1066 			result = str_totext(" )", target);
1067 		}
1068 	}
1069 	return (result);
1070 }
1071 
1072 static isc_result_t
1073 rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
1074 	     isc_buffer_t *target) {
1075 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
1076 	bool use_default = false;
1077 	unsigned int cur;
1078 
1079 	REQUIRE(rdata != NULL);
1080 	REQUIRE(tctx->origin == NULL || dns_name_isabsolute(tctx->origin));
1081 
1082 	/*
1083 	 * Some DynDNS meta-RRs have empty rdata.
1084 	 */
1085 	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
1086 		INSIST(rdata->length == 0);
1087 		return (ISC_R_SUCCESS);
1088 	}
1089 
1090 	if ((tctx->flags & DNS_STYLEFLAG_UNKNOWNFORMAT) != 0) {
1091 		return (unknown_totext(rdata, tctx, target));
1092 	}
1093 
1094 	cur = isc_buffer_usedlength(target);
1095 
1096 	TOTEXTSWITCH
1097 
1098 	if (use_default || (result == ISC_R_NOTIMPLEMENTED)) {
1099 		unsigned int u = isc_buffer_usedlength(target);
1100 
1101 		INSIST(u >= cur);
1102 		isc_buffer_subtract(target, u - cur);
1103 		result = unknown_totext(rdata, tctx, target);
1104 	}
1105 
1106 	return (result);
1107 }
1108 
1109 isc_result_t
1110 dns_rdata_totext(dns_rdata_t *rdata, const dns_name_t *origin,
1111 		 isc_buffer_t *target) {
1112 	dns_rdata_textctx_t tctx;
1113 
1114 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1115 
1116 	/*
1117 	 * Set up formatting options for single-line output.
1118 	 */
1119 	tctx.origin = origin;
1120 	tctx.flags = 0;
1121 	tctx.width = 60;
1122 	tctx.linebreak = " ";
1123 	return (rdata_totext(rdata, &tctx, target));
1124 }
1125 
1126 isc_result_t
1127 dns_rdata_tofmttext(dns_rdata_t *rdata, const dns_name_t *origin,
1128 		    dns_masterstyle_flags_t flags, unsigned int width,
1129 		    unsigned int split_width, const char *linebreak,
1130 		    isc_buffer_t *target) {
1131 	dns_rdata_textctx_t tctx;
1132 
1133 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1134 
1135 	/*
1136 	 * Set up formatting options for formatted output.
1137 	 */
1138 	tctx.origin = origin;
1139 	tctx.flags = flags;
1140 	if (split_width == 0xffffffff) {
1141 		tctx.width = width;
1142 	} else {
1143 		tctx.width = split_width;
1144 	}
1145 
1146 	if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
1147 		tctx.linebreak = linebreak;
1148 	} else {
1149 		if (split_width == 0xffffffff) {
1150 			tctx.width = 60; /* Used for hex word length only. */
1151 		}
1152 		tctx.linebreak = " ";
1153 	}
1154 	return (rdata_totext(rdata, &tctx, target));
1155 }
1156 
1157 isc_result_t
1158 dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
1159 		     dns_rdatatype_t type, void *source, isc_buffer_t *target) {
1160 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
1161 	isc_buffer_t st;
1162 	isc_region_t region;
1163 	bool use_default = false;
1164 	unsigned int length;
1165 
1166 	REQUIRE(source != NULL);
1167 	if (rdata != NULL) {
1168 		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
1169 		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1170 	}
1171 
1172 	st = *target;
1173 
1174 	FROMSTRUCTSWITCH
1175 
1176 	if (use_default) {
1177 		(void)NULL;
1178 	}
1179 
1180 	length = isc_buffer_usedlength(target) - isc_buffer_usedlength(&st);
1181 	if (result == ISC_R_SUCCESS && length > DNS_RDATA_MAXLENGTH) {
1182 		result = ISC_R_NOSPACE;
1183 	}
1184 
1185 	if (rdata != NULL && result == ISC_R_SUCCESS) {
1186 		region.base = isc_buffer_used(&st);
1187 		region.length = length;
1188 		dns_rdata_fromregion(rdata, rdclass, type, &region);
1189 	}
1190 	if (result != ISC_R_SUCCESS) {
1191 		*target = st;
1192 	}
1193 	return (result);
1194 }
1195 
1196 isc_result_t
1197 dns_rdata_tostruct(const dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
1198 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
1199 	bool use_default = false;
1200 
1201 	REQUIRE(rdata != NULL);
1202 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1203 
1204 	TOSTRUCTSWITCH
1205 
1206 	if (use_default) {
1207 		(void)NULL;
1208 	}
1209 
1210 	return (result);
1211 }
1212 
1213 void
1214 dns_rdata_freestruct(void *source) {
1215 	dns_rdatacommon_t *common = source;
1216 	REQUIRE(common != NULL);
1217 
1218 	FREESTRUCTSWITCH
1219 }
1220 
1221 isc_result_t
1222 dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
1223 			 void *arg) {
1224 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
1225 	bool use_default = false;
1226 
1227 	/*
1228 	 * Call 'add' for each name and type from 'rdata' which is subject to
1229 	 * additional section processing.
1230 	 */
1231 
1232 	REQUIRE(rdata != NULL);
1233 	REQUIRE(add != NULL);
1234 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1235 
1236 	ADDITIONALDATASWITCH
1237 
1238 	/* No additional processing for unknown types */
1239 	if (use_default) {
1240 		result = ISC_R_SUCCESS;
1241 	}
1242 
1243 	return (result);
1244 }
1245 
1246 isc_result_t
1247 dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
1248 	isc_result_t result = ISC_R_NOTIMPLEMENTED;
1249 	bool use_default = false;
1250 	isc_region_t r;
1251 
1252 	/*
1253 	 * Send 'rdata' in DNSSEC canonical form to 'digest'.
1254 	 */
1255 
1256 	REQUIRE(rdata != NULL);
1257 	REQUIRE(digest != NULL);
1258 	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
1259 
1260 	DIGESTSWITCH
1261 
1262 	if (use_default) {
1263 		dns_rdata_toregion(rdata, &r);
1264 		result = (digest)(arg, &r);
1265 	}
1266 
1267 	return (result);
1268 }
1269 
1270 bool
1271 dns_rdata_checkowner(const dns_name_t *name, dns_rdataclass_t rdclass,
1272 		     dns_rdatatype_t type, bool wildcard) {
1273 	bool result;
1274 
1275 	CHECKOWNERSWITCH
1276 	return (result);
1277 }
1278 
1279 bool
1280 dns_rdata_checknames(dns_rdata_t *rdata, const dns_name_t *owner,
1281 		     dns_name_t *bad) {
1282 	bool result;
1283 
1284 	CHECKNAMESSWITCH
1285 	return (result);
1286 }
1287 
1288 unsigned int
1289 dns_rdatatype_attributes(dns_rdatatype_t type) {
1290 	RDATATYPE_ATTRIBUTE_SW
1291 	if (type >= (dns_rdatatype_t)128 && type <= (dns_rdatatype_t)255) {
1292 		return (DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META);
1293 	}
1294 	return (DNS_RDATATYPEATTR_UNKNOWN);
1295 }
1296 
1297 isc_result_t
1298 dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
1299 	unsigned int hash;
1300 	unsigned int n;
1301 	unsigned char a, b;
1302 
1303 	n = source->length;
1304 
1305 	if (n == 0) {
1306 		return (DNS_R_UNKNOWN);
1307 	}
1308 
1309 	a = tolower((unsigned char)source->base[0]);
1310 	b = tolower((unsigned char)source->base[n - 1]);
1311 
1312 	hash = ((a + n) * b) % 256;
1313 
1314 	/*
1315 	 * This switch block is inlined via \#define, and will use "return"
1316 	 * to return a result to the caller if it is a valid (known)
1317 	 * rdatatype name.
1318 	 */
1319 	RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
1320 
1321 	if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
1322 	    strncasecmp("type", source->base, 4) == 0)
1323 	{
1324 		char buf[sizeof("65000")];
1325 		char *endp;
1326 		unsigned int val;
1327 
1328 		/*
1329 		 * source->base is not required to be NUL terminated.
1330 		 * Copy up to remaining bytes and NUL terminate.
1331 		 */
1332 		snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 4),
1333 			 source->base + 4);
1334 		val = strtoul(buf, &endp, 10);
1335 		if (*endp == '\0' && val <= 0xffff) {
1336 			*typep = (dns_rdatatype_t)val;
1337 			return (ISC_R_SUCCESS);
1338 		}
1339 	}
1340 
1341 	return (DNS_R_UNKNOWN);
1342 }
1343 
1344 isc_result_t
1345 dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
1346 	RDATATYPE_TOTEXT_SW
1347 
1348 	return (dns_rdatatype_tounknowntext(type, target));
1349 }
1350 
1351 isc_result_t
1352 dns_rdatatype_tounknowntext(dns_rdatatype_t type, isc_buffer_t *target) {
1353 	char buf[sizeof("TYPE65535")];
1354 
1355 	snprintf(buf, sizeof(buf), "TYPE%u", type);
1356 	return (str_totext(buf, target));
1357 }
1358 
1359 void
1360 dns_rdatatype_format(dns_rdatatype_t rdtype, char *array, unsigned int size) {
1361 	isc_result_t result;
1362 	isc_buffer_t buf;
1363 
1364 	if (size == 0U) {
1365 		return;
1366 	}
1367 
1368 	isc_buffer_init(&buf, array, size);
1369 	result = dns_rdatatype_totext(rdtype, &buf);
1370 	/*
1371 	 * Null terminate.
1372 	 */
1373 	if (result == ISC_R_SUCCESS) {
1374 		if (isc_buffer_availablelength(&buf) >= 1) {
1375 			isc_buffer_putuint8(&buf, 0);
1376 		} else {
1377 			result = ISC_R_NOSPACE;
1378 		}
1379 	}
1380 	if (result != ISC_R_SUCCESS) {
1381 		strlcpy(array, "<unknown>", size);
1382 	}
1383 }
1384 
1385 /*
1386  * Private function.
1387  */
1388 
1389 static unsigned int
1390 name_length(const dns_name_t *name) {
1391 	return (name->length);
1392 }
1393 
1394 static isc_result_t
1395 txt_totext(isc_region_t *source, bool quote, isc_buffer_t *target) {
1396 	unsigned int tl;
1397 	unsigned int n;
1398 	unsigned char *sp;
1399 	char *tp;
1400 	isc_region_t region;
1401 
1402 	isc_buffer_availableregion(target, &region);
1403 	sp = source->base;
1404 	tp = (char *)region.base;
1405 	tl = region.length;
1406 
1407 	n = *sp++;
1408 
1409 	REQUIRE(n + 1 <= source->length);
1410 	if (n == 0U) {
1411 		REQUIRE(quote);
1412 	}
1413 
1414 	if (quote) {
1415 		if (tl < 1) {
1416 			return (ISC_R_NOSPACE);
1417 		}
1418 		*tp++ = '"';
1419 		tl--;
1420 	}
1421 	while (n--) {
1422 		/*
1423 		 * \DDD space (0x20) if not quoting.
1424 		 */
1425 		if (*sp < (quote ? 0x20 : 0x21) || *sp >= 0x7f) {
1426 			if (tl < 4) {
1427 				return (ISC_R_NOSPACE);
1428 			}
1429 			*tp++ = 0x5c;
1430 			*tp++ = 0x30 + ((*sp / 100) % 10);
1431 			*tp++ = 0x30 + ((*sp / 10) % 10);
1432 			*tp++ = 0x30 + (*sp % 10);
1433 			sp++;
1434 			tl -= 4;
1435 			continue;
1436 		}
1437 		/*
1438 		 * Escape double quote and backslash.  If we are not
1439 		 * enclosing the string in double quotes also escape
1440 		 * at sign and semicolon.
1441 		 */
1442 		if (*sp == 0x22 || *sp == 0x5c ||
1443 		    (!quote && (*sp == 0x40 || *sp == 0x3b))) {
1444 			if (tl < 2) {
1445 				return (ISC_R_NOSPACE);
1446 			}
1447 			*tp++ = '\\';
1448 			tl--;
1449 		}
1450 		if (tl < 1) {
1451 			return (ISC_R_NOSPACE);
1452 		}
1453 		*tp++ = *sp++;
1454 		tl--;
1455 	}
1456 	if (quote) {
1457 		if (tl < 1) {
1458 			return (ISC_R_NOSPACE);
1459 		}
1460 		*tp++ = '"';
1461 		tl--;
1462 		POST(tl);
1463 	}
1464 	isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1465 	isc_region_consume(source, *source->base + 1);
1466 	return (ISC_R_SUCCESS);
1467 }
1468 
1469 static isc_result_t
1470 txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1471 	isc_region_t tregion;
1472 	bool escape;
1473 	unsigned int n, nrem;
1474 	char *s;
1475 	unsigned char *t;
1476 	int d;
1477 	int c;
1478 
1479 	isc_buffer_availableregion(target, &tregion);
1480 	s = source->base;
1481 	n = source->length;
1482 	t = tregion.base;
1483 	nrem = tregion.length;
1484 	escape = false;
1485 	if (nrem < 1) {
1486 		return (ISC_R_NOSPACE);
1487 	}
1488 	/*
1489 	 * Length byte.
1490 	 */
1491 	nrem--;
1492 	t++;
1493 	/*
1494 	 * Maximum text string length.
1495 	 */
1496 	if (nrem > 255) {
1497 		nrem = 255;
1498 	}
1499 	while (n-- != 0) {
1500 		c = (*s++) & 0xff;
1501 		if (escape && (d = decvalue((char)c)) != -1) {
1502 			c = d;
1503 			if (n == 0) {
1504 				return (DNS_R_SYNTAX);
1505 			}
1506 			n--;
1507 			if ((d = decvalue(*s++)) != -1) {
1508 				c = c * 10 + d;
1509 			} else {
1510 				return (DNS_R_SYNTAX);
1511 			}
1512 			if (n == 0) {
1513 				return (DNS_R_SYNTAX);
1514 			}
1515 			n--;
1516 			if ((d = decvalue(*s++)) != -1) {
1517 				c = c * 10 + d;
1518 			} else {
1519 				return (DNS_R_SYNTAX);
1520 			}
1521 			if (c > 255) {
1522 				return (DNS_R_SYNTAX);
1523 			}
1524 		} else if (!escape && c == '\\') {
1525 			escape = true;
1526 			continue;
1527 		}
1528 		escape = false;
1529 		if (nrem == 0) {
1530 			return ((tregion.length <= 256U) ? ISC_R_NOSPACE
1531 							 : DNS_R_SYNTAX);
1532 		}
1533 		*t++ = c;
1534 		nrem--;
1535 	}
1536 	if (escape) {
1537 		return (DNS_R_SYNTAX);
1538 	}
1539 	*tregion.base = (unsigned char)(t - tregion.base - 1);
1540 	isc_buffer_add(target, *tregion.base + 1);
1541 	return (ISC_R_SUCCESS);
1542 }
1543 
1544 static isc_result_t
1545 txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
1546 	unsigned int n;
1547 	isc_region_t sregion;
1548 	isc_region_t tregion;
1549 
1550 	isc_buffer_activeregion(source, &sregion);
1551 	if (sregion.length == 0) {
1552 		return (ISC_R_UNEXPECTEDEND);
1553 	}
1554 	n = *sregion.base + 1;
1555 	if (n > sregion.length) {
1556 		return (ISC_R_UNEXPECTEDEND);
1557 	}
1558 
1559 	isc_buffer_availableregion(target, &tregion);
1560 	if (n > tregion.length) {
1561 		return (ISC_R_NOSPACE);
1562 	}
1563 
1564 	if (tregion.base != sregion.base) {
1565 		memmove(tregion.base, sregion.base, n);
1566 	}
1567 	isc_buffer_forward(source, n);
1568 	isc_buffer_add(target, n);
1569 	return (ISC_R_SUCCESS);
1570 }
1571 
1572 /*
1573  * Conversion of TXT-like rdata fields without length limits.
1574  */
1575 static isc_result_t
1576 multitxt_totext(isc_region_t *source, isc_buffer_t *target) {
1577 	unsigned int tl;
1578 	unsigned int n0, n;
1579 	unsigned char *sp;
1580 	char *tp;
1581 	isc_region_t region;
1582 
1583 	isc_buffer_availableregion(target, &region);
1584 	sp = source->base;
1585 	tp = (char *)region.base;
1586 	tl = region.length;
1587 
1588 	if (tl < 1) {
1589 		return (ISC_R_NOSPACE);
1590 	}
1591 	*tp++ = '"';
1592 	tl--;
1593 	do {
1594 		n = source->length;
1595 		n0 = source->length - 1;
1596 
1597 		while (n--) {
1598 			if (*sp < 0x20 || *sp >= 0x7f) {
1599 				if (tl < 4) {
1600 					return (ISC_R_NOSPACE);
1601 				}
1602 				*tp++ = 0x5c;
1603 				*tp++ = 0x30 + ((*sp / 100) % 10);
1604 				*tp++ = 0x30 + ((*sp / 10) % 10);
1605 				*tp++ = 0x30 + (*sp % 10);
1606 				sp++;
1607 				tl -= 4;
1608 				continue;
1609 			}
1610 			/* double quote, backslash */
1611 			if (*sp == 0x22 || *sp == 0x5c) {
1612 				if (tl < 2) {
1613 					return (ISC_R_NOSPACE);
1614 				}
1615 				*tp++ = '\\';
1616 				tl--;
1617 			}
1618 			if (tl < 1) {
1619 				return (ISC_R_NOSPACE);
1620 			}
1621 			*tp++ = *sp++;
1622 			tl--;
1623 		}
1624 		isc_region_consume(source, n0 + 1);
1625 	} while (source->length != 0);
1626 	if (tl < 1) {
1627 		return (ISC_R_NOSPACE);
1628 	}
1629 	*tp++ = '"';
1630 	tl--;
1631 	POST(tl);
1632 	isc_buffer_add(target, (unsigned int)(tp - (char *)region.base));
1633 	return (ISC_R_SUCCESS);
1634 }
1635 
1636 static isc_result_t
1637 multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1638 	isc_region_t tregion;
1639 	bool escape;
1640 	unsigned int n, nrem;
1641 	char *s;
1642 	unsigned char *t0, *t;
1643 	int d;
1644 	int c;
1645 
1646 	s = source->base;
1647 	n = source->length;
1648 	escape = false;
1649 
1650 	do {
1651 		isc_buffer_availableregion(target, &tregion);
1652 		t0 = t = tregion.base;
1653 		nrem = tregion.length;
1654 		if (nrem < 1) {
1655 			return (ISC_R_NOSPACE);
1656 		}
1657 
1658 		while (n != 0) {
1659 			--n;
1660 			c = (*s++) & 0xff;
1661 			if (escape && (d = decvalue((char)c)) != -1) {
1662 				c = d;
1663 				if (n == 0) {
1664 					return (DNS_R_SYNTAX);
1665 				}
1666 				n--;
1667 				if ((d = decvalue(*s++)) != -1) {
1668 					c = c * 10 + d;
1669 				} else {
1670 					return (DNS_R_SYNTAX);
1671 				}
1672 				if (n == 0) {
1673 					return (DNS_R_SYNTAX);
1674 				}
1675 				n--;
1676 				if ((d = decvalue(*s++)) != -1) {
1677 					c = c * 10 + d;
1678 				} else {
1679 					return (DNS_R_SYNTAX);
1680 				}
1681 				if (c > 255) {
1682 					return (DNS_R_SYNTAX);
1683 				}
1684 			} else if (!escape && c == '\\') {
1685 				escape = true;
1686 				continue;
1687 			}
1688 			escape = false;
1689 			*t++ = c;
1690 			nrem--;
1691 			if (nrem == 0) {
1692 				break;
1693 			}
1694 		}
1695 		if (escape) {
1696 			return (DNS_R_SYNTAX);
1697 		}
1698 
1699 		isc_buffer_add(target, (unsigned int)(t - t0));
1700 	} while (n != 0);
1701 	return (ISC_R_SUCCESS);
1702 }
1703 
1704 static bool
1705 name_prefix(dns_name_t *name, const dns_name_t *origin, dns_name_t *target) {
1706 	int l1, l2;
1707 
1708 	if (origin == NULL) {
1709 		goto return_false;
1710 	}
1711 
1712 	if (dns_name_compare(origin, dns_rootname) == 0) {
1713 		goto return_false;
1714 	}
1715 
1716 	if (!dns_name_issubdomain(name, origin)) {
1717 		goto return_false;
1718 	}
1719 
1720 	l1 = dns_name_countlabels(name);
1721 	l2 = dns_name_countlabels(origin);
1722 
1723 	if (l1 == l2) {
1724 		goto return_false;
1725 	}
1726 
1727 	/* Master files should be case preserving. */
1728 	dns_name_getlabelsequence(name, l1 - l2, l2, target);
1729 	if (!dns_name_caseequal(origin, target)) {
1730 		goto return_false;
1731 	}
1732 
1733 	dns_name_getlabelsequence(name, 0, l1 - l2, target);
1734 	return (true);
1735 
1736 return_false:
1737 	*target = *name;
1738 	return (false);
1739 }
1740 
1741 static isc_result_t
1742 str_totext(const char *source, isc_buffer_t *target) {
1743 	unsigned int l;
1744 	isc_region_t region;
1745 
1746 	isc_buffer_availableregion(target, &region);
1747 	l = strlen(source);
1748 
1749 	if (l > region.length) {
1750 		return (ISC_R_NOSPACE);
1751 	}
1752 
1753 	memmove(region.base, source, l);
1754 	isc_buffer_add(target, l);
1755 	return (ISC_R_SUCCESS);
1756 }
1757 
1758 static isc_result_t
1759 inet_totext(int af, uint32_t flags, isc_region_t *src, isc_buffer_t *target) {
1760 	char tmpbuf[64];
1761 
1762 	/* Note - inet_ntop doesn't do size checking on its input. */
1763 	if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) {
1764 		return (ISC_R_NOSPACE);
1765 	}
1766 	if (strlen(tmpbuf) > isc_buffer_availablelength(target)) {
1767 		return (ISC_R_NOSPACE);
1768 	}
1769 	isc_buffer_putstr(target, tmpbuf);
1770 
1771 	/*
1772 	 * An IPv6 address ending in "::" breaks YAML
1773 	 * parsing, so append 0 in that case.
1774 	 */
1775 	if (af == AF_INET6 && (flags & DNS_STYLEFLAG_YAML) != 0) {
1776 		isc_region_t tr;
1777 		isc_buffer_usedregion(target, &tr);
1778 		if (tr.base[tr.length - 1] == ':') {
1779 			if (isc_buffer_availablelength(target) == 0) {
1780 				return (ISC_R_NOSPACE);
1781 			}
1782 			isc_buffer_putmem(target, (const unsigned char *)"0",
1783 					  1);
1784 		}
1785 	}
1786 
1787 	return (ISC_R_SUCCESS);
1788 }
1789 
1790 static bool
1791 buffer_empty(isc_buffer_t *source) {
1792 	return ((source->current == source->active) ? true : false);
1793 }
1794 
1795 static void
1796 buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
1797 	isc_buffer_init(buffer, region->base, region->length);
1798 	isc_buffer_add(buffer, region->length);
1799 	isc_buffer_setactive(buffer, region->length);
1800 }
1801 
1802 static isc_result_t
1803 uint32_tobuffer(uint32_t value, isc_buffer_t *target) {
1804 	isc_region_t region;
1805 
1806 	isc_buffer_availableregion(target, &region);
1807 	if (region.length < 4) {
1808 		return (ISC_R_NOSPACE);
1809 	}
1810 	isc_buffer_putuint32(target, value);
1811 	return (ISC_R_SUCCESS);
1812 }
1813 
1814 static isc_result_t
1815 uint16_tobuffer(uint32_t value, isc_buffer_t *target) {
1816 	isc_region_t region;
1817 
1818 	if (value > 0xffff) {
1819 		return (ISC_R_RANGE);
1820 	}
1821 	isc_buffer_availableregion(target, &region);
1822 	if (region.length < 2) {
1823 		return (ISC_R_NOSPACE);
1824 	}
1825 	isc_buffer_putuint16(target, (uint16_t)value);
1826 	return (ISC_R_SUCCESS);
1827 }
1828 
1829 static isc_result_t
1830 uint8_tobuffer(uint32_t value, isc_buffer_t *target) {
1831 	isc_region_t region;
1832 
1833 	if (value > 0xff) {
1834 		return (ISC_R_RANGE);
1835 	}
1836 	isc_buffer_availableregion(target, &region);
1837 	if (region.length < 1) {
1838 		return (ISC_R_NOSPACE);
1839 	}
1840 	isc_buffer_putuint8(target, (uint8_t)value);
1841 	return (ISC_R_SUCCESS);
1842 }
1843 
1844 static isc_result_t
1845 name_tobuffer(const dns_name_t *name, isc_buffer_t *target) {
1846 	isc_region_t r;
1847 	dns_name_toregion(name, &r);
1848 	return (isc_buffer_copyregion(target, &r));
1849 }
1850 
1851 static uint32_t
1852 uint32_fromregion(isc_region_t *region) {
1853 	uint32_t value;
1854 
1855 	REQUIRE(region->length >= 4);
1856 	value = (uint32_t)region->base[0] << 24;
1857 	value |= (uint32_t)region->base[1] << 16;
1858 	value |= (uint32_t)region->base[2] << 8;
1859 	value |= (uint32_t)region->base[3];
1860 	return (value);
1861 }
1862 
1863 static uint16_t
1864 uint16_consume_fromregion(isc_region_t *region) {
1865 	uint16_t r = uint16_fromregion(region);
1866 
1867 	isc_region_consume(region, 2);
1868 	return (r);
1869 }
1870 
1871 static uint16_t
1872 uint16_fromregion(isc_region_t *region) {
1873 	REQUIRE(region->length >= 2);
1874 
1875 	return ((region->base[0] << 8) | region->base[1]);
1876 }
1877 
1878 static uint8_t
1879 uint8_fromregion(isc_region_t *region) {
1880 	REQUIRE(region->length >= 1);
1881 
1882 	return (region->base[0]);
1883 }
1884 
1885 static uint8_t
1886 uint8_consume_fromregion(isc_region_t *region) {
1887 	uint8_t r = uint8_fromregion(region);
1888 
1889 	isc_region_consume(region, 1);
1890 	return (r);
1891 }
1892 
1893 static isc_result_t
1894 mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
1895 	isc_region_t tr;
1896 
1897 	if (length == 0U) {
1898 		return (ISC_R_SUCCESS);
1899 	}
1900 
1901 	isc_buffer_availableregion(target, &tr);
1902 	if (length > tr.length) {
1903 		return (ISC_R_NOSPACE);
1904 	}
1905 	if (tr.base != base) {
1906 		memmove(tr.base, base, length);
1907 	}
1908 	isc_buffer_add(target, length);
1909 	return (ISC_R_SUCCESS);
1910 }
1911 
1912 static int
1913 hexvalue(char value) {
1914 	const char *s;
1915 	unsigned char c;
1916 
1917 	c = (unsigned char)value;
1918 
1919 	if (!isascii(c)) {
1920 		return (-1);
1921 	}
1922 	if (isupper(c)) {
1923 		c = tolower(c);
1924 	}
1925 	if ((s = strchr(hexdigits, c)) == NULL) {
1926 		return (-1);
1927 	}
1928 	return ((int)(s - hexdigits));
1929 }
1930 
1931 static int
1932 decvalue(char value) {
1933 	const char *s;
1934 
1935 	/*
1936 	 * isascii() is valid for full range of int values, no need to
1937 	 * mask or cast.
1938 	 */
1939 	if (!isascii(value)) {
1940 		return (-1);
1941 	}
1942 	if ((s = strchr(decdigits, value)) == NULL) {
1943 		return (-1);
1944 	}
1945 	return ((int)(s - decdigits));
1946 }
1947 
1948 static void
1949 default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
1950 			  ...) {
1951 	va_list ap;
1952 
1953 	UNUSED(callbacks);
1954 
1955 	va_start(ap, fmt);
1956 	vfprintf(stderr, fmt, ap);
1957 	va_end(ap);
1958 	fprintf(stderr, "\n");
1959 }
1960 
1961 static void
1962 fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
1963 	if (isc_lex_isfile(lexer) && callbacks != NULL) {
1964 		const char *name = isc_lex_getsourcename(lexer);
1965 		if (name == NULL) {
1966 			name = "UNKNOWN";
1967 		}
1968 		(*callbacks->warn)(callbacks,
1969 				   "%s:%lu: file does not end with newline",
1970 				   name, isc_lex_getsourceline(lexer));
1971 	}
1972 }
1973 
1974 static void
1975 warn_badmx(isc_token_t *token, isc_lex_t *lexer,
1976 	   dns_rdatacallbacks_t *callbacks) {
1977 	const char *file;
1978 	unsigned long line;
1979 
1980 	if (lexer != NULL) {
1981 		file = isc_lex_getsourcename(lexer);
1982 		line = isc_lex_getsourceline(lexer);
1983 		(*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", file,
1984 				   line, DNS_AS_STR(*token),
1985 				   dns_result_totext(DNS_R_MXISADDRESS));
1986 	}
1987 }
1988 
1989 static void
1990 warn_badname(const dns_name_t *name, isc_lex_t *lexer,
1991 	     dns_rdatacallbacks_t *callbacks) {
1992 	const char *file;
1993 	unsigned long line;
1994 	char namebuf[DNS_NAME_FORMATSIZE];
1995 
1996 	if (lexer != NULL) {
1997 		file = isc_lex_getsourcename(lexer);
1998 		line = isc_lex_getsourceline(lexer);
1999 		dns_name_format(name, namebuf, sizeof(namebuf));
2000 		(*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", file,
2001 				   line, namebuf,
2002 				   dns_result_totext(DNS_R_BADNAME));
2003 	}
2004 }
2005 
2006 static void
2007 fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
2008 	       dns_rdatacallbacks_t *callbacks, const char *name,
2009 	       unsigned long line, isc_token_t *token, isc_result_t result) {
2010 	if (name == NULL) {
2011 		name = "UNKNOWN";
2012 	}
2013 
2014 	if (token != NULL) {
2015 		switch (token->type) {
2016 		case isc_tokentype_eol:
2017 			(*callback)(callbacks, "%s: %s:%lu: near eol: %s",
2018 				    "dns_rdata_fromtext", name, line,
2019 				    dns_result_totext(result));
2020 			break;
2021 		case isc_tokentype_eof:
2022 			(*callback)(callbacks, "%s: %s:%lu: near eof: %s",
2023 				    "dns_rdata_fromtext", name, line,
2024 				    dns_result_totext(result));
2025 			break;
2026 		case isc_tokentype_number:
2027 			(*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
2028 				    "dns_rdata_fromtext", name, line,
2029 				    token->value.as_ulong,
2030 				    dns_result_totext(result));
2031 			break;
2032 		case isc_tokentype_string:
2033 		case isc_tokentype_qstring:
2034 			(*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
2035 				    "dns_rdata_fromtext", name, line,
2036 				    DNS_AS_STR(*token),
2037 				    dns_result_totext(result));
2038 			break;
2039 		default:
2040 			(*callback)(callbacks, "%s: %s:%lu: %s",
2041 				    "dns_rdata_fromtext", name, line,
2042 				    dns_result_totext(result));
2043 			break;
2044 		}
2045 	} else {
2046 		(*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", name,
2047 			    line, dns_result_totext(result));
2048 	}
2049 }
2050 
2051 dns_rdatatype_t
2052 dns_rdata_covers(dns_rdata_t *rdata) {
2053 	if (rdata->type == dns_rdatatype_rrsig) {
2054 		return (covers_rrsig(rdata));
2055 	}
2056 	return (covers_sig(rdata));
2057 }
2058 
2059 bool
2060 dns_rdatatype_ismeta(dns_rdatatype_t type) {
2061 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0) {
2062 		return (true);
2063 	}
2064 	return (false);
2065 }
2066 
2067 bool
2068 dns_rdatatype_issingleton(dns_rdatatype_t type) {
2069 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) != 0)
2070 	{
2071 		return (true);
2072 	}
2073 	return (false);
2074 }
2075 
2076 bool
2077 dns_rdatatype_notquestion(dns_rdatatype_t type) {
2078 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION) !=
2079 	    0) {
2080 		return (true);
2081 	}
2082 	return (false);
2083 }
2084 
2085 bool
2086 dns_rdatatype_questiononly(dns_rdatatype_t type) {
2087 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY) !=
2088 	    0) {
2089 		return (true);
2090 	}
2091 	return (false);
2092 }
2093 
2094 bool
2095 dns_rdatatype_atcname(dns_rdatatype_t type) {
2096 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATCNAME) != 0) {
2097 		return (true);
2098 	}
2099 	return (false);
2100 }
2101 
2102 bool
2103 dns_rdatatype_atparent(dns_rdatatype_t type) {
2104 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
2105 	{
2106 		return (true);
2107 	}
2108 	return (false);
2109 }
2110 
2111 bool
2112 dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
2113 	if (rdclass == dns_rdataclass_reserved0 ||
2114 	    rdclass == dns_rdataclass_none || rdclass == dns_rdataclass_any)
2115 	{
2116 		return (true);
2117 	}
2118 
2119 	return (false); /* Assume it is not a meta class. */
2120 }
2121 
2122 bool
2123 dns_rdatatype_isdnssec(dns_rdatatype_t type) {
2124 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0) {
2125 		return (true);
2126 	}
2127 	return (false);
2128 }
2129 
2130 bool
2131 dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
2132 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ZONECUTAUTH) !=
2133 	    0) {
2134 		return (true);
2135 	}
2136 	return (false);
2137 }
2138 
2139 bool
2140 dns_rdatatype_isknown(dns_rdatatype_t type) {
2141 	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) == 0) {
2142 		return (true);
2143 	}
2144 	return (false);
2145 }
2146 
2147 void
2148 dns_rdata_exists(dns_rdata_t *rdata, dns_rdatatype_t type) {
2149 	REQUIRE(rdata != NULL);
2150 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2151 
2152 	rdata->data = NULL;
2153 	rdata->length = 0;
2154 	rdata->flags = DNS_RDATA_UPDATE;
2155 	rdata->type = type;
2156 	rdata->rdclass = dns_rdataclass_any;
2157 }
2158 
2159 void
2160 dns_rdata_notexist(dns_rdata_t *rdata, dns_rdatatype_t type) {
2161 	REQUIRE(rdata != NULL);
2162 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2163 
2164 	rdata->data = NULL;
2165 	rdata->length = 0;
2166 	rdata->flags = DNS_RDATA_UPDATE;
2167 	rdata->type = type;
2168 	rdata->rdclass = dns_rdataclass_none;
2169 }
2170 
2171 void
2172 dns_rdata_deleterrset(dns_rdata_t *rdata, dns_rdatatype_t type) {
2173 	REQUIRE(rdata != NULL);
2174 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2175 
2176 	rdata->data = NULL;
2177 	rdata->length = 0;
2178 	rdata->flags = DNS_RDATA_UPDATE;
2179 	rdata->type = type;
2180 	rdata->rdclass = dns_rdataclass_any;
2181 }
2182 
2183 void
2184 dns_rdata_makedelete(dns_rdata_t *rdata) {
2185 	REQUIRE(rdata != NULL);
2186 
2187 	rdata->rdclass = dns_rdataclass_none;
2188 }
2189 
2190 const char *
2191 dns_rdata_updateop(dns_rdata_t *rdata, dns_section_t section) {
2192 	REQUIRE(rdata != NULL);
2193 	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
2194 
2195 	switch (section) {
2196 	case DNS_SECTION_PREREQUISITE:
2197 		switch (rdata->rdclass) {
2198 		case dns_rdataclass_none:
2199 			switch (rdata->type) {
2200 			case dns_rdatatype_any:
2201 				return ("domain doesn't exist");
2202 			default:
2203 				return ("rrset doesn't exist");
2204 			}
2205 		case dns_rdataclass_any:
2206 			switch (rdata->type) {
2207 			case dns_rdatatype_any:
2208 				return ("domain exists");
2209 			default:
2210 				return ("rrset exists (value independent)");
2211 			}
2212 		default:
2213 			return ("rrset exists (value dependent)");
2214 		}
2215 	case DNS_SECTION_UPDATE:
2216 		switch (rdata->rdclass) {
2217 		case dns_rdataclass_none:
2218 			return ("delete");
2219 		case dns_rdataclass_any:
2220 			switch (rdata->type) {
2221 			case dns_rdatatype_any:
2222 				return ("delete all rrsets");
2223 			default:
2224 				return ("delete rrset");
2225 			}
2226 		default:
2227 			return ("add");
2228 		}
2229 	}
2230 	return ("invalid");
2231 }
2232