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