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