]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/nameser/ns_print.c
Update our stub resolver to final version of libbind.
[FreeBSD/FreeBSD.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         }
915
916         case ns_t_ipseckey: {
917                 int n;
918                 unsigned int siz;
919                 char base64_key[8192];
920                 const char *leader;
921         
922                 if (rdlen < 2)
923                         goto formerr;
924
925                 switch (rdata[1]) {
926                 case 0:
927                 case 3:
928                         if (rdlen < 3)
929                                 goto formerr;
930                         break;
931                 case 1:
932                         if (rdlen < 7)
933                                 goto formerr;
934                         break;
935                 case 2:
936                         if (rdlen < 19)
937                                 goto formerr;
938                         break;
939                 default:
940                         comment = "unknown IPSECKEY gateway type";
941                         goto hexify;
942                 }
943
944                 len = SPRINTF((tmp, "%u ", *rdata));
945                 T(addstr(tmp, len, &buf, &buflen));
946                 rdata++;
947
948                 len = SPRINTF((tmp, "%u ", *rdata));
949                 T(addstr(tmp, len, &buf, &buflen));
950                 rdata++;
951                 
952                 len = SPRINTF((tmp, "%u ", *rdata));
953                 T(addstr(tmp, len, &buf, &buflen));
954                 rdata++;
955
956                 switch (rdata[-2]) {
957                 case 0:
958                         T(addstr(".", 1, &buf, &buflen));
959                         break;
960                 case 1:
961                         (void) inet_ntop(AF_INET, rdata, buf, buflen);
962                         addlen(strlen(buf), &buf, &buflen);
963                         rdata += 4;
964                         break;
965                 case 2:
966                         (void) inet_ntop(AF_INET6, rdata, buf, buflen);
967                         addlen(strlen(buf), &buf, &buflen);
968                         rdata += 16;
969                         break;
970                 case 3:
971                         T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
972                         break;
973                 }
974
975                 if (rdata >= edata)
976                         break;
977
978                 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
979                 if (siz > sizeof(base64_key) * 3/4) {
980                         const char *str = "record too long to print";
981                         T(addstr(str, strlen(str), &buf, &buflen));
982                 } else {
983                         len = b64_ntop(rdata, edata-rdata, base64_key, siz);
984
985                         if (len < 0)
986                                 goto formerr;
987
988                         else if (len > 15) {
989                                 T(addstr(" (", 2, &buf, &buflen));
990                                 leader = "\n\t\t";
991                                 spaced = 0;
992                         }
993                         else
994                                 leader = " ";
995
996                         for (n = 0; n < len; n += 48) {
997                                 T(addstr(leader, strlen(leader),
998                                          &buf, &buflen));
999                                 T(addstr(base64_key + n, MIN(len - n, 48),
1000                                          &buf, &buflen));
1001                         }
1002                         if (len > 15)
1003                                 T(addstr(" )", 2, &buf, &buflen));
1004                 }
1005         }
1006
1007         case ns_t_hip: {
1008                 unsigned int i, hip_len, algorithm, key_len;
1009                 char base64_key[NS_MD5RSA_MAX_BASE64];
1010                 unsigned int siz;
1011                 const char *leader = "\n\t\t\t\t\t";
1012                 
1013                 hip_len = *rdata++;
1014                 algorithm = *rdata++;
1015                 key_len = ns_get16(rdata);
1016                 rdata += NS_INT16SZ;
1017
1018                 siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
1019                 if (siz > sizeof(base64_key) * 3/4) {
1020                         const char *str = "record too long to print";
1021                         T(addstr(str, strlen(str), &buf, &buflen));
1022                 } else {
1023                         len = sprintf(tmp, "( %u ", algorithm);
1024                         T(addstr(tmp, len, &buf, &buflen));
1025
1026                         for (i = 0; i < hip_len; i++) {
1027                                 len = sprintf(tmp, "%02X", *rdata);
1028                                 T(addstr(tmp, len, &buf, &buflen));
1029                                 rdata++;
1030                         }
1031                         T(addstr(leader, strlen(leader), &buf, &buflen));
1032
1033                         len = b64_ntop(rdata, key_len, base64_key, siz);
1034                         if (len < 0)
1035                                 goto formerr;
1036
1037                         T(addstr(base64_key, len, &buf, &buflen));
1038                                 
1039                         rdata += key_len;
1040                         while (rdata < edata) {
1041                                 T(addstr(leader, strlen(leader), &buf, &buflen));
1042                                 T(addname(msg, msglen, &rdata, origin,
1043                                           &buf, &buflen));
1044                         }
1045                         T(addstr(" )", 2, &buf, &buflen));
1046                 }
1047                 break;
1048         }
1049
1050         default:
1051                 comment = "unknown RR type";
1052                 goto hexify;
1053         }
1054         return (buf - obuf);
1055  formerr:
1056         comment = "RR format error";
1057  hexify: {
1058         int n, m;
1059         char *p;
1060
1061         len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
1062                        rdlen != 0U ? " (" : "", comment));
1063         T(addstr(tmp, len, &buf, &buflen));
1064         while (rdata < edata) {
1065                 p = tmp;
1066                 p += SPRINTF((p, "\n\t"));
1067                 spaced = 0;
1068                 n = MIN(16, edata - rdata);
1069                 for (m = 0; m < n; m++)
1070                         p += SPRINTF((p, "%02x ", rdata[m]));
1071                 T(addstr(tmp, p - tmp, &buf, &buflen));
1072                 if (n < 16) {
1073                         T(addstr(")", 1, &buf, &buflen));
1074                         T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
1075                 }
1076                 p = tmp;
1077                 p += SPRINTF((p, "; "));
1078                 for (m = 0; m < n; m++)
1079                         *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
1080                                 ? rdata[m]
1081                                 : '.';
1082                 T(addstr(tmp, p - tmp, &buf, &buflen));
1083                 rdata += n;
1084         }
1085         return (buf - obuf);
1086     }
1087 }
1088
1089 /* Private. */
1090
1091 /*%
1092  * size_t
1093  * prune_origin(name, origin)
1094  *      Find out if the name is at or under the current origin.
1095  * return:
1096  *      Number of characters in name before start of origin,
1097  *      or length of name if origin does not match.
1098  * notes:
1099  *      This function should share code with samedomain().
1100  */
1101 static size_t
1102 prune_origin(const char *name, const char *origin) {
1103         const char *oname = name;
1104
1105         while (*name != '\0') {
1106                 if (origin != NULL && ns_samename(name, origin) == 1)
1107                         return (name - oname - (name > oname));
1108                 while (*name != '\0') {
1109                         if (*name == '\\') {
1110                                 name++;
1111                                 /* XXX need to handle \nnn form. */
1112                                 if (*name == '\0')
1113                                         break;
1114                         } else if (*name == '.') {
1115                                 name++;
1116                                 break;
1117                         }
1118                         name++;
1119                 }
1120         }
1121         return (name - oname);
1122 }
1123
1124 /*%
1125  * int
1126  * charstr(rdata, edata, buf, buflen)
1127  *      Format a <character-string> into the presentation buffer.
1128  * return:
1129  *      Number of rdata octets consumed
1130  *      0 for protocol format error
1131  *      -1 for output buffer error
1132  * side effects:
1133  *      buffer is advanced on success.
1134  */
1135 static int
1136 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
1137         const u_char *odata = rdata;
1138         size_t save_buflen = *buflen;
1139         char *save_buf = *buf;
1140
1141         if (addstr("\"", 1, buf, buflen) < 0)
1142                 goto enospc;
1143         if (rdata < edata) {
1144                 int n = *rdata;
1145
1146                 if (rdata + 1 + n <= edata) {
1147                         rdata++;
1148                         while (n-- > 0) {
1149                                 if (strchr("\n\"\\", *rdata) != NULL)
1150                                         if (addstr("\\", 1, buf, buflen) < 0)
1151                                                 goto enospc;
1152                                 if (addstr((const char *)rdata, 1,
1153                                            buf, buflen) < 0)
1154                                         goto enospc;
1155                                 rdata++;
1156                         }
1157                 }
1158         }
1159         if (addstr("\"", 1, buf, buflen) < 0)
1160                 goto enospc;
1161         return (rdata - odata);
1162  enospc:
1163         errno = ENOSPC;
1164         *buf = save_buf;
1165         *buflen = save_buflen;
1166         return (-1);
1167 }
1168
1169 static int
1170 addname(const u_char *msg, size_t msglen,
1171         const u_char **pp, const char *origin,
1172         char **buf, size_t *buflen)
1173 {
1174         size_t newlen, save_buflen = *buflen;
1175         char *save_buf = *buf;
1176         int n;
1177
1178         n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
1179         if (n < 0)
1180                 goto enospc;    /*%< Guess. */
1181         newlen = prune_origin(*buf, origin);
1182         if (**buf == '\0') {
1183                 goto root;
1184         } else if (newlen == 0U) {
1185                 /* Use "@" instead of name. */
1186                 if (newlen + 2 > *buflen)
1187                         goto enospc;        /* No room for "@\0". */
1188                 (*buf)[newlen++] = '@';
1189                 (*buf)[newlen] = '\0';
1190         } else {
1191                 if (((origin == NULL || origin[0] == '\0') ||
1192                     (origin[0] != '.' && origin[1] != '\0' &&
1193                     (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
1194                         /* No trailing dot. */
1195  root:
1196                         if (newlen + 2 > *buflen)
1197                                 goto enospc;    /* No room for ".\0". */
1198                         (*buf)[newlen++] = '.';
1199                         (*buf)[newlen] = '\0';
1200                 }
1201         }
1202         *pp += n;
1203         addlen(newlen, buf, buflen);
1204         **buf = '\0';
1205         return (newlen);
1206  enospc:
1207         errno = ENOSPC;
1208         *buf = save_buf;
1209         *buflen = save_buflen;
1210         return (-1);
1211 }
1212
1213 static void
1214 addlen(size_t len, char **buf, size_t *buflen) {
1215         INSIST(len <= *buflen);
1216         *buf += len;
1217         *buflen -= len;
1218 }
1219
1220 static int
1221 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
1222         if (len >= *buflen) {
1223                 errno = ENOSPC;
1224                 return (-1);
1225         }
1226         memcpy(*buf, src, len);
1227         addlen(len, buf, buflen);
1228         **buf = '\0';
1229         return (0);
1230 }
1231
1232 static int
1233 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
1234         size_t save_buflen = *buflen;
1235         char *save_buf = *buf;
1236         int t;
1237
1238         if (spaced || len >= target - 1) {
1239                 T(addstr("  ", 2, buf, buflen));
1240                 spaced = 1;
1241         } else {
1242                 for (t = (target - len - 1) / 8; t >= 0; t--)
1243                         if (addstr("\t", 1, buf, buflen) < 0) {
1244                                 *buflen = save_buflen;
1245                                 *buf = save_buf;
1246                                 return (-1);
1247                         }
1248                 spaced = 0;
1249         }
1250         return (spaced);
1251 }
1252
1253 /*! \file */