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