1 /* $OpenBSD: print-domain.c,v 1.17 2009/10/27 23:59:55 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #include <sys/param.h> 25 #include <sys/time.h> 26 #include <sys/socket.h> 27 28 #include <net/if.h> 29 30 #include <netinet/in.h> 31 #include <netinet/if_ether.h> 32 #include <netinet/in_systm.h> 33 #include <netinet/ip.h> 34 #include <netinet/ip_var.h> 35 #include <netinet/udp.h> 36 #include <netinet/udp_var.h> 37 #include <netinet/tcp.h> 38 39 #ifdef NOERROR 40 #undef NOERROR /* Solaris sucks */ 41 #endif 42 #ifdef NOERROR 43 #undef T_UNSPEC /* SINIX does too */ 44 #endif 45 #include "nameser.h" 46 47 #include <stdio.h> 48 #include <string.h> 49 50 #include "interface.h" 51 #include "addrtoname.h" 52 #include "extract.h" /* must come after interface.h */ 53 54 static const char *ns_ops[] = { 55 "", " inv_q", " stat", " op3", " notify", " update", " op6", " op7", 56 " op8", " updataA", " updateD", " updateDA", 57 " updateM", " updateMA", " zoneInit", " zoneRef", 58 }; 59 60 static const char *ns_resp[] = { 61 "", " FormErr", " ServFail", " NXDomain", 62 " NotImp", " Refused", " YXDomain", " YXRRSet", 63 " NXRRSet", " NotAuth", " NotZone", " Resp11", 64 " Resp12", " Resp13", " Resp14", " NoChange", 65 }; 66 67 /* skip over a domain name */ 68 static const u_char * 69 ns_nskip(register const u_char *cp) 70 { 71 register u_char i; 72 73 if (!TTEST2(*cp, 1)) 74 return (NULL); 75 i = *cp++; 76 while (i) { 77 if ((i & INDIR_MASK) == INDIR_MASK) 78 return (cp + 1); 79 if ((i & INDIR_MASK) == EDNS0_MASK) { 80 int bitlen, bytelen; 81 82 if ((i & ~INDIR_MASK) != EDNS0_ELT_BITLABEL) 83 return(NULL); /* unknown ELT */ 84 if (!TTEST2(*cp, 1)) 85 return (NULL); 86 if ((bitlen = *cp++) == 0) 87 bitlen = 256; 88 bytelen = (bitlen + 7) / 8; 89 cp += bytelen; 90 } else 91 cp += i; 92 if (!TTEST2(*cp, 1)) 93 return (NULL); 94 i = *cp++; 95 } 96 return (cp); 97 } 98 99 /* print a <domain-name> */ 100 static const u_char * 101 blabel_print(const u_char *cp) 102 { 103 int bitlen, slen, b; 104 int truncated = 0; 105 const u_char *bitp, *lim; 106 char tc; 107 108 if (!TTEST2(*cp, 1)) 109 return(NULL); 110 if ((bitlen = *cp) == 0) 111 bitlen = 256; 112 slen = (bitlen + 3) / 4; 113 if ((lim = cp + 1 + slen) > snapend) { 114 truncated = 1; 115 lim = snapend; 116 } 117 118 /* print the bit string as a hex string */ 119 printf("\\[x"); 120 for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) 121 printf("%02x", *bitp); 122 if (bitp == lim) 123 printf("..."); 124 else if (b > 4) { 125 tc = *bitp++; 126 printf("%02x", tc & (0xff << (8 - b))); 127 } else if (b > 0) { 128 tc = *bitp++; 129 printf("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); 130 } 131 printf("/%d]", bitlen); 132 133 return(truncated ? NULL : lim); 134 } 135 136 static int 137 labellen(const u_char *cp) 138 { 139 register u_int i; 140 141 if (!TTEST2(*cp, 1)) 142 return(-1); 143 i = *cp; 144 if ((i & INDIR_MASK) == EDNS0_MASK) { 145 int bitlen, elt; 146 147 if ((elt = (i & ~INDIR_MASK)) != EDNS0_ELT_BITLABEL) 148 return(-1); 149 if (!TTEST2(*(cp + 1), 1)) 150 return(-1); 151 if ((bitlen = *(cp + 1)) == 0) 152 bitlen = 256; 153 return(((bitlen + 7) / 8) + 1); 154 } else 155 return(i); 156 } 157 158 static const u_char * 159 ns_nprint(register const u_char *cp, register const u_char *bp) 160 { 161 register u_int i, l; 162 register const u_char *rp = NULL; 163 register int compress = 0; 164 int chars_processed; 165 int elt; 166 int data_size = snapend - bp; 167 168 if ((l = labellen(cp)) == (u_int)-1) 169 return(NULL); 170 if (!TTEST2(*cp, 1)) 171 return(NULL); 172 chars_processed = 1; 173 if (((i = *cp++) & INDIR_MASK) != INDIR_MASK) { 174 compress = 0; 175 rp = cp + l; 176 } 177 178 if (i != 0) 179 while (i && cp < snapend) { 180 if ((i & INDIR_MASK) == INDIR_MASK) { 181 if (!compress) { 182 rp = cp + 1; 183 compress = 1; 184 } 185 if (!TTEST2(*cp, 1)) 186 return(NULL); 187 cp = bp + (((i << 8) | *cp) & 0x3fff); 188 if ((l = labellen(cp)) == (u_int)-1) 189 return(NULL); 190 if (!TTEST2(*cp, 1)) 191 return(NULL); 192 i = *cp++; 193 chars_processed++; 194 195 /* 196 * If we've looked at every character in 197 * the message, this pointer will make 198 * us look at some character again, 199 * which means we're looping. 200 */ 201 if (chars_processed >= data_size) { 202 printf("<LOOP>"); 203 return (NULL); 204 } 205 continue; 206 } 207 if ((i & INDIR_MASK) == EDNS0_MASK) { 208 elt = (i & ~INDIR_MASK); 209 switch(elt) { 210 case EDNS0_ELT_BITLABEL: 211 if (blabel_print(cp) == NULL) 212 return (NULL); 213 break; 214 default: 215 /* unknown ELT */ 216 printf("<ELT %d>", elt); 217 return(NULL); 218 } 219 } else { 220 if (fn_printn(cp, l, snapend)) 221 return(NULL); 222 } 223 224 cp += l; 225 chars_processed += l; 226 putchar('.'); 227 if ((l = labellen(cp)) == (u_int)-1) 228 return(NULL); 229 if (!TTEST2(*cp, 1)) 230 return(NULL); 231 i = *cp++; 232 chars_processed++; 233 if (!compress) 234 rp += l + 1; 235 } 236 else 237 putchar('.'); 238 return (rp); 239 } 240 241 /* print a <character-string> */ 242 static const u_char * 243 ns_cprint(register const u_char *cp) 244 { 245 register u_int i; 246 247 if (!TTEST2(*cp, 1)) 248 return (NULL); 249 i = *cp++; 250 if (fn_printn(cp, i, snapend)) 251 return (NULL); 252 return (cp + i); 253 } 254 255 /* http://www.iana.org/assignments/dns-parameters */ 256 struct tok ns_type2str[] = { 257 { T_A, "A" }, /* RFC 1035 */ 258 { T_NS, "NS" }, /* RFC 1035 */ 259 { T_MD, "MD" }, /* RFC 1035 */ 260 { T_MF, "MF" }, /* RFC 1035 */ 261 { T_CNAME, "CNAME" }, /* RFC 1035 */ 262 { T_SOA, "SOA" }, /* RFC 1035 */ 263 { T_MB, "MB" }, /* RFC 1035 */ 264 { T_MG, "MG" }, /* RFC 1035 */ 265 { T_MR, "MR" }, /* RFC 1035 */ 266 { T_NULL, "NULL" }, /* RFC 1035 */ 267 { T_WKS, "WKS" }, /* RFC 1035 */ 268 { T_PTR, "PTR" }, /* RFC 1035 */ 269 { T_HINFO, "HINFO" }, /* RFC 1035 */ 270 { T_MINFO, "MINFO" }, /* RFC 1035 */ 271 { T_MX, "MX" }, /* RFC 1035 */ 272 { T_TXT, "TXT" }, /* RFC 1035 */ 273 { T_RP, "RP" }, /* RFC 1183 */ 274 { T_AFSDB, "AFSDB" }, /* RFC 1183 */ 275 { T_X25, "X25" }, /* RFC 1183 */ 276 { T_ISDN, "ISDN" }, /* RFC 1183 */ 277 { T_RT, "RT" }, /* RFC 1183 */ 278 { T_NSAP, "NSAP" }, /* RFC 1706 */ 279 { T_NSAP_PTR, "NSAP_PTR" }, 280 { T_SIG, "SIG" }, /* RFC 2535 */ 281 { T_KEY, "KEY" }, /* RFC 2535 */ 282 { T_PX, "PX" }, /* RFC 2163 */ 283 { T_GPOS, "GPOS" }, /* RFC 1712 */ 284 { T_AAAA, "AAAA" }, /* RFC 1886 */ 285 { T_LOC, "LOC" }, /* RFC 1876 */ 286 { T_NXT, "NXT" }, /* RFC 2535 */ 287 { T_EID, "EID" }, /* Nimrod */ 288 { T_NIMLOC, "NIMLOC" }, /* Nimrod */ 289 { T_SRV, "SRV" }, /* RFC 2782 */ 290 { T_ATMA, "ATMA" }, /* ATM Forum */ 291 { T_NAPTR, "NAPTR" }, /* RFC 2168, RFC 2915 */ 292 { T_KX, "KX" }, 293 { T_A6, "A6" }, /* RFC 2874 */ 294 { T_DNAME, "DNAME" }, /* RFC 2672 */ 295 { T_SINK, "SINK" }, 296 { T_OPT, "OPT" }, /* RFC 2671 */ 297 { T_APL, "APL" }, 298 { T_DS, "DS" }, 299 { T_SSHFP, "SSHFP" }, 300 { T_RRSIG, "RRSIG" }, 301 { T_NSEC, "NSEC" }, 302 { T_DNSKEY, "DNSKEY" }, 303 { T_UINFO, "UINFO" }, 304 { T_UID, "UID" }, 305 { T_GID, "GID" }, 306 { T_UNSPEC, "UNSPEC" }, 307 { T_UNSPECA, "UNSPECA" }, 308 { T_TKEY, "TKEY" }, /* RFC 2930 */ 309 { T_TSIG, "TSIG" }, /* RFC 2845 */ 310 { T_IXFR, "IXFR" }, /* RFC 1995 */ 311 { T_AXFR, "AXFR" }, /* RFC 1035 */ 312 { T_MAILB, "MAILB" }, /* RFC 1035 */ 313 { T_MAILA, "MAILA" }, /* RFC 1035 */ 314 { T_ANY, "ANY" }, 315 { 0, NULL } 316 }; 317 318 struct tok ns_class2str[] = { 319 { C_IN, "IN" }, /* Not used */ 320 { C_CHAOS, "CHAOS" }, 321 { C_HS, "HS" }, 322 { C_ANY, "ANY" }, 323 { 0, NULL } 324 }; 325 326 /* print a query */ 327 static const u_char * 328 ns_qprint(register const u_char *cp, register const u_char *bp, int is_mdns) 329 { 330 register const u_char *np = cp; 331 register u_int i; 332 333 cp = ns_nskip(cp); 334 335 if (cp == NULL || !TTEST2(*cp, 4)) 336 return(NULL); 337 338 /* print the qtype and qclass (if it's not IN) */ 339 i = EXTRACT_16BITS(cp); 340 cp += 2; 341 printf(" %s", tok2str(ns_type2str, "Type%d", i)); 342 i = EXTRACT_16BITS(cp); 343 cp += 2; 344 if (is_mdns && i == (C_IN|C_CACHE_FLUSH)) 345 printf(" (Cache flush)"); 346 else if (i != C_IN) 347 printf(" %s", tok2str(ns_class2str, "(Class %d)", i)); 348 349 fputs("? ", stdout); 350 cp = ns_nprint(np, bp); 351 return(cp ? cp + 4 : NULL); 352 } 353 354 /* print a reply */ 355 static const u_char * 356 ns_rprint(register const u_char *cp, register const u_char *bp, int is_mdns) 357 { 358 register u_int class; 359 register u_short typ, len; 360 register const u_char *rp; 361 362 if (vflag) { 363 putchar(' '); 364 if ((cp = ns_nprint(cp, bp)) == NULL) 365 return NULL; 366 } else 367 cp = ns_nskip(cp); 368 369 if (cp == NULL || !TTEST2(*cp, 10)) 370 return (snapend); 371 372 /* print the type/qtype and class (if it's not IN) */ 373 typ = EXTRACT_16BITS(cp); 374 cp += 2; 375 class = EXTRACT_16BITS(cp); 376 cp += 2; 377 if (is_mdns && class == (C_IN|C_CACHE_FLUSH)) 378 printf(" (Cache flush)"); 379 else if (class != C_IN && typ != T_OPT) 380 printf(" %s", tok2str(ns_class2str, "(Class %d)", class)); 381 382 /* ignore ttl */ 383 cp += 4; 384 385 len = EXTRACT_16BITS(cp); 386 cp += 2; 387 388 rp = cp + len; 389 390 printf(" %s", tok2str(ns_type2str, "Type%d", typ)); 391 if (rp > snapend) 392 return(NULL); 393 394 switch (typ) { 395 case T_A: 396 if (!TTEST2(*cp, sizeof(struct in_addr))) 397 return(NULL); 398 printf(" %s", ipaddr_string(cp)); 399 break; 400 401 case T_NS: 402 case T_CNAME: 403 case T_PTR: 404 #ifdef T_DNAME 405 case T_DNAME: 406 #endif 407 putchar(' '); 408 if (ns_nprint(cp, bp) == NULL) 409 return(NULL); 410 break; 411 412 case T_SOA: 413 if (!vflag) 414 break; 415 putchar(' '); 416 if ((cp = ns_nprint(cp, bp)) == NULL) 417 return(NULL); 418 putchar(' '); 419 if ((cp = ns_nprint(cp, bp)) == NULL) 420 return(NULL); 421 if (!TTEST2(*cp, 5 * 4)) 422 return(NULL); 423 printf(" %u", EXTRACT_32BITS(cp)); 424 cp += 4; 425 printf(" %u", EXTRACT_32BITS(cp)); 426 cp += 4; 427 printf(" %u", EXTRACT_32BITS(cp)); 428 cp += 4; 429 printf(" %u", EXTRACT_32BITS(cp)); 430 cp += 4; 431 printf(" %u", EXTRACT_32BITS(cp)); 432 cp += 4; 433 break; 434 case T_MX: 435 putchar(' '); 436 if (!TTEST2(*cp, 2)) 437 return(NULL); 438 if (ns_nprint(cp + 2, bp) == NULL) 439 return(NULL); 440 printf(" %d", EXTRACT_16BITS(cp)); 441 break; 442 443 case T_TXT: 444 while (cp < rp) { 445 printf(" \""); 446 cp = ns_cprint(cp); 447 if (cp == NULL) 448 return(NULL); 449 putchar('"'); 450 } 451 break; 452 453 case T_SRV: 454 putchar(' '); 455 if (!TTEST2(*cp, 6)) 456 return(NULL); 457 if (ns_nprint(cp + 6, bp) == NULL) 458 return(NULL); 459 printf(":%d %d %d", EXTRACT_16BITS(cp + 4), 460 EXTRACT_16BITS(cp), EXTRACT_16BITS(cp + 2)); 461 break; 462 463 #ifdef INET6 464 case T_AAAA: 465 if (!TTEST2(*cp, sizeof(struct in6_addr))) 466 return(NULL); 467 printf(" %s", ip6addr_string(cp)); 468 break; 469 470 case T_A6: 471 { 472 struct in6_addr a; 473 int pbit, pbyte; 474 475 if (!TTEST2(*cp, 1)) 476 return(NULL); 477 pbit = *cp; 478 pbyte = (pbit & ~7) / 8; 479 if (pbit > 128) { 480 printf(" %u(bad plen)", pbit); 481 break; 482 } else if (pbit < 128) { 483 if (!TTEST2(*(cp + 1), sizeof(a) - pbyte)) 484 return(NULL); 485 memset(&a, 0, sizeof(a)); 486 memcpy(&a.s6_addr[pbyte], cp + 1, sizeof(a) - pbyte); 487 printf(" %u %s", pbit, ip6addr_string(&a)); 488 } 489 if (pbit > 0) { 490 putchar(' '); 491 if (ns_nprint(cp + 1 + sizeof(a) - pbyte, bp) == NULL) 492 return(NULL); 493 } 494 break; 495 } 496 #endif /*INET6*/ 497 498 case T_OPT: 499 printf(" UDPsize=%u", class); 500 break; 501 502 case T_UNSPECA: /* One long string */ 503 if (!TTEST2(*cp, len)) 504 return(NULL); 505 if (fn_printn(cp, len, snapend)) 506 return(NULL); 507 break; 508 509 case T_TSIG: 510 { 511 if (cp + len > snapend) 512 return(NULL); 513 if (!vflag) 514 break; 515 putchar(' '); 516 if ((cp = ns_nprint(cp, bp)) == NULL) 517 return(NULL); 518 cp += 6; 519 if (!TTEST2(*cp, 2)) 520 return(NULL); 521 printf(" fudge=%u", EXTRACT_16BITS(cp)); 522 cp += 2; 523 if (!TTEST2(*cp, 2)) 524 return(NULL); 525 printf(" maclen=%u", EXTRACT_16BITS(cp)); 526 cp += 2 + EXTRACT_16BITS(cp); 527 if (!TTEST2(*cp, 2)) 528 return(NULL); 529 printf(" origid=%u", EXTRACT_16BITS(cp)); 530 cp += 2; 531 if (!TTEST2(*cp, 2)) 532 return(NULL); 533 printf(" error=%u", EXTRACT_16BITS(cp)); 534 cp += 2; 535 if (!TTEST2(*cp, 2)) 536 return(NULL); 537 printf(" otherlen=%u", EXTRACT_16BITS(cp)); 538 cp += 2; 539 } 540 } 541 return (rp); /* XXX This isn't always right */ 542 } 543 544 void 545 ns_print(register const u_char *bp, u_int length, int is_mdns) 546 { 547 register const HEADER *np; 548 register int qdcount, ancount, nscount, arcount; 549 register const u_char *cp; 550 u_int16_t b2; 551 552 np = (const HEADER *)bp; 553 TCHECK(*np); 554 /* get the byte-order right */ 555 qdcount = EXTRACT_16BITS(&np->qdcount); 556 ancount = EXTRACT_16BITS(&np->ancount); 557 nscount = EXTRACT_16BITS(&np->nscount); 558 arcount = EXTRACT_16BITS(&np->arcount); 559 560 if (DNS_QR(np)) { 561 /* this is a response */ 562 printf(" %d%s%s%s%s%s%s", 563 EXTRACT_16BITS(&np->id), 564 ns_ops[DNS_OPCODE(np)], 565 ns_resp[DNS_RCODE(np)], 566 DNS_AA(np)? "*" : "", 567 DNS_RA(np)? "" : "-", 568 DNS_TC(np)? "|" : "", 569 DNS_AD(np)? "$" : ""); 570 571 if (qdcount != 1) 572 printf(" [%dq]", qdcount); 573 /* Print QUESTION section on -vv */ 574 cp = (const u_char *)(np + 1); 575 while (qdcount--) { 576 if (qdcount < EXTRACT_16BITS(&np->qdcount) - 1) 577 putchar(','); 578 if (vflag > 1) { 579 fputs(" q:", stdout); 580 if ((cp = ns_qprint(cp, bp, is_mdns)) == NULL) 581 goto trunc; 582 } else { 583 if ((cp = ns_nskip(cp)) == NULL) 584 goto trunc; 585 cp += 4; /* skip QTYPE and QCLASS */ 586 } 587 } 588 printf(" %d/%d/%d", ancount, nscount, arcount); 589 if (ancount--) { 590 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 591 goto trunc; 592 while (cp < snapend && ancount--) { 593 putchar(','); 594 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 595 goto trunc; 596 } 597 } 598 if (ancount > 0) 599 goto trunc; 600 /* Print NS and AR sections on -vv */ 601 if (vflag > 1) { 602 if (cp < snapend && nscount--) { 603 fputs(" ns:", stdout); 604 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 605 goto trunc; 606 while (cp < snapend && nscount--) { 607 putchar(','); 608 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 609 goto trunc; 610 } 611 } 612 if (nscount > 0) 613 goto trunc; 614 if (cp < snapend && arcount--) { 615 fputs(" ar:", stdout); 616 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 617 goto trunc; 618 while (cp < snapend && arcount--) { 619 putchar(','); 620 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 621 goto trunc; 622 } 623 } 624 if (arcount > 0) 625 goto trunc; 626 } 627 } 628 else { 629 /* this is a request */ 630 printf(" %d%s%s%s", EXTRACT_16BITS(&np->id), ns_ops[DNS_OPCODE(np)], 631 DNS_RD(np) ? "+" : "", 632 DNS_CD(np) ? "%" : ""); 633 634 /* any weirdness? */ 635 b2 = EXTRACT_16BITS(((u_short *)np)+1); 636 if (b2 & 0x6cf) 637 printf(" [b2&3=0x%x]", b2); 638 639 if (DNS_OPCODE(np) == IQUERY) { 640 if (qdcount) 641 printf(" [%dq]", qdcount); 642 if (ancount != 1) 643 printf(" [%da]", ancount); 644 } 645 else { 646 if (ancount) 647 printf(" [%da]", ancount); 648 if (qdcount != 1) 649 printf(" [%dq]", qdcount); 650 } 651 if (nscount) 652 printf(" [%dn]", nscount); 653 if (arcount) 654 printf(" [%dau]", arcount); 655 656 cp = (const u_char *)(np + 1); 657 if (qdcount--) { 658 cp = ns_qprint(cp, (const u_char *)np, is_mdns); 659 if (!cp) 660 goto trunc; 661 while (cp < snapend && qdcount--) { 662 cp = ns_qprint((const u_char *)cp, 663 (const u_char *)np, 664 is_mdns); 665 if (!cp) 666 goto trunc; 667 } 668 } 669 if (qdcount > 0) 670 goto trunc; 671 672 /* Print remaining sections on -vv */ 673 if (vflag > 1) { 674 if (ancount--) { 675 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 676 goto trunc; 677 while (cp < snapend && ancount--) { 678 putchar(','); 679 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 680 goto trunc; 681 } 682 } 683 if (ancount > 0) 684 goto trunc; 685 if (cp < snapend && nscount--) { 686 fputs(" ns:", stdout); 687 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 688 goto trunc; 689 while (nscount-- && cp < snapend) { 690 putchar(','); 691 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 692 goto trunc; 693 } 694 } 695 if (nscount > 0) 696 goto trunc; 697 if (cp < snapend && arcount--) { 698 fputs(" ar:", stdout); 699 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 700 goto trunc; 701 while (cp < snapend && arcount--) { 702 putchar(','); 703 if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL) 704 goto trunc; 705 } 706 } 707 if (arcount > 0) 708 goto trunc; 709 } 710 } 711 printf(" (%d)", length); 712 return; 713 714 trunc: 715 printf("[|domain]"); 716 return; 717 } 718