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