1 /* $NetBSD: ns_print.c,v 1.8 2008/06/21 20:41:48 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (c) 1996-1999 by Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/cdefs.h> 21 #ifndef lint 22 #ifdef notdef 23 static const char rcsid[] = "Id: ns_print.c,v 1.10 2005/04/27 04:56:40 sra Exp"; 24 #else 25 __RCSID("$NetBSD: ns_print.c,v 1.8 2008/06/21 20:41:48 christos Exp $"); 26 #endif 27 #endif 28 29 /* Import. */ 30 31 #include "port_before.h" 32 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 36 #include <netinet/in.h> 37 #include <arpa/nameser.h> 38 #include <arpa/inet.h> 39 40 #include <isc/assertions.h> 41 #include <isc/dst.h> 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 (/*CONSTCOND*/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", (size_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", (size_t)4, &buf, &buflen)); 131 } else { 132 T(addstr(name, (size_t)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(".", (size_t)1, &buf, &buflen)); 139 len++; 140 } 141 T(spaced = addtab((size_t)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((size_t)x, &buf, &buflen); 150 len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type))); 151 T(addstr(tmp, (size_t)len, &buf, &buflen)); 152 T(spaced = addtab((size_t)(x + len), (size_t)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(" ", (size_t)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(" ", (size_t)1, &buf, &buflen)); 201 202 /* Administrator name. */ 203 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 204 T(addstr(" (\n", (size_t)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", (size_t)5, &buf, &buflen)); 213 len = SPRINTF((tmp, "%lu", t)); 214 T(addstr(tmp, (size_t)len, &buf, &buflen)); 215 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); 216 T(addstr("; serial\n", (size_t)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", (size_t)5, &buf, &buflen)); 222 T(len = ns_format_ttl(t, buf, buflen)); 223 addlen((size_t)len, &buf, &buflen); 224 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); 225 T(addstr("; refresh\n", (size_t)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", (size_t)5, &buf, &buflen)); 231 T(len = ns_format_ttl(t, buf, buflen)); 232 addlen((size_t)len, &buf, &buflen); 233 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); 234 T(addstr("; retry\n", (size_t)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", (size_t)5, &buf, &buflen)); 240 T(len = ns_format_ttl(t, buf, buflen)); 241 addlen((size_t)len, &buf, &buflen); 242 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); 243 T(addstr("; expiry\n", (size_t)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", (size_t)5, &buf, &buflen)); 249 T(len = ns_format_ttl(t, buf, buflen)); 250 addlen((size_t)len, &buf, &buflen); 251 T(addstr(" )", (size_t)2, &buf, &buflen)); 252 T(spaced = addtab((size_t)len, (size_t)16, spaced, &buf, &buflen)); 253 T(addstr("; minimum\n", (size_t)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, (size_t)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, (size_t)len, &buf, &buflen)); 289 290 /* Name1. */ 291 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 292 T(addstr(" ", (size_t)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(" ", (size_t)1, &buf, &buflen)); 315 } 316 break; 317 318 case ns_t_nsap: { 319 char t[2+255*3]; 320 321 (void) inet_nsap_ntoa((int)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, (size_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(" ", (size_t)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(" ", (size_t)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(" ", (size_t)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, (size_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(" ", (size_t)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, (size_t)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", (size_t)5, 438 &buf, &buflen)); 439 lcnt = 10; 440 spaced = 0; 441 } 442 len = SPRINTF((tmp, "%d ", n)); 443 T(addstr(tmp, (size_t)len, &buf, &buflen)); 444 lcnt--; 445 } 446 c <<= 1; 447 } while (++n & 07); 448 } 449 T(addstr(")", (size_t)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, (size_t)len, &buf, &buflen)); 475 476 /* Public key data. */ 477 len = b64_ntop(rdata, (size_t)(edata - rdata), 478 base64_key, sizeof base64_key); 479 if (len < 0) 480 goto formerr; 481 if (len > 15) { 482 T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48), 490 &buf, &buflen)); 491 } 492 if (len > 15) 493 T(addstr(" )", (size_t)2, &buf, &buflen)); 494 n = SPRINTF((tmp, " ; key_tag= %u", key_id)); 495 T(addstr(tmp, (size_t)n, &buf, &buflen)); 496 497 break; 498 } 499 500 case ns_t_sig: { 501 char base64_key[NS_MD5RSA_MAX_BASE64]; 502 u_int typ, 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 typ = 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((int)typ), algorithm, labels, t)); 517 T(addstr(tmp, (size_t)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, (size_t)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, (size_t)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, (size_t)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, (size_t)(edata - rdata), 541 base64_key, sizeof base64_key); 542 if (len > 15) { 543 T(addstr(" (", (size_t)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, (size_t)MIN(len - n, 48), 553 &buf, &buflen)); 554 } 555 if (len > 15) 556 T(addstr(" )", (size_t)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, (size_t)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], tmp1[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((tmp1, "%d %d %d ", c_type, key_tag, alg)); 588 T(addstr(tmp1, (size_t)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, (size_t)(edata-rdata), 596 base64_cert, siz); 597 598 if (len < 0) 599 goto formerr; 600 else if (len > 15) { 601 T(addstr(" (", (size_t)2, &buf, &buflen)); 602 leader = "\n\t\t"; 603 spaced = 0; 604 } 605 else 606 leader = " "; 607 608 for (n = 0; n < len; n += 48) { 609 T(addstr(leader, strlen(leader), 610 &buf, &buflen)); 611 T(addstr(base64_cert + n, (size_t)MIN(len - n, 48), 612 &buf, &buflen)); 613 } 614 if (len > 15) 615 T(addstr(" )", (size_t)2, &buf, &buflen)); 616 } 617 break; 618 } 619 620 case ns_t_tkey: { 621 /* KJD - need to complete this */ 622 u_long t; 623 int mode, err, keysize; 624 625 /* Algorithm name. */ 626 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 627 T(addstr(" ", (size_t)1, &buf, &buflen)); 628 629 /* Inception. */ 630 t = ns_get32(rdata); rdata += NS_INT32SZ; 631 len = SPRINTF((tmp, "%s ", p_secstodate(t))); 632 T(addstr(tmp, (size_t)len, &buf, &buflen)); 633 634 /* Experation. */ 635 t = ns_get32(rdata); rdata += NS_INT32SZ; 636 len = SPRINTF((tmp, "%s ", p_secstodate(t))); 637 T(addstr(tmp, (size_t)len, &buf, &buflen)); 638 639 /* Mode , Error, Key Size. */ 640 /* Priority, Weight, Port. */ 641 mode = ns_get16(rdata); rdata += NS_INT16SZ; 642 err = ns_get16(rdata); rdata += NS_INT16SZ; 643 keysize = ns_get16(rdata); rdata += NS_INT16SZ; 644 len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize)); 645 T(addstr(tmp, (size_t)len, &buf, &buflen)); 646 647 /* XXX need to dump key, print otherdata length & other data */ 648 break; 649 } 650 651 case ns_t_tsig: { 652 /* BEW - need to complete this */ 653 int n; 654 655 T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen)); 656 T(addstr(" ", (size_t)1, &buf, &buflen)); 657 rdata += 8; /*%< time */ 658 n = ns_get16(rdata); rdata += INT16SZ; 659 rdata += n; /*%< sig */ 660 n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */ 661 sprintf(buf, "%d", ns_get16(rdata)); 662 rdata += INT16SZ; 663 addlen(strlen(buf), &buf, &buflen); 664 break; 665 } 666 667 case ns_t_a6: { 668 struct in6_addr a; 669 int pbyte, pbit; 670 671 /* prefix length */ 672 if (rdlen == 0U) goto formerr; 673 len = SPRINTF((tmp, "%d ", *rdata)); 674 T(addstr(tmp, (size_t)len, &buf, &buflen)); 675 pbit = *rdata; 676 if (pbit > 128) goto formerr; 677 pbyte = (pbit & ~7) / 8; 678 rdata++; 679 680 /* address suffix: provided only when prefix len != 128 */ 681 if (pbit < 128) { 682 if (rdata + pbyte >= edata) goto formerr; 683 memset(&a, 0, sizeof(a)); 684 memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte); 685 (void) inet_ntop(AF_INET6, &a, buf, buflen); 686 addlen(strlen(buf), &buf, &buflen); 687 rdata += sizeof(a) - pbyte; 688 } 689 690 /* prefix name: provided only when prefix len > 0 */ 691 if (pbit == 0) 692 break; 693 if (rdata >= edata) goto formerr; 694 T(addstr(" ", (size_t)1, &buf, &buflen)); 695 T(addname(msg, msglen, &rdata, origin, &buf, &buflen)); 696 697 break; 698 } 699 700 case ns_t_opt: { 701 len = SPRINTF((tmp, "%u bytes", class)); 702 T(addstr(tmp, (size_t)len, &buf, &buflen)); 703 break; 704 } 705 706 default: 707 comment = "unknown RR type"; 708 goto hexify; 709 } 710 return (buf - obuf); 711 formerr: 712 comment = "RR format error"; 713 hexify: { 714 int n, m; 715 char *p; 716 717 len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata), 718 rdlen != 0U ? " (" : "", comment)); 719 T(addstr(tmp, (size_t)len, &buf, &buflen)); 720 while (rdata < edata) { 721 p = tmp; 722 p += SPRINTF((p, "\n\t")); 723 spaced = 0; 724 n = MIN(16, edata - rdata); 725 for (m = 0; m < n; m++) 726 p += SPRINTF((p, "%02x ", rdata[m])); 727 T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); 728 if (n < 16) { 729 T(addstr(")", (size_t)1, &buf, &buflen)); 730 T(addtab((size_t)(p - tmp + 1), (size_t)48, spaced, &buf, &buflen)); 731 } 732 p = tmp; 733 p += SPRINTF((p, "; ")); 734 for (m = 0; m < n; m++) 735 *p++ = (isascii(rdata[m]) && isprint(rdata[m])) 736 ? rdata[m] 737 : '.'; 738 T(addstr(tmp, (size_t)(p - tmp), &buf, &buflen)); 739 rdata += n; 740 } 741 return (buf - obuf); 742 } 743 } 744 745 /* Private. */ 746 747 /*% 748 * size_t 749 * prune_origin(name, origin) 750 * Find out if the name is at or under the current origin. 751 * return: 752 * Number of characters in name before start of origin, 753 * or length of name if origin does not match. 754 * notes: 755 * This function should share code with samedomain(). 756 */ 757 static size_t 758 prune_origin(const char *name, const char *origin) { 759 const char *oname = name; 760 761 while (*name != '\0') { 762 if (origin != NULL && ns_samename(name, origin) == 1) 763 return (name - oname - (name > oname)); 764 while (*name != '\0') { 765 if (*name == '\\') { 766 name++; 767 /* XXX need to handle \nnn form. */ 768 if (*name == '\0') 769 break; 770 } else if (*name == '.') { 771 name++; 772 break; 773 } 774 name++; 775 } 776 } 777 return (name - oname); 778 } 779 780 /*% 781 * int 782 * charstr(rdata, edata, buf, buflen) 783 * Format a <character-string> into the presentation buffer. 784 * return: 785 * Number of rdata octets consumed 786 * 0 for protocol format error 787 * -1 for output buffer error 788 * side effects: 789 * buffer is advanced on success. 790 */ 791 static int 792 charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) { 793 const u_char *odata = rdata; 794 size_t save_buflen = *buflen; 795 char *save_buf = *buf; 796 797 if (addstr("\"", (size_t)1, buf, buflen) < 0) 798 goto enospc; 799 if (rdata < edata) { 800 int n = *rdata; 801 802 if (rdata + 1 + n <= edata) { 803 rdata++; 804 while (n-- > 0) { 805 if (strchr("\n\"\\", *rdata) != NULL) 806 if (addstr("\\", (size_t)1, buf, buflen) < 0) 807 goto enospc; 808 if (addstr((const char *)rdata, (size_t)1, 809 buf, buflen) < 0) 810 goto enospc; 811 rdata++; 812 } 813 } 814 } 815 if (addstr("\"", (size_t)1, buf, buflen) < 0) 816 goto enospc; 817 return (rdata - odata); 818 enospc: 819 errno = ENOSPC; 820 *buf = save_buf; 821 *buflen = save_buflen; 822 return (-1); 823 } 824 825 static int 826 addname(const u_char *msg, size_t msglen, 827 const u_char **pp, const char *origin, 828 char **buf, size_t *buflen) 829 { 830 size_t newlen, save_buflen = *buflen; 831 char *save_buf = *buf; 832 int n; 833 834 n = dn_expand(msg, msg + msglen, *pp, *buf, (int)*buflen); 835 if (n < 0) 836 goto enospc; /*%< Guess. */ 837 newlen = prune_origin(*buf, origin); 838 if (**buf == '\0') { 839 goto root; 840 } else if (newlen == 0U) { 841 /* Use "@" instead of name. */ 842 if (newlen + 2 > *buflen) 843 goto enospc; /* No room for "@\0". */ 844 (*buf)[newlen++] = '@'; 845 (*buf)[newlen] = '\0'; 846 } else { 847 if (((origin == NULL || origin[0] == '\0') || 848 (origin[0] != '.' && origin[1] != '\0' && 849 (*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') { 850 /* No trailing dot. */ 851 root: 852 if (newlen + 2 > *buflen) 853 goto enospc; /* No room for ".\0". */ 854 (*buf)[newlen++] = '.'; 855 (*buf)[newlen] = '\0'; 856 } 857 } 858 *pp += n; 859 addlen(newlen, buf, buflen); 860 **buf = '\0'; 861 return (newlen); 862 enospc: 863 errno = ENOSPC; 864 *buf = save_buf; 865 *buflen = save_buflen; 866 return (-1); 867 } 868 869 static void 870 addlen(size_t len, char **buf, size_t *buflen) { 871 INSIST(len <= *buflen); 872 *buf += len; 873 *buflen -= len; 874 } 875 876 static int 877 addstr(const char *src, size_t len, char **buf, size_t *buflen) { 878 if (len >= *buflen) { 879 errno = ENOSPC; 880 return (-1); 881 } 882 memcpy(*buf, src, len); 883 addlen(len, buf, buflen); 884 **buf = '\0'; 885 return (0); 886 } 887 888 static int 889 addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) { 890 size_t save_buflen = *buflen; 891 char *save_buf = *buf; 892 int t; 893 894 if (spaced || len >= target - 1) { 895 T(addstr(" ", (size_t)2, buf, buflen)); 896 spaced = 1; 897 } else { 898 for (t = (target - len - 1) / 8; t >= 0; t--) 899 if (addstr("\t", (size_t)1, buf, buflen) < 0) { 900 *buflen = save_buflen; 901 *buf = save_buf; 902 return (-1); 903 } 904 spaced = 0; 905 } 906 return (spaced); 907 } 908 909 /*! \file */ 910