Home | History | Annotate | Download | only in tcpdump
      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 #define NETDISSECT_REWORKED
     23 #ifdef HAVE_CONFIG_H
     24 #include "config.h"
     25 #endif
     26 
     27 #include <tcpdump-stdinc.h>
     28 
     29 #include "nameser.h"
     30 
     31 #include <string.h>
     32 
     33 #include "interface.h"
     34 #include "addrtoname.h"
     35 #include "extract.h"                    /* must come after interface.h */
     36 
     37 static const char *ns_ops[] = {
     38 	"", " inv_q", " stat", " op3", " notify", " update", " op6", " op7",
     39 	" op8", " updateA", " updateD", " updateDA",
     40 	" updateM", " updateMA", " zoneInit", " zoneRef",
     41 };
     42 
     43 static const char *ns_resp[] = {
     44 	"", " FormErr", " ServFail", " NXDomain",
     45 	" NotImp", " Refused", " YXDomain", " YXRRSet",
     46 	" NXRRSet", " NotAuth", " NotZone", " Resp11",
     47 	" Resp12", " Resp13", " Resp14", " NoChange",
     48 };
     49 
     50 /* skip over a domain name */
     51 static const u_char *
     52 ns_nskip(netdissect_options *ndo,
     53          register const u_char *cp)
     54 {
     55 	register u_char i;
     56 
     57 	if (!ND_TTEST2(*cp, 1))
     58 		return (NULL);
     59 	i = *cp++;
     60 	while (i) {
     61 		if ((i & INDIR_MASK) == INDIR_MASK)
     62 			return (cp + 1);
     63 		if ((i & INDIR_MASK) == EDNS0_MASK) {
     64 			int bitlen, bytelen;
     65 
     66 			if ((i & ~INDIR_MASK) != EDNS0_ELT_BITLABEL)
     67 				return(NULL); /* unknown ELT */
     68 			if (!ND_TTEST2(*cp, 1))
     69 				return (NULL);
     70 			if ((bitlen = *cp++) == 0)
     71 				bitlen = 256;
     72 			bytelen = (bitlen + 7) / 8;
     73 			cp += bytelen;
     74 		} else
     75 			cp += i;
     76 		if (!ND_TTEST2(*cp, 1))
     77 			return (NULL);
     78 		i = *cp++;
     79 	}
     80 	return (cp);
     81 }
     82 
     83 /* print a <domain-name> */
     84 static const u_char *
     85 blabel_print(netdissect_options *ndo,
     86              const u_char *cp)
     87 {
     88 	int bitlen, slen, b;
     89 	const u_char *bitp, *lim;
     90 	char tc;
     91 
     92 	if (!ND_TTEST2(*cp, 1))
     93 		return(NULL);
     94 	if ((bitlen = *cp) == 0)
     95 		bitlen = 256;
     96 	slen = (bitlen + 3) / 4;
     97 	lim = cp + 1 + slen;
     98 
     99 	/* print the bit string as a hex string */
    100 	ND_PRINT((ndo, "\\[x"));
    101 	for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) {
    102 		ND_TCHECK(*bitp);
    103 		ND_PRINT((ndo, "%02x", *bitp));
    104 	}
    105 	if (b > 4) {
    106 		ND_TCHECK(*bitp);
    107 		tc = *bitp++;
    108 		ND_PRINT((ndo, "%02x", tc & (0xff << (8 - b))));
    109 	} else if (b > 0) {
    110 		ND_TCHECK(*bitp);
    111 		tc = *bitp++;
    112 		ND_PRINT((ndo, "%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
    113 	}
    114 	ND_PRINT((ndo, "/%d]", bitlen));
    115 	return lim;
    116 trunc:
    117 	ND_PRINT((ndo, ".../%d]", bitlen));
    118 	return NULL;
    119 }
    120 
    121 static int
    122 labellen(netdissect_options *ndo,
    123          const u_char *cp)
    124 {
    125 	register u_int i;
    126 
    127 	if (!ND_TTEST2(*cp, 1))
    128 		return(-1);
    129 	i = *cp;
    130 	if ((i & INDIR_MASK) == EDNS0_MASK) {
    131 		int bitlen, elt;
    132 		if ((elt = (i & ~INDIR_MASK)) != EDNS0_ELT_BITLABEL) {
    133 			ND_PRINT((ndo, "<ELT %d>", elt));
    134 			return(-1);
    135 		}
    136 		if (!ND_TTEST2(*(cp + 1), 1))
    137 			return(-1);
    138 		if ((bitlen = *(cp + 1)) == 0)
    139 			bitlen = 256;
    140 		return(((bitlen + 7) / 8) + 1);
    141 	} else
    142 		return(i);
    143 }
    144 
    145 const u_char *
    146 ns_nprint(netdissect_options *ndo,
    147           register const u_char *cp, register const u_char *bp)
    148 {
    149 	register u_int i, l;
    150 	register const u_char *rp = NULL;
    151 	register int compress = 0;
    152 	int chars_processed;
    153 	int elt;
    154 	int data_size = ndo->ndo_snapend - bp;
    155 
    156 	if ((l = labellen(ndo, cp)) == (u_int)-1)
    157 		return(NULL);
    158 	if (!ND_TTEST2(*cp, 1))
    159 		return(NULL);
    160 	chars_processed = 1;
    161 	if (((i = *cp++) & INDIR_MASK) != INDIR_MASK) {
    162 		compress = 0;
    163 		rp = cp + l;
    164 	}
    165 
    166 	if (i != 0)
    167 		while (i && cp < ndo->ndo_snapend) {
    168 			if ((i & INDIR_MASK) == INDIR_MASK) {
    169 				if (!compress) {
    170 					rp = cp + 1;
    171 					compress = 1;
    172 				}
    173 				if (!ND_TTEST2(*cp, 1))
    174 					return(NULL);
    175 				cp = bp + (((i << 8) | *cp) & 0x3fff);
    176 				if ((l = labellen(ndo, cp)) == (u_int)-1)
    177 					return(NULL);
    178 				if (!ND_TTEST2(*cp, 1))
    179 					return(NULL);
    180 				i = *cp++;
    181 				chars_processed++;
    182 
    183 				/*
    184 				 * If we've looked at every character in
    185 				 * the message, this pointer will make
    186 				 * us look at some character again,
    187 				 * which means we're looping.
    188 				 */
    189 				if (chars_processed >= data_size) {
    190 					ND_PRINT((ndo, "<LOOP>"));
    191 					return (NULL);
    192 				}
    193 				continue;
    194 			}
    195 			if ((i & INDIR_MASK) == EDNS0_MASK) {
    196 				elt = (i & ~INDIR_MASK);
    197 				switch(elt) {
    198 				case EDNS0_ELT_BITLABEL:
    199 					if (blabel_print(ndo, cp) == NULL)
    200 						return (NULL);
    201 					break;
    202 				default:
    203 					/* unknown ELT */
    204 					ND_PRINT((ndo, "<ELT %d>", elt));
    205 					return(NULL);
    206 				}
    207 			} else {
    208 				if (fn_printn(ndo, cp, l, ndo->ndo_snapend))
    209 					return(NULL);
    210 			}
    211 
    212 			cp += l;
    213 			chars_processed += l;
    214 			ND_PRINT((ndo, "."));
    215 			if ((l = labellen(ndo, cp)) == (u_int)-1)
    216 				return(NULL);
    217 			if (!ND_TTEST2(*cp, 1))
    218 				return(NULL);
    219 			i = *cp++;
    220 			chars_processed++;
    221 			if (!compress)
    222 				rp += l + 1;
    223 		}
    224 	else
    225 		ND_PRINT((ndo, "."));
    226 	return (rp);
    227 }
    228 
    229 /* print a <character-string> */
    230 static const u_char *
    231 ns_cprint(netdissect_options *ndo,
    232           register const u_char *cp)
    233 {
    234 	register u_int i;
    235 
    236 	if (!ND_TTEST2(*cp, 1))
    237 		return (NULL);
    238 	i = *cp++;
    239 	if (fn_printn(ndo, cp, i, ndo->ndo_snapend))
    240 		return (NULL);
    241 	return (cp + i);
    242 }
    243 
    244 /* http://www.iana.org/assignments/dns-parameters */
    245 const struct tok ns_type2str[] = {
    246 	{ T_A,		"A" },			/* RFC 1035 */
    247 	{ T_NS,		"NS" },			/* RFC 1035 */
    248 	{ T_MD,		"MD" },			/* RFC 1035 */
    249 	{ T_MF,		"MF" },			/* RFC 1035 */
    250 	{ T_CNAME,	"CNAME" },		/* RFC 1035 */
    251 	{ T_SOA,	"SOA" },		/* RFC 1035 */
    252 	{ T_MB,		"MB" },			/* RFC 1035 */
    253 	{ T_MG,		"MG" },			/* RFC 1035 */
    254 	{ T_MR,		"MR" },			/* RFC 1035 */
    255 	{ T_NULL,	"NULL" },		/* RFC 1035 */
    256 	{ T_WKS,	"WKS" },		/* RFC 1035 */
    257 	{ T_PTR,	"PTR" },		/* RFC 1035 */
    258 	{ T_HINFO,	"HINFO" },		/* RFC 1035 */
    259 	{ T_MINFO,	"MINFO" },		/* RFC 1035 */
    260 	{ T_MX,		"MX" },			/* RFC 1035 */
    261 	{ T_TXT,	"TXT" },		/* RFC 1035 */
    262 	{ T_RP,		"RP" },			/* RFC 1183 */
    263 	{ T_AFSDB,	"AFSDB" },		/* RFC 1183 */
    264 	{ T_X25,	"X25" },		/* RFC 1183 */
    265 	{ T_ISDN,	"ISDN" },		/* RFC 1183 */
    266 	{ T_RT,		"RT" },			/* RFC 1183 */
    267 	{ T_NSAP,	"NSAP" },		/* RFC 1706 */
    268 	{ T_NSAP_PTR,	"NSAP_PTR" },
    269 	{ T_SIG,	"SIG" },		/* RFC 2535 */
    270 	{ T_KEY,	"KEY" },		/* RFC 2535 */
    271 	{ T_PX,		"PX" },			/* RFC 2163 */
    272 	{ T_GPOS,	"GPOS" },		/* RFC 1712 */
    273 	{ T_AAAA,	"AAAA" },		/* RFC 1886 */
    274 	{ T_LOC,	"LOC" },		/* RFC 1876 */
    275 	{ T_NXT,	"NXT" },		/* RFC 2535 */
    276 	{ T_EID,	"EID" },		/* Nimrod */
    277 	{ T_NIMLOC,	"NIMLOC" },		/* Nimrod */
    278 	{ T_SRV,	"SRV" },		/* RFC 2782 */
    279 	{ T_ATMA,	"ATMA" },		/* ATM Forum */
    280 	{ T_NAPTR,	"NAPTR" },		/* RFC 2168, RFC 2915 */
    281 	{ T_KX,		"KX" },			/* RFC 2230 */
    282 	{ T_CERT,	"CERT" },		/* RFC 2538 */
    283 	{ T_A6,		"A6" },			/* RFC 2874 */
    284 	{ T_DNAME,	"DNAME" },		/* RFC 2672 */
    285 	{ T_SINK, 	"SINK" },
    286 	{ T_OPT,	"OPT" },		/* RFC 2671 */
    287 	{ T_APL, 	"APL" },		/* RFC 3123 */
    288 	{ T_DS,		"DS" },			/* RFC 4034 */
    289 	{ T_SSHFP,	"SSHFP" },		/* RFC 4255 */
    290 	{ T_IPSECKEY,	"IPSECKEY" },		/* RFC 4025 */
    291 	{ T_RRSIG, 	"RRSIG" },		/* RFC 4034 */
    292 	{ T_NSEC,	"NSEC" },		/* RFC 4034 */
    293 	{ T_DNSKEY,	"DNSKEY" },		/* RFC 4034 */
    294 	{ T_SPF,	"SPF" },		/* RFC-schlitt-spf-classic-02.txt */
    295 	{ T_UINFO,	"UINFO" },
    296 	{ T_UID,	"UID" },
    297 	{ T_GID,	"GID" },
    298 	{ T_UNSPEC,	"UNSPEC" },
    299 	{ T_UNSPECA,	"UNSPECA" },
    300 	{ T_TKEY,	"TKEY" },		/* RFC 2930 */
    301 	{ T_TSIG,	"TSIG" },		/* RFC 2845 */
    302 	{ T_IXFR,	"IXFR" },		/* RFC 1995 */
    303 	{ T_AXFR,	"AXFR" },		/* RFC 1035 */
    304 	{ T_MAILB,	"MAILB" },		/* RFC 1035 */
    305 	{ T_MAILA,	"MAILA" },		/* RFC 1035 */
    306 	{ T_ANY,	"ANY" },
    307 	{ 0,		NULL }
    308 };
    309 
    310 const struct tok ns_class2str[] = {
    311 	{ C_IN,		"IN" },		/* Not used */
    312 	{ C_CHAOS,	"CHAOS" },
    313 	{ C_HS,		"HS" },
    314 	{ C_ANY,	"ANY" },
    315 	{ 0,		NULL }
    316 };
    317 
    318 /* print a query */
    319 static const u_char *
    320 ns_qprint(netdissect_options *ndo,
    321           register const u_char *cp, register const u_char *bp, int is_mdns)
    322 {
    323 	register const u_char *np = cp;
    324 	register u_int i, class;
    325 
    326 	cp = ns_nskip(ndo, cp);
    327 
    328 	if (cp == NULL || !ND_TTEST2(*cp, 4))
    329 		return(NULL);
    330 
    331 	/* print the qtype */
    332 	i = EXTRACT_16BITS(cp);
    333 	cp += 2;
    334 	ND_PRINT((ndo, " %s", tok2str(ns_type2str, "Type%d", i)));
    335 	/* print the qclass (if it's not IN) */
    336 	i = EXTRACT_16BITS(cp);
    337 	cp += 2;
    338 	if (is_mdns)
    339 		class = (i & ~C_QU);
    340 	else
    341 		class = i;
    342 	if (class != C_IN)
    343 		ND_PRINT((ndo, " %s", tok2str(ns_class2str, "(Class %d)", class)));
    344 	if (is_mdns) {
    345 		ND_PRINT((ndo, i & C_QU ? " (QU)" : " (QM)"));
    346 	}
    347 
    348 	ND_PRINT((ndo, "? "));
    349 	cp = ns_nprint(ndo, np, bp);
    350 	return(cp ? cp + 4 : NULL);
    351 }
    352 
    353 /* print a reply */
    354 static const u_char *
    355 ns_rprint(netdissect_options *ndo,
    356           register const u_char *cp, register const u_char *bp, int is_mdns)
    357 {
    358 	register u_int i, class, opt_flags = 0;
    359 	register u_short typ, len;
    360 	register const u_char *rp;
    361 
    362 	if (ndo->ndo_vflag) {
    363 		ND_PRINT((ndo, " "));
    364 		if ((cp = ns_nprint(ndo, cp, bp)) == NULL)
    365 			return NULL;
    366 	} else
    367 		cp = ns_nskip(ndo, cp);
    368 
    369 	if (cp == NULL || !ND_TTEST2(*cp, 10))
    370 		return (ndo->ndo_snapend);
    371 
    372 	/* print the type/qtype */
    373 	typ = EXTRACT_16BITS(cp);
    374 	cp += 2;
    375 	/* print the class (if it's not IN and the type isn't OPT) */
    376 	i = EXTRACT_16BITS(cp);
    377 	cp += 2;
    378 	if (is_mdns)
    379 		class = (i & ~C_CACHE_FLUSH);
    380 	else
    381 		class = i;
    382 	if (class != C_IN && typ != T_OPT)
    383 		ND_PRINT((ndo, " %s", tok2str(ns_class2str, "(Class %d)", class)));
    384 	if (is_mdns) {
    385 		if (i & C_CACHE_FLUSH)
    386 			ND_PRINT((ndo, " (Cache flush)"));
    387 	}
    388 
    389 	if (typ == T_OPT) {
    390 		/* get opt flags */
    391 		cp += 2;
    392 		opt_flags = EXTRACT_16BITS(cp);
    393 		/* ignore rest of ttl field */
    394 		cp += 2;
    395 	} else if (ndo->ndo_vflag > 2) {
    396 		/* print ttl */
    397 		ND_PRINT((ndo, " ["));
    398 		relts_print(ndo, EXTRACT_32BITS(cp));
    399 		ND_PRINT((ndo, "]"));
    400 		cp += 4;
    401 	} else {
    402 		/* ignore ttl */
    403 		cp += 4;
    404 	}
    405 
    406 	len = EXTRACT_16BITS(cp);
    407 	cp += 2;
    408 
    409 	rp = cp + len;
    410 
    411 	ND_PRINT((ndo, " %s", tok2str(ns_type2str, "Type%d", typ)));
    412 	if (rp > ndo->ndo_snapend)
    413 		return(NULL);
    414 
    415 	switch (typ) {
    416 	case T_A:
    417 		if (!ND_TTEST2(*cp, sizeof(struct in_addr)))
    418 			return(NULL);
    419 		ND_PRINT((ndo, " %s", intoa(htonl(EXTRACT_32BITS(cp)))));
    420 		break;
    421 
    422 	case T_NS:
    423 	case T_CNAME:
    424 	case T_PTR:
    425 #ifdef T_DNAME
    426 	case T_DNAME:
    427 #endif
    428 		ND_PRINT((ndo, " "));
    429 		if (ns_nprint(ndo, cp, bp) == NULL)
    430 			return(NULL);
    431 		break;
    432 
    433 	case T_SOA:
    434 		if (!ndo->ndo_vflag)
    435 			break;
    436 		ND_PRINT((ndo, " "));
    437 		if ((cp = ns_nprint(ndo, cp, bp)) == NULL)
    438 			return(NULL);
    439 		ND_PRINT((ndo, " "));
    440 		if ((cp = ns_nprint(ndo, cp, bp)) == NULL)
    441 			return(NULL);
    442 		if (!ND_TTEST2(*cp, 5 * 4))
    443 			return(NULL);
    444 		ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
    445 		cp += 4;
    446 		ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
    447 		cp += 4;
    448 		ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
    449 		cp += 4;
    450 		ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
    451 		cp += 4;
    452 		ND_PRINT((ndo, " %u", EXTRACT_32BITS(cp)));
    453 		cp += 4;
    454 		break;
    455 	case T_MX:
    456 		ND_PRINT((ndo, " "));
    457 		if (!ND_TTEST2(*cp, 2))
    458 			return(NULL);
    459 		if (ns_nprint(ndo, cp + 2, bp) == NULL)
    460 			return(NULL);
    461 		ND_PRINT((ndo, " %d", EXTRACT_16BITS(cp)));
    462 		break;
    463 
    464 	case T_TXT:
    465 		while (cp < rp) {
    466 			ND_PRINT((ndo, " \""));
    467 			cp = ns_cprint(ndo, cp);
    468 			if (cp == NULL)
    469 				return(NULL);
    470 			ND_PRINT((ndo, "\""));
    471 		}
    472 		break;
    473 
    474 	case T_SRV:
    475 		ND_PRINT((ndo, " "));
    476 		if (!ND_TTEST2(*cp, 6))
    477 			return(NULL);
    478 		if (ns_nprint(ndo, cp + 6, bp) == NULL)
    479 			return(NULL);
    480 		ND_PRINT((ndo, ":%d %d %d", EXTRACT_16BITS(cp + 4),
    481 			EXTRACT_16BITS(cp), EXTRACT_16BITS(cp + 2)));
    482 		break;
    483 
    484 #ifdef INET6
    485 	case T_AAAA:
    486 	    {
    487 		struct in6_addr addr;
    488 		char ntop_buf[INET6_ADDRSTRLEN];
    489 
    490 		if (!ND_TTEST2(*cp, sizeof(struct in6_addr)))
    491 			return(NULL);
    492 		memcpy(&addr, cp, sizeof(struct in6_addr));
    493 		ND_PRINT((ndo, " %s",
    494 		    inet_ntop(AF_INET6, &addr, ntop_buf, sizeof(ntop_buf))));
    495 
    496 		break;
    497 	    }
    498 
    499 	case T_A6:
    500 	    {
    501 		struct in6_addr a;
    502 		int pbit, pbyte;
    503 		char ntop_buf[INET6_ADDRSTRLEN];
    504 
    505 		if (!ND_TTEST2(*cp, 1))
    506 			return(NULL);
    507 		pbit = *cp;
    508 		pbyte = (pbit & ~7) / 8;
    509 		if (pbit > 128) {
    510 			ND_PRINT((ndo, " %u(bad plen)", pbit));
    511 			break;
    512 		} else if (pbit < 128) {
    513 			if (!ND_TTEST2(*(cp + 1), sizeof(a) - pbyte))
    514 				return(NULL);
    515 			memset(&a, 0, sizeof(a));
    516 			memcpy(&a.s6_addr[pbyte], cp + 1, sizeof(a) - pbyte);
    517 			ND_PRINT((ndo, " %u %s", pbit,
    518 			    inet_ntop(AF_INET6, &a, ntop_buf, sizeof(ntop_buf))));
    519 		}
    520 		if (pbit > 0) {
    521 			ND_PRINT((ndo, " "));
    522 			if (ns_nprint(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL)
    523 				return(NULL);
    524 		}
    525 		break;
    526 	    }
    527 #endif /*INET6*/
    528 
    529 	case T_OPT:
    530 		ND_PRINT((ndo, " UDPsize=%u", class));
    531 		if (opt_flags & 0x8000)
    532 			ND_PRINT((ndo, " OK"));
    533 		break;
    534 
    535 	case T_UNSPECA:		/* One long string */
    536 		if (!ND_TTEST2(*cp, len))
    537 			return(NULL);
    538 		if (fn_printn(ndo, cp, len, ndo->ndo_snapend))
    539 			return(NULL);
    540 		break;
    541 
    542 	case T_TSIG:
    543 	    {
    544 		if (cp + len > ndo->ndo_snapend)
    545 			return(NULL);
    546 		if (!ndo->ndo_vflag)
    547 			break;
    548 		ND_PRINT((ndo, " "));
    549 		if ((cp = ns_nprint(ndo, cp, bp)) == NULL)
    550 			return(NULL);
    551 		cp += 6;
    552 		if (!ND_TTEST2(*cp, 2))
    553 			return(NULL);
    554 		ND_PRINT((ndo, " fudge=%u", EXTRACT_16BITS(cp)));
    555 		cp += 2;
    556 		if (!ND_TTEST2(*cp, 2))
    557 			return(NULL);
    558 		ND_PRINT((ndo, " maclen=%u", EXTRACT_16BITS(cp)));
    559 		cp += 2 + EXTRACT_16BITS(cp);
    560 		if (!ND_TTEST2(*cp, 2))
    561 			return(NULL);
    562 		ND_PRINT((ndo, " origid=%u", EXTRACT_16BITS(cp)));
    563 		cp += 2;
    564 		if (!ND_TTEST2(*cp, 2))
    565 			return(NULL);
    566 		ND_PRINT((ndo, " error=%u", EXTRACT_16BITS(cp)));
    567 		cp += 2;
    568 		if (!ND_TTEST2(*cp, 2))
    569 			return(NULL);
    570 		ND_PRINT((ndo, " otherlen=%u", EXTRACT_16BITS(cp)));
    571 		cp += 2;
    572 	    }
    573 	}
    574 	return (rp);		/* XXX This isn't always right */
    575 }
    576 
    577 void
    578 ns_print(netdissect_options *ndo,
    579          register const u_char *bp, u_int length, int is_mdns)
    580 {
    581 	register const HEADER *np;
    582 	register int qdcount, ancount, nscount, arcount;
    583 	register const u_char *cp;
    584 	uint16_t b2;
    585 
    586 	np = (const HEADER *)bp;
    587 	ND_TCHECK(*np);
    588 	/* get the byte-order right */
    589 	qdcount = EXTRACT_16BITS(&np->qdcount);
    590 	ancount = EXTRACT_16BITS(&np->ancount);
    591 	nscount = EXTRACT_16BITS(&np->nscount);
    592 	arcount = EXTRACT_16BITS(&np->arcount);
    593 
    594 	if (DNS_QR(np)) {
    595 		/* this is a response */
    596 		ND_PRINT((ndo, "%d%s%s%s%s%s%s",
    597 			EXTRACT_16BITS(&np->id),
    598 			ns_ops[DNS_OPCODE(np)],
    599 			ns_resp[DNS_RCODE(np)],
    600 			DNS_AA(np)? "*" : "",
    601 			DNS_RA(np)? "" : "-",
    602 			DNS_TC(np)? "|" : "",
    603 			DNS_AD(np)? "$" : ""));
    604 
    605 		if (qdcount != 1)
    606 			ND_PRINT((ndo, " [%dq]", qdcount));
    607 		/* Print QUESTION section on -vv */
    608 		cp = (const u_char *)(np + 1);
    609 		while (qdcount--) {
    610 			if (qdcount < EXTRACT_16BITS(&np->qdcount) - 1)
    611 				ND_PRINT((ndo, ","));
    612 			if (ndo->ndo_vflag > 1) {
    613 				ND_PRINT((ndo, " q:"));
    614 				if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL)
    615 					goto trunc;
    616 			} else {
    617 				if ((cp = ns_nskip(ndo, cp)) == NULL)
    618 					goto trunc;
    619 				cp += 4;	/* skip QTYPE and QCLASS */
    620 			}
    621 		}
    622 		ND_PRINT((ndo, " %d/%d/%d", ancount, nscount, arcount));
    623 		if (ancount--) {
    624 			if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    625 				goto trunc;
    626 			while (cp < ndo->ndo_snapend && ancount--) {
    627 				ND_PRINT((ndo, ","));
    628 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    629 					goto trunc;
    630 			}
    631 		}
    632 		if (ancount > 0)
    633 			goto trunc;
    634 		/* Print NS and AR sections on -vv */
    635 		if (ndo->ndo_vflag > 1) {
    636 			if (cp < ndo->ndo_snapend && nscount--) {
    637 				ND_PRINT((ndo, " ns:"));
    638 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    639 					goto trunc;
    640 				while (cp < ndo->ndo_snapend && nscount--) {
    641 					ND_PRINT((ndo, ","));
    642 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    643 						goto trunc;
    644 				}
    645 			}
    646 			if (nscount > 0)
    647 				goto trunc;
    648 			if (cp < ndo->ndo_snapend && arcount--) {
    649 				ND_PRINT((ndo, " ar:"));
    650 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    651 					goto trunc;
    652 				while (cp < ndo->ndo_snapend && arcount--) {
    653 					ND_PRINT((ndo, ","));
    654 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    655 						goto trunc;
    656 				}
    657 			}
    658 			if (arcount > 0)
    659 				goto trunc;
    660 		}
    661 	}
    662 	else {
    663 		/* this is a request */
    664 		ND_PRINT((ndo, "%d%s%s%s", EXTRACT_16BITS(&np->id), ns_ops[DNS_OPCODE(np)],
    665 		    DNS_RD(np) ? "+" : "",
    666 		    DNS_CD(np) ? "%" : ""));
    667 
    668 		/* any weirdness? */
    669 		b2 = EXTRACT_16BITS(((u_short *)np)+1);
    670 		if (b2 & 0x6cf)
    671 			ND_PRINT((ndo, " [b2&3=0x%x]", b2));
    672 
    673 		if (DNS_OPCODE(np) == IQUERY) {
    674 			if (qdcount)
    675 				ND_PRINT((ndo, " [%dq]", qdcount));
    676 			if (ancount != 1)
    677 				ND_PRINT((ndo, " [%da]", ancount));
    678 		}
    679 		else {
    680 			if (ancount)
    681 				ND_PRINT((ndo, " [%da]", ancount));
    682 			if (qdcount != 1)
    683 				ND_PRINT((ndo, " [%dq]", qdcount));
    684 		}
    685 		if (nscount)
    686 			ND_PRINT((ndo, " [%dn]", nscount));
    687 		if (arcount)
    688 			ND_PRINT((ndo, " [%dau]", arcount));
    689 
    690 		cp = (const u_char *)(np + 1);
    691 		if (qdcount--) {
    692 			cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns);
    693 			if (!cp)
    694 				goto trunc;
    695 			while (cp < ndo->ndo_snapend && qdcount--) {
    696 				cp = ns_qprint(ndo, (const u_char *)cp,
    697 					       (const u_char *)np,
    698 					       is_mdns);
    699 				if (!cp)
    700 					goto trunc;
    701 			}
    702 		}
    703 		if (qdcount > 0)
    704 			goto trunc;
    705 
    706 		/* Print remaining sections on -vv */
    707 		if (ndo->ndo_vflag > 1) {
    708 			if (ancount--) {
    709 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    710 					goto trunc;
    711 				while (cp < ndo->ndo_snapend && ancount--) {
    712 					ND_PRINT((ndo, ","));
    713 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    714 						goto trunc;
    715 				}
    716 			}
    717 			if (ancount > 0)
    718 				goto trunc;
    719 			if (cp < ndo->ndo_snapend && nscount--) {
    720 				ND_PRINT((ndo, " ns:"));
    721 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    722 					goto trunc;
    723 				while (nscount-- && cp < ndo->ndo_snapend) {
    724 					ND_PRINT((ndo, ","));
    725 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    726 						goto trunc;
    727 				}
    728 			}
    729 			if (nscount > 0)
    730 				goto trunc;
    731 			if (cp < ndo->ndo_snapend && arcount--) {
    732 				ND_PRINT((ndo, " ar:"));
    733 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    734 					goto trunc;
    735 				while (cp < ndo->ndo_snapend && arcount--) {
    736 					ND_PRINT((ndo, ","));
    737 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
    738 						goto trunc;
    739 				}
    740 			}
    741 			if (arcount > 0)
    742 				goto trunc;
    743 		}
    744 	}
    745 	ND_PRINT((ndo, " (%d)", length));
    746 	return;
    747 
    748   trunc:
    749 	ND_PRINT((ndo, "[|domain]"));
    750 }
    751