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