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