res_debug.c revision 1219:f89f56c2d9ac
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*
24 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29/*	  All Rights Reserved  	*/
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
41#pragma ident	"%Z%%M%	%I%	%E% SMI"
42
43#include "c_synonyms.h"
44#include <sys/types.h>
45#include <netinet/in.h>
46#include <stdio.h>
47#include <arpa/nameser.h>
48
49extern char *p_cdname(), *p_rr(), *p_type(), *p_class(), *p_time();
50extern char *inet_ntoa();
51void fp_query(char *msg, FILE *file);
52
53char *_res_opcodes[] = {
54	"QUERY",
55	"IQUERY",
56	"CQUERYM",
57	"CQUERYU",
58	"4",
59	"5",
60	"6",
61	"7",
62	"8",
63	"UPDATEA",
64	"UPDATED",
65	"UPDATEDA",
66	"UPDATEM",
67	"UPDATEMA",
68	"ZONEINIT",
69	"ZONEREF",
70};
71
72char *_res_resultcodes[] = {
73	"NOERROR",
74	"FORMERR",
75	"SERVFAIL",
76	"NXDOMAIN",
77	"NOTIMP",
78	"REFUSED",
79	"6",
80	"7",
81	"8",
82	"9",
83	"10",
84	"11",
85	"12",
86	"13",
87	"14",
88	"NOCHANGE",
89};
90
91void
92p_query(msg)
93	char *msg;
94{
95	fp_query(msg, stdout);
96}
97
98/*
99 * Print the contents of a query.
100 * This is intended to be primarily a debugging routine.
101 */
102void
103fp_query(msg, file)
104	char *msg;
105	FILE *file;
106{
107	register char *cp;
108	register HEADER *hp;
109	register int n;
110
111	/*
112	 * Print header fields.
113	 */
114	hp = (HEADER *)msg;
115	cp = msg + sizeof (HEADER);
116	fprintf(file, "HEADER:\n");
117	fprintf(file, "\topcode = %s", _res_opcodes[hp->opcode]);
118	fprintf(file, ", id = %d", ntohs(hp->id));
119	fprintf(file, ", rcode = %s\n", _res_resultcodes[hp->rcode]);
120	fprintf(file, "\theader flags: ");
121	if (hp->qr)
122		fprintf(file, " qr");
123	if (hp->aa)
124		fprintf(file, " aa");
125	if (hp->tc)
126		fprintf(file, " tc");
127	if (hp->rd)
128		fprintf(file, " rd");
129	if (hp->ra)
130		fprintf(file, " ra");
131	if (hp->pr)
132		fprintf(file, " pr");
133	fprintf(file, "\n\tqdcount = %d", ntohs(hp->qdcount));
134	fprintf(file, ", ancount = %d", ntohs(hp->ancount));
135	fprintf(file, ", nscount = %d", ntohs(hp->nscount));
136	fprintf(file, ", arcount = %d\n\n", ntohs(hp->arcount));
137	/*
138	 * Print question records.
139	 */
140	if (n = ntohs(hp->qdcount)) {
141		fprintf(file, "QUESTIONS:\n");
142		while (--n >= 0) {
143			fprintf(file, "\t");
144			cp = p_cdname(cp, msg, file);
145			if (cp == NULL)
146				return;
147			fprintf(file, ", type = %s", p_type(_getshort(cp)));
148			cp += sizeof (u_short);
149			fprintf(file, ", class = %s\n\n",
150						p_class(_getshort(cp)));
151			cp += sizeof (u_short);
152		}
153	}
154	/*
155	 * Print authoritative answer records
156	 */
157	if (n = ntohs(hp->ancount)) {
158		fprintf(file, "ANSWERS:\n");
159		while (--n >= 0) {
160			fprintf(file, "\t");
161			cp = p_rr(cp, msg, file);
162			if (cp == NULL)
163				return;
164		}
165	}
166	/*
167	 * print name server records
168	 */
169	if (n = ntohs(hp->nscount)) {
170		fprintf(file, "NAME SERVERS:\n");
171		while (--n >= 0) {
172			fprintf(file, "\t");
173			cp = p_rr(cp, msg, file);
174			if (cp == NULL)
175				return;
176		}
177	}
178	/*
179	 * print additional records
180	 */
181	if (n = ntohs(hp->arcount)) {
182		fprintf(file, "ADDITIONAL RECORDS:\n");
183		while (--n >= 0) {
184			fprintf(file, "\t");
185			cp = p_rr(cp, msg, file);
186			if (cp == NULL)
187				return;
188		}
189	}
190}
191
192char *
193p_cdname(cp, msg, file)
194	char *cp, *msg;
195	FILE *file;
196{
197	char name[MAXDNAME];
198	int n;
199
200	if ((n = dn_expand(msg, msg + 512, cp, name, sizeof (name))) < 0)
201		return (NULL);
202	if (name[0] == '\0') {
203		name[0] = '.';
204		name[1] = '\0';
205	}
206	fputs(name, file);
207	return (cp + n);
208}
209
210/*
211 * Print resource record fields in human readable form.
212 */
213char *
214p_rr(cp, msg, file)
215	char *cp, *msg;
216	FILE *file;
217{
218	int type, class, dlen, n, c;
219	struct in_addr inaddr;
220	char *cp1, *cp2;
221
222	if ((cp = p_cdname(cp, msg, file)) == NULL)
223		return (NULL);			/* compression error */
224	fprintf(file, "\n\ttype = %s", p_type(type = _getshort(cp)));
225	cp += sizeof (u_short);
226	fprintf(file, ", class = %s", p_class(class = _getshort(cp)));
227	cp += sizeof (u_short);
228	fprintf(file, ", ttl = %s", p_time(_getlong(cp)));
229	cp += sizeof (u_long);
230	fprintf(file, ", dlen = %d\n", dlen = _getshort(cp));
231	cp += sizeof (u_short);
232	cp1 = cp;
233	/*
234	 * Print type specific data, if appropriate
235	 */
236	switch (type) {
237	case T_A:
238		switch (class) {
239		case C_IN:
240		case C_HS:
241#ifdef SYSV
242			memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
243#else
244			bcopy(cp, (char *)&inaddr, sizeof (inaddr));
245#endif
246			if (dlen == 4) {
247				fprintf(file, "\tinternet address = %s\n",
248					inet_ntoa(inaddr));
249				cp += dlen;
250			} else if (dlen == 7) {
251				fprintf(file, "\tinternet address = %s",
252					inet_ntoa(inaddr));
253				fprintf(file, ", protocol = %d", cp[4]);
254				fprintf(file, ", port = %d\n",
255					(cp[5] << 8) + cp[6]);
256				cp += dlen;
257			}
258			break;
259		default:
260			cp += dlen;
261		}
262		break;
263	case T_CNAME:
264	case T_MB:
265	case T_MG:
266	case T_MR:
267	case T_NS:
268	case T_PTR:
269		fprintf(file, "\tdomain name = ");
270		cp = p_cdname(cp, msg, file);
271		fprintf(file, "\n");
272		break;
273
274	case T_HINFO:
275		if (n = *cp++) {
276			fprintf(file, "\tCPU=%.*s\n", n, cp);
277			cp += n;
278		}
279		if (n = *cp++) {
280			fprintf(file, "\tOS=%.*s\n", n, cp);
281			cp += n;
282		}
283		break;
284
285	case T_SOA:
286		fprintf(file, "\torigin = ");
287		cp = p_cdname(cp, msg, file);
288		fprintf(file, "\n\tmail addr = ");
289		cp = p_cdname(cp, msg, file);
290		fprintf(file, "\n\tserial = %ld", _getlong(cp));
291		cp += sizeof (u_long);
292		fprintf(file, "\n\trefresh = %s", p_time(_getlong(cp)));
293		cp += sizeof (u_long);
294		fprintf(file, "\n\tretry = %s", p_time(_getlong(cp)));
295		cp += sizeof (u_long);
296		fprintf(file, "\n\texpire = %s", p_time(_getlong(cp)));
297		cp += sizeof (u_long);
298		fprintf(file, "\n\tmin = %s\n", p_time(_getlong(cp)));
299		cp += sizeof (u_long);
300		break;
301
302	case T_MX:
303		fprintf(file, "\tpreference = %ld,", _getshort(cp));
304		cp += sizeof (u_short);
305		fprintf(file, " name = ");
306		cp = p_cdname(cp, msg, file);
307		break;
308
309	case T_TXT:
310		(void) fputs("\t\"", file);
311		cp2 = cp1 + dlen;
312		while (cp < cp2) {
313			if (n = (unsigned char) *cp++) {
314				for (c = n; c > 0 && cp < cp2; c--)
315					if (*cp == '\n') {
316					    (void) putc('\\', file);
317					    (void) putc(*cp++, file);
318					} else
319					    (void) putc(*cp++, file);
320			}
321		}
322		(void) fputs("\"\n", file);
323		break;
324
325	case T_MINFO:
326		fprintf(file, "\trequests = ");
327		cp = p_cdname(cp, msg, file);
328		fprintf(file, "\n\terrors = ");
329		cp = p_cdname(cp, msg, file);
330		break;
331
332	case T_UINFO:
333		fprintf(file, "\t%s\n", cp);
334		cp += dlen;
335		break;
336
337	case T_UID:
338	case T_GID:
339		if (dlen == 4) {
340			fprintf(file, "\t%ld\n", _getlong(cp));
341			cp += sizeof (int);
342		}
343		break;
344
345	case T_WKS:
346		if (dlen < sizeof (u_long) + 1)
347			break;
348#ifdef SYSV
349		memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
350#else
351		bcopy(cp, (char *)&inaddr, sizeof (inaddr));
352#endif
353		cp += sizeof (u_long);
354		fprintf(file, "\tinternet address = %s, protocol = %d\n\t",
355			inet_ntoa(inaddr), *cp++);
356		n = 0;
357		while (cp < cp1 + dlen) {
358			c = *cp++;
359			do {
360				if (c & 0200)
361					fprintf(file, " %d", n);
362				c <<= 1;
363			} while (++n & 07);
364		}
365		putc('\n', file);
366		break;
367
368#ifdef ALLOW_T_UNSPEC
369	case T_UNSPEC:
370		{
371			int NumBytes = 8;
372			char *DataPtr;
373			int i;
374
375			if (dlen < NumBytes) NumBytes = dlen;
376			fprintf(file, "\tFirst %d bytes of hex data:",
377				NumBytes);
378			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
379				fprintf(file, " %x", *DataPtr);
380			fputs("\n", file);
381			cp += dlen;
382		}
383		break;
384#endif /* ALLOW_T_UNSPEC */
385
386	default:
387		fprintf(file, "\t???\n");
388		cp += dlen;
389	}
390	if (cp != cp1 + dlen) {
391		fprintf(file, "packet size error (%#x != %#x)\n", cp, cp1+dlen);
392		cp = NULL;
393	}
394	fprintf(file, "\n");
395	return (cp);
396}
397
398static	char nbuf[40];
399
400/*
401 * Return a string for the type
402 */
403char *
404p_type(type)
405	int type;
406{
407	switch (type) {
408	case T_A:
409		return ("A");
410	case T_NS:		/* authoritative server */
411		return ("NS");
412	case T_CNAME:		/* canonical name */
413		return ("CNAME");
414	case T_SOA:		/* start of authority zone */
415		return ("SOA");
416	case T_MB:		/* mailbox domain name */
417		return ("MB");
418	case T_MG:		/* mail group member */
419		return ("MG");
420	case T_MR:		/* mail rename name */
421		return ("MR");
422	case T_NULL:		/* null resource record */
423		return ("NULL");
424	case T_WKS:		/* well known service */
425		return ("WKS");
426	case T_PTR:		/* domain name pointer */
427		return ("PTR");
428	case T_HINFO:		/* host information */
429		return ("HINFO");
430	case T_MINFO:		/* mailbox information */
431		return ("MINFO");
432	case T_MX:		/* mail routing info */
433		return ("MX");
434	case T_TXT:		/* text */
435		return ("TXT");
436	case T_AXFR:		/* zone transfer */
437		return ("AXFR");
438	case T_MAILB:		/* mail box */
439		return ("MAILB");
440	case T_MAILA:		/* mail address */
441		return ("MAILA");
442	case T_ANY:		/* matches any type */
443		return ("ANY");
444	case T_UINFO:
445		return ("UINFO");
446	case T_UID:
447		return ("UID");
448	case T_GID:
449		return ("GID");
450#ifdef ALLOW_T_UNSPEC
451	case T_UNSPEC:
452		return ("UNSPEC");
453#endif /* ALLOW_T_UNSPEC */
454	default:
455		(void) sprintf(nbuf, "%d", type);
456		return (nbuf);
457	}
458}
459
460/*
461 * Return a mnemonic for class
462 */
463char *
464p_class(class)
465	int class;
466{
467
468	switch (class) {
469	case C_IN:		/* internet class */
470		return ("IN");
471	case C_HS:		/* hesiod class */
472		return ("HS");
473	case C_ANY:		/* matches any class */
474		return ("ANY");
475	default:
476		(void) sprintf(nbuf, "%d", class);
477		return (nbuf);
478	}
479}
480
481/*
482 * Return a mnemonic for a time to live
483 */
484char *
485p_time(value)
486	u_long value;
487{
488	int secs, mins, hours;
489	register char *p;
490
491	if (value == 0) {
492		strcpy(nbuf, "0 secs");
493		return (nbuf);
494	}
495
496	secs = value % 60;
497	value /= 60;
498	mins = value % 60;
499	value /= 60;
500	hours = value % 24;
501	value /= 24;
502
503#define	PLURALIZE(x)	x, (x == 1) ? "" : "s"
504	p = nbuf;
505	if (value) {
506		(void) sprintf(p, "%d day%s", PLURALIZE(value));
507		while (*++p);
508	}
509	if (hours) {
510		if (value)
511			*p++ = ' ';
512		(void) sprintf(p, "%d hour%s", PLURALIZE(hours));
513		while (*++p);
514	}
515	if (mins) {
516		if (value || hours)
517			*p++ = ' ';
518		(void) sprintf(p, "%d min%s", PLURALIZE(mins));
519		while (*++p);
520	}
521	if (secs || ! (value || hours || mins)) {
522		if (value || hours || mins)
523			*p++ = ' ';
524		(void) sprintf(p, "%d sec%s", PLURALIZE(secs));
525	}
526	return (nbuf);
527}
528