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