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