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