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 }