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