Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* $NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $ */
3 /*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996-1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
20 /*
21 * This version of this file is derived from Android 2.3 "Gingerbread",
22 * which contains uncredited changes by Android/Google developers. It has
23 * been modified in 2011 for use in the Android build of Mozilla Firefox by
24 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
25 * and Steve Workman <sjhworkman@gmail.com>).
26 * These changes are offered under the same license as the original NetBSD
27 * file, whose copyright and license are unchanged above.
28 */
30 #define ANDROID_CHANGES 1
31 #define MOZILLA_NECKO_EXCLUDE_CODE 1
33 #include <sys/cdefs.h>
34 #ifndef lint
35 #ifdef notdef
36 static const char rcsid[] = "Id: ns_print.c,v 1.3.2.1.4.5 2004/07/28 20:16:45 marka Exp";
37 #else
38 __RCSID("$NetBSD: ns_print.c,v 1.5 2004/11/07 02:19:49 christos Exp $");
39 #endif
40 #endif
42 /* Import. */
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include "arpa_nameser.h"
49 #include <arpa/inet.h>
51 #include "assertions.h"
52 #include "dst.h"
53 #include <errno.h>
54 #ifdef ANDROID_CHANGES
55 #include "resolv_private.h"
56 #else
57 #include <resolv.h>
58 #endif
59 #include <string.h>
60 #include <ctype.h>
61 #include <assert.h>
63 #ifdef SPRINTF_CHAR
64 # define SPRINTF(x) strlen(sprintf/**/x)
65 #else
66 # define SPRINTF(x) ((size_t)sprintf x)
67 #endif
69 #ifndef MIN
70 #define MIN(x,y) ((x)<(y)?(x):(y))
71 #endif
73 /* Forward. */
75 static size_t prune_origin(const char *name, const char *origin);
76 static int charstr(const u_char *rdata, const u_char *edata,
77 char **buf, size_t *buflen);
78 static int addname(const u_char *msg, size_t msglen,
79 const u_char **p, const char *origin,
80 char **buf, size_t *buflen);
81 static void addlen(size_t len, char **buf, size_t *buflen);
82 static int addstr(const char *src, size_t len,
83 char **buf, size_t *buflen);
84 static int addtab(size_t len, size_t target, int spaced,
85 char **buf, size_t *buflen);
87 /* Macros. */
89 #define T(x) \
90 do { \
91 if ((x) < 0) \
92 return (-1); \
93 } while (/*CONSTCOND*/0)
95 /* Public. */
97 /*
98 * int
99 * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
100 * Convert an RR to presentation format.
101 * return:
102 * Number of characters written to buf, or -1 (check errno).
103 */
104 int
105 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
106 const char *name_ctx, const char *origin,
107 char *buf, size_t buflen)
108 {
109 int n;
111 n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
112 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
113 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
114 name_ctx, origin, buf, buflen);
115 return (n);
116 }
118 /*
119 * int
120 * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
121 * name_ctx, origin, buf, buflen)
122 * Convert the fields of an RR into presentation format.
123 * return:
124 * Number of characters written to buf, or -1 (check errno).
125 */
126 int
127 ns_sprintrrf(const u_char *msg, size_t msglen,
128 const char *name, ns_class class, ns_type type,
129 u_long ttl, const u_char *rdata, size_t rdlen,
130 const char *name_ctx, const char *origin,
131 char *buf, size_t buflen)
132 {
133 const char *obuf = buf;
134 const u_char *edata = rdata + rdlen;
135 int spaced = 0;
137 const char *comment;
138 char tmp[100];
139 int len, x;
141 /*
142 * Owner.
143 */
144 if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
145 T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
146 } else {
147 len = prune_origin(name, origin);
148 if (*name == '\0') {
149 goto root;
150 } else if (len == 0) {
151 T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
152 } else {
153 T(addstr(name, (size_t)len, &buf, &buflen));
154 /* Origin not used or not root, and no trailing dot? */
155 if (((origin == NULL || origin[0] == '\0') ||
156 (origin[0] != '.' && origin[1] != '\0' &&
157 name[len] == '\0')) && name[len - 1] != '.') {
158 root:
159 T(addstr(".", (size_t)1, &buf, &buflen));
160 len++;
161 }
162 T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
163 }
164 }
166 /*
167 * TTL, Class, Type.
168 */
169 T(x = ns_format_ttl(ttl, buf, buflen));
170 addlen((size_t)x, &buf, &buflen);
171 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
172 T(addstr(tmp, (size_t)len, &buf, &buflen));
173 T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
175 /*
176 * RData.
177 */
178 switch (type) {
179 case ns_t_a:
180 if (rdlen != (size_t)NS_INADDRSZ)
181 goto formerr;
182 (void) inet_ntop(AF_INET, rdata, buf, buflen);
183 addlen(strlen(buf), &buf, &buflen);
184 break;
186 case ns_t_cname:
187 case ns_t_mb:
188 case ns_t_mg:
189 case ns_t_mr:
190 case ns_t_ns:
191 case ns_t_ptr:
192 case ns_t_dname:
193 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
194 break;
196 case ns_t_hinfo:
197 case ns_t_isdn:
198 /* First word. */
199 T(len = charstr(rdata, edata, &buf, &buflen));
200 if (len == 0)
201 goto formerr;
202 rdata += len;
203 T(addstr(" ", (size_t)1, &buf, &buflen));
206 /* Second word, optional in ISDN records. */
207 if (type == ns_t_isdn && rdata == edata)
208 break;
210 T(len = charstr(rdata, edata, &buf, &buflen));
211 if (len == 0)
212 goto formerr;
213 rdata += len;
214 break;
216 case ns_t_soa: {
217 u_long t;
219 /* Server name. */
220 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
221 T(addstr(" ", (size_t)1, &buf, &buflen));
223 /* Administrator name. */
224 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
225 T(addstr(" (\n", (size_t)3, &buf, &buflen));
226 spaced = 0;
228 if ((edata - rdata) != 5*NS_INT32SZ)
229 goto formerr;
231 /* Serial number. */
232 t = ns_get32(rdata); rdata += NS_INT32SZ;
233 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
234 len = SPRINTF((tmp, "%lu", t));
235 T(addstr(tmp, (size_t)len, &buf, &buflen));
236 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
237 T(addstr("; serial\n", (size_t)9, &buf, &buflen));
238 spaced = 0;
240 /* Refresh interval. */
241 t = ns_get32(rdata); rdata += NS_INT32SZ;
242 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
243 T(len = ns_format_ttl(t, buf, buflen));
244 addlen((size_t)len, &buf, &buflen);
245 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
246 T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
247 spaced = 0;
249 /* Retry interval. */
250 t = ns_get32(rdata); rdata += NS_INT32SZ;
251 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
252 T(len = ns_format_ttl(t, buf, buflen));
253 addlen((size_t)len, &buf, &buflen);
254 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
255 T(addstr("; retry\n", (size_t)8, &buf, &buflen));
256 spaced = 0;
258 /* Expiry. */
259 t = ns_get32(rdata); rdata += NS_INT32SZ;
260 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
261 T(len = ns_format_ttl(t, buf, buflen));
262 addlen((size_t)len, &buf, &buflen);
263 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
264 T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
265 spaced = 0;
267 /* Minimum TTL. */
268 t = ns_get32(rdata); rdata += NS_INT32SZ;
269 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
270 T(len = ns_format_ttl(t, buf, buflen));
271 addlen((size_t)len, &buf, &buflen);
272 T(addstr(" )", (size_t)2, &buf, &buflen));
273 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
274 T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
276 break;
277 }
279 case ns_t_mx:
280 case ns_t_afsdb:
281 case ns_t_rt: {
282 u_int t;
284 if (rdlen < (size_t)NS_INT16SZ)
285 goto formerr;
287 /* Priority. */
288 t = ns_get16(rdata);
289 rdata += NS_INT16SZ;
290 len = SPRINTF((tmp, "%u ", t));
291 T(addstr(tmp, (size_t)len, &buf, &buflen));
293 /* Target. */
294 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
296 break;
297 }
299 case ns_t_px: {
300 u_int t;
302 if (rdlen < (size_t)NS_INT16SZ)
303 goto formerr;
305 /* Priority. */
306 t = ns_get16(rdata);
307 rdata += NS_INT16SZ;
308 len = SPRINTF((tmp, "%u ", t));
309 T(addstr(tmp, (size_t)len, &buf, &buflen));
311 /* Name1. */
312 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
313 T(addstr(" ", (size_t)1, &buf, &buflen));
315 /* Name2. */
316 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
318 break;
319 }
321 case ns_t_x25:
322 T(len = charstr(rdata, edata, &buf, &buflen));
323 if (len == 0)
324 goto formerr;
325 rdata += len;
326 break;
328 case ns_t_txt:
329 while (rdata < edata) {
330 T(len = charstr(rdata, edata, &buf, &buflen));
331 if (len == 0)
332 goto formerr;
333 rdata += len;
334 if (rdata < edata)
335 T(addstr(" ", (size_t)1, &buf, &buflen));
336 }
337 break;
339 case ns_t_nsap: {
340 char t[2+255*3];
342 (void) inet_nsap_ntoa((int)rdlen, rdata, t);
343 T(addstr(t, strlen(t), &buf, &buflen));
344 break;
345 }
347 case ns_t_aaaa:
348 if (rdlen != (size_t)NS_IN6ADDRSZ)
349 goto formerr;
350 (void) inet_ntop(AF_INET6, rdata, buf, buflen);
351 addlen(strlen(buf), &buf, &buflen);
352 break;
354 case ns_t_loc: {
355 char t[255];
357 /* XXX protocol format checking? */
358 (void) loc_ntoa(rdata, t);
359 T(addstr(t, strlen(t), &buf, &buflen));
360 break;
361 }
363 case ns_t_naptr: {
364 u_int order, preference;
365 char t[50];
367 if (rdlen < 2U*NS_INT16SZ)
368 goto formerr;
370 /* Order, Precedence. */
371 order = ns_get16(rdata); rdata += NS_INT16SZ;
372 preference = ns_get16(rdata); rdata += NS_INT16SZ;
373 len = SPRINTF((t, "%u %u ", order, preference));
374 T(addstr(t, (size_t)len, &buf, &buflen));
376 /* Flags. */
377 T(len = charstr(rdata, edata, &buf, &buflen));
378 if (len == 0)
379 goto formerr;
380 rdata += len;
381 T(addstr(" ", (size_t)1, &buf, &buflen));
383 /* Service. */
384 T(len = charstr(rdata, edata, &buf, &buflen));
385 if (len == 0)
386 goto formerr;
387 rdata += len;
388 T(addstr(" ", (size_t)1, &buf, &buflen));
390 /* Regexp. */
391 T(len = charstr(rdata, edata, &buf, &buflen));
392 if (len < 0)
393 return (-1);
394 if (len == 0)
395 goto formerr;
396 rdata += len;
397 T(addstr(" ", (size_t)1, &buf, &buflen));
399 /* Server. */
400 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
401 break;
402 }
404 case ns_t_srv: {
405 u_int priority, weight, port;
406 char t[50];
408 if (rdlen < 3U*NS_INT16SZ)
409 goto formerr;
411 /* Priority, Weight, Port. */
412 priority = ns_get16(rdata); rdata += NS_INT16SZ;
413 weight = ns_get16(rdata); rdata += NS_INT16SZ;
414 port = ns_get16(rdata); rdata += NS_INT16SZ;
415 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
416 T(addstr(t, (size_t)len, &buf, &buflen));
418 /* Server. */
419 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
420 break;
421 }
423 case ns_t_minfo:
424 case ns_t_rp:
425 /* Name1. */
426 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
427 T(addstr(" ", (size_t)1, &buf, &buflen));
429 /* Name2. */
430 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
432 break;
434 case ns_t_wks: {
435 int n, lcnt;
437 if (rdlen < 1U + NS_INT32SZ)
438 goto formerr;
440 /* Address. */
441 (void) inet_ntop(AF_INET, rdata, buf, buflen);
442 addlen(strlen(buf), &buf, &buflen);
443 rdata += NS_INADDRSZ;
445 /* Protocol. */
446 len = SPRINTF((tmp, " %u ( ", *rdata));
447 T(addstr(tmp, (size_t)len, &buf, &buflen));
448 rdata += NS_INT8SZ;
450 /* Bit map. */
451 n = 0;
452 lcnt = 0;
453 while (rdata < edata) {
454 u_int c = *rdata++;
455 do {
456 if (c & 0200) {
457 if (lcnt == 0) {
458 T(addstr("\n\t\t\t\t", (size_t)5,
459 &buf, &buflen));
460 lcnt = 10;
461 spaced = 0;
462 }
463 len = SPRINTF((tmp, "%d ", n));
464 T(addstr(tmp, (size_t)len, &buf, &buflen));
465 lcnt--;
466 }
467 c <<= 1;
468 } while (++n & 07);
469 }
470 T(addstr(")", (size_t)1, &buf, &buflen));
472 break;
473 }
475 case ns_t_key: {
476 char base64_key[NS_MD5RSA_MAX_BASE64];
477 u_int keyflags, protocol, algorithm, key_id;
478 const char *leader;
479 int n;
481 if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
482 goto formerr;
484 /* Key flags, Protocol, Algorithm. */
485 #if !defined(MOZILLA_NECKO_EXCLUDE_CODE) && !defined(_LIBC)
486 key_id = dst_s_dns_key_id(rdata, edata-rdata);
487 #else
488 key_id = 0;
489 #endif
490 keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
491 protocol = *rdata++;
492 algorithm = *rdata++;
493 len = SPRINTF((tmp, "0x%04x %u %u",
494 keyflags, protocol, algorithm));
495 T(addstr(tmp, (size_t)len, &buf, &buflen));
497 /* Public key data. */
498 len = b64_ntop(rdata, (size_t)(edata - rdata),
499 base64_key, sizeof base64_key);
500 if (len < 0)
501 goto formerr;
502 if (len > 15) {
503 T(addstr(" (", (size_t)2, &buf, &buflen));
504 leader = "\n\t\t";
505 spaced = 0;
506 } else
507 leader = " ";
508 for (n = 0; n < len; n += 48) {
509 T(addstr(leader, strlen(leader), &buf, &buflen));
510 T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
511 &buf, &buflen));
512 }
513 if (len > 15)
514 T(addstr(" )", (size_t)2, &buf, &buflen));
515 n = SPRINTF((tmp, " ; key_tag= %u", key_id));
516 T(addstr(tmp, (size_t)n, &buf, &buflen));
518 break;
519 }
521 case ns_t_sig: {
522 char base64_key[NS_MD5RSA_MAX_BASE64];
523 u_int typ, algorithm, labels, footprint;
524 const char *leader;
525 u_long t;
526 int n;
528 if (rdlen < 22U)
529 goto formerr;
531 /* Type covered, Algorithm, Label count, Original TTL. */
532 typ = ns_get16(rdata); rdata += NS_INT16SZ;
533 algorithm = *rdata++;
534 labels = *rdata++;
535 t = ns_get32(rdata); rdata += NS_INT32SZ;
536 len = SPRINTF((tmp, "%s %d %d %lu ",
537 p_type((int)typ), algorithm, labels, t));
538 T(addstr(tmp, (size_t)len, &buf, &buflen));
539 if (labels > (u_int)dn_count_labels(name))
540 goto formerr;
542 /* Signature expiry. */
543 t = ns_get32(rdata); rdata += NS_INT32SZ;
544 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
545 T(addstr(tmp, (size_t)len, &buf, &buflen));
547 /* Time signed. */
548 t = ns_get32(rdata); rdata += NS_INT32SZ;
549 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
550 T(addstr(tmp, (size_t)len, &buf, &buflen));
552 /* Signature Footprint. */
553 footprint = ns_get16(rdata); rdata += NS_INT16SZ;
554 len = SPRINTF((tmp, "%u ", footprint));
555 T(addstr(tmp, (size_t)len, &buf, &buflen));
557 /* Signer's name. */
558 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
560 /* Signature. */
561 len = b64_ntop(rdata, (size_t)(edata - rdata),
562 base64_key, sizeof base64_key);
563 if (len > 15) {
564 T(addstr(" (", (size_t)2, &buf, &buflen));
565 leader = "\n\t\t";
566 spaced = 0;
567 } else
568 leader = " ";
569 if (len < 0)
570 goto formerr;
571 for (n = 0; n < len; n += 48) {
572 T(addstr(leader, strlen(leader), &buf, &buflen));
573 T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
574 &buf, &buflen));
575 }
576 if (len > 15)
577 T(addstr(" )", (size_t)2, &buf, &buflen));
578 break;
579 }
581 case ns_t_nxt: {
582 int n, c;
584 /* Next domain name. */
585 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
587 /* Type bit map. */
588 n = edata - rdata;
589 for (c = 0; c < n*8; c++)
590 if (NS_NXT_BIT_ISSET(c, rdata)) {
591 len = SPRINTF((tmp, " %s", p_type(c)));
592 T(addstr(tmp, (size_t)len, &buf, &buflen));
593 }
594 break;
595 }
597 case ns_t_cert: {
598 u_int c_type, key_tag, alg;
599 int n;
600 unsigned int siz;
601 char base64_cert[8192], tmp1[40];
602 const char *leader;
604 c_type = ns_get16(rdata); rdata += NS_INT16SZ;
605 key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
606 alg = (u_int) *rdata++;
608 len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
609 T(addstr(tmp1, (size_t)len, &buf, &buflen));
610 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
611 if (siz > sizeof(base64_cert) * 3/4) {
612 const char *str = "record too long to print";
613 T(addstr(str, strlen(str), &buf, &buflen));
614 }
615 else {
616 len = b64_ntop(rdata, (size_t)(edata-rdata),
617 base64_cert, siz);
619 if (len < 0)
620 goto formerr;
621 else if (len > 15) {
622 T(addstr(" (", (size_t)2, &buf, &buflen));
623 leader = "\n\t\t";
624 spaced = 0;
625 }
626 else
627 leader = " ";
629 for (n = 0; n < len; n += 48) {
630 T(addstr(leader, strlen(leader),
631 &buf, &buflen));
632 T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
633 &buf, &buflen));
634 }
635 if (len > 15)
636 T(addstr(" )", (size_t)2, &buf, &buflen));
637 }
638 break;
639 }
641 case ns_t_tkey: {
642 /* KJD - need to complete this */
643 u_long t;
644 int mode, err, keysize;
646 /* Algorithm name. */
647 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
648 T(addstr(" ", (size_t)1, &buf, &buflen));
650 /* Inception. */
651 t = ns_get32(rdata); rdata += NS_INT32SZ;
652 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
653 T(addstr(tmp, (size_t)len, &buf, &buflen));
655 /* Experation. */
656 t = ns_get32(rdata); rdata += NS_INT32SZ;
657 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
658 T(addstr(tmp, (size_t)len, &buf, &buflen));
660 /* Mode , Error, Key Size. */
661 /* Priority, Weight, Port. */
662 mode = ns_get16(rdata); rdata += NS_INT16SZ;
663 err = ns_get16(rdata); rdata += NS_INT16SZ;
664 keysize = ns_get16(rdata); rdata += NS_INT16SZ;
665 len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
666 T(addstr(tmp, (size_t)len, &buf, &buflen));
668 /* XXX need to dump key, print otherdata length & other data */
669 break;
670 }
672 case ns_t_tsig: {
673 /* BEW - need to complete this */
674 int n;
676 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
677 T(addstr(" ", (size_t)1, &buf, &buflen));
678 rdata += 8; /* time */
679 n = ns_get16(rdata); rdata += INT16SZ;
680 rdata += n; /* sig */
681 n = ns_get16(rdata); rdata += INT16SZ; /* original id */
682 sprintf(buf, "%d", ns_get16(rdata));
683 rdata += INT16SZ;
684 addlen(strlen(buf), &buf, &buflen);
685 break;
686 }
688 case ns_t_a6: {
689 struct in6_addr a;
690 int pbyte, pbit;
692 /* prefix length */
693 if (rdlen == 0U) goto formerr;
694 len = SPRINTF((tmp, "%d ", *rdata));
695 T(addstr(tmp, (size_t)len, &buf, &buflen));
696 pbit = *rdata;
697 if (pbit > 128) goto formerr;
698 pbyte = (pbit & ~7) / 8;
699 rdata++;
701 /* address suffix: provided only when prefix len != 128 */
702 if (pbit < 128) {
703 if (rdata + pbyte >= edata) goto formerr;
704 memset(&a, 0, sizeof(a));
705 memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
706 (void) inet_ntop(AF_INET6, &a, buf, buflen);
707 addlen(strlen(buf), &buf, &buflen);
708 rdata += sizeof(a) - pbyte;
709 }
711 /* prefix name: provided only when prefix len > 0 */
712 if (pbit == 0)
713 break;
714 if (rdata >= edata) goto formerr;
715 T(addstr(" ", (size_t)1, &buf, &buflen));
716 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
718 break;
719 }
721 case ns_t_opt: {
722 len = SPRINTF((tmp, "%u bytes", class));
723 T(addstr(tmp, (size_t)len, &buf, &buflen));
724 break;
725 }
727 default:
728 comment = "unknown RR type";
729 goto hexify;
730 }
731 return (buf - obuf);
732 formerr:
733 comment = "RR format error";
734 hexify: {
735 int n, m;
736 char *p;
738 len = SPRINTF((tmp, "\\# %tu%s\t; %s", edata - rdata,
739 rdlen != 0 ? " (" : "", comment));
740 T(addstr(tmp, (size_t)len, &buf, &buflen));
741 while (rdata < edata) {
742 p = tmp;
743 p += SPRINTF((p, "\n\t"));
744 spaced = 0;
745 n = MIN(16, edata - rdata);
746 for (m = 0; m < n; m++)
747 p += SPRINTF((p, "%02x ", rdata[m]));
748 T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
749 if (n < 16) {
750 T(addstr(")", (size_t)1, &buf, &buflen));
751 T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen));
752 }
753 p = tmp;
754 p += SPRINTF((p, "; "));
755 for (m = 0; m < n; m++)
756 *p++ = (isascii(rdata[m]) && isprint(rdata[m]))
757 ? rdata[m]
758 : '.';
759 T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen));
760 rdata += n;
761 }
762 return (buf - obuf);
763 }
764 }
766 /* Private. */
768 /*
769 * size_t
770 * prune_origin(name, origin)
771 * Find out if the name is at or under the current origin.
772 * return:
773 * Number of characters in name before start of origin,
774 * or length of name if origin does not match.
775 * notes:
776 * This function should share code with samedomain().
777 */
778 static size_t
779 prune_origin(const char *name, const char *origin) {
780 const char *oname = name;
782 while (*name != '\0') {
783 if (origin != NULL && ns_samename(name, origin) == 1)
784 return (name - oname - (name > oname));
785 while (*name != '\0') {
786 if (*name == '\\') {
787 name++;
788 /* XXX need to handle \nnn form. */
789 if (*name == '\0')
790 break;
791 } else if (*name == '.') {
792 name++;
793 break;
794 }
795 name++;
796 }
797 }
798 return (name - oname);
799 }
801 /*
802 * int
803 * charstr(rdata, edata, buf, buflen)
804 * Format a <character-string> into the presentation buffer.
805 * return:
806 * Number of rdata octets consumed
807 * 0 for protocol format error
808 * -1 for output buffer error
809 * side effects:
810 * buffer is advanced on success.
811 */
812 static int
813 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
814 const u_char *odata = rdata;
815 size_t save_buflen = *buflen;
816 char *save_buf = *buf;
818 if (addstr("\"", (size_t)1, buf, buflen) < 0)
819 goto enospc;
820 if (rdata < edata) {
821 int n = *rdata;
823 if (rdata + 1 + n <= edata) {
824 rdata++;
825 while (n-- > 0) {
826 if (strchr("\n\"\\", *rdata) != NULL)
827 if (addstr("\\", (size_t)1, buf, buflen) < 0)
828 goto enospc;
829 if (addstr((const char *)rdata, (size_t)1,
830 buf, buflen) < 0)
831 goto enospc;
832 rdata++;
833 }
834 }
835 }
836 if (addstr("\"", (size_t)1, buf, buflen) < 0)
837 goto enospc;
838 return (rdata - odata);
839 enospc:
840 errno = ENOSPC;
841 *buf = save_buf;
842 *buflen = save_buflen;
843 return (-1);
844 }
846 static int
847 addname(const u_char *msg, size_t msglen,
848 const u_char **pp, const char *origin,
849 char **buf, size_t *buflen)
850 {
851 size_t newlen, save_buflen = *buflen;
852 char *save_buf = *buf;
853 int n;
855 n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen);
856 if (n < 0)
857 goto enospc; /* Guess. */
858 newlen = prune_origin(*buf, origin);
859 if (**buf == '\0') {
860 goto root;
861 } else if (newlen == 0U) {
862 /* Use "@" instead of name. */
863 if (newlen + 2 > *buflen)
864 goto enospc; /* No room for "@\0". */
865 (*buf)[newlen++] = '@';
866 (*buf)[newlen] = '\0';
867 } else {
868 if (((origin == NULL || origin[0] == '\0') ||
869 (origin[0] != '.' && origin[1] != '\0' &&
870 (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
871 /* No trailing dot. */
872 root:
873 if (newlen + 2 > *buflen)
874 goto enospc; /* No room for ".\0". */
875 (*buf)[newlen++] = '.';
876 (*buf)[newlen] = '\0';
877 }
878 }
879 *pp += n;
880 addlen(newlen, buf, buflen);
881 **buf = '\0';
882 return (newlen);
883 enospc:
884 errno = ENOSPC;
885 *buf = save_buf;
886 *buflen = save_buflen;
887 return (-1);
888 }
890 static void
891 addlen(size_t len, char **buf, size_t *buflen) {
892 assert(len <= *buflen);
893 *buf += len;
894 *buflen -= len;
895 }
897 static int
898 addstr(const char *src, size_t len, char **buf, size_t *buflen) {
899 if (len >= *buflen) {
900 errno = ENOSPC;
901 return (-1);
902 }
903 memcpy(*buf, src, len);
904 addlen(len, buf, buflen);
905 **buf = '\0';
906 return (0);
907 }
909 static int
910 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
911 size_t save_buflen = *buflen;
912 char *save_buf = *buf;
913 int t;
915 if (spaced || len >= target - 1) {
916 T(addstr(" ", (size_t)2, buf, buflen));
917 spaced = 1;
918 } else {
919 for (t = (target - len - 1) / 8; t >= 0; t--)
920 if (addstr("\t", (size_t)1, buf, buflen) < 0) {
921 *buflen = save_buflen;
922 *buf = save_buf;
923 return (-1);
924 }
925 spaced = 0;
926 }
927 return (spaced);
928 }