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