xref: /netbsd-src/lib/libc/nameser/ns_print.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: ns_print.c,v 1.4 2004/05/21 08:20:50 martin 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.3.2.1.4.4 2004/03/17 01:13:36 marka Exp";
24 #else
25 __RCSID("$NetBSD: ns_print.c,v 1.4 2004/05/21 08:20:50 martin 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 /* Public. */
78 
79 /*
80  * int
81  * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
82  *	Convert an RR to presentation format.
83  * return:
84  *	Number of characters written to buf, or -1 (check errno).
85  */
86 int
87 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
88 	    const char *name_ctx, const char *origin,
89 	    char *buf, size_t buflen)
90 {
91 	int n;
92 
93 	n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
94 			 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
95 			 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
96 			 name_ctx, origin, buf, buflen);
97 	return (n);
98 }
99 
100 /*
101  * int
102  * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
103  *	       name_ctx, origin, buf, buflen)
104  *	Convert the fields of an RR into presentation format.
105  * return:
106  *	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 	if (rdlen == 0U)
156 		return (buf - obuf);
157 	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
158 
159 	/*
160 	 * RData.
161 	 */
162 	switch (type) {
163 	case ns_t_a:
164 		if (rdlen != (size_t)NS_INADDRSZ)
165 			goto formerr;
166 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
167 		addlen(strlen(buf), &buf, &buflen);
168 		break;
169 
170 	case ns_t_cname:
171 	case ns_t_mb:
172 	case ns_t_mg:
173 	case ns_t_mr:
174 	case ns_t_ns:
175 	case ns_t_ptr:
176 	case ns_t_dname:
177 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
178 		break;
179 
180 	case ns_t_hinfo:
181 	case ns_t_isdn:
182 		/* First word. */
183 		T(len = charstr(rdata, edata, &buf, &buflen));
184 		if (len == 0)
185 			goto formerr;
186 		rdata += len;
187 		T(addstr(" ", (size_t)1, &buf, &buflen));
188 
189 
190 		/* Second word, optional in ISDN records. */
191 		if (type == ns_t_isdn && rdata == edata)
192 			break;
193 
194 		T(len = charstr(rdata, edata, &buf, &buflen));
195 		if (len == 0)
196 			goto formerr;
197 		rdata += len;
198 		break;
199 
200 	case ns_t_soa: {
201 		u_long t;
202 
203 		/* Server name. */
204 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
205 		T(addstr(" ", (size_t)1, &buf, &buflen));
206 
207 		/* Administrator name. */
208 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
209 		T(addstr(" (\n", (size_t)3, &buf, &buflen));
210 		spaced = 0;
211 
212 		if ((edata - rdata) != 5*NS_INT32SZ)
213 			goto formerr;
214 
215 		/* Serial number. */
216 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
217 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
218 		len = SPRINTF((tmp, "%lu", t));
219 		T(addstr(tmp, (size_t)len, &buf, &buflen));
220 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
221 		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
222 		spaced = 0;
223 
224 		/* Refresh interval. */
225 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
226 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
227 		T(len = ns_format_ttl(t, buf, buflen));
228 		addlen((size_t)len, &buf, &buflen);
229 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
230 		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
231 		spaced = 0;
232 
233 		/* Retry interval. */
234 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
235 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
236 		T(len = ns_format_ttl(t, buf, buflen));
237 		addlen((size_t)len, &buf, &buflen);
238 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
239 		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
240 		spaced = 0;
241 
242 		/* Expiry. */
243 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
244 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
245 		T(len = ns_format_ttl(t, buf, buflen));
246 		addlen((size_t)len, &buf, &buflen);
247 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
248 		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
249 		spaced = 0;
250 
251 		/* Minimum TTL. */
252 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
253 		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
254 		T(len = ns_format_ttl(t, buf, buflen));
255 		addlen((size_t)len, &buf, &buflen);
256 		T(addstr(" )", (size_t)2, &buf, &buflen));
257 		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
258 		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
259 
260 		break;
261 	    }
262 
263 	case ns_t_mx:
264 	case ns_t_afsdb:
265 	case ns_t_rt: {
266 		u_int t;
267 
268 		if (rdlen < (size_t)NS_INT16SZ)
269 			goto formerr;
270 
271 		/* Priority. */
272 		t = ns_get16(rdata);
273 		rdata += NS_INT16SZ;
274 		len = SPRINTF((tmp, "%u ", t));
275 		T(addstr(tmp, (size_t)len, &buf, &buflen));
276 
277 		/* Target. */
278 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
279 
280 		break;
281 	    }
282 
283 	case ns_t_px: {
284 		u_int t;
285 
286 		if (rdlen < (size_t)NS_INT16SZ)
287 			goto formerr;
288 
289 		/* Priority. */
290 		t = ns_get16(rdata);
291 		rdata += NS_INT16SZ;
292 		len = SPRINTF((tmp, "%u ", t));
293 		T(addstr(tmp, (size_t)len, &buf, &buflen));
294 
295 		/* Name1. */
296 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
297 		T(addstr(" ", (size_t)1, &buf, &buflen));
298 
299 		/* Name2. */
300 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
301 
302 		break;
303 	    }
304 
305 	case ns_t_x25:
306 		T(len = charstr(rdata, edata, &buf, &buflen));
307 		if (len == 0)
308 			goto formerr;
309 		rdata += len;
310 		break;
311 
312 	case ns_t_txt:
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 		char base64_key[NS_MD5RSA_MAX_BASE64];
461 		u_int keyflags, protocol, algorithm, key_id;
462 		const char *leader;
463 		int n;
464 
465 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
466 			goto formerr;
467 
468 		/* Key flags, Protocol, Algorithm. */
469 #ifndef _LIBC
470 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
471 #else
472 		key_id = 0;
473 #endif
474 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
475 		protocol = *rdata++;
476 		algorithm = *rdata++;
477 		len = SPRINTF((tmp, "0x%04x %u %u",
478 			       keyflags, protocol, algorithm));
479 		T(addstr(tmp, (size_t)len, &buf, &buflen));
480 
481 		/* Public key data. */
482 		len = b64_ntop(rdata, (size_t)(edata - rdata),
483 			       base64_key, sizeof base64_key);
484 		if (len < 0)
485 			goto formerr;
486 		if (len > 15) {
487 			T(addstr(" (", (size_t)2, &buf, &buflen));
488 			leader = "\n\t\t";
489 			spaced = 0;
490 		} else
491 			leader = " ";
492 		for (n = 0; n < len; n += 48) {
493 			T(addstr(leader, strlen(leader), &buf, &buflen));
494 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
495 				 &buf, &buflen));
496 		}
497 		if (len > 15)
498 			T(addstr(" )", (size_t)2, &buf, &buflen));
499 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
500 		T(addstr(tmp, (size_t)n, &buf, &buflen));
501 
502 		break;
503 	    }
504 
505 	case ns_t_sig: {
506 		char base64_key[NS_MD5RSA_MAX_BASE64];
507 		u_int typ, algorithm, labels, footprint;
508 		const char *leader;
509 		u_long t;
510 		int n;
511 
512 		if (rdlen < 22U)
513 			goto formerr;
514 
515 		/* Type covered, Algorithm, Label count, Original TTL. */
516 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
517 		algorithm = *rdata++;
518 		labels = *rdata++;
519 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
520 		len = SPRINTF((tmp, "%s %d %d %lu ",
521 			       p_type((int)typ), algorithm, labels, t));
522 		T(addstr(tmp, (size_t)len, &buf, &buflen));
523 		if (labels > (u_int)dn_count_labels(name))
524 			goto formerr;
525 
526 		/* Signature expiry. */
527 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
528 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
529 		T(addstr(tmp, (size_t)len, &buf, &buflen));
530 
531 		/* Time signed. */
532 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
533 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
534 		T(addstr(tmp, (size_t)len, &buf, &buflen));
535 
536 		/* Signature Footprint. */
537 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
538 		len = SPRINTF((tmp, "%u ", footprint));
539 		T(addstr(tmp, (size_t)len, &buf, &buflen));
540 
541 		/* Signer's name. */
542 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
543 
544 		/* Signature. */
545 		len = b64_ntop(rdata, (size_t)(edata - rdata),
546 			       base64_key, sizeof base64_key);
547 		if (len > 15) {
548 			T(addstr(" (", (size_t)2, &buf, &buflen));
549 			leader = "\n\t\t";
550 			spaced = 0;
551 		} else
552 			leader = " ";
553 		if (len < 0)
554 			goto formerr;
555 		for (n = 0; n < len; n += 48) {
556 			T(addstr(leader, strlen(leader), &buf, &buflen));
557 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
558 				 &buf, &buflen));
559 		}
560 		if (len > 15)
561 			T(addstr(" )", (size_t)2, &buf, &buflen));
562 		break;
563 	    }
564 
565 	case ns_t_nxt: {
566 		int n, c;
567 
568 		/* Next domain name. */
569 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
570 
571 		/* Type bit map. */
572 		n = edata - rdata;
573 		for (c = 0; c < n*8; c++)
574 			if (NS_NXT_BIT_ISSET(c, rdata)) {
575 				len = SPRINTF((tmp, " %s", p_type(c)));
576 				T(addstr(tmp, (size_t)len, &buf, &buflen));
577 			}
578 		break;
579 	    }
580 
581 	case ns_t_cert: {
582 		u_int c_type, key_tag, alg;
583 		int n;
584 		unsigned int siz;
585 		char base64_cert[8192], tmp1[40];
586 		const char *leader;
587 
588 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
589 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
590 		alg = (u_int) *rdata++;
591 
592 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
593 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
594 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
595 		if (siz > sizeof(base64_cert) * 3/4) {
596 			const char *str = "record too long to print";
597 			T(addstr(str, strlen(str), &buf, &buflen));
598 		}
599 		else {
600 			len = b64_ntop(rdata, (size_t)(edata-rdata),
601 			    base64_cert, siz);
602 
603 			if (len < 0)
604 				goto formerr;
605 			else if (len > 15) {
606 				T(addstr(" (", (size_t)2, &buf, &buflen));
607 				leader = "\n\t\t";
608 				spaced = 0;
609 			}
610 			else
611 				leader = " ";
612 
613 			for (n = 0; n < len; n += 48) {
614 				T(addstr(leader, strlen(leader),
615 					 &buf, &buflen));
616 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
617 					 &buf, &buflen));
618 			}
619 			if (len > 15)
620 				T(addstr(" )", (size_t)2, &buf, &buflen));
621 		}
622 		break;
623 	    }
624 
625 	case ns_t_tkey: {
626 		/* KJD - need to complete this */
627 		u_long t;
628 		int mode, err, keysize;
629 
630 		/* Algorithm name. */
631 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
632 		T(addstr(" ", (size_t)1, &buf, &buflen));
633 
634 		/* Inception. */
635 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
636 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
637 		T(addstr(tmp, (size_t)len, &buf, &buflen));
638 
639 		/* Experation. */
640 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
641 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
642 		T(addstr(tmp, (size_t)len, &buf, &buflen));
643 
644 		/* Mode , Error, Key Size. */
645 		/* Priority, Weight, Port. */
646 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
647 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
648 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
649 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
650 		T(addstr(tmp, (size_t)len, &buf, &buflen));
651 
652 		/* XXX need to dump key, print otherdata length & other data */
653 		break;
654 	    }
655 
656 	case ns_t_tsig: {
657 		/* BEW - need to complete this */
658 		int n;
659 
660 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
661 		T(addstr(" ", (size_t)1, &buf, &buflen));
662 		rdata += 8; /* time */
663 		n = ns_get16(rdata); rdata += INT16SZ;
664 		rdata += n; /* sig */
665 		n = ns_get16(rdata); rdata += INT16SZ; /* original id */
666 		sprintf(buf, "%d", ns_get16(rdata));
667 		rdata += INT16SZ;
668 		addlen(strlen(buf), &buf, &buflen);
669 		break;
670 	    }
671 
672 	case ns_t_a6: {
673 		struct in6_addr a;
674 		int pbyte, pbit;
675 
676 		/* prefix length */
677 		if (rdlen == 0U) goto formerr;
678 		len = SPRINTF((tmp, "%d ", *rdata));
679 		T(addstr(tmp, (size_t)len, &buf, &buflen));
680 		pbit = *rdata;
681 		if (pbit > 128) goto formerr;
682 		pbyte = (pbit & ~7) / 8;
683 		rdata++;
684 
685 		/* address suffix: provided only when prefix len != 128 */
686 		if (pbit < 128) {
687 			if (rdata + pbyte >= edata) goto formerr;
688 			memset(&a, 0, sizeof(a));
689 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
690 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
691 			addlen(strlen(buf), &buf, &buflen);
692 			rdata += sizeof(a) - pbyte;
693 		}
694 
695 		/* prefix name: provided only when prefix len > 0 */
696 		if (pbit == 0)
697 			break;
698 		if (rdata >= edata) goto formerr;
699 		T(addstr(" ", (size_t)1, &buf, &buflen));
700 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
701 
702 		break;
703 	    }
704 
705 	case ns_t_opt: {
706 		len = SPRINTF((tmp, "%u bytes", class));
707 		T(addstr(tmp, (size_t)len, &buf, &buflen));
708 		break;
709 	    }
710 
711 	default:
712 		comment = "unknown RR type";
713 		goto hexify;
714 	}
715 	return (buf - obuf);
716  formerr:
717 	comment = "RR format error";
718  hexify: {
719 	int n, m;
720 	char *p;
721 
722 	len = SPRINTF((tmp, "\\# %tu (\t; %s", edata - rdata, comment));
723 	T(addstr(tmp, (size_t)len, &buf, &buflen));
724 	while (rdata < edata) {
725 		p = tmp;
726 		p += SPRINTF((p, "\n\t"));
727 		spaced = 0;
728 		n = MIN(16, edata - rdata);
729 		for (m = 0; m < n; m++)
730 			p += SPRINTF((p, "%02x ", rdata[m]));
731 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
732 		if (n < 16) {
733 			T(addstr(")", (size_t)1, &buf, &buflen));
734 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
735 		}
736 		p = tmp;
737 		p += SPRINTF((p, "; "));
738 		for (m = 0; m < n; m++)
739 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
740 				? rdata[m]
741 				: '.';
742 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
743 		rdata += n;
744 	}
745 	return (buf - obuf);
746     }
747 }
748 
749 /* Private. */
750 
751 /*
752  * size_t
753  * prune_origin(name, origin)
754  *	Find out if the name is at or under the current origin.
755  * return:
756  *	Number of characters in name before start of origin,
757  *	or length of name if origin does not match.
758  * notes:
759  *	This function should share code with samedomain().
760  */
761 static size_t
762 prune_origin(const char *name, const char *origin) {
763 	const char *oname = name;
764 
765 	while (*name != '\0') {
766 		if (origin != NULL && ns_samename(name, origin) == 1)
767 			return (name - oname - (name > oname));
768 		while (*name != '\0') {
769 			if (*name == '\\') {
770 				name++;
771 				/* XXX need to handle \nnn form. */
772 				if (*name == '\0')
773 					break;
774 			} else if (*name == '.') {
775 				name++;
776 				break;
777 			}
778 			name++;
779 		}
780 	}
781 	return (name - oname);
782 }
783 
784 /*
785  * int
786  * charstr(rdata, edata, buf, buflen)
787  *	Format a <character-string> into the presentation buffer.
788  * return:
789  *	Number of rdata octets consumed
790  *	0 for protocol format error
791  *	-1 for output buffer error
792  * side effects:
793  *	buffer is advanced on success.
794  */
795 static int
796 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
797 	const u_char *odata = rdata;
798 	size_t save_buflen = *buflen;
799 	char *save_buf = *buf;
800 
801 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
802 		goto enospc;
803 	if (rdata < edata) {
804 		int n = *rdata;
805 
806 		if (rdata + 1 + n <= edata) {
807 			rdata++;
808 			while (n-- > 0) {
809 				if (strchr("\n\"\\", *rdata) != NULL)
810 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
811 						goto enospc;
812 				if (addstr((const char *)rdata, (size_t)1,
813 					   buf, buflen) < 0)
814 					goto enospc;
815 				rdata++;
816 			}
817 		}
818 	}
819 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
820 		goto enospc;
821 	return (rdata - odata);
822  enospc:
823 	errno = ENOSPC;
824 	*buf = save_buf;
825 	*buflen = save_buflen;
826 	return (-1);
827 }
828 
829 static int
830 addname(const u_char *msg, size_t msglen,
831 	const u_char **pp, const char *origin,
832 	char **buf, size_t *buflen)
833 {
834 	size_t newlen, save_buflen = *buflen;
835 	char *save_buf = *buf;
836 	int n;
837 
838 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
839 	if (n < 0)
840 		goto enospc;	/* Guess. */
841 	newlen = prune_origin(*buf, origin);
842 	if (**buf == '\0') {
843 		goto root;
844 	} else if (newlen == 0U) {
845 		/* Use "@" instead of name. */
846 		if (newlen + 2 > *buflen)
847 			goto enospc;        /* No room for "@\0". */
848 		(*buf)[newlen++] = '@';
849 		(*buf)[newlen] = '\0';
850 	} else {
851 		if (((origin == NULL || origin[0] == '\0') ||
852 		    (origin[0] != '.' && origin[1] != '\0' &&
853 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
854 			/* No trailing dot. */
855  root:
856 			if (newlen + 2 > *buflen)
857 				goto enospc;	/* No room for ".\0". */
858 			(*buf)[newlen++] = '.';
859 			(*buf)[newlen] = '\0';
860 		}
861 	}
862 	*pp += n;
863 	addlen(newlen, buf, buflen);
864 	**buf = '\0';
865 	return (newlen);
866  enospc:
867 	errno = ENOSPC;
868 	*buf = save_buf;
869 	*buflen = save_buflen;
870 	return (-1);
871 }
872 
873 static void
874 addlen(size_t len, char **buf, size_t *buflen) {
875 	INSIST(len <= *buflen);
876 	*buf += len;
877 	*buflen -= len;
878 }
879 
880 static int
881 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
882 	if (len >= *buflen) {
883 		errno = ENOSPC;
884 		return (-1);
885 	}
886 	memcpy(*buf, src, len);
887 	addlen(len, buf, buflen);
888 	**buf = '\0';
889 	return (0);
890 }
891 
892 static int
893 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
894 	size_t save_buflen = *buflen;
895 	char *save_buf = *buf;
896 	int t;
897 
898 	if (spaced || len >= target - 1) {
899 		T(addstr("  ", (size_t)2, buf, buflen));
900 		spaced = 1;
901 	} else {
902 		for (t = (target - len - 1) / 8; t >= 0; t--)
903 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
904 				*buflen = save_buflen;
905 				*buf = save_buf;
906 				return (-1);
907 			}
908 		spaced = 0;
909 	}
910 	return (spaced);
911 }
912