xref: /netbsd-src/external/bsd/tcpdump/dist/print-domain.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  */
210f74e101Schristos 
2211b3aaa1Schristos #include <sys/cdefs.h>
230f74e101Schristos #ifndef lint
24*26ba0b50Schristos __RCSID("$NetBSD: print-domain.c,v 1.11 2024/09/02 16:15:31 christos Exp $");
250f74e101Schristos #endif
260f74e101Schristos 
27dc860a36Sspz /* \summary: Domain Name System (DNS) printer */
28dc860a36Sspz 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
330f74e101Schristos #include <string.h>
340f74e101Schristos 
35fdccd7e4Schristos #include "netdissect.h"
360f74e101Schristos #include "addrtoname.h"
37fdccd7e4Schristos #include "addrtostr.h"
38fdccd7e4Schristos #include "extract.h"
390f74e101Schristos 
40c74ad251Schristos #include "nameser.h"
41c74ad251Schristos 
420f74e101Schristos static const char *ns_ops[] = {
430f74e101Schristos 	"", " inv_q", " stat", " op3", " notify", " update", " op6", " op7",
44b3a00663Schristos 	" op8", " updateA", " updateD", " updateDA",
450f74e101Schristos 	" updateM", " updateMA", " zoneInit", " zoneRef",
460f74e101Schristos };
470f74e101Schristos 
480f74e101Schristos static const char *ns_resp[] = {
490f74e101Schristos 	"", " FormErr", " ServFail", " NXDomain",
500f74e101Schristos 	" NotImp", " Refused", " YXDomain", " YXRRSet",
510f74e101Schristos 	" NXRRSet", " NotAuth", " NotZone", " Resp11",
520f74e101Schristos 	" Resp12", " Resp13", " Resp14", " NoChange",
53c74ad251Schristos 	" BadVers", "Resp17", " Resp18", " Resp19",
54c74ad251Schristos 	" Resp20", "Resp21", " Resp22", " BadCookie",
550f74e101Schristos };
560f74e101Schristos 
57c74ad251Schristos static const char *
58c74ad251Schristos ns_rcode(u_int rcode) {
59c74ad251Schristos 	static char buf[sizeof(" Resp4095")];
60c74ad251Schristos 
61c74ad251Schristos 	if (rcode < sizeof(ns_resp)/sizeof(ns_resp[0])) {
62c74ad251Schristos 		return (ns_resp[rcode]);
63c74ad251Schristos 	}
64c74ad251Schristos 	snprintf(buf, sizeof(buf), " Resp%u", rcode & 0xfff);
65c74ad251Schristos 	return (buf);
66c74ad251Schristos }
67c74ad251Schristos 
680f74e101Schristos /* skip over a domain name */
690f74e101Schristos static const u_char *
70b3a00663Schristos ns_nskip(netdissect_options *ndo,
71c74ad251Schristos          const u_char *cp)
720f74e101Schristos {
73c74ad251Schristos 	u_char i;
740f74e101Schristos 
75c74ad251Schristos 	if (!ND_TTEST_1(cp))
760f74e101Schristos 		return (NULL);
77c74ad251Schristos 	i = GET_U_1(cp);
78c74ad251Schristos 	cp++;
790f74e101Schristos 	while (i) {
80c74ad251Schristos 		switch (i & TYPE_MASK) {
81c74ad251Schristos 
82c74ad251Schristos 		case TYPE_INDIR:
830f74e101Schristos 			return (cp + 1);
84c74ad251Schristos 
85c74ad251Schristos 		case TYPE_EDNS0: {
860f74e101Schristos 			int bitlen, bytelen;
870f74e101Schristos 
88c74ad251Schristos 			if ((i & ~TYPE_MASK) != EDNS0_ELT_BITLABEL)
890f74e101Schristos 				return(NULL); /* unknown ELT */
90c74ad251Schristos 			if (!ND_TTEST_1(cp))
910f74e101Schristos 				return (NULL);
92c74ad251Schristos 			if ((bitlen = GET_U_1(cp)) == 0)
930f74e101Schristos 				bitlen = 256;
94c74ad251Schristos 			cp++;
950f74e101Schristos 			bytelen = (bitlen + 7) / 8;
960f74e101Schristos 			cp += bytelen;
97c74ad251Schristos 		}
98c74ad251Schristos 		break;
99c74ad251Schristos 
100c74ad251Schristos 		case TYPE_RESERVED:
1010f74e101Schristos 			return (NULL);
102c74ad251Schristos 
103c74ad251Schristos 		case TYPE_LABEL:
104c74ad251Schristos 			cp += i;
105c74ad251Schristos 			break;
106c74ad251Schristos 		}
107c74ad251Schristos 		if (!ND_TTEST_1(cp))
108c74ad251Schristos 			return (NULL);
109c74ad251Schristos 		i = GET_U_1(cp);
110c74ad251Schristos 		cp++;
1110f74e101Schristos 	}
1120f74e101Schristos 	return (cp);
1130f74e101Schristos }
1140f74e101Schristos 
1150f74e101Schristos static const u_char *
116b3a00663Schristos blabel_print(netdissect_options *ndo,
117b3a00663Schristos              const u_char *cp)
1180f74e101Schristos {
119c74ad251Schristos 	u_int bitlen, slen, b;
1200f74e101Schristos 	const u_char *bitp, *lim;
121c74ad251Schristos 	uint8_t tc;
1220f74e101Schristos 
123c74ad251Schristos 	if (!ND_TTEST_1(cp))
1240f74e101Schristos 		return(NULL);
125c74ad251Schristos 	if ((bitlen = GET_U_1(cp)) == 0)
1260f74e101Schristos 		bitlen = 256;
1270f74e101Schristos 	slen = (bitlen + 3) / 4;
1280f74e101Schristos 	lim = cp + 1 + slen;
1290f74e101Schristos 
1300f74e101Schristos 	/* print the bit string as a hex string */
131c74ad251Schristos 	ND_PRINT("\\[x");
1320f74e101Schristos 	for (bitp = cp + 1, b = bitlen; bitp < lim && b > 7; b -= 8, bitp++) {
133c74ad251Schristos 		ND_PRINT("%02x", GET_U_1(bitp));
1340f74e101Schristos 	}
1350f74e101Schristos 	if (b > 4) {
136c74ad251Schristos 		tc = GET_U_1(bitp);
137c74ad251Schristos 		bitp++;
138c74ad251Schristos 		ND_PRINT("%02x", tc & (0xff << (8 - b)));
1390f74e101Schristos 	} else if (b > 0) {
140c74ad251Schristos 		tc = GET_U_1(bitp);
141c74ad251Schristos 		bitp++;
142c74ad251Schristos 		ND_PRINT("%1x", ((tc >> 4) & 0x0f) & (0x0f << (4 - b)));
1430f74e101Schristos 	}
144c74ad251Schristos 	ND_PRINT("/%u]", bitlen);
1450f74e101Schristos 	return lim;
1460f74e101Schristos }
1470f74e101Schristos 
1480f74e101Schristos static int
149b3a00663Schristos labellen(netdissect_options *ndo,
150b3a00663Schristos          const u_char *cp)
1510f74e101Schristos {
152c74ad251Schristos 	u_int i;
1530f74e101Schristos 
154c74ad251Schristos 	if (!ND_TTEST_1(cp))
1550f74e101Schristos 		return(-1);
156c74ad251Schristos 	i = GET_U_1(cp);
157c74ad251Schristos 	switch (i & TYPE_MASK) {
158c74ad251Schristos 
159c74ad251Schristos 	case TYPE_EDNS0: {
160c74ad251Schristos 		u_int bitlen, elt;
161c74ad251Schristos 		if ((elt = (i & ~TYPE_MASK)) != EDNS0_ELT_BITLABEL) {
162c74ad251Schristos 			ND_PRINT("<ELT %d>", elt);
1630f74e101Schristos 			return(-1);
1640f74e101Schristos 		}
165c74ad251Schristos 		if (!ND_TTEST_1(cp + 1))
1660f74e101Schristos 			return(-1);
167c74ad251Schristos 		if ((bitlen = GET_U_1(cp + 1)) == 0)
1680f74e101Schristos 			bitlen = 256;
1690f74e101Schristos 		return(((bitlen + 7) / 8) + 1);
1700f74e101Schristos 	}
1710f74e101Schristos 
172c74ad251Schristos 	case TYPE_INDIR:
173c74ad251Schristos 	case TYPE_LABEL:
174c74ad251Schristos 		return(i);
175c74ad251Schristos 
176c74ad251Schristos 	default:
177c74ad251Schristos 		/*
178c74ad251Schristos 		 * TYPE_RESERVED, but we use default to suppress compiler
179c74ad251Schristos 		 * warnings about falling out of the switch statement.
180c74ad251Schristos 		 */
181c74ad251Schristos 		ND_PRINT("<BAD LABEL TYPE>");
182c74ad251Schristos 		return(-1);
183c74ad251Schristos 	}
184c74ad251Schristos }
185c74ad251Schristos 
186c74ad251Schristos /* print a <domain-name> */
187870189d2Schristos const u_char *
188c74ad251Schristos fqdn_print(netdissect_options *ndo,
189c74ad251Schristos           const u_char *cp, const u_char *bp)
1900f74e101Schristos {
191c74ad251Schristos 	u_int i, l;
192c74ad251Schristos 	const u_char *rp = NULL;
193c74ad251Schristos 	int compress = 0;
194c74ad251Schristos 	u_int elt;
19572c96ff3Schristos 	u_int offset, max_offset;
196c74ad251Schristos 	u_int name_chars = 0;
1970f74e101Schristos 
198b3a00663Schristos 	if ((l = labellen(ndo, cp)) == (u_int)-1)
1990f74e101Schristos 		return(NULL);
200c74ad251Schristos 	if (!ND_TTEST_1(cp))
2010f74e101Schristos 		return(NULL);
20272c96ff3Schristos 	max_offset = (u_int)(cp - bp);
203c74ad251Schristos 	i = GET_U_1(cp);
204c74ad251Schristos 	cp++;
205c74ad251Schristos 	if ((i & TYPE_MASK) != TYPE_INDIR) {
2060f74e101Schristos 		compress = 0;
2070f74e101Schristos 		rp = cp + l;
2080f74e101Schristos 	}
2090f74e101Schristos 
210c74ad251Schristos 	if (i != 0) {
211b3a00663Schristos 		while (i && cp < ndo->ndo_snapend) {
212c74ad251Schristos 			switch (i & TYPE_MASK) {
213c74ad251Schristos 
214c74ad251Schristos 			case TYPE_INDIR:
2150f74e101Schristos 				if (!compress) {
2160f74e101Schristos 					rp = cp + 1;
2170f74e101Schristos 					compress = 1;
2180f74e101Schristos 				}
219c74ad251Schristos 				if (!ND_TTEST_1(cp))
2200f74e101Schristos 					return(NULL);
221c74ad251Schristos 				offset = (((i << 8) | GET_U_1(cp)) & 0x3fff);
22272c96ff3Schristos 				/*
22372c96ff3Schristos 				 * This must move backwards in the packet.
22472c96ff3Schristos 				 * No RFC explicitly says that, but BIND's
22572c96ff3Schristos 				 * name decompression code requires it,
22672c96ff3Schristos 				 * as a way of preventing infinite loops
22772c96ff3Schristos 				 * and other bad behavior, and it's probably
22872c96ff3Schristos 				 * what was intended (compress by pointing
22972c96ff3Schristos 				 * to domain name suffixes already seen in
23072c96ff3Schristos 				 * the packet).
23172c96ff3Schristos 				 */
23272c96ff3Schristos 				if (offset >= max_offset) {
233c74ad251Schristos 					ND_PRINT("<BAD PTR>");
23472c96ff3Schristos 					return(NULL);
23572c96ff3Schristos 				}
23672c96ff3Schristos 				max_offset = offset;
23772c96ff3Schristos 				cp = bp + offset;
238c74ad251Schristos 				if (!ND_TTEST_1(cp))
239c74ad251Schristos 					return(NULL);
240c74ad251Schristos 				i = GET_U_1(cp);
241b3a00663Schristos 				if ((l = labellen(ndo, cp)) == (u_int)-1)
2420f74e101Schristos 					return(NULL);
243c74ad251Schristos 				cp++;
2440f74e101Schristos 				continue;
245c74ad251Schristos 
246c74ad251Schristos 			case TYPE_EDNS0:
247c74ad251Schristos 				elt = (i & ~TYPE_MASK);
2480f74e101Schristos 				switch(elt) {
2490f74e101Schristos 				case EDNS0_ELT_BITLABEL:
250b3a00663Schristos 					if (blabel_print(ndo, cp) == NULL)
2510f74e101Schristos 						return (NULL);
2520f74e101Schristos 					break;
2530f74e101Schristos 				default:
2540f74e101Schristos 					/* unknown ELT */
255c74ad251Schristos 					ND_PRINT("<ELT %u>", elt);
2560f74e101Schristos 					return(NULL);
2570f74e101Schristos 				}
258c74ad251Schristos 				break;
259c74ad251Schristos 
260c74ad251Schristos 			case TYPE_RESERVED:
261c74ad251Schristos 				ND_PRINT("<BAD LABEL TYPE>");
2620f74e101Schristos 				return(NULL);
263c74ad251Schristos 
264c74ad251Schristos 			case TYPE_LABEL:
265c74ad251Schristos 				if (name_chars + l <= MAXCDNAME) {
266c74ad251Schristos 					if (nd_printn(ndo, cp, l, ndo->ndo_snapend))
267c74ad251Schristos 						return(NULL);
268c74ad251Schristos 				} else if (name_chars < MAXCDNAME) {
269c74ad251Schristos 					if (nd_printn(ndo, cp,
270c74ad251Schristos 					    MAXCDNAME - name_chars, ndo->ndo_snapend))
271c74ad251Schristos 						return(NULL);
272c74ad251Schristos 				}
273c74ad251Schristos 				name_chars += l;
274c74ad251Schristos 				break;
2750f74e101Schristos 			}
2760f74e101Schristos 
2770f74e101Schristos 			cp += l;
278c74ad251Schristos 			if (name_chars <= MAXCDNAME)
279c74ad251Schristos 				ND_PRINT(".");
280c74ad251Schristos 			name_chars++;
281c74ad251Schristos 			if (!ND_TTEST_1(cp))
282c74ad251Schristos 				return(NULL);
283c74ad251Schristos 			i = GET_U_1(cp);
284b3a00663Schristos 			if ((l = labellen(ndo, cp)) == (u_int)-1)
2850f74e101Schristos 				return(NULL);
286c74ad251Schristos 			cp++;
2870f74e101Schristos 			if (!compress)
2880f74e101Schristos 				rp += l + 1;
2890f74e101Schristos 		}
290c74ad251Schristos 		if (name_chars > MAXCDNAME)
291c74ad251Schristos 			ND_PRINT("<DOMAIN NAME TOO LONG>");
292c74ad251Schristos 	} else
293c74ad251Schristos 		ND_PRINT(".");
2940f74e101Schristos 	return (rp);
2950f74e101Schristos }
2960f74e101Schristos 
2970f74e101Schristos /* print a <character-string> */
2980f74e101Schristos static const u_char *
299b3a00663Schristos ns_cprint(netdissect_options *ndo,
300c74ad251Schristos           const u_char *cp)
3010f74e101Schristos {
302c74ad251Schristos 	u_int i;
3030f74e101Schristos 
304c74ad251Schristos 	if (!ND_TTEST_1(cp))
3050f74e101Schristos 		return (NULL);
306c74ad251Schristos 	i = GET_U_1(cp);
307c74ad251Schristos 	cp++;
308c74ad251Schristos 	if (nd_printn(ndo, cp, i, ndo->ndo_snapend))
3090f74e101Schristos 		return (NULL);
3100f74e101Schristos 	return (cp + i);
3110f74e101Schristos }
3120f74e101Schristos 
313c74ad251Schristos static void
314c74ad251Schristos print_eopt_ecs(netdissect_options *ndo, const u_char *cp,
315c74ad251Schristos                u_int data_len)
316c74ad251Schristos {
317c74ad251Schristos     u_int family, addr_bits, src_len, scope_len;
318c74ad251Schristos 
319c74ad251Schristos     u_char padded[32];
320c74ad251Schristos     char addr[INET6_ADDRSTRLEN];
321c74ad251Schristos 
322c74ad251Schristos     /* ecs option must at least contain family, src len, and scope len */
323c74ad251Schristos     if (data_len < 4) {
324c74ad251Schristos         nd_print_invalid(ndo);
325c74ad251Schristos         return;
326c74ad251Schristos     }
327c74ad251Schristos 
328c74ad251Schristos     family = GET_BE_U_2(cp);
329c74ad251Schristos     cp += 2;
330c74ad251Schristos     src_len = GET_U_1(cp);
331c74ad251Schristos     cp += 1;
332c74ad251Schristos     scope_len = GET_U_1(cp);
333c74ad251Schristos     cp += 1;
334c74ad251Schristos 
335c74ad251Schristos     if (family == 1)
336c74ad251Schristos         addr_bits = 32;
337c74ad251Schristos     else if (family == 2)
338c74ad251Schristos         addr_bits = 128;
339c74ad251Schristos     else {
340c74ad251Schristos         nd_print_invalid(ndo);
341c74ad251Schristos         return;
342c74ad251Schristos     }
343c74ad251Schristos 
344c74ad251Schristos     if (data_len - 4 > (addr_bits / 8)) {
345c74ad251Schristos         nd_print_invalid(ndo);
346c74ad251Schristos         return;
347c74ad251Schristos     }
348c74ad251Schristos     /* checks for invalid ecs scope or source length */
349c74ad251Schristos     if (src_len > addr_bits || scope_len > addr_bits || ((src_len + 7) / 8) != (data_len - 4)) {
350c74ad251Schristos         nd_print_invalid(ndo);
351c74ad251Schristos         return;
352c74ad251Schristos     }
353c74ad251Schristos 
354c74ad251Schristos     /* pad the truncated address from ecs with zeros */
355c74ad251Schristos     memset(padded, 0, sizeof(padded));
356c74ad251Schristos     memcpy(padded, cp, data_len - 4);
357c74ad251Schristos 
358c74ad251Schristos 
359c74ad251Schristos     if (family == 1)
360c74ad251Schristos         ND_PRINT("%s/%d/%d", addrtostr(padded, addr, INET_ADDRSTRLEN),
361c74ad251Schristos                 src_len, scope_len);
362c74ad251Schristos     else
363c74ad251Schristos         ND_PRINT("%s/%d/%d", addrtostr6(padded, addr, INET6_ADDRSTRLEN),
364c74ad251Schristos                 src_len, scope_len);
365c74ad251Schristos 
366c74ad251Schristos }
367c74ad251Schristos 
368c74ad251Schristos extern const struct tok edns_opt2str[];
369c74ad251Schristos extern const struct tok dau_alg2str[];
370c74ad251Schristos extern const struct tok dhu_alg2str[];
371c74ad251Schristos extern const struct tok n3u_alg2str[];
372c74ad251Schristos 
373c74ad251Schristos 
374c74ad251Schristos /* print an <EDNS-option> */
375c74ad251Schristos static const u_char *
376c74ad251Schristos eopt_print(netdissect_options *ndo,
377c74ad251Schristos           const u_char *cp)
378c74ad251Schristos {
379c74ad251Schristos     u_int opt, data_len, i;
380c74ad251Schristos 
381c74ad251Schristos     if (!ND_TTEST_2(cp))
382c74ad251Schristos         return (NULL);
383c74ad251Schristos     opt = GET_BE_U_2(cp);
384c74ad251Schristos     cp += 2;
385c74ad251Schristos     ND_PRINT("%s", tok2str(edns_opt2str, "Opt%u", opt));
386c74ad251Schristos     if (!ND_TTEST_2(cp))
387c74ad251Schristos         return (NULL);
388c74ad251Schristos     data_len = GET_BE_U_2(cp);
389c74ad251Schristos     cp += 2;
390c74ad251Schristos 
391c74ad251Schristos     ND_TCHECK_LEN(cp, data_len);
392c74ad251Schristos 
393c74ad251Schristos     if (data_len > 0) {
394c74ad251Schristos         ND_PRINT(" ");
395c74ad251Schristos         switch (opt) {
396c74ad251Schristos 
397c74ad251Schristos         case E_ECS:
398c74ad251Schristos             print_eopt_ecs(ndo, cp, data_len);
399c74ad251Schristos             break;
400c74ad251Schristos         case E_COOKIE:
401c74ad251Schristos             if (data_len < 8 || (data_len > 8 && data_len < 16) || data_len > 40)
402c74ad251Schristos                 nd_print_invalid(ndo);
403c74ad251Schristos             else {
404c74ad251Schristos                 for (i = 0; i < data_len; ++i) {
405c74ad251Schristos                     /* split client and server cookie */
406c74ad251Schristos                     if (i == 8)
407c74ad251Schristos                         ND_PRINT(" ");
408c74ad251Schristos                     ND_PRINT("%02x", GET_U_1(cp + i));
409c74ad251Schristos                 }
410c74ad251Schristos             }
411c74ad251Schristos             break;
412c74ad251Schristos         case E_KEEPALIVE:
413c74ad251Schristos             if (data_len != 2)
414c74ad251Schristos                 nd_print_invalid(ndo);
415c74ad251Schristos             else
416c74ad251Schristos                 /* keepalive is in increments of 100ms. Convert to seconds */
417c74ad251Schristos                 ND_PRINT("%0.1f sec", (GET_BE_U_2(cp) / 10.0));
418c74ad251Schristos             break;
419c74ad251Schristos         case E_EXPIRE:
420c74ad251Schristos             if (data_len != 4)
421c74ad251Schristos                 nd_print_invalid(ndo);
422c74ad251Schristos             else
423c74ad251Schristos                 ND_PRINT("%u sec", GET_BE_U_4(cp));
424c74ad251Schristos             break;
425c74ad251Schristos         case E_PADDING:
426c74ad251Schristos             /* ignore contents and just print length */
427c74ad251Schristos             ND_PRINT("(%u)", data_len);
428c74ad251Schristos             break;
429c74ad251Schristos         case E_KEYTAG:
430c74ad251Schristos             if (data_len % 2 != 0)
431c74ad251Schristos                 nd_print_invalid(ndo);
432c74ad251Schristos             else
433c74ad251Schristos                 for (i = 0; i < data_len; i += 2) {
434c74ad251Schristos                     if (i > 0)
435c74ad251Schristos                         ND_PRINT(" ");
436c74ad251Schristos                     ND_PRINT("%u", GET_BE_U_2(cp + i));
437c74ad251Schristos                 }
438c74ad251Schristos             break;
439c74ad251Schristos         case E_DAU:
440c74ad251Schristos             for (i = 0; i < data_len; ++i) {
441c74ad251Schristos                 if (i > 0)
442c74ad251Schristos                     ND_PRINT(" ");
443c74ad251Schristos                 ND_PRINT("%s", tok2str(dau_alg2str, "Alg_%u", GET_U_1(cp + i)));
444c74ad251Schristos             }
445c74ad251Schristos             break;
446c74ad251Schristos         case E_DHU:
447c74ad251Schristos             for (i = 0; i < data_len; ++i) {
448c74ad251Schristos                 if (i > 0)
449c74ad251Schristos                     ND_PRINT(" ");
450c74ad251Schristos                 ND_PRINT("%s", tok2str(dhu_alg2str, "Alg_%u", GET_U_1(cp + i)));
451c74ad251Schristos             }
452c74ad251Schristos             break;
453c74ad251Schristos         case E_N3U:
454c74ad251Schristos             for (i = 0; i < data_len; ++i) {
455c74ad251Schristos                 if (i > 0)
456c74ad251Schristos                     ND_PRINT(" ");
457c74ad251Schristos                 ND_PRINT("%s", tok2str(n3u_alg2str, "Alg_%u", GET_U_1(cp + i)));
458c74ad251Schristos             }
459c74ad251Schristos             break;
460c74ad251Schristos         case E_CHAIN:
461c74ad251Schristos             fqdn_print(ndo, cp, cp + data_len);
462c74ad251Schristos             break;
463c74ad251Schristos         case E_NSID:
464c74ad251Schristos             /* intentional fall-through. NSID is an undefined byte string */
465c74ad251Schristos         default:
466c74ad251Schristos             for (i = 0; i < data_len; ++i)
467c74ad251Schristos                 ND_PRINT("%02x", GET_U_1(cp + i));
468c74ad251Schristos             break;
469c74ad251Schristos         }
470c74ad251Schristos     }
471c74ad251Schristos     return (cp + data_len);
472c74ad251Schristos 
473c74ad251Schristos   trunc:
474c74ad251Schristos     return (NULL);
475c74ad251Schristos 
476c74ad251Schristos }
477c74ad251Schristos 
478c74ad251Schristos 
479c74ad251Schristos 
480c74ad251Schristos extern const struct tok ns_type2str[];
481c74ad251Schristos 
482c74ad251Schristos /* https://www.iana.org/assignments/dns-parameters */
483870189d2Schristos const struct tok ns_type2str[] = {
4840f74e101Schristos 	{ T_A,		"A" },			/* RFC 1035 */
4850f74e101Schristos 	{ T_NS,		"NS" },			/* RFC 1035 */
4860f74e101Schristos 	{ T_MD,		"MD" },			/* RFC 1035 */
4870f74e101Schristos 	{ T_MF,		"MF" },			/* RFC 1035 */
4880f74e101Schristos 	{ T_CNAME,	"CNAME" },		/* RFC 1035 */
4890f74e101Schristos 	{ T_SOA,	"SOA" },		/* RFC 1035 */
4900f74e101Schristos 	{ T_MB,		"MB" },			/* RFC 1035 */
4910f74e101Schristos 	{ T_MG,		"MG" },			/* RFC 1035 */
4920f74e101Schristos 	{ T_MR,		"MR" },			/* RFC 1035 */
4930f74e101Schristos 	{ T_NULL,	"NULL" },		/* RFC 1035 */
4940f74e101Schristos 	{ T_WKS,	"WKS" },		/* RFC 1035 */
4950f74e101Schristos 	{ T_PTR,	"PTR" },		/* RFC 1035 */
4960f74e101Schristos 	{ T_HINFO,	"HINFO" },		/* RFC 1035 */
4970f74e101Schristos 	{ T_MINFO,	"MINFO" },		/* RFC 1035 */
4980f74e101Schristos 	{ T_MX,		"MX" },			/* RFC 1035 */
4990f74e101Schristos 	{ T_TXT,	"TXT" },		/* RFC 1035 */
5000f74e101Schristos 	{ T_RP,		"RP" },			/* RFC 1183 */
501c74ad251Schristos 	{ T_AFSDB,	"AFSDB" },		/* RFC 5864 */
5020f74e101Schristos 	{ T_X25,	"X25" },		/* RFC 1183 */
5030f74e101Schristos 	{ T_ISDN,	"ISDN" },		/* RFC 1183 */
5040f74e101Schristos 	{ T_RT,		"RT" },			/* RFC 1183 */
5050f74e101Schristos 	{ T_NSAP,	"NSAP" },		/* RFC 1706 */
506c74ad251Schristos 	{ T_NSAP_PTR,	"NSAP_PTR" },		/* RFC 1706 */
507c74ad251Schristos 	{ T_SIG,	"SIG" },		/* RFC 3008 */
508c74ad251Schristos 	{ T_KEY,	"KEY" },		/* RFC 3110 */
5090f74e101Schristos 	{ T_PX,		"PX" },			/* RFC 2163 */
5100f74e101Schristos 	{ T_GPOS,	"GPOS" },		/* RFC 1712 */
511c74ad251Schristos 	{ T_AAAA,	"AAAA" },		/* RFC 3596 */
5120f74e101Schristos 	{ T_LOC,	"LOC" },		/* RFC 1876 */
513c74ad251Schristos 	{ T_NXT,	"NXT" },		/* RFC 3755 */
5140f74e101Schristos 	{ T_EID,	"EID" },		/* Nimrod */
5150f74e101Schristos 	{ T_NIMLOC,	"NIMLOC" },		/* Nimrod */
5160f74e101Schristos 	{ T_SRV,	"SRV" },		/* RFC 2782 */
5170f74e101Schristos 	{ T_ATMA,	"ATMA" },		/* ATM Forum */
518c74ad251Schristos 	{ T_NAPTR,	"NAPTR" },		/* RFC 3403 */
5190f74e101Schristos 	{ T_KX,		"KX" },			/* RFC 2230 */
520c74ad251Schristos 	{ T_CERT,	"CERT" },		/* RFC 4398 */
521c74ad251Schristos 	{ T_A6,		"A6" },			/* RFC 6563 */
522c74ad251Schristos 	{ T_DNAME,	"DNAME" },		/* RFC 6672 */
5230f74e101Schristos 	{ T_SINK,	"SINK" },
524c74ad251Schristos 	{ T_OPT,	"OPT" },		/* RFC 6891 */
5250f74e101Schristos 	{ T_APL,	"APL" },		/* RFC 3123 */
5260f74e101Schristos 	{ T_DS,		"DS" },			/* RFC 4034 */
5270f74e101Schristos 	{ T_SSHFP,	"SSHFP" },		/* RFC 4255 */
5280f74e101Schristos 	{ T_IPSECKEY,	"IPSECKEY" },		/* RFC 4025 */
5290f74e101Schristos 	{ T_RRSIG,	"RRSIG" },		/* RFC 4034 */
5300f74e101Schristos 	{ T_NSEC,	"NSEC" },		/* RFC 4034 */
5310f74e101Schristos 	{ T_DNSKEY,	"DNSKEY" },		/* RFC 4034 */
532c74ad251Schristos 	{ T_DHCID,	"DHCID" },		/* RFC 4071 */
533c74ad251Schristos 	{ T_NSEC3,	"NSEC3" },		/* RFC 5155 */
534c74ad251Schristos 	{ T_NSEC3PARAM,	"NSEC3PARAM" },		/* RFC 5155 */
535c74ad251Schristos 	{ T_TLSA,	"TLSA" },		/* RFC 6698 */
536c74ad251Schristos 	{ T_SMIMEA,	"SMIMEA" },		/* RFC 8162 */
537c74ad251Schristos 	{ T_HIP,	"HIP" },		/* RFC 8005 */
538c74ad251Schristos 	{ T_NINFO,	"NINFO" },
539c74ad251Schristos 	{ T_RKEY,	"RKEY" },
540c74ad251Schristos 	{ T_TALINK,	"TALINK" },
541c74ad251Schristos 	{ T_CDS,	"CDS" },		/* RFC 7344 */
542c74ad251Schristos 	{ T_CDNSKEY,	"CDNSKEY" },		/* RFC 7344 */
543c74ad251Schristos 	{ T_OPENPGPKEY,	"OPENPGPKEY" },		/* RFC 7929 */
544c74ad251Schristos 	{ T_CSYNC,	"CSYNC" },		/* RFC 7477 */
545c74ad251Schristos 	{ T_ZONEMD,	"ZONEMD" },		/* RFC 8976 */
546c74ad251Schristos 	{ T_SVCB,	"SVCB" },
547c74ad251Schristos 	{ T_HTTPS,	"HTTPS" },
548c74ad251Schristos 	{ T_SPF,	"SPF" },		/* RFC 7208 */
5490f74e101Schristos 	{ T_UINFO,	"UINFO" },
5500f74e101Schristos 	{ T_UID,	"UID" },
5510f74e101Schristos 	{ T_GID,	"GID" },
5520f74e101Schristos 	{ T_UNSPEC,	"UNSPEC" },
553c74ad251Schristos 	{ T_NID,	"NID" },		/* RFC 6742 */
554c74ad251Schristos 	{ T_L32,	"L32" },		/* RFC 6742 */
555c74ad251Schristos 	{ T_L64,	"L64" },		/* RFC 6742 */
556c74ad251Schristos 	{ T_LP,		"LP" },			/* RFC 6742 */
557c74ad251Schristos 	{ T_EUI48,	"EUI48" },		/* RFC 7043 */
558c74ad251Schristos 	{ T_EUI64,	"EUI64" },		/* RFC 7043 */
5590f74e101Schristos 	{ T_TKEY,	"TKEY" },		/* RFC 2930 */
560c74ad251Schristos 	{ T_TSIG,	"TSIG" },		/* RFC 8945 */
5610f74e101Schristos 	{ T_IXFR,	"IXFR" },		/* RFC 1995 */
562c74ad251Schristos 	{ T_AXFR,	"AXFR" },		/* RFC 5936 */
5630f74e101Schristos 	{ T_MAILB,	"MAILB" },		/* RFC 1035 */
5640f74e101Schristos 	{ T_MAILA,	"MAILA" },		/* RFC 1035 */
565c74ad251Schristos 	{ T_ANY,	"ANY" },		/* RFC 8482 */
566c74ad251Schristos 	{ T_URI,	"URI" },		/* RFC 7553 */
567c74ad251Schristos 	{ T_CAA,	"CAA" },		/* RFC 8659 */
568c74ad251Schristos 	{ T_AVC,	"AVC" },
569c74ad251Schristos 	{ T_DOA,	"DOA" },
570c74ad251Schristos 	{ T_AMTRELAY,	"AMTRELAY" },		/* RFC 8777 */
571c74ad251Schristos 	{ T_TA,		"TA" },
572c74ad251Schristos 	{ T_DLV,	"DLV" },		/* RFC 8749 */
5730f74e101Schristos 	{ 0,		NULL }
5740f74e101Schristos };
5750f74e101Schristos 
576c74ad251Schristos extern const struct tok ns_class2str[];
577c74ad251Schristos 
578870189d2Schristos const struct tok ns_class2str[] = {
5790f74e101Schristos 	{ C_IN,		"IN" },		/* Not used */
5800f74e101Schristos 	{ C_CHAOS,	"CHAOS" },
5810f74e101Schristos 	{ C_HS,		"HS" },
5820f74e101Schristos 	{ C_ANY,	"ANY" },
5830f74e101Schristos 	{ 0,		NULL }
5840f74e101Schristos };
5850f74e101Schristos 
586c74ad251Schristos const struct tok edns_opt2str[] = {
587c74ad251Schristos     { E_LLQ,        "LLQ" },
588c74ad251Schristos     { E_UL,         "UL" },
589c74ad251Schristos     { E_NSID,       "NSID" },
590c74ad251Schristos     { E_DAU,        "DAU" },
591c74ad251Schristos     { E_DHU,        "DHU" },
592c74ad251Schristos     { E_N3U,        "N3U" },
593c74ad251Schristos     { E_ECS,        "ECS" },
594c74ad251Schristos     { E_EXPIRE,     "EXPIRE" },
595c74ad251Schristos     { E_COOKIE,     "COOKIE" },
596c74ad251Schristos     { E_KEEPALIVE,  "KEEPALIVE" },
597c74ad251Schristos     { E_PADDING,    "PADDING" },
598c74ad251Schristos     { E_CHAIN,      "CHAIN" },
599c74ad251Schristos     { E_KEYTAG,     "KEY-TAG" },
600c74ad251Schristos     { E_CLIENTTAG,  "CLIENT-TAG" },
601c74ad251Schristos     { E_SERVERTAG,  "SERVER-TAG" },
602c74ad251Schristos     { 0,            NULL }
603c74ad251Schristos };
604c74ad251Schristos 
605c74ad251Schristos const struct tok dau_alg2str[] = {
606c74ad251Schristos     { A_DELETE,             "DELETE" },
607c74ad251Schristos     { A_RSAMD5,             "RSAMD5" },
608c74ad251Schristos     { A_DH,                 "DH" },
609c74ad251Schristos     { A_DSA,                "DS" },
610c74ad251Schristos     { A_RSASHA1,            "RSASHA1" },
611c74ad251Schristos     { A_DSA_NSEC3_SHA1,     "DSA-NSEC3-SHA1" },
612c74ad251Schristos     { A_RSASHA1_NSEC3_SHA1, "RSASHA1-NSEC3-SHA1" },
613c74ad251Schristos     { A_RSASHA256,          "RSASHA256" },
614c74ad251Schristos     { A_RSASHA512,          "RSASHA512" },
615c74ad251Schristos     { A_ECC_GOST,           "ECC-GOST" },
616c74ad251Schristos     { A_ECDSAP256SHA256,    "ECDSAP256SHA256" },
617c74ad251Schristos     { A_ECDSAP384SHA384,    "ECDSAP384SHA384" },
618c74ad251Schristos     { A_ED25519,            "ED25519" },
619c74ad251Schristos     { A_ED448,              "ED448" },
620c74ad251Schristos     { A_INDIRECT,           "INDIRECT" },
621c74ad251Schristos     { A_PRIVATEDNS,         "PRIVATEDNS" },
622c74ad251Schristos     { A_PRIVATEOID,         "PRIVATEOID" },
623c74ad251Schristos     { 0,                NULL }
624c74ad251Schristos };
625c74ad251Schristos 
626c74ad251Schristos const struct tok dhu_alg2str[] = {
627c74ad251Schristos     { DS_SHA1,  "SHA-1" },
628c74ad251Schristos     { DS_SHA256,"SHA-256" },
629c74ad251Schristos     { DS_GOST,  "GOST_R_34.11-94" },
630c74ad251Schristos     { DS_SHA384,"SHA-384" },
631c74ad251Schristos     { 0,    NULL }
632c74ad251Schristos };
633c74ad251Schristos 
634c74ad251Schristos const struct tok n3u_alg2str[] = {
635c74ad251Schristos     { NSEC_SHA1,"SHA-1" },
636c74ad251Schristos     { 0,    NULL }
637c74ad251Schristos };
638c74ad251Schristos 
6390f74e101Schristos /* print a query */
6400f74e101Schristos static const u_char *
641b3a00663Schristos ns_qprint(netdissect_options *ndo,
642c74ad251Schristos           const u_char *cp, const u_char *bp, int is_mdns)
6430f74e101Schristos {
644c74ad251Schristos 	const u_char *np = cp;
645c74ad251Schristos 	u_int i, class;
6460f74e101Schristos 
647b3a00663Schristos 	cp = ns_nskip(ndo, cp);
6480f74e101Schristos 
649c74ad251Schristos 	if (cp == NULL || !ND_TTEST_4(cp))
6500f74e101Schristos 		return(NULL);
6510f74e101Schristos 
6520f74e101Schristos 	/* print the qtype */
653c74ad251Schristos 	i = GET_BE_U_2(cp);
6540f74e101Schristos 	cp += 2;
655c74ad251Schristos 	ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", i));
6560f74e101Schristos 	/* print the qclass (if it's not IN) */
657c74ad251Schristos 	i = GET_BE_U_2(cp);
6580f74e101Schristos 	cp += 2;
6590f74e101Schristos 	if (is_mdns)
6600f74e101Schristos 		class = (i & ~C_QU);
6610f74e101Schristos 	else
6620f74e101Schristos 		class = i;
6630f74e101Schristos 	if (class != C_IN)
664c74ad251Schristos 		ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class));
6650f74e101Schristos 	if (is_mdns) {
666c74ad251Schristos 		ND_PRINT(i & C_QU ? " (QU)" : " (QM)");
6670f74e101Schristos 	}
6680f74e101Schristos 
669c74ad251Schristos 	ND_PRINT("? ");
670c74ad251Schristos 	cp = fqdn_print(ndo, np, bp);
6710f74e101Schristos 	return(cp ? cp + 4 : NULL);
6720f74e101Schristos }
6730f74e101Schristos 
6740f74e101Schristos /* print a reply */
6750f74e101Schristos static const u_char *
676b3a00663Schristos ns_rprint(netdissect_options *ndo,
677c74ad251Schristos           const u_char *cp, const u_char *bp, int is_mdns)
6780f74e101Schristos {
679c74ad251Schristos 	u_int i, class, opt_flags = 0;
680c74ad251Schristos 	u_short typ, len;
681c74ad251Schristos 	const u_char *rp;
6820f74e101Schristos 
683b3a00663Schristos 	if (ndo->ndo_vflag) {
684c74ad251Schristos 		ND_PRINT(" ");
685c74ad251Schristos 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
6860f74e101Schristos 			return NULL;
6870f74e101Schristos 	} else
688b3a00663Schristos 		cp = ns_nskip(ndo, cp);
6890f74e101Schristos 
690c74ad251Schristos 	if (cp == NULL || !ND_TTEST_LEN(cp, 10))
691b3a00663Schristos 		return (ndo->ndo_snapend);
6920f74e101Schristos 
6930f74e101Schristos 	/* print the type/qtype */
694c74ad251Schristos 	typ = GET_BE_U_2(cp);
6950f74e101Schristos 	cp += 2;
6960f74e101Schristos 	/* print the class (if it's not IN and the type isn't OPT) */
697c74ad251Schristos 	i = GET_BE_U_2(cp);
6980f74e101Schristos 	cp += 2;
6990f74e101Schristos 	if (is_mdns)
7000f74e101Schristos 		class = (i & ~C_CACHE_FLUSH);
7010f74e101Schristos 	else
7020f74e101Schristos 		class = i;
7030f74e101Schristos 	if (class != C_IN && typ != T_OPT)
704c74ad251Schristos 		ND_PRINT(" %s", tok2str(ns_class2str, "(Class %u)", class));
7050f74e101Schristos 	if (is_mdns) {
7060f74e101Schristos 		if (i & C_CACHE_FLUSH)
707c74ad251Schristos 			ND_PRINT(" (Cache flush)");
7080f74e101Schristos 	}
7090f74e101Schristos 
7100f74e101Schristos 	if (typ == T_OPT) {
7110f74e101Schristos 		/* get opt flags */
7120f74e101Schristos 		cp += 2;
713c74ad251Schristos 		opt_flags = GET_BE_U_2(cp);
7140f74e101Schristos 		/* ignore rest of ttl field */
7150f74e101Schristos 		cp += 2;
716b3a00663Schristos 	} else if (ndo->ndo_vflag > 2) {
7170f74e101Schristos 		/* print ttl */
718c74ad251Schristos 		ND_PRINT(" [");
719c74ad251Schristos 		unsigned_relts_print(ndo, GET_BE_U_4(cp));
720c74ad251Schristos 		ND_PRINT("]");
7210f74e101Schristos 		cp += 4;
7220f74e101Schristos 	} else {
7230f74e101Schristos 		/* ignore ttl */
7240f74e101Schristos 		cp += 4;
7250f74e101Schristos 	}
7260f74e101Schristos 
727c74ad251Schristos 	len = GET_BE_U_2(cp);
7280f74e101Schristos 	cp += 2;
7290f74e101Schristos 
7300f74e101Schristos 	rp = cp + len;
7310f74e101Schristos 
732c74ad251Schristos 	ND_PRINT(" %s", tok2str(ns_type2str, "Type%u", typ));
733b3a00663Schristos 	if (rp > ndo->ndo_snapend)
7340f74e101Schristos 		return(NULL);
7350f74e101Schristos 
7360f74e101Schristos 	switch (typ) {
7370f74e101Schristos 	case T_A:
738c74ad251Schristos 		if (!ND_TTEST_LEN(cp, sizeof(nd_ipv4)))
7390f74e101Schristos 			return(NULL);
740c74ad251Schristos 		ND_PRINT(" %s", intoa(GET_IPV4_TO_NETWORK_ORDER(cp)));
7410f74e101Schristos 		break;
7420f74e101Schristos 
7430f74e101Schristos 	case T_NS:
7440f74e101Schristos 	case T_CNAME:
7450f74e101Schristos 	case T_PTR:
7460f74e101Schristos 	case T_DNAME:
747c74ad251Schristos 		ND_PRINT(" ");
748c74ad251Schristos 		if (fqdn_print(ndo, cp, bp) == NULL)
7490f74e101Schristos 			return(NULL);
7500f74e101Schristos 		break;
7510f74e101Schristos 
7520f74e101Schristos 	case T_SOA:
753b3a00663Schristos 		if (!ndo->ndo_vflag)
7540f74e101Schristos 			break;
755c74ad251Schristos 		ND_PRINT(" ");
756c74ad251Schristos 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
7570f74e101Schristos 			return(NULL);
758c74ad251Schristos 		ND_PRINT(" ");
759c74ad251Schristos 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
7600f74e101Schristos 			return(NULL);
761c74ad251Schristos 		if (!ND_TTEST_LEN(cp, 5 * 4))
7620f74e101Schristos 			return(NULL);
763c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_4(cp));
7640f74e101Schristos 		cp += 4;
765c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_4(cp));
7660f74e101Schristos 		cp += 4;
767c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_4(cp));
7680f74e101Schristos 		cp += 4;
769c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_4(cp));
7700f74e101Schristos 		cp += 4;
771c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_4(cp));
7720f74e101Schristos 		cp += 4;
7730f74e101Schristos 		break;
7740f74e101Schristos 	case T_MX:
775c74ad251Schristos 		ND_PRINT(" ");
776c74ad251Schristos 		if (!ND_TTEST_2(cp))
7770f74e101Schristos 			return(NULL);
778c74ad251Schristos 		if (fqdn_print(ndo, cp + 2, bp) == NULL)
7790f74e101Schristos 			return(NULL);
780c74ad251Schristos 		ND_PRINT(" %u", GET_BE_U_2(cp));
7810f74e101Schristos 		break;
7820f74e101Schristos 
7830f74e101Schristos 	case T_TXT:
7840f74e101Schristos 		while (cp < rp) {
785c74ad251Schristos 			ND_PRINT(" \"");
786b3a00663Schristos 			cp = ns_cprint(ndo, cp);
7870f74e101Schristos 			if (cp == NULL)
7880f74e101Schristos 				return(NULL);
789c74ad251Schristos 			ND_PRINT("\"");
7900f74e101Schristos 		}
7910f74e101Schristos 		break;
7920f74e101Schristos 
7930f74e101Schristos 	case T_SRV:
794c74ad251Schristos 		ND_PRINT(" ");
795c74ad251Schristos 		if (!ND_TTEST_6(cp))
7960f74e101Schristos 			return(NULL);
797c74ad251Schristos 		if (fqdn_print(ndo, cp + 6, bp) == NULL)
7980f74e101Schristos 			return(NULL);
799c74ad251Schristos 		ND_PRINT(":%u %u %u", GET_BE_U_2(cp + 4),
800c74ad251Schristos 			  GET_BE_U_2(cp), GET_BE_U_2(cp + 2));
8010f74e101Schristos 		break;
8020f74e101Schristos 
8030f74e101Schristos 	case T_AAAA:
8040f74e101Schristos 	    {
8050f74e101Schristos 		char ntop_buf[INET6_ADDRSTRLEN];
8060f74e101Schristos 
807c74ad251Schristos 		if (!ND_TTEST_LEN(cp, sizeof(nd_ipv6)))
8080f74e101Schristos 			return(NULL);
809c74ad251Schristos 		ND_PRINT(" %s",
810c74ad251Schristos 		    addrtostr6(cp, ntop_buf, sizeof(ntop_buf)));
8110f74e101Schristos 
8120f74e101Schristos 		break;
8130f74e101Schristos 	    }
8140f74e101Schristos 
8150f74e101Schristos 	case T_A6:
8160f74e101Schristos 	    {
817c74ad251Schristos 		nd_ipv6 a;
8180f74e101Schristos 		int pbit, pbyte;
8190f74e101Schristos 		char ntop_buf[INET6_ADDRSTRLEN];
8200f74e101Schristos 
821c74ad251Schristos 		if (!ND_TTEST_1(cp))
8220f74e101Schristos 			return(NULL);
823c74ad251Schristos 		pbit = GET_U_1(cp);
8240f74e101Schristos 		pbyte = (pbit & ~7) / 8;
8250f74e101Schristos 		if (pbit > 128) {
826c74ad251Schristos 			ND_PRINT(" %u(bad plen)", pbit);
8270f74e101Schristos 			break;
8280f74e101Schristos 		} else if (pbit < 128) {
829c74ad251Schristos 			memset(a, 0, sizeof(a));
830c74ad251Schristos 			GET_CPY_BYTES(a + pbyte, cp + 1, sizeof(a) - pbyte);
831c74ad251Schristos 			ND_PRINT(" %u %s", pbit,
832c74ad251Schristos 			    addrtostr6(&a, ntop_buf, sizeof(ntop_buf)));
8330f74e101Schristos 		}
8340f74e101Schristos 		if (pbit > 0) {
835c74ad251Schristos 			ND_PRINT(" ");
836c74ad251Schristos 			if (fqdn_print(ndo, cp + 1 + sizeof(a) - pbyte, bp) == NULL)
8370f74e101Schristos 				return(NULL);
8380f74e101Schristos 		}
8390f74e101Schristos 		break;
8400f74e101Schristos 	    }
8410f74e101Schristos 
842c74ad251Schristos 	case T_URI:
843c74ad251Schristos 		if (!ND_TTEST_LEN(cp, len))
844c74ad251Schristos 			return(NULL);
845*26ba0b50Schristos 		if (len < 4) {
846*26ba0b50Schristos 			ND_PRINT(" len %u is too short (< 4)", len);
847*26ba0b50Schristos 			break;
848*26ba0b50Schristos 		}
849c74ad251Schristos 		ND_PRINT(" %u %u ", GET_BE_U_2(cp), GET_BE_U_2(cp + 2));
850c74ad251Schristos 		if (nd_printn(ndo, cp + 4, len - 4, ndo->ndo_snapend))
851c74ad251Schristos 			return(NULL);
852c74ad251Schristos 		break;
853c74ad251Schristos 
8540f74e101Schristos 	case T_OPT:
855c74ad251Schristos 		ND_PRINT(" UDPsize=%u", class);
8560f74e101Schristos 		if (opt_flags & 0x8000)
857c74ad251Schristos 			ND_PRINT(" DO");
858c74ad251Schristos         if (cp < rp) {
859c74ad251Schristos             ND_PRINT(" [");
860c74ad251Schristos             while (cp < rp) {
861c74ad251Schristos                 cp = eopt_print(ndo, cp);
862c74ad251Schristos                 if (cp == NULL)
8630f74e101Schristos                     return(NULL);
864c74ad251Schristos                 if (cp < rp)
865c74ad251Schristos                     ND_PRINT(",");
866c74ad251Schristos             }
867c74ad251Schristos             ND_PRINT("]");
868c74ad251Schristos         }
8690f74e101Schristos 		break;
8700f74e101Schristos 
8710f74e101Schristos 	case T_TSIG:
8720f74e101Schristos 	    {
873b3a00663Schristos 		if (cp + len > ndo->ndo_snapend)
8740f74e101Schristos 			return(NULL);
875b3a00663Schristos 		if (!ndo->ndo_vflag)
8760f74e101Schristos 			break;
877c74ad251Schristos 		ND_PRINT(" ");
878c74ad251Schristos 		if ((cp = fqdn_print(ndo, cp, bp)) == NULL)
8790f74e101Schristos 			return(NULL);
8800f74e101Schristos 		cp += 6;
881c74ad251Schristos 		if (!ND_TTEST_2(cp))
8820f74e101Schristos 			return(NULL);
883c74ad251Schristos 		ND_PRINT(" fudge=%u", GET_BE_U_2(cp));
8840f74e101Schristos 		cp += 2;
885c74ad251Schristos 		if (!ND_TTEST_2(cp))
8860f74e101Schristos 			return(NULL);
887c74ad251Schristos 		ND_PRINT(" maclen=%u", GET_BE_U_2(cp));
888c74ad251Schristos 		cp += 2 + GET_BE_U_2(cp);
889c74ad251Schristos 		if (!ND_TTEST_2(cp))
8900f74e101Schristos 			return(NULL);
891c74ad251Schristos 		ND_PRINT(" origid=%u", GET_BE_U_2(cp));
8920f74e101Schristos 		cp += 2;
893c74ad251Schristos 		if (!ND_TTEST_2(cp))
8940f74e101Schristos 			return(NULL);
895c74ad251Schristos 		ND_PRINT(" error=%u", GET_BE_U_2(cp));
8960f74e101Schristos 		cp += 2;
897c74ad251Schristos 		if (!ND_TTEST_2(cp))
8980f74e101Schristos 			return(NULL);
899c74ad251Schristos 		ND_PRINT(" otherlen=%u", GET_BE_U_2(cp));
9000f74e101Schristos 		cp += 2;
9010f74e101Schristos 	    }
9020f74e101Schristos 	}
9030f74e101Schristos 	return (rp);		/* XXX This isn't always right */
9040f74e101Schristos }
9050f74e101Schristos 
9060f74e101Schristos void
907c74ad251Schristos domain_print(netdissect_options *ndo,
908c74ad251Schristos              const u_char *bp, u_int length, int over_tcp, int is_mdns)
9090f74e101Schristos {
910c74ad251Schristos 	const dns_header_t *np;
911c74ad251Schristos 	uint16_t flags, rcode, rdlen, type;
912c74ad251Schristos 	u_int qdcount, ancount, nscount, arcount;
913c74ad251Schristos 	u_int i;
914c74ad251Schristos 	const u_char *cp;
915b3a00663Schristos 	uint16_t b2;
9160f74e101Schristos 
917c74ad251Schristos 	ndo->ndo_protocol = "domain";
918c74ad251Schristos 
919c74ad251Schristos 	if (over_tcp) {
920c74ad251Schristos 		/*
921c74ad251Schristos 		 * The message is prefixed with a two byte length field
922c74ad251Schristos 		 * which gives the message length, excluding the two byte
923c74ad251Schristos 		 * length field. (RFC 1035 - 4.2.2. TCP usage)
924c74ad251Schristos 		 */
925c74ad251Schristos 		if (length < 2) {
926c74ad251Schristos 			ND_PRINT(" [DNS over TCP: length %u < 2]", length);
927c74ad251Schristos 			nd_print_invalid(ndo);
928c74ad251Schristos 			return;
929c74ad251Schristos 		} else {
930c74ad251Schristos 			length -= 2; /* excluding the two byte length field */
931c74ad251Schristos 			if (GET_BE_U_2(bp) != length) {
932c74ad251Schristos 				ND_PRINT(" [prefix length(%u) != length(%u)]",
933c74ad251Schristos 					 GET_BE_U_2(bp), length);
934c74ad251Schristos 				nd_print_invalid(ndo);
935c74ad251Schristos 				return;
936c74ad251Schristos 			} else {
937c74ad251Schristos 				bp += 2;
938c74ad251Schristos 				/* in over TCP case, we need to prepend a space
939c74ad251Schristos 				 * (not needed in over UDP case)
940c74ad251Schristos 				 */
941c74ad251Schristos 				ND_PRINT(" ");
942c74ad251Schristos 			}
943c74ad251Schristos 		}
944c74ad251Schristos 	}
945c74ad251Schristos 
946c74ad251Schristos 	np = (const dns_header_t *)bp;
947c74ad251Schristos 
948817e9a7eSchristos 	if(length < sizeof(*np)) {
949c74ad251Schristos 		nd_print_protocol(ndo);
950c74ad251Schristos 		ND_PRINT(" [length %u < %zu]", length, sizeof(*np));
951c74ad251Schristos 		nd_print_invalid(ndo);
952817e9a7eSchristos 		return;
953817e9a7eSchristos 	}
954817e9a7eSchristos 
955c74ad251Schristos 	ND_TCHECK_SIZE(np);
956c74ad251Schristos 	flags = GET_BE_U_2(np->flags);
9570f74e101Schristos 	/* get the byte-order right */
958c74ad251Schristos 	qdcount = GET_BE_U_2(np->qdcount);
959c74ad251Schristos 	ancount = GET_BE_U_2(np->ancount);
960c74ad251Schristos 	nscount = GET_BE_U_2(np->nscount);
961c74ad251Schristos 	arcount = GET_BE_U_2(np->arcount);
9620f74e101Schristos 
963c74ad251Schristos 	/* find the opt record to extract extended rcode */
964c74ad251Schristos 	cp = (const u_char *)(np + 1);
965c74ad251Schristos 	rcode = DNS_RCODE(flags);
966c74ad251Schristos 	for (i = 0; i < qdcount; i++) {
967c74ad251Schristos 		if ((cp = ns_nskip(ndo, cp)) == NULL)
968c74ad251Schristos 			goto print;
969c74ad251Schristos 		cp += 4;	/* skip QTYPE and QCLASS */
970c74ad251Schristos 		if (cp >= ndo->ndo_snapend)
971c74ad251Schristos 			goto print;
972c74ad251Schristos 	}
973c74ad251Schristos 	for (i = 0; i < ancount + nscount; i++) {
974c74ad251Schristos 		if ((cp = ns_nskip(ndo, cp)) == NULL)
975c74ad251Schristos 			goto print;
976c74ad251Schristos 		cp += 8;	/* skip TYPE, CLASS and TTL */
977c74ad251Schristos 		if (cp + 2 > ndo->ndo_snapend)
978c74ad251Schristos 			goto print;
979c74ad251Schristos 		rdlen = GET_BE_U_2(cp);
980c74ad251Schristos 		cp += 2 + rdlen;
981c74ad251Schristos 		if (cp >= ndo->ndo_snapend)
982c74ad251Schristos 			goto print;
983c74ad251Schristos 	}
984c74ad251Schristos 	for (i = 0; i < arcount; i++) {
985c74ad251Schristos 		if ((cp = ns_nskip(ndo, cp)) == NULL)
986c74ad251Schristos 			goto print;
987c74ad251Schristos 		if (cp + 2 > ndo->ndo_snapend)
988c74ad251Schristos 			goto print;
989c74ad251Schristos 		type = GET_BE_U_2(cp);
990c74ad251Schristos 		cp += 4;	/* skip TYPE and CLASS */
991c74ad251Schristos 		if (cp + 1 > ndo->ndo_snapend)
992c74ad251Schristos 			goto print;
993c74ad251Schristos 		if (type == T_OPT) {
994c74ad251Schristos 			rcode |= (GET_U_1(cp) << 4);
995c74ad251Schristos 			goto print;
996c74ad251Schristos 		}
997c74ad251Schristos 		cp += 4;
998c74ad251Schristos 		if (cp + 2 > ndo->ndo_snapend)
999c74ad251Schristos 			goto print;
1000c74ad251Schristos 		rdlen = GET_BE_U_2(cp);
1001c74ad251Schristos 		cp += 2 + rdlen;
1002c74ad251Schristos 		if (cp >= ndo->ndo_snapend)
1003c74ad251Schristos 			goto print;
1004c74ad251Schristos 	}
1005c74ad251Schristos 
1006c74ad251Schristos  print:
1007c74ad251Schristos 	if (DNS_QR(flags)) {
10080f74e101Schristos 		/* this is a response */
1009c74ad251Schristos 		ND_PRINT("%u%s%s%s%s%s%s",
1010c74ad251Schristos 			GET_BE_U_2(np->id),
1011c74ad251Schristos 			ns_ops[DNS_OPCODE(flags)],
1012c74ad251Schristos 			ns_rcode(rcode),
1013c74ad251Schristos 			DNS_AA(flags)? "*" : "",
1014c74ad251Schristos 			DNS_RA(flags)? "" : "-",
1015c74ad251Schristos 			DNS_TC(flags)? "|" : "",
1016c74ad251Schristos 			DNS_AD(flags)? "$" : "");
10170f74e101Schristos 
10180f74e101Schristos 		if (qdcount != 1)
1019c74ad251Schristos 			ND_PRINT(" [%uq]", qdcount);
10200f74e101Schristos 		/* Print QUESTION section on -vv */
10210f74e101Schristos 		cp = (const u_char *)(np + 1);
1022c74ad251Schristos 		for (i = 0; i < qdcount; i++) {
1023c74ad251Schristos 			if (i != 0)
1024c74ad251Schristos 				ND_PRINT(",");
1025b3a00663Schristos 			if (ndo->ndo_vflag > 1) {
1026c74ad251Schristos 				ND_PRINT(" q:");
1027b3a00663Schristos 				if ((cp = ns_qprint(ndo, cp, bp, is_mdns)) == NULL)
10280f74e101Schristos 					goto trunc;
10290f74e101Schristos 			} else {
1030b3a00663Schristos 				if ((cp = ns_nskip(ndo, cp)) == NULL)
10310f74e101Schristos 					goto trunc;
10320f74e101Schristos 				cp += 4;	/* skip QTYPE and QCLASS */
10330f74e101Schristos 			}
10340f74e101Schristos 		}
1035c74ad251Schristos 		ND_PRINT(" %u/%u/%u", ancount, nscount, arcount);
1036c74ad251Schristos 		if (ancount) {
1037b3a00663Schristos 			if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10380f74e101Schristos 				goto trunc;
1039c74ad251Schristos 			ancount--;
1040c74ad251Schristos 			while (cp < ndo->ndo_snapend && ancount) {
1041c74ad251Schristos 				ND_PRINT(",");
1042b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10430f74e101Schristos 					goto trunc;
1044c74ad251Schristos 				ancount--;
10450f74e101Schristos 			}
10460f74e101Schristos 		}
1047c74ad251Schristos 		if (ancount)
10480f74e101Schristos 			goto trunc;
10490f74e101Schristos 		/* Print NS and AR sections on -vv */
1050b3a00663Schristos 		if (ndo->ndo_vflag > 1) {
1051c74ad251Schristos 			if (cp < ndo->ndo_snapend && nscount) {
1052c74ad251Schristos 				ND_PRINT(" ns:");
1053b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10540f74e101Schristos 					goto trunc;
1055c74ad251Schristos 				nscount--;
1056c74ad251Schristos 				while (cp < ndo->ndo_snapend && nscount) {
1057c74ad251Schristos 					ND_PRINT(",");
1058b3a00663Schristos 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10590f74e101Schristos 						goto trunc;
1060c74ad251Schristos 					nscount--;
10610f74e101Schristos 				}
10620f74e101Schristos 			}
1063c74ad251Schristos 			if (nscount)
10640f74e101Schristos 				goto trunc;
1065c74ad251Schristos 			if (cp < ndo->ndo_snapend && arcount) {
1066c74ad251Schristos 				ND_PRINT(" ar:");
1067b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10680f74e101Schristos 					goto trunc;
1069c74ad251Schristos 				arcount--;
1070c74ad251Schristos 				while (cp < ndo->ndo_snapend && arcount) {
1071c74ad251Schristos 					ND_PRINT(",");
1072b3a00663Schristos 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
10730f74e101Schristos 						goto trunc;
1074c74ad251Schristos 					arcount--;
10750f74e101Schristos 				}
10760f74e101Schristos 			}
1077c74ad251Schristos 			if (arcount)
10780f74e101Schristos 				goto trunc;
10790f74e101Schristos 		}
1080*26ba0b50Schristos 	} else {
10810f74e101Schristos 		/* this is a request */
1082c74ad251Schristos 		ND_PRINT("%u%s%s%s", GET_BE_U_2(np->id),
1083c74ad251Schristos 			  ns_ops[DNS_OPCODE(flags)],
1084c74ad251Schristos 			  DNS_RD(flags) ? "+" : "",
1085c74ad251Schristos 			  DNS_CD(flags) ? "%" : "");
10860f74e101Schristos 
10870f74e101Schristos 		/* any weirdness? */
1088c74ad251Schristos 		b2 = GET_BE_U_2(((const u_short *)np) + 1);
10890f74e101Schristos 		if (b2 & 0x6cf)
1090c74ad251Schristos 			ND_PRINT(" [b2&3=0x%x]", b2);
10910f74e101Schristos 
1092c74ad251Schristos 		if (DNS_OPCODE(flags) == IQUERY) {
10930f74e101Schristos 			if (qdcount)
1094c74ad251Schristos 				ND_PRINT(" [%uq]", qdcount);
10950f74e101Schristos 			if (ancount != 1)
1096c74ad251Schristos 				ND_PRINT(" [%ua]", ancount);
1097*26ba0b50Schristos 		} else {
10980f74e101Schristos 			if (ancount)
1099c74ad251Schristos 				ND_PRINT(" [%ua]", ancount);
11000f74e101Schristos 			if (qdcount != 1)
1101c74ad251Schristos 				ND_PRINT(" [%uq]", qdcount);
11020f74e101Schristos 		}
11030f74e101Schristos 		if (nscount)
1104c74ad251Schristos 			ND_PRINT(" [%un]", nscount);
11050f74e101Schristos 		if (arcount)
1106c74ad251Schristos 			ND_PRINT(" [%uau]", arcount);
11070f74e101Schristos 
11080f74e101Schristos 		cp = (const u_char *)(np + 1);
1109c74ad251Schristos 		if (qdcount) {
1110b3a00663Schristos 			cp = ns_qprint(ndo, cp, (const u_char *)np, is_mdns);
11110f74e101Schristos 			if (!cp)
11120f74e101Schristos 				goto trunc;
1113c74ad251Schristos 			qdcount--;
1114c74ad251Schristos 			while (cp < ndo->ndo_snapend && qdcount) {
1115b3a00663Schristos 				cp = ns_qprint(ndo, (const u_char *)cp,
11160f74e101Schristos 					       (const u_char *)np,
11170f74e101Schristos 					       is_mdns);
11180f74e101Schristos 				if (!cp)
11190f74e101Schristos 					goto trunc;
1120c74ad251Schristos 				qdcount--;
11210f74e101Schristos 			}
11220f74e101Schristos 		}
1123c74ad251Schristos 		if (qdcount)
11240f74e101Schristos 			goto trunc;
11250f74e101Schristos 
11260f74e101Schristos 		/* Print remaining sections on -vv */
1127b3a00663Schristos 		if (ndo->ndo_vflag > 1) {
1128c74ad251Schristos 			if (ancount) {
1129b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11300f74e101Schristos 					goto trunc;
1131c74ad251Schristos 				ancount--;
1132c74ad251Schristos 				while (cp < ndo->ndo_snapend && ancount) {
1133c74ad251Schristos 					ND_PRINT(",");
1134b3a00663Schristos 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11350f74e101Schristos 						goto trunc;
1136c74ad251Schristos 					ancount--;
11370f74e101Schristos 				}
11380f74e101Schristos 			}
1139c74ad251Schristos 			if (ancount)
11400f74e101Schristos 				goto trunc;
1141c74ad251Schristos 			if (cp < ndo->ndo_snapend && nscount) {
1142c74ad251Schristos 				ND_PRINT(" ns:");
1143b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11440f74e101Schristos 					goto trunc;
1145c74ad251Schristos 				nscount--;
1146c74ad251Schristos 				while (cp < ndo->ndo_snapend && nscount) {
1147c74ad251Schristos 					ND_PRINT(",");
1148b3a00663Schristos 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11490f74e101Schristos 						goto trunc;
1150c74ad251Schristos 					nscount--;
11510f74e101Schristos 				}
11520f74e101Schristos 			}
11530f74e101Schristos 			if (nscount > 0)
11540f74e101Schristos 				goto trunc;
1155c74ad251Schristos 			if (cp < ndo->ndo_snapend && arcount) {
1156c74ad251Schristos 				ND_PRINT(" ar:");
1157b3a00663Schristos 				if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11580f74e101Schristos 					goto trunc;
1159c74ad251Schristos 				arcount--;
1160c74ad251Schristos 				while (cp < ndo->ndo_snapend && arcount) {
1161c74ad251Schristos 					ND_PRINT(",");
1162b3a00663Schristos 					if ((cp = ns_rprint(ndo, cp, bp, is_mdns)) == NULL)
11630f74e101Schristos 						goto trunc;
1164c74ad251Schristos 					arcount--;
11650f74e101Schristos 				}
11660f74e101Schristos 			}
1167c74ad251Schristos 			if (arcount)
11680f74e101Schristos 				goto trunc;
11690f74e101Schristos 		}
11700f74e101Schristos 	}
1171c74ad251Schristos 	ND_PRINT(" (%u)", length);
11720f74e101Schristos 	return;
11730f74e101Schristos 
11740f74e101Schristos   trunc:
1175c74ad251Schristos 	nd_print_trunc(ndo);
11760f74e101Schristos }
1177