xref: /freebsd/contrib/tcpdump/print-domain.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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.42 1999/11/21 09:36:50 fenner 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 #include <sys/socket.h>
36 
37 #if __STDC__
38 struct mbuf;
39 struct rtentry;
40 #endif
41 #include <net/if.h>
42 
43 #include <netinet/in.h>
44 #include <net/ethernet.h>
45 #include <netinet/in_systm.h>
46 #include <netinet/ip.h>
47 #include <netinet/ip_var.h>
48 #include <netinet/udp.h>
49 #include <netinet/udp_var.h>
50 #include <netinet/tcp.h>
51 
52 #ifdef NOERROR
53 #undef NOERROR					/* Solaris sucks */
54 #endif
55 #ifdef NOERROR
56 #undef T_UNSPEC					/* SINIX does too */
57 #endif
58 #include <arpa/nameser.h>
59 
60 #include <stdio.h>
61 #include <string.h>
62 
63 #include "interface.h"
64 #include "addrtoname.h"
65 #include "extract.h"                    /* must come after interface.h */
66 
67 /* Compatibility */
68 #ifndef T_TXT
69 #define T_TXT		16		/* text strings */
70 #endif
71 #ifndef T_RP
72 #define T_RP		17		/* responsible person */
73 #endif
74 #ifndef T_AFSDB
75 #define T_AFSDB		18		/* AFS cell database */
76 #endif
77 #ifndef T_X25
78 #define T_X25		19		/* X_25 calling address */
79 #endif
80 #ifndef T_ISDN
81 #define T_ISDN		20		/* ISDN calling address */
82 #endif
83 #ifndef T_RT
84 #define T_RT		21		/* router */
85 #endif
86 #ifndef T_NSAP
87 #define T_NSAP		22		/* NSAP address */
88 #endif
89 #ifndef T_NSAP_PTR
90 #define T_NSAP_PTR	23		/* reverse NSAP lookup (deprecated) */
91 #endif
92 #ifndef T_SIG
93 #define T_SIG		24		/* security signature */
94 #endif
95 #ifndef T_KEY
96 #define T_KEY		25		/* security key */
97 #endif
98 #ifndef T_PX
99 #define T_PX		26		/* X.400 mail mapping */
100 #endif
101 #ifndef T_GPOS
102 #define T_GPOS		27		/* geographical position (withdrawn) */
103 #endif
104 #ifndef T_AAAA
105 #define T_AAAA		28		/* IP6 Address */
106 #endif
107 #ifndef T_LOC
108 #define T_LOC		29		/* Location Information */
109 #endif
110 #ifndef T_NXT
111 #define T_NXT		30		/* Next Valid Name in Zone */
112 #endif
113 #ifndef T_EID
114 #define T_EID		31		/* Endpoint identifier */
115 #endif
116 #ifndef T_NIMLOC
117 #define T_NIMLOC	32		/* Nimrod locator */
118 #endif
119 #ifndef T_SRV
120 #define T_SRV		33		/* Server selection */
121 #endif
122 #ifndef T_ATMA
123 #define T_ATMA		34		/* ATM Address */
124 #endif
125 #ifndef T_NAPTR
126 #define T_NAPTR		35		/* Naming Authority PoinTeR */
127 #endif
128 #ifndef T_A6
129 #define T_A6		38		/* IP6 address (ipngwg-dns-lookups) */
130 #endif
131 
132 #ifndef T_UNSPEC
133 #define T_UNSPEC	103		/* Unspecified format (binary data) */
134 #endif
135 #ifndef T_UNSPECA
136 #define T_UNSPECA	104		/* "unspecified ascii". Ugly MIT hack */
137 #endif
138 
139 #ifndef C_CHAOS
140 #define C_CHAOS		3		/* for chaos net (MIT) */
141 #endif
142 #ifndef C_HS
143 #define C_HS		4		/* for Hesiod name server (MIT) (XXX) */
144 #endif
145 
146 static char *ns_ops[] = {
147 	"", " inv_q", " stat", " op3", " notify", " op5", " op6", " op7",
148 	" op8", " updataA", " updateD", " updateDA",
149 	" updateM", " updateMA", " zoneInit", " zoneRef",
150 };
151 
152 static char *ns_resp[] = {
153 	"", " FormErr", " ServFail", " NXDomain",
154 	" NotImp", " Refused", " Resp6", " Resp7",
155 	" Resp8", " Resp9", " Resp10", " Resp11",
156 	" Resp12", " Resp13", " Resp14", " NoChange",
157 };
158 
159 /* skip over a domain name */
160 static const u_char *
161 ns_nskip(register const u_char *cp, register const u_char *bp)
162 {
163 	register u_char i;
164 
165 	if (((i = *cp++) & INDIR_MASK) == INDIR_MASK)
166 		return (cp + 1);
167 	while (i && cp < snapend) {
168 		cp += i;
169 		i = *cp++;
170 	}
171 	return (cp);
172 }
173 
174 /* print a <domain-name> */
175 static const u_char *
176 ns_nprint(register const u_char *cp, register const u_char *bp)
177 {
178 	register u_int i;
179 	register const u_char *rp;
180 	register int compress;
181 
182 	i = *cp++;
183 	rp = cp + i;
184 	if ((i & INDIR_MASK) == INDIR_MASK) {
185 		rp = cp + 1;
186 		compress = 1;
187 	} else
188 		compress = 0;
189 	if (i != 0)
190 		while (i && cp < snapend) {
191 			if ((i & INDIR_MASK) == INDIR_MASK) {
192 				cp = bp + (((i << 8) | *cp) & 0x3fff);
193 				i = *cp++;
194 				continue;
195 			}
196 			if (fn_printn(cp, i, snapend))
197 				break;
198 			cp += i;
199 			putchar('.');
200 			i = *cp++;
201 			if (!compress)
202 				rp += i + 1;
203 		}
204 	else
205 		putchar('.');
206 	return (rp);
207 }
208 
209 /* print a <character-string> */
210 static const u_char *
211 ns_cprint(register const u_char *cp, register const u_char *bp)
212 {
213 	register u_int i;
214 
215 	i = *cp++;
216 	(void)fn_printn(cp, i, snapend);
217 	return (cp + i);
218 }
219 
220 static struct tok type2str[] = {
221 	{ T_A,		"A" },
222 	{ T_NS,		"NS" },
223 	{ T_MD,		"MD" },
224 	{ T_MF,		"MF" },
225 	{ T_CNAME,	"CNAME" },
226 	{ T_SOA,	"SOA" },
227 	{ T_MB,		"MB" },
228 	{ T_MG,		"MG" },
229 	{ T_MR,		"MR" },
230 	{ T_NULL,	"NULL" },
231 	{ T_WKS,	"WKS" },
232 	{ T_PTR,	"PTR" },
233 	{ T_HINFO,	"HINFO" },
234 	{ T_MINFO,	"MINFO" },
235 	{ T_MX,		"MX" },
236 	{ T_TXT,	"TXT" },
237 	{ T_RP,		"RP" },
238 	{ T_AFSDB,	"AFSDB" },
239 	{ T_X25,	"X25" },
240 	{ T_ISDN,	"ISDN" },
241 	{ T_RT,		"RT" },
242 	{ T_NSAP,	"NSAP" },
243 	{ T_NSAP_PTR,	"NSAP_PTR" },
244 	{ T_SIG,	"SIG" },
245 	{ T_KEY,	"KEY" },
246 	{ T_PX,		"PX" },
247 	{ T_GPOS,	"GPOS" },
248 	{ T_AAAA,	"AAAA" },
249 	{ T_LOC,	"LOC " },
250 	{ T_NXT,	"NXT " },
251 	{ T_EID,	"EID " },
252 	{ T_NIMLOC,	"NIMLOC " },
253 	{ T_SRV,	"SRV " },
254 	{ T_ATMA,	"ATMA " },
255 	{ T_NAPTR,	"NAPTR " },
256 	{ T_A6,		"A6 " },
257 #ifndef T_UINFO
258 #define T_UINFO 100
259 #endif
260 	{ T_UINFO,	"UINFO" },
261 #ifndef T_UID
262 #define T_UID 101
263 #endif
264 	{ T_UID,	"UID" },
265 #ifndef T_GID
266 #define T_GID 102
267 #endif
268 	{ T_GID,	"GID" },
269 	{ T_UNSPEC,	"UNSPEC" },
270 	{ T_UNSPECA,	"UNSPECA" },
271 	{ T_AXFR,	"AXFR" },
272 	{ T_MAILB,	"MAILB" },
273 	{ T_MAILA,	"MAILA" },
274 	{ T_ANY,	"ANY" },
275 	{ 0,		NULL }
276 };
277 
278 static struct tok class2str[] = {
279 	{ C_IN,		"IN" },		/* Not used */
280 	{ C_CHAOS,	"CHAOS)" },
281 	{ C_HS,		"HS" },
282 	{ C_ANY,	"ANY" },
283 	{ 0,		NULL }
284 };
285 
286 /* print a query */
287 static void
288 ns_qprint(register const u_char *cp, register const u_char *bp)
289 {
290 	register const u_char *np = cp;
291 	register u_int i;
292 
293 	cp = ns_nskip(cp, bp);
294 
295 	if (cp + 4 > snapend)
296 		return;
297 
298 	/* print the qtype and qclass (if it's not IN) */
299 	i = *cp++ << 8;
300 	i |= *cp++;
301 	printf(" %s", tok2str(type2str, "Type%d", i));
302 	i = *cp++ << 8;
303 	i |= *cp++;
304 	if (i != C_IN)
305 		printf(" %s", tok2str(class2str, "(Class %d)", i));
306 
307 	fputs("? ", stdout);
308 	ns_nprint(np, bp);
309 }
310 
311 /* print a reply */
312 static const u_char *
313 ns_rprint(register const u_char *cp, register const u_char *bp)
314 {
315 	register u_int i;
316 	register u_short typ, len;
317 	register const u_char *rp;
318 
319 	if (vflag) {
320 		putchar(' ');
321 		cp = ns_nprint(cp, bp);
322 	} else
323 		cp = ns_nskip(cp, bp);
324 
325 	if (cp + 10 > snapend)
326 		return (snapend);
327 
328 	/* print the type/qtype and class (if it's not IN) */
329 	typ = *cp++ << 8;
330 	typ |= *cp++;
331 	i = *cp++ << 8;
332 	i |= *cp++;
333 	if (i != C_IN)
334 		printf(" %s", tok2str(class2str, "(Class %d)", i));
335 
336 	/* ignore ttl */
337 	cp += 4;
338 
339 	len = *cp++ << 8;
340 	len |= *cp++;
341 
342 	rp = cp + len;
343 
344 	printf(" %s", tok2str(type2str, "Type%d", typ));
345 	switch (typ) {
346 
347 	case T_A:
348 		printf(" %s", ipaddr_string(cp));
349 		break;
350 
351 	case T_NS:
352 	case T_CNAME:
353 	case T_PTR:
354 #ifdef T_DNAME
355 	case T_DNAME:	/*XXX not checked as there's no server support yet*/
356 #endif
357 		putchar(' ');
358 		(void)ns_nprint(cp, bp);
359 		break;
360 
361 	case T_MX:
362 		putchar(' ');
363 		(void)ns_nprint(cp + 2, bp);
364 		printf(" %d", EXTRACT_16BITS(cp));
365 		break;
366 
367 	case T_TXT:
368 		putchar(' ');
369 		(void)ns_cprint(cp, bp);
370 		break;
371 
372 #ifdef INET6
373 	case T_AAAA:
374 		printf(" %s", ip6addr_string(cp));
375 		break;
376 
377 	case T_A6:	/*XXX not checked as there's no server support yet*/
378 	    {
379 		struct in6_addr a;
380 		int pbyte;
381 
382 		pbyte = (*cp + 7) / 8;
383 		memset(&a, 0, sizeof(a));
384 		memcpy(&a, cp + 1, pbyte);
385 		printf(" %u %s ", *cp, ip6addr_string(&a));
386 		(void)ns_nprint(cp + 1 + pbyte, bp);
387 		break;
388 	    }
389 #endif /*INET6*/
390 
391 	case T_UNSPECA:		/* One long string */
392 	        printf(" %.*s", len, cp);
393 		break;
394 	}
395 	return (rp);		/* XXX This isn't always right */
396 }
397 
398 void
399 ns_print(register const u_char *bp, u_int length)
400 {
401 	register const HEADER *np;
402 	register int qdcount, ancount, nscount, arcount;
403 	register const u_char *cp;
404 
405 	np = (const HEADER *)bp;
406 	/* get the byte-order right */
407 	qdcount = ntohs(np->qdcount);
408 	ancount = ntohs(np->ancount);
409 	nscount = ntohs(np->nscount);
410 	arcount = ntohs(np->arcount);
411 
412 	if (np->qr) {
413 		/* this is a response */
414 		printf(" %d%s%s%s%s%s",
415 			ntohs(np->id),
416 			ns_ops[np->opcode],
417 			ns_resp[np->rcode],
418 			np->aa? "*" : "",
419 			np->ra? "" : "-",
420 			np->tc? "|" : "");
421 		if (qdcount != 1)
422 			printf(" [%dq]", qdcount);
423 		/* Print QUESTION section on -vv */
424 		if (vflag > 1) {
425 		            fputs(" q: ", stdout);
426 			    cp = ns_nprint((const u_char *)(np + 1), bp);
427 		} else
428 			    cp = ns_nskip((const u_char *)(np + 1), bp);
429 		printf(" %d/%d/%d", ancount, nscount, arcount);
430 		if (ancount--) {
431 			cp = ns_rprint(cp + 4, bp);
432 			while (ancount-- && cp < snapend) {
433 				putchar(',');
434 				cp = ns_rprint(cp, bp);
435 			}
436 		}
437 	}
438 	else {
439 		/* this is a request */
440 		printf(" %d%s%s",
441 		        ntohs(np->id),
442 			ns_ops[np->opcode],
443 			np->rd? "+" : "");
444 
445 		/* any weirdness? */
446 		if (*(((u_short *)np)+1) & htons(0x6ff))
447 			printf(" [b2&3=0x%x]", ntohs(*(((u_short *)np)+1)));
448 
449 		if (np->opcode == IQUERY) {
450 			if (qdcount)
451 				printf(" [%dq]", qdcount);
452 			if (ancount != 1)
453 				printf(" [%da]", ancount);
454 		}
455 		else {
456 			if (ancount)
457 				printf(" [%da]", ancount);
458 			if (qdcount != 1)
459 				printf(" [%dq]", qdcount);
460 		}
461 		if (nscount)
462 			printf(" [%dn]", nscount);
463 		if (arcount)
464 			printf(" [%dau]", arcount);
465 
466 		ns_qprint((const u_char *)(np + 1), (const u_char *)np);
467 	}
468 	printf(" (%d)", length);
469 }
470