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.12 2026/03/19 00:05:13 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 ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", typ)); 731 732 ND_TCHECK_LEN(cp, len); 733 rp = cp + len; 734 735 switch (typ) { 736 case T_A: 737 if (!ND_TTEST_LEN(cp, sizeof(nd_ipv4))) 738 return(NULL); 739 ND_PRINT(" %s", intoa(GET_IPV4_TO_NETWORK_ORDER(cp))); 740 break; 741 742 case T_NS: 743 case T_CNAME: 744 case T_PTR: 745 case T_DNAME: 746 ND_PRINT(" "); 747 if (fqdn_print(ndo, cp, bp) == NULL) 748 return(NULL); 749 break; 750 751 case T_SOA: 752 if (!ndo->ndo_vflag) 753 break; 754 ND_PRINT(" "); 755 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 756 return(NULL); 757 ND_PRINT(" "); 758 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 759 return(NULL); 760 if (!ND_TTEST_LEN(cp, 5 * 4)) 761 return(NULL); 762 ND_PRINT(" %u", GET_BE_U_4(cp)); 763 cp += 4; 764 ND_PRINT(" %u", GET_BE_U_4(cp)); 765 cp += 4; 766 ND_PRINT(" %u", GET_BE_U_4(cp)); 767 cp += 4; 768 ND_PRINT(" %u", GET_BE_U_4(cp)); 769 cp += 4; 770 ND_PRINT(" %u", GET_BE_U_4(cp)); 771 cp += 4; 772 break; 773 case T_MX: 774 ND_PRINT(" "); 775 if (!ND_TTEST_2(cp)) 776 return(NULL); 777 if (fqdn_print(ndo, cp + 2, bp) == NULL) 778 return(NULL); 779 ND_PRINT(" %u", GET_BE_U_2(cp)); 780 break; 781 782 case T_TXT: 783 while (cp < rp) { 784 ND_PRINT(" \""); 785 cp = ns_cprint(ndo, cp); 786 if (cp == NULL) 787 return(NULL); 788 ND_PRINT("\""); 789 } 790 break; 791 792 case T_SRV: 793 ND_PRINT(" "); 794 if (!ND_TTEST_6(cp)) 795 return(NULL); 796 if (fqdn_print(ndo, cp + 6, bp) == NULL) 797 return(NULL); 798 ND_PRINT(":%u %u %u", GET_BE_U_2(cp + 4), 799 GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 800 break; 801 802 case T_AAAA: 803 { 804 char ntop_buf[INET6_ADDRSTRLEN]; 805 806 if (!ND_TTEST_LEN(cp, sizeof(nd_ipv6))) 807 return(NULL); 808 ND_PRINT(" %s", 809 addrtostr6(cp, ntop_buf, sizeof(ntop_buf))); 810 811 break; 812 } 813 814 case T_A6: 815 { 816 nd_ipv6 a; 817 int pbit, pbyte; 818 char ntop_buf[INET6_ADDRSTRLEN]; 819 820 if (!ND_TTEST_1(cp)) 821 return(NULL); 822 pbit = GET_U_1(cp); 823 pbyte = (pbit & ~7) / 8; 824 if (pbit > 128) { 825 ND_PRINT(" %u(bad plen)", pbit); 826 break; 827 } else if (pbit < 128) { 828 memset(a, 0, sizeof(a)); 829 GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte); 830 ND_PRINT(" %u %s", pbit, 831 addrtostr6(&a, ntop_buf, sizeof(ntop_buf))); 832 } 833 if (pbit > 0) { 834 ND_PRINT(" "); 835 if (fqdn_print(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL) 836 return(NULL); 837 } 838 break; 839 } 840 841 case T_URI: 842 if (!ND_TTEST_LEN(cp, len)) 843 return(NULL); 844 if (len < 4) { 845 ND_PRINT(" len %u is too short (< 4)", len); 846 break; 847 } 848 ND_PRINT(" %u %u ", GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 849 if (nd_printn(ndo, cp + 4, len - 4, ndo->ndo_snapend)) 850 return(NULL); 851 break; 852 853 case T_OPT: 854 ND_PRINT(" UDPsize=%u", class); 855 if (opt_flags & 0x8000) 856 ND_PRINT(" DO"); 857 if (cp < rp) { 858 ND_PRINT(" ["); 859 while (cp < rp) { 860 cp = eopt_print(ndo, cp); 861 if (cp == NULL) 862 return(NULL); 863 if (cp < rp) 864 ND_PRINT(","); 865 } 866 ND_PRINT("]"); 867 } 868 break; 869 870 case T_TSIG: 871 { 872 if (cp + len > ndo->ndo_snapend) 873 return(NULL); 874 if (!ndo->ndo_vflag) 875 break; 876 ND_PRINT(" "); 877 if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 878 return(NULL); 879 cp += 6; 880 if (!ND_TTEST_2(cp)) 881 return(NULL); 882 ND_PRINT(" fudge=%u", GET_BE_U_2(cp)); 883 cp += 2; 884 if (!ND_TTEST_2(cp)) 885 return(NULL); 886 ND_PRINT(" maclen=%u", GET_BE_U_2(cp)); 887 cp += 2 + GET_BE_U_2(cp); 888 if (!ND_TTEST_2(cp)) 889 return(NULL); 890 ND_PRINT(" origid=%u", GET_BE_U_2(cp)); 891 cp += 2; 892 if (!ND_TTEST_2(cp)) 893 return(NULL); 894 ND_PRINT(" error=%u", GET_BE_U_2(cp)); 895 cp += 2; 896 if (!ND_TTEST_2(cp)) 897 return(NULL); 898 ND_PRINT(" otherlen=%u", GET_BE_U_2(cp)); 899 cp += 2; 900 } 901 } 902 return (rp); /* XXX This isn't always right */ 903 904 trunc: 905 return(NULL); 906 } 907 908 void 909 domain_print(netdissect_options *ndo, 910 const u_char *bp, u_int length, int over_tcp, int is_mdns) 911 { 912 const dns_header_t *np; 913 uint16_t flags, rcode, rdlen, type; 914 u_int qdcount, ancount, nscount, arcount; 915 u_int i; 916 const u_char *cp; 917 uint16_t b2; 918 919 ndo->ndo_protocol = "domain"; 920 921 if (over_tcp) { 922 /* 923 * The message is prefixed with a two byte length field 924 * which gives the message length, excluding the two byte 925 * length field. (RFC 1035 - 4.2.2. TCP usage) 926 */ 927 if (length < 2) { 928 ND_PRINT(" [DNS over TCP: length %u < 2]", length); 929 nd_print_invalid(ndo); 930 return; 931 } else { 932 length -= 2; /* excluding the two byte length field */ 933 if (GET_BE_U_2(bp) != length) { 934 ND_PRINT(" [prefix length(%u) != length(%u)]", 935 GET_BE_U_2(bp), length); 936 nd_print_invalid(ndo); 937 return; 938 } else { 939 bp += 2; 940 /* in over TCP case, we need to prepend a space 941 * (not needed in over UDP case) 942 */ 943 ND_PRINT(" "); 944 } 945 } 946 } 947 948 np = (const dns_header_t *)bp; 949 950 if(length < sizeof(*np)) { 951 nd_print_protocol(ndo); 952 ND_PRINT(" [length %u < %zu]", length, sizeof(*np)); 953 nd_print_invalid(ndo); 954 return; 955 } 956 957 ND_TCHECK_SIZE(np); 958 flags = GET_BE_U_2(np->flags); 959 /* get the byte-order right */ 960 qdcount = GET_BE_U_2(np->qdcount); 961 ancount = GET_BE_U_2(np->ancount); 962 nscount = GET_BE_U_2(np->nscount); 963 arcount = GET_BE_U_2(np->arcount); 964 965 /* find the opt record to extract extended rcode */ 966 cp = (const u_char *)(np + 1); 967 rcode = DNS_RCODE(flags); 968 for (i = 0; i < qdcount; i++) { 969 if ((cp = ns_nskip(ndo, cp)) == NULL) 970 goto print; 971 cp += 4; /* skip QTYPE and QCLASS */ 972 if (cp >= ndo->ndo_snapend) 973 goto print; 974 } 975 for (i = 0; i < ancount + nscount; i++) { 976 if ((cp = ns_nskip(ndo, cp)) == NULL) 977 goto print; 978 cp += 8; /* skip TYPE, CLASS and TTL */ 979 if (cp + 2 > ndo->ndo_snapend) 980 goto print; 981 rdlen = GET_BE_U_2(cp); 982 cp += 2 + rdlen; 983 if (cp >= ndo->ndo_snapend) 984 goto print; 985 } 986 for (i = 0; i < arcount; i++) { 987 if ((cp = ns_nskip(ndo, cp)) == NULL) 988 goto print; 989 if (cp + 2 > ndo->ndo_snapend) 990 goto print; 991 type = GET_BE_U_2(cp); 992 cp += 4; /* skip TYPE and CLASS */ 993 if (cp + 1 > ndo->ndo_snapend) 994 goto print; 995 if (type == T_OPT) { 996 rcode |= (GET_U_1(cp) << 4); 997 goto print; 998 } 999 cp += 4; 1000 if (cp + 2 > ndo->ndo_snapend) 1001 goto print; 1002 rdlen = GET_BE_U_2(cp); 1003 cp += 2 + rdlen; 1004 if (cp >= ndo->ndo_snapend) 1005 goto print; 1006 } 1007 1008 print: 1009 if (DNS_QR(flags)) { 1010 /* this is a response */ 1011 ND_PRINT("%u%s%s%s%s%s%s", 1012 GET_BE_U_2(np->id), 1013 ns_ops[DNS_OPCODE(flags)], 1014 ns_rcode(rcode), 1015 DNS_AA(flags)? "*" : "", 1016 DNS_RA(flags)? "" : "-", 1017 DNS_TC(flags)? "|" : "", 1018 DNS_AD(flags)? "$" : ""); 1019 1020 if (qdcount != 1) 1021 ND_PRINT(" [%uq]", qdcount); 1022 /* Print QUESTION section on -vv */ 1023 cp = (const u_char *)(np + 1); 1024 for (i = 0; i < qdcount; i++) { 1025 if (i != 0) 1026 ND_PRINT(","); 1027 if (ndo->ndo_vflag > 1) { 1028 ND_PRINT(" q:"); 1029 if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL) 1030 goto trunc; 1031 } else { 1032 if ((cp = ns_nskip(ndo, cp)) == NULL) 1033 goto trunc; 1034 cp += 4; /* skip QTYPE and QCLASS */ 1035 } 1036 } 1037 ND_PRINT(" %u/%u/%u", ancount, nscount, arcount); 1038 if (ancount) { 1039 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1040 goto trunc; 1041 ancount--; 1042 while (cp < ndo->ndo_snapend && ancount) { 1043 ND_PRINT(","); 1044 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1045 goto trunc; 1046 ancount--; 1047 } 1048 } 1049 if (ancount) 1050 goto trunc; 1051 /* Print NS and AR sections on -vv */ 1052 if (ndo->ndo_vflag > 1) { 1053 if (cp < ndo->ndo_snapend && nscount) { 1054 ND_PRINT(" ns:"); 1055 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1056 goto trunc; 1057 nscount--; 1058 while (cp < ndo->ndo_snapend && nscount) { 1059 ND_PRINT(","); 1060 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1061 goto trunc; 1062 nscount--; 1063 } 1064 } 1065 if (nscount) 1066 goto trunc; 1067 if (cp < ndo->ndo_snapend && arcount) { 1068 ND_PRINT(" ar:"); 1069 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1070 goto trunc; 1071 arcount--; 1072 while (cp < ndo->ndo_snapend && arcount) { 1073 ND_PRINT(","); 1074 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1075 goto trunc; 1076 arcount--; 1077 } 1078 } 1079 if (arcount) 1080 goto trunc; 1081 } 1082 } else { 1083 /* this is a request */ 1084 ND_PRINT("%u%s%s%s", GET_BE_U_2(np->id), 1085 ns_ops[DNS_OPCODE(flags)], 1086 DNS_RD(flags) ? "+" : "", 1087 DNS_CD(flags) ? "%" : ""); 1088 1089 /* any weirdness? */ 1090 b2 = GET_BE_U_2(((const u_short *)np) + 1); 1091 if (b2 & 0x6cf) 1092 ND_PRINT(" [b2&3=0x%x]", b2); 1093 1094 if (DNS_OPCODE(flags) == IQUERY) { 1095 if (qdcount) 1096 ND_PRINT(" [%uq]", qdcount); 1097 if (ancount != 1) 1098 ND_PRINT(" [%ua]", ancount); 1099 } else { 1100 if (ancount) 1101 ND_PRINT(" [%ua]", ancount); 1102 if (qdcount != 1) 1103 ND_PRINT(" [%uq]", qdcount); 1104 } 1105 if (nscount) 1106 ND_PRINT(" [%un]", nscount); 1107 if (arcount) 1108 ND_PRINT(" [%uau]", arcount); 1109 1110 cp = (const u_char *)(np + 1); 1111 if (qdcount) { 1112 cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns); 1113 if (!cp) 1114 goto trunc; 1115 qdcount--; 1116 while (cp < ndo->ndo_snapend && qdcount) { 1117 cp = ns_qprint(ndo, (const u_char *)cp, 1118 (const u_char *)np, 1119 is_mdns); 1120 if (!cp) 1121 goto trunc; 1122 qdcount--; 1123 } 1124 } 1125 if (qdcount) 1126 goto trunc; 1127 1128 /* Print remaining sections on -vv */ 1129 if (ndo->ndo_vflag > 1) { 1130 if (ancount) { 1131 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1132 goto trunc; 1133 ancount--; 1134 while (cp < ndo->ndo_snapend && ancount) { 1135 ND_PRINT(","); 1136 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1137 goto trunc; 1138 ancount--; 1139 } 1140 } 1141 if (ancount) 1142 goto trunc; 1143 if (cp < ndo->ndo_snapend && nscount) { 1144 ND_PRINT(" ns:"); 1145 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1146 goto trunc; 1147 nscount--; 1148 while (cp < ndo->ndo_snapend && nscount) { 1149 ND_PRINT(","); 1150 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1151 goto trunc; 1152 nscount--; 1153 } 1154 } 1155 if (nscount > 0) 1156 goto trunc; 1157 if (cp < ndo->ndo_snapend && arcount) { 1158 ND_PRINT(" ar:"); 1159 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1160 goto trunc; 1161 arcount--; 1162 while (cp < ndo->ndo_snapend && arcount) { 1163 ND_PRINT(","); 1164 if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 1165 goto trunc; 1166 arcount--; 1167 } 1168 } 1169 if (arcount) 1170 goto trunc; 1171 } 1172 } 1173 ND_PRINT(" (%u)", length); 1174 return; 1175 1176 trunc: 1177 nd_print_trunc(ndo); 1178 } 1179