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