ns_print.c revision 1.2 1 /* $NetBSD: ns_print.c,v 1.2 2004/05/20 20:35:05 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.3.2.1.4.4 2004/03/17 01:13:36 marka Exp";
24 #else
25 __RCSID("$NetBSD: ns_print.c,v 1.2 2004/05/20 20:35:05 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 * int
81 * ns_sprintrr(handle, rr, name_ctx, origin, buf, buflen)
82 * Convert an RR to presentation format.
83 * return:
84 * Number of characters written to buf, or -1 (check errno).
85 */
86 int
87 ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
88 const char *name_ctx, const char *origin,
89 char *buf, size_t buflen)
90 {
91 int n;
92
93 n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
94 ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
95 ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
96 name_ctx, origin, buf, buflen);
97 return (n);
98 }
99
100 /*
101 * int
102 * ns_sprintrrf(msg, msglen, name, class, type, ttl, rdata, rdlen,
103 * name_ctx, origin, buf, buflen)
104 * Convert the fields of an RR into presentation format.
105 * return:
106 * Number of characters written to buf, or -1 (check errno).
107 */
108 int
109 ns_sprintrrf(const u_char *msg, size_t msglen,
110 const char *name, ns_class class, ns_type type,
111 u_long ttl, const u_char *rdata, size_t rdlen,
112 const char *name_ctx, const char *origin,
113 char *buf, size_t buflen)
114 {
115 const char *obuf = buf;
116 const u_char *edata = rdata + rdlen;
117 int spaced = 0;
118
119 const char *comment;
120 char tmp[100];
121 int len, x;
122
123 /*
124 * Owner.
125 */
126 if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
127 T(addstr("\t\t\t", (size_t)3, &buf, &buflen));
128 } else {
129 len = prune_origin(name, origin);
130 if (*name == '\0') {
131 goto root;
132 } else if (len == 0) {
133 T(addstr("@\t\t\t", (size_t)4, &buf, &buflen));
134 } else {
135 T(addstr(name, (size_t)len, &buf, &buflen));
136 /* Origin not used or not root, and no trailing dot? */
137 if (((origin == NULL || origin[0] == '\0') ||
138 (origin[0] != '.' && origin[1] != '\0' &&
139 name[len] == '\0')) && name[len - 1] != '.') {
140 root:
141 T(addstr(".", (size_t)1, &buf, &buflen));
142 len++;
143 }
144 T(spaced = addtab((size_t)len, 24, spaced, &buf, &buflen));
145 }
146 }
147
148 /*
149 * TTL, Class, Type.
150 */
151 T(x = ns_format_ttl(ttl, buf, buflen));
152 addlen((size_t)x, &buf, &buflen);
153 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
154 T(addstr(tmp, (size_t)len, &buf, &buflen));
155 if (rdlen == 0U)
156 return (buf - obuf);
157 T(spaced = addtab((size_t)(x + len), (size_t)16, spaced, &buf, &buflen));
158
159 /*
160 * RData.
161 */
162 switch (type) {
163 case ns_t_a:
164 if (rdlen != (size_t)NS_INADDRSZ)
165 goto formerr;
166 (void) inet_ntop(AF_INET, rdata, buf, buflen);
167 addlen(strlen(buf), &buf, &buflen);
168 break;
169
170 case ns_t_cname:
171 case ns_t_mb:
172 case ns_t_mg:
173 case ns_t_mr:
174 case ns_t_ns:
175 case ns_t_ptr:
176 case ns_t_dname:
177 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
178 break;
179
180 case ns_t_hinfo:
181 case ns_t_isdn:
182 /* First word. */
183 T(len = charstr(rdata, edata, &buf, &buflen));
184 if (len == 0)
185 goto formerr;
186 rdata += len;
187 T(addstr(" ", (size_t)1, &buf, &buflen));
188
189
190 /* Second word, optional in ISDN records. */
191 if (type == ns_t_isdn && rdata == edata)
192 break;
193
194 T(len = charstr(rdata, edata, &buf, &buflen));
195 if (len == 0)
196 goto formerr;
197 rdata += len;
198 break;
199
200 case ns_t_soa: {
201 u_long t;
202
203 /* Server name. */
204 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
205 T(addstr(" ", (size_t)1, &buf, &buflen));
206
207 /* Administrator name. */
208 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
209 T(addstr(" (\n", (size_t)3, &buf, &buflen));
210 spaced = 0;
211
212 if ((edata - rdata) != 5*NS_INT32SZ)
213 goto formerr;
214
215 /* Serial number. */
216 t = ns_get32(rdata); rdata += NS_INT32SZ;
217 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
218 len = SPRINTF((tmp, "%lu", t));
219 T(addstr(tmp, (size_t)len, &buf, &buflen));
220 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
221 T(addstr("; serial\n", (size_t)9, &buf, &buflen));
222 spaced = 0;
223
224 /* Refresh interval. */
225 t = ns_get32(rdata); rdata += NS_INT32SZ;
226 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
227 T(len = ns_format_ttl(t, buf, buflen));
228 addlen((size_t)len, &buf, &buflen);
229 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
230 T(addstr("; refresh\n", (size_t)10, &buf, &buflen));
231 spaced = 0;
232
233 /* Retry interval. */
234 t = ns_get32(rdata); rdata += NS_INT32SZ;
235 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
236 T(len = ns_format_ttl(t, buf, buflen));
237 addlen((size_t)len, &buf, &buflen);
238 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
239 T(addstr("; retry\n", (size_t)8, &buf, &buflen));
240 spaced = 0;
241
242 /* Expiry. */
243 t = ns_get32(rdata); rdata += NS_INT32SZ;
244 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
245 T(len = ns_format_ttl(t, buf, buflen));
246 addlen((size_t)len, &buf, &buflen);
247 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
248 T(addstr("; expiry\n", (size_t)9, &buf, &buflen));
249 spaced = 0;
250
251 /* Minimum TTL. */
252 t = ns_get32(rdata); rdata += NS_INT32SZ;
253 T(addstr("\t\t\t\t\t", (size_t)5, &buf, &buflen));
254 T(len = ns_format_ttl(t, buf, buflen));
255 addlen((size_t)len, &buf, &buflen);
256 T(addstr(" )", (size_t)2, &buf, &buflen));
257 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen));
258 T(addstr("; minimum\n", (size_t)10, &buf, &buflen));
259
260 break;
261 }
262
263 case ns_t_mx:
264 case ns_t_afsdb:
265 case ns_t_rt: {
266 u_int t;
267
268 if (rdlen < (size_t)NS_INT16SZ)
269 goto formerr;
270
271 /* Priority. */
272 t = ns_get16(rdata);
273 rdata += NS_INT16SZ;
274 len = SPRINTF((tmp, "%u ", t));
275 T(addstr(tmp, (size_t)len, &buf, &buflen));
276
277 /* Target. */
278 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
279
280 break;
281 }
282
283 case ns_t_px: {
284 u_int t;
285
286 if (rdlen < (size_t)NS_INT16SZ)
287 goto formerr;
288
289 /* Priority. */
290 t = ns_get16(rdata);
291 rdata += NS_INT16SZ;
292 len = SPRINTF((tmp, "%u ", t));
293 T(addstr(tmp, (size_t)len, &buf, &buflen));
294
295 /* Name1. */
296 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
297 T(addstr(" ", (size_t)1, &buf, &buflen));
298
299 /* Name2. */
300 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
301
302 break;
303 }
304
305 case ns_t_x25:
306 T(len = charstr(rdata, edata, &buf, &buflen));
307 if (len == 0)
308 goto formerr;
309 rdata += len;
310 break;
311
312 case ns_t_txt:
313 while (rdata < edata) {
314 T(len = charstr(rdata, edata, &buf, &buflen));
315 if (len == 0)
316 goto formerr;
317 rdata += len;
318 if (rdata < edata)
319 T(addstr(" ", (size_t)1, &buf, &buflen));
320 }
321 break;
322
323 case ns_t_nsap: {
324 char t[2+255*3];
325
326 (void) inet_nsap_ntoa((int)rdlen, rdata, t);
327 T(addstr(t, strlen(t), &buf, &buflen));
328 break;
329 }
330
331 case ns_t_aaaa:
332 if (rdlen != (size_t)NS_IN6ADDRSZ)
333 goto formerr;
334 (void) inet_ntop(AF_INET6, rdata, buf, buflen);
335 addlen(strlen(buf), &buf, &buflen);
336 break;
337
338 case ns_t_loc: {
339 char t[255];
340
341 /* XXX protocol format checking? */
342 (void) loc_ntoa(rdata, t);
343 T(addstr(t, strlen(t), &buf, &buflen));
344 break;
345 }
346
347 case ns_t_naptr: {
348 u_int order, preference;
349 char t[50];
350
351 if (rdlen < 2U*NS_INT16SZ)
352 goto formerr;
353
354 /* Order, Precedence. */
355 order = ns_get16(rdata); rdata += NS_INT16SZ;
356 preference = ns_get16(rdata); rdata += NS_INT16SZ;
357 len = SPRINTF((t, "%u %u ", order, preference));
358 T(addstr(t, (size_t)len, &buf, &buflen));
359
360 /* Flags. */
361 T(len = charstr(rdata, edata, &buf, &buflen));
362 if (len == 0)
363 goto formerr;
364 rdata += len;
365 T(addstr(" ", (size_t)1, &buf, &buflen));
366
367 /* Service. */
368 T(len = charstr(rdata, edata, &buf, &buflen));
369 if (len == 0)
370 goto formerr;
371 rdata += len;
372 T(addstr(" ", (size_t)1, &buf, &buflen));
373
374 /* Regexp. */
375 T(len = charstr(rdata, edata, &buf, &buflen));
376 if (len < 0)
377 return (-1);
378 if (len == 0)
379 goto formerr;
380 rdata += len;
381 T(addstr(" ", (size_t)1, &buf, &buflen));
382
383 /* Server. */
384 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
385 break;
386 }
387
388 case ns_t_srv: {
389 u_int priority, weight, port;
390 char t[50];
391
392 if (rdlen < 3U*NS_INT16SZ)
393 goto formerr;
394
395 /* Priority, Weight, Port. */
396 priority = ns_get16(rdata); rdata += NS_INT16SZ;
397 weight = ns_get16(rdata); rdata += NS_INT16SZ;
398 port = ns_get16(rdata); rdata += NS_INT16SZ;
399 len = SPRINTF((t, "%u %u %u ", priority, weight, port));
400 T(addstr(t, (size_t)len, &buf, &buflen));
401
402 /* Server. */
403 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
404 break;
405 }
406
407 case ns_t_minfo:
408 case ns_t_rp:
409 /* Name1. */
410 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
411 T(addstr(" ", (size_t)1, &buf, &buflen));
412
413 /* Name2. */
414 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
415
416 break;
417
418 case ns_t_wks: {
419 int n, lcnt;
420
421 if (rdlen < 1U + NS_INT32SZ)
422 goto formerr;
423
424 /* Address. */
425 (void) inet_ntop(AF_INET, rdata, buf, buflen);
426 addlen(strlen(buf), &buf, &buflen);
427 rdata += NS_INADDRSZ;
428
429 /* Protocol. */
430 len = SPRINTF((tmp, " %u ( ", *rdata));
431 T(addstr(tmp, (size_t)len, &buf, &buflen));
432 rdata += NS_INT8SZ;
433
434 /* Bit map. */
435 n = 0;
436 lcnt = 0;
437 while (rdata < edata) {
438 u_int c = *rdata++;
439 do {
440 if (c & 0200) {
441 if (lcnt == 0) {
442 T(addstr("\n\t\t\t\t", (size_t)5,
443 &buf, &buflen));
444 lcnt = 10;
445 spaced = 0;
446 }
447 len = SPRINTF((tmp, "%d ", n));
448 T(addstr(tmp, (size_t)len, &buf, &buflen));
449 lcnt--;
450 }
451 c <<= 1;
452 } while (++n & 07);
453 }
454 T(addstr(")", (size_t)1, &buf, &buflen));
455
456 break;
457 }
458
459 case ns_t_key: {
460 char base64_key[NS_MD5RSA_MAX_BASE64];
461 u_int keyflags, protocol, algorithm, key_id;
462 const char *leader;
463 int n;
464
465 if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
466 goto formerr;
467
468 /* Key flags, Protocol, Algorithm. */
469 key_id = dst_s_dns_key_id(rdata, edata-rdata);
470 keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
471 protocol = *rdata++;
472 algorithm = *rdata++;
473 len = SPRINTF((tmp, "0x%04x %u %u",
474 keyflags, protocol, algorithm));
475 T(addstr(tmp, (size_t)len, &buf, &buflen));
476
477 /* Public key data. */
478 len = b64_ntop(rdata, (size_t)(edata - rdata),
479 base64_key, sizeof base64_key);
480 if (len < 0)
481 goto formerr;
482 if (len > 15) {
483 T(addstr(" (", (size_t)2, &buf, &buflen));
484 leader = "\n\t\t";
485 spaced = 0;
486 } else
487 leader = " ";
488 for (n = 0; n < len; n += 48) {
489 T(addstr(leader, strlen(leader), &buf, &buflen));
490 T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
491 &buf, &buflen));
492 }
493 if (len > 15)
494 T(addstr(" )", (size_t)2, &buf, &buflen));
495 n = SPRINTF((tmp, " ; key_tag= %u", key_id));
496 T(addstr(tmp, (size_t)n, &buf, &buflen));
497
498 break;
499 }
500
501 case ns_t_sig: {
502 char base64_key[NS_MD5RSA_MAX_BASE64];
503 u_int typ, algorithm, labels, footprint;
504 const char *leader;
505 u_long t;
506 int n;
507
508 if (rdlen < 22U)
509 goto formerr;
510
511 /* Type covered, Algorithm, Label count, Original TTL. */
512 typ = ns_get16(rdata); rdata += NS_INT16SZ;
513 algorithm = *rdata++;
514 labels = *rdata++;
515 t = ns_get32(rdata); rdata += NS_INT32SZ;
516 len = SPRINTF((tmp, "%s %d %d %lu ",
517 p_type((int)typ), algorithm, labels, t));
518 T(addstr(tmp, (size_t)len, &buf, &buflen));
519 if (labels > (u_int)dn_count_labels(name))
520 goto formerr;
521
522 /* Signature expiry. */
523 t = ns_get32(rdata); rdata += NS_INT32SZ;
524 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
525 T(addstr(tmp, (size_t)len, &buf, &buflen));
526
527 /* Time signed. */
528 t = ns_get32(rdata); rdata += NS_INT32SZ;
529 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
530 T(addstr(tmp, (size_t)len, &buf, &buflen));
531
532 /* Signature Footprint. */
533 footprint = ns_get16(rdata); rdata += NS_INT16SZ;
534 len = SPRINTF((tmp, "%u ", footprint));
535 T(addstr(tmp, (size_t)len, &buf, &buflen));
536
537 /* Signer's name. */
538 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
539
540 /* Signature. */
541 len = b64_ntop(rdata, (size_t)(edata - rdata),
542 base64_key, sizeof base64_key);
543 if (len > 15) {
544 T(addstr(" (", (size_t)2, &buf, &buflen));
545 leader = "\n\t\t";
546 spaced = 0;
547 } else
548 leader = " ";
549 if (len < 0)
550 goto formerr;
551 for (n = 0; n < len; n += 48) {
552 T(addstr(leader, strlen(leader), &buf, &buflen));
553 T(addstr(base64_key + n, (size_t)MIN(len - n, 48),
554 &buf, &buflen));
555 }
556 if (len > 15)
557 T(addstr(" )", (size_t)2, &buf, &buflen));
558 break;
559 }
560
561 case ns_t_nxt: {
562 int n, c;
563
564 /* Next domain name. */
565 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
566
567 /* Type bit map. */
568 n = edata - rdata;
569 for (c = 0; c < n*8; c++)
570 if (NS_NXT_BIT_ISSET(c, rdata)) {
571 len = SPRINTF((tmp, " %s", p_type(c)));
572 T(addstr(tmp, (size_t)len, &buf, &buflen));
573 }
574 break;
575 }
576
577 case ns_t_cert: {
578 u_int c_type, key_tag, alg;
579 int n;
580 unsigned int siz;
581 char base64_cert[8192], tmp1[40];
582 const char *leader;
583
584 c_type = ns_get16(rdata); rdata += NS_INT16SZ;
585 key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
586 alg = (u_int) *rdata++;
587
588 len = SPRINTF((tmp1, "%d %d %d ", c_type, key_tag, alg));
589 T(addstr(tmp1, (size_t)len, &buf, &buflen));
590 siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
591 if (siz > sizeof(base64_cert) * 3/4) {
592 const char *str = "record too long to print";
593 T(addstr(str, strlen(str), &buf, &buflen));
594 }
595 else {
596 len = b64_ntop(rdata, (size_t)(edata-rdata),
597 base64_cert, siz);
598
599 if (len < 0)
600 goto formerr;
601 else if (len > 15) {
602 T(addstr(" (", (size_t)2, &buf, &buflen));
603 leader = "\n\t\t";
604 spaced = 0;
605 }
606 else
607 leader = " ";
608
609 for (n = 0; n < len; n += 48) {
610 T(addstr(leader, strlen(leader),
611 &buf, &buflen));
612 T(addstr(base64_cert + n, (size_t)MIN(len - n, 48),
613 &buf, &buflen));
614 }
615 if (len > 15)
616 T(addstr(" )", (size_t)2, &buf, &buflen));
617 }
618 break;
619 }
620
621 case ns_t_tkey: {
622 /* KJD - need to complete this */
623 u_long t;
624 int mode, err, keysize;
625
626 /* Algorithm name. */
627 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
628 T(addstr(" ", (size_t)1, &buf, &buflen));
629
630 /* Inception. */
631 t = ns_get32(rdata); rdata += NS_INT32SZ;
632 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
633 T(addstr(tmp, (size_t)len, &buf, &buflen));
634
635 /* Experation. */
636 t = ns_get32(rdata); rdata += NS_INT32SZ;
637 len = SPRINTF((tmp, "%s ", p_secstodate(t)));
638 T(addstr(tmp, (size_t)len, &buf, &buflen));
639
640 /* Mode , Error, Key Size. */
641 /* Priority, Weight, Port. */
642 mode = ns_get16(rdata); rdata += NS_INT16SZ;
643 err = ns_get16(rdata); rdata += NS_INT16SZ;
644 keysize = ns_get16(rdata); rdata += NS_INT16SZ;
645 len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
646 T(addstr(tmp, (size_t)len, &buf, &buflen));
647
648 /* XXX need to dump key, print otherdata length & other data */
649 break;
650 }
651
652 case ns_t_tsig: {
653 /* BEW - need to complete this */
654 int n;
655
656 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
657 T(addstr(" ", (size_t)1, &buf, &buflen));
658 rdata += 8; /* time */
659 n = ns_get16(rdata); rdata += INT16SZ;
660 rdata += n; /* sig */
661 n = ns_get16(rdata); rdata += INT16SZ; /* original id */
662 sprintf(buf, "%d", ns_get16(rdata));
663 rdata += INT16SZ;
664 addlen(strlen(buf), &buf, &buflen);
665 break;
666 }
667
668 case ns_t_a6: {
669 struct in6_addr a;
670 int pbyte, pbit;
671
672 /* prefix length */
673 if (rdlen == 0U) goto formerr;
674 len = SPRINTF((tmp, "%d ", *rdata));
675 T(addstr(tmp, (size_t)len, &buf, &buflen));
676 pbit = *rdata;
677 if (pbit > 128) goto formerr;
678 pbyte = (pbit & ~7) / 8;
679 rdata++;
680
681 /* address suffix: provided only when prefix len != 128 */
682 if (pbit < 128) {
683 if (rdata + pbyte >= edata) goto formerr;
684 memset(&a, 0, sizeof(a));
685 memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
686 (void) inet_ntop(AF_INET6, &a, buf, buflen);
687 addlen(strlen(buf), &buf, &buflen);
688 rdata += sizeof(a) - pbyte;
689 }
690
691 /* prefix name: provided only when prefix len > 0 */
692 if (pbit == 0)
693 break;
694 if (rdata >= edata) goto formerr;
695 T(addstr(" ", (size_t)1, &buf, &buflen));
696 T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
697
698 break;
699 }
700
701 case ns_t_opt: {
702 len = SPRINTF((tmp, "%u bytes", class));
703 T(addstr(tmp, (size_t)len, &buf, &buflen));
704 break;
705 }
706
707 default:
708 comment = "unknown RR type";
709 goto hexify;
710 }
711 return (buf - obuf);
712 formerr:
713 comment = "RR format error";
714 hexify: {
715 int n, m;
716 char *p;
717
718 len = SPRINTF((tmp, "\\# %u (\t; %s", edata - rdata, 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