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