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