xref: /netbsd-src/lib/libc/nameser/ns_print.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 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.3.2.1.4.5 2004/07/28 20:16:45 marka Exp";
24 #else
25 __RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 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 /* 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 	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 		u_int t;
265 
266 		if (rdlen < (size_t)NS_INT16SZ)
267 			goto formerr;
268 
269 		/* Priority. */
270 		t = ns_get16(rdata);
271 		rdata += NS_INT16SZ;
272 		len = SPRINTF((tmp, "%u ", t));
273 		T(addstr(tmp, (size_t)len, &buf, &buflen));
274 
275 		/* Target. */
276 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
277 
278 		break;
279 	    }
280 
281 	case ns_t_px: {
282 		u_int t;
283 
284 		if (rdlen < (size_t)NS_INT16SZ)
285 			goto formerr;
286 
287 		/* Priority. */
288 		t = ns_get16(rdata);
289 		rdata += NS_INT16SZ;
290 		len = SPRINTF((tmp, "%u ", t));
291 		T(addstr(tmp, (size_t)len, &buf, &buflen));
292 
293 		/* Name1. */
294 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
295 		T(addstr(" ", (size_t)1, &buf, &buflen));
296 
297 		/* Name2. */
298 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
299 
300 		break;
301 	    }
302 
303 	case ns_t_x25:
304 		T(len = charstr(rdata, edata, &buf, &buflen));
305 		if (len == 0)
306 			goto formerr;
307 		rdata += len;
308 		break;
309 
310 	case ns_t_txt:
311 		while (rdata < edata) {
312 			T(len = charstr(rdata, edata, &buf, &buflen));
313 			if (len == 0)
314 				goto formerr;
315 			rdata += len;
316 			if (rdata < edata)
317 				T(addstr(" ", (size_t)1, &buf, &buflen));
318 		}
319 		break;
320 
321 	case ns_t_nsap: {
322 		char t[2+255*3];
323 
324 		(void) inet_nsap_ntoa((int)rdlen, rdata, t);
325 		T(addstr(t, strlen(t), &buf, &buflen));
326 		break;
327 	    }
328 
329 	case ns_t_aaaa:
330 		if (rdlen != (size_t)NS_IN6ADDRSZ)
331 			goto formerr;
332 		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
333 		addlen(strlen(buf), &buf, &buflen);
334 		break;
335 
336 	case ns_t_loc: {
337 		char t[255];
338 
339 		/* XXX protocol format checking? */
340 		(void) loc_ntoa(rdata, t);
341 		T(addstr(t, strlen(t), &buf, &buflen));
342 		break;
343 	    }
344 
345 	case ns_t_naptr: {
346 		u_int order, preference;
347 		char t[50];
348 
349 		if (rdlen < 2U*NS_INT16SZ)
350 			goto formerr;
351 
352 		/* Order, Precedence. */
353 		order = ns_get16(rdata);	rdata += NS_INT16SZ;
354 		preference = ns_get16(rdata);	rdata += NS_INT16SZ;
355 		len = SPRINTF((t, "%u %u ", order, preference));
356 		T(addstr(t, (size_t)len, &buf, &buflen));
357 
358 		/* Flags. */
359 		T(len = charstr(rdata, edata, &buf, &buflen));
360 		if (len == 0)
361 			goto formerr;
362 		rdata += len;
363 		T(addstr(" ", (size_t)1, &buf, &buflen));
364 
365 		/* Service. */
366 		T(len = charstr(rdata, edata, &buf, &buflen));
367 		if (len == 0)
368 			goto formerr;
369 		rdata += len;
370 		T(addstr(" ", (size_t)1, &buf, &buflen));
371 
372 		/* Regexp. */
373 		T(len = charstr(rdata, edata, &buf, &buflen));
374 		if (len < 0)
375 			return (-1);
376 		if (len == 0)
377 			goto formerr;
378 		rdata += len;
379 		T(addstr(" ", (size_t)1, &buf, &buflen));
380 
381 		/* Server. */
382 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
383 		break;
384 	    }
385 
386 	case ns_t_srv: {
387 		u_int priority, weight, port;
388 		char t[50];
389 
390 		if (rdlen < 3U*NS_INT16SZ)
391 			goto formerr;
392 
393 		/* Priority, Weight, Port. */
394 		priority = ns_get16(rdata);  rdata += NS_INT16SZ;
395 		weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
396 		port     = ns_get16(rdata);  rdata += NS_INT16SZ;
397 		len = SPRINTF((t, "%u %u %u ", priority, weight, port));
398 		T(addstr(t, (size_t)len, &buf, &buflen));
399 
400 		/* Server. */
401 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
402 		break;
403 	    }
404 
405 	case ns_t_minfo:
406 	case ns_t_rp:
407 		/* Name1. */
408 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
409 		T(addstr(" ", (size_t)1, &buf, &buflen));
410 
411 		/* Name2. */
412 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
413 
414 		break;
415 
416 	case ns_t_wks: {
417 		int n, lcnt;
418 
419 		if (rdlen < 1U + NS_INT32SZ)
420 			goto formerr;
421 
422 		/* Address. */
423 		(void) inet_ntop(AF_INET, rdata, buf, buflen);
424 		addlen(strlen(buf), &buf, &buflen);
425 		rdata += NS_INADDRSZ;
426 
427 		/* Protocol. */
428 		len = SPRINTF((tmp, " %u ( ", *rdata));
429 		T(addstr(tmp, (size_t)len, &buf, &buflen));
430 		rdata += NS_INT8SZ;
431 
432 		/* Bit map. */
433 		n = 0;
434 		lcnt = 0;
435 		while (rdata < edata) {
436 			u_int c = *rdata++;
437 			do {
438 				if (c & 0200) {
439 					if (lcnt == 0) {
440 						T(addstr("\n\t\t\t\t", (size_t)5,
441 							 &buf, &buflen));
442 						lcnt = 10;
443 						spaced = 0;
444 					}
445 					len = SPRINTF((tmp, "%d ", n));
446 					T(addstr(tmp, (size_t)len, &buf, &buflen));
447 					lcnt--;
448 				}
449 				c <<= 1;
450 			} while (++n & 07);
451 		}
452 		T(addstr(")", (size_t)1, &buf, &buflen));
453 
454 		break;
455 	    }
456 
457 	case ns_t_key: {
458 		char base64_key[NS_MD5RSA_MAX_BASE64];
459 		u_int keyflags, protocol, algorithm, key_id;
460 		const char *leader;
461 		int n;
462 
463 		if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
464 			goto formerr;
465 
466 		/* Key flags, Protocol, Algorithm. */
467 #ifndef _LIBC
468 		key_id = dst_s_dns_key_id(rdata, edata-rdata);
469 #else
470 		key_id = 0;
471 #endif
472 		keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
473 		protocol = *rdata++;
474 		algorithm = *rdata++;
475 		len = SPRINTF((tmp, "0x%04x %u %u",
476 			       keyflags, protocol, algorithm));
477 		T(addstr(tmp, (size_t)len, &buf, &buflen));
478 
479 		/* Public key data. */
480 		len = b64_ntop(rdata, (size_t)(edata - rdata),
481 			       base64_key, sizeof base64_key);
482 		if (len < 0)
483 			goto formerr;
484 		if (len > 15) {
485 			T(addstr(" (", (size_t)2, &buf, &buflen));
486 			leader = "\n\t\t";
487 			spaced = 0;
488 		} else
489 			leader = " ";
490 		for (n = 0; n < len; n += 48) {
491 			T(addstr(leader, strlen(leader), &buf, &buflen));
492 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
493 				 &buf, &buflen));
494 		}
495 		if (len > 15)
496 			T(addstr(" )", (size_t)2, &buf, &buflen));
497 		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
498 		T(addstr(tmp, (size_t)n, &buf, &buflen));
499 
500 		break;
501 	    }
502 
503 	case ns_t_sig: {
504 		char base64_key[NS_MD5RSA_MAX_BASE64];
505 		u_int typ, algorithm, labels, footprint;
506 		const char *leader;
507 		u_long t;
508 		int n;
509 
510 		if (rdlen < 22U)
511 			goto formerr;
512 
513 		/* Type covered, Algorithm, Label count, Original TTL. */
514 	        typ = ns_get16(rdata);  rdata += NS_INT16SZ;
515 		algorithm = *rdata++;
516 		labels = *rdata++;
517 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
518 		len = SPRINTF((tmp, "%s %d %d %lu ",
519 			       p_type((int)typ), algorithm, labels, t));
520 		T(addstr(tmp, (size_t)len, &buf, &buflen));
521 		if (labels > (u_int)dn_count_labels(name))
522 			goto formerr;
523 
524 		/* Signature expiry. */
525 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
526 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
527 		T(addstr(tmp, (size_t)len, &buf, &buflen));
528 
529 		/* Time signed. */
530 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
531 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
532 		T(addstr(tmp, (size_t)len, &buf, &buflen));
533 
534 		/* Signature Footprint. */
535 		footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
536 		len = SPRINTF((tmp, "%u ", footprint));
537 		T(addstr(tmp, (size_t)len, &buf, &buflen));
538 
539 		/* Signer's name. */
540 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
541 
542 		/* Signature. */
543 		len = b64_ntop(rdata, (size_t)(edata - rdata),
544 			       base64_key, sizeof base64_key);
545 		if (len > 15) {
546 			T(addstr(" (", (size_t)2, &buf, &buflen));
547 			leader = "\n\t\t";
548 			spaced = 0;
549 		} else
550 			leader = " ";
551 		if (len < 0)
552 			goto formerr;
553 		for (n = 0; n < len; n += 48) {
554 			T(addstr(leader, strlen(leader), &buf, &buflen));
555 			T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
556 				 &buf, &buflen));
557 		}
558 		if (len > 15)
559 			T(addstr(" )", (size_t)2, &buf, &buflen));
560 		break;
561 	    }
562 
563 	case ns_t_nxt: {
564 		int n, c;
565 
566 		/* Next domain name. */
567 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
568 
569 		/* Type bit map. */
570 		n = edata - rdata;
571 		for (c = 0; c < n*8; c++)
572 			if (NS_NXT_BIT_ISSET(c, rdata)) {
573 				len = SPRINTF((tmp, " %s", p_type(c)));
574 				T(addstr(tmp, (size_t)len, &buf, &buflen));
575 			}
576 		break;
577 	    }
578 
579 	case ns_t_cert: {
580 		u_int c_type, key_tag, alg;
581 		int n;
582 		unsigned int siz;
583 		char base64_cert[8192], tmp1[40];
584 		const char *leader;
585 
586 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
587 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
588 		alg = (u_int) *rdata++;
589 
590 		len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
591 		T(addstr(tmp1, (size_t)len, &buf, &buflen));
592 		siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
593 		if (siz > sizeof(base64_cert) * 3/4) {
594 			const char *str = "record too long to print";
595 			T(addstr(str, strlen(str), &buf, &buflen));
596 		}
597 		else {
598 			len = b64_ntop(rdata, (size_t)(edata-rdata),
599 			    base64_cert, siz);
600 
601 			if (len < 0)
602 				goto formerr;
603 			else if (len > 15) {
604 				T(addstr(" (", (size_t)2, &buf, &buflen));
605 				leader = "\n\t\t";
606 				spaced = 0;
607 			}
608 			else
609 				leader = " ";
610 
611 			for (n = 0; n < len; n += 48) {
612 				T(addstr(leader, strlen(leader),
613 					 &buf, &buflen));
614 				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
615 					 &buf, &buflen));
616 			}
617 			if (len > 15)
618 				T(addstr(" )", (size_t)2, &buf, &buflen));
619 		}
620 		break;
621 	    }
622 
623 	case ns_t_tkey: {
624 		/* KJD - need to complete this */
625 		u_long t;
626 		int mode, err, keysize;
627 
628 		/* Algorithm name. */
629 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
630 		T(addstr(" ", (size_t)1, &buf, &buflen));
631 
632 		/* Inception. */
633 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
634 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
635 		T(addstr(tmp, (size_t)len, &buf, &buflen));
636 
637 		/* Experation. */
638 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
639 		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
640 		T(addstr(tmp, (size_t)len, &buf, &buflen));
641 
642 		/* Mode , Error, Key Size. */
643 		/* Priority, Weight, Port. */
644 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
645 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
646 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
647 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
648 		T(addstr(tmp, (size_t)len, &buf, &buflen));
649 
650 		/* XXX need to dump key, print otherdata length & other data */
651 		break;
652 	    }
653 
654 	case ns_t_tsig: {
655 		/* BEW - need to complete this */
656 		int n;
657 
658 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
659 		T(addstr(" ", (size_t)1, &buf, &buflen));
660 		rdata += 8; /* time */
661 		n = ns_get16(rdata); rdata += INT16SZ;
662 		rdata += n; /* sig */
663 		n = ns_get16(rdata); rdata += INT16SZ; /* original id */
664 		sprintf(buf, "%d", ns_get16(rdata));
665 		rdata += INT16SZ;
666 		addlen(strlen(buf), &buf, &buflen);
667 		break;
668 	    }
669 
670 	case ns_t_a6: {
671 		struct in6_addr a;
672 		int pbyte, pbit;
673 
674 		/* prefix length */
675 		if (rdlen == 0U) goto formerr;
676 		len = SPRINTF((tmp, "%d ", *rdata));
677 		T(addstr(tmp, (size_t)len, &buf, &buflen));
678 		pbit = *rdata;
679 		if (pbit > 128) goto formerr;
680 		pbyte = (pbit & ~7) / 8;
681 		rdata++;
682 
683 		/* address suffix: provided only when prefix len != 128 */
684 		if (pbit < 128) {
685 			if (rdata + pbyte >= edata) goto formerr;
686 			memset(&a, 0, sizeof(a));
687 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
688 			(void) inet_ntop(AF_INET6, &a, buf, buflen);
689 			addlen(strlen(buf), &buf, &buflen);
690 			rdata += sizeof(a) - pbyte;
691 		}
692 
693 		/* prefix name: provided only when prefix len > 0 */
694 		if (pbit == 0)
695 			break;
696 		if (rdata >= edata) goto formerr;
697 		T(addstr(" ", (size_t)1, &buf, &buflen));
698 		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
699 
700 		break;
701 	    }
702 
703 	case ns_t_opt: {
704 		len = SPRINTF((tmp, "%u bytes", class));
705 		T(addstr(tmp, (size_t)len, &buf, &buflen));
706 		break;
707 	    }
708 
709 	default:
710 		comment = "unknown RR type";
711 		goto hexify;
712 	}
713 	return (buf - obuf);
714  formerr:
715 	comment = "RR format error";
716  hexify: {
717 	int n, m;
718 	char *p;
719 
720 	len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata,
721 		       rdlen != 0 ? " (" : "", comment));
722 	T(addstr(tmp, (size_t)len, &buf, &buflen));
723 	while (rdata < edata) {
724 		p = tmp;
725 		p += SPRINTF((p, "\n\t"));
726 		spaced = 0;
727 		n = MIN(16, edata - rdata);
728 		for (m = 0; m < n; m++)
729 			p += SPRINTF((p, "%02x ", rdata[m]));
730 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
731 		if (n < 16) {
732 			T(addstr(")", (size_t)1, &buf, &buflen));
733 			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
734 		}
735 		p = tmp;
736 		p += SPRINTF((p, "; "));
737 		for (m = 0; m < n; m++)
738 			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
739 				? rdata[m]
740 				: '.';
741 		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
742 		rdata += n;
743 	}
744 	return (buf - obuf);
745     }
746 }
747 
748 /* Private. */
749 
750 /*
751  * size_t
752  * prune_origin(name, origin)
753  *	Find out if the name is at or under the current origin.
754  * return:
755  *	Number of characters in name before start of origin,
756  *	or length of name if origin does not match.
757  * notes:
758  *	This function should share code with samedomain().
759  */
760 static size_t
761 prune_origin(const char *name, const char *origin) {
762 	const char *oname = name;
763 
764 	while (*name != '\0') {
765 		if (origin != NULL && ns_samename(name, origin) == 1)
766 			return (name - oname - (name > oname));
767 		while (*name != '\0') {
768 			if (*name == '\\') {
769 				name++;
770 				/* XXX need to handle \nnn form. */
771 				if (*name == '\0')
772 					break;
773 			} else if (*name == '.') {
774 				name++;
775 				break;
776 			}
777 			name++;
778 		}
779 	}
780 	return (name - oname);
781 }
782 
783 /*
784  * int
785  * charstr(rdata, edata, buf, buflen)
786  *	Format a <character-string> into the presentation buffer.
787  * return:
788  *	Number of rdata octets consumed
789  *	0 for protocol format error
790  *	-1 for output buffer error
791  * side effects:
792  *	buffer is advanced on success.
793  */
794 static int
795 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
796 	const u_char *odata = rdata;
797 	size_t save_buflen = *buflen;
798 	char *save_buf = *buf;
799 
800 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
801 		goto enospc;
802 	if (rdata < edata) {
803 		int n = *rdata;
804 
805 		if (rdata + 1 + n <= edata) {
806 			rdata++;
807 			while (n-- > 0) {
808 				if (strchr("\n\"\\", *rdata) != NULL)
809 					if (addstr("\\", (size_t)1, buf, buflen) < 0)
810 						goto enospc;
811 				if (addstr((const char *)rdata, (size_t)1,
812 					   buf, buflen) < 0)
813 					goto enospc;
814 				rdata++;
815 			}
816 		}
817 	}
818 	if (addstr("\"", (size_t)1, buf, buflen) < 0)
819 		goto enospc;
820 	return (rdata - odata);
821  enospc:
822 	errno = ENOSPC;
823 	*buf = save_buf;
824 	*buflen = save_buflen;
825 	return (-1);
826 }
827 
828 static int
829 addname(const u_char *msg, size_t msglen,
830 	const u_char **pp, const char *origin,
831 	char **buf, size_t *buflen)
832 {
833 	size_t newlen, save_buflen = *buflen;
834 	char *save_buf = *buf;
835 	int n;
836 
837 	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
838 	if (n < 0)
839 		goto enospc;	/* Guess. */
840 	newlen = prune_origin(*buf, origin);
841 	if (**buf == '\0') {
842 		goto root;
843 	} else if (newlen == 0U) {
844 		/* Use "@" instead of name. */
845 		if (newlen + 2 > *buflen)
846 			goto enospc;        /* No room for "@\0". */
847 		(*buf)[newlen++] = '@';
848 		(*buf)[newlen] = '\0';
849 	} else {
850 		if (((origin == NULL || origin[0] == '\0') ||
851 		    (origin[0] != '.' && origin[1] != '\0' &&
852 		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
853 			/* No trailing dot. */
854  root:
855 			if (newlen + 2 > *buflen)
856 				goto enospc;	/* No room for ".\0". */
857 			(*buf)[newlen++] = '.';
858 			(*buf)[newlen] = '\0';
859 		}
860 	}
861 	*pp += n;
862 	addlen(newlen, buf, buflen);
863 	**buf = '\0';
864 	return (newlen);
865  enospc:
866 	errno = ENOSPC;
867 	*buf = save_buf;
868 	*buflen = save_buflen;
869 	return (-1);
870 }
871 
872 static void
873 addlen(size_t len, char **buf, size_t *buflen) {
874 	INSIST(len <= *buflen);
875 	*buf += len;
876 	*buflen -= len;
877 }
878 
879 static int
880 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
881 	if (len >= *buflen) {
882 		errno = ENOSPC;
883 		return (-1);
884 	}
885 	memcpy(*buf, src, len);
886 	addlen(len, buf, buflen);
887 	**buf = '\0';
888 	return (0);
889 }
890 
891 static int
892 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
893 	size_t save_buflen = *buflen;
894 	char *save_buf = *buf;
895 	int t;
896 
897 	if (spaced || len >= target - 1) {
898 		T(addstr("  ", (size_t)2, buf, buflen));
899 		spaced = 1;
900 	} else {
901 		for (t = (target - len - 1) / 8; t >= 0; t--)
902 			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
903 				*buflen = save_buflen;
904 				*buf = save_buf;
905 				return (-1);
906 			}
907 		spaced = 0;
908 	}
909 	return (spaced);
910 }
911