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