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