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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <netinet/in.h> 44 #include <stdio.h> 45 #include <arpa/nameser.h> 46 47 extern char *p_cdname(), *p_rr(), *p_type(), *p_class(), *p_time(); 48 extern char *inet_ntoa(); 49 void fp_query(char *msg, FILE *file); 50 51 char *_res_opcodes[] = { 52 "QUERY", 53 "IQUERY", 54 "CQUERYM", 55 "CQUERYU", 56 "4", 57 "5", 58 "6", 59 "7", 60 "8", 61 "UPDATEA", 62 "UPDATED", 63 "UPDATEDA", 64 "UPDATEM", 65 "UPDATEMA", 66 "ZONEINIT", 67 "ZONEREF", 68 }; 69 70 char *_res_resultcodes[] = { 71 "NOERROR", 72 "FORMERR", 73 "SERVFAIL", 74 "NXDOMAIN", 75 "NOTIMP", 76 "REFUSED", 77 "6", 78 "7", 79 "8", 80 "9", 81 "10", 82 "11", 83 "12", 84 "13", 85 "14", 86 "NOCHANGE", 87 }; 88 89 void 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 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, ", class = %s\n\n", 148 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 char * 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(msg, msg + 512, cp, name, sizeof (name))) < 0) 199 return (NULL); 200 if (name[0] == '\0') { 201 name[0] = '.'; 202 name[1] = '\0'; 203 } 204 fputs(name, file); 205 return (cp + n); 206 } 207 208 /* 209 * Print resource record fields in human readable form. 210 */ 211 char * 212 p_rr(cp, msg, file) 213 char *cp, *msg; 214 FILE *file; 215 { 216 int type, class, dlen, n, c; 217 struct in_addr inaddr; 218 char *cp1, *cp2; 219 220 if ((cp = p_cdname(cp, msg, file)) == NULL) 221 return (NULL); /* compression error */ 222 fprintf(file, "\n\ttype = %s", p_type(type = _getshort(cp))); 223 cp += sizeof (u_short); 224 fprintf(file, ", class = %s", p_class(class = _getshort(cp))); 225 cp += sizeof (u_short); 226 fprintf(file, ", ttl = %s", p_time(_getlong(cp))); 227 cp += sizeof (u_long); 228 fprintf(file, ", dlen = %d\n", dlen = _getshort(cp)); 229 cp += sizeof (u_short); 230 cp1 = cp; 231 /* 232 * Print type specific data, if appropriate 233 */ 234 switch (type) { 235 case T_A: 236 switch (class) { 237 case C_IN: 238 case C_HS: 239 #ifdef SYSV 240 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr)); 241 #else 242 bcopy(cp, (char *)&inaddr, sizeof (inaddr)); 243 #endif 244 if (dlen == 4) { 245 fprintf(file, "\tinternet address = %s\n", 246 inet_ntoa(inaddr)); 247 cp += dlen; 248 } else if (dlen == 7) { 249 fprintf(file, "\tinternet address = %s", 250 inet_ntoa(inaddr)); 251 fprintf(file, ", protocol = %d", cp[4]); 252 fprintf(file, ", port = %d\n", 253 (cp[5] << 8) + cp[6]); 254 cp += dlen; 255 } 256 break; 257 default: 258 cp += dlen; 259 } 260 break; 261 case T_CNAME: 262 case T_MB: 263 case T_MG: 264 case T_MR: 265 case T_NS: 266 case T_PTR: 267 fprintf(file, "\tdomain name = "); 268 cp = p_cdname(cp, msg, file); 269 fprintf(file, "\n"); 270 break; 271 272 case T_HINFO: 273 if (n = *cp++) { 274 fprintf(file, "\tCPU=%.*s\n", n, cp); 275 cp += n; 276 } 277 if (n = *cp++) { 278 fprintf(file, "\tOS=%.*s\n", n, cp); 279 cp += n; 280 } 281 break; 282 283 case T_SOA: 284 fprintf(file, "\torigin = "); 285 cp = p_cdname(cp, msg, file); 286 fprintf(file, "\n\tmail addr = "); 287 cp = p_cdname(cp, msg, file); 288 fprintf(file, "\n\tserial = %ld", _getlong(cp)); 289 cp += sizeof (u_long); 290 fprintf(file, "\n\trefresh = %s", p_time(_getlong(cp))); 291 cp += sizeof (u_long); 292 fprintf(file, "\n\tretry = %s", p_time(_getlong(cp))); 293 cp += sizeof (u_long); 294 fprintf(file, "\n\texpire = %s", p_time(_getlong(cp))); 295 cp += sizeof (u_long); 296 fprintf(file, "\n\tmin = %s\n", p_time(_getlong(cp))); 297 cp += sizeof (u_long); 298 break; 299 300 case T_MX: 301 fprintf(file, "\tpreference = %ld,", _getshort(cp)); 302 cp += sizeof (u_short); 303 fprintf(file, " name = "); 304 cp = p_cdname(cp, msg, file); 305 break; 306 307 case T_TXT: 308 (void) fputs("\t\"", file); 309 cp2 = cp1 + dlen; 310 while (cp < cp2) { 311 if (n = (unsigned char) *cp++) { 312 for (c = n; c > 0 && cp < cp2; c--) 313 if (*cp == '\n') { 314 (void) putc('\\', file); 315 (void) putc(*cp++, file); 316 } else 317 (void) putc(*cp++, file); 318 } 319 } 320 (void) fputs("\"\n", file); 321 break; 322 323 case T_MINFO: 324 fprintf(file, "\trequests = "); 325 cp = p_cdname(cp, msg, file); 326 fprintf(file, "\n\terrors = "); 327 cp = p_cdname(cp, msg, file); 328 break; 329 330 case T_UINFO: 331 fprintf(file, "\t%s\n", cp); 332 cp += dlen; 333 break; 334 335 case T_UID: 336 case T_GID: 337 if (dlen == 4) { 338 fprintf(file, "\t%ld\n", _getlong(cp)); 339 cp += sizeof (int); 340 } 341 break; 342 343 case T_WKS: 344 if (dlen < sizeof (u_long) + 1) 345 break; 346 #ifdef SYSV 347 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr)); 348 #else 349 bcopy(cp, (char *)&inaddr, sizeof (inaddr)); 350 #endif 351 cp += sizeof (u_long); 352 fprintf(file, "\tinternet address = %s, protocol = %d\n\t", 353 inet_ntoa(inaddr), *cp++); 354 n = 0; 355 while (cp < cp1 + dlen) { 356 c = *cp++; 357 do { 358 if (c & 0200) 359 fprintf(file, " %d", n); 360 c <<= 1; 361 } while (++n & 07); 362 } 363 putc('\n', file); 364 break; 365 366 #ifdef ALLOW_T_UNSPEC 367 case T_UNSPEC: 368 { 369 int NumBytes = 8; 370 char *DataPtr; 371 int i; 372 373 if (dlen < NumBytes) NumBytes = dlen; 374 fprintf(file, "\tFirst %d bytes of hex data:", 375 NumBytes); 376 for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) 377 fprintf(file, " %x", *DataPtr); 378 fputs("\n", file); 379 cp += dlen; 380 } 381 break; 382 #endif /* ALLOW_T_UNSPEC */ 383 384 default: 385 fprintf(file, "\t???\n"); 386 cp += dlen; 387 } 388 if (cp != cp1 + dlen) { 389 fprintf(file, "packet size error (%#x != %#x)\n", cp, cp1+dlen); 390 cp = NULL; 391 } 392 fprintf(file, "\n"); 393 return (cp); 394 } 395 396 static char nbuf[40]; 397 398 /* 399 * Return a string for the type 400 */ 401 char * 402 p_type(type) 403 int type; 404 { 405 switch (type) { 406 case T_A: 407 return ("A"); 408 case T_NS: /* authoritative server */ 409 return ("NS"); 410 case T_CNAME: /* canonical name */ 411 return ("CNAME"); 412 case T_SOA: /* start of authority zone */ 413 return ("SOA"); 414 case T_MB: /* mailbox domain name */ 415 return ("MB"); 416 case T_MG: /* mail group member */ 417 return ("MG"); 418 case T_MR: /* mail rename name */ 419 return ("MR"); 420 case T_NULL: /* null resource record */ 421 return ("NULL"); 422 case T_WKS: /* well known service */ 423 return ("WKS"); 424 case T_PTR: /* domain name pointer */ 425 return ("PTR"); 426 case T_HINFO: /* host information */ 427 return ("HINFO"); 428 case T_MINFO: /* mailbox information */ 429 return ("MINFO"); 430 case T_MX: /* mail routing info */ 431 return ("MX"); 432 case T_TXT: /* text */ 433 return ("TXT"); 434 case T_AXFR: /* zone transfer */ 435 return ("AXFR"); 436 case T_MAILB: /* mail box */ 437 return ("MAILB"); 438 case T_MAILA: /* mail address */ 439 return ("MAILA"); 440 case T_ANY: /* matches any type */ 441 return ("ANY"); 442 case T_UINFO: 443 return ("UINFO"); 444 case T_UID: 445 return ("UID"); 446 case T_GID: 447 return ("GID"); 448 #ifdef ALLOW_T_UNSPEC 449 case T_UNSPEC: 450 return ("UNSPEC"); 451 #endif /* ALLOW_T_UNSPEC */ 452 default: 453 (void) sprintf(nbuf, "%d", type); 454 return (nbuf); 455 } 456 } 457 458 /* 459 * Return a mnemonic for class 460 */ 461 char * 462 p_class(class) 463 int class; 464 { 465 466 switch (class) { 467 case C_IN: /* internet class */ 468 return ("IN"); 469 case C_HS: /* hesiod class */ 470 return ("HS"); 471 case C_ANY: /* matches any class */ 472 return ("ANY"); 473 default: 474 (void) sprintf(nbuf, "%d", class); 475 return (nbuf); 476 } 477 } 478 479 /* 480 * Return a mnemonic for a time to live 481 */ 482 char * 483 p_time(value) 484 u_long value; 485 { 486 int secs, mins, hours; 487 register char *p; 488 489 if (value == 0) { 490 strcpy(nbuf, "0 secs"); 491 return (nbuf); 492 } 493 494 secs = value % 60; 495 value /= 60; 496 mins = value % 60; 497 value /= 60; 498 hours = value % 24; 499 value /= 24; 500 501 #define PLURALIZE(x) x, (x == 1) ? "" : "s" 502 p = nbuf; 503 if (value) { 504 (void) sprintf(p, "%d day%s", PLURALIZE(value)); 505 while (*++p); 506 } 507 if (hours) { 508 if (value) 509 *p++ = ' '; 510 (void) sprintf(p, "%d hour%s", PLURALIZE(hours)); 511 while (*++p); 512 } 513 if (mins) { 514 if (value || hours) 515 *p++ = ' '; 516 (void) sprintf(p, "%d min%s", PLURALIZE(mins)); 517 while (*++p); 518 } 519 if (secs || ! (value || hours || mins)) { 520 if (value || hours || mins) 521 *p++ = ' '; 522 (void) sprintf(p, "%d sec%s", PLURALIZE(secs)); 523 } 524 return (nbuf); 525 } 526