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