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#ifndef lint
23static const char rcsid[] _U_ =
24    "@(#) $Header: /tcpdump/master/tcpdump/print-domain.c,v 1.98 2007-12-09 01:40:32 guy Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <tcpdump-stdinc.h>
32
33#include "nameser.h"
34
35#include <stdio.h>
36#include <string.h>
37
38#include "interface.h"
39#include "addrtoname.h"
40#include "extract.h"                    /* must come after interface.h */
41
42static const char *ns_ops[] = {
43	"", " inv_q", " stat", " op3", " notify", " update", " op6", " op7",
44	" op8", " updataA", " updateD", " updateDA",
45	" updateM", " updateMA", " zoneInit", " zoneRef",
46};
47
48static const char *ns_resp[] = {
49	"", " FormErr", " ServFail", " NXDomain",
50	" NotImp", " Refused", " YXDomain", " YXRRSet",
51	" NXRRSet", " NotAuth", " NotZone", " Resp11",
52	" Resp12", " Resp13", " Resp14", " NoChange",
53};
54
55/* skip over a domain name */
56static const u_char *
57ns_nskip(register const u_char *cp)
58{
59	register u_char i;
60
61	if (!TTEST2(*cp, 1))
62		return (NULL);
63	i = *cp++;
64	while (i) {
65		if ((i & INDIR_MASK) == INDIR_MASK)
66			return (cp + 1);
67		if ((i & INDIR_MASK) == EDNS0_MASK) {
68			int bitlen, bytelen;
69
70			if ((i & ~INDIR_MASK) != EDNS0_ELT_BITLABEL)
71				return(NULL); /* unknown ELT */
72			if (!TTEST2(*cp, 1))
73				return (NULL);
74			if ((bitlen = *cp++) == 0)
75				bitlen = 256;
76			bytelen = (bitlen + 7) / 8;
77			cp += bytelen;
78		} else
79			cp += i;
80		if (!TTEST2(*cp, 1))
81			return (NULL);
82		i = *cp++;
83	}
84	return (cp);
85}
86
87/* print a <domain-name> */
88static const u_char *
89blabel_print(const u_char *cp)
90{
91	int bitlen, slen, b;
92	const u_char *bitp, *lim;
93	char tc;
94
95	if (!TTEST2(*cp, 1))
96		return(NULL);
97	if ((bitlen = *cp) == 0)
98		bitlen = 256;
99	slen = (bitlen + 3) / 4;
100	lim = cp + 1 + slen;
101
102	/* print the bit string as a hex string */
103	printf("\\[x");
104	for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) {
105		TCHECK(*bitp);
106		printf("%02x", *bitp);
107	}
108	if (b > 4) {
109		TCHECK(*bitp);
110		tc = *bitp++;
111		printf("%02x", tc & (0xff << (8 - b)));
112	} else if (b > 0) {
113		TCHECK(*bitp);
114		tc = *bitp++;
115		printf("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
116	}
117	printf("/%d]", bitlen);
118	return lim;
119trunc:
120	printf(".../%d]", bitlen);
121	return NULL;
122}
123
124static int
125labellen(const u_char *cp)
126{
127	register u_int i;
128
129	if (!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			printf("<ELT %d>", elt);
136			return(-1);
137		}
138		if (!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
147const u_char *
148ns_nprint(register const u_char *cp, register const u_char *bp)
149{
150	register u_int i, l;
151	register const u_char *rp = NULL;
152	register int compress = 0;
153	int chars_processed;
154	int elt;
155	int data_size = snapend - bp;
156
157	if ((l = labellen(cp)) == (u_int)-1)
158		return(NULL);
159	if (!TTEST2(*cp, 1))
160		return(NULL);
161	chars_processed = 1;
162	if (((i = *cp++) & INDIR_MASK) != INDIR_MASK) {
163		compress = 0;
164		rp = cp + l;
165	}
166
167	if (i != 0)
168		while (i && cp < snapend) {
169			if ((i & INDIR_MASK) == INDIR_MASK) {
170				if (!compress) {
171					rp = cp + 1;
172					compress = 1;
173				}
174				if (!TTEST2(*cp, 1))
175					return(NULL);
176				cp = bp + (((i << 8) | *cp) & 0x3fff);
177				if ((l = labellen(cp)) == (u_int)-1)
178					return(NULL);
179				if (!TTEST2(*cp, 1))
180					return(NULL);
181				i = *cp++;
182				chars_processed++;
183
184				/*
185				 * If we've looked at every character in
186				 * the message, this pointer will make
187				 * us look at some character again,
188				 * which means we're looping.
189				 */
190				if (chars_processed >= data_size) {
191					printf("<LOOP>");
192					return (NULL);
193				}
194				continue;
195			}
196			if ((i & INDIR_MASK) == EDNS0_MASK) {
197				elt = (i & ~INDIR_MASK);
198				switch(elt) {
199				case EDNS0_ELT_BITLABEL:
200					if (blabel_print(cp) == NULL)
201						return (NULL);
202					break;
203				default:
204					/* unknown ELT */
205					printf("<ELT %d>", elt);
206					return(NULL);
207				}
208			} else {
209				if (fn_printn(cp, l, snapend))
210					return(NULL);
211			}
212
213			cp += l;
214			chars_processed += l;
215			putchar('.');
216			if ((l = labellen(cp)) == (u_int)-1)
217				return(NULL);
218			if (!TTEST2(*cp, 1))
219				return(NULL);
220			i = *cp++;
221			chars_processed++;
222			if (!compress)
223				rp += l + 1;
224		}
225	else
226		putchar('.');
227	return (rp);
228}
229
230/* print a <character-string> */
231static const u_char *
232ns_cprint(register const u_char *cp)
233{
234	register u_int i;
235
236	if (!TTEST2(*cp, 1))
237		return (NULL);
238	i = *cp++;
239	if (fn_printn(cp, i, snapend))
240		return (NULL);
241	return (cp + i);
242}
243
244/* http://www.iana.org/assignments/dns-parameters */
245const 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
310const 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 */
319static const u_char *
320ns_qprint(register const u_char *cp, register const u_char *bp, int is_mdns)
321{
322	register const u_char *np = cp;
323	register u_int i, class;
324
325	cp = ns_nskip(cp);
326
327	if (cp == NULL || !TTEST2(*cp, 4))
328		return(NULL);
329
330	/* print the qtype */
331	i = EXTRACT_16BITS(cp);
332	cp += 2;
333	printf(" %s", tok2str(ns_type2str, "Type%d", i));
334	/* print the qclass (if it's not IN) */
335	i = EXTRACT_16BITS(cp);
336	cp += 2;
337	if (is_mdns)
338		class = (i & ~C_QU);
339	else
340		class = i;
341	if (class != C_IN)
342		printf(" %s", tok2str(ns_class2str, "(Class %d)", class));
343	if (is_mdns) {
344		if (i & C_QU)
345			printf(" (QU)");
346		else
347			printf(" (QM)");
348	}
349
350	fputs("? ", stdout);
351	cp = ns_nprint(np, bp);
352	return(cp ? cp + 4 : NULL);
353}
354
355/* print a reply */
356static const u_char *
357ns_rprint(register const u_char *cp, register const u_char *bp, int is_mdns)
358{
359	register u_int i, class, opt_flags = 0;
360	register u_short typ, len;
361	register const u_char *rp;
362
363	if (vflag) {
364		putchar(' ');
365		if ((cp = ns_nprint(cp, bp)) == NULL)
366			return NULL;
367	} else
368		cp = ns_nskip(cp);
369
370	if (cp == NULL || !TTEST2(*cp, 10))
371		return (snapend);
372
373	/* print the type/qtype */
374	typ = EXTRACT_16BITS(cp);
375	cp += 2;
376	/* print the class (if it's not IN and the type isn't OPT) */
377	i = EXTRACT_16BITS(cp);
378	cp += 2;
379	if (is_mdns)
380		class = (i & ~C_CACHE_FLUSH);
381	else
382		class = i;
383	if (class != C_IN && typ != T_OPT)
384		printf(" %s", tok2str(ns_class2str, "(Class %d)", class));
385	if (is_mdns) {
386		if (i & C_CACHE_FLUSH)
387			printf(" (Cache flush)");
388	}
389
390	if (typ == T_OPT) {
391		/* get opt flags */
392		cp += 2;
393		opt_flags = EXTRACT_16BITS(cp);
394		/* ignore rest of ttl field */
395		cp += 2;
396	} else if (vflag > 2) {
397		/* print ttl */
398		printf(" [");
399		relts_print(EXTRACT_32BITS(cp));
400		printf("]");
401		cp += 4;
402	} else {
403		/* ignore ttl */
404		cp += 4;
405	}
406
407	len = EXTRACT_16BITS(cp);
408	cp += 2;
409
410	rp = cp + len;
411
412	printf(" %s", tok2str(ns_type2str, "Type%d", typ));
413	if (rp > snapend)
414		return(NULL);
415
416	switch (typ) {
417	case T_A:
418		if (!TTEST2(*cp, sizeof(struct in_addr)))
419			return(NULL);
420		printf(" %s", intoa(htonl(EXTRACT_32BITS(cp))));
421		break;
422
423	case T_NS:
424	case T_CNAME:
425	case T_PTR:
426#ifdef T_DNAME
427	case T_DNAME:
428#endif
429		putchar(' ');
430		if (ns_nprint(cp, bp) == NULL)
431			return(NULL);
432		break;
433
434	case T_SOA:
435		if (!vflag)
436			break;
437		putchar(' ');
438		if ((cp = ns_nprint(cp, bp)) == NULL)
439			return(NULL);
440		putchar(' ');
441		if ((cp = ns_nprint(cp, bp)) == NULL)
442			return(NULL);
443		if (!TTEST2(*cp, 5 * 4))
444			return(NULL);
445		printf(" %u", EXTRACT_32BITS(cp));
446		cp += 4;
447		printf(" %u", EXTRACT_32BITS(cp));
448		cp += 4;
449		printf(" %u", EXTRACT_32BITS(cp));
450		cp += 4;
451		printf(" %u", EXTRACT_32BITS(cp));
452		cp += 4;
453		printf(" %u", EXTRACT_32BITS(cp));
454		cp += 4;
455		break;
456	case T_MX:
457		putchar(' ');
458		if (!TTEST2(*cp, 2))
459			return(NULL);
460		if (ns_nprint(cp + 2, bp) == NULL)
461			return(NULL);
462		printf(" %d", EXTRACT_16BITS(cp));
463		break;
464
465	case T_TXT:
466		while (cp < rp) {
467			printf(" \"");
468			cp = ns_cprint(cp);
469			if (cp == NULL)
470				return(NULL);
471			putchar('"');
472		}
473		break;
474
475	case T_SRV:
476		putchar(' ');
477		if (!TTEST2(*cp, 6))
478			return(NULL);
479		if (ns_nprint(cp + 6, bp) == NULL)
480			return(NULL);
481		printf(":%d %d %d", EXTRACT_16BITS(cp + 4),
482			EXTRACT_16BITS(cp), EXTRACT_16BITS(cp + 2));
483		break;
484
485#ifdef INET6
486	case T_AAAA:
487	    {
488		struct in6_addr addr;
489		char ntop_buf[INET6_ADDRSTRLEN];
490
491		if (!TTEST2(*cp, sizeof(struct in6_addr)))
492			return(NULL);
493		memcpy(&addr, cp, sizeof(struct in6_addr));
494		printf(" %s",
495		    inet_ntop(AF_INET6, &addr, ntop_buf, sizeof(ntop_buf)));
496
497		break;
498	    }
499
500	case T_A6:
501	    {
502		struct in6_addr a;
503		int pbit, pbyte;
504		char ntop_buf[INET6_ADDRSTRLEN];
505
506		if (!TTEST2(*cp, 1))
507			return(NULL);
508		pbit = *cp;
509		pbyte = (pbit & ~7) / 8;
510		if (pbit > 128) {
511			printf(" %u(bad plen)", pbit);
512			break;
513		} else if (pbit < 128) {
514			if (!TTEST2(*(cp + 1), sizeof(a) - pbyte))
515				return(NULL);
516			memset(&a, 0, sizeof(a));
517			memcpy(&a.s6_addr[pbyte], cp + 1, sizeof(a) - pbyte);
518			printf(" %u %s", pbit,
519			    inet_ntop(AF_INET6, &a, ntop_buf, sizeof(ntop_buf)));
520		}
521		if (pbit > 0) {
522			putchar(' ');
523			if (ns_nprint(cp + 1 + sizeof(a) - pbyte, bp) == NULL)
524				return(NULL);
525		}
526		break;
527	    }
528#endif /*INET6*/
529
530	case T_OPT:
531		printf(" UDPsize=%u", class);
532		if (opt_flags & 0x8000)
533			printf(" OK");
534		break;
535
536	case T_UNSPECA:		/* One long string */
537		if (!TTEST2(*cp, len))
538			return(NULL);
539		if (fn_printn(cp, len, snapend))
540			return(NULL);
541		break;
542
543	case T_TSIG:
544	    {
545		if (cp + len > snapend)
546			return(NULL);
547		if (!vflag)
548			break;
549		putchar(' ');
550		if ((cp = ns_nprint(cp, bp)) == NULL)
551			return(NULL);
552		cp += 6;
553		if (!TTEST2(*cp, 2))
554			return(NULL);
555		printf(" fudge=%u", EXTRACT_16BITS(cp));
556		cp += 2;
557		if (!TTEST2(*cp, 2))
558			return(NULL);
559		printf(" maclen=%u", EXTRACT_16BITS(cp));
560		cp += 2 + EXTRACT_16BITS(cp);
561		if (!TTEST2(*cp, 2))
562			return(NULL);
563		printf(" origid=%u", EXTRACT_16BITS(cp));
564		cp += 2;
565		if (!TTEST2(*cp, 2))
566			return(NULL);
567		printf(" error=%u", EXTRACT_16BITS(cp));
568		cp += 2;
569		if (!TTEST2(*cp, 2))
570			return(NULL);
571		printf(" otherlen=%u", EXTRACT_16BITS(cp));
572		cp += 2;
573	    }
574	}
575	return (rp);		/* XXX This isn't always right */
576}
577
578void
579ns_print(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	u_int16_t b2;
585
586	np = (const HEADER *)bp;
587	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		printf("%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			printf(" [%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				putchar(',');
612			if (vflag > 1) {
613				fputs(" q:", stdout);
614				if ((cp = ns_qprint(cp, bp, is_mdns)) == NULL)
615					goto trunc;
616			} else {
617				if ((cp = ns_nskip(cp)) == NULL)
618					goto trunc;
619				cp += 4;	/* skip QTYPE and QCLASS */
620			}
621		}
622		printf(" %d/%d/%d", ancount, nscount, arcount);
623		if (ancount--) {
624			if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
625				goto trunc;
626			while (cp < snapend && ancount--) {
627				putchar(',');
628				if ((cp = ns_rprint(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 (vflag > 1) {
636			if (cp < snapend && nscount--) {
637				fputs(" ns:", stdout);
638				if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
639					goto trunc;
640				while (cp < snapend && nscount--) {
641					putchar(',');
642					if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
643						goto trunc;
644				}
645			}
646			if (nscount > 0)
647				goto trunc;
648			if (cp < snapend && arcount--) {
649				fputs(" ar:", stdout);
650				if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
651					goto trunc;
652				while (cp < snapend && arcount--) {
653					putchar(',');
654					if ((cp = ns_rprint(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		printf("%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			printf(" [b2&3=0x%x]", b2);
672
673		if (DNS_OPCODE(np) == IQUERY) {
674			if (qdcount)
675				printf(" [%dq]", qdcount);
676			if (ancount != 1)
677				printf(" [%da]", ancount);
678		}
679		else {
680			if (ancount)
681				printf(" [%da]", ancount);
682			if (qdcount != 1)
683				printf(" [%dq]", qdcount);
684		}
685		if (nscount)
686			printf(" [%dn]", nscount);
687		if (arcount)
688			printf(" [%dau]", arcount);
689
690		cp = (const u_char *)(np + 1);
691		if (qdcount--) {
692			cp = ns_qprint(cp, (const u_char *)np, is_mdns);
693			if (!cp)
694				goto trunc;
695			while (cp < snapend && qdcount--) {
696				cp = ns_qprint((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 (vflag > 1) {
708			if (ancount--) {
709				if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
710					goto trunc;
711				while (cp < snapend && ancount--) {
712					putchar(',');
713					if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
714						goto trunc;
715				}
716			}
717			if (ancount > 0)
718				goto trunc;
719			if (cp < snapend && nscount--) {
720				fputs(" ns:", stdout);
721				if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
722					goto trunc;
723				while (nscount-- && cp < snapend) {
724					putchar(',');
725					if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
726						goto trunc;
727				}
728			}
729			if (nscount > 0)
730				goto trunc;
731			if (cp < snapend && arcount--) {
732				fputs(" ar:", stdout);
733				if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
734					goto trunc;
735				while (cp < snapend && arcount--) {
736					putchar(',');
737					if ((cp = ns_rprint(cp, bp, is_mdns)) == NULL)
738						goto trunc;
739				}
740			}
741			if (arcount > 0)
742				goto trunc;
743		}
744	}
745	printf(" (%d)", length);
746	return;
747
748  trunc:
749	printf("[|domain]");
750	return;
751}
752