xref: /freebsd/contrib/tcpdump/print-domain.c (revision 87b759f0fa1f7554d50ce640c40138512bbded44)
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 #include <config.h>
25 
26 #include "netdissect-stdinc.h"
27 
28 #include <string.h>
29 
30 #include "netdissect.h"
31 #include "addrtoname.h"
32 #include "addrtostr.h"
33 #include "extract.h"
34 
35 #include "nameser.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 	" BadVers", "Resp17", " Resp18", " Resp19",
49 	" Resp20", "Resp21", " Resp22", " BadCookie",
50 };
51 
52 static const char *
53 ns_rcode(u_int rcode) {
54 	static char buf[sizeof(" Resp4095")];
55 
56 	if (rcode < sizeof(ns_resp)/sizeof(ns_resp[0])) {
57 		return (ns_resp[rcode]);
58 	}
59 	snprintf(buf, sizeof(buf), " Resp%u", rcode & 0xfff);
60 	return (buf);
61 }
62 
63 /* skip over a domain name */
64 static const u_char *
65 ns_nskip(netdissect_options *ndo,
66          const u_char *cp)
67 {
68 	u_char i;
69 
70 	if (!ND_TTEST_1(cp))
71 		return (NULL);
72 	i = GET_U_1(cp);
73 	cp++;
74 	while (i) {
75 		switch (i & TYPE_MASK) {
76 
77 		case TYPE_INDIR:
78 			return (cp + 1);
79 
80 		case TYPE_EDNS0: {
81 			int bitlen, bytelen;
82 
83 			if ((i & ~TYPE_MASK) != EDNS0_ELT_BITLABEL)
84 				return(NULL); /* unknown ELT */
85 			if (!ND_TTEST_1(cp))
86 				return (NULL);
87 			if ((bitlen = GET_U_1(cp)) == 0)
88 				bitlen = 256;
89 			cp++;
90 			bytelen = (bitlen + 7) / 8;
91 			cp += bytelen;
92 		}
93 		break;
94 
95 		case TYPE_RESERVED:
96 			return (NULL);
97 
98 		case TYPE_LABEL:
99 			cp += i;
100 			break;
101 		}
102 		if (!ND_TTEST_1(cp))
103 			return (NULL);
104 		i = GET_U_1(cp);
105 		cp++;
106 	}
107 	return (cp);
108 }
109 
110 static const u_char *
111 blabel_print(netdissect_options *ndo,
112              const u_char *cp)
113 {
114 	u_int bitlen, slen, b;
115 	const u_char *bitp, *lim;
116 	uint8_t tc;
117 
118 	if (!ND_TTEST_1(cp))
119 		return(NULL);
120 	if ((bitlen = GET_U_1(cp)) == 0)
121 		bitlen = 256;
122 	slen = (bitlen + 3) / 4;
123 	lim = cp + 1 + slen;
124 
125 	/* print the bit string as a hex string */
126 	ND_PRINT("\\[x");
127 	for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) {
128 		ND_PRINT("%02x", GET_U_1(bitp));
129 	}
130 	if (b > 4) {
131 		tc = GET_U_1(bitp);
132 		bitp++;
133 		ND_PRINT("%02x", tc & (0xff << (8 - b)));
134 	} else if (b > 0) {
135 		tc = GET_U_1(bitp);
136 		bitp++;
137 		ND_PRINT("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
138 	}
139 	ND_PRINT("/%u]", bitlen);
140 	return lim;
141 }
142 
143 static int
144 labellen(netdissect_options *ndo,
145          const u_char *cp)
146 {
147 	u_int i;
148 
149 	if (!ND_TTEST_1(cp))
150 		return(-1);
151 	i = GET_U_1(cp);
152 	switch (i & TYPE_MASK) {
153 
154 	case TYPE_EDNS0: {
155 		u_int bitlen, elt;
156 		if ((elt = (i & ~TYPE_MASK)) != EDNS0_ELT_BITLABEL) {
157 			ND_PRINT("<ELT %d>", elt);
158 			return(-1);
159 		}
160 		if (!ND_TTEST_1(cp + 1))
161 			return(-1);
162 		if ((bitlen = GET_U_1(cp + 1)) == 0)
163 			bitlen = 256;
164 		return(((bitlen + 7) / 8) + 1);
165 	}
166 
167 	case TYPE_INDIR:
168 	case TYPE_LABEL:
169 		return(i);
170 
171 	default:
172 		/*
173 		 * TYPE_RESERVED, but we use default to suppress compiler
174 		 * warnings about falling out of the switch statement.
175 		 */
176 		ND_PRINT("<BAD LABEL TYPE>");
177 		return(-1);
178 	}
179 }
180 
181 /* print a <domain-name> */
182 const u_char *
183 fqdn_print(netdissect_options *ndo,
184           const u_char *cp, const u_char *bp)
185 {
186 	u_int i, l;
187 	const u_char *rp = NULL;
188 	int compress = 0;
189 	u_int elt;
190 	u_int offset, max_offset;
191 	u_int name_chars = 0;
192 
193 	if ((l = labellen(ndo, cp)) == (u_int)-1)
194 		return(NULL);
195 	if (!ND_TTEST_1(cp))
196 		return(NULL);
197 	max_offset = (u_int)(cp - bp);
198 	i = GET_U_1(cp);
199 	cp++;
200 	if ((i & TYPE_MASK) != TYPE_INDIR) {
201 		compress = 0;
202 		rp = cp + l;
203 	}
204 
205 	if (i != 0) {
206 		while (i && cp < ndo->ndo_snapend) {
207 			switch (i & TYPE_MASK) {
208 
209 			case TYPE_INDIR:
210 				if (!compress) {
211 					rp = cp + 1;
212 					compress = 1;
213 				}
214 				if (!ND_TTEST_1(cp))
215 					return(NULL);
216 				offset = (((i << 8) | GET_U_1(cp)) & 0x3fff);
217 				/*
218 				 * This must move backwards in the packet.
219 				 * No RFC explicitly says that, but BIND's
220 				 * name decompression code requires it,
221 				 * as a way of preventing infinite loops
222 				 * and other bad behavior, and it's probably
223 				 * what was intended (compress by pointing
224 				 * to domain name suffixes already seen in
225 				 * the packet).
226 				 */
227 				if (offset >= max_offset) {
228 					ND_PRINT("<BAD PTR>");
229 					return(NULL);
230 				}
231 				max_offset = offset;
232 				cp = bp + offset;
233 				if (!ND_TTEST_1(cp))
234 					return(NULL);
235 				i = GET_U_1(cp);
236 				if ((l = labellen(ndo, cp)) == (u_int)-1)
237 					return(NULL);
238 				cp++;
239 				continue;
240 
241 			case TYPE_EDNS0:
242 				elt = (i & ~TYPE_MASK);
243 				switch(elt) {
244 				case EDNS0_ELT_BITLABEL:
245 					if (blabel_print(ndo, cp) == NULL)
246 						return (NULL);
247 					break;
248 				default:
249 					/* unknown ELT */
250 					ND_PRINT("<ELT %u>", elt);
251 					return(NULL);
252 				}
253 				break;
254 
255 			case TYPE_RESERVED:
256 				ND_PRINT("<BAD LABEL TYPE>");
257 				return(NULL);
258 
259 			case TYPE_LABEL:
260 				if (name_chars + l <= MAXCDNAME) {
261 					if (nd_printn(ndo, cp, l, ndo->ndo_snapend))
262 						return(NULL);
263 				} else if (name_chars < MAXCDNAME) {
264 					if (nd_printn(ndo, cp,
265 					    MAXCDNAME - name_chars, ndo->ndo_snapend))
266 						return(NULL);
267 				}
268 				name_chars += l;
269 				break;
270 			}
271 
272 			cp += l;
273 			if (name_chars <= MAXCDNAME)
274 				ND_PRINT(".");
275 			name_chars++;
276 			if (!ND_TTEST_1(cp))
277 				return(NULL);
278 			i = GET_U_1(cp);
279 			if ((l = labellen(ndo, cp)) == (u_int)-1)
280 				return(NULL);
281 			cp++;
282 			if (!compress)
283 				rp += l + 1;
284 		}
285 		if (name_chars > MAXCDNAME)
286 			ND_PRINT("<DOMAIN NAME TOO LONG>");
287 	} else
288 		ND_PRINT(".");
289 	return (rp);
290 }
291 
292 /* print a <character-string> */
293 static const u_char *
294 ns_cprint(netdissect_options *ndo,
295           const u_char *cp)
296 {
297 	u_int i;
298 
299 	if (!ND_TTEST_1(cp))
300 		return (NULL);
301 	i = GET_U_1(cp);
302 	cp++;
303 	if (nd_printn(ndo, cp, i, ndo->ndo_snapend))
304 		return (NULL);
305 	return (cp + i);
306 }
307 
308 static void
309 print_eopt_ecs(netdissect_options *ndo, const u_char *cp,
310                u_int data_len)
311 {
312     u_int family, addr_bits, src_len, scope_len;
313 
314     u_char padded[32];
315     char addr[INET6_ADDRSTRLEN];
316 
317     /* ecs option must at least contain family, src len, and scope len */
318     if (data_len < 4) {
319         nd_print_invalid(ndo);
320         return;
321     }
322 
323     family = GET_BE_U_2(cp);
324     cp += 2;
325     src_len = GET_U_1(cp);
326     cp += 1;
327     scope_len = GET_U_1(cp);
328     cp += 1;
329 
330     if (family == 1)
331         addr_bits = 32;
332     else if (family == 2)
333         addr_bits = 128;
334     else {
335         nd_print_invalid(ndo);
336         return;
337     }
338 
339     if (data_len - 4 > (addr_bits / 8)) {
340         nd_print_invalid(ndo);
341         return;
342     }
343     /* checks for invalid ecs scope or source length */
344     if (src_len > addr_bits || scope_len > addr_bits || ((src_len + 7) / 8) != (data_len - 4)) {
345         nd_print_invalid(ndo);
346         return;
347     }
348 
349     /* pad the truncated address from ecs with zeros */
350     memset(padded, 0, sizeof(padded));
351     memcpy(padded, cp, data_len - 4);
352 
353 
354     if (family == 1)
355         ND_PRINT("%s/%d/%d", addrtostr(padded, addr, INET_ADDRSTRLEN),
356                 src_len, scope_len);
357     else
358         ND_PRINT("%s/%d/%d", addrtostr6(padded, addr, INET6_ADDRSTRLEN),
359                 src_len, scope_len);
360 
361 }
362 
363 extern const struct tok edns_opt2str[];
364 extern const struct tok dau_alg2str[];
365 extern const struct tok dhu_alg2str[];
366 extern const struct tok n3u_alg2str[];
367 
368 
369 /* print an <EDNS-option> */
370 static const u_char *
371 eopt_print(netdissect_options *ndo,
372           const u_char *cp)
373 {
374     u_int opt, data_len, i;
375 
376     if (!ND_TTEST_2(cp))
377         return (NULL);
378     opt = GET_BE_U_2(cp);
379     cp += 2;
380     ND_PRINT("%s", tok2str(edns_opt2str, "Opt%u", opt));
381     if (!ND_TTEST_2(cp))
382         return (NULL);
383     data_len = GET_BE_U_2(cp);
384     cp += 2;
385 
386     ND_TCHECK_LEN(cp, data_len);
387 
388     if (data_len > 0) {
389         ND_PRINT(" ");
390         switch (opt) {
391 
392         case E_ECS:
393             print_eopt_ecs(ndo, cp, data_len);
394             break;
395         case E_COOKIE:
396             if (data_len < 8 || (data_len > 8 && data_len < 16) || data_len > 40)
397                 nd_print_invalid(ndo);
398             else {
399                 for (i = 0; i < data_len; ++i) {
400                     /* split client and server cookie */
401                     if (i == 8)
402                         ND_PRINT(" ");
403                     ND_PRINT("%02x", GET_U_1(cp + i));
404                 }
405             }
406             break;
407         case E_KEEPALIVE:
408             if (data_len != 2)
409                 nd_print_invalid(ndo);
410             else
411                 /* keepalive is in increments of 100ms. Convert to seconds */
412                 ND_PRINT("%0.1f sec", (GET_BE_U_2(cp) / 10.0));
413             break;
414         case E_EXPIRE:
415             if (data_len != 4)
416                 nd_print_invalid(ndo);
417             else
418                 ND_PRINT("%u sec", GET_BE_U_4(cp));
419             break;
420         case E_PADDING:
421             /* ignore contents and just print length */
422             ND_PRINT("(%u)", data_len);
423             break;
424         case E_KEYTAG:
425             if (data_len % 2 != 0)
426                 nd_print_invalid(ndo);
427             else
428                 for (i = 0; i < data_len; i += 2) {
429                     if (i > 0)
430                         ND_PRINT(" ");
431                     ND_PRINT("%u", GET_BE_U_2(cp + i));
432                 }
433             break;
434         case E_DAU:
435             for (i = 0; i < data_len; ++i) {
436                 if (i > 0)
437                     ND_PRINT(" ");
438                 ND_PRINT("%s", tok2str(dau_alg2str, "Alg_%u", GET_U_1(cp + i)));
439             }
440             break;
441         case E_DHU:
442             for (i = 0; i < data_len; ++i) {
443                 if (i > 0)
444                     ND_PRINT(" ");
445                 ND_PRINT("%s", tok2str(dhu_alg2str, "Alg_%u", GET_U_1(cp + i)));
446             }
447             break;
448         case E_N3U:
449             for (i = 0; i < data_len; ++i) {
450                 if (i > 0)
451                     ND_PRINT(" ");
452                 ND_PRINT("%s", tok2str(n3u_alg2str, "Alg_%u", GET_U_1(cp + i)));
453             }
454             break;
455         case E_CHAIN:
456             fqdn_print(ndo, cp, cp + data_len);
457             break;
458         case E_NSID:
459             /* intentional fall-through. NSID is an undefined byte string */
460         default:
461             for (i = 0; i < data_len; ++i)
462                 ND_PRINT("%02x", GET_U_1(cp + i));
463             break;
464         }
465     }
466     return (cp + data_len);
467 
468   trunc:
469     return (NULL);
470 
471 }
472 
473 
474 
475 extern const struct tok ns_type2str[];
476 
477 /* https://www.iana.org/assignments/dns-parameters */
478 const struct tok ns_type2str[] = {
479 	{ T_A,		"A" },			/* RFC 1035 */
480 	{ T_NS,		"NS" },			/* RFC 1035 */
481 	{ T_MD,		"MD" },			/* RFC 1035 */
482 	{ T_MF,		"MF" },			/* RFC 1035 */
483 	{ T_CNAME,	"CNAME" },		/* RFC 1035 */
484 	{ T_SOA,	"SOA" },		/* RFC 1035 */
485 	{ T_MB,		"MB" },			/* RFC 1035 */
486 	{ T_MG,		"MG" },			/* RFC 1035 */
487 	{ T_MR,		"MR" },			/* RFC 1035 */
488 	{ T_NULL,	"NULL" },		/* RFC 1035 */
489 	{ T_WKS,	"WKS" },		/* RFC 1035 */
490 	{ T_PTR,	"PTR" },		/* RFC 1035 */
491 	{ T_HINFO,	"HINFO" },		/* RFC 1035 */
492 	{ T_MINFO,	"MINFO" },		/* RFC 1035 */
493 	{ T_MX,		"MX" },			/* RFC 1035 */
494 	{ T_TXT,	"TXT" },		/* RFC 1035 */
495 	{ T_RP,		"RP" },			/* RFC 1183 */
496 	{ T_AFSDB,	"AFSDB" },		/* RFC 5864 */
497 	{ T_X25,	"X25" },		/* RFC 1183 */
498 	{ T_ISDN,	"ISDN" },		/* RFC 1183 */
499 	{ T_RT,		"RT" },			/* RFC 1183 */
500 	{ T_NSAP,	"NSAP" },		/* RFC 1706 */
501 	{ T_NSAP_PTR,	"NSAP_PTR" },		/* RFC 1706 */
502 	{ T_SIG,	"SIG" },		/* RFC 3008 */
503 	{ T_KEY,	"KEY" },		/* RFC 3110 */
504 	{ T_PX,		"PX" },			/* RFC 2163 */
505 	{ T_GPOS,	"GPOS" },		/* RFC 1712 */
506 	{ T_AAAA,	"AAAA" },		/* RFC 3596 */
507 	{ T_LOC,	"LOC" },		/* RFC 1876 */
508 	{ T_NXT,	"NXT" },		/* RFC 3755 */
509 	{ T_EID,	"EID" },		/* Nimrod */
510 	{ T_NIMLOC,	"NIMLOC" },		/* Nimrod */
511 	{ T_SRV,	"SRV" },		/* RFC 2782 */
512 	{ T_ATMA,	"ATMA" },		/* ATM Forum */
513 	{ T_NAPTR,	"NAPTR" },		/* RFC 3403 */
514 	{ T_KX,		"KX" },			/* RFC 2230 */
515 	{ T_CERT,	"CERT" },		/* RFC 4398 */
516 	{ T_A6,		"A6" },			/* RFC 6563 */
517 	{ T_DNAME,	"DNAME" },		/* RFC 6672 */
518 	{ T_SINK,	"SINK" },
519 	{ T_OPT,	"OPT" },		/* RFC 6891 */
520 	{ T_APL,	"APL" },		/* RFC 3123 */
521 	{ T_DS,		"DS" },			/* RFC 4034 */
522 	{ T_SSHFP,	"SSHFP" },		/* RFC 4255 */
523 	{ T_IPSECKEY,	"IPSECKEY" },		/* RFC 4025 */
524 	{ T_RRSIG,	"RRSIG" },		/* RFC 4034 */
525 	{ T_NSEC,	"NSEC" },		/* RFC 4034 */
526 	{ T_DNSKEY,	"DNSKEY" },		/* RFC 4034 */
527 	{ T_DHCID,	"DHCID" },		/* RFC 4071 */
528 	{ T_NSEC3,	"NSEC3" },		/* RFC 5155 */
529 	{ T_NSEC3PARAM,	"NSEC3PARAM" },		/* RFC 5155 */
530 	{ T_TLSA,	"TLSA" },		/* RFC 6698 */
531 	{ T_SMIMEA,	"SMIMEA" },		/* RFC 8162 */
532 	{ T_HIP,	"HIP" },		/* RFC 8005 */
533 	{ T_NINFO,	"NINFO" },
534 	{ T_RKEY,	"RKEY" },
535 	{ T_TALINK,	"TALINK" },
536 	{ T_CDS,	"CDS" },		/* RFC 7344 */
537 	{ T_CDNSKEY,	"CDNSKEY" },		/* RFC 7344 */
538 	{ T_OPENPGPKEY,	"OPENPGPKEY" },		/* RFC 7929 */
539 	{ T_CSYNC,	"CSYNC" },		/* RFC 7477 */
540 	{ T_ZONEMD,	"ZONEMD" },		/* RFC 8976 */
541 	{ T_SVCB,	"SVCB" },
542 	{ T_HTTPS,	"HTTPS" },
543 	{ T_SPF,	"SPF" },		/* RFC 7208 */
544 	{ T_UINFO,	"UINFO" },
545 	{ T_UID,	"UID" },
546 	{ T_GID,	"GID" },
547 	{ T_UNSPEC,	"UNSPEC" },
548 	{ T_NID,	"NID" },		/* RFC 6742 */
549 	{ T_L32,	"L32" },		/* RFC 6742 */
550 	{ T_L64,	"L64" },		/* RFC 6742 */
551 	{ T_LP,		"LP" },			/* RFC 6742 */
552 	{ T_EUI48,	"EUI48" },		/* RFC 7043 */
553 	{ T_EUI64,	"EUI64" },		/* RFC 7043 */
554 	{ T_TKEY,	"TKEY" },		/* RFC 2930 */
555 	{ T_TSIG,	"TSIG" },		/* RFC 8945 */
556 	{ T_IXFR,	"IXFR" },		/* RFC 1995 */
557 	{ T_AXFR,	"AXFR" },		/* RFC 5936 */
558 	{ T_MAILB,	"MAILB" },		/* RFC 1035 */
559 	{ T_MAILA,	"MAILA" },		/* RFC 1035 */
560 	{ T_ANY,	"ANY" },		/* RFC 8482 */
561 	{ T_URI,	"URI" },		/* RFC 7553 */
562 	{ T_CAA,	"CAA" },		/* RFC 8659 */
563 	{ T_AVC,	"AVC" },
564 	{ T_DOA,	"DOA" },
565 	{ T_AMTRELAY,	"AMTRELAY" },		/* RFC 8777 */
566 	{ T_TA,		"TA" },
567 	{ T_DLV,	"DLV" },		/* RFC 8749 */
568 	{ 0,		NULL }
569 };
570 
571 extern const struct tok ns_class2str[];
572 
573 const struct tok ns_class2str[] = {
574 	{ C_IN,		"IN" },		/* Not used */
575 	{ C_CHAOS,	"CHAOS" },
576 	{ C_HS,		"HS" },
577 	{ C_ANY,	"ANY" },
578 	{ 0,		NULL }
579 };
580 
581 const struct tok edns_opt2str[] = {
582     { E_LLQ,        "LLQ" },
583     { E_UL,         "UL" },
584     { E_NSID,       "NSID" },
585     { E_DAU,        "DAU" },
586     { E_DHU,        "DHU" },
587     { E_N3U,        "N3U" },
588     { E_ECS,        "ECS" },
589     { E_EXPIRE,     "EXPIRE" },
590     { E_COOKIE,     "COOKIE" },
591     { E_KEEPALIVE,  "KEEPALIVE" },
592     { E_PADDING,    "PADDING" },
593     { E_CHAIN,      "CHAIN" },
594     { E_KEYTAG,     "KEY-TAG" },
595     { E_CLIENTTAG,  "CLIENT-TAG" },
596     { E_SERVERTAG,  "SERVER-TAG" },
597     { 0,            NULL }
598 };
599 
600 const struct tok dau_alg2str[] = {
601     { A_DELETE,             "DELETE" },
602     { A_RSAMD5,             "RSAMD5" },
603     { A_DH,                 "DH" },
604     { A_DSA,                "DS" },
605     { A_RSASHA1,            "RSASHA1" },
606     { A_DSA_NSEC3_SHA1,     "DSA-NSEC3-SHA1" },
607     { A_RSASHA1_NSEC3_SHA1, "RSASHA1-NSEC3-SHA1" },
608     { A_RSASHA256,          "RSASHA256" },
609     { A_RSASHA512,          "RSASHA512" },
610     { A_ECC_GOST,           "ECC-GOST" },
611     { A_ECDSAP256SHA256,    "ECDSAP256SHA256" },
612     { A_ECDSAP384SHA384,    "ECDSAP384SHA384" },
613     { A_ED25519,            "ED25519" },
614     { A_ED448,              "ED448" },
615     { A_INDIRECT,           "INDIRECT" },
616     { A_PRIVATEDNS,         "PRIVATEDNS" },
617     { A_PRIVATEOID,         "PRIVATEOID" },
618     { 0,                NULL }
619 };
620 
621 const struct tok dhu_alg2str[] = {
622     { DS_SHA1,  "SHA-1" },
623     { DS_SHA256,"SHA-256" },
624     { DS_GOST,  "GOST_R_34.11-94" },
625     { DS_SHA384,"SHA-384" },
626     { 0,    NULL }
627 };
628 
629 const struct tok n3u_alg2str[] = {
630     { NSEC_SHA1,"SHA-1" },
631     { 0,    NULL }
632 };
633 
634 /* print a query */
635 static const u_char *
636 ns_qprint(netdissect_options *ndo,
637           const u_char *cp, const u_char *bp, int is_mdns)
638 {
639 	const u_char *np = cp;
640 	u_int i, class;
641 
642 	cp = ns_nskip(ndo, cp);
643 
644 	if (cp == NULL || !ND_TTEST_4(cp))
645 		return(NULL);
646 
647 	/* print the qtype */
648 	i = GET_BE_U_2(cp);
649 	cp += 2;
650 	ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", i));
651 	/* print the qclass (if it's not IN) */
652 	i = GET_BE_U_2(cp);
653 	cp += 2;
654 	if (is_mdns)
655 		class = (i & ~C_QU);
656 	else
657 		class = i;
658 	if (class != C_IN)
659 		ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class));
660 	if (is_mdns) {
661 		ND_PRINT(i & C_QU ? " (QU)" : " (QM)");
662 	}
663 
664 	ND_PRINT("? ");
665 	cp = fqdn_print(ndo, np, bp);
666 	return(cp ? cp + 4 : NULL);
667 }
668 
669 /* print a reply */
670 static const u_char *
671 ns_rprint(netdissect_options *ndo,
672           const u_char *cp, const u_char *bp, int is_mdns)
673 {
674 	u_int i, class, opt_flags = 0;
675 	u_short typ, len;
676 	const u_char *rp;
677 
678 	if (ndo->ndo_vflag) {
679 		ND_PRINT(" ");
680 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
681 			return NULL;
682 	} else
683 		cp = ns_nskip(ndo, cp);
684 
685 	if (cp == NULL || !ND_TTEST_LEN(cp, 10))
686 		return (ndo->ndo_snapend);
687 
688 	/* print the type/qtype */
689 	typ = GET_BE_U_2(cp);
690 	cp += 2;
691 	/* print the class (if it's not IN and the type isn't OPT) */
692 	i = GET_BE_U_2(cp);
693 	cp += 2;
694 	if (is_mdns)
695 		class = (i & ~C_CACHE_FLUSH);
696 	else
697 		class = i;
698 	if (class != C_IN && typ != T_OPT)
699 		ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class));
700 	if (is_mdns) {
701 		if (i & C_CACHE_FLUSH)
702 			ND_PRINT(" (Cache flush)");
703 	}
704 
705 	if (typ == T_OPT) {
706 		/* get opt flags */
707 		cp += 2;
708 		opt_flags = GET_BE_U_2(cp);
709 		/* ignore rest of ttl field */
710 		cp += 2;
711 	} else if (ndo->ndo_vflag > 2) {
712 		/* print ttl */
713 		ND_PRINT(" [");
714 		unsigned_relts_print(ndo, GET_BE_U_4(cp));
715 		ND_PRINT("]");
716 		cp += 4;
717 	} else {
718 		/* ignore ttl */
719 		cp += 4;
720 	}
721 
722 	len = GET_BE_U_2(cp);
723 	cp += 2;
724 
725 	rp = cp + len;
726 
727 	ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", typ));
728 	if (rp > ndo->ndo_snapend)
729 		return(NULL);
730 
731 	switch (typ) {
732 	case T_A:
733 		if (!ND_TTEST_LEN(cp, sizeof(nd_ipv4)))
734 			return(NULL);
735 		ND_PRINT(" %s", intoa(GET_IPV4_TO_NETWORK_ORDER(cp)));
736 		break;
737 
738 	case T_NS:
739 	case T_CNAME:
740 	case T_PTR:
741 	case T_DNAME:
742 		ND_PRINT(" ");
743 		if (fqdn_print(ndo, cp, bp) == NULL)
744 			return(NULL);
745 		break;
746 
747 	case T_SOA:
748 		if (!ndo->ndo_vflag)
749 			break;
750 		ND_PRINT(" ");
751 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
752 			return(NULL);
753 		ND_PRINT(" ");
754 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
755 			return(NULL);
756 		if (!ND_TTEST_LEN(cp, 5 * 4))
757 			return(NULL);
758 		ND_PRINT(" %u", GET_BE_U_4(cp));
759 		cp += 4;
760 		ND_PRINT(" %u", GET_BE_U_4(cp));
761 		cp += 4;
762 		ND_PRINT(" %u", GET_BE_U_4(cp));
763 		cp += 4;
764 		ND_PRINT(" %u", GET_BE_U_4(cp));
765 		cp += 4;
766 		ND_PRINT(" %u", GET_BE_U_4(cp));
767 		cp += 4;
768 		break;
769 	case T_MX:
770 		ND_PRINT(" ");
771 		if (!ND_TTEST_2(cp))
772 			return(NULL);
773 		if (fqdn_print(ndo, cp + 2, bp) == NULL)
774 			return(NULL);
775 		ND_PRINT(" %u", GET_BE_U_2(cp));
776 		break;
777 
778 	case T_TXT:
779 		while (cp < rp) {
780 			ND_PRINT(" \"");
781 			cp = ns_cprint(ndo, cp);
782 			if (cp == NULL)
783 				return(NULL);
784 			ND_PRINT("\"");
785 		}
786 		break;
787 
788 	case T_SRV:
789 		ND_PRINT(" ");
790 		if (!ND_TTEST_6(cp))
791 			return(NULL);
792 		if (fqdn_print(ndo, cp + 6, bp) == NULL)
793 			return(NULL);
794 		ND_PRINT(":%u %u %u", GET_BE_U_2(cp + 4),
795 			  GET_BE_U_2(cp), GET_BE_U_2(cp + 2));
796 		break;
797 
798 	case T_AAAA:
799 	    {
800 		char ntop_buf[INET6_ADDRSTRLEN];
801 
802 		if (!ND_TTEST_LEN(cp, sizeof(nd_ipv6)))
803 			return(NULL);
804 		ND_PRINT(" %s",
805 		    addrtostr6(cp, ntop_buf, sizeof(ntop_buf)));
806 
807 		break;
808 	    }
809 
810 	case T_A6:
811 	    {
812 		nd_ipv6 a;
813 		int pbit, pbyte;
814 		char ntop_buf[INET6_ADDRSTRLEN];
815 
816 		if (!ND_TTEST_1(cp))
817 			return(NULL);
818 		pbit = GET_U_1(cp);
819 		pbyte = (pbit & ~7) / 8;
820 		if (pbit > 128) {
821 			ND_PRINT(" %u(bad plen)", pbit);
822 			break;
823 		} else if (pbit < 128) {
824 			memset(a, 0, sizeof(a));
825 			GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte);
826 			ND_PRINT(" %u %s", pbit,
827 			    addrtostr6(&a, ntop_buf, sizeof(ntop_buf)));
828 		}
829 		if (pbit > 0) {
830 			ND_PRINT(" ");
831 			if (fqdn_print(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL)
832 				return(NULL);
833 		}
834 		break;
835 	    }
836 
837 	case T_URI:
838 		if (!ND_TTEST_LEN(cp, len))
839 			return(NULL);
840 		if (len < 4) {
841 			ND_PRINT(" len %u is too short (< 4)", len);
842 			break;
843 		}
844 		ND_PRINT(" %u %u ", GET_BE_U_2(cp), GET_BE_U_2(cp + 2));
845 		if (nd_printn(ndo, cp + 4, len - 4, ndo->ndo_snapend))
846 			return(NULL);
847 		break;
848 
849 	case T_OPT:
850 		ND_PRINT(" UDPsize=%u", class);
851 		if (opt_flags & 0x8000)
852 			ND_PRINT(" DO");
853         if (cp < rp) {
854             ND_PRINT(" [");
855             while (cp < rp) {
856                 cp = eopt_print(ndo, cp);
857                 if (cp == NULL)
858                     return(NULL);
859                 if (cp < rp)
860                     ND_PRINT(",");
861             }
862             ND_PRINT("]");
863         }
864 		break;
865 
866 	case T_TSIG:
867 	    {
868 		if (cp + len > ndo->ndo_snapend)
869 			return(NULL);
870 		if (!ndo->ndo_vflag)
871 			break;
872 		ND_PRINT(" ");
873 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
874 			return(NULL);
875 		cp += 6;
876 		if (!ND_TTEST_2(cp))
877 			return(NULL);
878 		ND_PRINT(" fudge=%u", GET_BE_U_2(cp));
879 		cp += 2;
880 		if (!ND_TTEST_2(cp))
881 			return(NULL);
882 		ND_PRINT(" maclen=%u", GET_BE_U_2(cp));
883 		cp += 2 + GET_BE_U_2(cp);
884 		if (!ND_TTEST_2(cp))
885 			return(NULL);
886 		ND_PRINT(" origid=%u", GET_BE_U_2(cp));
887 		cp += 2;
888 		if (!ND_TTEST_2(cp))
889 			return(NULL);
890 		ND_PRINT(" error=%u", GET_BE_U_2(cp));
891 		cp += 2;
892 		if (!ND_TTEST_2(cp))
893 			return(NULL);
894 		ND_PRINT(" otherlen=%u", GET_BE_U_2(cp));
895 		cp += 2;
896 	    }
897 	}
898 	return (rp);		/* XXX This isn't always right */
899 }
900 
901 void
902 domain_print(netdissect_options *ndo,
903              const u_char *bp, u_int length, int over_tcp, int is_mdns)
904 {
905 	const dns_header_t *np;
906 	uint16_t flags, rcode, rdlen, type;
907 	u_int qdcount, ancount, nscount, arcount;
908 	u_int i;
909 	const u_char *cp;
910 	uint16_t b2;
911 
912 	ndo->ndo_protocol = "domain";
913 
914 	if (over_tcp) {
915 		/*
916 		 * The message is prefixed with a two byte length field
917 		 * which gives the message length, excluding the two byte
918 		 * length field. (RFC 1035 - 4.2.2. TCP usage)
919 		 */
920 		if (length < 2) {
921 			ND_PRINT(" [DNS over TCP: length %u < 2]", length);
922 			nd_print_invalid(ndo);
923 			return;
924 		} else {
925 			length -= 2; /* excluding the two byte length field */
926 			if (GET_BE_U_2(bp) != length) {
927 				ND_PRINT(" [prefix length(%u) != length(%u)]",
928 					 GET_BE_U_2(bp), length);
929 				nd_print_invalid(ndo);
930 				return;
931 			} else {
932 				bp += 2;
933 				/* in over TCP case, we need to prepend a space
934 				 * (not needed in over UDP case)
935 				 */
936 				ND_PRINT(" ");
937 			}
938 		}
939 	}
940 
941 	np = (const dns_header_t *)bp;
942 
943 	if(length < sizeof(*np)) {
944 		nd_print_protocol(ndo);
945 		ND_PRINT(" [length %u < %zu]", length, sizeof(*np));
946 		nd_print_invalid(ndo);
947 		return;
948 	}
949 
950 	ND_TCHECK_SIZE(np);
951 	flags = GET_BE_U_2(np->flags);
952 	/* get the byte-order right */
953 	qdcount = GET_BE_U_2(np->qdcount);
954 	ancount = GET_BE_U_2(np->ancount);
955 	nscount = GET_BE_U_2(np->nscount);
956 	arcount = GET_BE_U_2(np->arcount);
957 
958 	/* find the opt record to extract extended rcode */
959 	cp = (const u_char *)(np + 1);
960 	rcode = DNS_RCODE(flags);
961 	for (i = 0; i < qdcount; i++) {
962 		if ((cp = ns_nskip(ndo, cp)) == NULL)
963 			goto print;
964 		cp += 4;	/* skip QTYPE and QCLASS */
965 		if (cp >= ndo->ndo_snapend)
966 			goto print;
967 	}
968 	for (i = 0; i < ancount + nscount; i++) {
969 		if ((cp = ns_nskip(ndo, cp)) == NULL)
970 			goto print;
971 		cp += 8;	/* skip TYPE, CLASS and TTL */
972 		if (cp + 2 > ndo->ndo_snapend)
973 			goto print;
974 		rdlen = GET_BE_U_2(cp);
975 		cp += 2 + rdlen;
976 		if (cp >= ndo->ndo_snapend)
977 			goto print;
978 	}
979 	for (i = 0; i < arcount; i++) {
980 		if ((cp = ns_nskip(ndo, cp)) == NULL)
981 			goto print;
982 		if (cp + 2 > ndo->ndo_snapend)
983 			goto print;
984 		type = GET_BE_U_2(cp);
985 		cp += 4;	/* skip TYPE and CLASS */
986 		if (cp + 1 > ndo->ndo_snapend)
987 			goto print;
988 		if (type == T_OPT) {
989 			rcode |= (GET_U_1(cp) << 4);
990 			goto print;
991 		}
992 		cp += 4;
993 		if (cp + 2 > ndo->ndo_snapend)
994 			goto print;
995 		rdlen = GET_BE_U_2(cp);
996 		cp += 2 + rdlen;
997 		if (cp >= ndo->ndo_snapend)
998 			goto print;
999 	}
1000 
1001  print:
1002 	if (DNS_QR(flags)) {
1003 		/* this is a response */
1004 		ND_PRINT("%u%s%s%s%s%s%s",
1005 			GET_BE_U_2(np->id),
1006 			ns_ops[DNS_OPCODE(flags)],
1007 			ns_rcode(rcode),
1008 			DNS_AA(flags)? "*" : "",
1009 			DNS_RA(flags)? "" : "-",
1010 			DNS_TC(flags)? "|" : "",
1011 			DNS_AD(flags)? "$" : "");
1012 
1013 		if (qdcount != 1)
1014 			ND_PRINT(" [%uq]", qdcount);
1015 		/* Print QUESTION section on -vv */
1016 		cp = (const u_char *)(np + 1);
1017 		for (i = 0; i < qdcount; i++) {
1018 			if (i != 0)
1019 				ND_PRINT(",");
1020 			if (ndo->ndo_vflag > 1) {
1021 				ND_PRINT(" q:");
1022 				if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL)
1023 					goto trunc;
1024 			} else {
1025 				if ((cp = ns_nskip(ndo, cp)) == NULL)
1026 					goto trunc;
1027 				cp += 4;	/* skip QTYPE and QCLASS */
1028 			}
1029 		}
1030 		ND_PRINT(" %u/%u/%u", ancount, nscount, arcount);
1031 		if (ancount) {
1032 			if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1033 				goto trunc;
1034 			ancount--;
1035 			while (cp < ndo->ndo_snapend && ancount) {
1036 				ND_PRINT(",");
1037 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1038 					goto trunc;
1039 				ancount--;
1040 			}
1041 		}
1042 		if (ancount)
1043 			goto trunc;
1044 		/* Print NS and AR sections on -vv */
1045 		if (ndo->ndo_vflag > 1) {
1046 			if (cp < ndo->ndo_snapend && nscount) {
1047 				ND_PRINT(" ns:");
1048 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1049 					goto trunc;
1050 				nscount--;
1051 				while (cp < ndo->ndo_snapend && nscount) {
1052 					ND_PRINT(",");
1053 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1054 						goto trunc;
1055 					nscount--;
1056 				}
1057 			}
1058 			if (nscount)
1059 				goto trunc;
1060 			if (cp < ndo->ndo_snapend && arcount) {
1061 				ND_PRINT(" ar:");
1062 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1063 					goto trunc;
1064 				arcount--;
1065 				while (cp < ndo->ndo_snapend && arcount) {
1066 					ND_PRINT(",");
1067 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1068 						goto trunc;
1069 					arcount--;
1070 				}
1071 			}
1072 			if (arcount)
1073 				goto trunc;
1074 		}
1075 	} else {
1076 		/* this is a request */
1077 		ND_PRINT("%u%s%s%s", GET_BE_U_2(np->id),
1078 			  ns_ops[DNS_OPCODE(flags)],
1079 			  DNS_RD(flags) ? "+" : "",
1080 			  DNS_CD(flags) ? "%" : "");
1081 
1082 		/* any weirdness? */
1083 		b2 = GET_BE_U_2(((const u_short *)np) + 1);
1084 		if (b2 & 0x6cf)
1085 			ND_PRINT(" [b2&3=0x%x]", b2);
1086 
1087 		if (DNS_OPCODE(flags) == IQUERY) {
1088 			if (qdcount)
1089 				ND_PRINT(" [%uq]", qdcount);
1090 			if (ancount != 1)
1091 				ND_PRINT(" [%ua]", ancount);
1092 		} else {
1093 			if (ancount)
1094 				ND_PRINT(" [%ua]", ancount);
1095 			if (qdcount != 1)
1096 				ND_PRINT(" [%uq]", qdcount);
1097 		}
1098 		if (nscount)
1099 			ND_PRINT(" [%un]", nscount);
1100 		if (arcount)
1101 			ND_PRINT(" [%uau]", arcount);
1102 
1103 		cp = (const u_char *)(np + 1);
1104 		if (qdcount) {
1105 			cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns);
1106 			if (!cp)
1107 				goto trunc;
1108 			qdcount--;
1109 			while (cp < ndo->ndo_snapend && qdcount) {
1110 				cp = ns_qprint(ndo, (const u_char *)cp,
1111 					       (const u_char *)np,
1112 					       is_mdns);
1113 				if (!cp)
1114 					goto trunc;
1115 				qdcount--;
1116 			}
1117 		}
1118 		if (qdcount)
1119 			goto trunc;
1120 
1121 		/* Print remaining sections on -vv */
1122 		if (ndo->ndo_vflag > 1) {
1123 			if (ancount) {
1124 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1125 					goto trunc;
1126 				ancount--;
1127 				while (cp < ndo->ndo_snapend && ancount) {
1128 					ND_PRINT(",");
1129 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1130 						goto trunc;
1131 					ancount--;
1132 				}
1133 			}
1134 			if (ancount)
1135 				goto trunc;
1136 			if (cp < ndo->ndo_snapend && nscount) {
1137 				ND_PRINT(" ns:");
1138 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1139 					goto trunc;
1140 				nscount--;
1141 				while (cp < ndo->ndo_snapend && nscount) {
1142 					ND_PRINT(",");
1143 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1144 						goto trunc;
1145 					nscount--;
1146 				}
1147 			}
1148 			if (nscount > 0)
1149 				goto trunc;
1150 			if (cp < ndo->ndo_snapend && arcount) {
1151 				ND_PRINT(" ar:");
1152 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1153 					goto trunc;
1154 				arcount--;
1155 				while (cp < ndo->ndo_snapend && arcount) {
1156 					ND_PRINT(",");
1157 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
1158 						goto trunc;
1159 					arcount--;
1160 				}
1161 			}
1162 			if (arcount)
1163 				goto trunc;
1164 		}
1165 	}
1166 	ND_PRINT(" (%u)", length);
1167 	return;
1168 
1169   trunc:
1170 	nd_print_trunc(ndo);
1171 }
1172