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