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