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