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