xref: /freebsd/contrib/tcpdump/print-domain.c (revision 3ff369fed2a08f32dda232c10470b949bef9489f)
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.2.1 2001/02/21 09:01:20 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 	TCHECK(*np);
561 	/* get the byte-order right */
562 	qdcount = ntohs(np->qdcount);
563 	ancount = ntohs(np->ancount);
564 	nscount = ntohs(np->nscount);
565 	arcount = ntohs(np->arcount);
566 
567 	if (DNS_QR(np)) {
568 		/* this is a response */
569 		printf(" %d%s%s%s%s%s%s",
570 			ntohs(np->id),
571 			ns_ops[DNS_OPCODE(np)],
572 			ns_resp[DNS_RCODE(np)],
573 			DNS_AA(np)? "*" : "",
574 			DNS_RA(np)? "" : "-",
575 			DNS_TC(np)? "|" : "",
576 			DNS_CD(np)? "%" : "");
577 
578 		if (qdcount != 1)
579 			printf(" [%dq]", qdcount);
580 		/* Print QUESTION section on -vv */
581 		if (vflag > 1) {
582 			fputs(" q:", stdout);
583 			if ((cp = ns_qprint((const u_char *)(np + 1), bp))
584 			    == NULL)
585 				goto trunc;
586 		} else {
587 			if ((cp = ns_nskip((const u_char *)(np + 1), bp))
588 			    == NULL)
589 				goto trunc;
590 			cp += 4;
591 		}
592 		printf(" %d/%d/%d", ancount, nscount, arcount);
593 		if (ancount--) {
594 			if ((cp = ns_rprint(cp, bp)) == NULL)
595 				goto trunc;
596 			while (ancount-- && cp < snapend) {
597 				putchar(',');
598 				if ((cp = ns_rprint(cp, bp)) == NULL)
599 					goto trunc;
600 			}
601 		}
602 		/* Print NS and AR sections on -vv */
603 		if (vflag > 1) {
604 			if (nscount-- && cp < snapend) {
605 				fputs(" ns:", stdout);
606 				if ((cp = ns_rprint(cp, bp)) == NULL)
607 					goto trunc;
608 				while (nscount-- && cp < snapend) {
609 					putchar(',');
610 					if ((cp = ns_rprint(cp, bp)) == NULL)
611 						goto trunc;
612 				}
613 			}
614 			if (arcount-- && cp < snapend) {
615 				fputs(" ar:", stdout);
616 				if ((cp = ns_rprint(cp, bp)) == NULL)
617 					goto trunc;
618 				while (arcount-- && cp < snapend) {
619 					putchar(',');
620 					if ((cp = ns_rprint(cp, bp)) == NULL)
621 						goto trunc;
622 				}
623 			}
624 		}
625 	}
626 	else {
627 		/* this is a request */
628 		printf(" %d%s%s%s", ntohs(np->id), ns_ops[DNS_OPCODE(np)],
629 		    DNS_RD(np) ? "+" : "",
630 		    DNS_AD(np) ? "$" : "");
631 
632 		/* any weirdness? */
633 		if (*(((u_short *)np)+1) & htons(0x6cf))
634 			printf(" [b2&3=0x%x]", ntohs(*(((u_short *)np)+1)));
635 
636 		if (DNS_OPCODE(np) == IQUERY) {
637 			if (qdcount)
638 				printf(" [%dq]", qdcount);
639 			if (ancount != 1)
640 				printf(" [%da]", ancount);
641 		}
642 		else {
643 			if (ancount)
644 				printf(" [%da]", ancount);
645 			if (qdcount != 1)
646 				printf(" [%dq]", qdcount);
647 		}
648 		if (nscount)
649 			printf(" [%dn]", nscount);
650 		if (arcount)
651 			printf(" [%dau]", arcount);
652 
653 		if (qdcount--) {
654 			cp = ns_qprint((const u_char *)(np + 1),
655 				       (const u_char *)np);
656 			if (!cp)
657 				goto trunc;
658 			if ((cp = ns_rprint(cp, bp)) == NULL)
659 				goto trunc;
660 			while (qdcount-- && cp < snapend) {
661 				cp = ns_qprint((const u_char *)cp,
662 					       (const u_char *)np);
663 				if (!cp)
664 					goto trunc;
665 				if ((cp = ns_rprint(cp, bp)) == NULL)
666 					goto trunc;
667 			}
668 		}
669 
670 		/* Print remaining sections on -vv */
671 		if (vflag > 1) {
672 			if (ancount--) {
673 				if ((cp = ns_rprint(cp, bp)) == NULL)
674 					goto trunc;
675 				while (ancount-- && cp < snapend) {
676 					putchar(',');
677 					if ((cp = ns_rprint(cp, bp)) == NULL)
678 						goto trunc;
679 				}
680 			}
681 			if (nscount-- && cp < snapend) {
682 				fputs(" ns:", stdout);
683 				if ((cp = ns_rprint(cp, bp)) == NULL)
684 					goto trunc;
685 				while (nscount-- && cp < snapend) {
686 					putchar(',');
687 					if ((cp = ns_rprint(cp, bp)) == NULL)
688 						goto trunc;
689 				}
690 			}
691 			if (arcount-- && cp < snapend) {
692 				fputs(" ar:", stdout);
693 				if ((cp = ns_rprint(cp, bp)) == NULL)
694 					goto trunc;
695 				while (arcount-- && cp < snapend) {
696 					putchar(',');
697 					if ((cp = ns_rprint(cp, bp)) == NULL)
698 						goto trunc;
699 				}
700 			}
701 		}
702 	}
703 	printf(" (%d)", length);
704 	return;
705 
706   trunc:
707 	printf("[|domain]");
708 	return;
709 }
710