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