10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos */ 210f74e101Schristos 2211b3aaa1Schristos #include <sys/cdefs.h> 230f74e101Schristos #ifndef lint 24*26ba0b50Schristos __RCSID("$NetBSD: print-domain.c,v 1.11 2024/09/02 16:15:31 christos Exp $"); 250f74e101Schristos #endif 260f74e101Schristos 27dc860a36Sspz /* \summary: Domain Name System (DNS) printer */ 28dc860a36Sspz 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 330f74e101Schristos #include <string.h> 340f74e101Schristos 35fdccd7e4Schristos #include "netdissect.h" 360f74e101Schristos #include "addrtoname.h" 37fdccd7e4Schristos #include "addrtostr.h" 38fdccd7e4Schristos #include "extract.h" 390f74e101Schristos 40c74ad251Schristos #include "nameser.h" 41c74ad251Schristos 420f74e101Schristos static const char *ns_ops[] = { 430f74e101Schristos "", " inv_q", " stat", " op3", " notify", " update", " op6", " op7", 44b3a00663Schristos " op8", " updateA", " updateD", " updateDA", 450f74e101Schristos " updateM", " updateMA", " zoneInit", " zoneRef", 460f74e101Schristos }; 470f74e101Schristos 480f74e101Schristos static const char *ns_resp[] = { 490f74e101Schristos "", " FormErr", " ServFail", " NXDomain", 500f74e101Schristos " NotImp", " Refused", " YXDomain", " YXRRSet", 510f74e101Schristos " NXRRSet", " NotAuth", " NotZone", " Resp11", 520f74e101Schristos " Resp12", " Resp13", " Resp14", " NoChange", 53c74ad251Schristos " BadVers", "Resp17", " Resp18", " Resp19", 54c74ad251Schristos " Resp20", "Resp21", " Resp22", " BadCookie", 550f74e101Schristos }; 560f74e101Schristos 57c74ad251Schristos static const char * 58c74ad251Schristos ns_rcode(u_int rcode) { 59c74ad251Schristos static char buf[sizeof(" Resp4095")]; 60c74ad251Schristos 61c74ad251Schristos if (rcode < sizeof(ns_resp)/sizeof(ns_resp[0])) { 62c74ad251Schristos return (ns_resp[rcode]); 63c74ad251Schristos } 64c74ad251Schristos snprintf(buf, sizeof(buf), " Resp%u", rcode & 0xfff); 65c74ad251Schristos return (buf); 66c74ad251Schristos } 67c74ad251Schristos 680f74e101Schristos /* skip over a domain name */ 690f74e101Schristos static const u_char * 70b3a00663Schristos ns_nskip(netdissect_options *ndo, 71c74ad251Schristos const u_char *cp) 720f74e101Schristos { 73c74ad251Schristos u_char i; 740f74e101Schristos 75c74ad251Schristos if (!ND_TTEST_1(cp)) 760f74e101Schristos return (NULL); 77c74ad251Schristos i = GET_U_1(cp); 78c74ad251Schristos cp++; 790f74e101Schristos while (i) { 80c74ad251Schristos switch (i & TYPE_MASK) { 81c74ad251Schristos 82c74ad251Schristos case TYPE_INDIR: 830f74e101Schristos return (cp + 1); 84c74ad251Schristos 85c74ad251Schristos case TYPE_EDNS0: { 860f74e101Schristos int bitlen, bytelen; 870f74e101Schristos 88c74ad251Schristos if ((i & ~TYPE_MASK) != EDNS0_ELT_BITLABEL) 890f74e101Schristos return(NULL); /* unknown ELT */ 90c74ad251Schristos if (!ND_TTEST_1(cp)) 910f74e101Schristos return (NULL); 92c74ad251Schristos if ((bitlen = GET_U_1(cp)) == 0) 930f74e101Schristos bitlen = 256; 94c74ad251Schristos cp++; 950f74e101Schristos bytelen = (bitlen + 7) / 8; 960f74e101Schristos cp += bytelen; 97c74ad251Schristos } 98c74ad251Schristos break; 99c74ad251Schristos 100c74ad251Schristos case TYPE_RESERVED: 1010f74e101Schristos return (NULL); 102c74ad251Schristos 103c74ad251Schristos case TYPE_LABEL: 104c74ad251Schristos cp += i; 105c74ad251Schristos break; 106c74ad251Schristos } 107c74ad251Schristos if (!ND_TTEST_1(cp)) 108c74ad251Schristos return (NULL); 109c74ad251Schristos i = GET_U_1(cp); 110c74ad251Schristos cp++; 1110f74e101Schristos } 1120f74e101Schristos return (cp); 1130f74e101Schristos } 1140f74e101Schristos 1150f74e101Schristos static const u_char * 116b3a00663Schristos blabel_print(netdissect_options *ndo, 117b3a00663Schristos const u_char *cp) 1180f74e101Schristos { 119c74ad251Schristos u_int bitlen, slen, b; 1200f74e101Schristos const u_char *bitp, *lim; 121c74ad251Schristos uint8_t tc; 1220f74e101Schristos 123c74ad251Schristos if (!ND_TTEST_1(cp)) 1240f74e101Schristos return(NULL); 125c74ad251Schristos if ((bitlen = GET_U_1(cp)) == 0) 1260f74e101Schristos bitlen = 256; 1270f74e101Schristos slen = (bitlen + 3) / 4; 1280f74e101Schristos lim = cp + 1 + slen; 1290f74e101Schristos 1300f74e101Schristos /* print the bit string as a hex string */ 131c74ad251Schristos ND_PRINT("\\[x"); 1320f74e101Schristos for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) { 133c74ad251Schristos ND_PRINT("%02x", GET_U_1(bitp)); 1340f74e101Schristos } 1350f74e101Schristos if (b > 4) { 136c74ad251Schristos tc = GET_U_1(bitp); 137c74ad251Schristos bitp++; 138c74ad251Schristos ND_PRINT("%02x", tc & (0xff << (8 - b))); 1390f74e101Schristos } else if (b > 0) { 140c74ad251Schristos tc = GET_U_1(bitp); 141c74ad251Schristos bitp++; 142c74ad251Schristos ND_PRINT("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))); 1430f74e101Schristos } 144c74ad251Schristos ND_PRINT("/%u]", bitlen); 1450f74e101Schristos return lim; 1460f74e101Schristos } 1470f74e101Schristos 1480f74e101Schristos static int 149b3a00663Schristos labellen(netdissect_options *ndo, 150b3a00663Schristos const u_char *cp) 1510f74e101Schristos { 152c74ad251Schristos u_int i; 1530f74e101Schristos 154c74ad251Schristos if (!ND_TTEST_1(cp)) 1550f74e101Schristos return(-1); 156c74ad251Schristos i = GET_U_1(cp); 157c74ad251Schristos switch (i & TYPE_MASK) { 158c74ad251Schristos 159c74ad251Schristos case TYPE_EDNS0: { 160c74ad251Schristos u_int bitlen, elt; 161c74ad251Schristos if ((elt = (i & ~TYPE_MASK)) != EDNS0_ELT_BITLABEL) { 162c74ad251Schristos ND_PRINT("<ELT %d>", elt); 1630f74e101Schristos return(-1); 1640f74e101Schristos } 165c74ad251Schristos if (!ND_TTEST_1(cp + 1)) 1660f74e101Schristos return(-1); 167c74ad251Schristos if ((bitlen = GET_U_1(cp + 1)) == 0) 1680f74e101Schristos bitlen = 256; 1690f74e101Schristos return(((bitlen + 7) / 8) + 1); 1700f74e101Schristos } 1710f74e101Schristos 172c74ad251Schristos case TYPE_INDIR: 173c74ad251Schristos case TYPE_LABEL: 174c74ad251Schristos return(i); 175c74ad251Schristos 176c74ad251Schristos default: 177c74ad251Schristos /* 178c74ad251Schristos * TYPE_RESERVED, but we use default to suppress compiler 179c74ad251Schristos * warnings about falling out of the switch statement. 180c74ad251Schristos */ 181c74ad251Schristos ND_PRINT("<BAD LABEL TYPE>"); 182c74ad251Schristos return(-1); 183c74ad251Schristos } 184c74ad251Schristos } 185c74ad251Schristos 186c74ad251Schristos /* print a <domain-name> */ 187870189d2Schristos const u_char * 188c74ad251Schristos fqdn_print(netdissect_options *ndo, 189c74ad251Schristos const u_char *cp, const u_char *bp) 1900f74e101Schristos { 191c74ad251Schristos u_int i, l; 192c74ad251Schristos const u_char *rp = NULL; 193c74ad251Schristos int compress = 0; 194c74ad251Schristos u_int elt; 19572c96ff3Schristos u_int offset, max_offset; 196c74ad251Schristos u_int name_chars = 0; 1970f74e101Schristos 198b3a00663Schristos if ((l = labellen(ndo, cp)) == (u_int)-1) 1990f74e101Schristos return(NULL); 200c74ad251Schristos if (!ND_TTEST_1(cp)) 2010f74e101Schristos return(NULL); 20272c96ff3Schristos max_offset = (u_int)(cp - bp); 203c74ad251Schristos i = GET_U_1(cp); 204c74ad251Schristos cp++; 205c74ad251Schristos if ((i & TYPE_MASK) != TYPE_INDIR) { 2060f74e101Schristos compress = 0; 2070f74e101Schristos rp = cp + l; 2080f74e101Schristos } 2090f74e101Schristos 210c74ad251Schristos if (i != 0) { 211b3a00663Schristos while (i && cp < ndo->ndo_snapend) { 212c74ad251Schristos switch (i & TYPE_MASK) { 213c74ad251Schristos 214c74ad251Schristos case TYPE_INDIR: 2150f74e101Schristos if (!compress) { 2160f74e101Schristos rp = cp + 1; 2170f74e101Schristos compress = 1; 2180f74e101Schristos } 219c74ad251Schristos if (!ND_TTEST_1(cp)) 2200f74e101Schristos return(NULL); 221c74ad251Schristos offset = (((i << 8) | GET_U_1(cp)) & 0x3fff); 22272c96ff3Schristos /* 22372c96ff3Schristos * This must move backwards in the packet. 22472c96ff3Schristos * No RFC explicitly says that, but BIND's 22572c96ff3Schristos * name decompression code requires it, 22672c96ff3Schristos * as a way of preventing infinite loops 22772c96ff3Schristos * and other bad behavior, and it's probably 22872c96ff3Schristos * what was intended (compress by pointing 22972c96ff3Schristos * to domain name suffixes already seen in 23072c96ff3Schristos * the packet). 23172c96ff3Schristos */ 23272c96ff3Schristos if (offset >= max_offset) { 233c74ad251Schristos ND_PRINT("<BAD PTR>"); 23472c96ff3Schristos return(NULL); 23572c96ff3Schristos } 23672c96ff3Schristos max_offset = offset; 23772c96ff3Schristos cp = bp + offset; 238c74ad251Schristos if (!ND_TTEST_1(cp)) 239c74ad251Schristos return(NULL); 240c74ad251Schristos i = GET_U_1(cp); 241b3a00663Schristos if ((l = labellen(ndo, cp)) == (u_int)-1) 2420f74e101Schristos return(NULL); 243c74ad251Schristos cp++; 2440f74e101Schristos continue; 245c74ad251Schristos 246c74ad251Schristos case TYPE_EDNS0: 247c74ad251Schristos elt = (i & ~TYPE_MASK); 2480f74e101Schristos switch(elt) { 2490f74e101Schristos case EDNS0_ELT_BITLABEL: 250b3a00663Schristos if (blabel_print(ndo, cp) == NULL) 2510f74e101Schristos return (NULL); 2520f74e101Schristos break; 2530f74e101Schristos default: 2540f74e101Schristos /* unknown ELT */ 255c74ad251Schristos ND_PRINT("<ELT %u>", elt); 2560f74e101Schristos return(NULL); 2570f74e101Schristos } 258c74ad251Schristos break; 259c74ad251Schristos 260c74ad251Schristos case TYPE_RESERVED: 261c74ad251Schristos ND_PRINT("<BAD LABEL TYPE>"); 2620f74e101Schristos return(NULL); 263c74ad251Schristos 264c74ad251Schristos case TYPE_LABEL: 265c74ad251Schristos if (name_chars + l <= MAXCDNAME) { 266c74ad251Schristos if (nd_printn(ndo, cp, l, ndo->ndo_snapend)) 267c74ad251Schristos return(NULL); 268c74ad251Schristos } else if (name_chars < MAXCDNAME) { 269c74ad251Schristos if (nd_printn(ndo, cp, 270c74ad251Schristos MAXCDNAME - name_chars, ndo->ndo_snapend)) 271c74ad251Schristos return(NULL); 272c74ad251Schristos } 273c74ad251Schristos name_chars += l; 274c74ad251Schristos break; 2750f74e101Schristos } 2760f74e101Schristos 2770f74e101Schristos cp += l; 278c74ad251Schristos if (name_chars <= MAXCDNAME) 279c74ad251Schristos ND_PRINT("."); 280c74ad251Schristos name_chars++; 281c74ad251Schristos if (!ND_TTEST_1(cp)) 282c74ad251Schristos return(NULL); 283c74ad251Schristos i = GET_U_1(cp); 284b3a00663Schristos if ((l = labellen(ndo, cp)) == (u_int)-1) 2850f74e101Schristos return(NULL); 286c74ad251Schristos cp++; 2870f74e101Schristos if (!compress) 2880f74e101Schristos rp += l + 1; 2890f74e101Schristos } 290c74ad251Schristos if (name_chars > MAXCDNAME) 291c74ad251Schristos ND_PRINT("<DOMAIN NAME TOO LONG>"); 292c74ad251Schristos } else 293c74ad251Schristos ND_PRINT("."); 2940f74e101Schristos return (rp); 2950f74e101Schristos } 2960f74e101Schristos 2970f74e101Schristos /* print a <character-string> */ 2980f74e101Schristos static const u_char * 299b3a00663Schristos ns_cprint(netdissect_options *ndo, 300c74ad251Schristos const u_char *cp) 3010f74e101Schristos { 302c74ad251Schristos u_int i; 3030f74e101Schristos 304c74ad251Schristos if (!ND_TTEST_1(cp)) 3050f74e101Schristos return (NULL); 306c74ad251Schristos i = GET_U_1(cp); 307c74ad251Schristos cp++; 308c74ad251Schristos if (nd_printn(ndo, cp, i, ndo->ndo_snapend)) 3090f74e101Schristos return (NULL); 3100f74e101Schristos return (cp + i); 3110f74e101Schristos } 3120f74e101Schristos 313c74ad251Schristos static void 314c74ad251Schristos print_eopt_ecs(netdissect_options *ndo, const u_char *cp, 315c74ad251Schristos u_int data_len) 316c74ad251Schristos { 317c74ad251Schristos u_int family, addr_bits, src_len, scope_len; 318c74ad251Schristos 319c74ad251Schristos u_char padded[32]; 320c74ad251Schristos char addr[INET6_ADDRSTRLEN]; 321c74ad251Schristos 322c74ad251Schristos /* ecs option must at least contain family, src len, and scope len */ 323c74ad251Schristos if (data_len < 4) { 324c74ad251Schristos nd_print_invalid(ndo); 325c74ad251Schristos return; 326c74ad251Schristos } 327c74ad251Schristos 328c74ad251Schristos family = GET_BE_U_2(cp); 329c74ad251Schristos cp += 2; 330c74ad251Schristos src_len = GET_U_1(cp); 331c74ad251Schristos cp += 1; 332c74ad251Schristos scope_len = GET_U_1(cp); 333c74ad251Schristos cp += 1; 334c74ad251Schristos 335c74ad251Schristos if (family == 1) 336c74ad251Schristos addr_bits = 32; 337c74ad251Schristos else if (family == 2) 338c74ad251Schristos addr_bits = 128; 339c74ad251Schristos else { 340c74ad251Schristos nd_print_invalid(ndo); 341c74ad251Schristos return; 342c74ad251Schristos } 343c74ad251Schristos 344c74ad251Schristos if (data_len - 4 > (addr_bits / 8)) { 345c74ad251Schristos nd_print_invalid(ndo); 346c74ad251Schristos return; 347c74ad251Schristos } 348c74ad251Schristos /* checks for invalid ecs scope or source length */ 349c74ad251Schristos if (src_len > addr_bits || scope_len > addr_bits || ((src_len + 7) / 8) != (data_len - 4)) { 350c74ad251Schristos nd_print_invalid(ndo); 351c74ad251Schristos return; 352c74ad251Schristos } 353c74ad251Schristos 354c74ad251Schristos /* pad the truncated address from ecs with zeros */ 355c74ad251Schristos memset(padded, 0, sizeof(padded)); 356c74ad251Schristos memcpy(padded, cp, data_len - 4); 357c74ad251Schristos 358c74ad251Schristos 359c74ad251Schristos if (family == 1) 360c74ad251Schristos ND_PRINT("%s/%d/%d", addrtostr(padded, addr, INET_ADDRSTRLEN), 361c74ad251Schristos src_len, scope_len); 362c74ad251Schristos else 363c74ad251Schristos ND_PRINT("%s/%d/%d", addrtostr6(padded, addr, INET6_ADDRSTRLEN), 364c74ad251Schristos src_len, scope_len); 365c74ad251Schristos 366c74ad251Schristos } 367c74ad251Schristos 368c74ad251Schristos extern const struct tok edns_opt2str[]; 369c74ad251Schristos extern const struct tok dau_alg2str[]; 370c74ad251Schristos extern const struct tok dhu_alg2str[]; 371c74ad251Schristos extern const struct tok n3u_alg2str[]; 372c74ad251Schristos 373c74ad251Schristos 374c74ad251Schristos /* print an <EDNS-option> */ 375c74ad251Schristos static const u_char * 376c74ad251Schristos eopt_print(netdissect_options *ndo, 377c74ad251Schristos const u_char *cp) 378c74ad251Schristos { 379c74ad251Schristos u_int opt, data_len, i; 380c74ad251Schristos 381c74ad251Schristos if (!ND_TTEST_2(cp)) 382c74ad251Schristos return (NULL); 383c74ad251Schristos opt = GET_BE_U_2(cp); 384c74ad251Schristos cp += 2; 385c74ad251Schristos ND_PRINT("%s", tok2str(edns_opt2str, "Opt%u", opt)); 386c74ad251Schristos if (!ND_TTEST_2(cp)) 387c74ad251Schristos return (NULL); 388c74ad251Schristos data_len = GET_BE_U_2(cp); 389c74ad251Schristos cp += 2; 390c74ad251Schristos 391c74ad251Schristos ND_TCHECK_LEN(cp, data_len); 392c74ad251Schristos 393c74ad251Schristos if (data_len > 0) { 394c74ad251Schristos ND_PRINT(" "); 395c74ad251Schristos switch (opt) { 396c74ad251Schristos 397c74ad251Schristos case E_ECS: 398c74ad251Schristos print_eopt_ecs(ndo, cp, data_len); 399c74ad251Schristos break; 400c74ad251Schristos case E_COOKIE: 401c74ad251Schristos if (data_len < 8 || (data_len > 8 && data_len < 16) || data_len > 40) 402c74ad251Schristos nd_print_invalid(ndo); 403c74ad251Schristos else { 404c74ad251Schristos for (i = 0; i < data_len; ++i) { 405c74ad251Schristos /* split client and server cookie */ 406c74ad251Schristos if (i == 8) 407c74ad251Schristos ND_PRINT(" "); 408c74ad251Schristos ND_PRINT("%02x", GET_U_1(cp + i)); 409c74ad251Schristos } 410c74ad251Schristos } 411c74ad251Schristos break; 412c74ad251Schristos case E_KEEPALIVE: 413c74ad251Schristos if (data_len != 2) 414c74ad251Schristos nd_print_invalid(ndo); 415c74ad251Schristos else 416c74ad251Schristos /* keepalive is in increments of 100ms. Convert to seconds */ 417c74ad251Schristos ND_PRINT("%0.1f sec", (GET_BE_U_2(cp) / 10.0)); 418c74ad251Schristos break; 419c74ad251Schristos case E_EXPIRE: 420c74ad251Schristos if (data_len != 4) 421c74ad251Schristos nd_print_invalid(ndo); 422c74ad251Schristos else 423c74ad251Schristos ND_PRINT("%u sec", GET_BE_U_4(cp)); 424c74ad251Schristos break; 425c74ad251Schristos case E_PADDING: 426c74ad251Schristos /* ignore contents and just print length */ 427c74ad251Schristos ND_PRINT("(%u)", data_len); 428c74ad251Schristos break; 429c74ad251Schristos case E_KEYTAG: 430c74ad251Schristos if (data_len % 2 != 0) 431c74ad251Schristos nd_print_invalid(ndo); 432c74ad251Schristos else 433c74ad251Schristos for (i = 0; i < data_len; i += 2) { 434c74ad251Schristos if (i > 0) 435c74ad251Schristos ND_PRINT(" "); 436c74ad251Schristos ND_PRINT("%u", GET_BE_U_2(cp + i)); 437c74ad251Schristos } 438c74ad251Schristos break; 439c74ad251Schristos case E_DAU: 440c74ad251Schristos for (i = 0; i < data_len; ++i) { 441c74ad251Schristos if (i > 0) 442c74ad251Schristos ND_PRINT(" "); 443c74ad251Schristos ND_PRINT("%s", tok2str(dau_alg2str, "Alg_%u", GET_U_1(cp + i))); 444c74ad251Schristos } 445c74ad251Schristos break; 446c74ad251Schristos case E_DHU: 447c74ad251Schristos for (i = 0; i < data_len; ++i) { 448c74ad251Schristos if (i > 0) 449c74ad251Schristos ND_PRINT(" "); 450c74ad251Schristos ND_PRINT("%s", tok2str(dhu_alg2str, "Alg_%u", GET_U_1(cp + i))); 451c74ad251Schristos } 452c74ad251Schristos break; 453c74ad251Schristos case E_N3U: 454c74ad251Schristos for (i = 0; i < data_len; ++i) { 455c74ad251Schristos if (i > 0) 456c74ad251Schristos ND_PRINT(" "); 457c74ad251Schristos ND_PRINT("%s", tok2str(n3u_alg2str, "Alg_%u", GET_U_1(cp + i))); 458c74ad251Schristos } 459c74ad251Schristos break; 460c74ad251Schristos case E_CHAIN: 461c74ad251Schristos fqdn_print(ndo, cp, cp + data_len); 462c74ad251Schristos break; 463c74ad251Schristos case E_NSID: 464c74ad251Schristos /* intentional fall-through. NSID is an undefined byte string */ 465c74ad251Schristos default: 466c74ad251Schristos for (i = 0; i < data_len; ++i) 467c74ad251Schristos ND_PRINT("%02x", GET_U_1(cp + i)); 468c74ad251Schristos break; 469c74ad251Schristos } 470c74ad251Schristos } 471c74ad251Schristos return (cp + data_len); 472c74ad251Schristos 473c74ad251Schristos trunc: 474c74ad251Schristos return (NULL); 475c74ad251Schristos 476c74ad251Schristos } 477c74ad251Schristos 478c74ad251Schristos 479c74ad251Schristos 480c74ad251Schristos extern const struct tok ns_type2str[]; 481c74ad251Schristos 482c74ad251Schristos /* https://www.iana.org/assignments/dns-parameters */ 483870189d2Schristos const struct tok ns_type2str[] = { 4840f74e101Schristos { T_A, "A" }, /* RFC 1035 */ 4850f74e101Schristos { T_NS, "NS" }, /* RFC 1035 */ 4860f74e101Schristos { T_MD, "MD" }, /* RFC 1035 */ 4870f74e101Schristos { T_MF, "MF" }, /* RFC 1035 */ 4880f74e101Schristos { T_CNAME, "CNAME" }, /* RFC 1035 */ 4890f74e101Schristos { T_SOA, "SOA" }, /* RFC 1035 */ 4900f74e101Schristos { T_MB, "MB" }, /* RFC 1035 */ 4910f74e101Schristos { T_MG, "MG" }, /* RFC 1035 */ 4920f74e101Schristos { T_MR, "MR" }, /* RFC 1035 */ 4930f74e101Schristos { T_NULL, "NULL" }, /* RFC 1035 */ 4940f74e101Schristos { T_WKS, "WKS" }, /* RFC 1035 */ 4950f74e101Schristos { T_PTR, "PTR" }, /* RFC 1035 */ 4960f74e101Schristos { T_HINFO, "HINFO" }, /* RFC 1035 */ 4970f74e101Schristos { T_MINFO, "MINFO" }, /* RFC 1035 */ 4980f74e101Schristos { T_MX, "MX" }, /* RFC 1035 */ 4990f74e101Schristos { T_TXT, "TXT" }, /* RFC 1035 */ 5000f74e101Schristos { T_RP, "RP" }, /* RFC 1183 */ 501c74ad251Schristos { T_AFSDB, "AFSDB" }, /* RFC 5864 */ 5020f74e101Schristos { T_X25, "X25" }, /* RFC 1183 */ 5030f74e101Schristos { T_ISDN, "ISDN" }, /* RFC 1183 */ 5040f74e101Schristos { T_RT, "RT" }, /* RFC 1183 */ 5050f74e101Schristos { T_NSAP, "NSAP" }, /* RFC 1706 */ 506c74ad251Schristos { T_NSAP_PTR, "NSAP_PTR" }, /* RFC 1706 */ 507c74ad251Schristos { T_SIG, "SIG" }, /* RFC 3008 */ 508c74ad251Schristos { T_KEY, "KEY" }, /* RFC 3110 */ 5090f74e101Schristos { T_PX, "PX" }, /* RFC 2163 */ 5100f74e101Schristos { T_GPOS, "GPOS" }, /* RFC 1712 */ 511c74ad251Schristos { T_AAAA, "AAAA" }, /* RFC 3596 */ 5120f74e101Schristos { T_LOC, "LOC" }, /* RFC 1876 */ 513c74ad251Schristos { T_NXT, "NXT" }, /* RFC 3755 */ 5140f74e101Schristos { T_EID, "EID" }, /* Nimrod */ 5150f74e101Schristos { T_NIMLOC, "NIMLOC" }, /* Nimrod */ 5160f74e101Schristos { T_SRV, "SRV" }, /* RFC 2782 */ 5170f74e101Schristos { T_ATMA, "ATMA" }, /* ATM Forum */ 518c74ad251Schristos { T_NAPTR, "NAPTR" }, /* RFC 3403 */ 5190f74e101Schristos { T_KX, "KX" }, /* RFC 2230 */ 520c74ad251Schristos { T_CERT, "CERT" }, /* RFC 4398 */ 521c74ad251Schristos { T_A6, "A6" }, /* RFC 6563 */ 522c74ad251Schristos { T_DNAME, "DNAME" }, /* RFC 6672 */ 5230f74e101Schristos { T_SINK, "SINK" }, 524c74ad251Schristos { T_OPT, "OPT" }, /* RFC 6891 */ 5250f74e101Schristos { T_APL, "APL" }, /* RFC 3123 */ 5260f74e101Schristos { T_DS, "DS" }, /* RFC 4034 */ 5270f74e101Schristos { T_SSHFP, "SSHFP" }, /* RFC 4255 */ 5280f74e101Schristos { T_IPSECKEY, "IPSECKEY" }, /* RFC 4025 */ 5290f74e101Schristos { T_RRSIG, "RRSIG" }, /* RFC 4034 */ 5300f74e101Schristos { T_NSEC, "NSEC" }, /* RFC 4034 */ 5310f74e101Schristos { T_DNSKEY, "DNSKEY" }, /* RFC 4034 */ 532c74ad251Schristos { T_DHCID, "DHCID" }, /* RFC 4071 */ 533c74ad251Schristos { T_NSEC3, "NSEC3" }, /* RFC 5155 */ 534c74ad251Schristos { T_NSEC3PARAM, "NSEC3PARAM" }, /* RFC 5155 */ 535c74ad251Schristos { T_TLSA, "TLSA" }, /* RFC 6698 */ 536c74ad251Schristos { T_SMIMEA, "SMIMEA" }, /* RFC 8162 */ 537c74ad251Schristos { T_HIP, "HIP" }, /* RFC 8005 */ 538c74ad251Schristos { T_NINFO, "NINFO" }, 539c74ad251Schristos { T_RKEY, "RKEY" }, 540c74ad251Schristos { T_TALINK, "TALINK" }, 541c74ad251Schristos { T_CDS, "CDS" }, /* RFC 7344 */ 542c74ad251Schristos { T_CDNSKEY, "CDNSKEY" }, /* RFC 7344 */ 543c74ad251Schristos { T_OPENPGPKEY, "OPENPGPKEY" }, /* RFC 7929 */ 544c74ad251Schristos { T_CSYNC, "CSYNC" }, /* RFC 7477 */ 545c74ad251Schristos { T_ZONEMD, "ZONEMD" }, /* RFC 8976 */ 546c74ad251Schristos { T_SVCB, "SVCB" }, 547c74ad251Schristos { T_HTTPS, "HTTPS" }, 548c74ad251Schristos { T_SPF, "SPF" }, /* RFC 7208 */ 5490f74e101Schristos { T_UINFO, "UINFO" }, 5500f74e101Schristos { T_UID, "UID" }, 5510f74e101Schristos { T_GID, "GID" }, 5520f74e101Schristos { T_UNSPEC, "UNSPEC" }, 553c74ad251Schristos { T_NID, "NID" }, /* RFC 6742 */ 554c74ad251Schristos { T_L32, "L32" }, /* RFC 6742 */ 555c74ad251Schristos { T_L64, "L64" }, /* RFC 6742 */ 556c74ad251Schristos { T_LP, "LP" }, /* RFC 6742 */ 557c74ad251Schristos { T_EUI48, "EUI48" }, /* RFC 7043 */ 558c74ad251Schristos { T_EUI64, "EUI64" }, /* RFC 7043 */ 5590f74e101Schristos { T_TKEY, "TKEY" }, /* RFC 2930 */ 560c74ad251Schristos { T_TSIG, "TSIG" }, /* RFC 8945 */ 5610f74e101Schristos { T_IXFR, "IXFR" }, /* RFC 1995 */ 562c74ad251Schristos { T_AXFR, "AXFR" }, /* RFC 5936 */ 5630f74e101Schristos { T_MAILB, "MAILB" }, /* RFC 1035 */ 5640f74e101Schristos { T_MAILA, "MAILA" }, /* RFC 1035 */ 565c74ad251Schristos { T_ANY, "ANY" }, /* RFC 8482 */ 566c74ad251Schristos { T_URI, "URI" }, /* RFC 7553 */ 567c74ad251Schristos { T_CAA, "CAA" }, /* RFC 8659 */ 568c74ad251Schristos { T_AVC, "AVC" }, 569c74ad251Schristos { T_DOA, "DOA" }, 570c74ad251Schristos { T_AMTRELAY, "AMTRELAY" }, /* RFC 8777 */ 571c74ad251Schristos { T_TA, "TA" }, 572c74ad251Schristos { T_DLV, "DLV" }, /* RFC 8749 */ 5730f74e101Schristos { 0, NULL } 5740f74e101Schristos }; 5750f74e101Schristos 576c74ad251Schristos extern const struct tok ns_class2str[]; 577c74ad251Schristos 578870189d2Schristos const struct tok ns_class2str[] = { 5790f74e101Schristos { C_IN, "IN" }, /* Not used */ 5800f74e101Schristos { C_CHAOS, "CHAOS" }, 5810f74e101Schristos { C_HS, "HS" }, 5820f74e101Schristos { C_ANY, "ANY" }, 5830f74e101Schristos { 0, NULL } 5840f74e101Schristos }; 5850f74e101Schristos 586c74ad251Schristos const struct tok edns_opt2str[] = { 587c74ad251Schristos { E_LLQ, "LLQ" }, 588c74ad251Schristos { E_UL, "UL" }, 589c74ad251Schristos { E_NSID, "NSID" }, 590c74ad251Schristos { E_DAU, "DAU" }, 591c74ad251Schristos { E_DHU, "DHU" }, 592c74ad251Schristos { E_N3U, "N3U" }, 593c74ad251Schristos { E_ECS, "ECS" }, 594c74ad251Schristos { E_EXPIRE, "EXPIRE" }, 595c74ad251Schristos { E_COOKIE, "COOKIE" }, 596c74ad251Schristos { E_KEEPALIVE, "KEEPALIVE" }, 597c74ad251Schristos { E_PADDING, "PADDING" }, 598c74ad251Schristos { E_CHAIN, "CHAIN" }, 599c74ad251Schristos { E_KEYTAG, "KEY-TAG" }, 600c74ad251Schristos { E_CLIENTTAG, "CLIENT-TAG" }, 601c74ad251Schristos { E_SERVERTAG, "SERVER-TAG" }, 602c74ad251Schristos { 0, NULL } 603c74ad251Schristos }; 604c74ad251Schristos 605c74ad251Schristos const struct tok dau_alg2str[] = { 606c74ad251Schristos { A_DELETE, "DELETE" }, 607c74ad251Schristos { A_RSAMD5, "RSAMD5" }, 608c74ad251Schristos { A_DH, "DH" }, 609c74ad251Schristos { A_DSA, "DS" }, 610c74ad251Schristos { A_RSASHA1, "RSASHA1" }, 611c74ad251Schristos { A_DSA_NSEC3_SHA1, "DSA-NSEC3-SHA1" }, 612c74ad251Schristos { A_RSASHA1_NSEC3_SHA1, "RSASHA1-NSEC3-SHA1" }, 613c74ad251Schristos { A_RSASHA256, "RSASHA256" }, 614c74ad251Schristos { A_RSASHA512, "RSASHA512" }, 615c74ad251Schristos { A_ECC_GOST, "ECC-GOST" }, 616c74ad251Schristos { A_ECDSAP256SHA256, "ECDSAP256SHA256" }, 617c74ad251Schristos { A_ECDSAP384SHA384, "ECDSAP384SHA384" }, 618c74ad251Schristos { A_ED25519, "ED25519" }, 619c74ad251Schristos { A_ED448, "ED448" }, 620c74ad251Schristos { A_INDIRECT, "INDIRECT" }, 621c74ad251Schristos { A_PRIVATEDNS, "PRIVATEDNS" }, 622c74ad251Schristos { A_PRIVATEOID, "PRIVATEOID" }, 623c74ad251Schristos { 0, NULL } 624c74ad251Schristos }; 625c74ad251Schristos 626c74ad251Schristos const struct tok dhu_alg2str[] = { 627c74ad251Schristos { DS_SHA1, "SHA-1" }, 628c74ad251Schristos { DS_SHA256,"SHA-256" }, 629c74ad251Schristos { DS_GOST, "GOST_R_34.11-94" }, 630c74ad251Schristos { DS_SHA384,"SHA-384" }, 631c74ad251Schristos { 0, NULL } 632c74ad251Schristos }; 633c74ad251Schristos 634c74ad251Schristos const struct tok n3u_alg2str[] = { 635c74ad251Schristos { NSEC_SHA1,"SHA-1" }, 636c74ad251Schristos { 0, NULL } 637c74ad251Schristos }; 638c74ad251Schristos 6390f74e101Schristos /* print a query */ 6400f74e101Schristos static const u_char * 641b3a00663Schristos ns_qprint(netdissect_options *ndo, 642c74ad251Schristos const u_char *cp, const u_char *bp, int is_mdns) 6430f74e101Schristos { 644c74ad251Schristos const u_char *np = cp; 645c74ad251Schristos u_int i, class; 6460f74e101Schristos 647b3a00663Schristos cp = ns_nskip(ndo, cp); 6480f74e101Schristos 649c74ad251Schristos if (cp == NULL || !ND_TTEST_4(cp)) 6500f74e101Schristos return(NULL); 6510f74e101Schristos 6520f74e101Schristos /* print the qtype */ 653c74ad251Schristos i = GET_BE_U_2(cp); 6540f74e101Schristos cp += 2; 655c74ad251Schristos ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", i)); 6560f74e101Schristos /* print the qclass (if it's not IN) */ 657c74ad251Schristos i = GET_BE_U_2(cp); 6580f74e101Schristos cp += 2; 6590f74e101Schristos if (is_mdns) 6600f74e101Schristos class = (i & ~C_QU); 6610f74e101Schristos else 6620f74e101Schristos class = i; 6630f74e101Schristos if (class != C_IN) 664c74ad251Schristos ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class)); 6650f74e101Schristos if (is_mdns) { 666c74ad251Schristos ND_PRINT(i & C_QU ? " (QU)" : " (QM)"); 6670f74e101Schristos } 6680f74e101Schristos 669c74ad251Schristos ND_PRINT("? "); 670c74ad251Schristos cp = fqdn_print(ndo, np, bp); 6710f74e101Schristos return(cp ? cp + 4 : NULL); 6720f74e101Schristos } 6730f74e101Schristos 6740f74e101Schristos /* print a reply */ 6750f74e101Schristos static const u_char * 676b3a00663Schristos ns_rprint(netdissect_options *ndo, 677c74ad251Schristos const u_char *cp, const u_char *bp, int is_mdns) 6780f74e101Schristos { 679c74ad251Schristos u_int i, class, opt_flags = 0; 680c74ad251Schristos u_short typ, len; 681c74ad251Schristos const u_char *rp; 6820f74e101Schristos 683b3a00663Schristos if (ndo->ndo_vflag) { 684c74ad251Schristos ND_PRINT(" "); 685c74ad251Schristos if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 6860f74e101Schristos return NULL; 6870f74e101Schristos } else 688b3a00663Schristos cp = ns_nskip(ndo, cp); 6890f74e101Schristos 690c74ad251Schristos if (cp == NULL || !ND_TTEST_LEN(cp, 10)) 691b3a00663Schristos return (ndo->ndo_snapend); 6920f74e101Schristos 6930f74e101Schristos /* print the type/qtype */ 694c74ad251Schristos typ = GET_BE_U_2(cp); 6950f74e101Schristos cp += 2; 6960f74e101Schristos /* print the class (if it's not IN and the type isn't OPT) */ 697c74ad251Schristos i = GET_BE_U_2(cp); 6980f74e101Schristos cp += 2; 6990f74e101Schristos if (is_mdns) 7000f74e101Schristos class = (i & ~C_CACHE_FLUSH); 7010f74e101Schristos else 7020f74e101Schristos class = i; 7030f74e101Schristos if (class != C_IN && typ != T_OPT) 704c74ad251Schristos ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class)); 7050f74e101Schristos if (is_mdns) { 7060f74e101Schristos if (i & C_CACHE_FLUSH) 707c74ad251Schristos ND_PRINT(" (Cache flush)"); 7080f74e101Schristos } 7090f74e101Schristos 7100f74e101Schristos if (typ == T_OPT) { 7110f74e101Schristos /* get opt flags */ 7120f74e101Schristos cp += 2; 713c74ad251Schristos opt_flags = GET_BE_U_2(cp); 7140f74e101Schristos /* ignore rest of ttl field */ 7150f74e101Schristos cp += 2; 716b3a00663Schristos } else if (ndo->ndo_vflag > 2) { 7170f74e101Schristos /* print ttl */ 718c74ad251Schristos ND_PRINT(" ["); 719c74ad251Schristos unsigned_relts_print(ndo, GET_BE_U_4(cp)); 720c74ad251Schristos ND_PRINT("]"); 7210f74e101Schristos cp += 4; 7220f74e101Schristos } else { 7230f74e101Schristos /* ignore ttl */ 7240f74e101Schristos cp += 4; 7250f74e101Schristos } 7260f74e101Schristos 727c74ad251Schristos len = GET_BE_U_2(cp); 7280f74e101Schristos cp += 2; 7290f74e101Schristos 7300f74e101Schristos rp = cp + len; 7310f74e101Schristos 732c74ad251Schristos ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", typ)); 733b3a00663Schristos if (rp > ndo->ndo_snapend) 7340f74e101Schristos return(NULL); 7350f74e101Schristos 7360f74e101Schristos switch (typ) { 7370f74e101Schristos case T_A: 738c74ad251Schristos if (!ND_TTEST_LEN(cp, sizeof(nd_ipv4))) 7390f74e101Schristos return(NULL); 740c74ad251Schristos ND_PRINT(" %s", intoa(GET_IPV4_TO_NETWORK_ORDER(cp))); 7410f74e101Schristos break; 7420f74e101Schristos 7430f74e101Schristos case T_NS: 7440f74e101Schristos case T_CNAME: 7450f74e101Schristos case T_PTR: 7460f74e101Schristos case T_DNAME: 747c74ad251Schristos ND_PRINT(" "); 748c74ad251Schristos if (fqdn_print(ndo, cp, bp) == NULL) 7490f74e101Schristos return(NULL); 7500f74e101Schristos break; 7510f74e101Schristos 7520f74e101Schristos case T_SOA: 753b3a00663Schristos if (!ndo->ndo_vflag) 7540f74e101Schristos break; 755c74ad251Schristos ND_PRINT(" "); 756c74ad251Schristos if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 7570f74e101Schristos return(NULL); 758c74ad251Schristos ND_PRINT(" "); 759c74ad251Schristos if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 7600f74e101Schristos return(NULL); 761c74ad251Schristos if (!ND_TTEST_LEN(cp, 5 * 4)) 7620f74e101Schristos return(NULL); 763c74ad251Schristos ND_PRINT(" %u", GET_BE_U_4(cp)); 7640f74e101Schristos cp += 4; 765c74ad251Schristos ND_PRINT(" %u", GET_BE_U_4(cp)); 7660f74e101Schristos cp += 4; 767c74ad251Schristos ND_PRINT(" %u", GET_BE_U_4(cp)); 7680f74e101Schristos cp += 4; 769c74ad251Schristos ND_PRINT(" %u", GET_BE_U_4(cp)); 7700f74e101Schristos cp += 4; 771c74ad251Schristos ND_PRINT(" %u", GET_BE_U_4(cp)); 7720f74e101Schristos cp += 4; 7730f74e101Schristos break; 7740f74e101Schristos case T_MX: 775c74ad251Schristos ND_PRINT(" "); 776c74ad251Schristos if (!ND_TTEST_2(cp)) 7770f74e101Schristos return(NULL); 778c74ad251Schristos if (fqdn_print(ndo, cp + 2, bp) == NULL) 7790f74e101Schristos return(NULL); 780c74ad251Schristos ND_PRINT(" %u", GET_BE_U_2(cp)); 7810f74e101Schristos break; 7820f74e101Schristos 7830f74e101Schristos case T_TXT: 7840f74e101Schristos while (cp < rp) { 785c74ad251Schristos ND_PRINT(" \""); 786b3a00663Schristos cp = ns_cprint(ndo, cp); 7870f74e101Schristos if (cp == NULL) 7880f74e101Schristos return(NULL); 789c74ad251Schristos ND_PRINT("\""); 7900f74e101Schristos } 7910f74e101Schristos break; 7920f74e101Schristos 7930f74e101Schristos case T_SRV: 794c74ad251Schristos ND_PRINT(" "); 795c74ad251Schristos if (!ND_TTEST_6(cp)) 7960f74e101Schristos return(NULL); 797c74ad251Schristos if (fqdn_print(ndo, cp + 6, bp) == NULL) 7980f74e101Schristos return(NULL); 799c74ad251Schristos ND_PRINT(":%u %u %u", GET_BE_U_2(cp + 4), 800c74ad251Schristos GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 8010f74e101Schristos break; 8020f74e101Schristos 8030f74e101Schristos case T_AAAA: 8040f74e101Schristos { 8050f74e101Schristos char ntop_buf[INET6_ADDRSTRLEN]; 8060f74e101Schristos 807c74ad251Schristos if (!ND_TTEST_LEN(cp, sizeof(nd_ipv6))) 8080f74e101Schristos return(NULL); 809c74ad251Schristos ND_PRINT(" %s", 810c74ad251Schristos addrtostr6(cp, ntop_buf, sizeof(ntop_buf))); 8110f74e101Schristos 8120f74e101Schristos break; 8130f74e101Schristos } 8140f74e101Schristos 8150f74e101Schristos case T_A6: 8160f74e101Schristos { 817c74ad251Schristos nd_ipv6 a; 8180f74e101Schristos int pbit, pbyte; 8190f74e101Schristos char ntop_buf[INET6_ADDRSTRLEN]; 8200f74e101Schristos 821c74ad251Schristos if (!ND_TTEST_1(cp)) 8220f74e101Schristos return(NULL); 823c74ad251Schristos pbit = GET_U_1(cp); 8240f74e101Schristos pbyte = (pbit & ~7) / 8; 8250f74e101Schristos if (pbit > 128) { 826c74ad251Schristos ND_PRINT(" %u(bad plen)", pbit); 8270f74e101Schristos break; 8280f74e101Schristos } else if (pbit < 128) { 829c74ad251Schristos memset(a, 0, sizeof(a)); 830c74ad251Schristos GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte); 831c74ad251Schristos ND_PRINT(" %u %s", pbit, 832c74ad251Schristos addrtostr6(&a, ntop_buf, sizeof(ntop_buf))); 8330f74e101Schristos } 8340f74e101Schristos if (pbit > 0) { 835c74ad251Schristos ND_PRINT(" "); 836c74ad251Schristos if (fqdn_print(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL) 8370f74e101Schristos return(NULL); 8380f74e101Schristos } 8390f74e101Schristos break; 8400f74e101Schristos } 8410f74e101Schristos 842c74ad251Schristos case T_URI: 843c74ad251Schristos if (!ND_TTEST_LEN(cp, len)) 844c74ad251Schristos return(NULL); 845*26ba0b50Schristos if (len < 4) { 846*26ba0b50Schristos ND_PRINT(" len %u is too short (< 4)", len); 847*26ba0b50Schristos break; 848*26ba0b50Schristos } 849c74ad251Schristos ND_PRINT(" %u %u ", GET_BE_U_2(cp), GET_BE_U_2(cp + 2)); 850c74ad251Schristos if (nd_printn(ndo, cp + 4, len - 4, ndo->ndo_snapend)) 851c74ad251Schristos return(NULL); 852c74ad251Schristos break; 853c74ad251Schristos 8540f74e101Schristos case T_OPT: 855c74ad251Schristos ND_PRINT(" UDPsize=%u", class); 8560f74e101Schristos if (opt_flags & 0x8000) 857c74ad251Schristos ND_PRINT(" DO"); 858c74ad251Schristos if (cp < rp) { 859c74ad251Schristos ND_PRINT(" ["); 860c74ad251Schristos while (cp < rp) { 861c74ad251Schristos cp = eopt_print(ndo, cp); 862c74ad251Schristos if (cp == NULL) 8630f74e101Schristos return(NULL); 864c74ad251Schristos if (cp < rp) 865c74ad251Schristos ND_PRINT(","); 866c74ad251Schristos } 867c74ad251Schristos ND_PRINT("]"); 868c74ad251Schristos } 8690f74e101Schristos break; 8700f74e101Schristos 8710f74e101Schristos case T_TSIG: 8720f74e101Schristos { 873b3a00663Schristos if (cp + len > ndo->ndo_snapend) 8740f74e101Schristos return(NULL); 875b3a00663Schristos if (!ndo->ndo_vflag) 8760f74e101Schristos break; 877c74ad251Schristos ND_PRINT(" "); 878c74ad251Schristos if ((cp = fqdn_print(ndo, cp, bp)) == NULL) 8790f74e101Schristos return(NULL); 8800f74e101Schristos cp += 6; 881c74ad251Schristos if (!ND_TTEST_2(cp)) 8820f74e101Schristos return(NULL); 883c74ad251Schristos ND_PRINT(" fudge=%u", GET_BE_U_2(cp)); 8840f74e101Schristos cp += 2; 885c74ad251Schristos if (!ND_TTEST_2(cp)) 8860f74e101Schristos return(NULL); 887c74ad251Schristos ND_PRINT(" maclen=%u", GET_BE_U_2(cp)); 888c74ad251Schristos cp += 2 + GET_BE_U_2(cp); 889c74ad251Schristos if (!ND_TTEST_2(cp)) 8900f74e101Schristos return(NULL); 891c74ad251Schristos ND_PRINT(" origid=%u", GET_BE_U_2(cp)); 8920f74e101Schristos cp += 2; 893c74ad251Schristos if (!ND_TTEST_2(cp)) 8940f74e101Schristos return(NULL); 895c74ad251Schristos ND_PRINT(" error=%u", GET_BE_U_2(cp)); 8960f74e101Schristos cp += 2; 897c74ad251Schristos if (!ND_TTEST_2(cp)) 8980f74e101Schristos return(NULL); 899c74ad251Schristos ND_PRINT(" otherlen=%u", GET_BE_U_2(cp)); 9000f74e101Schristos cp += 2; 9010f74e101Schristos } 9020f74e101Schristos } 9030f74e101Schristos return (rp); /* XXX This isn't always right */ 9040f74e101Schristos } 9050f74e101Schristos 9060f74e101Schristos void 907c74ad251Schristos domain_print(netdissect_options *ndo, 908c74ad251Schristos const u_char *bp, u_int length, int over_tcp, int is_mdns) 9090f74e101Schristos { 910c74ad251Schristos const dns_header_t *np; 911c74ad251Schristos uint16_t flags, rcode, rdlen, type; 912c74ad251Schristos u_int qdcount, ancount, nscount, arcount; 913c74ad251Schristos u_int i; 914c74ad251Schristos const u_char *cp; 915b3a00663Schristos uint16_t b2; 9160f74e101Schristos 917c74ad251Schristos ndo->ndo_protocol = "domain"; 918c74ad251Schristos 919c74ad251Schristos if (over_tcp) { 920c74ad251Schristos /* 921c74ad251Schristos * The message is prefixed with a two byte length field 922c74ad251Schristos * which gives the message length, excluding the two byte 923c74ad251Schristos * length field. (RFC 1035 - 4.2.2. TCP usage) 924c74ad251Schristos */ 925c74ad251Schristos if (length < 2) { 926c74ad251Schristos ND_PRINT(" [DNS over TCP: length %u < 2]", length); 927c74ad251Schristos nd_print_invalid(ndo); 928c74ad251Schristos return; 929c74ad251Schristos } else { 930c74ad251Schristos length -= 2; /* excluding the two byte length field */ 931c74ad251Schristos if (GET_BE_U_2(bp) != length) { 932c74ad251Schristos ND_PRINT(" [prefix length(%u) != length(%u)]", 933c74ad251Schristos GET_BE_U_2(bp), length); 934c74ad251Schristos nd_print_invalid(ndo); 935c74ad251Schristos return; 936c74ad251Schristos } else { 937c74ad251Schristos bp += 2; 938c74ad251Schristos /* in over TCP case, we need to prepend a space 939c74ad251Schristos * (not needed in over UDP case) 940c74ad251Schristos */ 941c74ad251Schristos ND_PRINT(" "); 942c74ad251Schristos } 943c74ad251Schristos } 944c74ad251Schristos } 945c74ad251Schristos 946c74ad251Schristos np = (const dns_header_t *)bp; 947c74ad251Schristos 948817e9a7eSchristos if(length < sizeof(*np)) { 949c74ad251Schristos nd_print_protocol(ndo); 950c74ad251Schristos ND_PRINT(" [length %u < %zu]", length, sizeof(*np)); 951c74ad251Schristos nd_print_invalid(ndo); 952817e9a7eSchristos return; 953817e9a7eSchristos } 954817e9a7eSchristos 955c74ad251Schristos ND_TCHECK_SIZE(np); 956c74ad251Schristos flags = GET_BE_U_2(np->flags); 9570f74e101Schristos /* get the byte-order right */ 958c74ad251Schristos qdcount = GET_BE_U_2(np->qdcount); 959c74ad251Schristos ancount = GET_BE_U_2(np->ancount); 960c74ad251Schristos nscount = GET_BE_U_2(np->nscount); 961c74ad251Schristos arcount = GET_BE_U_2(np->arcount); 9620f74e101Schristos 963c74ad251Schristos /* find the opt record to extract extended rcode */ 964c74ad251Schristos cp = (const u_char *)(np + 1); 965c74ad251Schristos rcode = DNS_RCODE(flags); 966c74ad251Schristos for (i = 0; i < qdcount; i++) { 967c74ad251Schristos if ((cp = ns_nskip(ndo, cp)) == NULL) 968c74ad251Schristos goto print; 969c74ad251Schristos cp += 4; /* skip QTYPE and QCLASS */ 970c74ad251Schristos if (cp >= ndo->ndo_snapend) 971c74ad251Schristos goto print; 972c74ad251Schristos } 973c74ad251Schristos for (i = 0; i < ancount + nscount; i++) { 974c74ad251Schristos if ((cp = ns_nskip(ndo, cp)) == NULL) 975c74ad251Schristos goto print; 976c74ad251Schristos cp += 8; /* skip TYPE, CLASS and TTL */ 977c74ad251Schristos if (cp + 2 > ndo->ndo_snapend) 978c74ad251Schristos goto print; 979c74ad251Schristos rdlen = GET_BE_U_2(cp); 980c74ad251Schristos cp += 2 + rdlen; 981c74ad251Schristos if (cp >= ndo->ndo_snapend) 982c74ad251Schristos goto print; 983c74ad251Schristos } 984c74ad251Schristos for (i = 0; i < arcount; i++) { 985c74ad251Schristos if ((cp = ns_nskip(ndo, cp)) == NULL) 986c74ad251Schristos goto print; 987c74ad251Schristos if (cp + 2 > ndo->ndo_snapend) 988c74ad251Schristos goto print; 989c74ad251Schristos type = GET_BE_U_2(cp); 990c74ad251Schristos cp += 4; /* skip TYPE and CLASS */ 991c74ad251Schristos if (cp + 1 > ndo->ndo_snapend) 992c74ad251Schristos goto print; 993c74ad251Schristos if (type == T_OPT) { 994c74ad251Schristos rcode |= (GET_U_1(cp) << 4); 995c74ad251Schristos goto print; 996c74ad251Schristos } 997c74ad251Schristos cp += 4; 998c74ad251Schristos if (cp + 2 > ndo->ndo_snapend) 999c74ad251Schristos goto print; 1000c74ad251Schristos rdlen = GET_BE_U_2(cp); 1001c74ad251Schristos cp += 2 + rdlen; 1002c74ad251Schristos if (cp >= ndo->ndo_snapend) 1003c74ad251Schristos goto print; 1004c74ad251Schristos } 1005c74ad251Schristos 1006c74ad251Schristos print: 1007c74ad251Schristos if (DNS_QR(flags)) { 10080f74e101Schristos /* this is a response */ 1009c74ad251Schristos ND_PRINT("%u%s%s%s%s%s%s", 1010c74ad251Schristos GET_BE_U_2(np->id), 1011c74ad251Schristos ns_ops[DNS_OPCODE(flags)], 1012c74ad251Schristos ns_rcode(rcode), 1013c74ad251Schristos DNS_AA(flags)? "*" : "", 1014c74ad251Schristos DNS_RA(flags)? "" : "-", 1015c74ad251Schristos DNS_TC(flags)? "|" : "", 1016c74ad251Schristos DNS_AD(flags)? "$" : ""); 10170f74e101Schristos 10180f74e101Schristos if (qdcount != 1) 1019c74ad251Schristos ND_PRINT(" [%uq]", qdcount); 10200f74e101Schristos /* Print QUESTION section on -vv */ 10210f74e101Schristos cp = (const u_char *)(np + 1); 1022c74ad251Schristos for (i = 0; i < qdcount; i++) { 1023c74ad251Schristos if (i != 0) 1024c74ad251Schristos ND_PRINT(","); 1025b3a00663Schristos if (ndo->ndo_vflag > 1) { 1026c74ad251Schristos ND_PRINT(" q:"); 1027b3a00663Schristos if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL) 10280f74e101Schristos goto trunc; 10290f74e101Schristos } else { 1030b3a00663Schristos if ((cp = ns_nskip(ndo, cp)) == NULL) 10310f74e101Schristos goto trunc; 10320f74e101Schristos cp += 4; /* skip QTYPE and QCLASS */ 10330f74e101Schristos } 10340f74e101Schristos } 1035c74ad251Schristos ND_PRINT(" %u/%u/%u", ancount, nscount, arcount); 1036c74ad251Schristos if (ancount) { 1037b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10380f74e101Schristos goto trunc; 1039c74ad251Schristos ancount--; 1040c74ad251Schristos while (cp < ndo->ndo_snapend && ancount) { 1041c74ad251Schristos ND_PRINT(","); 1042b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10430f74e101Schristos goto trunc; 1044c74ad251Schristos ancount--; 10450f74e101Schristos } 10460f74e101Schristos } 1047c74ad251Schristos if (ancount) 10480f74e101Schristos goto trunc; 10490f74e101Schristos /* Print NS and AR sections on -vv */ 1050b3a00663Schristos if (ndo->ndo_vflag > 1) { 1051c74ad251Schristos if (cp < ndo->ndo_snapend && nscount) { 1052c74ad251Schristos ND_PRINT(" ns:"); 1053b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10540f74e101Schristos goto trunc; 1055c74ad251Schristos nscount--; 1056c74ad251Schristos while (cp < ndo->ndo_snapend && nscount) { 1057c74ad251Schristos ND_PRINT(","); 1058b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10590f74e101Schristos goto trunc; 1060c74ad251Schristos nscount--; 10610f74e101Schristos } 10620f74e101Schristos } 1063c74ad251Schristos if (nscount) 10640f74e101Schristos goto trunc; 1065c74ad251Schristos if (cp < ndo->ndo_snapend && arcount) { 1066c74ad251Schristos ND_PRINT(" ar:"); 1067b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10680f74e101Schristos goto trunc; 1069c74ad251Schristos arcount--; 1070c74ad251Schristos while (cp < ndo->ndo_snapend && arcount) { 1071c74ad251Schristos ND_PRINT(","); 1072b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 10730f74e101Schristos goto trunc; 1074c74ad251Schristos arcount--; 10750f74e101Schristos } 10760f74e101Schristos } 1077c74ad251Schristos if (arcount) 10780f74e101Schristos goto trunc; 10790f74e101Schristos } 1080*26ba0b50Schristos } else { 10810f74e101Schristos /* this is a request */ 1082c74ad251Schristos ND_PRINT("%u%s%s%s", GET_BE_U_2(np->id), 1083c74ad251Schristos ns_ops[DNS_OPCODE(flags)], 1084c74ad251Schristos DNS_RD(flags) ? "+" : "", 1085c74ad251Schristos DNS_CD(flags) ? "%" : ""); 10860f74e101Schristos 10870f74e101Schristos /* any weirdness? */ 1088c74ad251Schristos b2 = GET_BE_U_2(((const u_short *)np) + 1); 10890f74e101Schristos if (b2 & 0x6cf) 1090c74ad251Schristos ND_PRINT(" [b2&3=0x%x]", b2); 10910f74e101Schristos 1092c74ad251Schristos if (DNS_OPCODE(flags) == IQUERY) { 10930f74e101Schristos if (qdcount) 1094c74ad251Schristos ND_PRINT(" [%uq]", qdcount); 10950f74e101Schristos if (ancount != 1) 1096c74ad251Schristos ND_PRINT(" [%ua]", ancount); 1097*26ba0b50Schristos } else { 10980f74e101Schristos if (ancount) 1099c74ad251Schristos ND_PRINT(" [%ua]", ancount); 11000f74e101Schristos if (qdcount != 1) 1101c74ad251Schristos ND_PRINT(" [%uq]", qdcount); 11020f74e101Schristos } 11030f74e101Schristos if (nscount) 1104c74ad251Schristos ND_PRINT(" [%un]", nscount); 11050f74e101Schristos if (arcount) 1106c74ad251Schristos ND_PRINT(" [%uau]", arcount); 11070f74e101Schristos 11080f74e101Schristos cp = (const u_char *)(np + 1); 1109c74ad251Schristos if (qdcount) { 1110b3a00663Schristos cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns); 11110f74e101Schristos if (!cp) 11120f74e101Schristos goto trunc; 1113c74ad251Schristos qdcount--; 1114c74ad251Schristos while (cp < ndo->ndo_snapend && qdcount) { 1115b3a00663Schristos cp = ns_qprint(ndo, (const u_char *)cp, 11160f74e101Schristos (const u_char *)np, 11170f74e101Schristos is_mdns); 11180f74e101Schristos if (!cp) 11190f74e101Schristos goto trunc; 1120c74ad251Schristos qdcount--; 11210f74e101Schristos } 11220f74e101Schristos } 1123c74ad251Schristos if (qdcount) 11240f74e101Schristos goto trunc; 11250f74e101Schristos 11260f74e101Schristos /* Print remaining sections on -vv */ 1127b3a00663Schristos if (ndo->ndo_vflag > 1) { 1128c74ad251Schristos if (ancount) { 1129b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11300f74e101Schristos goto trunc; 1131c74ad251Schristos ancount--; 1132c74ad251Schristos while (cp < ndo->ndo_snapend && ancount) { 1133c74ad251Schristos ND_PRINT(","); 1134b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11350f74e101Schristos goto trunc; 1136c74ad251Schristos ancount--; 11370f74e101Schristos } 11380f74e101Schristos } 1139c74ad251Schristos if (ancount) 11400f74e101Schristos goto trunc; 1141c74ad251Schristos if (cp < ndo->ndo_snapend && nscount) { 1142c74ad251Schristos ND_PRINT(" ns:"); 1143b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11440f74e101Schristos goto trunc; 1145c74ad251Schristos nscount--; 1146c74ad251Schristos while (cp < ndo->ndo_snapend && nscount) { 1147c74ad251Schristos ND_PRINT(","); 1148b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11490f74e101Schristos goto trunc; 1150c74ad251Schristos nscount--; 11510f74e101Schristos } 11520f74e101Schristos } 11530f74e101Schristos if (nscount > 0) 11540f74e101Schristos goto trunc; 1155c74ad251Schristos if (cp < ndo->ndo_snapend && arcount) { 1156c74ad251Schristos ND_PRINT(" ar:"); 1157b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11580f74e101Schristos goto trunc; 1159c74ad251Schristos arcount--; 1160c74ad251Schristos while (cp < ndo->ndo_snapend && arcount) { 1161c74ad251Schristos ND_PRINT(","); 1162b3a00663Schristos if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL) 11630f74e101Schristos goto trunc; 1164c74ad251Schristos arcount--; 11650f74e101Schristos } 11660f74e101Schristos } 1167c74ad251Schristos if (arcount) 11680f74e101Schristos goto trunc; 11690f74e101Schristos } 11700f74e101Schristos } 1171c74ad251Schristos ND_PRINT(" (%u)", length); 11720f74e101Schristos return; 11730f74e101Schristos 11740f74e101Schristos trunc: 1175c74ad251Schristos nd_print_trunc(ndo); 11760f74e101Schristos } 1177