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