1 /*
2  * Copyright (c) 1985,1989 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 
34 #ifndef lint
35 static char sccsid[] = "@(#)debug.c	5.26 (Berkeley) 3/21/91";
36 #endif /* not lint */
37 
38 /*
39  *******************************************************************************
40  *
41  *  debug.c --
42  *
43  *	Routines to print out packets received from a name server query.
44  *
45  *      Modified version of 4.3BSD BIND res_debug.c 5.30 6/27/90
46  *
47  *******************************************************************************
48  */
49 
50 #include <sys/param.h>
51 #include <netinet/in.h>
52 #include <arpa/nameser.h>
53 #include <arpa/inet.h>
54 #include <resolv.h>
55 #include <netdb.h>
56 #include <stdio.h>
57 #include "res.h"
58 
59 extern char ctime();
60 
61 /*
62  *  Imported from res_debug.c
63  */
64 extern char *_res_resultcodes[];
65 extern char *_res_opcodes[];
66 
67 /*
68  *  Used to highlight the start of a record when printing it.
69  */
70 #define INDENT "    ->  "
71 
72 
73 
74 /*
75  * Print the contents of a query.
76  * This is intended to be primarily a debugging routine.
77  */
78 
Print_query(msg,eom,printHeader)79 Print_query(msg, eom, printHeader)
80 	char *msg, *eom;
81 	int printHeader;
82 {
83 	Fprint_query(msg, eom, printHeader,stdout);
84 }
85 
Fprint_query(msg,eom,printHeader,file)86 Fprint_query(msg, eom, printHeader,file)
87 	char *msg, *eom;
88 	int printHeader;
89 	FILE *file;
90 {
91 	register char *cp;
92 	register HEADER *hp;
93 	register int n;
94 	short class;
95 	short type;
96 
97 	/*
98 	 * Print header fields.
99 	 */
100 	hp = (HEADER *)msg;
101 	cp = msg + sizeof(HEADER);
102 	if (printHeader || (_res.options & RES_DEBUG2)) {
103 	    fprintf(file,"    HEADER:\n");
104 	    fprintf(file,"\topcode = %s", _res_opcodes[hp->opcode]);
105 	    fprintf(file,", id = %d", ntohs(hp->id));
106 	    fprintf(file,", rcode = %s\n", _res_resultcodes[hp->rcode]);
107 	    fprintf(file,"\theader flags: ");
108 	    if (hp->qr) {
109 		    fprintf(file," response");
110 	    } else {
111 		    fprintf(file," query");
112 	    }
113 	    if (hp->aa)
114 		    fprintf(file,", auth. answer");
115 	    if (hp->tc)
116 		    fprintf(file,", truncation");
117 	    if (hp->rd)
118 		    fprintf(file,", want recursion");
119 	    if (hp->ra)
120 		    fprintf(file,", recursion avail.");
121 	    if (hp->pr)
122 		    fprintf(file,", primary");
123 	    fprintf(file,"\n\tquestions = %d", ntohs(hp->qdcount));
124 	    fprintf(file,",  answers = %d", ntohs(hp->ancount));
125 	    fprintf(file,",  authority records = %d", ntohs(hp->nscount));
126 	    fprintf(file,",  additional = %d\n\n", ntohs(hp->arcount));
127 	}
128 
129 	/*
130 	 * Print question records.
131 	 */
132 	if (n = ntohs(hp->qdcount)) {
133 		fprintf(file,"    QUESTIONS:\n");
134 		while (--n >= 0) {
135 			fprintf(file,"\t");
136 			cp = Print_cdname(cp, msg, eom, file);
137 			if (cp == NULL)
138 				return;
139 			type = _getshort(cp);
140 			cp += sizeof(u_short);
141 			class = _getshort(cp);
142 			cp += sizeof(u_short);
143 			fprintf(file,", type = %s", p_type(type));
144 			fprintf(file,", class = %s\n", p_class(class));
145 		}
146 	}
147 	/*
148 	 * Print authoritative answer records
149 	 */
150 	if (n = ntohs(hp->ancount)) {
151 		fprintf(file,"    ANSWERS:\n");
152 		while (--n >= 0) {
153 			fprintf(file, INDENT);
154 			cp = Print_rr(cp, msg, eom, file);
155 			if (cp == NULL)
156 				return;
157 		}
158 	}
159 	/*
160 	 * print name server records
161 	 */
162 	if (n = ntohs(hp->nscount)) {
163 		fprintf(file,"    AUTHORITY RECORDS:\n");
164 		while (--n >= 0) {
165 			fprintf(file, INDENT);
166 			cp = Print_rr(cp, msg, eom, file);
167 			if (cp == NULL)
168 				return;
169 		}
170 	}
171 	/*
172 	 * print additional records
173 	 */
174 	if (n = ntohs(hp->arcount)) {
175 		fprintf(file,"    ADDITIONAL RECORDS:\n");
176 		while (--n >= 0) {
177 			fprintf(file, INDENT);
178 			cp = Print_rr(cp, msg, eom, file);
179 			if (cp == NULL)
180 				return;
181 		}
182 	}
183 	fprintf(file,"\n------------\n");
184 }
185 
186 
187 char *
Print_cdname_sub(cp,msg,eom,file,format)188 Print_cdname_sub(cp, msg, eom, file, format)
189 	u_char *cp, *msg, *eom;
190 	FILE *file;
191 	int format;
192 {
193 	int n;
194 	u_char name[MAXDNAME];
195 	extern char *strcpy();
196 
197 	if ((n = dn_expand(msg, eom, cp, name, sizeof(name))) < 0)
198 		return (NULL);
199 	if (name[0] == '\0') {
200 	    (void) strcpy(name, "(root)");
201 	}
202 	if (format) {
203 	    fprintf(file, "%-30s", name);
204 	} else {
205 	    fputs((char *)name, file);
206 	}
207 	return ((char *)cp + n);
208 }
209 
210 char *
Print_cdname(cp,msg,eom,file)211 Print_cdname(cp, msg, eom, file)
212 	char *cp, *msg, *eom;
213 	FILE *file;
214 {
215     return(Print_cdname_sub(cp, msg, eom, file, 0));
216 }
217 
218 char *
Print_cdname2(cp,msg,eom,file)219 Print_cdname2(cp, msg, eom, file)
220 	char *cp, *msg, *eom;
221 	FILE *file;
222 {
223     return(Print_cdname_sub(cp, msg, eom, file, 1));
224 }
225 
226 /*
227  * Print resource record fields in human readable form.
228  */
229 char *
Print_rr(cp,msg,eom,file)230 Print_rr(cp, msg, eom, file)
231 	char *cp, *msg, *eom;
232 	FILE *file;
233 {
234 	int type, class, dlen, n, c;
235 	unsigned long rrttl, ttl;
236 	struct in_addr inaddr;
237 	char *cp1, *cp2;
238 	int debug;
239 
240 	if ((cp = Print_cdname(cp, msg, eom, file)) == NULL) {
241 		fprintf(file, "(name truncated?)\n");
242 		return (NULL);			/* compression error */
243 	}
244 
245 	type = _getshort(cp);
246 	cp += sizeof(u_short);
247 	class = _getshort(cp);
248 	cp += sizeof(u_short);
249 	rrttl = _getlong(cp);
250 	cp += sizeof(u_long);
251 	dlen = _getshort(cp);
252 	cp += sizeof(u_short);
253 
254 	debug = _res.options & (RES_DEBUG|RES_DEBUG2);
255 	if (debug) {
256 	    if (_res.options & RES_DEBUG2) {
257 		fprintf(file,"\n\ttype = %s, class = %s, dlen = %d",
258 			    p_type(type), p_class(class), dlen);
259 	    }
260 	    if (type == T_SOA) {
261 		fprintf(file,"\n\tttl = %lu (%s)", rrttl, p_time(rrttl));
262 	    }
263 	    (void) putc('\n', file);
264 	}
265 
266 	cp1 = cp;
267 
268 	/*
269 	 * Print type specific data, if appropriate
270 	 */
271 	switch (type) {
272 	case T_A:
273 		switch (class) {
274 		case C_IN:
275 		case C_HS:
276 			bcopy(cp, (char *)&inaddr, sizeof(inaddr));
277 			if (dlen == 4) {
278 				fprintf(file,"\tinternet address = %s\n",
279 					inet_ntoa(inaddr));
280 				cp += dlen;
281 			} else if (dlen == 7) {
282 				fprintf(file,"\tinternet address = %s",
283 					inet_ntoa(inaddr));
284 				fprintf(file,", protocol = %d", cp[4]);
285 				fprintf(file,", port = %d\n",
286 					(cp[5] << 8) + cp[6]);
287 				cp += dlen;
288 			}
289 			break;
290 		default:
291 			fprintf(file,"\taddress, class = %d, len = %d\n",
292 			    class, dlen);
293 			cp += dlen;
294 		}
295 		break;
296 
297 	case T_CNAME:
298 		fprintf(file,"\tcanonical name = ");
299 		goto doname;
300 
301 	case T_MG:
302 		fprintf(file,"\tmail group member = ");
303 		goto doname;
304 	case T_MB:
305 		fprintf(file,"\tmail box = ");
306 		goto doname;
307 	case T_MR:
308 		fprintf(file,"\tmailbox rename = ");
309 		goto doname;
310 	case T_MX:
311 		fprintf(file,"\tpreference = %u",_getshort(cp));
312 		cp += sizeof(u_short);
313 		fprintf(file,", mail exchanger = ");
314 		goto doname;
315 	case T_NS:
316 		fprintf(file,"\tnameserver = ");
317 		goto doname;
318 	case T_PTR:
319 		fprintf(file,"\tname = ");
320 doname:
321 		cp = Print_cdname(cp, msg, eom, file);
322 		(void) putc('\n', file);
323 		break;
324 
325 	case T_HINFO:
326 		if (n = *cp++) {
327 			fprintf(file,"\tCPU = %.*s", n, cp);
328 			cp += n;
329 		}
330 		if (n = *cp++) {
331 			fprintf(file,"\tOS = %.*s\n", n, cp);
332 			cp += n;
333 		}
334 		break;
335 
336 	case T_SOA:
337 		if (!debug)
338 		    (void) putc('\n', file);
339 		fprintf(file,"\torigin = ");
340 		cp = Print_cdname(cp, msg, eom, file);
341 		fprintf(file,"\n\tmail addr = ");
342 		cp = Print_cdname(cp, msg, eom, file);
343 		fprintf(file,"\n\tserial = %lu", _getlong(cp));
344 		cp += sizeof(u_long);
345 		ttl = _getlong(cp);
346 		fprintf(file,"\n\trefresh = %lu (%s)", ttl, p_time(ttl));
347 		cp += sizeof(u_long);
348 		ttl = _getlong(cp);
349 		fprintf(file,"\n\tretry   = %lu (%s)", ttl, p_time(ttl));
350 		cp += sizeof(u_long);
351 		ttl = _getlong(cp);
352 		fprintf(file,"\n\texpire  = %lu (%s)", ttl, p_time(ttl));
353 		cp += sizeof(u_long);
354 		ttl = _getlong(cp);
355 		fprintf(file,
356 		    "\n\tminimum ttl = %lu (%s)\n", ttl, p_time(ttl));
357 		cp += sizeof(u_long);
358 		break;
359 
360 	case T_MINFO:
361 		if (!debug)
362 		    (void) putc('\n', file);
363 		fprintf(file,"\trequests = ");
364 		cp = Print_cdname(cp, msg, eom, file);
365 		fprintf(file,"\n\terrors = ");
366 		cp = Print_cdname(cp, msg, eom, file);
367 		(void) putc('\n', file);
368 		break;
369 
370 	case T_TXT:
371 		(void) fputs("\ttext = \"", file);
372 		cp2 = cp1 + dlen;
373 		while (cp < cp2) {
374 			if (n = (unsigned char) *cp++) {
375 				for (c = n; c > 0 && cp < cp2; c--)
376 					if (*cp == '\n') {
377 					    (void) putc('\\', file);
378 					    (void) putc(*cp++, file);
379 					} else
380 					    (void) putc(*cp++, file);
381 			}
382 		}
383 		(void) fputs("\"\n", file);
384   		break;
385 
386 	case T_UINFO:
387 		fprintf(file,"\tuser info = %s\n", cp);
388 		cp += dlen;
389 		break;
390 
391 	case T_UID:
392 	case T_GID:
393 		if (dlen == 4) {
394 			fprintf(file,"\t%cid = %lu\n",type == T_UID ? 'u' : 'g',
395 			    _getlong(cp));
396 			cp += sizeof(int);
397 		} else {
398 			fprintf(file,"\t%cid of length %d?\n",
399 			    type == T_UID ? 'u' : 'g', dlen);
400 			cp += dlen;
401 		}
402 		break;
403 
404 	case T_WKS: {
405 		struct protoent *protoPtr;
406 
407 		if (dlen < sizeof(u_long) + 1)
408 			break;
409 		if (!debug)
410 		    (void) putc('\n', file);
411 		bcopy(cp, (char *)&inaddr, sizeof(inaddr));
412 		cp += sizeof(u_long);
413 		if ((protoPtr = getprotobynumber(*cp)) != NULL) {
414 		    fprintf(file,"\tinet address = %s, protocol = %s\n\t",
415 			inet_ntoa(inaddr), protoPtr->p_name);
416 		} else {
417 		    fprintf(file,"\tinet address = %s, protocol = %d\n\t",
418 			inet_ntoa(inaddr), *cp);
419 		}
420 		cp++;
421 		n = 0;
422 		while (cp < cp1 + dlen) {
423 			c = *cp++;
424 			do {
425 				struct servent *s;
426 
427  				if (c & 0200) {
428 					s = getservbyport((int)htons(n),
429 					    protoPtr ? protoPtr->p_name : NULL);
430 					if (s != NULL) {
431 					    fprintf(file,"  %s", s->s_name);
432 					} else {
433 					    fprintf(file," #%d", n);
434 					}
435 				}
436  				c <<= 1;
437 			} while (++n & 07);
438 		}
439 		putc('\n',file);
440 	    }
441 	    break;
442 
443 	case T_NULL:
444 		fprintf(file, "\tNULL (dlen %d)\n", dlen);
445 		cp += dlen;
446 		break;
447 
448 	default:
449 		fprintf(file,"\t??? unknown type %d ???\n", type);
450 		cp += dlen;
451 	}
452 	if (_res.options & RES_DEBUG && type != T_SOA) {
453 	    fprintf(file,"\tttl = %lu (%s)\n", rrttl, p_time(rrttl));
454 	}
455 	if (cp != cp1 + dlen) {
456 		fprintf(file,
457 			"\n*** Error: record size incorrect (%d != %d)\n\n",
458 			cp - cp1, dlen);
459 		cp = NULL;
460 	}
461 	return (cp);
462 }
463