xref: /illumos-gate/usr/src/lib/libresolv/res_debug.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 2015 Gary Mills
24  * Copyright 2008 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 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <arpa/nameser.h>
48 #include <resolv.h>
49 #include "crossl.h"
50 
51 void fp_query(char *msg, FILE *file);
52 
53 char *_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 
72 char *_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 
91 void
92 p_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  */
102 void
103 fp_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 
192 char *
193 p_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((u_char *)msg, (u_char *)(msg + 512), (u_char *)cp,
201 	    (u_char *)name, sizeof (name))) < 0)
202 		return (NULL);
203 	if (name[0] == '\0') {
204 		name[0] = '.';
205 		name[1] = '\0';
206 	}
207 	fputs(name, file);
208 	return (cp + n);
209 }
210 
211 /*
212  * Print resource record fields in human readable form.
213  */
214 char *
215 p_rr(cp, msg, file)
216 	char *cp, *msg;
217 	FILE *file;
218 {
219 	int type, class, dlen, n, c;
220 	struct in_addr inaddr;
221 	char *cp1, *cp2;
222 
223 	if ((cp = p_cdname(cp, msg, file)) == NULL)
224 		return (NULL);			/* compression error */
225 	fprintf(file, "\n\ttype = %s", p_type(type = _getshort(cp)));
226 	cp += sizeof (u_short);
227 	fprintf(file, ", class = %s", p_class(class = _getshort(cp)));
228 	cp += sizeof (u_short);
229 	fprintf(file, ", ttl = %s", p_time(_getlong(cp)));
230 	cp += sizeof (u_long);
231 	fprintf(file, ", dlen = %d\n", dlen = _getshort(cp));
232 	cp += sizeof (u_short);
233 	cp1 = cp;
234 	/*
235 	 * Print type specific data, if appropriate
236 	 */
237 	switch (type) {
238 	case T_A:
239 		switch (class) {
240 		case C_IN:
241 		case C_HS:
242 #ifdef SYSV
243 			memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
244 #else
245 			bcopy(cp, (char *)&inaddr, sizeof (inaddr));
246 #endif
247 			if (dlen == 4) {
248 				fprintf(file, "\tinternet address = %s\n",
249 					inet_ntoa(inaddr));
250 				cp += dlen;
251 			} else if (dlen == 7) {
252 				fprintf(file, "\tinternet address = %s",
253 					inet_ntoa(inaddr));
254 				fprintf(file, ", protocol = %d", cp[4]);
255 				fprintf(file, ", port = %d\n",
256 					(cp[5] << 8) + cp[6]);
257 				cp += dlen;
258 			}
259 			break;
260 		default:
261 			cp += dlen;
262 		}
263 		break;
264 	case T_CNAME:
265 	case T_MB:
266 	case T_MG:
267 	case T_MR:
268 	case T_NS:
269 	case T_PTR:
270 		fprintf(file, "\tdomain name = ");
271 		cp = p_cdname(cp, msg, file);
272 		fprintf(file, "\n");
273 		break;
274 
275 	case T_HINFO:
276 		if (n = *cp++) {
277 			fprintf(file, "\tCPU=%.*s\n", n, cp);
278 			cp += n;
279 		}
280 		if (n = *cp++) {
281 			fprintf(file, "\tOS=%.*s\n", n, cp);
282 			cp += n;
283 		}
284 		break;
285 
286 	case T_SOA:
287 		fprintf(file, "\torigin = ");
288 		cp = p_cdname(cp, msg, file);
289 		fprintf(file, "\n\tmail addr = ");
290 		cp = p_cdname(cp, msg, file);
291 		fprintf(file, "\n\tserial = %ld", _getlong(cp));
292 		cp += sizeof (u_long);
293 		fprintf(file, "\n\trefresh = %s", p_time(_getlong(cp)));
294 		cp += sizeof (u_long);
295 		fprintf(file, "\n\tretry = %s", p_time(_getlong(cp)));
296 		cp += sizeof (u_long);
297 		fprintf(file, "\n\texpire = %s", p_time(_getlong(cp)));
298 		cp += sizeof (u_long);
299 		fprintf(file, "\n\tmin = %s\n", p_time(_getlong(cp)));
300 		cp += sizeof (u_long);
301 		break;
302 
303 	case T_MX:
304 		fprintf(file, "\tpreference = %ld,", _getshort(cp));
305 		cp += sizeof (u_short);
306 		fprintf(file, " name = ");
307 		cp = p_cdname(cp, msg, file);
308 		break;
309 
310 	case T_TXT:
311 		(void) fputs("\t\"", file);
312 		cp2 = cp1 + dlen;
313 		while (cp < cp2) {
314 			if (n = (unsigned char) *cp++) {
315 				for (c = n; c > 0 && cp < cp2; c--)
316 					if (*cp == '\n') {
317 					    (void) putc('\\', file);
318 					    (void) putc(*cp++, file);
319 					} else
320 					    (void) putc(*cp++, file);
321 			}
322 		}
323 		(void) fputs("\"\n", file);
324 		break;
325 
326 	case T_MINFO:
327 		fprintf(file, "\trequests = ");
328 		cp = p_cdname(cp, msg, file);
329 		fprintf(file, "\n\terrors = ");
330 		cp = p_cdname(cp, msg, file);
331 		break;
332 
333 	case T_UINFO:
334 		fprintf(file, "\t%s\n", cp);
335 		cp += dlen;
336 		break;
337 
338 	case T_UID:
339 	case T_GID:
340 		if (dlen == 4) {
341 			fprintf(file, "\t%ld\n", _getlong(cp));
342 			cp += sizeof (int);
343 		}
344 		break;
345 
346 	case T_WKS:
347 		if (dlen < sizeof (u_long) + 1)
348 			break;
349 #ifdef SYSV
350 		memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr));
351 #else
352 		bcopy(cp, (char *)&inaddr, sizeof (inaddr));
353 #endif
354 		cp += sizeof (u_long);
355 		fprintf(file, "\tinternet address = %s, protocol = %d\n\t",
356 			inet_ntoa(inaddr), *cp++);
357 		n = 0;
358 		while (cp < cp1 + dlen) {
359 			c = *cp++;
360 			do {
361 				if (c & 0200)
362 					fprintf(file, " %d", n);
363 				c <<= 1;
364 			} while (++n & 07);
365 		}
366 		putc('\n', file);
367 		break;
368 
369 #ifdef ALLOW_T_UNSPEC
370 	case T_UNSPEC:
371 		{
372 			int NumBytes = 8;
373 			char *DataPtr;
374 			int i;
375 
376 			if (dlen < NumBytes) NumBytes = dlen;
377 			fprintf(file, "\tFirst %d bytes of hex data:",
378 				NumBytes);
379 			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
380 				fprintf(file, " %x", *DataPtr);
381 			fputs("\n", file);
382 			cp += dlen;
383 		}
384 		break;
385 #endif /* ALLOW_T_UNSPEC */
386 
387 	default:
388 		fprintf(file, "\t???\n");
389 		cp += dlen;
390 	}
391 	if (cp != cp1 + dlen) {
392 		fprintf(file, "packet size error (%#x != %#x)\n", cp, cp1+dlen);
393 		cp = NULL;
394 	}
395 	fprintf(file, "\n");
396 	return (cp);
397 }
398 
399 static	char nbuf[40];
400 
401 /*
402  * Return a string for the type
403  */
404 char *
405 p_type(type)
406 	int type;
407 {
408 	switch (type) {
409 	case T_A:
410 		return ("A");
411 	case T_NS:		/* authoritative server */
412 		return ("NS");
413 	case T_CNAME:		/* canonical name */
414 		return ("CNAME");
415 	case T_SOA:		/* start of authority zone */
416 		return ("SOA");
417 	case T_MB:		/* mailbox domain name */
418 		return ("MB");
419 	case T_MG:		/* mail group member */
420 		return ("MG");
421 	case T_MR:		/* mail rename name */
422 		return ("MR");
423 	case T_NULL:		/* null resource record */
424 		return ("NULL");
425 	case T_WKS:		/* well known service */
426 		return ("WKS");
427 	case T_PTR:		/* domain name pointer */
428 		return ("PTR");
429 	case T_HINFO:		/* host information */
430 		return ("HINFO");
431 	case T_MINFO:		/* mailbox information */
432 		return ("MINFO");
433 	case T_MX:		/* mail routing info */
434 		return ("MX");
435 	case T_TXT:		/* text */
436 		return ("TXT");
437 	case T_AXFR:		/* zone transfer */
438 		return ("AXFR");
439 	case T_MAILB:		/* mail box */
440 		return ("MAILB");
441 	case T_MAILA:		/* mail address */
442 		return ("MAILA");
443 	case T_ANY:		/* matches any type */
444 		return ("ANY");
445 	case T_UINFO:
446 		return ("UINFO");
447 	case T_UID:
448 		return ("UID");
449 	case T_GID:
450 		return ("GID");
451 #ifdef ALLOW_T_UNSPEC
452 	case T_UNSPEC:
453 		return ("UNSPEC");
454 #endif /* ALLOW_T_UNSPEC */
455 	default:
456 		(void) sprintf(nbuf, "%d", type);
457 		return (nbuf);
458 	}
459 }
460 
461 /*
462  * Return a mnemonic for class
463  */
464 char *
465 p_class(class)
466 	int class;
467 {
468 
469 	switch (class) {
470 	case C_IN:		/* internet class */
471 		return ("IN");
472 	case C_HS:		/* hesiod class */
473 		return ("HS");
474 	case C_ANY:		/* matches any class */
475 		return ("ANY");
476 	default:
477 		(void) sprintf(nbuf, "%d", class);
478 		return (nbuf);
479 	}
480 }
481 
482 /*
483  * Return a mnemonic for a time to live
484  */
485 char *
486 p_time(value)
487 	u_long value;
488 {
489 	int secs, mins, hours;
490 	register char *p;
491 
492 	if (value == 0) {
493 		strcpy(nbuf, "0 secs");
494 		return (nbuf);
495 	}
496 
497 	secs = value % 60;
498 	value /= 60;
499 	mins = value % 60;
500 	value /= 60;
501 	hours = value % 24;
502 	value /= 24;
503 
504 #define	PLURALIZE(x)	x, (x == 1) ? "" : "s"
505 	p = nbuf;
506 	if (value) {
507 		(void) sprintf(p, "%d day%s", PLURALIZE(value));
508 		while (*++p);
509 	}
510 	if (hours) {
511 		if (value)
512 			*p++ = ' ';
513 		(void) sprintf(p, "%d hour%s", PLURALIZE(hours));
514 		while (*++p);
515 	}
516 	if (mins) {
517 		if (value || hours)
518 			*p++ = ' ';
519 		(void) sprintf(p, "%d min%s", PLURALIZE(mins));
520 		while (*++p);
521 	}
522 	if (secs || ! (value || hours || mins)) {
523 		if (value || hours || mins)
524 			*p++ = ' ';
525 		(void) sprintf(p, "%d sec%s", PLURALIZE(secs));
526 	}
527 	return (nbuf);
528 }
529