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