"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-domain.c" (7 Jun 2021, 27855 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-domain.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

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