xref: /openbsd/usr.sbin/nsd/rdata.c (revision 09467b48)
1 /*
2  * rdata.c -- RDATA conversion functions.
3  *
4  * Copyright (c) 2001-2006, 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 	{ 6, "DSA-NSEC3-SHA1" },	/* RFC 5155 */
55 	{ 7, "RSASHA1-NSEC3-SHA1" },	/* RFC 5155 */
56 	{ 8, "RSASHA256" },		/* RFC 5702 */
57 	{ 10, "RSASHA512" },		/* RFC 5702 */
58 	{ 12, "ECC-GOST" },		/* RFC 5933 */
59 	{ 13, "ECDSAP256SHA256" },	/* RFC 6605 */
60 	{ 14, "ECDSAP384SHA384" },	/* RFC 6605 */
61 	{ 15, "ED25519" },		/* RFC 8080 */
62 	{ 16, "ED448" },		/* RFC 8080 */
63 	{ 252, "INDIRECT" },
64 	{ 253, "PRIVATEDNS" },
65 	{ 254, "PRIVATEOID" },
66 	{ 0, NULL }
67 };
68 
69 typedef int (*rdata_to_string_type)(buffer_type *output,
70 				    rdata_atom_type rdata,
71 				    rr_type *rr);
72 
73 static int
74 rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata,
75 	rr_type* ATTR_UNUSED(rr))
76 {
77 	buffer_printf(output,
78 		      "%s",
79 		      dname_to_string(domain_dname(rdata_atom_domain(rdata)),
80 				      NULL));
81 	return 1;
82 }
83 
84 static int
85 rdata_dns_name_to_string(buffer_type *output, rdata_atom_type rdata,
86 	rr_type* ATTR_UNUSED(rr))
87 {
88 	const uint8_t *data = rdata_atom_data(rdata);
89 	size_t offset = 0;
90 	uint8_t length = data[offset];
91 	size_t i;
92 
93 	while (length > 0)
94 	{
95 		if (offset) /* concat label */
96 			buffer_printf(output, ".");
97 
98 		for (i = 1; i <= length; ++i) {
99 			uint8_t ch = data[i+offset];
100 
101 			if (ch=='.' || ch==';' || ch=='(' || ch==')' || ch=='\\') {
102 				buffer_printf(output, "\\%c", (char) ch);
103 			} else if (!isgraph((unsigned char) ch)) {
104 				buffer_printf(output, "\\%03u", (unsigned int) ch);
105 			} else if (isprint((unsigned char) ch)) {
106 				buffer_printf(output, "%c", (char) ch);
107 			} else {
108 				buffer_printf(output, "\\%03u", (unsigned int) ch);
109 			}
110 		}
111 		/* next label */
112 		offset = offset+length+1;
113 		length = data[offset];
114 	}
115 
116 	/* root label */
117 	buffer_printf(output, ".");
118 	return 1;
119 }
120 
121 static int
122 rdata_text_to_string(buffer_type *output, rdata_atom_type rdata,
123 	rr_type* ATTR_UNUSED(rr))
124 {
125 	const uint8_t *data = rdata_atom_data(rdata);
126 	uint8_t length = data[0];
127 	size_t i;
128 
129 	buffer_printf(output, "\"");
130 	for (i = 1; i <= length; ++i) {
131 		char ch = (char) data[i];
132 		if (isprint((unsigned char)ch)) {
133 			if (ch == '"' || ch == '\\') {
134 				buffer_printf(output, "\\");
135 			}
136 			buffer_printf(output, "%c", ch);
137 		} else {
138 			buffer_printf(output, "\\%03u", (unsigned) data[i]);
139 		}
140 	}
141 	buffer_printf(output, "\"");
142 	return 1;
143 }
144 
145 static int
146 rdata_texts_to_string(buffer_type *output, rdata_atom_type rdata,
147 	rr_type* ATTR_UNUSED(rr))
148 {
149 	uint16_t pos = 0;
150 	const uint8_t *data = rdata_atom_data(rdata);
151 	uint16_t length = rdata_atom_size(rdata);
152 	size_t i;
153 
154 	while (pos < length && pos + data[pos] < length) {
155 		buffer_printf(output, "\"");
156 		for (i = 1; i <= data[pos]; ++i) {
157 			char ch = (char) data[pos + i];
158 			if (isprint((unsigned char)ch)) {
159 				if (ch == '"' || ch == '\\') {
160 					buffer_printf(output, "\\");
161 				}
162 				buffer_printf(output, "%c", ch);
163 			} else {
164 				buffer_printf(output, "\\%03u", (unsigned) data[pos+i]);
165 			}
166 		}
167 		pos += data[pos]+1;
168 		buffer_printf(output, pos < length?"\" ":"\"");
169 	}
170 	return 1;
171 }
172 
173 static int
174 rdata_long_text_to_string(buffer_type *output, rdata_atom_type rdata,
175 	rr_type* ATTR_UNUSED(rr))
176 {
177 	const uint8_t *data = rdata_atom_data(rdata);
178 	uint16_t length = rdata_atom_size(rdata);
179 	size_t i;
180 
181 	buffer_printf(output, "\"");
182 	for (i = 0; i < length; ++i) {
183 		char ch = (char) data[i];
184 		if (isprint((unsigned char)ch)) {
185 			if (ch == '"' || ch == '\\') {
186 				buffer_printf(output, "\\");
187 			}
188 			buffer_printf(output, "%c", ch);
189 		} else {
190 			buffer_printf(output, "\\%03u", (unsigned) data[i]);
191 		}
192 	}
193 	buffer_printf(output, "\"");
194 	return 1;
195 }
196 
197 static int
198 rdata_tag_to_string(buffer_type *output, rdata_atom_type rdata,
199 	rr_type* ATTR_UNUSED(rr))
200 {
201 	const uint8_t *data = rdata_atom_data(rdata);
202 	uint8_t length = data[0];
203 	size_t i;
204 	for (i = 1; i <= length; ++i) {
205 		char ch = (char) data[i];
206 		if (isdigit((unsigned char)ch) || islower((unsigned char)ch))
207 			buffer_printf(output, "%c", ch);
208 		else	return 0;
209 	}
210 	return 1;
211 }
212 
213 static int
214 rdata_byte_to_string(buffer_type *output, rdata_atom_type rdata,
215 	rr_type* ATTR_UNUSED(rr))
216 {
217 	uint8_t data = *rdata_atom_data(rdata);
218 	buffer_printf(output, "%lu", (unsigned long) data);
219 	return 1;
220 }
221 
222 static int
223 rdata_short_to_string(buffer_type *output, rdata_atom_type rdata,
224 	rr_type* ATTR_UNUSED(rr))
225 {
226 	uint16_t data = read_uint16(rdata_atom_data(rdata));
227 	buffer_printf(output, "%lu", (unsigned long) data);
228 	return 1;
229 }
230 
231 static int
232 rdata_long_to_string(buffer_type *output, rdata_atom_type rdata,
233 	rr_type* ATTR_UNUSED(rr))
234 {
235 	uint32_t data = read_uint32(rdata_atom_data(rdata));
236 	buffer_printf(output, "%lu", (unsigned long) data);
237 	return 1;
238 }
239 
240 static int
241 rdata_a_to_string(buffer_type *output, rdata_atom_type rdata,
242 	rr_type* ATTR_UNUSED(rr))
243 {
244 	int result = 0;
245 	char str[200];
246 	if (inet_ntop(AF_INET, rdata_atom_data(rdata), str, sizeof(str))) {
247 		buffer_printf(output, "%s", str);
248 		result = 1;
249 	}
250 	return result;
251 }
252 
253 static int
254 rdata_aaaa_to_string(buffer_type *output, rdata_atom_type rdata,
255 	rr_type* ATTR_UNUSED(rr))
256 {
257 	int result = 0;
258 	char str[200];
259 	if (inet_ntop(AF_INET6, rdata_atom_data(rdata), str, sizeof(str))) {
260 		buffer_printf(output, "%s", str);
261 		result = 1;
262 	}
263 	return result;
264 }
265 
266 static int
267 rdata_ilnp64_to_string(buffer_type *output, rdata_atom_type rdata,
268 	rr_type* ATTR_UNUSED(rr))
269 {
270 	uint8_t* data = rdata_atom_data(rdata);
271 	uint16_t a1 = read_uint16(data);
272 	uint16_t a2 = read_uint16(data+2);
273 	uint16_t a3 = read_uint16(data+4);
274 	uint16_t a4 = read_uint16(data+6);
275 
276 	buffer_printf(output, "%.4x:%.4x:%.4x:%.4x", a1, a2, a3, a4);
277 	return 1;
278 }
279 
280 static int
281 rdata_eui48_to_string(buffer_type *output, rdata_atom_type rdata,
282 	rr_type* ATTR_UNUSED(rr))
283 {
284 	uint8_t* data = rdata_atom_data(rdata);
285 	uint8_t a1 = data[0];
286 	uint8_t a2 = data[1];
287 	uint8_t a3 = data[2];
288 	uint8_t a4 = data[3];
289 	uint8_t a5 = data[4];
290 	uint8_t a6 = data[5];
291 
292 	buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
293 		a1, a2, a3, a4, a5, a6);
294 	return 1;
295 }
296 
297 static int
298 rdata_eui64_to_string(buffer_type *output, rdata_atom_type rdata,
299 	rr_type* ATTR_UNUSED(rr))
300 {
301 	uint8_t* data = rdata_atom_data(rdata);
302 	uint8_t a1 = data[0];
303 	uint8_t a2 = data[1];
304 	uint8_t a3 = data[2];
305 	uint8_t a4 = data[3];
306 	uint8_t a5 = data[4];
307 	uint8_t a6 = data[5];
308 	uint8_t a7 = data[6];
309 	uint8_t a8 = data[7];
310 
311 	buffer_printf(output, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
312 		a1, a2, a3, a4, a5, a6, a7, a8);
313 	return 1;
314 }
315 
316 static int
317 rdata_rrtype_to_string(buffer_type *output, rdata_atom_type rdata,
318 	rr_type* ATTR_UNUSED(rr))
319 {
320 	uint16_t type = read_uint16(rdata_atom_data(rdata));
321 	buffer_printf(output, "%s", rrtype_to_string(type));
322 	return 1;
323 }
324 
325 static int
326 rdata_algorithm_to_string(buffer_type *output, rdata_atom_type rdata,
327 	rr_type* ATTR_UNUSED(rr))
328 {
329 	uint8_t id = *rdata_atom_data(rdata);
330 	buffer_printf(output, "%u", (unsigned) id);
331 	return 1;
332 }
333 
334 static int
335 rdata_certificate_type_to_string(buffer_type *output, rdata_atom_type rdata,
336 	rr_type* ATTR_UNUSED(rr))
337 {
338 	uint16_t id = read_uint16(rdata_atom_data(rdata));
339 	lookup_table_type *type
340 		= lookup_by_id(dns_certificate_types, id);
341 	if (type) {
342 		buffer_printf(output, "%s", type->name);
343 	} else {
344 		buffer_printf(output, "%u", (unsigned) id);
345 	}
346 	return 1;
347 }
348 
349 static int
350 rdata_period_to_string(buffer_type *output, rdata_atom_type rdata,
351 	rr_type* ATTR_UNUSED(rr))
352 {
353 	uint32_t period = read_uint32(rdata_atom_data(rdata));
354 	buffer_printf(output, "%lu", (unsigned long) period);
355 	return 1;
356 }
357 
358 static int
359 rdata_time_to_string(buffer_type *output, rdata_atom_type rdata,
360 	rr_type* ATTR_UNUSED(rr))
361 {
362 	int result = 0;
363 	time_t time = (time_t) read_uint32(rdata_atom_data(rdata));
364 	struct tm *tm = gmtime(&time);
365 	char buf[15];
366 	if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", tm)) {
367 		buffer_printf(output, "%s", buf);
368 		result = 1;
369 	}
370 	return result;
371 }
372 
373 static int
374 rdata_base32_to_string(buffer_type *output, rdata_atom_type rdata,
375 	rr_type* ATTR_UNUSED(rr))
376 {
377 	int length;
378 	size_t size = rdata_atom_size(rdata);
379 	if(size == 0) {
380 		buffer_write(output, "-", 1);
381 		return 1;
382 	}
383 	size -= 1; /* remove length byte from count */
384 	buffer_reserve(output, size * 2 + 1);
385 	length = b32_ntop(rdata_atom_data(rdata)+1, size,
386 			  (char *) buffer_current(output), size * 2);
387 	if (length > 0) {
388 		buffer_skip(output, length);
389 	}
390 	return length != -1;
391 }
392 
393 static int
394 rdata_base64_to_string(buffer_type *output, rdata_atom_type rdata,
395 	rr_type* ATTR_UNUSED(rr))
396 {
397 	int length;
398 	size_t size = rdata_atom_size(rdata);
399 	if(size == 0) {
400 		/* single zero represents empty buffer */
401 		buffer_write(output, "0", 1);
402 		return 1;
403 	}
404 	buffer_reserve(output, size * 2 + 1);
405 	length = __b64_ntop(rdata_atom_data(rdata), size,
406 			  (char *) buffer_current(output), size * 2);
407 	if (length > 0) {
408 		buffer_skip(output, length);
409 	}
410 	return length != -1;
411 }
412 
413 static void
414 hex_to_string(buffer_type *output, const uint8_t *data, size_t size)
415 {
416 	static const char hexdigits[] = {
417 		'0', '1', '2', '3', '4', '5', '6', '7',
418 		'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
419 	};
420 	size_t i;
421 
422 	buffer_reserve(output, size * 2);
423 	for (i = 0; i < size; ++i) {
424 		uint8_t octet = *data++;
425 		buffer_write_u8(output, hexdigits[octet >> 4]);
426 		buffer_write_u8(output, hexdigits[octet & 0x0f]);
427 	}
428 }
429 
430 static int
431 rdata_hex_to_string(buffer_type *output, rdata_atom_type rdata,
432 	rr_type* ATTR_UNUSED(rr))
433 {
434 	if(rdata_atom_size(rdata) == 0) {
435 		/* single zero represents empty buffer, such as CDS deletes */
436 		buffer_printf(output, "0");
437 	} else {
438 		hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
439 	}
440 	return 1;
441 }
442 
443 static int
444 rdata_hexlen_to_string(buffer_type *output, rdata_atom_type rdata,
445 	rr_type* ATTR_UNUSED(rr))
446 {
447 	if(rdata_atom_size(rdata) <= 1) {
448 		/* NSEC3 salt hex can be empty */
449 		buffer_printf(output, "-");
450 		return 1;
451 	}
452 	hex_to_string(output, rdata_atom_data(rdata)+1, rdata_atom_size(rdata)-1);
453 	return 1;
454 }
455 
456 static int
457 rdata_nsap_to_string(buffer_type *output, rdata_atom_type rdata,
458 	rr_type* ATTR_UNUSED(rr))
459 {
460 	buffer_printf(output, "0x");
461 	hex_to_string(output, rdata_atom_data(rdata), rdata_atom_size(rdata));
462 	return 1;
463 }
464 
465 static int
466 rdata_apl_to_string(buffer_type *output, rdata_atom_type rdata,
467 	rr_type* ATTR_UNUSED(rr))
468 {
469 	int result = 0;
470 	buffer_type packet;
471 
472 	buffer_create_from(
473 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
474 
475 	if (buffer_available(&packet, 4)) {
476 		uint16_t address_family = buffer_read_u16(&packet);
477 		uint8_t prefix = buffer_read_u8(&packet);
478 		uint8_t length = buffer_read_u8(&packet);
479 		int negated = length & APL_NEGATION_MASK;
480 		int af = -1;
481 
482 		length &= APL_LENGTH_MASK;
483 		switch (address_family) {
484 		case 1: af = AF_INET; break;
485 		case 2: af = AF_INET6; break;
486 		}
487 		if (af != -1 && buffer_available(&packet, length)) {
488 			char text_address[1000];
489 			uint8_t address[128];
490 			memset(address, 0, sizeof(address));
491 			buffer_read(&packet, address, length);
492 			if (inet_ntop(af, address, text_address, sizeof(text_address))) {
493 				buffer_printf(output, "%s%d:%s/%d",
494 					      negated ? "!" : "",
495 					      (int) address_family,
496 					      text_address,
497 					      (int) prefix);
498 				result = 1;
499 			}
500 		}
501 	}
502 	return result;
503 }
504 
505 static int
506 rdata_services_to_string(buffer_type *output, rdata_atom_type rdata,
507 	rr_type* ATTR_UNUSED(rr))
508 {
509 	int result = 0;
510 	buffer_type packet;
511 
512 	buffer_create_from(
513 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
514 
515 	if (buffer_available(&packet, 1)) {
516 		uint8_t protocol_number = buffer_read_u8(&packet);
517 		ssize_t bitmap_size = buffer_remaining(&packet);
518 		uint8_t *bitmap = buffer_current(&packet);
519 		struct protoent *proto = getprotobynumber(protocol_number);
520 
521 		if (proto) {
522 			int i;
523 
524 			buffer_printf(output, "%s", proto->p_name);
525 
526 			for (i = 0; i < bitmap_size * 8; ++i) {
527 				if (get_bit(bitmap, i)) {
528 					struct servent *service = getservbyport((int)htons(i), proto->p_name);
529 					if (service) {
530 						buffer_printf(output, " %s", service->s_name);
531 					} else {
532 						buffer_printf(output, " %d", i);
533 					}
534 				}
535 			}
536 			buffer_skip(&packet, bitmap_size);
537 			result = 1;
538 		}
539 	}
540 	return result;
541 }
542 
543 static int
544 rdata_ipsecgateway_to_string(buffer_type *output, rdata_atom_type rdata, rr_type* rr)
545 {
546 	int gateway_type = rdata_atom_data(rr->rdatas[1])[0];
547 	switch(gateway_type) {
548 	case IPSECKEY_NOGATEWAY:
549 		buffer_printf(output, ".");
550 		break;
551 	case IPSECKEY_IP4:
552 		rdata_a_to_string(output, rdata, rr);
553 		break;
554 	case IPSECKEY_IP6:
555 		rdata_aaaa_to_string(output, rdata, rr);
556 		break;
557 	case IPSECKEY_DNAME:
558 		{
559 			region_type* temp = region_create(xalloc, free);
560 			const dname_type* d = dname_make(temp,
561 				rdata_atom_data(rdata), 0);
562 			if(!d) {
563 				region_destroy(temp);
564 				return 0;
565 			}
566 			buffer_printf(output, "%s", dname_to_string(d, NULL));
567 			region_destroy(temp);
568 		}
569 		break;
570 	default:
571 		return 0;
572 	}
573 	return 1;
574 }
575 
576 static int
577 rdata_nxt_to_string(buffer_type *output, rdata_atom_type rdata,
578 	rr_type* ATTR_UNUSED(rr))
579 {
580 	size_t i;
581 	uint8_t *bitmap = rdata_atom_data(rdata);
582 	size_t bitmap_size = rdata_atom_size(rdata);
583 
584 	for (i = 0; i < bitmap_size * 8; ++i) {
585 		if (get_bit(bitmap, i)) {
586 			buffer_printf(output, "%s ", rrtype_to_string(i));
587 		}
588 	}
589 
590 	buffer_skip(output, -1);
591 
592 	return 1;
593 }
594 
595 static int
596 rdata_nsec_to_string(buffer_type *output, rdata_atom_type rdata,
597 	rr_type* ATTR_UNUSED(rr))
598 {
599 	size_t saved_position = buffer_position(output);
600 	buffer_type packet;
601 	int insert_space = 0;
602 
603 	buffer_create_from(
604 		&packet, rdata_atom_data(rdata), rdata_atom_size(rdata));
605 
606 	while (buffer_available(&packet, 2)) {
607 		uint8_t window = buffer_read_u8(&packet);
608 		uint8_t bitmap_size = buffer_read_u8(&packet);
609 		uint8_t *bitmap = buffer_current(&packet);
610 		int i;
611 
612 		if (!buffer_available(&packet, bitmap_size)) {
613 			buffer_set_position(output, saved_position);
614 			return 0;
615 		}
616 
617 		for (i = 0; i < bitmap_size * 8; ++i) {
618 			if (get_bit(bitmap, i)) {
619 				buffer_printf(output,
620 					      "%s%s",
621 					      insert_space ? " " : "",
622 					      rrtype_to_string(
623 						      window * 256 + i));
624 				insert_space = 1;
625 			}
626 		}
627 		buffer_skip(&packet, bitmap_size);
628 	}
629 
630 	return 1;
631 }
632 
633 static int
634 rdata_loc_to_string(buffer_type *ATTR_UNUSED(output),
635 		    rdata_atom_type ATTR_UNUSED(rdata),
636 		    rr_type* ATTR_UNUSED(rr))
637 {
638 	/*
639 	 * Returning 0 forces the record to be printed in unknown
640 	 * format.
641 	 */
642 	return 0;
643 }
644 
645 static int
646 rdata_unknown_to_string(buffer_type *output, rdata_atom_type rdata,
647 	rr_type* ATTR_UNUSED(rr))
648 {
649  	uint16_t size = rdata_atom_size(rdata);
650  	buffer_printf(output, "\\# %lu ", (unsigned long) size);
651 	hex_to_string(output, rdata_atom_data(rdata), size);
652 	return 1;
653 }
654 
655 static rdata_to_string_type rdata_to_string_table[RDATA_ZF_UNKNOWN + 1] = {
656 	rdata_dname_to_string,
657 	rdata_dns_name_to_string,
658 	rdata_text_to_string,
659 	rdata_texts_to_string,
660 	rdata_byte_to_string,
661 	rdata_short_to_string,
662 	rdata_long_to_string,
663 	rdata_a_to_string,
664 	rdata_aaaa_to_string,
665 	rdata_rrtype_to_string,
666 	rdata_algorithm_to_string,
667 	rdata_certificate_type_to_string,
668 	rdata_period_to_string,
669 	rdata_time_to_string,
670 	rdata_base64_to_string,
671 	rdata_base32_to_string,
672 	rdata_hex_to_string,
673 	rdata_hexlen_to_string,
674 	rdata_nsap_to_string,
675 	rdata_apl_to_string,
676 	rdata_ipsecgateway_to_string,
677 	rdata_services_to_string,
678 	rdata_nxt_to_string,
679 	rdata_nsec_to_string,
680 	rdata_loc_to_string,
681 	rdata_ilnp64_to_string,
682 	rdata_eui48_to_string,
683 	rdata_eui64_to_string,
684 	rdata_long_text_to_string,
685 	rdata_tag_to_string,
686 	rdata_unknown_to_string
687 };
688 
689 int
690 rdata_atom_to_string(buffer_type *output, rdata_zoneformat_type type,
691 		     rdata_atom_type rdata, rr_type* record)
692 {
693 	return rdata_to_string_table[type](output, rdata, record);
694 }
695 
696 ssize_t
697 rdata_wireformat_to_rdata_atoms(region_type *region,
698 				domain_table_type *owners,
699 				uint16_t rrtype,
700 				uint16_t data_size,
701 				buffer_type *packet,
702 				rdata_atom_type **rdatas)
703 {
704 	size_t end = buffer_position(packet) + data_size;
705 	size_t i;
706 	rdata_atom_type temp_rdatas[MAXRDATALEN];
707 	rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype);
708 	region_type *temp_region;
709 
710 	assert(descriptor->maximum <= MAXRDATALEN);
711 
712 	if (!buffer_available(packet, data_size)) {
713 		return -1;
714 	}
715 
716 	temp_region = region_create(xalloc, free);
717 
718 	for (i = 0; i < descriptor->maximum; ++i) {
719 		int is_domain = 0;
720 		int is_normalized = 0;
721 		int is_wirestore = 0;
722 		size_t length = 0;
723 		int required = i < descriptor->minimum;
724 
725 		switch (rdata_atom_wireformat_type(rrtype, i)) {
726 		case RDATA_WF_COMPRESSED_DNAME:
727 		case RDATA_WF_UNCOMPRESSED_DNAME:
728 			is_domain = 1;
729 			is_normalized = 1;
730 			break;
731 		case RDATA_WF_LITERAL_DNAME:
732 			is_domain = 1;
733 			is_wirestore = 1;
734 			break;
735 		case RDATA_WF_BYTE:
736 			length = sizeof(uint8_t);
737 			break;
738 		case RDATA_WF_SHORT:
739 			length = sizeof(uint16_t);
740 			break;
741 		case RDATA_WF_LONG:
742 			length = sizeof(uint32_t);
743 			break;
744 		case RDATA_WF_TEXTS:
745 		case RDATA_WF_LONG_TEXT:
746 			length = end - buffer_position(packet);
747 			break;
748 		case RDATA_WF_TEXT:
749 		case RDATA_WF_BINARYWITHLENGTH:
750 			/* Length is stored in the first byte.  */
751 			length = 1;
752 			if (buffer_position(packet) + length <= end) {
753 				length += buffer_current(packet)[length - 1];
754 			}
755 			break;
756 		case RDATA_WF_A:
757 			length = sizeof(in_addr_t);
758 			break;
759 		case RDATA_WF_AAAA:
760 			length = IP6ADDRLEN;
761 			break;
762 		case RDATA_WF_ILNP64:
763 			length = IP6ADDRLEN/2;
764 			break;
765 		case RDATA_WF_EUI48:
766 			length = EUI48ADDRLEN;
767 			break;
768 		case RDATA_WF_EUI64:
769 			length = EUI64ADDRLEN;
770 			break;
771 		case RDATA_WF_BINARY:
772 			/* Remaining RDATA is binary.  */
773 			length = end - buffer_position(packet);
774 			break;
775 		case RDATA_WF_APL:
776 			length = (sizeof(uint16_t)    /* address family */
777 				  + sizeof(uint8_t)   /* prefix */
778 				  + sizeof(uint8_t)); /* length */
779 			if (buffer_position(packet) + length <= end) {
780 				/* Mask out negation bit.  */
781 				length += (buffer_current(packet)[length - 1]
782 					   & APL_LENGTH_MASK);
783 			}
784 			break;
785 		case RDATA_WF_IPSECGATEWAY:
786 			switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ {
787 			default:
788 			case IPSECKEY_NOGATEWAY:
789 				length = 0;
790 				break;
791 			case IPSECKEY_IP4:
792 				length = IP4ADDRLEN;
793 				break;
794 			case IPSECKEY_IP6:
795 				length = IP6ADDRLEN;
796 				break;
797 			case IPSECKEY_DNAME:
798 				is_domain = 1;
799 				is_normalized = 1;
800 				is_wirestore = 1;
801 				break;
802 			}
803 			break;
804 		}
805 
806 		if (is_domain) {
807 			const dname_type *dname;
808 
809 			if (!required && buffer_position(packet) == end) {
810 				break;
811 			}
812 
813 			dname = dname_make_from_packet(
814 				temp_region, packet, 1, is_normalized);
815 			if (!dname || buffer_position(packet) > end) {
816 				/* Error in domain name.  */
817 				region_destroy(temp_region);
818 				return -1;
819 			}
820 			if(is_wirestore) {
821 				temp_rdatas[i].data = (uint16_t *) region_alloc(
822                                 	region, sizeof(uint16_t) + ((size_t)dname->name_size));
823 				temp_rdatas[i].data[0] = dname->name_size;
824 				memcpy(temp_rdatas[i].data+1, dname_name(dname),
825 					dname->name_size);
826 			} else {
827 				temp_rdatas[i].domain
828 					= domain_table_insert(owners, dname);
829 				temp_rdatas[i].domain->usage ++;
830 			}
831 		} else {
832 			if (buffer_position(packet) + length > end) {
833 				if (required) {
834 					/* Truncated RDATA.  */
835 					region_destroy(temp_region);
836 					return -1;
837 				} else {
838 					break;
839 				}
840 			}
841 			if (!required && buffer_position(packet) == end) {
842 				break;
843 			}
844 
845 			temp_rdatas[i].data = (uint16_t *) region_alloc(
846 				region, sizeof(uint16_t) + length);
847 			temp_rdatas[i].data[0] = length;
848 			buffer_read(packet, temp_rdatas[i].data + 1, length);
849 		}
850 	}
851 
852 	if (buffer_position(packet) < end) {
853 		/* Trailing garbage.  */
854 		region_destroy(temp_region);
855 		return -1;
856 	}
857 
858 	*rdatas = (rdata_atom_type *) region_alloc_array_init(
859 		region, temp_rdatas, i, sizeof(rdata_atom_type));
860 	region_destroy(temp_region);
861 	return (ssize_t)i;
862 }
863 
864 size_t
865 rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor,
866 			      size_t rdata_count,
867 			      rdata_atom_type *rdatas)
868 {
869 	size_t result = 0;
870 	size_t i;
871 	for (i = 0; i < rdata_count; ++i) {
872 		if (rdata_atom_is_domain(descriptor->type, i)) {
873 			result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size;
874 		} else {
875 			result += rdata_atom_size(rdatas[i]);
876 		}
877 	}
878 	return result;
879 }
880 
881 int
882 rdata_atoms_to_unknown_string(buffer_type *output,
883 			      rrtype_descriptor_type *descriptor,
884 			      size_t rdata_count,
885 			      rdata_atom_type *rdatas)
886 {
887 	size_t i;
888 	size_t size =
889 		rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas);
890 	buffer_printf(output, " \\# %lu ", (unsigned long) size);
891 	for (i = 0; i < rdata_count; ++i) {
892 		if (rdata_atom_is_domain(descriptor->type, i)) {
893 			const dname_type *dname =
894 				domain_dname(rdata_atom_domain(rdatas[i]));
895 			hex_to_string(
896 				output, dname_name(dname), dname->name_size);
897 		} else {
898 			hex_to_string(output, rdata_atom_data(rdatas[i]),
899 				rdata_atom_size(rdatas[i]));
900 		}
901 	}
902 	return 1;
903 }
904 
905 int
906 print_rdata(buffer_type *output, rrtype_descriptor_type *descriptor,
907 	    rr_type *record)
908 {
909 	size_t i;
910 	size_t saved_position = buffer_position(output);
911 
912 	for (i = 0; i < record->rdata_count; ++i) {
913 		if (i == 0) {
914 			buffer_printf(output, "\t");
915 		} else if (descriptor->type == TYPE_SOA && i == 2) {
916 			buffer_printf(output, " (\n\t\t");
917 		} else {
918 			buffer_printf(output, " ");
919 		}
920 		if (!rdata_atom_to_string(
921 			    output,
922 			    (rdata_zoneformat_type) descriptor->zoneformat[i],
923 			    record->rdatas[i], record))
924 		{
925 			buffer_set_position(output, saved_position);
926 			return 0;
927 		}
928 	}
929 	if (descriptor->type == TYPE_SOA) {
930 		buffer_printf(output, " )");
931 	}
932 
933 	return 1;
934 }
935 
936 
937