print-domain.c revision 75118
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: head/contrib/tcpdump/print-domain.c 75118 2001-04-03 07:50:46Z fenner $
22 */
23
24#ifndef lint
25static 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
139static char *ns_ops[] = {
140	"", " inv_q", " stat", " op3", " notify", " op5", " op6", " op7",
141	" op8", " updataA", " updateD", " updateDA",
142	" updateM", " updateMA", " zoneInit", " zoneRef",
143};
144
145static 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 */
153static const u_char *
154ns_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> */
182static const u_char *
183blabel_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
218static int
219labellen(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
240static const u_char *
241ns_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> */
319static const u_char *
320ns_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
331static 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
382static 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 */
391static const u_char *
392ns_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 */
417static const u_char *
418ns_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
552void
553ns_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