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