1/*	$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 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
23static const char rcsid[] = "Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp";
24#else
25//__RCSID("$NetBSD: ns_print.c,v 1.11 2012/03/13 21:13:39 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 <assert.h>
43#include <errno.h>
44#include <resolv.h>
45#include <stddef.h>
46#include <string.h>
47#include <ctype.h>
48
49#include "port_after.h"
50
51#ifdef SPRINTF_CHAR
52# define SPRINTF(x) ((int)strlen(sprintf/**/x))
53#else
54# define SPRINTF(x) (sprintf x)
55#endif
56
57/* Forward. */
58
59static size_t	prune_origin(const char *name, const char *origin);
60static int	charstr(const u_char *rdata, const u_char *edata,
61			char **buf, size_t *buflen);
62static int	addname(const u_char *msg, size_t msglen,
63			const u_char **p, const char *origin,
64			char **buf, size_t *buflen);
65static void	addlen(size_t len, char **buf, size_t *buflen);
66static int	addstr(const char *src, size_t len,
67		       char **buf, size_t *buflen);
68static 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 (/*CONSTCOND*/0)
78
79static 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 */
90int
91ns_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 */
110int
111ns_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", (size_t)3, &buf, &buflen));
130	} else {
131		len = (int)prune_origin(name, origin);
132		if (*name == '\0') {
133			goto root;
134		} else if (len == 0) {
135			T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
136		} else {
137			T(addstr(name, (size_t)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(".", (size_t)1, &buf, &buflen));
144				len++;
145			}
146			T(spaced = addtab((size_t)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((size_t)x, &buf, &buflen);
155	len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
156	T(addstr(tmp, (size_t)len, &buf, &buflen));
157	T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
158
159	/*
160	 * RData.
161	 */
162	switch (type) {
163	case ns_t_a:
164		if (rdlen != (size_t)NS_INADDRSZ)
165			goto formerr;
166		(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
167		addlen(strlen(buf), &buf, &buflen);
168		break;
169
170	case ns_t_cname:
171	case ns_t_mb:
172	case ns_t_mg:
173	case ns_t_mr:
174	case ns_t_ns:
175	case ns_t_ptr:
176	case ns_t_dname:
177		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
178		break;
179
180	case ns_t_hinfo:
181	case ns_t_isdn:
182		/* First word. */
183		T(len = charstr(rdata, edata, &buf, &buflen));
184		if (len == 0)
185			goto formerr;
186		rdata += len;
187		T(addstr(" ", (size_t)1, &buf, &buflen));
188
189
190		/* Second word, optional in ISDN records. */
191		if (type == ns_t_isdn && rdata == edata)
192			break;
193
194		T(len = charstr(rdata, edata, &buf, &buflen));
195		if (len == 0)
196			goto formerr;
197		rdata += len;
198		break;
199
200	case ns_t_soa: {
201		u_long t;
202
203		/* Server name. */
204		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
205		T(addstr(" ", (size_t)1, &buf, &buflen));
206
207		/* Administrator name. */
208		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
209		T(addstr(" (\n", (size_t)3, &buf, &buflen));
210		spaced = 0;
211
212		if ((edata - rdata) != 5*NS_INT32SZ)
213			goto formerr;
214
215		/* Serial number. */
216		t = ns_get32(rdata);  rdata += NS_INT32SZ;
217		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
218		len = SPRINTF((tmp, "%lu", t));
219		T(addstr(tmp, (size_t)len, &buf, &buflen));
220		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
221		T(addstr("; serial\n", (size_t)9, &buf, &buflen));
222		spaced = 0;
223
224		/* Refresh interval. */
225		t = ns_get32(rdata);  rdata += NS_INT32SZ;
226		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
227		T(len = ns_format_ttl(t, buf, buflen));
228		addlen((size_t)len, &buf, &buflen);
229		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
230		T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
231		spaced = 0;
232
233		/* Retry interval. */
234		t = ns_get32(rdata);  rdata += NS_INT32SZ;
235		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
236		T(len = ns_format_ttl(t, buf, buflen));
237		addlen((size_t)len, &buf, &buflen);
238		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
239		T(addstr("; retry\n", (size_t)8, &buf, &buflen));
240		spaced = 0;
241
242		/* Expiry. */
243		t = ns_get32(rdata);  rdata += NS_INT32SZ;
244		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
245		T(len = ns_format_ttl(t, buf, buflen));
246		addlen((size_t)len, &buf, &buflen);
247		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
248		T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
249		spaced = 0;
250
251		/* Minimum TTL. */
252		t = ns_get32(rdata);  rdata += NS_INT32SZ;
253		T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
254		T(len = ns_format_ttl(t, buf, buflen));
255		addlen((size_t)len, &buf, &buflen);
256		T(addstr(" )", (size_t)2, &buf, &buflen));
257		T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
258		T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
259
260		break;
261	    }
262
263	case ns_t_mx:
264	case ns_t_afsdb:
265	case ns_t_rt:
266	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, (size_t)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, (size_t)len, &buf, &buflen));
295
296		/* Name1. */
297		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
298		T(addstr(" ", (size_t)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(" ", (size_t)1, &buf, &buflen));
322		}
323		break;
324
325	case ns_t_nsap: {
326		char t[2+255*3];
327
328		(void) inet_nsap_ntoa((int)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, (socklen_t)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, (size_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(" ", (size_t)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(" ", (size_t)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(" ", (size_t)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, (size_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(" ", (size_t)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, (socklen_t)buflen);
428		addlen(strlen(buf), &buf, &buflen);
429		rdata += NS_INADDRSZ;
430
431		/* Protocol. */
432		len = SPRINTF((tmp, " %u ( ", *rdata));
433		T(addstr(tmp, (size_t)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", (size_t)5,
445							 &buf, &buflen));
446						lcnt = 10;
447						spaced = 0;
448					}
449					len = SPRINTF((tmp, "%d ", n));
450					T(addstr(tmp, (size_t)len, &buf, &buflen));
451					lcnt--;
452				}
453				c <<= 1;
454			} while (++n & 07);
455		}
456		T(addstr(")", (size_t)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, (size_t)len, &buf, &buflen));
483
484		/* Public key data. */
485		len = b64_ntop(rdata, (size_t)(edata - rdata),
486			       base64_key, sizeof base64_key);
487		if (len < 0)
488			goto formerr;
489		if (len > 15) {
490			T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48),
498				 &buf, &buflen));
499		}
500		if (len > 15)
501			T(addstr(" )", (size_t)2, &buf, &buflen));
502		n = SPRINTF((tmp, " ; key_tag= %u", key_id));
503		T(addstr(tmp, (size_t)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 typ, 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	        typ = 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((int)typ), algorithm, labels, t));
526		T(addstr(tmp, (size_t)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, (size_t)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, (size_t)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, (size_t)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, (size_t)(edata - rdata),
550			       base64_key, sizeof base64_key);
551		if (len > 15) {
552			T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48),
562				 &buf, &buflen));
563		}
564		if (len > 15)
565			T(addstr(" )", (size_t)2, &buf, &buflen));
566		break;
567	    }
568
569	case ns_t_nxt: {
570		ptrdiff_t 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((int)c)));
580				T(addstr(tmp, (size_t)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		size_t siz;
589		char base64_cert[8192], tmp1[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((tmp1, "%d %d %d ", c_type, key_tag, alg));
597		T(addstr(tmp1, (size_t)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, (size_t)(edata-rdata),
605			    base64_cert, siz);
606
607			if (len < 0)
608				goto formerr;
609			else if (len > 15) {
610				T(addstr(" (", (size_t)2, &buf, &buflen));
611				leader = "\n\t\t";
612				spaced = 0;
613			}
614			else
615				leader = " ";
616
617			for (n = 0; n < len; n += 48) {
618				T(addstr(leader, strlen(leader),
619					 &buf, &buflen));
620				T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
621					 &buf, &buflen));
622			}
623			if (len > 15)
624				T(addstr(" )", (size_t)2, &buf, &buflen));
625		}
626		break;
627	    }
628
629	case ns_t_tkey: {
630		/* KJD - need to complete this */
631		u_long t;
632		int mode, err, keysize;
633
634		/* Algorithm name. */
635		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
636		T(addstr(" ", (size_t)1, &buf, &buflen));
637
638		/* Inception. */
639		t = ns_get32(rdata);  rdata += NS_INT32SZ;
640		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
641		T(addstr(tmp, (size_t)len, &buf, &buflen));
642
643		/* Experation. */
644		t = ns_get32(rdata);  rdata += NS_INT32SZ;
645		len = SPRINTF((tmp, "%s ", p_secstodate(t)));
646		T(addstr(tmp, (size_t)len, &buf, &buflen));
647
648		/* Mode , Error, Key Size. */
649		/* Priority, Weight, Port. */
650		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
651		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
652		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
653		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
654		T(addstr(tmp, (size_t)len, &buf, &buflen));
655
656		/* XXX need to dump key, print otherdata length & other data */
657		break;
658	    }
659
660	case ns_t_tsig: {
661		/* BEW - need to complete this */
662		int n;
663
664		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
665		T(addstr(" ", (size_t)1, &buf, &buflen));
666		rdata += 8; /*%< time */
667		n = ns_get16(rdata); rdata += INT16SZ;
668		rdata += n; /*%< sig */
669		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
670		sprintf(buf, "%d", ns_get16(rdata));
671		rdata += INT16SZ;
672		addlen(strlen(buf), &buf, &buflen);
673		break;
674	    }
675
676	case ns_t_a6: {
677		struct in6_addr a;
678		int pbyte, pbit;
679
680		/* prefix length */
681		if (rdlen == 0U) goto formerr;
682		len = SPRINTF((tmp, "%d ", *rdata));
683		T(addstr(tmp, (size_t)len, &buf, &buflen));
684		pbit = *rdata;
685		if (pbit > 128) goto formerr;
686		pbyte = (pbit & ~7) / 8;
687		rdata++;
688
689		/* address suffix: provided only when prefix len != 128 */
690		if (pbit < 128) {
691			if (rdata + pbyte >= edata) goto formerr;
692			memset(&a, 0, sizeof(a));
693			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
694			(void) inet_ntop(AF_INET6, &a, buf, (socklen_t)buflen);
695			addlen(strlen(buf), &buf, &buflen);
696			rdata += sizeof(a) - pbyte;
697		}
698
699		/* prefix name: provided only when prefix len > 0 */
700		if (pbit == 0)
701			break;
702		if (rdata >= edata) goto formerr;
703		T(addstr(" ", (size_t)1, &buf, &buflen));
704		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
705
706		break;
707	    }
708
709	case ns_t_opt: {
710		len = SPRINTF((tmp, "%u bytes", class));
711		T(addstr(tmp, (size_t)len, &buf, &buflen));
712		break;
713	    }
714
715	case ns_t_ds:
716	case ns_t_dlv:
717	case ns_t_sshfp: {
718		u_int t;
719
720		if (type == ns_t_ds || type == ns_t_dlv) {
721			if (rdlen < 4U) goto formerr;
722			t = ns_get16(rdata);
723			rdata += NS_INT16SZ;
724			len = SPRINTF((tmp, "%u ", t));
725			T(addstr(tmp, (size_t)len, &buf, &buflen));
726		} else
727			if (rdlen < 2U) goto formerr;
728
729		len = SPRINTF((tmp, "%u ", *rdata));
730		T(addstr(tmp, (size_t)len, &buf, &buflen));
731		rdata++;
732
733		len = SPRINTF((tmp, "%u ", *rdata));
734		T(addstr(tmp, (size_t)len, &buf, &buflen));
735		rdata++;
736
737		while (rdata < edata) {
738			len = SPRINTF((tmp, "%02X", *rdata));
739			T(addstr(tmp, (size_t)len, &buf, &buflen));
740			rdata++;
741		}
742		break;
743	    }
744
745	case ns_t_nsec3:
746	case ns_t_nsec3param: {
747		u_int t, w, l, j, k, c;
748
749		len = SPRINTF((tmp, "%u ", *rdata));
750		T(addstr(tmp, (size_t)len, &buf, &buflen));
751		rdata++;
752
753		len = SPRINTF((tmp, "%u ", *rdata));
754		T(addstr(tmp, (size_t)len, &buf, &buflen));
755		rdata++;
756
757		t = ns_get16(rdata);
758		rdata += NS_INT16SZ;
759		len = SPRINTF((tmp, "%u ", t));
760		T(addstr(tmp, (size_t)len, &buf, &buflen));
761
762		t = *rdata++;
763		if (t == 0) {
764			T(addstr("-", 1, &buf, &buflen));
765		} else {
766			while (t-- > 0) {
767				len = SPRINTF((tmp, "%02X", *rdata));
768				T(addstr(tmp, (size_t)len, &buf, &buflen));
769				rdata++;
770			}
771		}
772		if (type == ns_t_nsec3param)
773			break;
774		T(addstr(" ", 1, &buf, &buflen));
775
776		t = *rdata++;
777		while (t > 0) {
778			switch (t) {
779			case 1:
780				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
781				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)];
782				tmp[2] = tmp[3] = tmp[4] = '=';
783				tmp[5] = tmp[6] = tmp[7] = '=';
784				break;
785			case 2:
786				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
787				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
788						   (((uint32_t)rdata[1]>>6)&0x03)];
789				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
790				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)];
791				tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
792				break;
793			case 3:
794				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
795				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
796						   (((uint32_t)rdata[1]>>6)&0x03)];
797				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
798				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
799						   (((uint32_t)rdata[2]>>4)&0x0f)];
800				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)];
801				tmp[5] = tmp[6] = tmp[7] = '=';
802				break;
803			case 4:
804				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
805				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
806						   (((uint32_t)rdata[1]>>6)&0x03)];
807				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
808				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
809						   (((uint32_t)rdata[2]>>4)&0x0f)];
810				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
811						   (((uint32_t)rdata[3]>>7)&0x01)];
812				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
813				tmp[6] = base32hex[((uint32_t)rdata[3]<<3)&0x18];
814				tmp[7] = '=';
815				break;
816			default:
817				tmp[0] = base32hex[(((uint32_t)rdata[0]>>3)&0x1f)];
818				tmp[1] = base32hex[(((uint32_t)rdata[0]<<2)&0x1c)|
819						   (((uint32_t)rdata[1]>>6)&0x03)];
820				tmp[2] = base32hex[(((uint32_t)rdata[1]>>1)&0x1f)];
821				tmp[3] = base32hex[(((uint32_t)rdata[1]<<4)&0x10)|
822						   (((uint32_t)rdata[2]>>4)&0x0f)];
823				tmp[4] = base32hex[(((uint32_t)rdata[2]<<1)&0x1e)|
824						   (((uint32_t)rdata[3]>>7)&0x01)];
825				tmp[5] = base32hex[(((uint32_t)rdata[3]>>2)&0x1f)];
826				tmp[6] = base32hex[(((uint32_t)rdata[3]<<3)&0x18)|
827						   (((uint32_t)rdata[4]>>5)&0x07)];
828				tmp[7] = base32hex[(rdata[4]&0x1f)];
829				break;
830			}
831			T(addstr(tmp, 8, &buf, &buflen));
832			if (t >= 5) {
833				rdata += 5;
834				t -= 5;
835			} else {
836				rdata += t;
837				t -= t;
838			}
839		}
840
841		while (rdata < edata) {
842			w = *rdata++;
843			l = *rdata++;
844			for (j = 0; j < l; j++) {
845				if (rdata[j] == 0)
846					continue;
847				for (k = 0; k < 8; k++) {
848					if ((rdata[j] & (0x80 >> k)) == 0)
849						continue;
850					c = w * 256 + j * 8 + k;
851					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
852					T(addstr(tmp, (size_t)len, &buf, &buflen));
853				}
854			}
855			rdata += l;
856		}
857		break;
858	    }
859
860	case ns_t_nsec: {
861		u_int w, l, j, k, c;
862
863		T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
864
865		while (rdata < edata) {
866			w = *rdata++;
867			l = *rdata++;
868			for (j = 0; j < l; j++) {
869				if (rdata[j] == 0)
870					continue;
871				for (k = 0; k < 8; k++) {
872					if ((rdata[j] & (0x80 >> k)) == 0)
873						continue;
874					c = w * 256 + j * 8 + k;
875					len = SPRINTF((tmp, " %s", p_type((ns_type)c)));
876					T(addstr(tmp, (size_t)len, &buf, &buflen));
877				}
878			}
879			rdata += l;
880		}
881		break;
882	    }
883
884	case ns_t_dhcid: {
885		int n;
886		unsigned int siz;
887		char base64_dhcid[8192];
888		const char *leader;
889
890		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
891		if (siz > sizeof(base64_dhcid) * 3/4) {
892			const char *str = "record too long to print";
893			T(addstr(str, strlen(str), &buf, &buflen));
894		} else {
895			len = b64_ntop(rdata, (size_t)(edata-rdata),
896			    base64_dhcid, siz);
897
898			if (len < 0)
899				goto formerr;
900
901			else if (len > 15) {
902				T(addstr(" (", 2, &buf, &buflen));
903				leader = "\n\t\t";
904				spaced = 0;
905			}
906			else
907				leader = " ";
908
909			for (n = 0; n < len; n += 48) {
910				T(addstr(leader, strlen(leader),
911					 &buf, &buflen));
912				T(addstr(base64_dhcid + n,
913				    (size_t)MIN(len - n, 48), &buf, &buflen));
914			}
915			if (len > 15)
916				T(addstr(" )", 2, &buf, &buflen));
917		}
918		break;
919	}
920
921	case ns_t_ipseckey: {
922		int n;
923		unsigned int siz;
924		char base64_key[8192];
925		const char *leader;
926
927		if (rdlen < 2)
928			goto formerr;
929
930		switch (rdata[1]) {
931		case 0:
932		case 3:
933			if (rdlen < 3)
934				goto formerr;
935			break;
936		case 1:
937			if (rdlen < 7)
938				goto formerr;
939			break;
940		case 2:
941			if (rdlen < 19)
942				goto formerr;
943			break;
944		default:
945			comment = "unknown IPSECKEY gateway type";
946			goto hexify;
947		}
948
949		len = SPRINTF((tmp, "%u ", *rdata));
950		T(addstr(tmp, (size_t)len, &buf, &buflen));
951		rdata++;
952
953		len = SPRINTF((tmp, "%u ", *rdata));
954		T(addstr(tmp, (size_t)len, &buf, &buflen));
955		rdata++;
956
957		len = SPRINTF((tmp, "%u ", *rdata));
958		T(addstr(tmp, (size_t)len, &buf, &buflen));
959		rdata++;
960
961		switch (rdata[-2]) {
962		case 0:
963			T(addstr(".", 1, &buf, &buflen));
964			break;
965		case 1:
966			(void) inet_ntop(AF_INET, rdata, buf, (socklen_t)buflen);
967			addlen(strlen(buf), &buf, &buflen);
968			rdata += 4;
969			break;
970		case 2:
971			(void) inet_ntop(AF_INET6, rdata, buf, (socklen_t)buflen);
972			addlen(strlen(buf), &buf, &buflen);
973			rdata += 16;
974			break;
975		case 3:
976			T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
977			break;
978		}
979
980		if (rdata >= edata)
981			break;
982
983		siz = (int)(edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
984		if (siz > sizeof(base64_key) * 3/4) {
985			const char *str = "record too long to print";
986			T(addstr(str, strlen(str), &buf, &buflen));
987		} else {
988			len = b64_ntop(rdata, (size_t)(edata-rdata),
989			    base64_key, siz);
990
991			if (len < 0)
992				goto formerr;
993
994			else if (len > 15) {
995				T(addstr(" (", 2, &buf, &buflen));
996				leader = "\n\t\t";
997				spaced = 0;
998			}
999			else
1000				leader = " ";
1001
1002			for (n = 0; n < len; n += 48) {
1003				T(addstr(leader, strlen(leader),
1004					 &buf, &buflen));
1005				T(addstr(base64_key + n,
1006				    (size_t)MIN(len - n, 48), &buf, &buflen));
1007			}
1008			if (len > 15)
1009				T(addstr(" )", 2, &buf, &buflen));
1010		}
1011		break;
1012	}
1013
1014	case ns_t_hip: {
1015		unsigned int i, hip_len, algorithm, key_len;
1016		char base64_key[NS_MD5RSA_MAX_BASE64];
1017		unsigned int siz;
1018		const char *leader = "\n\t\t\t\t\t";
1019
1020		hip_len = *rdata++;
1021		algorithm = *rdata++;
1022		key_len = ns_get16(rdata);
1023		rdata += NS_INT16SZ;
1024
1025		siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
1026		if (siz > sizeof(base64_key) * 3/4) {
1027			const char *str = "record too long to print";
1028			T(addstr(str, strlen(str), &buf, &buflen));
1029		} else {
1030			len = sprintf(tmp, "( %u ", algorithm);
1031			T(addstr(tmp, (size_t)len, &buf, &buflen));
1032
1033			for (i = 0; i < hip_len; i++) {
1034				len = sprintf(tmp, "%02X", *rdata);
1035				T(addstr(tmp, (size_t)len, &buf, &buflen));
1036				rdata++;
1037			}
1038			T(addstr(leader, strlen(leader), &buf, &buflen));
1039
1040			len = b64_ntop(rdata, key_len, base64_key, siz);
1041			if (len < 0)
1042				goto formerr;
1043
1044			T(addstr(base64_key, (size_t)len, &buf, &buflen));
1045
1046			rdata += key_len;
1047			while (rdata < edata) {
1048				T(addstr(leader, strlen(leader), &buf, &buflen));
1049				T(addname(msg, msglen, &rdata, origin,
1050					  &buf, &buflen));
1051			}
1052			T(addstr(" )", 2, &buf, &buflen));
1053		}
1054		break;
1055	}
1056
1057	default:
1058		comment = "unknown RR type";
1059		goto hexify;
1060	}
1061	assert(INT_MIN <= (buf - obuf) && (buf - obuf) <= INT_MAX);
1062	return (int)(buf - obuf);
1063 formerr:
1064	comment = "RR format error";
1065 hexify: {
1066	int n, m;
1067	char *p;
1068
1069	len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
1070		       rdlen != 0U ? " (" : "", comment));
1071	T(addstr(tmp, (size_t)len, &buf, &buflen));
1072	while (rdata < edata) {
1073		p = tmp;
1074		p += SPRINTF((p, "\n\t"));
1075		spaced = 0;
1076		n = MIN(16, (int)(edata - rdata));
1077		for (m = 0; m < n; m++)
1078			p += SPRINTF((p, "%02x ", rdata[m]));
1079		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
1080		if (n < 16) {
1081			T(addstr(")", (size_t)1, &buf, &buflen));
1082			T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
1083		}
1084		p = tmp;
1085		p += SPRINTF((p, "; "));
1086		for (m = 0; m < n; m++)
1087			*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
1088				? rdata[m]
1089				: '.';
1090		T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
1091		rdata += n;
1092	}
1093	assert(INT_MIN <= (buf - obuf) && (buf - obuf) <= INT_MAX);
1094	return (int)(buf - obuf);
1095    }
1096}
1097
1098/* Private. */
1099
1100/*%
1101 * size_t
1102 * prune_origin(name, origin)
1103 *	Find out if the name is at or under the current origin.
1104 * return:
1105 *	Number of characters in name before start of origin,
1106 *	or length of name if origin does not match.
1107 * notes:
1108 *	This function should share code with samedomain().
1109 */
1110static size_t
1111prune_origin(const char *name, const char *origin) {
1112	const char *oname = name;
1113
1114	while (*name != '\0') {
1115		if (origin != NULL && ns_samename(name, origin) == 1)
1116			return (name - oname - (name > oname));
1117		while (*name != '\0') {
1118			if (*name == '\\') {
1119				name++;
1120				/* XXX need to handle \nnn form. */
1121				if (*name == '\0')
1122					break;
1123			} else if (*name == '.') {
1124				name++;
1125				break;
1126			}
1127			name++;
1128		}
1129	}
1130	return (name - oname);
1131}
1132
1133/*%
1134 * int
1135 * charstr(rdata, edata, buf, buflen)
1136 *	Format a <character-string> into the presentation buffer.
1137 * return:
1138 *	Number of rdata octets consumed
1139 *	0 for protocol format error
1140 *	-1 for output buffer error
1141 * side effects:
1142 *	buffer is advanced on success.
1143 */
1144static int
1145charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
1146	const u_char *odata = rdata;
1147	size_t save_buflen = *buflen;
1148	char *save_buf = *buf;
1149
1150	if (addstr("\"", (size_t)1, buf, buflen) < 0)
1151		goto enospc;
1152	if (rdata < edata) {
1153		int n = *rdata;
1154
1155		if (rdata + 1 + n <= edata) {
1156			rdata++;
1157			while (n-- > 0) {
1158				if (strchr("\n\"\\", *rdata) != NULL)
1159					if (addstr("\\", (size_t)1, buf, buflen) < 0)
1160						goto enospc;
1161				if (addstr((const char *)rdata, (size_t)1,
1162					   buf, buflen) < 0)
1163					goto enospc;
1164				rdata++;
1165			}
1166		}
1167	}
1168	if (addstr("\"", (size_t)1, buf, buflen) < 0)
1169		goto enospc;
1170	assert(INT_MIN <= (rdata - odata) && (rdata - odata) <= INT_MAX);
1171	return (int)(rdata - odata);
1172 enospc:
1173	errno = ENOSPC;
1174	*buf = save_buf;
1175	*buflen = save_buflen;
1176	return (-1);
1177}
1178
1179static int
1180addname(const u_char *msg, size_t msglen,
1181	const u_char **pp, const char *origin,
1182	char **buf, size_t *buflen)
1183{
1184	size_t newlen, save_buflen = *buflen;
1185	char *save_buf = *buf;
1186	int n;
1187
1188	n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
1189	if (n < 0)
1190		goto enospc;	/*%< Guess. */
1191	newlen = prune_origin(*buf, origin);
1192	if (**buf == '\0') {
1193		goto root;
1194	} else if (newlen == 0U) {
1195		/* Use "@" instead of name. */
1196		if (newlen + 2 > *buflen)
1197			goto enospc;        /* No room for "@\0". */
1198		(*buf)[newlen++] = '@';
1199		(*buf)[newlen] = '\0';
1200	} else {
1201		if (((origin == NULL || origin[0] == '\0') ||
1202		    (origin[0] != '.' && origin[1] != '\0' &&
1203		    (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
1204			/* No trailing dot. */
1205 root:
1206			if (newlen + 2 > *buflen)
1207				goto enospc;	/* No room for ".\0". */
1208			(*buf)[newlen++] = '.';
1209			(*buf)[newlen] = '\0';
1210		}
1211	}
1212	*pp += n;
1213	addlen(newlen, buf, buflen);
1214	**buf = '\0';
1215	assert(newlen <= INT_MAX);
1216	return (int)newlen;
1217 enospc:
1218	errno = ENOSPC;
1219	*buf = save_buf;
1220	*buflen = save_buflen;
1221	return (-1);
1222}
1223
1224static void
1225addlen(size_t len, char **buf, size_t *buflen) {
1226	INSIST(len <= *buflen);
1227	*buf += len;
1228	*buflen -= len;
1229}
1230
1231static int
1232addstr(const char *src, size_t len, char **buf, size_t *buflen) {
1233	if (len >= *buflen) {
1234		errno = ENOSPC;
1235		return (-1);
1236	}
1237	memcpy(*buf, src, len);
1238	addlen(len, buf, buflen);
1239	**buf = '\0';
1240	return (0);
1241}
1242
1243static int
1244addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
1245	size_t save_buflen = *buflen;
1246	char *save_buf = *buf;
1247	ptrdiff_t t;
1248
1249	if (spaced || len >= target - 1) {
1250		T(addstr("  ", (size_t)2, buf, buflen));
1251		spaced = 1;
1252	} else {
1253		for (t = (target - len - 1) / 8; t >= 0; t--)
1254			if (addstr("\t", (size_t)1, buf, buflen) < 0) {
1255				*buflen = save_buflen;
1256				*buf = save_buf;
1257				return (-1);
1258			}
1259		spaced = 0;
1260	}
1261	return (spaced);
1262}
1263
1264/*! \file */
1265