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