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