xref: /386bsd/usr/src/lib/libc/net/res_debug.c (revision a2142627)
1 /*-
2  * Copyright (c) 1985, 1990 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *	@(#)res_debug.c	5.36 (Berkeley) 3/6/91
34  */
35 
36 #if defined(LIBC_SCCS) && !defined(lint)
37 static char sccsid[] = "@(#)res_debug.c	5.36 (Berkeley) 3/6/91";
38 #endif /* LIBC_SCCS and not lint */
39 
40 #include <sys/param.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <arpa/nameser.h>
44 #include <resolv.h>
45 #include <stdio.h>
46 #include <string.h>
47 
48 void __fp_query();
49 char *__p_class(), *__p_time(), *__p_type();
50 static char *p_cdname(), *p_rr();
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 
__p_query(msg)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
__fp_query(msg,file)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,
148 			    ", class = %s\n\n", __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 static char *
p_cdname(cp,msg,file)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((u_char *)msg, (u_char *)msg + 512, (u_char *)cp,
199 	    (u_char *)name, sizeof(name))) < 0)
200 		return (NULL);
201 	if (name[0] == '\0') {
202 		name[0] = '.';
203 		name[1] = '\0';
204 	}
205 	fputs(name, file);
206 	return (cp + n);
207 }
208 
209 /*
210  * Print resource record fields in human readable form.
211  */
212 static char *
p_rr(cp,msg,file)213 p_rr(cp, msg, file)
214 	char *cp, *msg;
215 	FILE *file;
216 {
217 	int type, class, dlen, n, c;
218 	struct in_addr inaddr;
219 	char *cp1, *cp2;
220 
221 	if ((cp = p_cdname(cp, msg, file)) == NULL)
222 		return (NULL);			/* compression error */
223 	fprintf(file,"\n\ttype = %s", __p_type(type = _getshort(cp)));
224 	cp += sizeof(u_short);
225 	fprintf(file,", class = %s", __p_class(class = _getshort(cp)));
226 	cp += sizeof(u_short);
227 	fprintf(file,", ttl = %s", __p_time(_getlong(cp)));
228 	cp += sizeof(u_long);
229 	fprintf(file,", dlen = %d\n", dlen = _getshort(cp));
230 	cp += sizeof(u_short);
231 	cp1 = cp;
232 	/*
233 	 * Print type specific data, if appropriate
234 	 */
235 	switch (type) {
236 	case T_A:
237 		switch (class) {
238 		case C_IN:
239 		case C_HS:
240 			bcopy(cp, (char *)&inaddr, sizeof(inaddr));
241 			if (dlen == 4) {
242 				fprintf(file,"\tinternet address = %s\n",
243 					inet_ntoa(inaddr));
244 				cp += dlen;
245 			} else if (dlen == 7) {
246 				fprintf(file,"\tinternet address = %s",
247 					inet_ntoa(inaddr));
248 				fprintf(file,", protocol = %d", cp[4]);
249 				fprintf(file,", port = %d\n",
250 					(cp[5] << 8) + cp[6]);
251 				cp += dlen;
252 			}
253 			break;
254 		default:
255 			cp += dlen;
256 		}
257 		break;
258 	case T_CNAME:
259 	case T_MB:
260 	case T_MG:
261 	case T_MR:
262 	case T_NS:
263 	case T_PTR:
264 		fprintf(file,"\tdomain name = ");
265 		cp = p_cdname(cp, msg, file);
266 		fprintf(file,"\n");
267 		break;
268 
269 	case T_HINFO:
270 		if (n = *cp++) {
271 			fprintf(file,"\tCPU=%.*s\n", n, cp);
272 			cp += n;
273 		}
274 		if (n = *cp++) {
275 			fprintf(file,"\tOS=%.*s\n", n, cp);
276 			cp += n;
277 		}
278 		break;
279 
280 	case T_SOA:
281 		fprintf(file,"\torigin = ");
282 		cp = p_cdname(cp, msg, file);
283 		fprintf(file,"\n\tmail addr = ");
284 		cp = p_cdname(cp, msg, file);
285 		fprintf(file,"\n\tserial = %ld", _getlong(cp));
286 		cp += sizeof(u_long);
287 		fprintf(file,"\n\trefresh = %s", __p_time(_getlong(cp)));
288 		cp += sizeof(u_long);
289 		fprintf(file,"\n\tretry = %s", __p_time(_getlong(cp)));
290 		cp += sizeof(u_long);
291 		fprintf(file,"\n\texpire = %s", __p_time(_getlong(cp)));
292 		cp += sizeof(u_long);
293 		fprintf(file,"\n\tmin = %s\n", __p_time(_getlong(cp)));
294 		cp += sizeof(u_long);
295 		break;
296 
297 	case T_MX:
298 		fprintf(file,"\tpreference = %ld,",_getshort(cp));
299 		cp += sizeof(u_short);
300 		fprintf(file," name = ");
301 		cp = p_cdname(cp, msg, file);
302 		break;
303 
304   	case T_TXT:
305 		(void) fputs("\t\"", file);
306 		cp2 = cp1 + dlen;
307 		while (cp < cp2) {
308 			if (n = (unsigned char) *cp++) {
309 				for (c = n; c > 0 && cp < cp2; c--)
310 					if (*cp == '\n') {
311 					    (void) putc('\\', file);
312 					    (void) putc(*cp++, file);
313 					} else
314 					    (void) putc(*cp++, file);
315 			}
316 		}
317 		(void) fputs("\"\n", file);
318   		break;
319 
320 	case T_MINFO:
321 		fprintf(file,"\trequests = ");
322 		cp = p_cdname(cp, msg, file);
323 		fprintf(file,"\n\terrors = ");
324 		cp = p_cdname(cp, msg, file);
325 		break;
326 
327 	case T_UINFO:
328 		fprintf(file,"\t%s\n", cp);
329 		cp += dlen;
330 		break;
331 
332 	case T_UID:
333 	case T_GID:
334 		if (dlen == 4) {
335 			fprintf(file,"\t%ld\n", _getlong(cp));
336 			cp += sizeof(int);
337 		}
338 		break;
339 
340 	case T_WKS:
341 		if (dlen < sizeof(u_long) + 1)
342 			break;
343 		bcopy(cp, (char *)&inaddr, sizeof(inaddr));
344 		cp += sizeof(u_long);
345 		fprintf(file,"\tinternet address = %s, protocol = %d\n\t",
346 			inet_ntoa(inaddr), *cp++);
347 		n = 0;
348 		while (cp < cp1 + dlen) {
349 			c = *cp++;
350 			do {
351  				if (c & 0200)
352 					fprintf(file," %d", n);
353  				c <<= 1;
354 			} while (++n & 07);
355 		}
356 		putc('\n',file);
357 		break;
358 
359 #ifdef ALLOW_T_UNSPEC
360 	case T_UNSPEC:
361 		{
362 			int NumBytes = 8;
363 			char *DataPtr;
364 			int i;
365 
366 			if (dlen < NumBytes) NumBytes = dlen;
367 			fprintf(file, "\tFirst %d bytes of hex data:",
368 				NumBytes);
369 			for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++)
370 				fprintf(file, " %x", *DataPtr);
371 			fputs("\n", file);
372 			cp += dlen;
373 		}
374 		break;
375 #endif /* ALLOW_T_UNSPEC */
376 
377 	default:
378 		fprintf(file,"\t???\n");
379 		cp += dlen;
380 	}
381 	if (cp != cp1 + dlen) {
382 		fprintf(file,"packet size error (%#x != %#x)\n", cp, cp1+dlen);
383 		cp = NULL;
384 	}
385 	fprintf(file,"\n");
386 	return (cp);
387 }
388 
389 static	char nbuf[40];
390 
391 /*
392  * Return a string for the type
393  */
394 char *
__p_type(type)395 __p_type(type)
396 	int type;
397 {
398 	switch (type) {
399 	case T_A:
400 		return("A");
401 	case T_NS:		/* authoritative server */
402 		return("NS");
403 	case T_CNAME:		/* canonical name */
404 		return("CNAME");
405 	case T_SOA:		/* start of authority zone */
406 		return("SOA");
407 	case T_MB:		/* mailbox domain name */
408 		return("MB");
409 	case T_MG:		/* mail group member */
410 		return("MG");
411 	case T_MR:		/* mail rename name */
412 		return("MR");
413 	case T_NULL:		/* null resource record */
414 		return("NULL");
415 	case T_WKS:		/* well known service */
416 		return("WKS");
417 	case T_PTR:		/* domain name pointer */
418 		return("PTR");
419 	case T_HINFO:		/* host information */
420 		return("HINFO");
421 	case T_MINFO:		/* mailbox information */
422 		return("MINFO");
423 	case T_MX:		/* mail routing info */
424 		return("MX");
425 	case T_TXT:		/* text */
426 		return("TXT");
427 	case T_AXFR:		/* zone transfer */
428 		return("AXFR");
429 	case T_MAILB:		/* mail box */
430 		return("MAILB");
431 	case T_MAILA:		/* mail address */
432 		return("MAILA");
433 	case T_ANY:		/* matches any type */
434 		return("ANY");
435 	case T_UINFO:
436 		return("UINFO");
437 	case T_UID:
438 		return("UID");
439 	case T_GID:
440 		return("GID");
441 #ifdef ALLOW_T_UNSPEC
442 	case T_UNSPEC:
443 		return("UNSPEC");
444 #endif /* ALLOW_T_UNSPEC */
445 	default:
446 		(void)sprintf(nbuf, "%d", type);
447 		return(nbuf);
448 	}
449 }
450 
451 /*
452  * Return a mnemonic for class
453  */
454 char *
__p_class(class)455 __p_class(class)
456 	int class;
457 {
458 
459 	switch (class) {
460 	case C_IN:		/* internet class */
461 		return("IN");
462 	case C_HS:		/* hesiod class */
463 		return("HS");
464 	case C_ANY:		/* matches any class */
465 		return("ANY");
466 	default:
467 		(void)sprintf(nbuf, "%d", class);
468 		return(nbuf);
469 	}
470 }
471 
472 /*
473  * Return a mnemonic for a time to live
474  */
475 char *
__p_time(value)476 __p_time(value)
477 	u_long value;
478 {
479 	int secs, mins, hours;
480 	register char *p;
481 
482 	if (value == 0) {
483 		strcpy(nbuf, "0 secs");
484 		return(nbuf);
485 	}
486 
487 	secs = value % 60;
488 	value /= 60;
489 	mins = value % 60;
490 	value /= 60;
491 	hours = value % 24;
492 	value /= 24;
493 
494 #define	PLURALIZE(x)	x, (x == 1) ? "" : "s"
495 	p = nbuf;
496 	if (value) {
497 		(void)sprintf(p, "%d day%s", PLURALIZE(value));
498 		while (*++p);
499 	}
500 	if (hours) {
501 		if (value)
502 			*p++ = ' ';
503 		(void)sprintf(p, "%d hour%s", PLURALIZE(hours));
504 		while (*++p);
505 	}
506 	if (mins) {
507 		if (value || hours)
508 			*p++ = ' ';
509 		(void)sprintf(p, "%d min%s", PLURALIZE(mins));
510 		while (*++p);
511 	}
512 	if (secs || ! (value || hours || mins)) {
513 		if (value || hours || mins)
514 			*p++ = ' ';
515 		(void)sprintf(p, "%d sec%s", PLURALIZE(secs));
516 	}
517 	return(nbuf);
518 }
519