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