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