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 }