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 * Copyright 1996 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 "synonyms.h" 43 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 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 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 fp_query(msg, file) 101 char *msg; 102 FILE *file; 103 { 104 register char *cp; 105 register HEADER *hp; 106 register int n; 107 108 /* 109 * Print header fields. 110 */ 111 hp = (HEADER *)msg; 112 cp = msg + sizeof (HEADER); 113 fprintf(file, "HEADER:\n"); 114 fprintf(file, "\topcode = %s", _res_opcodes[hp->opcode]); 115 fprintf(file, ", id = %d", ntohs(hp->id)); 116 fprintf(file, ", rcode = %s\n", _res_resultcodes[hp->rcode]); 117 fprintf(file, "\theader flags: "); 118 if (hp->qr) 119 fprintf(file, " qr"); 120 if (hp->aa) 121 fprintf(file, " aa"); 122 if (hp->tc) 123 fprintf(file, " tc"); 124 if (hp->rd) 125 fprintf(file, " rd"); 126 if (hp->ra) 127 fprintf(file, " ra"); 128 if (hp->pr) 129 fprintf(file, " pr"); 130 fprintf(file, "\n\tqdcount = %d", ntohs(hp->qdcount)); 131 fprintf(file, ", ancount = %d", ntohs(hp->ancount)); 132 fprintf(file, ", nscount = %d", ntohs(hp->nscount)); 133 fprintf(file, ", arcount = %d\n\n", ntohs(hp->arcount)); 134 /* 135 * Print question records. 136 */ 137 if (n = ntohs(hp->qdcount)) { 138 fprintf(file, "QUESTIONS:\n"); 139 while (--n >= 0) { 140 fprintf(file, "\t"); 141 cp = p_cdname(cp, msg, file); 142 if (cp == NULL) 143 return; 144 fprintf(file, ", type = %s", p_type(_getshort(cp))); 145 cp += sizeof (u_short); 146 fprintf(file, ", class = %s\n\n", 147 p_class(_getshort(cp))); 148 cp += sizeof (u_short); 149 } 150 } 151 /* 152 * Print authoritative answer records 153 */ 154 if (n = ntohs(hp->ancount)) { 155 fprintf(file, "ANSWERS:\n"); 156 while (--n >= 0) { 157 fprintf(file, "\t"); 158 cp = p_rr(cp, msg, file); 159 if (cp == NULL) 160 return; 161 } 162 } 163 /* 164 * print name server records 165 */ 166 if (n = ntohs(hp->nscount)) { 167 fprintf(file, "NAME SERVERS:\n"); 168 while (--n >= 0) { 169 fprintf(file, "\t"); 170 cp = p_rr(cp, msg, file); 171 if (cp == NULL) 172 return; 173 } 174 } 175 /* 176 * print additional records 177 */ 178 if (n = ntohs(hp->arcount)) { 179 fprintf(file, "ADDITIONAL RECORDS:\n"); 180 while (--n >= 0) { 181 fprintf(file, "\t"); 182 cp = p_rr(cp, msg, file); 183 if (cp == NULL) 184 return; 185 } 186 } 187 } 188 189 char * 190 p_cdname(cp, msg, file) 191 char *cp, *msg; 192 FILE *file; 193 { 194 char name[MAXDNAME]; 195 int n; 196 197 if ((n = dn_expand(msg, msg + 512, cp, name, sizeof (name))) < 0) 198 return (NULL); 199 if (name[0] == '\0') { 200 name[0] = '.'; 201 name[1] = '\0'; 202 } 203 fputs(name, file); 204 return (cp + n); 205 } 206 207 /* 208 * Print resource record fields in human readable form. 209 */ 210 char * 211 p_rr(cp, msg, file) 212 char *cp, *msg; 213 FILE *file; 214 { 215 int type, class, dlen, n, c; 216 struct in_addr inaddr; 217 char *cp1, *cp2; 218 219 if ((cp = p_cdname(cp, msg, file)) == NULL) 220 return (NULL); /* compression error */ 221 fprintf(file, "\n\ttype = %s", p_type(type = _getshort(cp))); 222 cp += sizeof (u_short); 223 fprintf(file, ", class = %s", p_class(class = _getshort(cp))); 224 cp += sizeof (u_short); 225 fprintf(file, ", ttl = %s", p_time(_getlong(cp))); 226 cp += sizeof (u_long); 227 fprintf(file, ", dlen = %d\n", dlen = _getshort(cp)); 228 cp += sizeof (u_short); 229 cp1 = cp; 230 /* 231 * Print type specific data, if appropriate 232 */ 233 switch (type) { 234 case T_A: 235 switch (class) { 236 case C_IN: 237 case C_HS: 238 #ifdef SYSV 239 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr)); 240 #else 241 bcopy(cp, (char *)&inaddr, sizeof (inaddr)); 242 #endif 243 if (dlen == 4) { 244 fprintf(file, "\tinternet address = %s\n", 245 inet_ntoa(inaddr)); 246 cp += dlen; 247 } else if (dlen == 7) { 248 fprintf(file, "\tinternet address = %s", 249 inet_ntoa(inaddr)); 250 fprintf(file, ", protocol = %d", cp[4]); 251 fprintf(file, ", port = %d\n", 252 (cp[5] << 8) + cp[6]); 253 cp += dlen; 254 } 255 break; 256 default: 257 cp += dlen; 258 } 259 break; 260 case T_CNAME: 261 case T_MB: 262 case T_MG: 263 case T_MR: 264 case T_NS: 265 case T_PTR: 266 fprintf(file, "\tdomain name = "); 267 cp = p_cdname(cp, msg, file); 268 fprintf(file, "\n"); 269 break; 270 271 case T_HINFO: 272 if (n = *cp++) { 273 fprintf(file, "\tCPU=%.*s\n", n, cp); 274 cp += n; 275 } 276 if (n = *cp++) { 277 fprintf(file, "\tOS=%.*s\n", n, cp); 278 cp += n; 279 } 280 break; 281 282 case T_SOA: 283 fprintf(file, "\torigin = "); 284 cp = p_cdname(cp, msg, file); 285 fprintf(file, "\n\tmail addr = "); 286 cp = p_cdname(cp, msg, file); 287 fprintf(file, "\n\tserial = %ld", _getlong(cp)); 288 cp += sizeof (u_long); 289 fprintf(file, "\n\trefresh = %s", p_time(_getlong(cp))); 290 cp += sizeof (u_long); 291 fprintf(file, "\n\tretry = %s", p_time(_getlong(cp))); 292 cp += sizeof (u_long); 293 fprintf(file, "\n\texpire = %s", p_time(_getlong(cp))); 294 cp += sizeof (u_long); 295 fprintf(file, "\n\tmin = %s\n", p_time(_getlong(cp))); 296 cp += sizeof (u_long); 297 break; 298 299 case T_MX: 300 fprintf(file, "\tpreference = %ld,", _getshort(cp)); 301 cp += sizeof (u_short); 302 fprintf(file, " name = "); 303 cp = p_cdname(cp, msg, file); 304 break; 305 306 case T_TXT: 307 (void) fputs("\t\"", file); 308 cp2 = cp1 + dlen; 309 while (cp < cp2) { 310 if (n = (unsigned char) *cp++) { 311 for (c = n; c > 0 && cp < cp2; c--) 312 if (*cp == '\n') { 313 (void) putc('\\', file); 314 (void) putc(*cp++, file); 315 } else 316 (void) putc(*cp++, file); 317 } 318 } 319 (void) fputs("\"\n", file); 320 break; 321 322 case T_MINFO: 323 fprintf(file, "\trequests = "); 324 cp = p_cdname(cp, msg, file); 325 fprintf(file, "\n\terrors = "); 326 cp = p_cdname(cp, msg, file); 327 break; 328 329 case T_UINFO: 330 fprintf(file, "\t%s\n", cp); 331 cp += dlen; 332 break; 333 334 case T_UID: 335 case T_GID: 336 if (dlen == 4) { 337 fprintf(file, "\t%ld\n", _getlong(cp)); 338 cp += sizeof (int); 339 } 340 break; 341 342 case T_WKS: 343 if (dlen < sizeof (u_long) + 1) 344 break; 345 #ifdef SYSV 346 memcpy((void *)&inaddr, (void *)cp, sizeof (inaddr)); 347 #else 348 bcopy(cp, (char *)&inaddr, sizeof (inaddr)); 349 #endif 350 cp += sizeof (u_long); 351 fprintf(file, "\tinternet address = %s, protocol = %d\n\t", 352 inet_ntoa(inaddr), *cp++); 353 n = 0; 354 while (cp < cp1 + dlen) { 355 c = *cp++; 356 do { 357 if (c & 0200) 358 fprintf(file, " %d", n); 359 c <<= 1; 360 } while (++n & 07); 361 } 362 putc('\n', file); 363 break; 364 365 #ifdef ALLOW_T_UNSPEC 366 case T_UNSPEC: 367 { 368 int NumBytes = 8; 369 char *DataPtr; 370 int i; 371 372 if (dlen < NumBytes) NumBytes = dlen; 373 fprintf(file, "\tFirst %d bytes of hex data:", 374 NumBytes); 375 for (i = 0, DataPtr = cp; i < NumBytes; i++, DataPtr++) 376 fprintf(file, " %x", *DataPtr); 377 fputs("\n", file); 378 cp += dlen; 379 } 380 break; 381 #endif /* ALLOW_T_UNSPEC */ 382 383 default: 384 fprintf(file, "\t???\n"); 385 cp += dlen; 386 } 387 if (cp != cp1 + dlen) { 388 fprintf(file, "packet size error (%#x != %#x)\n", cp, cp1+dlen); 389 cp = NULL; 390 } 391 fprintf(file, "\n"); 392 return (cp); 393 } 394 395 static char nbuf[40]; 396 397 /* 398 * Return a string for the type 399 */ 400 char * 401 p_type(type) 402 int type; 403 { 404 switch (type) { 405 case T_A: 406 return ("A"); 407 case T_NS: /* authoritative server */ 408 return ("NS"); 409 case T_CNAME: /* canonical name */ 410 return ("CNAME"); 411 case T_SOA: /* start of authority zone */ 412 return ("SOA"); 413 case T_MB: /* mailbox domain name */ 414 return ("MB"); 415 case T_MG: /* mail group member */ 416 return ("MG"); 417 case T_MR: /* mail rename name */ 418 return ("MR"); 419 case T_NULL: /* null resource record */ 420 return ("NULL"); 421 case T_WKS: /* well known service */ 422 return ("WKS"); 423 case T_PTR: /* domain name pointer */ 424 return ("PTR"); 425 case T_HINFO: /* host information */ 426 return ("HINFO"); 427 case T_MINFO: /* mailbox information */ 428 return ("MINFO"); 429 case T_MX: /* mail routing info */ 430 return ("MX"); 431 case T_TXT: /* text */ 432 return ("TXT"); 433 case T_AXFR: /* zone transfer */ 434 return ("AXFR"); 435 case T_MAILB: /* mail box */ 436 return ("MAILB"); 437 case T_MAILA: /* mail address */ 438 return ("MAILA"); 439 case T_ANY: /* matches any type */ 440 return ("ANY"); 441 case T_UINFO: 442 return ("UINFO"); 443 case T_UID: 444 return ("UID"); 445 case T_GID: 446 return ("GID"); 447 #ifdef ALLOW_T_UNSPEC 448 case T_UNSPEC: 449 return ("UNSPEC"); 450 #endif /* ALLOW_T_UNSPEC */ 451 default: 452 (void) sprintf(nbuf, "%d", type); 453 return (nbuf); 454 } 455 } 456 457 /* 458 * Return a mnemonic for class 459 */ 460 char * 461 p_class(class) 462 int class; 463 { 464 465 switch (class) { 466 case C_IN: /* internet class */ 467 return ("IN"); 468 case C_HS: /* hesiod class */ 469 return ("HS"); 470 case C_ANY: /* matches any class */ 471 return ("ANY"); 472 default: 473 (void) sprintf(nbuf, "%d", class); 474 return (nbuf); 475 } 476 } 477 478 /* 479 * Return a mnemonic for a time to live 480 */ 481 char * 482 p_time(value) 483 u_long value; 484 { 485 int secs, mins, hours; 486 register char *p; 487 488 if (value == 0) { 489 strcpy(nbuf, "0 secs"); 490 return (nbuf); 491 } 492 493 secs = value % 60; 494 value /= 60; 495 mins = value % 60; 496 value /= 60; 497 hours = value % 24; 498 value /= 24; 499 500 #define PLURALIZE(x) x, (x == 1) ? "" : "s" 501 p = nbuf; 502 if (value) { 503 (void) sprintf(p, "%d day%s", PLURALIZE(value)); 504 while (*++p); 505 } 506 if (hours) { 507 if (value) 508 *p++ = ' '; 509 (void) sprintf(p, "%d hour%s", PLURALIZE(hours)); 510 while (*++p); 511 } 512 if (mins) { 513 if (value || hours) 514 *p++ = ' '; 515 (void) sprintf(p, "%d min%s", PLURALIZE(mins)); 516 while (*++p); 517 } 518 if (secs || ! (value || hours || mins)) { 519 if (value || hours || mins) 520 *p++ = ' '; 521 (void) sprintf(p, "%d sec%s", PLURALIZE(secs)); 522 } 523 return (nbuf); 524 } 525