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