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