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