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 22 #include <sys/cdefs.h> 23 #ifndef lint 24 __RCSID("$NetBSD: print-domain.c,v 1.10 2023/08/17 20:19:40 christos Exp $"); 25 #endif 26 27 /* \summary: Domain Name System (DNS) printer */ 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> 31 #endif 32 33 #include "netdissect-stdinc.h" 34 35 #include <string.h> 36 37 #include "netdissect.h" 38 #include "addrtoname.h" 39 #include "addrtostr.h" 40 #include "extract.h" 41 42 #include "nameser.h" 43 44 static const char *ns_ops[] = { 45 "", " inv_q", " stat", " op3", " notify", " update", " op6", " op7", 46 " op8", " updateA", " updateD", " updateDA", 47 " updateM", " updateMA", " zoneInit", " zoneRef", 48 }; 49 50 static const char *ns_resp[] = { 51 "", " FormErr", " ServFail", " NXDomain", 52 " NotImp", " Refused", " YXDomain", " YXRRSet", 53 " NXRRSet", " NotAuth", " NotZone", " Resp11", 54 " Resp12", " Resp13", " Resp14", " NoChange", 55 " BadVers", "Resp17", " Resp18", " Resp19", 56 " Resp20", "Resp21", " Resp22", " BadCookie", 57 }; 58 59 static const char * 60 ns_rcode(u_int rcode) { 61 static char buf[sizeof(" Resp4095")]; 62 63 if (rcode < sizeof(ns_resp)/sizeof(ns_resp[0])) { 64 return (ns_resp[rcode]); 65 } 66 snprintf(buf, sizeof(buf), " Resp%u", rcode & 0xfff); 67 return (buf); 68 } 69 70 /* skip over a domain name */ 71 static const u_char * 72 ns_nskip(netdissect_options *ndo, 73 const u_char *cp) 74 { 75 u_char i; 76 77 if (!ND_TTEST_1(cp)) 78 return (NULL); 79 i = GET_U_1(cp); 80 cp++; 81 while (i) { 82 switch (i & TYPE_MASK) { 83 84 case TYPE_INDIR: 85 return (cp + 1); 86 87 case TYPE_EDNS0: { 88 int bitlen, bytelen; 89 90 if ((i & ~TYPE_MASK) != EDNS0_ELT_BITLABEL) 91 return(NULL); /* unknown ELT */ 92 if (!ND_TTEST_1(cp)) 93 return (NULL); 94 if ((bitlen = GET_U_1(cp)) == 0) 95 bitlen = 256; 96 cp++; 97 bytelen = (bitlen + 7) / 8; 98 cp += bytelen; 99 } 100 break; 101 102 case TYPE_RESERVED: 103 return (NULL); 104 105 case TYPE_LABEL: 106 cp += i; 107 break; 108 } 109 if (!ND_TTEST_1(cp)) 110 return (NULL); 111 i = GET_U_1(cp); 112 cp++; 113 } 114 return (cp); 115 } 116 117 static const u_char * 118 blabel_print(netdissect_options *ndo, 119 const u_char *cp) 120 { 121 u_int bitlen, slen, b; 122 const u_char *bitp, *lim; 123 uint8_t tc; 124 125 if (!ND_TTEST_1(cp)) 126 return(NULL); 127 if ((bitlen = GET_U_1(cp)) == 0) 128 bitlen = 256; 129 slen = (bitlen + 3) / 4; 130 lim = cp + 1 + slen; 131 132 /* print the bit string as a hex string */ 133 ND_PRINT("\\[x"); 134 for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) { 135 ND_PRINT("%02x", GET_U_1(bitp)); 136 } 137 if (b > 4) { 138 tc = GET_U_1(bitp); 139 bitp++; 140 ND_PRINT("%02x", tc & (0xff << (8 - b))); 141 } else if (b > 0) { 142 tc = GET_U_1(bitp); 143 bitp++; 144 ND_PRINT("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); 145 } 146 ND_PRINT("/%u]", bitlen); 147 return lim; 148 } 149 150 static int 151 labellen(netdissect_options *ndo, 152 const u_char *cp) 153 { 154 u_int i; 155 156 if (!ND_TTEST_1(cp)) 157 return(-1); 158 i = GET_U_1(cp); 159 switch (i & TYPE_MASK) { 160 161 case TYPE_EDNS0: { 162 u_int bitlen, elt; 163 if ((elt = (i & ~TYPE_MASK)) != EDNS0_ELT_BITLABEL) { 164 ND_PRINT("<ELT %d>", elt); 165 return(-1); 166 } 167 if (!ND_TTEST_1(cp + 1)) 168 return(-1); 169 if ((bitlen = GET_U_1(cp + 1)) == 0) 170 bitlen = 256; 171 return(((bitlen + 7) / 8) + 1); 172 } 173 174 case TYPE_INDIR: 175 case TYPE_LABEL: 176 return(i); 177 178 default: 179 /* 180 * TYPE_RESERVED, but we use default to suppress compiler 181 * warnings about falling out of the switch statement. 182 */ 183 ND_PRINT("<BAD LABEL TYPE>"); 184 return(-1); 185 } 186 } 187 188 /* print a <domain-name> */ 189 const u_char * 190 fqdn_print(netdissect_options *ndo, 191 const u_char *cp, const u_char *bp) 192 { 193 u_int i, l; 194 const u_char *rp = NULL; 195 int compress = 0; 196 u_int elt; 197 u_int offset, max_offset; 198 u_int name_chars = 0; 199 200 if ((l = labellen(ndo, cp)) == (u_int)-1) 201 return(NULL); 202 if (!ND_TTEST_1(cp)) 203 return(NULL); 204 max_offset = (u_int)(cp - bp); 205 i = GET_U_1(cp); 206 cp++; 207 if ((i & TYPE_MASK) != TYPE_INDIR) { 208 compress = 0; 209 rp = cp + l; 210 } 211 212 if (i != 0) { 213 while (i && cp < ndo->ndo_snapend) { 214 switch (i & TYPE_MASK) { 215 216 case TYPE_INDIR: 217 if (!compress) { 218 rp = cp + 1; 219 compress = 1; 220 } 221 if (!ND_TTEST_1(cp)) 222 return(NULL); 223 offset = (((i << 8) | GET_U_1(cp)) & 0x3fff); 224 /* 225 * This must move backwards in the packet. 226 * No RFC explicitly says that, but BIND's 227 * name decompression code requires it, 228 * as a way of preventing infinite loops 229 * and other bad behavior, and it's probably 230 * what was intended (compress by pointing 231 * to domain name suffixes already seen in 232 * the packet). 233 */ 234 if (offset >= max_offset) { 235 ND_PRINT("<BAD PTR>"); 236 return(NULL); 237 } 238 max_offset = offset; 239 cp = bp + offset; 240 if (!ND_TTEST_1(cp)) 241 return(NULL); 242 i = GET_U_1(cp); 243 if ((l = labellen(ndo, cp)) == (u_int)-1) 244 return(NULL); 245 cp++; 246 continue; 247 248 case TYPE_EDNS0: 249 elt = (i & ~TYPE_MASK); 250 switch(elt) { 251 case EDNS0_ELT_BITLABEL: 252 if (blabel_print(ndo, cp) == NULL) 253 return (NULL); 254 break; 255 default: 256 /* unknown ELT */ 257 ND_PRINT("<ELT %u>", elt); 258 return(NULL); 259 } 260 break; 261 262 case TYPE_RESERVED: 263 ND_PRINT("<BAD LABEL TYPE>"); 264 return(NULL); 265 266 case TYPE_LABEL: 267 if (name_chars + l <= MAXCDNAME) { 268 if (nd_printn(ndo, cp, l, ndo->ndo_snapend)) 269 return(NULL); 270 } else if (name_chars < MAXCDNAME) { 271 if (nd_printn(ndo, cp, 272 MAXCDNAME - name_chars, ndo->ndo_snapend)) 273 return(NULL); 274 } 275 name_chars += l; 276 break; 277 } 278 279 cp += l; 280 if (name_chars <= MAXCDNAME) 281 ND_PRINT("."); 282 name_chars++; 283 if (!ND_TTEST_1(cp)) 284 return(NULL); 285 i = GET_U_1(cp); 286 if ((l = labellen(ndo, cp)) == (u_int)-1) 287 return(NULL); 288 cp++; 289 if (!compress) 290 rp += l + 1; 291 } 292 if (name_chars > MAXCDNAME) 293 ND_PRINT("<DOMAIN NAME TOO LONG>"); 294 } else 295 ND_PRINT("."); 296 return (rp); 297 } 298 299 /* print a <character-string> */ 300 static const u_char * 301 ns_cprint(netdissect_options *ndo, 302 const u_char *cp) 303 { 304 u_int i; 305 306 if (!ND_TTEST_1(cp)) 307 return (NULL); 308 i = GET_U_1(cp); 309 cp++; 310 if (nd_printn(ndo, cp, i, ndo->ndo_snapend)) 311 return (NULL); 312 return (cp + i); 313 } 314 315 static void 316 print_eopt_ecs(netdissect_options *ndo, const u_char *cp, 317 u_int data_len) 318 { 319 u_int family, addr_bits, src_len, scope_len; 320 321 u_char padded[32]; 322 char addr[INET6_ADDRSTRLEN]; 323 324 /* ecs option must at least contain family, src len, and scope len */ 325 if (data_len < 4) { 326 nd_print_invalid(ndo); 327 return; 328 } 329 330 family = GET_BE_U_2(cp); 331 cp += 2; 332 src_len = GET_U_1(cp); 333 cp += 1; 334 scope_len = GET_U_1(cp); 335 cp += 1; 336 337 if (family == 1) 338 addr_bits = 32; 339 else if (family == 2) 340 addr_bits = 128; 341 else { 342 nd_print_invalid(ndo); 343 return; 344 } 345 346 if (data_len - 4 > (addr_bits / 8)) { 347 nd_print_invalid(ndo); 348 return; 349 } 350 /* checks for invalid ecs scope or source length */ 351 if (src_len > addr_bits || scope_len > addr_bits || ((src_len + 7) / 8) != (data_len - 4)) { 352 nd_print_invalid(ndo); 353 return; 354 } 355 356 /* pad the truncated address from ecs with zeros */ 357 memset(padded, 0, sizeof(padded)); 358 memcpy(padded, cp, data_len - 4); 359 360 361 if (family == 1) 362 ND_PRINT("%s/%d/%d", addrtostr(padded, addr, INET_ADDRSTRLEN), 363 src_len, scope_len); 364 else 365 ND_PRINT("%s/%d/%d", addrtostr6(padded, addr, INET6_ADDRSTRLEN), 366 src_len, scope_len); 367 368 } 369 370 extern const struct tok edns_opt2str[]; 371 extern const struct tok dau_alg2str[]; 372 extern const struct tok dhu_alg2str[]; 373 extern const struct tok n3u_alg2str[]; 374 375 376 /* print an <EDNS-option> */ 377 static const u_char * 378 eopt_print(netdissect_options *ndo, 379 const u_char *cp) 380 { 381 u_int opt, data_len, i; 382 383 if (!ND_TTEST_2(cp)) 384 return (NULL); 385 opt = GET_BE_U_2(cp); 386 cp += 2; 387 ND_PRINT("%s", tok2str(edns_opt2str, "Opt%u", opt)); 388 if (!ND_TTEST_2(cp)) 389 return (NULL); 390 data_len = GET_BE_U_2(cp); 391 cp += 2; 392 393 ND_TCHECK_LEN(cp, data_len); 394 395 if (data_len > 0) { 396 ND_PRINT(" "); 397 switch (opt) { 398 399 case E_ECS: 400 print_eopt_ecs(ndo, cp, data_len); 401 break; 402 case E_COOKIE: 403 if (data_len < 8 || (data_len > 8 && data_len < 16) || data_len > 40) 404 nd_print_invalid(ndo); 405 else { 406 for (i = 0; i < data_len; ++i) { 407 /* split client and server cookie */ 408 if (i == 8) 409 ND_PRINT(" "); 410 ND_PRINT("%02x", GET_U_1(cp + i)); 411 } 412 } 413 break; 414 case E_KEEPALIVE: 415 if (data_len != 2) 416 nd_print_invalid(ndo); 417 else 418 /* keepalive is in increments of 100ms. Convert to seconds */ 419 ND_PRINT("%0.1f sec", (GET_BE_U_2(cp) / 10.0)); 420 break; 421 case E_EXPIRE: 422 if (data_len != 4) 423 nd_print_invalid(ndo); 424 else 425 ND_PRINT("%u sec", GET_BE_U_4(cp)); 426 break; 427 case E_PADDING: 428 /* ignore contents and just print length */ 429 ND_PRINT("(%u)", data_len); 430 break; 431 case E_KEYTAG: 432 if (data_len % 2 != 0) 433 nd_print_invalid(ndo); 434 else 435 for (i = 0; i < data_len; i += 2) { 436 if (i > 0) 437 ND_PRINT(" "); 438 ND_PRINT("%u", GET_BE_U_2(cp + i)); 439 } 440 break; 441 case E_DAU: 442 for (i = 0; i < data_len; ++i) { 443 if (i > 0) 444 ND_PRINT(" "); 445 ND_PRINT("%s", tok2str(dau_alg2str, "Alg_%u", GET_U_1(cp + i))); 446 } 447 break; 448 case E_DHU: 449 for (i = 0; i < data_len; ++i) { 450 if (i > 0) 451 ND_PRINT(" "); 452 ND_PRINT("%s", tok2str(dhu_alg2str, "Alg_%u", GET_U_1(cp + i))); 453 } 454 break; 455 case E_N3U: 456 for (i = 0; i < data_len; ++i) { 457 if (i > 0) 458 ND_PRINT(" "); 459 ND_PRINT("%s", tok2str(n3u_alg2str, "Alg_%u", GET_U_1(cp + i))); 460 } 461 break; 462 case E_CHAIN: 463 fqdn_print(ndo, cp, cp + data_len); 464 break; 465 case E_NSID: 466 /* intentional fall-through. NSID is an undefined byte string */ 467 default: 468 for (i = 0; i < data_len; ++i) 469 ND_PRINT("%02x", GET_U_1(cp + i)); 470 break; 471 } 472 } 473 return (cp + data_len); 474 475 trunc: 476 return (NULL); 477 478 } 479 480 481 482 extern const struct tok ns_type2str[]; 483 484 /* https://www.iana.org/assignments/dns-parameters */ 485 const struct tok ns_type2str[] = { 486 { T_A, "A" }, /* RFC 1035 */ 487 { T_NS, "NS" }, /* RFC 1035 */ 488 { T_MD, "MD" }, /* RFC 1035 */ 489 { T_MF, "MF" }, /* RFC 1035 */ 490 { T_CNAME, "CNAME" }, /* RFC 1035 */ 491 { T_SOA, "SOA" }, /* RFC 1035 */ 492 { T_MB, "MB" }, /* RFC 1035 */ 493 { T_MG, "MG" }, /* RFC 1035 */ 494 { T_MR, "MR" }, /* RFC 1035 */ 495 { T_NULL, "NULL" }, /* RFC 1035 */ 496 { T_WKS, "WKS" }, /* RFC 1035 */ 497 { T_PTR, "PTR" }, /* RFC 1035 */ 498 { T_HINFO, "HINFO" }, /* RFC 1035 */ 499 { T_MINFO, "MINFO" }, /* RFC 1035 */ 500 { T_MX, "MX" }, /* RFC 1035 */ 501 { T_TXT, "TXT" }, /* RFC 1035 */ 502 { T_RP, "RP" }, /* RFC 1183 */ 503 { T_AFSDB, "AFSDB" }, /* RFC 5864 */ 504 { T_X25, "X25" }, /* RFC 1183 */ 505 { T_ISDN, "ISDN" }, /* RFC 1183 */ 506 { T_RT, "RT" }, /* RFC 1183 */ 507 { T_NSAP, "NSAP" }, /* RFC 1706 */ 508 { T_NSAP_PTR, "NSAP_PTR" }, /* RFC 1706 */ 509 { T_SIG, "SIG" }, /* RFC 3008 */ 510 { T_KEY, "KEY" }, /* RFC 3110 */ 511 { T_PX, "PX" }, /* RFC 2163 */ 512 { T_GPOS, "GPOS" }, /* RFC 1712 */ 513 { T_AAAA, "AAAA" }, /* RFC 3596 */ 514 { T_LOC, "LOC" }, /* RFC 1876 */ 515 { T_NXT, "NXT" }, /* RFC 3755 */ 516 { T_EID, "EID" }, /* Nimrod */ 517 { T_NIMLOC, "NIMLOC" }, /* Nimrod */ 518 { T_SRV, "SRV" }, /* RFC 2782 */ 519 { T_ATMA, "ATMA" }, /* ATM Forum */ 520 { T_NAPTR, "NAPTR" }, /* RFC 3403 */ 521 { T_KX, "KX" }, /* RFC 2230 */ 522 { T_CERT, "CERT" }, /* RFC 4398 */ 523 { T_A6, "A6" }, /* RFC 6563 */ 524 { T_DNAME, "DNAME" }, /* RFC 6672 */ 525 { T_SINK, "SINK" }, 526 { T_OPT, "OPT" }, /* RFC 6891 */ 527 { T_APL, "APL" }, /* RFC 3123 */ 528 { T_DS, "DS" }, /* RFC 4034 */ 529 { T_SSHFP, "SSHFP" }, /* RFC 4255 */ 530 { T_IPSECKEY, "IPSECKEY" }, /* RFC 4025 */ 531 { T_RRSIG, "RRSIG" }, /* RFC 4034 */ 532 { T_NSEC, "NSEC" }, /* RFC 4034 */ 533 { T_DNSKEY, "DNSKEY" }, /* RFC 4034 */ 534 { T_DHCID, "DHCID" }, /* RFC 4071 */ 535 { T_NSEC3, "NSEC3" }, /* RFC 5155 */ 536 { T_NSEC3PARAM, "NSEC3PARAM" }, /* RFC 5155 */ 537 { T_TLSA, "TLSA" }, /* RFC 6698 */ 538 { T_SMIMEA, "SMIMEA" }, /* RFC 8162 */ 539 { T_HIP, "HIP" }, /* RFC 8005 */ 540 { T_NINFO, "NINFO" }, 541 { T_RKEY, "RKEY" }, 542 { T_TALINK, "TALINK" }, 543 { T_CDS, "CDS" }, /* RFC 7344 */ 544 { T_CDNSKEY, "CDNSKEY" }, /* RFC 7344 */ 545 { T_OPENPGPKEY, "OPENPGPKEY" }, /* RFC 7929 */ 546 { T_CSYNC, "CSYNC" }, /* RFC 7477 */ 547 { T_ZONEMD, "ZONEMD" }, /* RFC 8976 */ 548 { T_SVCB, "SVCB" }, 549 { T_HTTPS, "HTTPS" }, 550 { T_SPF, "SPF" }, /* RFC 7208 */ 551 { T_UINFO, "UINFO" }, 552 { T_UID, "UID" }, 553 { T_GID, "GID" }, 554 { T_UNSPEC, "UNSPEC" }, 555 { T_NID, "NID" }, /* RFC 6742 */ 556 { T_L32, "L32" }, /* RFC 6742 */ 557 { T_L64, "L64" }, /* RFC 6742 */ 558 { T_LP, "LP" }, /* RFC 6742 */ 559 { T_EUI48, "EUI48" }, /* RFC 7043 */ 560 { T_EUI64, "EUI64" }, /* RFC 7043 */ 561 { T_TKEY, "TKEY" }, /* RFC 2930 */ 562 { T_TSIG, "TSIG" }, /* RFC 8945 */ 563 { T_IXFR, "IXFR" }, /* RFC 1995 */ 564 { T_AXFR, "AXFR" }, /* RFC 5936 */ 565 { T_MAILB, "MAILB" }, /* RFC 1035 */ 566 { T_MAILA, "MAILA" }, /* RFC 1035 */ 567 { T_ANY, "ANY" }, /* RFC 8482 */ 568 { T_URI, "URI" }, /* RFC 7553 */ 569 { T_CAA, "CAA" }, /* RFC 8659 */ 570 { T_AVC, "AVC" }, 571 { T_DOA, "DOA" }, 572 { T_AMTRELAY, "AMTRELAY" }, /* RFC 8777 */ 573 { T_TA, "TA" }, 574 { T_DLV, "DLV" }, /* RFC 8749 */ 575 { 0, NULL } 576 }; 577 578 extern const struct tok ns_class2str[]; 579 580 const struct tok ns_class2str[] = { 581 { C_IN, "IN" }, /* Not used */ 582 { C_CHAOS, "CHAOS" }, 583 { C_HS, "HS" }, 584 { C_ANY, "ANY" }, 585 { 0, NULL } 586 }; 587 588 const struct tok edns_opt2str[] = { 589 { E_LLQ, "LLQ" }, 590 { E_UL, "UL" }, 591 { E_NSID, "NSID" }, 592 { E_DAU, "DAU" }, 593 { E_DHU, "DHU" }, 594 { E_N3U, "N3U" }, 595 { E_ECS, "ECS" }, 596 { E_EXPIRE, "EXPIRE" }, 597 { E_COOKIE, "COOKIE" }, 598 { E_KEEPALIVE, "KEEPALIVE" }, 599 { E_PADDING, "PADDING" }, 600 { E_CHAIN, "CHAIN" }, 601 { E_KEYTAG, "KEY-TAG" }, 602 { E_CLIENTTAG, "CLIENT-TAG" }, 603 { E_SERVERTAG, "SERVER-TAG" }, 604 { 0, NULL } 605 }; 606 607 const struct tok dau_alg2str[] = { 608 { A_DELETE, "DELETE" }, 609 { A_RSAMD5, "RSAMD5" }, 610 { A_DH, "DH" }, 611 { A_DSA, "DS" }, 612 { A_RSASHA1, "RSASHA1" }, 613 { A_DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1" }, 614 { A_RSASHA1_NSEC3_SHA1, "RSASHA1-NSEC3-SHA1" }, 615 { A_RSASHA256, "RSASHA256" }, 616 { A_RSASHA512, "RSASHA512" }, 617 { A_ECC_GOST, "ECC-GOST" }, 618 { A_ECDSAP256SHA256, "ECDSAP256SHA256" }, 619 { A_ECDSAP384SHA384, "ECDSAP384SHA384" }, 620 { A_ED25519, "ED25519" }, 621 { A_ED448, "ED448" }, 622 { A_INDIRECT, "INDIRECT" }, 623 { A_PRIVATEDNS, "PRIVATEDNS" }, 624 { A_PRIVATEOID, "PRIVATEOID" }, 625 { 0, NULL } 626 }; 627 628 const struct tok dhu_alg2str[] = { 629 { DS_SHA1, "SHA-1" }, 630 { DS_SHA256,"SHA-256" }, 631 { DS_GOST, "GOST_R_34.11-94" }, 632 { DS_SHA384,"SHA-384" }, 633 { 0, NULL } 634 }; 635 636 const struct tok n3u_alg2str[] = { 637 { NSEC_SHA1,"SHA-1" }, 638 { 0, NULL } 639 }; 640 641 /* print a query */ 642 static const u_char * 643 ns_qprint(netdissect_options *ndo, 644 const u_char *cp, const u_char *bp, int is_mdns) 645 { 646 const u_char *np = cp; 647 u_int i, class; 648 649 cp = ns_nskip(ndo, cp); 650 651 if (cp == NULL || !ND_TTEST_4(cp)) 652 return(NULL); 653 654 /* print the qtype */ 655 i = GET_BE_U_2(cp); 656 cp += 2; 657 ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", i)); 658 /* print the qclass (if it's not IN) */ 659 i = GET_BE_U_2(cp); 660 cp += 2; 661 if (is_mdns) 662 class = (i & ~C_QU); 663 else 664 class = i; 665 if (class != C_IN) 666 ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class)); 667 if (is_mdns) { 668 ND_PRINT(i & C_QU ? " (QU)" : " (QM)"); 669 } 670 671 ND_PRINT("? "); 672 cp = fqdn_print(ndo, np, bp); 673 return(cp ? cp + 4 : NULL); 674 } 675 676 /* print a reply */ 677 static const u_char * 678 ns_rprint(netdissect_options *ndo, 679 const u_char *cp, const u_char *bp, int is_mdns) 680 { 681 u_int i, class, opt_flags = 0; 682 u_short typ, len; 683 const u_char *rp; 684 685 if (ndo->ndo_vflag) { 686 ND_PRINT(" "); 687 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 688 return NULL; 689 } else 690 cp = ns_nskip(ndo, cp); 691 692 if (cp == NULL || !ND_TTEST_LEN(cp, 10)) 693 return (ndo->ndo_snapend); 694 695 /* print the type/qtype */ 696 typ = GET_BE_U_2(cp); 697 cp += 2; 698 /* print the class (if it's not IN and the type isn't OPT) */ 699 i = GET_BE_U_2(cp); 700 cp += 2; 701 if (is_mdns) 702 class = (i & ~C_CACHE_FLUSH); 703 else 704 class = i; 705 if (class != C_IN && typ != T_OPT) 706 ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class)); 707 if (is_mdns) { 708 if (i & C_CACHE_FLUSH) 709 ND_PRINT(" (Cache flush)"); 710 } 711 712 if (typ == T_OPT) { 713 /* get opt flags */ 714 cp += 2; 715 opt_flags = GET_BE_U_2(cp); 716 /* ignore rest of ttl field */ 717 cp += 2; 718 } else if (ndo->ndo_vflag > 2) { 719 /* print ttl */ 720 ND_PRINT(" ["); 721 unsigned_relts_print(ndo, GET_BE_U_4(cp)); 722 ND_PRINT("]"); 723 cp += 4; 724 } else { 725 /* ignore ttl */ 726 cp += 4; 727 } 728 729 len = GET_BE_U_2(cp); 730 cp += 2; 731 732 rp = cp + len; 733 734 ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", typ)); 735 if (rp > ndo->ndo_snapend) 736 return(NULL); 737 738 switch (typ) { 739 case T_A: 740 if (!ND_TTEST_LEN(cp, sizeof(nd_ipv4))) 741 return(NULL); 742 ND_PRINT(" %s", intoa(GET_IPV4_TO_NETWORK_ORDER(cp))); 743 break; 744 745 case T_NS: 746 case T_CNAME: 747 case T_PTR: 748 case T_DNAME: 749 ND_PRINT(" "); 750 if (fqdn_print(ndo, cp, bp) == NULL) 751 return(NULL); 752 break; 753 754 case T_SOA: 755 if (!ndo->ndo_vflag) 756 break; 757 ND_PRINT(" "); 758 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 759 return(NULL); 760 ND_PRINT(" "); 761 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 762 return(NULL); 763 if (!ND_TTEST_LEN(cp, 5 * 4)) 764 return(NULL); 765 ND_PRINT(" %u", GET_BE_U_4(cp)); 766 cp += 4; 767 ND_PRINT(" %u", GET_BE_U_4(cp)); 768 cp += 4; 769 ND_PRINT(" %u", GET_BE_U_4(cp)); 770 cp += 4; 771 ND_PRINT(" %u", GET_BE_U_4(cp)); 772 cp += 4; 773 ND_PRINT(" %u", GET_BE_U_4(cp)); 774 cp += 4; 775 break; 776 case T_MX: 777 ND_PRINT(" "); 778 if (!ND_TTEST_2(cp)) 779 return(NULL); 780 if (fqdn_print(ndo, cp + 2, bp) == NULL) 781 return(NULL); 782 ND_PRINT(" %u", GET_BE_U_2(cp)); 783 break; 784 785 case T_TXT: 786 while (cp < rp) { 787 ND_PRINT(" \""); 788 cp = ns_cprint(ndo, cp); 789 if (cp == NULL) 790 return(NULL); 791 ND_PRINT("\""); 792 } 793 break; 794 795 case T_SRV: 796 ND_PRINT(" "); 797 if (!ND_TTEST_6(cp)) 798 return(NULL); 799 if (fqdn_print(ndo, cp + 6, bp) == NULL) 800 return(NULL); 801 ND_PRINT(":%u %u %u", GET_BE_U_2(cp + 4), 802 GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 803 break; 804 805 case T_AAAA: 806 { 807 char ntop_buf[INET6_ADDRSTRLEN]; 808 809 if (!ND_TTEST_LEN(cp, sizeof(nd_ipv6))) 810 return(NULL); 811 ND_PRINT(" %s", 812 addrtostr6(cp, ntop_buf, sizeof(ntop_buf))); 813 814 break; 815 } 816 817 case T_A6: 818 { 819 nd_ipv6 a; 820 int pbit, pbyte; 821 char ntop_buf[INET6_ADDRSTRLEN]; 822 823 if (!ND_TTEST_1(cp)) 824 return(NULL); 825 pbit = GET_U_1(cp); 826 pbyte = (pbit & ~7) / 8; 827 if (pbit > 128) { 828 ND_PRINT(" %u(bad plen)", pbit); 829 break; 830 } else if (pbit < 128) { 831 memset(a, 0, sizeof(a)); 832 GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte); 833 ND_PRINT(" %u %s", pbit, 834 addrtostr6(&a, ntop_buf, sizeof(ntop_buf))); 835 } 836 if (pbit > 0) { 837 ND_PRINT(" "); 838 if (fqdn_print(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL) 839 return(NULL); 840 } 841 break; 842 } 843 844 case T_URI: 845 if (!ND_TTEST_LEN(cp, len)) 846 return(NULL); 847 ND_PRINT(" %u %u ", GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 848 if (nd_printn(ndo, cp + 4, len - 4, ndo->ndo_snapend)) 849 return(NULL); 850 break; 851 852 case T_OPT: 853 ND_PRINT(" UDPsize=%u", class); 854 if (opt_flags & 0x8000) 855 ND_PRINT(" DO"); 856 if (cp < rp) { 857 ND_PRINT(" ["); 858 while (cp < rp) { 859 cp = eopt_print(ndo, cp); 860 if (cp == NULL) 861 return(NULL); 862 if (cp < rp) 863 ND_PRINT(","); 864 } 865 ND_PRINT("]"); 866 } 867 break; 868 869 case T_TSIG: 870 { 871 if (cp + len > ndo->ndo_snapend) 872 return(NULL); 873 if (!ndo->ndo_vflag) 874 break; 875 ND_PRINT(" "); 876 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 877 return(NULL); 878 cp += 6; 879 if (!ND_TTEST_2(cp)) 880 return(NULL); 881 ND_PRINT(" fudge=%u", GET_BE_U_2(cp)); 882 cp += 2; 883 if (!ND_TTEST_2(cp)) 884 return(NULL); 885 ND_PRINT(" maclen=%u", GET_BE_U_2(cp)); 886 cp += 2 + GET_BE_U_2(cp); 887 if (!ND_TTEST_2(cp)) 888 return(NULL); 889 ND_PRINT(" origid=%u", GET_BE_U_2(cp)); 890 cp += 2; 891 if (!ND_TTEST_2(cp)) 892 return(NULL); 893 ND_PRINT(" error=%u", GET_BE_U_2(cp)); 894 cp += 2; 895 if (!ND_TTEST_2(cp)) 896 return(NULL); 897 ND_PRINT(" otherlen=%u", GET_BE_U_2(cp)); 898 cp += 2; 899 } 900 } 901 return (rp); /* XXX This isn't always right */ 902 } 903 904 void 905 domain_print(netdissect_options *ndo, 906 const u_char *bp, u_int length, int over_tcp, int is_mdns) 907 { 908 const dns_header_t *np; 909 uint16_t flags, rcode, rdlen, type; 910 u_int qdcount, ancount, nscount, arcount; 911 u_int i; 912 const u_char *cp; 913 uint16_t b2; 914 915 ndo->ndo_protocol = "domain"; 916 917 if (over_tcp) { 918 /* 919 * The message is prefixed with a two byte length field 920 * which gives the message length, excluding the two byte 921 * length field. (RFC 1035 - 4.2.2. TCP usage) 922 */ 923 if (length < 2) { 924 ND_PRINT(" [DNS over TCP: length %u < 2]", length); 925 nd_print_invalid(ndo); 926 return; 927 } else { 928 length -= 2; /* excluding the two byte length field */ 929 if (GET_BE_U_2(bp) != length) { 930 ND_PRINT(" [prefix length(%u) != length(%u)]", 931 GET_BE_U_2(bp), length); 932 nd_print_invalid(ndo); 933 return; 934 } else { 935 bp += 2; 936 /* in over TCP case, we need to prepend a space 937 * (not needed in over UDP case) 938 */ 939 ND_PRINT(" "); 940 } 941 } 942 } 943 944 np = (const dns_header_t *)bp; 945 946 if(length < sizeof(*np)) { 947 nd_print_protocol(ndo); 948 ND_PRINT(" [length %u < %zu]", length, sizeof(*np)); 949 nd_print_invalid(ndo); 950 return; 951 } 952 953 ND_TCHECK_SIZE(np); 954 flags = GET_BE_U_2(np->flags); 955 /* get the byte-order right */ 956 qdcount = GET_BE_U_2(np->qdcount); 957 ancount = GET_BE_U_2(np->ancount); 958 nscount = GET_BE_U_2(np->nscount); 959 arcount = GET_BE_U_2(np->arcount); 960 961 /* find the opt record to extract extended rcode */ 962 cp = (const u_char *)(np + 1); 963 rcode = DNS_RCODE(flags); 964 for (i = 0; i < qdcount; i++) { 965 if ((cp = ns_nskip(ndo, cp)) == NULL) 966 goto print; 967 cp += 4; /* skip QTYPE and QCLASS */ 968 if (cp >= ndo->ndo_snapend) 969 goto print; 970 } 971 for (i = 0; i < ancount + nscount; i++) { 972 if ((cp = ns_nskip(ndo, cp)) == NULL) 973 goto print; 974 cp += 8; /* skip TYPE, CLASS and TTL */ 975 if (cp + 2 > ndo->ndo_snapend) 976 goto print; 977 rdlen = GET_BE_U_2(cp); 978 cp += 2 + rdlen; 979 if (cp >= ndo->ndo_snapend) 980 goto print; 981 } 982 for (i = 0; i < arcount; i++) { 983 if ((cp = ns_nskip(ndo, cp)) == NULL) 984 goto print; 985 if (cp + 2 > ndo->ndo_snapend) 986 goto print; 987 type = GET_BE_U_2(cp); 988 cp += 4; /* skip TYPE and CLASS */ 989 if (cp + 1 > ndo->ndo_snapend) 990 goto print; 991 if (type == T_OPT) { 992 rcode |= (GET_U_1(cp) << 4); 993 goto print; 994 } 995 cp += 4; 996 if (cp + 2 > ndo->ndo_snapend) 997 goto print; 998 rdlen = GET_BE_U_2(cp); 999 cp += 2 + rdlen; 1000 if (cp >= ndo->ndo_snapend) 1001 goto print; 1002 } 1003 1004 print: 1005 if (DNS_QR(flags)) { 1006 /* this is a response */ 1007 ND_PRINT("%u%s%s%s%s%s%s", 1008 GET_BE_U_2(np->id), 1009 ns_ops[DNS_OPCODE(flags)], 1010 ns_rcode(rcode), 1011 DNS_AA(flags)? "*" : "", 1012 DNS_RA(flags)? "" : "-", 1013 DNS_TC(flags)? "|" : "", 1014 DNS_AD(flags)? "$" : ""); 1015 1016 if (qdcount != 1) 1017 ND_PRINT(" [%uq]", qdcount); 1018 /* Print QUESTION section on -vv */ 1019 cp = (const u_char *)(np + 1); 1020 for (i = 0; i < qdcount; i++) { 1021 if (i != 0) 1022 ND_PRINT(","); 1023 if (ndo->ndo_vflag > 1) { 1024 ND_PRINT(" q:"); 1025 if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL) 1026 goto trunc; 1027 } else { 1028 if ((cp = ns_nskip(ndo, cp)) == NULL) 1029 goto trunc; 1030 cp += 4; /* skip QTYPE and QCLASS */ 1031 } 1032 } 1033 ND_PRINT(" %u/%u/%u", ancount, nscount, arcount); 1034 if (ancount) { 1035 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1036 goto trunc; 1037 ancount--; 1038 while (cp < ndo->ndo_snapend && ancount) { 1039 ND_PRINT(","); 1040 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1041 goto trunc; 1042 ancount--; 1043 } 1044 } 1045 if (ancount) 1046 goto trunc; 1047 /* Print NS and AR sections on -vv */ 1048 if (ndo->ndo_vflag > 1) { 1049 if (cp < ndo->ndo_snapend && nscount) { 1050 ND_PRINT(" ns:"); 1051 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1052 goto trunc; 1053 nscount--; 1054 while (cp < ndo->ndo_snapend && nscount) { 1055 ND_PRINT(","); 1056 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1057 goto trunc; 1058 nscount--; 1059 } 1060 } 1061 if (nscount) 1062 goto trunc; 1063 if (cp < ndo->ndo_snapend && arcount) { 1064 ND_PRINT(" ar:"); 1065 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1066 goto trunc; 1067 arcount--; 1068 while (cp < ndo->ndo_snapend && arcount) { 1069 ND_PRINT(","); 1070 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1071 goto trunc; 1072 arcount--; 1073 } 1074 } 1075 if (arcount) 1076 goto trunc; 1077 } 1078 } 1079 else { 1080 /* this is a request */ 1081 ND_PRINT("%u%s%s%s", GET_BE_U_2(np->id), 1082 ns_ops[DNS_OPCODE(flags)], 1083 DNS_RD(flags) ? "+" : "", 1084 DNS_CD(flags) ? "%" : ""); 1085 1086 /* any weirdness? */ 1087 b2 = GET_BE_U_2(((const u_short *)np) + 1); 1088 if (b2 & 0x6cf) 1089 ND_PRINT(" [b2&3=0x%x]", b2); 1090 1091 if (DNS_OPCODE(flags) == IQUERY) { 1092 if (qdcount) 1093 ND_PRINT(" [%uq]", qdcount); 1094 if (ancount != 1) 1095 ND_PRINT(" [%ua]", ancount); 1096 } 1097 else { 1098 if (ancount) 1099 ND_PRINT(" [%ua]", ancount); 1100 if (qdcount != 1) 1101 ND_PRINT(" [%uq]", qdcount); 1102 } 1103 if (nscount) 1104 ND_PRINT(" [%un]", nscount); 1105 if (arcount) 1106 ND_PRINT(" [%uau]", arcount); 1107 1108 cp = (const u_char *)(np + 1); 1109 if (qdcount) { 1110 cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns); 1111 if (!cp) 1112 goto trunc; 1113 qdcount--; 1114 while (cp < ndo->ndo_snapend && qdcount) { 1115 cp = ns_qprint(ndo, (const u_char *)cp, 1116 (const u_char *)np, 1117 is_mdns); 1118 if (!cp) 1119 goto trunc; 1120 qdcount--; 1121 } 1122 } 1123 if (qdcount) 1124 goto trunc; 1125 1126 /* Print remaining sections on -vv */ 1127 if (ndo->ndo_vflag > 1) { 1128 if (ancount) { 1129 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1130 goto trunc; 1131 ancount--; 1132 while (cp < ndo->ndo_snapend && ancount) { 1133 ND_PRINT(","); 1134 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1135 goto trunc; 1136 ancount--; 1137 } 1138 } 1139 if (ancount) 1140 goto trunc; 1141 if (cp < ndo->ndo_snapend && nscount) { 1142 ND_PRINT(" ns:"); 1143 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1144 goto trunc; 1145 nscount--; 1146 while (cp < ndo->ndo_snapend && nscount) { 1147 ND_PRINT(","); 1148 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1149 goto trunc; 1150 nscount--; 1151 } 1152 } 1153 if (nscount > 0) 1154 goto trunc; 1155 if (cp < ndo->ndo_snapend && arcount) { 1156 ND_PRINT(" ar:"); 1157 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1158 goto trunc; 1159 arcount--; 1160 while (cp < ndo->ndo_snapend && arcount) { 1161 ND_PRINT(","); 1162 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1163 goto trunc; 1164 arcount--; 1165 } 1166 } 1167 if (arcount) 1168 goto trunc; 1169 } 1170 } 1171 ND_PRINT(" (%u)", length); 1172 return; 1173 1174 trunc: 1175 nd_print_trunc(ndo); 1176 } 1177