Merge branch 'vendor/MPFR' into gcc441
[dragonfly.git] / contrib / bind-9.3 / lib / bind / 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.3.2.1.4.7 2004/09/16 07:01:12 marka Exp $";
20 #endif
21
22 /* Import. */
23
24 #include "port_before.h"
25
26 #include <sys/types.h>
27 #include <sys/socket.h>
28
29 #include <netinet/in.h>
30 #include <arpa/nameser.h>
31 #include <arpa/inet.h>
32
33 #ifdef _LIBC
34 #include <assert.h>
35 #define INSIST(cond)    assert(cond)
36 #else
37 #include <isc/assertions.h>
38 #include <isc/dst.h>
39 #endif
40 #include <errno.h>
41 #include <resolv.h>
42 #include <string.h>
43 #include <ctype.h>
44
45 #include "port_after.h"
46
47 #ifdef SPRINTF_CHAR
48 # define SPRINTF(x) strlen(sprintf/**/x)
49 #else
50 # define SPRINTF(x) ((size_t)sprintf x)
51 #endif
52
53 /* Forward. */
54
55 static size_t   prune_origin(const char *name, const char *origin);
56 static int      charstr(const u_char *rdata, const u_char *edata,
57                         char **buf, size_t *buflen);
58 static int      addname(const u_char *msg, size_t msglen,
59                         const u_char **p, const char *origin,
60                         char **buf, size_t *buflen);
61 static void     addlen(size_t len, char **buf, size_t *buflen);
62 static int      addstr(const char *src, size_t len,
63                        char **buf, size_t *buflen);
64 static int      addtab(size_t len, size_t target, int spaced,
65                        char **buf, size_t *buflen);
66
67 /* Macros. */
68
69 #define T(x) \
70         do { \
71                 if ((x) < 0) \
72                         return (-1); \
73         } while (0)
74
75 /* Public. */
76
77 /*
78  * int
79  * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
80  *      Convert an RR to presentation format.
81  * return:
82  *      Number of characters written to buf, or -1 (check errno).
83  */
84 int
85 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
86             const char *name_ctx, const char *origin,
87             char *buf, size_t buflen)
88 {
89         int n;
90
91         n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
92                          ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
93                          ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
94                          name_ctx, origin, buf, buflen);
95         return (n);
96 }
97
98 /*
99  * int
100  * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
101  *             name_ctx, origin, buf, buflen)
102  *      Convert the fields of an RR into presentation format.
103  * return:
104  *      Number of characters written to buf, or -1 (check errno).
105  */
106 int
107 ns_sprintrrf(const u_char *msg, size_t msglen,
108             const char *name, ns_class class, ns_type type,
109             u_long ttl, const u_char *rdata, size_t rdlen,
110             const char *name_ctx, const char *origin,
111             char *buf, size_t buflen)
112 {
113         const char *obuf = buf;
114         const u_char *edata = rdata + rdlen;
115         int spaced = 0;
116
117         const char *comment;
118         char tmp[100];
119         int len, x;
120
121         /*
122          * Owner.
123          */
124         if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
125                 T(addstr("\t\t\t", 3, &buf, &buflen));
126         } else {
127                 len = prune_origin(name, origin);
128                 if (*name == '\0') {
129                         goto root;
130                 } else if (len == 0) {
131                         T(addstr("@\t\t\t", 4, &buf, &buflen));
132                 } else {
133                         T(addstr(name, len, &buf, &buflen));
134                         /* Origin not used or not root, and no trailing dot? */
135                         if (((origin == NULL || origin[0] == '\0') ||
136                             (origin[0] != '.' && origin[1] != '\0' &&
137                             name[len] == '\0')) && name[len - 1] != '.') {
138  root:
139                                 T(addstr(".", 1, &buf, &buflen));
140                                 len++;
141                         }
142                         T(spaced = addtab(len, 24, spaced, &buf, &buflen));
143                 }
144         }
145
146         /*
147          * TTL, Class, Type.
148          */
149         T(x = ns_format_ttl(ttl, buf, buflen));
150         addlen(x, &buf, &buflen);
151         len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
152         T(addstr(tmp, len, &buf, &buflen));
153         T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
154
155         /*
156          * RData.
157          */
158         switch (type) {
159         case ns_t_a:
160                 if (rdlen != (size_t)NS_INADDRSZ)
161                         goto formerr;
162                 (void) inet_ntop(AF_INET, rdata, buf, buflen);
163                 addlen(strlen(buf), &buf, &buflen);
164                 break;
165
166         case ns_t_cname:
167         case ns_t_mb:
168         case ns_t_mg:
169         case ns_t_mr:
170         case ns_t_ns:
171         case ns_t_ptr:
172         case ns_t_dname:
173                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
174                 break;
175
176         case ns_t_hinfo:
177         case ns_t_isdn:
178                 /* First word. */
179                 T(len = charstr(rdata, edata, &buf, &buflen));
180                 if (len == 0)
181                         goto formerr;
182                 rdata += len;
183                 T(addstr(" ", 1, &buf, &buflen));
184
185                     
186                 /* Second word, optional in ISDN records. */
187                 if (type == ns_t_isdn && rdata == edata)
188                         break;
189                     
190                 T(len = charstr(rdata, edata, &buf, &buflen));
191                 if (len == 0)
192                         goto formerr;
193                 rdata += len;
194                 break;
195
196         case ns_t_soa: {
197                 u_long t;
198
199                 /* Server name. */
200                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
201                 T(addstr(" ", 1, &buf, &buflen));
202
203                 /* Administrator name. */
204                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
205                 T(addstr(" (\n", 3, &buf, &buflen));
206                 spaced = 0;
207
208                 if ((edata - rdata) != 5*NS_INT32SZ)
209                         goto formerr;
210
211                 /* Serial number. */
212                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
213                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
214                 len = SPRINTF((tmp, "%lu", t));
215                 T(addstr(tmp, len, &buf, &buflen));
216                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
217                 T(addstr("; serial\n", 9, &buf, &buflen));
218                 spaced = 0;
219
220                 /* Refresh interval. */
221                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
222                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
223                 T(len = ns_format_ttl(t, buf, buflen));
224                 addlen(len, &buf, &buflen);
225                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
226                 T(addstr("; refresh\n", 10, &buf, &buflen));
227                 spaced = 0;
228
229                 /* Retry interval. */
230                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
231                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
232                 T(len = ns_format_ttl(t, buf, buflen));
233                 addlen(len, &buf, &buflen);
234                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
235                 T(addstr("; retry\n", 8, &buf, &buflen));
236                 spaced = 0;
237
238                 /* Expiry. */
239                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
240                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
241                 T(len = ns_format_ttl(t, buf, buflen));
242                 addlen(len, &buf, &buflen);
243                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
244                 T(addstr("; expiry\n", 9, &buf, &buflen));
245                 spaced = 0;
246
247                 /* Minimum TTL. */
248                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
249                 T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
250                 T(len = ns_format_ttl(t, buf, buflen));
251                 addlen(len, &buf, &buflen);
252                 T(addstr(" )", 2, &buf, &buflen));
253                 T(spaced = addtab(len, 16, spaced, &buf, &buflen));
254                 T(addstr("; minimum\n", 10, &buf, &buflen));
255
256                 break;
257             }
258
259         case ns_t_mx:
260         case ns_t_afsdb:
261         case ns_t_rt: {
262                 u_int t;
263
264                 if (rdlen < (size_t)NS_INT16SZ)
265                         goto formerr;
266
267                 /* Priority. */
268                 t = ns_get16(rdata);
269                 rdata += NS_INT16SZ;
270                 len = SPRINTF((tmp, "%u ", t));
271                 T(addstr(tmp, len, &buf, &buflen));
272
273                 /* Target. */
274                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
275
276                 break;
277             }
278
279         case ns_t_px: {
280                 u_int t;
281
282                 if (rdlen < (size_t)NS_INT16SZ)
283                         goto formerr;
284
285                 /* Priority. */
286                 t = ns_get16(rdata);
287                 rdata += NS_INT16SZ;
288                 len = SPRINTF((tmp, "%u ", t));
289                 T(addstr(tmp, len, &buf, &buflen));
290
291                 /* Name1. */
292                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
293                 T(addstr(" ", 1, &buf, &buflen));
294
295                 /* Name2. */
296                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
297
298                 break;
299             }
300
301         case ns_t_x25:
302                 T(len = charstr(rdata, edata, &buf, &buflen));
303                 if (len == 0)
304                         goto formerr;
305                 rdata += len;
306                 break;
307
308         case ns_t_txt:
309                 while (rdata < edata) {
310                         T(len = charstr(rdata, edata, &buf, &buflen));
311                         if (len == 0)
312                                 goto formerr;
313                         rdata += len;
314                         if (rdata < edata)
315                                 T(addstr(" ", 1, &buf, &buflen));
316                 }
317                 break;
318
319         case ns_t_nsap: {
320                 char t[2+255*3];
321
322                 (void) inet_nsap_ntoa(rdlen, rdata, t);
323                 T(addstr(t, strlen(t), &buf, &buflen));
324                 break;
325             }
326
327         case ns_t_aaaa:
328                 if (rdlen != (size_t)NS_IN6ADDRSZ)
329                         goto formerr;
330                 (void) inet_ntop(AF_INET6, rdata, buf, buflen);
331                 addlen(strlen(buf), &buf, &buflen);
332                 break;
333
334         case ns_t_loc: {
335                 char t[255];
336
337                 /* XXX protocol format checking? */
338                 (void) loc_ntoa(rdata, t);
339                 T(addstr(t, strlen(t), &buf, &buflen));
340                 break;
341             }
342
343         case ns_t_naptr: {
344                 u_int order, preference;
345                 char t[50];
346
347                 if (rdlen < 2U*NS_INT16SZ)
348                         goto formerr;
349
350                 /* Order, Precedence. */
351                 order = ns_get16(rdata);        rdata += NS_INT16SZ;
352                 preference = ns_get16(rdata);   rdata += NS_INT16SZ;
353                 len = SPRINTF((t, "%u %u ", order, preference));
354                 T(addstr(t, len, &buf, &buflen));
355
356                 /* Flags. */
357                 T(len = charstr(rdata, edata, &buf, &buflen));
358                 if (len == 0)
359                         goto formerr;
360                 rdata += len;
361                 T(addstr(" ", 1, &buf, &buflen));
362
363                 /* Service. */
364                 T(len = charstr(rdata, edata, &buf, &buflen));
365                 if (len == 0)
366                         goto formerr;
367                 rdata += len;
368                 T(addstr(" ", 1, &buf, &buflen));
369
370                 /* Regexp. */
371                 T(len = charstr(rdata, edata, &buf, &buflen));
372                 if (len < 0)
373                         return (-1);
374                 if (len == 0)
375                         goto formerr;
376                 rdata += len;
377                 T(addstr(" ", 1, &buf, &buflen));
378
379                 /* Server. */
380                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
381                 break;
382             }
383
384         case ns_t_srv: {
385                 u_int priority, weight, port;
386                 char t[50];
387
388                 if (rdlen < 3U*NS_INT16SZ)
389                         goto formerr;
390
391                 /* Priority, Weight, Port. */
392                 priority = ns_get16(rdata);  rdata += NS_INT16SZ;
393                 weight   = ns_get16(rdata);  rdata += NS_INT16SZ;
394                 port     = ns_get16(rdata);  rdata += NS_INT16SZ;
395                 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
396                 T(addstr(t, len, &buf, &buflen));
397
398                 /* Server. */
399                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
400                 break;
401             }
402
403         case ns_t_minfo:
404         case ns_t_rp:
405                 /* Name1. */
406                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
407                 T(addstr(" ", 1, &buf, &buflen));
408
409                 /* Name2. */
410                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
411
412                 break;
413
414         case ns_t_wks: {
415                 int n, lcnt;
416
417                 if (rdlen < 1U + NS_INT32SZ)
418                         goto formerr;
419
420                 /* Address. */
421                 (void) inet_ntop(AF_INET, rdata, buf, buflen);
422                 addlen(strlen(buf), &buf, &buflen);
423                 rdata += NS_INADDRSZ;
424
425                 /* Protocol. */
426                 len = SPRINTF((tmp, " %u ( ", *rdata));
427                 T(addstr(tmp, len, &buf, &buflen));
428                 rdata += NS_INT8SZ;
429
430                 /* Bit map. */
431                 n = 0;
432                 lcnt = 0;
433                 while (rdata < edata) {
434                         u_int c = *rdata++;
435                         do {
436                                 if (c & 0200) {
437                                         if (lcnt == 0) {
438                                                 T(addstr("\n\t\t\t\t", 5,
439                                                          &buf, &buflen));
440                                                 lcnt = 10;
441                                                 spaced = 0;
442                                         }
443                                         len = SPRINTF((tmp, "%d ", n));
444                                         T(addstr(tmp, len, &buf, &buflen));
445                                         lcnt--;
446                                 }
447                                 c <<= 1;
448                         } while (++n & 07);
449                 }
450                 T(addstr(")", 1, &buf, &buflen));
451
452                 break;
453             }
454
455         case ns_t_key: {
456                 char base64_key[NS_MD5RSA_MAX_BASE64];
457                 u_int keyflags, protocol, algorithm, key_id;
458                 const char *leader;
459                 int n;
460
461                 if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
462                         goto formerr;
463
464                 /* Key flags, Protocol, Algorithm. */
465 #ifndef _LIBC
466                 key_id = dst_s_dns_key_id(rdata, edata-rdata);
467 #else
468                 key_id = 0;
469 #endif
470                 keyflags = ns_get16(rdata);  rdata += NS_INT16SZ;
471                 protocol = *rdata++;
472                 algorithm = *rdata++;
473                 len = SPRINTF((tmp, "0x%04x %u %u",
474                                keyflags, protocol, algorithm));
475                 T(addstr(tmp, len, &buf, &buflen));
476
477                 /* Public key data. */
478                 len = b64_ntop(rdata, edata - rdata,
479                                base64_key, sizeof base64_key);
480                 if (len < 0)
481                         goto formerr;
482                 if (len > 15) {
483                         T(addstr(" (", 2, &buf, &buflen));
484                         leader = "\n\t\t";
485                         spaced = 0;
486                 } else
487                         leader = " ";
488                 for (n = 0; n < len; n += 48) {
489                         T(addstr(leader, strlen(leader), &buf, &buflen));
490                         T(addstr(base64_key + n, MIN(len - n, 48),
491                                  &buf, &buflen));
492                 }
493                 if (len > 15)
494                         T(addstr(" )", 2, &buf, &buflen));
495                 n = SPRINTF((tmp, " ; key_tag= %u", key_id));
496                 T(addstr(tmp, n, &buf, &buflen));
497
498                 break;
499             }
500
501         case ns_t_sig: {
502                 char base64_key[NS_MD5RSA_MAX_BASE64];
503                 u_int type, algorithm, labels, footprint;
504                 const char *leader;
505                 u_long t;
506                 int n;
507
508                 if (rdlen < 22U)
509                         goto formerr;
510
511                 /* Type covered, Algorithm, Label count, Original TTL. */
512                 type = ns_get16(rdata);  rdata += NS_INT16SZ;
513                 algorithm = *rdata++;
514                 labels = *rdata++;
515                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
516                 len = SPRINTF((tmp, "%s %d %d %lu ",
517                                p_type(type), algorithm, labels, t));
518                 T(addstr(tmp, len, &buf, &buflen));
519                 if (labels > (u_int)dn_count_labels(name))
520                         goto formerr;
521
522                 /* Signature expiry. */
523                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
524                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
525                 T(addstr(tmp, len, &buf, &buflen));
526
527                 /* Time signed. */
528                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
529                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
530                 T(addstr(tmp, len, &buf, &buflen));
531
532                 /* Signature Footprint. */
533                 footprint = ns_get16(rdata);  rdata += NS_INT16SZ;
534                 len = SPRINTF((tmp, "%u ", footprint));
535                 T(addstr(tmp, len, &buf, &buflen));
536
537                 /* Signer's name. */
538                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
539
540                 /* Signature. */
541                 len = b64_ntop(rdata, edata - rdata,
542                                base64_key, sizeof base64_key);
543                 if (len > 15) {
544                         T(addstr(" (", 2, &buf, &buflen));
545                         leader = "\n\t\t";
546                         spaced = 0;
547                 } else
548                         leader = " ";
549                 if (len < 0)
550                         goto formerr;
551                 for (n = 0; n < len; n += 48) {
552                         T(addstr(leader, strlen(leader), &buf, &buflen));
553                         T(addstr(base64_key + n, MIN(len - n, 48),
554                                  &buf, &buflen));
555                 }
556                 if (len > 15)
557                         T(addstr(" )", 2, &buf, &buflen));
558                 break;
559             }
560
561         case ns_t_nxt: {
562                 int n, c;
563
564                 /* Next domain name. */
565                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
566
567                 /* Type bit map. */
568                 n = edata - rdata;
569                 for (c = 0; c < n*8; c++)
570                         if (NS_NXT_BIT_ISSET(c, rdata)) {
571                                 len = SPRINTF((tmp, " %s", p_type(c)));
572                                 T(addstr(tmp, len, &buf, &buflen));
573                         }
574                 break;
575             }
576
577         case ns_t_cert: {
578                 u_int c_type, key_tag, alg;
579                 int n;
580                 unsigned int siz;
581                 char base64_cert[8192], tmp[40];
582                 const char *leader;
583
584                 c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
585                 key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
586                 alg = (u_int) *rdata++;
587
588                 len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
589                 T(addstr(tmp, len, &buf, &buflen));
590                 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
591                 if (siz > sizeof(base64_cert) * 3/4) {
592                         const char *str = "record too long to print";
593                         T(addstr(str, strlen(str), &buf, &buflen));
594                 }
595                 else {
596                         len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
597
598                         if (len < 0)
599                                 goto formerr;
600                         else if (len > 15) {
601                                 T(addstr(" (", 2, &buf, &buflen));
602                                 leader = "\n\t\t";
603                                 spaced = 0;
604                         }
605                         else
606                                 leader = " ";
607         
608                         for (n = 0; n < len; n += 48) {
609                                 T(addstr(leader, strlen(leader),
610                                          &buf, &buflen));
611                                 T(addstr(base64_cert + n, MIN(len - n, 48),
612                                          &buf, &buflen));
613                         }
614                         if (len > 15)
615                                 T(addstr(" )", 2, &buf, &buflen));
616                 }
617                 break;
618             }
619
620         case ns_t_tkey: {
621                 /* KJD - need to complete this */
622                 u_long t;
623                 int mode, err, keysize;
624
625                 /* Algorithm name. */
626                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
627                 T(addstr(" ", 1, &buf, &buflen));
628
629                 /* Inception. */
630                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
631                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
632                 T(addstr(tmp, len, &buf, &buflen));
633
634                 /* Experation. */
635                 t = ns_get32(rdata);  rdata += NS_INT32SZ;
636                 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
637                 T(addstr(tmp, len, &buf, &buflen));
638
639                 /* Mode , Error, Key Size. */
640                 /* Priority, Weight, Port. */
641                 mode = ns_get16(rdata);  rdata += NS_INT16SZ;
642                 err  = ns_get16(rdata);  rdata += NS_INT16SZ;
643                 keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
644                 len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
645                 T(addstr(tmp, len, &buf, &buflen));
646
647                 /* XXX need to dump key, print otherdata length & other data */
648                 break;
649             }
650
651         case ns_t_tsig: {
652                 /* BEW - need to complete this */
653                 int n;
654
655                 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
656                 T(addstr(" ", 1, &buf, &buflen));
657                 rdata += 8; /* time */
658                 n = ns_get16(rdata); rdata += INT16SZ;
659                 rdata += n; /* sig */
660                 n = ns_get16(rdata); rdata += INT16SZ; /* original id */
661                 sprintf(buf, "%d", ns_get16(rdata));
662                 rdata += INT16SZ;
663                 addlen(strlen(buf), &buf, &buflen);
664                 break;
665             }
666
667         case ns_t_a6: {
668                 struct in6_addr a;
669                 int pbyte, pbit;
670
671                 /* prefix length */
672                 if (rdlen == 0U) goto formerr;
673                 len = SPRINTF((tmp, "%d ", *rdata));
674                 T(addstr(tmp, len, &buf, &buflen));
675                 pbit = *rdata;
676                 if (pbit > 128) goto formerr;
677                 pbyte = (pbit & ~7) / 8;
678                 rdata++;
679
680                 /* address suffix: provided only when prefix len != 128 */
681                 if (pbit < 128) {
682                         if (rdata + pbyte >= edata) goto formerr;
683                         memset(&a, 0, sizeof(a));
684                         memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
685                         (void) inet_ntop(AF_INET6, &a, buf, buflen);
686                         addlen(strlen(buf), &buf, &buflen);
687                         rdata += sizeof(a) - pbyte;
688                 }
689
690                 /* prefix name: provided only when prefix len > 0 */
691                 if (pbit == 0)
692                         break;
693                 if (rdata >= edata) goto formerr;
694                 T(addstr(" ", 1, &buf, &buflen));
695                 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
696                 
697                 break;
698             }
699
700         case ns_t_opt: {
701                 len = SPRINTF((tmp, "%u bytes", class));
702                 T(addstr(tmp, len, &buf, &buflen));
703                 break;
704             }
705
706         default:
707                 comment = "unknown RR type";
708                 goto hexify;
709         }
710         return (buf - obuf);
711  formerr:
712         comment = "RR format error";
713  hexify: {
714         int n, m;
715         char *p;
716
717         len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
718                        rdlen != 0U ? " (" : "", comment));
719         T(addstr(tmp, len, &buf, &buflen));
720         while (rdata < edata) {
721                 p = tmp;
722                 p += SPRINTF((p, "\n\t"));
723                 spaced = 0;
724                 n = MIN(16, edata - rdata);
725                 for (m = 0; m < n; m++)
726                         p += SPRINTF((p, "%02x ", rdata[m]));
727                 T(addstr(tmp, p - tmp, &buf, &buflen));
728                 if (n < 16) {
729                         T(addstr(")", 1, &buf, &buflen));
730                         T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
731                 }
732                 p = tmp;
733                 p += SPRINTF((p, "; "));
734                 for (m = 0; m < n; m++)
735                         *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
736                                 ? rdata[m]
737                                 : '.';
738                 T(addstr(tmp, p - tmp, &buf, &buflen));
739                 rdata += n;
740         }
741         return (buf - obuf);
742     }
743 }
744
745 /* Private. */
746
747 /*
748  * size_t
749  * prune_origin(name, origin)
750  *      Find out if the name is at or under the current origin.
751  * return:
752  *      Number of characters in name before start of origin,
753  *      or length of name if origin does not match.
754  * notes:
755  *      This function should share code with samedomain().
756  */
757 static size_t
758 prune_origin(const char *name, const char *origin) {
759         const char *oname = name;
760
761         while (*name != '\0') {
762                 if (origin != NULL && ns_samename(name, origin) == 1)
763                         return (name - oname - (name > oname));
764                 while (*name != '\0') {
765                         if (*name == '\\') {
766                                 name++;
767                                 /* XXX need to handle \nnn form. */
768                                 if (*name == '\0')
769                                         break;
770                         } else if (*name == '.') {
771                                 name++;
772                                 break;
773                         }
774                         name++;
775                 }
776         }
777         return (name - oname);
778 }
779
780 /*
781  * int
782  * charstr(rdata, edata, buf, buflen)
783  *      Format a <character-string> into the presentation buffer.
784  * return:
785  *      Number of rdata octets consumed
786  *      0 for protocol format error
787  *      -1 for output buffer error
788  * side effects:
789  *      buffer is advanced on success.
790  */
791 static int
792 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
793         const u_char *odata = rdata;
794         size_t save_buflen = *buflen;
795         char *save_buf = *buf;
796
797         if (addstr("\"", 1, buf, buflen) < 0)
798                 goto enospc;
799         if (rdata < edata) {
800                 int n = *rdata;
801
802                 if (rdata + 1 + n <= edata) {
803                         rdata++;
804                         while (n-- > 0) {
805                                 if (strchr("\n\"\\", *rdata) != NULL)
806                                         if (addstr("\\", 1, buf, buflen) < 0)
807                                                 goto enospc;
808                                 if (addstr((const char *)rdata, 1,
809                                            buf, buflen) < 0)
810                                         goto enospc;
811                                 rdata++;
812                         }
813                 }
814         }
815         if (addstr("\"", 1, buf, buflen) < 0)
816                 goto enospc;
817         return (rdata - odata);
818  enospc:
819         errno = ENOSPC;
820         *buf = save_buf;
821         *buflen = save_buflen;
822         return (-1);
823 }
824
825 static int
826 addname(const u_char *msg, size_t msglen,
827         const u_char **pp, const char *origin,
828         char **buf, size_t *buflen)
829 {
830         size_t newlen, save_buflen = *buflen;
831         char *save_buf = *buf;
832         int n;
833
834         n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
835         if (n < 0)
836                 goto enospc;    /* Guess. */
837         newlen = prune_origin(*buf, origin);
838         if (**buf == '\0') {
839                 goto root;
840         } else if (newlen == 0U) {
841                 /* Use "@" instead of name. */
842                 if (newlen + 2 > *buflen)
843                         goto enospc;        /* No room for "@\0". */
844                 (*buf)[newlen++] = '@';
845                 (*buf)[newlen] = '\0';
846         } else {
847                 if (((origin == NULL || origin[0] == '\0') ||
848                     (origin[0] != '.' && origin[1] != '\0' &&
849                     (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
850                         /* No trailing dot. */
851  root:
852                         if (newlen + 2 > *buflen)
853                                 goto enospc;    /* No room for ".\0". */
854                         (*buf)[newlen++] = '.';
855                         (*buf)[newlen] = '\0';
856                 }
857         }
858         *pp += n;
859         addlen(newlen, buf, buflen);
860         **buf = '\0';
861         return (newlen);
862  enospc:
863         errno = ENOSPC;
864         *buf = save_buf;
865         *buflen = save_buflen;
866         return (-1);
867 }
868
869 static void
870 addlen(size_t len, char **buf, size_t *buflen) {
871         INSIST(len <= *buflen);
872         *buf += len;
873         *buflen -= len;
874 }
875
876 static int
877 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
878         if (len >= *buflen) {
879                 errno = ENOSPC;
880                 return (-1);
881         }
882         memcpy(*buf, src, len);
883         addlen(len, buf, buflen);
884         **buf = '\0';
885         return (0);
886 }
887
888 static int
889 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
890         size_t save_buflen = *buflen;
891         char *save_buf = *buf;
892         int t;
893
894         if (spaced || len >= target - 1) {
895                 T(addstr("  ", 2, buf, buflen));
896                 spaced = 1;
897         } else {
898                 for (t = (target - len - 1) / 8; t >= 0; t--)
899                         if (addstr("\t", 1, buf, buflen) < 0) {
900                                 *buflen = save_buflen;
901                                 *buf = save_buf;
902                                 return (-1);
903                         }
904                 spaced = 0;
905         }
906         return (spaced);
907 }