xref: /openbsd-src/usr.sbin/nsd/rdata.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*
2  * rdata.c -- RDATA conversion functions.
3  *
4  * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include <config.h>
11 
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <ctype.h>
17 #include <netdb.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #ifdef HAVE_STRINGS_H
21 #include <strings.h>
22 #endif
23 
24 #include "rdata.h"
25 #include "zonec.h"
26 
27 /* Taken from RFC 4398, section 2.1.  */
28 lookup_table_type dns_certificate_types[] = {
29 /*	0		Reserved */
30 	{ 1, "PKIX" },	/* X.509 as per PKIX */
31 	{ 2, "SPKI" },	/* SPKI cert */
32 	{ 3, "PGP" },	/* OpenPGP packet */
33 	{ 4, "IPKIX" },	/* The URL of an X.509 data object */
34 	{ 5, "ISPKI" },	/* The URL of an SPKI certificate */
35 	{ 6, "IPGP" },	/* The fingerprint and URL of an OpenPGP packet */
36 	{ 7, "ACPKIX" },	/* Attribute Certificate */
37 	{ 8, "IACPKIX" },	/* The URL of an Attribute Certificate */
38 	{ 253, "URI" },	/* URI private */
39 	{ 254, "OID" },	/* OID private */
40 /*	255 		Reserved */
41 /* 	256-65279	Available for IANA assignment */
42 /*	65280-65534	Experimental */
43 /*	65535		Reserved */
44 	{ 0, NULL }
45 };
46 
47 /* Taken from RFC 2535, section 7.  */
48 lookup_table_type dns_algorithms[] = {
49 	{ 1, "RSAMD5" },	/* RFC 2537 */
50 	{ 2, "DH" },		/* RFC 2539 */
51 	{ 3, "DSA" },		/* RFC 2536 */
52 	{ 4, "ECC" },
53 	{ 5, "RSASHA1" },	/* RFC 3110 */
54 	{ 252, "INDIRECT" },
55 	{ 253, "PRIVATEDNS" },
56 	{ 254, "PRIVATEOID" },
57 	{ 0, NULL }
58 };
59 
60 typedef int (*rdata_to_string_type)(buffer_type *output,
61 				    rdata_atom_type rdata,
62 				    rr_type *rr);
63 
64 static int
65 rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata,
66 	rr_type* ATTR_UNUSED(rr))
67 {
68 	buffer_printf(output,
69 		      "%s",
70 		      dname_to_string(domain_dname(rdata_atom_domain(rdata)),
71 				      NULL));
72 	return 1;
73 }
74 
75 static int
76 rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata,
77 	rr_type* ATTR_UNUSED(rr))
78 {
79 	const uint8_t *data = rdata_atom_data(rdata);
80 	size_t offset = 0;
81 	uint8_t length = data[offset];
82 	size_t i;
83 
84 	while (length > 0)
85 	{
86 		if (offset) /* concat label */
87 			buffer_printf(output, ".");
88 
89 		for (i = 1; i <= length; ++i) {
90 			uint8_t ch = data[i+offset];
91 
92 			if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') {
93 				buffer_printf(output, "\\%c", (char) ch);
94 			} else if (!isgraph((int) ch)) {
95 				buffer_printf(output, "\\%03u", (unsigned int) ch);
96 			} else if (isprint((int) ch)) {
97 				buffer_printf(output, "%c", (char) ch);
98 			} else {
99 				buffer_printf(output, "\\%03u", (unsigned int) ch);
100 			}
101 		}
102 		/* next label */
103 		offset = offset+length+1;
104 		length = data[offset];
105 	}
106 
107 	/* root label */
108 	buffer_printf(output, ".");
109 	return 1;
110 }
111 
112 static int
113 rdata_text_to_string(buffer_type *output, rdata_atom_type rdata,
114 	rr_type* ATTR_UNUSED(rr))
115 {
116 	const uint8_t *data = rdata_atom_data(rdata);
117 	uint8_t length = data[0];
118 	size_t i;
119 
120 	buffer_printf(output, "\"");
121 	for (i = 1; i <= length; ++i) {
122 		char ch = (char) data[i];
123 		if (isprint((int)ch)) {
124 			if (ch == '"' || ch == '\\') {
125 				buffer_printf(output, "\\");
126 			}
127 			buffer_printf(output, "%c", ch);
128 		} else {
129 			buffer_printf(output, "\\%03u", (unsigned) ch);
130 		}
131 	}
132 	buffer_printf(output, "\"");
133 	return 1;
134 }
135 
136 static int
137 rdata_texts_to_string(buffer_type *output, rdata_atom_type rdata,
138 	rr_type* ATTR_UNUSED(rr))
139 {
140 	uint16_t pos = 0;
141 	const uint8_t *data = rdata_atom_data(rdata);
142 	uint16_t length = rdata_atom_size(rdata);
143 	size_t i;
144 
145 	while (pos < length && pos + data[pos] < length) {
146 		buffer_printf(output, "\"");
147 		for (i = 1; i <= data[pos]; ++i) {
148 			char ch = (char) data[pos + i];
149 			if (isprint((int)ch)) {
150 				if (ch == '"' || ch == '\\') {
151 					buffer_printf(output, "\\");
152 				}
153 				buffer_printf(output, "%c", ch);
154 			} else {
155 				buffer_printf(output, "\\%03u", (unsigned) ch);
156 			}
157 		}
158 		pos += data[pos]+1;
159 		buffer_printf(output, pos < length?"\" ":"\"");
160 	}
161 	return 1;
162 }
163 
164 static int
165 rdata_byte_to_string(buffer_type *output, rdata_atom_type rdata,
166 	rr_type* ATTR_UNUSED(rr))
167 {
168 	uint8_t data = *rdata_atom_data(rdata);
169 	buffer_printf(output, "%lu", (unsigned long) data);
170 	return 1;
171 }
172 
173 static int
174 rdata_short_to_string(buffer_type *output, rdata_atom_type rdata,
175 	rr_type* ATTR_UNUSED(rr))
176 {
177 	uint16_t data = read_uint16(rdata_atom_data(rdata));
178 	buffer_printf(output, "%lu", (unsigned long) data);
179 	return 1;
180 }
181 
182 static int
183 rdata_long_to_string(buffer_type *output, rdata_atom_type rdata,
184 	rr_type* ATTR_UNUSED(rr))
185 {
186 	uint32_t data = read_uint32(rdata_atom_data(rdata));
187 	buffer_printf(output, "%lu", (unsigned long) data);
188 	return 1;
189 }
190 
191 static int
192 rdata_a_to_string(buffer_type *output, rdata_atom_type rdata,
193 	rr_type* ATTR_UNUSED(rr))
194 {
195 	int result = 0;
196 	char str[200];
197 	if (inet_ntop(AF_INET, rdata_atom_data(rdata), str, sizeof(str))) {
198 		buffer_printf(output, "%s", str);
199 		result = 1;
200 	}
201 	return result;
202 }
203 
204 static int
205 rdata_aaaa_to_string(buffer_type *output, rdata_atom_type rdata,
206 	rr_type* ATTR_UNUSED(rr))
207 {
208 	int result = 0;
209 	char str[200];
210 	if (inet_ntop(AF_INET6, rdata_atom_data(rdata), str, sizeof(str))) {
211 		buffer_printf(output, "%s", str);
212 		result = 1;
213 	}
214 	return result;
215 }
216 
217 static int
218 rdata_rrtype_to_string(buffer_type *output, rdata_atom_type rdata,
219 	rr_type* ATTR_UNUSED(rr))
220 {
221 	uint16_t type = read_uint16(rdata_atom_data(rdata));
222 	buffer_printf(output, "%s", rrtype_to_string(type));
223 	return 1;
224 }
225 
226 static int
227 rdata_algorithm_to_string(buffer_type *output, rdata_atom_type rdata,
228 	rr_type* ATTR_UNUSED(rr))
229 {
230 	uint8_t id = *rdata_atom_data(rdata);
231 	lookup_table_type *alg
232 		= lookup_by_id(dns_algorithms, id);
233 	if (alg) {
234 		buffer_printf(output, "%s", alg->name);
235 	} else {
236 		buffer_printf(output, "%u", (unsigned) id);
237 	}
238 	return 1;
239 }
240 
241 static int
242 rdata_certificate_type_to_string(buffer_type *output, rdata_atom_type rdata,
243 	rr_type* ATTR_UNUSED(rr))
244 {
245 	uint16_t id = read_uint16(rdata_atom_data(rdata));
246 	lookup_table_type *type
247 		= lookup_by_id(dns_certificate_types, id);
248 	if (type) {
249 		buffer_printf(output, "%s", type->name);
250 	} else {
251 		buffer_printf(output, "%u", (unsigned) id);
252 	}
253 	return 1;
254 }
255 
256 static int
257 rdata_period_to_string(buffer_type *output, rdata_atom_type rdata,
258 	rr_type* ATTR_UNUSED(rr))
259 {
260 	uint32_t period = read_uint32(rdata_atom_data(rdata));
261 	buffer_printf(output, "%lu", (unsigned long) period);
262 	return 1;
263 }
264 
265 static int
266 rdata_time_to_string(buffer_type *output, rdata_atom_type rdata,
267 	rr_type* ATTR_UNUSED(rr))
268 {
269 	int result = 0;
270 	time_t time = (time_t) read_uint32(rdata_atom_data(rdata));
271 	struct tm *tm = gmtime(&time);
272 	char buf[15];
273 	if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm)) {
274 		buffer_printf(output, "%s", buf);
275 		result = 1;
276 	}
277 	return result;
278 }
279 
280 static int
281 rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata,
282 	rr_type* ATTR_UNUSED(rr))
283 {
284 	int length;
285 	size_t size = rdata_atom_size(rdata);
286 	if(size == 0) {
287 		buffer_write(output, "-", 1);
288 		return 1;
289 	}
290 	size -= 1; /* remove length byte from count */
291 	buffer_reserve(output, size * 2 + 1);
292 	length = b32_ntop(rdata_atom_data(rdata)+1, size,
293 			  (char *) buffer_current(output), size * 2);
294 	if (length > 0) {
295 		buffer_skip(output, length);
296 	}
297 	return length != -1;
298 }
299 
300 static int
301 rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata,
302 	rr_type* ATTR_UNUSED(rr))
303 {
304 	int length;
305 	size_t size = rdata_atom_size(rdata);
306 	buffer_reserve(output, size * 2 + 1);
307 	length = b64_ntop(rdata_atom_data(rdata), size,
308 			  (char *) buffer_current(output), size * 2);
309 	if (length > 0) {
310 		buffer_skip(output, length);
311 	}
312 	return length != -1;
313 }
314 
315 static void
316 hex_to_string(buffer_type *output, const uint8_t *data, size_t size)
317 {
318 	static const char hexdigits[] = {
319 		'0', '1', '2', '3', '4', '5', '6', '7',
320 		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
321 	};
322 	size_t i;
323 
324 	buffer_reserve(output, size * 2);
325 	for (i = 0; i < size; ++i) {
326 		uint8_t octet = *data++;
327 		buffer_write_u8(output, hexdigits[octet >> 4]);
328 		buffer_write_u8(output, hexdigits[octet & 0x0f]);
329 	}
330 }
331 
332 static int
333 rdata_hex_to_string(buffer_type *output, rdata_atom_type rdata,
334 	rr_type* ATTR_UNUSED(rr))
335 {
336 	hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
337 	return 1;
338 }
339 
340 static int
341 rdata_hexlen_to_string(buffer_type *output, rdata_atom_type rdata,
342 	rr_type* ATTR_UNUSED(rr))
343 {
344 	if(rdata_atom_size(rdata) <= 1) {
345 		/* NSEC3 salt hex can be empty */
346 		buffer_printf(output, "-");
347 		return 1;
348 	}
349 	hex_to_string(output, rdata_atom_data(rdata)+1, rdata_atom_size(rdata)-1);
350 	return 1;
351 }
352 
353 static int
354 rdata_nsap_to_string(buffer_type *output, rdata_atom_type rdata,
355 	rr_type* ATTR_UNUSED(rr))
356 {
357 	buffer_printf(output, "0x");
358 	hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
359 	return 1;
360 }
361 
362 static int
363 rdata_apl_to_string(buffer_type *output, rdata_atom_type rdata,
364 	rr_type* ATTR_UNUSED(rr))
365 {
366 	int result = 0;
367 	buffer_type packet;
368 
369 	buffer_create_from(
370 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
371 
372 	if (buffer_available(&packet, 4)) {
373 		uint16_t address_family = buffer_read_u16(&packet);
374 		uint8_t prefix = buffer_read_u8(&packet);
375 		uint8_t length = buffer_read_u8(&packet);
376 		int negated = length & APL_NEGATION_MASK;
377 		int af = -1;
378 
379 		length &= APL_LENGTH_MASK;
380 		switch (address_family) {
381 		case 1: af = AF_INET; break;
382 		case 2: af = AF_INET6; break;
383 		}
384 		if (af != -1 && buffer_available(&packet, length)) {
385 			char text_address[1000];
386 			uint8_t address[128];
387 			memset(address, 0, sizeof(address));
388 			buffer_read(&packet, address, length);
389 			if (inet_ntop(af, address, text_address, sizeof(text_address))) {
390 				buffer_printf(output, "%s%d:%s/%d",
391 					      negated ? "!" : "",
392 					      (int) address_family,
393 					      text_address,
394 					      (int) prefix);
395 				result = 1;
396 			}
397 		}
398 	}
399 	return result;
400 }
401 
402 static int
403 rdata_services_to_string(buffer_type *output, rdata_atom_type rdata,
404 	rr_type* ATTR_UNUSED(rr))
405 {
406 	int result = 0;
407 	buffer_type packet;
408 
409 	buffer_create_from(
410 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
411 
412 	if (buffer_available(&packet, 1)) {
413 		uint8_t protocol_number = buffer_read_u8(&packet);
414 		ssize_t bitmap_size = buffer_remaining(&packet);
415 		uint8_t *bitmap = buffer_current(&packet);
416 		struct protoent *proto = getprotobynumber(protocol_number);
417 
418 		if (proto) {
419 			int i;
420 
421 			buffer_printf(output, "%s", proto->p_name);
422 
423 			for (i = 0; i < bitmap_size * 8; ++i) {
424 				if (get_bit(bitmap, i)) {
425 					struct servent *service = getservbyport((int)htons(i), proto->p_name);
426 					if (service) {
427 						buffer_printf(output, " %s", service->s_name);
428 					} else {
429 						buffer_printf(output, " %d", i);
430 					}
431 				}
432 			}
433 			buffer_skip(&packet, bitmap_size);
434 			result = 1;
435 		}
436 	}
437 	return result;
438 }
439 
440 static int
441 rdata_ipsecgateway_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr)
442 {
443 	int gateway_type = rdata_atom_data(rr->rdatas[1])[0];
444 	switch(gateway_type) {
445 	case IPSECKEY_NOGATEWAY:
446 		buffer_printf(output, ".");
447 		break;
448 	case IPSECKEY_IP4:
449 		rdata_a_to_string(output, rdata, rr);
450 		break;
451 	case IPSECKEY_IP6:
452 		rdata_aaaa_to_string(output, rdata, rr);
453 		break;
454 	case IPSECKEY_DNAME:
455 		rdata_dname_to_string(output, rdata, rr);
456 		break;
457 	default:
458 		return 0;
459 	}
460 	return 1;
461 }
462 
463 static int
464 rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata,
465 	rr_type* ATTR_UNUSED(rr))
466 {
467 	size_t i;
468 	uint8_t *bitmap = rdata_atom_data(rdata);
469 	size_t bitmap_size = rdata_atom_size(rdata);
470 
471 	for (i = 0; i < bitmap_size * 8; ++i) {
472 		if (get_bit(bitmap, i)) {
473 			buffer_printf(output, "%s ", rrtype_to_string(i));
474 		}
475 	}
476 
477 	buffer_skip(output, -1);
478 
479 	return 1;
480 }
481 
482 static int
483 rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata,
484 	rr_type* ATTR_UNUSED(rr))
485 {
486 	size_t saved_position = buffer_position(output);
487 	buffer_type packet;
488 	int insert_space = 0;
489 
490 	buffer_create_from(
491 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
492 
493 	while (buffer_available(&packet, 2)) {
494 		uint8_t window = buffer_read_u8(&packet);
495 		uint8_t bitmap_size = buffer_read_u8(&packet);
496 		uint8_t *bitmap = buffer_current(&packet);
497 		int i;
498 
499 		if (!buffer_available(&packet, bitmap_size)) {
500 			buffer_set_position(output, saved_position);
501 			return 0;
502 		}
503 
504 		for (i = 0; i < bitmap_size * 8; ++i) {
505 			if (get_bit(bitmap, i)) {
506 				buffer_printf(output,
507 					      "%s%s",
508 					      insert_space ? " " : "",
509 					      rrtype_to_string(
510 						      window * 256 + i));
511 				insert_space = 1;
512 			}
513 		}
514 		buffer_skip(&packet, bitmap_size);
515 	}
516 
517 	return 1;
518 }
519 
520 static int
521 rdata_loc_to_string(buffer_type *ATTR_UNUSED(output),
522 		    rdata_atom_type ATTR_UNUSED(rdata),
523 		    rr_type* ATTR_UNUSED(rr))
524 {
525 	/*
526 	 * Returning 0 forces the record to be printed in unknown
527 	 * format.
528 	 */
529 	return 0;
530 }
531 
532 static int
533 rdata_unknown_to_string(buffer_type *output, rdata_atom_type rdata,
534 	rr_type* ATTR_UNUSED(rr))
535 {
536  	uint16_t size = rdata_atom_size(rdata);
537  	buffer_printf(output, "\\# %lu ", (unsigned long) size);
538 	hex_to_string(output, rdata_atom_data(rdata), size);
539 	return 1;
540 }
541 
542 static rdata_to_string_type rdata_to_string_table[RDATA_ZF_UNKNOWN + 1] = {
543 	rdata_dname_to_string,
544 	rdata_dns_name_to_string,
545 	rdata_text_to_string,
546 	rdata_texts_to_string,
547 	rdata_byte_to_string,
548 	rdata_short_to_string,
549 	rdata_long_to_string,
550 	rdata_a_to_string,
551 	rdata_aaaa_to_string,
552 	rdata_rrtype_to_string,
553 	rdata_algorithm_to_string,
554 	rdata_certificate_type_to_string,
555 	rdata_period_to_string,
556 	rdata_time_to_string,
557 	rdata_base64_to_string,
558 	rdata_base32_to_string,
559 	rdata_hex_to_string,
560 	rdata_hexlen_to_string,
561 	rdata_nsap_to_string,
562 	rdata_apl_to_string,
563 	rdata_ipsecgateway_to_string,
564 	rdata_services_to_string,
565 	rdata_nxt_to_string,
566 	rdata_nsec_to_string,
567 	rdata_loc_to_string,
568 	rdata_unknown_to_string
569 };
570 
571 int
572 rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type,
573 		     rdata_atom_type rdata, rr_type* record)
574 {
575 	return rdata_to_string_table[type](output, rdata, record);
576 }
577 
578 ssize_t
579 rdata_wireformat_to_rdata_atoms(region_type *region,
580 				domain_table_type *owners,
581 				uint16_t rrtype,
582 				uint16_t data_size,
583 				buffer_type *packet,
584 				rdata_atom_type **rdatas)
585 {
586 	size_t end = buffer_position(packet) + data_size;
587 	size_t i;
588 	rdata_atom_type temp_rdatas[MAXRDATALEN];
589 	rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype);
590 	region_type *temp_region;
591 
592 	assert(descriptor->maximum <= MAXRDATALEN);
593 
594 	if (!buffer_available(packet, data_size)) {
595 		return -1;
596 	}
597 
598 	temp_region = region_create(xalloc, free);
599 
600 	for (i = 0; i < descriptor->maximum; ++i) {
601 		int is_domain = 0;
602 		int is_normalized = 0;
603 		int is_wirestore = 0;
604 		size_t length = 0;
605 		int required = i < descriptor->minimum;
606 
607 		switch (rdata_atom_wireformat_type(rrtype, i)) {
608 		case RDATA_WF_COMPRESSED_DNAME:
609 		case RDATA_WF_UNCOMPRESSED_DNAME:
610 			is_domain = 1;
611 			is_normalized = 1;
612 			break;
613 		case RDATA_WF_LITERAL_DNAME:
614 			is_domain = 1;
615 			is_wirestore = 1;
616 			break;
617 		case RDATA_WF_BYTE:
618 			length = sizeof(uint8_t);
619 			break;
620 		case RDATA_WF_SHORT:
621 			length = sizeof(uint16_t);
622 			break;
623 		case RDATA_WF_LONG:
624 			length = sizeof(uint32_t);
625 			break;
626 		case RDATA_WF_TEXTS:
627 			length = data_size;
628 			break;
629 		case RDATA_WF_TEXT:
630 		case RDATA_WF_BINARYWITHLENGTH:
631 			/* Length is stored in the first byte.  */
632 			length = 1;
633 			if (buffer_position(packet) + length <= end) {
634 				length += buffer_current(packet)[length - 1];
635 			}
636 			break;
637 		case RDATA_WF_A:
638 			length = sizeof(in_addr_t);
639 			break;
640 		case RDATA_WF_AAAA:
641 			length = IP6ADDRLEN;
642 			break;
643 		case RDATA_WF_BINARY:
644 			/* Remaining RDATA is binary.  */
645 			length = end - buffer_position(packet);
646 			break;
647 		case RDATA_WF_APL:
648 			length = (sizeof(uint16_t)    /* address family */
649 				  + sizeof(uint8_t)   /* prefix */
650 				  + sizeof(uint8_t)); /* length */
651 			if (buffer_position(packet) + length <= end) {
652 				/* Mask out negation bit.  */
653 				length += (buffer_current(packet)[length - 1]
654 					   & APL_LENGTH_MASK);
655 			}
656 			break;
657 		case RDATA_WF_IPSECGATEWAY:
658 			switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ {
659 			default:
660 			case IPSECKEY_NOGATEWAY:
661 				length = 0;
662 				break;
663 			case IPSECKEY_IP4:
664 				length = IP4ADDRLEN;
665 				break;
666 			case IPSECKEY_IP6:
667 				length = IP6ADDRLEN;
668 				break;
669 			case IPSECKEY_DNAME:
670 				is_domain = 1;
671 				is_normalized = 1;
672 				is_wirestore = 1;
673 				break;
674 			}
675 			break;
676 		}
677 
678 		if (is_domain) {
679 			const dname_type *dname;
680 
681 			if (!required && buffer_position(packet) == end) {
682 				break;
683 			}
684 
685 			dname = dname_make_from_packet(
686 				temp_region, packet, 1, is_normalized);
687 			if (!dname || buffer_position(packet) > end) {
688 				/* Error in domain name.  */
689 				region_destroy(temp_region);
690 				return -1;
691 			}
692 			if(is_wirestore) {
693 				temp_rdatas[i].data = (uint16_t *) region_alloc(
694                                 	region, sizeof(uint16_t) + dname->name_size);
695 				temp_rdatas[i].data[0] = dname->name_size;
696 				memcpy(temp_rdatas[i].data+1, dname_name(dname),
697 					dname->name_size);
698 			} else
699 				temp_rdatas[i].domain
700 					= domain_table_insert(owners, dname);
701 		} else {
702 			if (buffer_position(packet) + length > end) {
703 				if (required) {
704 					/* Truncated RDATA.  */
705 					region_destroy(temp_region);
706 					return -1;
707 				} else {
708 					break;
709 				}
710 			}
711 
712 			temp_rdatas[i].data = (uint16_t *) region_alloc(
713 				region, sizeof(uint16_t) + length);
714 			temp_rdatas[i].data[0] = length;
715 			buffer_read(packet, temp_rdatas[i].data + 1, length);
716 		}
717 	}
718 
719 	if (buffer_position(packet) < end) {
720 		/* Trailing garbage.  */
721 		region_destroy(temp_region);
722 		return -1;
723 	}
724 
725 	*rdatas = (rdata_atom_type *) region_alloc_init(
726 		region, temp_rdatas, i * sizeof(rdata_atom_type));
727 	region_destroy(temp_region);
728 	return (ssize_t)i;
729 }
730 
731 size_t
732 rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor,
733 			      size_t rdata_count,
734 			      rdata_atom_type *rdatas)
735 {
736 	size_t result = 0;
737 	size_t i;
738 	for (i = 0; i < rdata_count; ++i) {
739 		if (rdata_atom_is_domain(descriptor->type, i)) {
740 			result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size;
741 		} else {
742 			result += rdata_atom_size(rdatas[i]);
743 		}
744 	}
745 	return result;
746 }
747 
748 int
749 rdata_atoms_to_unknown_string(buffer_type *output,
750 			      rrtype_descriptor_type *descriptor,
751 			      size_t rdata_count,
752 			      rdata_atom_type *rdatas)
753 {
754 	size_t i;
755 	size_t size =
756 		rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas);
757 	buffer_printf(output, " \\# %lu ", (unsigned long) size);
758 	for (i = 0; i < rdata_count; ++i) {
759 		if (rdata_atom_is_domain(descriptor->type, i)) {
760 			const dname_type *dname =
761 				domain_dname(rdata_atom_domain(rdatas[i]));
762 			hex_to_string(
763 				output, dname_name(dname), dname->name_size);
764 		} else {
765 			hex_to_string(output, rdata_atom_data(rdatas[i]),
766 				rdata_atom_size(rdatas[i]));
767 		}
768 	}
769 	return 1;
770 }
771 
772 int
773 print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor,
774 	    rr_type *record)
775 {
776 	size_t i;
777 	size_t saved_position = buffer_position(output);
778 
779 	for (i = 0; i < record->rdata_count; ++i) {
780 		if (i == 0) {
781 			buffer_printf(output, "\t");
782 		} else if (descriptor->type == TYPE_SOA && i == 2) {
783 			buffer_printf(output, " (\n\t\t");
784 		} else {
785 			buffer_printf(output, " ");
786 		}
787 		if (!rdata_atom_to_string(
788 			    output,
789 			    (rdata_zoneformat_type) descriptor->zoneformat[i],
790 			    record->rdatas[i], record))
791 		{
792 			buffer_set_position(output, saved_position);
793 			return 0;
794 		}
795 	}
796 	if (descriptor->type == TYPE_SOA) {
797 		buffer_printf(output, " )");
798 	}
799 
800 	return 1;
801 }
802 
803 
804