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