xref: /netbsd/lib/libc/nameser/ns_print.c (revision 6550d01e)
1 /*	$NetBSD: ns_print.c,v 1.10 2009/04/12 19:43:37 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1996-1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/cdefs.h>
21 #ifndef lint
22 #ifdef notdef
23 static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp";
24 #else
25 __RCSID("$NetBSD: ns_print.c,v 1.10 2009/04/12 19:43:37 christos Exp $");
26 #endif
27 #endif
28 
29 /* Import. */
30 
31 #include "port_before.h"
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 
36 #include <netinet/in.h>
37 #include <arpa/nameser.h>
38 #include <arpa/inet.h>
39 
40 #include <isc/assertions.h>
41 #include <isc/dst.h>
42 #include <errno.h>
43 #include <resolv.h>
44 #include <string.h>
45 #include <ctype.h>
46 
47 #include "port_after.h"
48 
49 #ifdef SPRINTF_CHAR
50 # define SPRINTF(x) strlen(sprintf/**/x)
51 #else
52 # define SPRINTF(x) ((size_t)sprintf x)
53 #endif
54 
55 /* Forward. */
56 
57 static size_t	prune_origin(const char *name, const char *origin);
58 static int	charstr(const u_char *rdata, const u_char *edata,
59 			char **buf, size_t *buflen);
60 static int	addname(const u_char *msg, size_t msglen,
61 			const u_char **p, const char *origin,
62 			char **buf, size_t *buflen);
63 static void	addlen(size_t len, char **buf, size_t *buflen);
64 static int	addstr(const char *src, size_t len,
65 		       char **buf, size_t *buflen);
66 static int	addtab(size_t len, size_t target, int spaced,
67 		       char **buf, size_t *buflen);
68 
69 /* Macros. */
70 
71 #define	T(x) \
72 	do { \
73 		if ((x) < 0) \
74 			return (-1); \
75 	} while (/*CONSTCOND*/0)
76 
77 static const char base32hex[] =
78         "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
79 
80 /* Public. */
81 
82 /*%
83  *	Convert an RR to presentation format.
84  *
85  * return:
86  *\li	Number of characters written to buf, or -1 (check errno).
87  */
88 int
89 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
90 	    const char *name_ctx, const char *origin,
91 	    char *buf, size_t buflen)
92 {
93 	int n;
94 
95 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
96 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
97 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
98 			 name_ctx, origin, buf, buflen);
99 	return (n);
100 }
101 
102 /*%
103  *	Convert the fields of an RR into presentation format.
104  *
105  * return:
106  *\li	Number of characters written to buf, or -1 (check errno).
107  */
108 int
109 ns_sprintrrf(const u_char *msg, size_t msglen,
110 	    const char *name, ns_class class, ns_type type,
111 	    u_long ttl, const u_char *rdata, size_t rdlen,
112 	    const char *name_ctx, const char *origin,
113 	    char *buf, size_t buflen)
114 {
115 	const char *obuf = buf;
116 	const u_char *edata = rdata + rdlen;
117 	int spaced = 0;
118 
119 	const char *comment;
120 	char tmp[100];
121 	int len, x;
122 
123 	/*
124 	 * Owner.
125 	 */
126 	if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
127 		T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
128 	} else {
129 		len = prune_origin(name, origin);
130 		if (*name == '\0') {
131 			goto root;
132 		} else if (len == 0) {
133 			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
134 		} else {
135 			T(addstr(name, (size_t)len, &buf, &buflen));
136 			/* Origin not used or not root, and no trailing dot? */
137 			if (((origin == NULL || origin[0] == '\0') ||
138 			    (origin[0] != '.' && origin[1] != '\0' &&
139 			    name[len] == '\0')) && name[len - 1] != '.') {
140  root:
141 				T(addstr(".", (size_t)1, &buf, &buflen));
142 				len++;
143 			}
144 			T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
145 		}
146 	}
147 
148 	/*
149 	 * TTL, Class, Type.
150 	 */
151 	T(x = ns_format_ttl(ttl, buf, buflen));
152 	addlen((size_t)x, &buf, &buflen);
153 	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
154 	T(addstr(tmp, (size_t)len, &buf, &buflen));
155 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
156 
157 	/*
158 	 * RData.
159 	 */
160 	switch (type) {
161 	case ns_t_a:
162 		if (rdlen != (size_t)NS_INADDRSZ)
163 			goto formerr;
164 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
165 		addlen(strlen(buf), &buf, &buflen);
166 		break;
167 
168 	case ns_t_cname:
169 	case ns_t_mb:
170 	case ns_t_mg:
171 	case ns_t_mr:
172 	case ns_t_ns:
173 	case ns_t_ptr:
174 	case ns_t_dname:
175 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
176 		break;
177 
178 	case ns_t_hinfo:
179 	case ns_t_isdn:
180 		/* First word. */
181 		T(len = charstr(rdata, edata, &buf, &buflen));
182 		if (len == 0)
183 			goto formerr;
184 		rdata += len;
185 		T(addstr(" ", (size_t)1, &buf, &buflen));
186 
187 
188 		/* Second word, optional in ISDN records. */
189 		if (type == ns_t_isdn && rdata == edata)
190 			break;
191 
192 		T(len = charstr(rdata, edata, &buf, &buflen));
193 		if (len == 0)
194 			goto formerr;
195 		rdata += len;
196 		break;
197 
198 	case ns_t_soa: {
199 		u_long t;
200 
201 		/* Server name. */
202 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
203 		T(addstr(" ", (size_t)1, &buf, &buflen));
204 
205 		/* Administrator name. */
206 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
207 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
208 		spaced = 0;
209 
210 		if ((edata - rdata) != 5*NS_INT32SZ)
211 			goto formerr;
212 
213 		/* Serial number. */
214 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
215 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
216 		len = SPRINTF((tmp, "%lu", t));
217 		T(addstr(tmp, (size_t)len, &buf, &buflen));
218 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
219 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
220 		spaced = 0;
221 
222 		/* Refresh interval. */
223 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
224 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
225 		T(len = ns_format_ttl(t, buf, buflen));
226 		addlen((size_t)len, &buf, &buflen);
227 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
228 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
229 		spaced = 0;
230 
231 		/* Retry interval. */
232 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
233 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
234 		T(len = ns_format_ttl(t, buf, buflen));
235 		addlen((size_t)len, &buf, &buflen);
236 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
237 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
238 		spaced = 0;
239 
240 		/* Expiry. */
241 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
242 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
243 		T(len = ns_format_ttl(t, buf, buflen));
244 		addlen((size_t)len, &buf, &buflen);
245 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
246 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
247 		spaced = 0;
248 
249 		/* Minimum TTL. */
250 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
251 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
252 		T(len = ns_format_ttl(t, buf, buflen));
253 		addlen((size_t)len, &buf, &buflen);
254 		T(addstr(" )", (size_t)2, &buf, &buflen));
255 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
256 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
257 
258 		break;
259 	    }
260 
261 	case ns_t_mx:
262 	case ns_t_afsdb:
263 	case ns_t_rt:
264 	case ns_t_kx: {
265 		u_int t;
266 
267 		if (rdlen < (size_t)NS_INT16SZ)
268 			goto formerr;
269 
270 		/* Priority. */
271 		t = ns_get16(rdata);
272 		rdata += NS_INT16SZ;
273 		len = SPRINTF((tmp, "%u ", t));
274 		T(addstr(tmp, (size_t)len, &buf, &buflen));
275 
276 		/* Target. */
277 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
278 
279 		break;
280 	    }
281 
282 	case ns_t_px: {
283 		u_int t;
284 
285 		if (rdlen < (size_t)NS_INT16SZ)
286 			goto formerr;
287 
288 		/* Priority. */
289 		t = ns_get16(rdata);
290 		rdata += NS_INT16SZ;
291 		len = SPRINTF((tmp, "%u ", t));
292 		T(addstr(tmp, (size_t)len, &buf, &buflen));
293 
294 		/* Name1. */
295 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
296 		T(addstr(" ", (size_t)1, &buf, &buflen));
297 
298 		/* Name2. */
299 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
300 
301 		break;
302 	    }
303 
304 	case ns_t_x25:
305 		T(len = charstr(rdata, edata, &buf, &buflen));
306 		if (len == 0)
307 			goto formerr;
308 		rdata += len;
309 		break;
310 
311 	case ns_t_txt:
312 	case ns_t_spf:
313 		while (rdata < edata) {
314 			T(len = charstr(rdata, edata, &buf, &buflen));
315 			if (len == 0)
316 				goto formerr;
317 			rdata += len;
318 			if (rdata < edata)
319 				T(addstr(" ", (size_t)1, &buf, &buflen));
320 		}
321 		break;
322 
323 	case ns_t_nsap: {
324 		char t[2+255*3];
325 
326 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
327 		T(addstr(t, strlen(t), &buf, &buflen));
328 		break;
329 	    }
330 
331 	case ns_t_aaaa:
332 		if (rdlen != (size_t)NS_IN6ADDRSZ)
333 			goto formerr;
334 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
335 		addlen(strlen(buf), &buf, &buflen);
336 		break;
337 
338 	case ns_t_loc: {
339 		char t[255];
340 
341 		/* XXX protocol format checking? */
342 		(void) loc_ntoa(rdata, t);
343 		T(addstr(t, strlen(t), &buf, &buflen));
344 		break;
345 	    }
346 
347 	case ns_t_naptr: {
348 		u_int order, preference;
349 		char t[50];
350 
351 		if (rdlen < 2U*NS_INT16SZ)
352 			goto formerr;
353 
354 		/* Order, Precedence. */
355 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
356 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
357 		len = SPRINTF((t, "%u %u ", order, preference));
358 		T(addstr(t, (size_t)len, &buf, &buflen));
359 
360 		/* Flags. */
361 		T(len = charstr(rdata, edata, &buf, &buflen));
362 		if (len == 0)
363 			goto formerr;
364 		rdata += len;
365 		T(addstr(" ", (size_t)1, &buf, &buflen));
366 
367 		/* Service. */
368 		T(len = charstr(rdata, edata, &buf, &buflen));
369 		if (len == 0)
370 			goto formerr;
371 		rdata += len;
372 		T(addstr(" ", (size_t)1, &buf, &buflen));
373 
374 		/* Regexp. */
375 		T(len = charstr(rdata, edata, &buf, &buflen));
376 		if (len < 0)
377 			return (-1);
378 		if (len == 0)
379 			goto formerr;
380 		rdata += len;
381 		T(addstr(" ", (size_t)1, &buf, &buflen));
382 
383 		/* Server. */
384 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
385 		break;
386 	    }
387 
388 	case ns_t_srv: {
389 		u_int priority, weight, port;
390 		char t[50];
391 
392 		if (rdlen < 3U*NS_INT16SZ)
393 			goto formerr;
394 
395 		/* Priority, Weight, Port. */
396 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
397 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
398 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
399 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
400 		T(addstr(t, (size_t)len, &buf, &buflen));
401 
402 		/* Server. */
403 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
404 		break;
405 	    }
406 
407 	case ns_t_minfo:
408 	case ns_t_rp:
409 		/* Name1. */
410 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
411 		T(addstr(" ", (size_t)1, &buf, &buflen));
412 
413 		/* Name2. */
414 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
415 
416 		break;
417 
418 	case ns_t_wks: {
419 		int n, lcnt;
420 
421 		if (rdlen < 1U + NS_INT32SZ)
422 			goto formerr;
423 
424 		/* Address. */
425 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
426 		addlen(strlen(buf), &buf, &buflen);
427 		rdata += NS_INADDRSZ;
428 
429 		/* Protocol. */
430 		len = SPRINTF((tmp, " %u ( ", *rdata));
431 		T(addstr(tmp, (size_t)len, &buf, &buflen));
432 		rdata += NS_INT8SZ;
433 
434 		/* Bit map. */
435 		n = 0;
436 		lcnt = 0;
437 		while (rdata < edata) {
438 			u_int c = *rdata++;
439 			do {
440 				if (c & 0200) {
441 					if (lcnt == 0) {
442 						T(addstr("\n\t\t\t\t", (size_t)5,
443 							 &buf, &buflen));
444 						lcnt = 10;
445 						spaced = 0;
446 					}
447 					len = SPRINTF((tmp, "%d ", n));
448 					T(addstr(tmp, (size_t)len, &buf, &buflen));
449 					lcnt--;
450 				}
451 				c <<= 1;
452 			} while (++n & 07);
453 		}
454 		T(addstr(")", (size_t)1, &buf, &buflen));
455 
456 		break;
457 	    }
458 
459 	case ns_t_key:
460 	case ns_t_dnskey: {
461 		char base64_key[NS_MD5RSA_MAX_BASE64];
462 		u_int keyflags, protocol, algorithm, key_id;
463 		const char *leader;
464 		int n;
465 
466 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
467 			goto formerr;
468 
469 		/* Key flags, Protocol, Algorithm. */
470 #ifndef _LIBC
471 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
472 #else
473 		key_id = 0;
474 #endif
475 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
476 		protocol = *rdata++;
477 		algorithm = *rdata++;
478 		len = SPRINTF((tmp, "0x%04x %u %u",
479 			       keyflags, protocol, algorithm));
480 		T(addstr(tmp, (size_t)len, &buf, &buflen));
481 
482 		/* Public key data. */
483 		len = b64_ntop(rdata, (size_t)(edata - rdata),
484 			       base64_key, sizeof base64_key);
485 		if (len < 0)
486 			goto formerr;
487 		if (len > 15) {
488 			T(addstr(" (", (size_t)2, &buf, &buflen));
489 			leader = "\n\t\t";
490 			spaced = 0;
491 		} else
492 			leader = " ";
493 		for (n = 0; n < len; n += 48) {
494 			T(addstr(leader, strlen(leader), &buf, &buflen));
495 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
496 				 &buf, &buflen));
497 		}
498 		if (len > 15)
499 			T(addstr(" )", (size_t)2, &buf, &buflen));
500 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
501 		T(addstr(tmp, (size_t)n, &buf, &buflen));
502 
503 		break;
504 	    }
505 
506 	case ns_t_sig:
507 	case ns_t_rrsig: {
508 		char base64_key[NS_MD5RSA_MAX_BASE64];
509 		u_int typ, algorithm, labels, footprint;
510 		const char *leader;
511 		u_long t;
512 		int n;
513 
514 		if (rdlen < 22U)
515 			goto formerr;
516 
517 		/* Type covered, Algorithm, Label count, Original TTL. */
518 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
519 		algorithm = *rdata++;
520 		labels = *rdata++;
521 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
522 		len = SPRINTF((tmp, "%s %d %d %lu ",
523 			       p_type((int)typ), algorithm, labels, t));
524 		T(addstr(tmp, (size_t)len, &buf, &buflen));
525 		if (labels > (u_int)dn_count_labels(name))
526 			goto formerr;
527 
528 		/* Signature expiry. */
529 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
530 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
531 		T(addstr(tmp, (size_t)len, &buf, &buflen));
532 
533 		/* Time signed. */
534 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
535 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
536 		T(addstr(tmp, (size_t)len, &buf, &buflen));
537 
538 		/* Signature Footprint. */
539 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
540 		len = SPRINTF((tmp, "%u ", footprint));
541 		T(addstr(tmp, (size_t)len, &buf, &buflen));
542 
543 		/* Signer's name. */
544 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
545 
546 		/* Signature. */
547 		len = b64_ntop(rdata, (size_t)(edata - rdata),
548 			       base64_key, sizeof base64_key);
549 		if (len > 15) {
550 			T(addstr(" (", (size_t)2, &buf, &buflen));
551 			leader = "\n\t\t";
552 			spaced = 0;
553 		} else
554 			leader = " ";
555 		if (len < 0)
556 			goto formerr;
557 		for (n = 0; n < len; n += 48) {
558 			T(addstr(leader, strlen(leader), &buf, &buflen));
559 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
560 				 &buf, &buflen));
561 		}
562 		if (len > 15)
563 			T(addstr(" )", (size_t)2, &buf, &buflen));
564 		break;
565 	    }
566 
567 	case ns_t_nxt: {
568 		int n, c;
569 
570 		/* Next domain name. */
571 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
572 
573 		/* Type bit map. */
574 		n = edata - rdata;
575 		for (c = 0; c < n*8; c++)
576 			if (NS_NXT_BIT_ISSET(c, rdata)) {
577 				len = SPRINTF((tmp, " %s", p_type(c)));
578 				T(addstr(tmp, (size_t)len, &buf, &buflen));
579 			}
580 		break;
581 	    }
582 
583 	case ns_t_cert: {
584 		u_int c_type, key_tag, alg;
585 		int n;
586 		unsigned int siz;
587 		char base64_cert[8192], tmp1[40];
588 		const char *leader;
589 
590 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
591 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
592 		alg = (u_int) *rdata++;
593 
594 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
595 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
596 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
597 		if (siz > sizeof(base64_cert) * 3/4) {
598 			const char *str = "record too long to print";
599 			T(addstr(str, strlen(str), &buf, &buflen));
600 		}
601 		else {
602 			len = b64_ntop(rdata, (size_t)(edata-rdata),
603 			    base64_cert, siz);
604 
605 			if (len < 0)
606 				goto formerr;
607 			else if (len > 15) {
608 				T(addstr(" (", (size_t)2, &buf, &buflen));
609 				leader = "\n\t\t";
610 				spaced = 0;
611 			}
612 			else
613 				leader = " ";
614 
615 			for (n = 0; n < len; n += 48) {
616 				T(addstr(leader, strlen(leader),
617 					 &buf, &buflen));
618 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
619 					 &buf, &buflen));
620 			}
621 			if (len > 15)
622 				T(addstr(" )", (size_t)2, &buf, &buflen));
623 		}
624 		break;
625 	    }
626 
627 	case ns_t_tkey: {
628 		/* KJD - need to complete this */
629 		u_long t;
630 		int mode, err, keysize;
631 
632 		/* Algorithm name. */
633 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
634 		T(addstr(" ", (size_t)1, &buf, &buflen));
635 
636 		/* Inception. */
637 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
638 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
639 		T(addstr(tmp, (size_t)len, &buf, &buflen));
640 
641 		/* Experation. */
642 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
643 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
644 		T(addstr(tmp, (size_t)len, &buf, &buflen));
645 
646 		/* Mode , Error, Key Size. */
647 		/* Priority, Weight, Port. */
648 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
649 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
650 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
651 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
652 		T(addstr(tmp, (size_t)len, &buf, &buflen));
653 
654 		/* XXX need to dump key, print otherdata length & other data */
655 		break;
656 	    }
657 
658 	case ns_t_tsig: {
659 		/* BEW - need to complete this */
660 		int n;
661 
662 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
663 		T(addstr(" ", (size_t)1, &buf, &buflen));
664 		rdata += 8; /*%< time */
665 		n = ns_get16(rdata); rdata += INT16SZ;
666 		rdata += n; /*%< sig */
667 		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
668 		sprintf(buf, "%d", ns_get16(rdata));
669 		rdata += INT16SZ;
670 		addlen(strlen(buf), &buf, &buflen);
671 		break;
672 	    }
673 
674 	case ns_t_a6: {
675 		struct in6_addr a;
676 		int pbyte, pbit;
677 
678 		/* prefix length */
679 		if (rdlen == 0U) goto formerr;
680 		len = SPRINTF((tmp, "%d ", *rdata));
681 		T(addstr(tmp, (size_t)len, &buf, &buflen));
682 		pbit = *rdata;
683 		if (pbit > 128) goto formerr;
684 		pbyte = (pbit & ~7) / 8;
685 		rdata++;
686 
687 		/* address suffix: provided only when prefix len != 128 */
688 		if (pbit < 128) {
689 			if (rdata + pbyte >= edata) goto formerr;
690 			memset(&a, 0, sizeof(a));
691 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
692 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
693 			addlen(strlen(buf), &buf, &buflen);
694 			rdata += sizeof(a) - pbyte;
695 		}
696 
697 		/* prefix name: provided only when prefix len > 0 */
698 		if (pbit == 0)
699 			break;
700 		if (rdata >= edata) goto formerr;
701 		T(addstr(" ", (size_t)1, &buf, &buflen));
702 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
703 
704 		break;
705 	    }
706 
707 	case ns_t_opt: {
708 		len = SPRINTF((tmp, "%u bytes", class));
709 		T(addstr(tmp, (size_t)len, &buf, &buflen));
710 		break;
711 	    }
712 
713 	case ns_t_ds:
714 	case ns_t_dlv:
715 	case ns_t_sshfp: {
716 		u_int t;
717 
718 		if (type == ns_t_ds || type == ns_t_dlv) {
719 			if (rdlen < 4U) goto formerr;
720 			t = ns_get16(rdata);
721 			rdata += NS_INT16SZ;
722 			len = SPRINTF((tmp, "%u ", t));
723 			T(addstr(tmp, (size_t)len, &buf, &buflen));
724 		} else
725 			if (rdlen < 2U) goto formerr;
726 
727 		len = SPRINTF((tmp, "%u ", *rdata));
728 		T(addstr(tmp, (size_t)len, &buf, &buflen));
729 		rdata++;
730 
731 		len = SPRINTF((tmp, "%u ", *rdata));
732 		T(addstr(tmp, (size_t)len, &buf, &buflen));
733 		rdata++;
734 
735 		while (rdata < edata) {
736 			len = SPRINTF((tmp, "%02X", *rdata));
737 			T(addstr(tmp, (size_t)len, &buf, &buflen));
738 			rdata++;
739 		}
740 		break;
741 	    }
742 
743 	case ns_t_nsec3:
744 	case ns_t_nsec3param: {
745 		u_int t, w, l, j, k, c;
746 
747 		len = SPRINTF((tmp, "%u ", *rdata));
748 		T(addstr(tmp, (size_t)len, &buf, &buflen));
749 		rdata++;
750 
751 		len = SPRINTF((tmp, "%u ", *rdata));
752 		T(addstr(tmp, (size_t)len, &buf, &buflen));
753 		rdata++;
754 
755 		t = ns_get16(rdata);
756 		rdata += NS_INT16SZ;
757 		len = SPRINTF((tmp, "%u ", t));
758 		T(addstr(tmp, (size_t)len, &buf, &buflen));
759 
760 		t = *rdata++;
761 		if (t == 0) {
762 			T(addstr("-", 1, &buf, &buflen));
763 		} else {
764 			while (t-- > 0) {
765 				len = SPRINTF((tmp, "%02X", *rdata));
766 				T(addstr(tmp, (size_t)len, &buf, &buflen));
767 				rdata++;
768 			}
769 		}
770 		if (type == ns_t_nsec3param)
771 			break;
772 		T(addstr(" ", 1, &buf, &buflen));
773 
774 		t = *rdata++;
775 		while (t > 0) {
776 			switch (t) {
777 			case 1:
778 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
779 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)];
780 				tmp[2] = tmp[3] = tmp[4] = '=';
781 				tmp[5] = tmp[6] = tmp[7] = '=';
782 				break;
783 			case 2:
784 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
785 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
786 						   (((uint32_t)rdata[1]>>6)&0x03)];
787 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
788 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)];
789 				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
790 				break;
791 			case 3:
792 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
793 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
794 						   (((uint32_t)rdata[1]>>6)&0x03)];
795 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
796 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
797 						   (((uint32_t)rdata[2]>>4)&0x0f)];
798 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)];
799 				tmp[5] = tmp[6] = tmp[7] = '=';
800 				break;
801 			case 4:
802 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
803 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
804 						   (((uint32_t)rdata[1]>>6)&0x03)];
805 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
806 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
807 						   (((uint32_t)rdata[2]>>4)&0x0f)];
808 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
809 						   (((uint32_t)rdata[3]>>7)&0x01)];
810 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
811 				tmp[6] = base32hex[((uint32_t)rdata[3]<<3)&0x18];
812 				tmp[7] = '=';
813 				break;
814 			default:
815 				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
816 				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
817 						   (((uint32_t)rdata[1]>>6)&0x03)];
818 				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
819 				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
820 						   (((uint32_t)rdata[2]>>4)&0x0f)];
821 				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
822 						   (((uint32_t)rdata[3]>>7)&0x01)];
823 				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
824 				tmp[6] = base32hex[(((uint32_t)rdata[3]<<3)&0x18)|
825 						   (((uint32_t)rdata[4]>>5)&0x07)];
826 				tmp[7] = base32hex[(rdata[4]&0x1f)];
827 				break;
828 			}
829 			T(addstr(tmp, 8, &buf, &buflen));
830 			if (t >= 5) {
831 				rdata += 5;
832 				t -= 5;
833 			} else {
834 				rdata += t;
835 				t -= t;
836 			}
837 		}
838 
839 		while (rdata < edata) {
840 			w = *rdata++;
841 			l = *rdata++;
842 			for (j = 0; j < l; j++) {
843 				if (rdata[j] == 0)
844 					continue;
845 				for (k = 0; k < 8; k++) {
846 					if ((rdata[j] & (0x80 >> k)) == 0)
847 						continue;
848 					c = w * 256 + j * 8 + k;
849 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
850 					T(addstr(tmp, (size_t)len, &buf, &buflen));
851 				}
852 			}
853 			rdata += l;
854 		}
855 		break;
856 	    }
857 
858 	case ns_t_nsec: {
859 		u_int w, l, j, k, c;
860 
861 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
862 
863 		while (rdata < edata) {
864 			w = *rdata++;
865 			l = *rdata++;
866 			for (j = 0; j < l; j++) {
867 				if (rdata[j] == 0)
868 					continue;
869 				for (k = 0; k < 8; k++) {
870 					if ((rdata[j] & (0x80 >> k)) == 0)
871 						continue;
872 					c = w * 256 + j * 8 + k;
873 					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
874 					T(addstr(tmp, (size_t)len, &buf, &buflen));
875 				}
876 			}
877 			rdata += l;
878 		}
879 		break;
880 	    }
881 
882 	case ns_t_dhcid: {
883 		int n;
884 		unsigned int siz;
885 		char base64_dhcid[8192];
886 		const char *leader;
887 
888 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
889 		if (siz > sizeof(base64_dhcid) * 3/4) {
890 			const char *str = "record too long to print";
891 			T(addstr(str, strlen(str), &buf, &buflen));
892 		} else {
893 			len = b64_ntop(rdata, (size_t)(edata-rdata),
894 			    base64_dhcid, siz);
895 
896 			if (len < 0)
897 				goto formerr;
898 
899 			else if (len > 15) {
900 				T(addstr(" (", 2, &buf, &buflen));
901 				leader = "\n\t\t";
902 				spaced = 0;
903 			}
904 			else
905 				leader = " ";
906 
907 			for (n = 0; n < len; n += 48) {
908 				T(addstr(leader, strlen(leader),
909 					 &buf, &buflen));
910 				T(addstr(base64_dhcid + n,
911 				    (size_t)MIN(len - n, 48), &buf, &buflen));
912 			}
913 			if (len > 15)
914 				T(addstr(" )", 2, &buf, &buflen));
915 		}
916 		break;
917 	}
918 
919 	case ns_t_ipseckey: {
920 		int n;
921 		unsigned int siz;
922 		char base64_key[8192];
923 		const char *leader;
924 
925 		if (rdlen < 2)
926 			goto formerr;
927 
928 		switch (rdata[1]) {
929 		case 0:
930 		case 3:
931 			if (rdlen < 3)
932 				goto formerr;
933 			break;
934 		case 1:
935 			if (rdlen < 7)
936 				goto formerr;
937 			break;
938 		case 2:
939 			if (rdlen < 19)
940 				goto formerr;
941 			break;
942 		default:
943 			comment = "unknown IPSECKEY gateway type";
944 			goto hexify;
945 		}
946 
947 		len = SPRINTF((tmp, "%u ", *rdata));
948 		T(addstr(tmp, (size_t)len, &buf, &buflen));
949 		rdata++;
950 
951 		len = SPRINTF((tmp, "%u ", *rdata));
952 		T(addstr(tmp, (size_t)len, &buf, &buflen));
953 		rdata++;
954 
955 		len = SPRINTF((tmp, "%u ", *rdata));
956 		T(addstr(tmp, (size_t)len, &buf, &buflen));
957 		rdata++;
958 
959 		switch (rdata[-2]) {
960 		case 0:
961 			T(addstr(".", 1, &buf, &buflen));
962 			break;
963 		case 1:
964 			(void) inet_ntop(AF_INET, rdata, buf, buflen);
965 			addlen(strlen(buf), &buf, &buflen);
966 			rdata += 4;
967 			break;
968 		case 2:
969 			(void) inet_ntop(AF_INET6, rdata, buf, buflen);
970 			addlen(strlen(buf), &buf, &buflen);
971 			rdata += 16;
972 			break;
973 		case 3:
974 			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
975 			break;
976 		}
977 
978 		if (rdata >= edata)
979 			break;
980 
981 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
982 		if (siz > sizeof(base64_key) * 3/4) {
983 			const char *str = "record too long to print";
984 			T(addstr(str, strlen(str), &buf, &buflen));
985 		} else {
986 			len = b64_ntop(rdata, (size_t)(edata-rdata),
987 			    base64_key, siz);
988 
989 			if (len < 0)
990 				goto formerr;
991 
992 			else if (len > 15) {
993 				T(addstr(" (", 2, &buf, &buflen));
994 				leader = "\n\t\t";
995 				spaced = 0;
996 			}
997 			else
998 				leader = " ";
999 
1000 			for (n = 0; n < len; n += 48) {
1001 				T(addstr(leader, strlen(leader),
1002 					 &buf, &buflen));
1003 				T(addstr(base64_key + n,
1004 				    (size_t)MIN(len - n, 48), &buf, &buflen));
1005 			}
1006 			if (len > 15)
1007 				T(addstr(" )", 2, &buf, &buflen));
1008 		}
1009 		break;
1010 	}
1011 
1012 	case ns_t_hip: {
1013 		unsigned int i, hip_len, algorithm, key_len;
1014 		char base64_key[NS_MD5RSA_MAX_BASE64];
1015 		unsigned int siz;
1016 		const char *leader = "\n\t\t\t\t\t";
1017 
1018 		hip_len = *rdata++;
1019 		algorithm = *rdata++;
1020 		key_len = ns_get16(rdata);
1021 		rdata += NS_INT16SZ;
1022 
1023 		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
1024 		if (siz > sizeof(base64_key) * 3/4) {
1025 			const char *str = "record too long to print";
1026 			T(addstr(str, strlen(str), &buf, &buflen));
1027 		} else {
1028 			len = sprintf(tmp, "( %u ", algorithm);
1029 			T(addstr(tmp, (size_t)len, &buf, &buflen));
1030 
1031 			for (i = 0; i < hip_len; i++) {
1032 				len = sprintf(tmp, "%02X", *rdata);
1033 				T(addstr(tmp, (size_t)len, &buf, &buflen));
1034 				rdata++;
1035 			}
1036 			T(addstr(leader, strlen(leader), &buf, &buflen));
1037 
1038 			len = b64_ntop(rdata, key_len, base64_key, siz);
1039 			if (len < 0)
1040 				goto formerr;
1041 
1042 			T(addstr(base64_key, (size_t)len, &buf, &buflen));
1043 
1044 			rdata += key_len;
1045 			while (rdata < edata) {
1046 				T(addstr(leader, strlen(leader), &buf, &buflen));
1047 				T(addname(msg, msglen, &rdata, origin,
1048 					  &buf, &buflen));
1049 			}
1050 			T(addstr(" )", 2, &buf, &buflen));
1051 		}
1052 		break;
1053 	}
1054 
1055 	default:
1056 		comment = "unknown RR type";
1057 		goto hexify;
1058 	}
1059 	return (buf - obuf);
1060  formerr:
1061 	comment = "RR format error";
1062  hexify: {
1063 	int n, m;
1064 	char *p;
1065 
1066 	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
1067 		       rdlen != 0U ? " (" : "", comment));
1068 	T(addstr(tmp, (size_t)len, &buf, &buflen));
1069 	while (rdata < edata) {
1070 		p = tmp;
1071 		p += SPRINTF((p, "\n\t"));
1072 		spaced = 0;
1073 		n = MIN(16, edata - rdata);
1074 		for (m = 0; m < n; m++)
1075 			p += SPRINTF((p, "%02x ", rdata[m]));
1076 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
1077 		if (n < 16) {
1078 			T(addstr(")", (size_t)1, &buf, &buflen));
1079 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
1080 		}
1081 		p = tmp;
1082 		p += SPRINTF((p, "; "));
1083 		for (m = 0; m < n; m++)
1084 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
1085 				? rdata[m]
1086 				: '.';
1087 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
1088 		rdata += n;
1089 	}
1090 	return (buf - obuf);
1091     }
1092 }
1093 
1094 /* Private. */
1095 
1096 /*%
1097  * size_t
1098  * prune_origin(name, origin)
1099  *	Find out if the name is at or under the current origin.
1100  * return:
1101  *	Number of characters in name before start of origin,
1102  *	or length of name if origin does not match.
1103  * notes:
1104  *	This function should share code with samedomain().
1105  */
1106 static size_t
1107 prune_origin(const char *name, const char *origin) {
1108 	const char *oname = name;
1109 
1110 	while (*name != '\0') {
1111 		if (origin != NULL && ns_samename(name, origin) == 1)
1112 			return (name - oname - (name > oname));
1113 		while (*name != '\0') {
1114 			if (*name == '\\') {
1115 				name++;
1116 				/* XXX need to handle \nnn form. */
1117 				if (*name == '\0')
1118 					break;
1119 			} else if (*name == '.') {
1120 				name++;
1121 				break;
1122 			}
1123 			name++;
1124 		}
1125 	}
1126 	return (name - oname);
1127 }
1128 
1129 /*%
1130  * int
1131  * charstr(rdata, edata, buf, buflen)
1132  *	Format a <character-string> into the presentation buffer.
1133  * return:
1134  *	Number of rdata octets consumed
1135  *	0 for protocol format error
1136  *	-1 for output buffer error
1137  * side effects:
1138  *	buffer is advanced on success.
1139  */
1140 static int
1141 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
1142 	const u_char *odata = rdata;
1143 	size_t save_buflen = *buflen;
1144 	char *save_buf = *buf;
1145 
1146 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
1147 		goto enospc;
1148 	if (rdata < edata) {
1149 		int n = *rdata;
1150 
1151 		if (rdata + 1 + n <= edata) {
1152 			rdata++;
1153 			while (n-- > 0) {
1154 				if (strchr("\n\"\\", *rdata) != NULL)
1155 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
1156 						goto enospc;
1157 				if (addstr((const char *)rdata, (size_t)1,
1158 					   buf, buflen) < 0)
1159 					goto enospc;
1160 				rdata++;
1161 			}
1162 		}
1163 	}
1164 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
1165 		goto enospc;
1166 	return (rdata - odata);
1167  enospc:
1168 	errno = ENOSPC;
1169 	*buf = save_buf;
1170 	*buflen = save_buflen;
1171 	return (-1);
1172 }
1173 
1174 static int
1175 addname(const u_char *msg, size_t msglen,
1176 	const u_char **pp, const char *origin,
1177 	char **buf, size_t *buflen)
1178 {
1179 	size_t newlen, save_buflen = *buflen;
1180 	char *save_buf = *buf;
1181 	int n;
1182 
1183 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
1184 	if (n < 0)
1185 		goto enospc;	/*%< Guess. */
1186 	newlen = prune_origin(*buf, origin);
1187 	if (**buf == '\0') {
1188 		goto root;
1189 	} else if (newlen == 0U) {
1190 		/* Use "@" instead of name. */
1191 		if (newlen + 2 > *buflen)
1192 			goto enospc;        /* No room for "@\0". */
1193 		(*buf)[newlen++] = '@';
1194 		(*buf)[newlen] = '\0';
1195 	} else {
1196 		if (((origin == NULL || origin[0] == '\0') ||
1197 		    (origin[0] != '.' && origin[1] != '\0' &&
1198 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
1199 			/* No trailing dot. */
1200  root:
1201 			if (newlen + 2 > *buflen)
1202 				goto enospc;	/* No room for ".\0". */
1203 			(*buf)[newlen++] = '.';
1204 			(*buf)[newlen] = '\0';
1205 		}
1206 	}
1207 	*pp += n;
1208 	addlen(newlen, buf, buflen);
1209 	**buf = '\0';
1210 	return (newlen);
1211  enospc:
1212 	errno = ENOSPC;
1213 	*buf = save_buf;
1214 	*buflen = save_buflen;
1215 	return (-1);
1216 }
1217 
1218 static void
1219 addlen(size_t len, char **buf, size_t *buflen) {
1220 	INSIST(len <= *buflen);
1221 	*buf += len;
1222 	*buflen -= len;
1223 }
1224 
1225 static int
1226 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
1227 	if (len >= *buflen) {
1228 		errno = ENOSPC;
1229 		return (-1);
1230 	}
1231 	memcpy(*buf, src, len);
1232 	addlen(len, buf, buflen);
1233 	**buf = '\0';
1234 	return (0);
1235 }
1236 
1237 static int
1238 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
1239 	size_t save_buflen = *buflen;
1240 	char *save_buf = *buf;
1241 	int t;
1242 
1243 	if (spaced || len >= target - 1) {
1244 		T(addstr("  ", (size_t)2, buf, buflen));
1245 		spaced = 1;
1246 	} else {
1247 		for (t = (target - len - 1) / 8; t >= 0; t--)
1248 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
1249 				*buflen = save_buflen;
1250 				*buf = save_buf;
1251 				return (-1);
1252 			}
1253 		spaced = 0;
1254 	}
1255 	return (spaced);
1256 }
1257 
1258 /*! \file */
1259