1: /*
   2:  * Copyright (c) 1985,1989 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted provided
   6:  * that: (1) source distributions retain this entire copyright notice and
   7:  * comment, and (2) distributions including binaries display the following
   8:  * acknowledgement:  ``This product includes software developed by the
   9:  * University of California, Berkeley and its contributors'' in the
  10:  * documentation or other materials provided with the distribution and in
  11:  * all advertising materials mentioning features or use of this software.
  12:  * Neither the name of the University nor the names of its contributors may
  13:  * be used to endorse or promote products derived from this software without
  14:  * specific prior written permission.
  15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18:  */
  19: 
  20: #if !defined(lint) && defined(DOSCCS)
  21: char copyright[] =
  22: "@(#) Copyright (c) 1985,1989 Regents of the University of California.\n\
  23:  All rights reserved.\n";
  24: 
  25: static char sccsid[] = "@(#)main.c	5.39 (Berkeley) 6/24/90";
  26: #endif
  27: 
  28: /*
  29:  *******************************************************************************
  30:  *
  31:  *   main.c --
  32:  *
  33:  *	Main routine and some action routines for the name server
  34:  *	lookup program.
  35:  *
  36:  *	Andrew Cherenson
  37:  *	U.C. Berkeley Computer Science Div.
  38:  *	CS298-26, Fall 1985
  39:  *
  40:  *******************************************************************************
  41:  */
  42: 
  43: #include <sys/param.h>
  44: #include <netdb.h>
  45: #include <sys/socket.h>
  46: #include <netinet/in.h>
  47: #include <arpa/nameser.h>
  48: #include <arpa/inet.h>
  49: #include <resolv.h>
  50: #include <signal.h>
  51: #include <setjmp.h>
  52: #include <ctype.h>
  53: #include <stdio.h>
  54: #include <string.h>
  55: #include "res.h"
  56: #include "pathnames.h"
  57: 
  58: /*
  59:  *  Default Internet address of the current host.
  60:  */
  61: 
  62: #if BSD < 43
  63: #define LOCALHOST "127.0.0.1"
  64: #endif
  65: 
  66: 
  67: /*
  68:  * Name of a top-level name server. Can be changed with
  69:  * the "set root" command.
  70:  */
  71: 
  72: #ifndef ROOT_SERVER
  73: #define     ROOT_SERVER "ns.internic.net."
  74: #endif
  75: char        rootServerName[NAME_LEN] = ROOT_SERVER;
  76: 
  77: 
  78: /*
  79:  *  Import the state information from the resolver library.
  80:  */
  81: 
  82: extern struct state _res;
  83: 
  84: 
  85: /*
  86:  *  Info about the most recently queried host.
  87:  */
  88: 
  89: HostInfo    curHostInfo;
  90: int     curHostValid = FALSE;
  91: 
  92: 
  93: /*
  94:  *  Info about the default name server.
  95:  */
  96: 
  97: HostInfo    *defaultPtr = NULL;
  98: char        defaultServer[NAME_LEN];
  99: struct in_addr  defaultAddr;
 100: 
 101: 
 102: /*
 103:  *  Initial name server query type is Address.
 104:  */
 105: 
 106: int     queryType = T_A;
 107: int     queryClass = C_IN;
 108: 
 109: /*
 110:  * Stuff for Interrupt (control-C) signal handler.
 111:  */
 112: 
 113: #ifdef SVR3
 114: extern void IntrHandler();
 115: #else
 116: extern int  IntrHandler();
 117: #endif
 118: FILE        *filePtr;
 119: jmp_buf     env;
 120: 
 121: static void CvtAddrToPtr();
 122: static void ReadRC();
 123: 
 124: 
 125: /*
 126:  *******************************************************************************
 127:  *
 128:  *  main --
 129:  *
 130:  *	Initializes the resolver library and determines the address
 131:  *	of the initial name server. The yylex routine is used to
 132:  *	read and perform commands.
 133:  *
 134:  *******************************************************************************
 135:  */
 136: 
 137: main(argc, argv)
 138:     int     argc;
 139:     char    **argv;
 140: {
 141:     char    *wantedHost = NULL;
 142:     Boolean useLocalServer;
 143:     int     result;
 144:     int     i;
 145:     struct hostent  *hp;
 146:     extern int  h_errno;
 147: 
 148:     /*
 149:      *  Initialize the resolver library routines.
 150:      */
 151: 
 152:     if (res_init() == -1) {
 153:     fprintf(stderr,"*** Can't initialize resolver.\n");
 154:     exit(1);
 155:     }
 156: 
 157:     /*
 158:      *  Allocate space for the default server's host info and
 159:      *  find the server's address and name. If the resolver library
 160:      *  already has some addresses for a potential name server,
 161:      *  then use them. Otherwise, see if the current host has a server.
 162:      *  Command line arguments may override the choice of initial server.
 163:      */
 164: 
 165:     defaultPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
 166: 
 167:     /*
 168:      * Parse the arguments:
 169:      *  no args =  go into interactive mode, use default host as server
 170:      *	1 arg	=  use as host name to be looked up, default host will be server
 171:      *		   non-interactive mode
 172:      *  2 args	=  1st arg:
 173:      *		     if it is '-', then
 174:      *		        ignore but go into interactive mode
 175:      *		     else
 176:      *		         use as host name to be looked up,
 177:      *			 go into non-interactive mode
 178:      *		2nd arg: name or inet address of server
 179:      *
 180:      *	"Set" options are specified with a leading - and must come before
 181:      *	any arguments. For example, to find the well-known services for
 182:      *  a host, type "nslookup -query=wks host"
 183:      */
 184: 
 185:     ReadRC();           /* look for options file */
 186: 
 187:     ++argv; --argc;     /* skip prog name */
 188: 
 189:     while (argc && *argv[0] == '-' && argv[0][1]) {
 190:     (void) SetOption (&(argv[0][1]));
 191:     ++argv; --argc;
 192:     }
 193:     if (argc > 2) {
 194:     Usage();
 195:     }
 196:     if (argc && *argv[0] != '-') {
 197:     wantedHost = *argv; /* name of host to be looked up */
 198:     }
 199: 
 200:     useLocalServer = FALSE;
 201:     if (argc == 2) {
 202:     struct in_addr addr;
 203: 
 204:     /*
 205: 	 * Use an explicit name server. If the hostname lookup fails,
 206: 	 * default to the server(s) in resolv.conf.
 207: 	 */
 208: 
 209:     addr.s_addr = inet_addr(*++argv);
 210:     if (addr.s_addr != (u_long)-1) {
 211:         _res.nscount = 1;
 212:         _res.nsaddr.sin_addr = addr;
 213:     } else {
 214:         hp = gethostbyname(*argv);
 215:         if (hp == NULL) {
 216:         fprintf(stderr, "*** Can't find server address for '%s': ",
 217:             *argv);
 218:         herror((char *)NULL);
 219:         fputc('\n', stderr);
 220:         } else {
 221: #if BSD < 43
 222:         bcopy(hp->h_addr, (char *)&_res.nsaddr.sin_addr, hp->h_length);
 223:         _res.nscount = 1;
 224: #else
 225:         for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) {
 226:             bcopy(hp->h_addr_list[i],
 227:                 (char *)&_res.nsaddr_list[i].sin_addr,
 228:                 hp->h_length);
 229:         }
 230:         _res.nscount = i;
 231: #endif
 232:         }
 233:     }
 234:     }
 235: 
 236: 
 237:     if (_res.nscount == 0 || useLocalServer) {
 238:     LocalServer(defaultPtr);
 239:     } else {
 240:     for (i = 0; i < _res.nscount; i++) {
 241:         if (_res.nsaddr_list[i].sin_addr.s_addr == INADDR_ANY) {
 242:             LocalServer(defaultPtr);
 243:         break;
 244:         } else {
 245:         result = GetHostInfoByAddr(&(_res.nsaddr_list[i].sin_addr),
 246:                     &(_res.nsaddr_list[i].sin_addr),
 247:                     defaultPtr);
 248:         if (result != SUCCESS) {
 249:             fprintf(stderr,
 250:             "*** Can't find server name for address %s: %s\n",
 251:                inet_ntoa(_res.nsaddr_list[i].sin_addr),
 252:                DecodeError(result));
 253:         } else {
 254:             defaultAddr = _res.nsaddr_list[i].sin_addr;
 255:             break;
 256:         }
 257:         }
 258:     }
 259: 
 260:     /*
 261: 	 *  If we have exhausted the list, tell the user about the
 262: 	 *  command line argument to specify an address.
 263: 	 */
 264: 
 265:     if (i == _res.nscount) {
 266:         fprintf(stderr, "*** Default servers are not available\n");
 267:         exit(1);
 268:     }
 269: 
 270:     }
 271:     strcpy(defaultServer, defaultPtr->name);
 272: 
 273: 
 274: #ifdef DEBUG
 275: #ifdef DEBUG2
 276:     _res.options |= RES_DEBUG2;
 277: #endif
 278:     _res.options |= RES_DEBUG;
 279:     _res.retry    = 2;
 280: #endif DEBUG
 281: 
 282:     /*
 283:      * If we're in non-interactive mode, look up the wanted host and quit.
 284:      * Otherwise, print the initial server's name and continue with
 285:      * the initialization.
 286:      */
 287: 
 288:     if (wantedHost != (char *) NULL) {
 289:     LookupHost(wantedHost, 0);
 290:     } else {
 291:     PrintHostInfo(stdout, "Default Server:", defaultPtr);
 292: 
 293:     /*
 294: 	 * Setup the environment to allow the interrupt handler to return here.
 295: 	 */
 296: 
 297:     (void) setjmp(env);
 298: 
 299:     /*
 300: 	 * Return here after a longjmp.
 301: 	 */
 302: 
 303:     signal(SIGINT, IntrHandler);
 304:     signal(SIGPIPE, SIG_IGN);
 305: 
 306:     /*
 307: 	 * Read and evaluate commands. The commands are described in commands.l
 308: 	 * Yylex returns 0 when ^D or 'exit' is typed.
 309: 	 */
 310: 
 311:     printf("> ");
 312:     fflush(stdout);
 313:     while(yylex()) {
 314:         printf("> ");
 315:         fflush(stdout);
 316:     }
 317:     }
 318:     exit(0);
 319: }
 320: 
 321: 
 322: LocalServer(defaultPtr)
 323:     HostInfo *defaultPtr;
 324: {
 325:     char    hostName[NAME_LEN];
 326: #if BSD < 43
 327:     int     result;
 328: #endif
 329: 
 330:     gethostname(hostName, sizeof(hostName));
 331: 
 332: #if BSD < 43
 333:     defaultAddr.s_addr = inet_addr(LOCALHOST);
 334:     result = GetHostInfoByName(&defaultAddr, C_IN, T_A,
 335:         hostName, defaultPtr, 1);
 336:     if (result != SUCCESS) {
 337:     fprintf(stderr,
 338:     "*** Can't find initialize address for server %s: %s\n",
 339:             defaultServer, DecodeError(result));
 340:     exit(1);
 341:     }
 342: #else
 343:     defaultAddr.s_addr = htonl(INADDR_ANY);
 344:     (void) GetHostInfoByName(&defaultAddr, C_IN, T_A, "0.0.0.0", defaultPtr, 1);
 345:     free(defaultPtr->name);
 346:     defaultPtr->name = Calloc(1, sizeof(hostName)+1);
 347:     strcpy(defaultPtr->name, hostName);
 348: #endif
 349: }
 350: 
 351: 
 352: /*
 353:  *******************************************************************************
 354:  *
 355:  *  Usage --
 356:  *
 357:  *	Lists the proper methods to run the program and exits.
 358:  *
 359:  *******************************************************************************
 360:  */
 361: 
 362: Usage()
 363: {
 364:     fprintf(stderr, "Usage:\n");
 365:     fprintf(stderr,
 366: "   nslookup [-opt ...]             # interactive mode using default server\n");
 367:     fprintf(stderr,
 368: "   nslookup [-opt ...] - server    # interactive mode using 'server'\n");
 369:     fprintf(stderr,
 370: "   nslookup [-opt ...] host        # just look up 'host' using default server\n");
 371:     fprintf(stderr,
 372: "   nslookup [-opt ...] host server # just look up 'host' using 'server'\n");
 373:     exit(1);
 374: }
 375: 
 376: /*
 377:  *******************************************************************************
 378:  *
 379:  * IsAddr --
 380:  *
 381:  *	Returns TRUE if the string looks like an Internet address.
 382:  *	A string with a trailing dot is not an address, even if it looks
 383:  *	like one.
 384:  *
 385:  *	XXX doesn't treat 255.255.255.255 as an address.
 386:  *
 387:  *******************************************************************************
 388:  */
 389: 
 390: Boolean
 391: IsAddr(host, addrPtr)
 392:     char *host;
 393:     u_long *addrPtr;    /* If return TRUE, contains IP address */
 394: {
 395:     register char *cp;
 396:     u_long addr;
 397: 
 398:     if (isdigit(host[0])) {
 399:         /* Make sure it has only digits and dots. */
 400:         for (cp = host; *cp; ++cp) {
 401:         if (!isdigit(*cp) && *cp != '.')
 402:             return FALSE;
 403:         }
 404:         /* If it has a trailing dot, don't treat it as an address. */
 405:         if (*--cp != '.') {
 406:         if ((addr = inet_addr(host)) != (u_long) -1) {
 407:             *addrPtr = addr;
 408:             return TRUE;
 409: #if 0
 410:         } else {
 411:             /* XXX Check for 255.255.255.255 case */
 412: #endif
 413:         }
 414:         }
 415:     }
 416:     return FALSE;
 417: }
 418: 
 419: 
 420: /*
 421:  *******************************************************************************
 422:  *
 423:  *  SetDefaultServer --
 424:  *
 425:  *	Changes the default name server to the one specified by
 426:  *	the first argument. The command "server name" uses the current
 427:  *	default server to lookup the info for "name". The command
 428:  *	"lserver name" uses the original server to lookup "name".
 429:  *
 430:  *  Side effects:
 431:  *	This routine will cause a core dump if the allocation requests fail.
 432:  *
 433:  *  Results:
 434:  *	SUCCESS		The default server was changed successfully.
 435:  *	NONAUTH		The server was changed but addresses of
 436:  *			other servers who know about the requested server
 437:  *			were returned.
 438:  *	Errors		No info about the new server was found or
 439:  *			requests to the current server timed-out.
 440:  *
 441:  *******************************************************************************
 442:  */
 443: 
 444: int
 445: SetDefaultServer(string, local)
 446:     char    *string;
 447:     Boolean local;
 448: {
 449:     register HostInfo   *newDefPtr;
 450:     struct in_addr  *servAddrPtr;
 451:     struct in_addr  addr;
 452:     char        newServer[NAME_LEN];
 453:     int         result;
 454:     int         i;
 455: 
 456:     /*
 457:      *  Parse the command line. It maybe of the form "server name",
 458:      *  "lserver name" or just "name".
 459:      */
 460: 
 461:     if (local) {
 462:     i = sscanf(string, " lserver %s", newServer);
 463:     } else {
 464:     i = sscanf(string, " server %s", newServer);
 465:     }
 466:     if (i != 1) {
 467:     i = sscanf(string, " %s", newServer);
 468:     if (i != 1) {
 469:         fprintf(stderr,"SetDefaultServer: invalid name: %s\n",  string);
 470:         return(ERROR);
 471:     }
 472:     }
 473: 
 474:     /*
 475:      * Allocate space for a HostInfo variable for the new server. Don't
 476:      * overwrite the old HostInfo struct because info about the new server
 477:      * might not be found and we need to have valid default server info.
 478:      */
 479: 
 480:     newDefPtr = (HostInfo *) Calloc(1, sizeof(HostInfo));
 481: 
 482: 
 483:     /*
 484:      *	A 'local' lookup uses the original server that the program was
 485:      *  initialized with.
 486:      *
 487:      *  Check to see if we have the address of the server or the
 488:      *  address of a server who knows about this domain.
 489:      *  XXX For now, just use the first address in the list.
 490:      */
 491: 
 492:     if (local) {
 493:     servAddrPtr = &defaultAddr;
 494:     } else if (defaultPtr->addrList != NULL) {
 495:     servAddrPtr = (struct in_addr *) defaultPtr->addrList[0];
 496:     } else {
 497:     servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0];
 498:     }
 499: 
 500:     result = ERROR;
 501:     if (IsAddr(newServer, &addr.s_addr)) {
 502:     result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr);
 503:     /* If we can't get the name, fall through... */
 504:     }
 505:     if (result != SUCCESS && result != NONAUTH) {
 506:     result = GetHostInfoByName(servAddrPtr, C_IN, T_A,
 507:             newServer, newDefPtr, 1);
 508:     }
 509: 
 510:     if (result == SUCCESS || result == NONAUTH) {
 511:         /*
 512: 	     *  Found info about the new server. Free the resources for
 513: 	     *  the old server.
 514: 	     */
 515: 
 516:         FreeHostInfoPtr(defaultPtr);
 517:         free((char *)defaultPtr);
 518:         defaultPtr = newDefPtr;
 519:         strcpy(defaultServer, defaultPtr->name);
 520:         PrintHostInfo(stdout, "Default Server:", defaultPtr);
 521:         return(SUCCESS);
 522:     } else {
 523:         fprintf(stderr, "*** Can't find address for server %s: %s\n",
 524:             newServer, DecodeError(result));
 525:         free((char *)newDefPtr);
 526: 
 527:         return(result);
 528:     }
 529: }
 530: 
 531: /*
 532:  *******************************************************************************
 533:  *
 534:  * DoLoookup --
 535:  *
 536:  *	Common subroutine for LookupHost and LookupHostWithServer.
 537:  *
 538:  *  Results:
 539:  *	SUCCESS		- the lookup was successful.
 540:  *	Misc. Errors	- an error message is printed if the lookup failed.
 541:  *
 542:  *******************************************************************************
 543:  */
 544: 
 545: static int
 546: DoLookup(host, servPtr, serverName)
 547:     char    *host;
 548:     HostInfo    *servPtr;
 549:     char    *serverName;
 550: {
 551:     int result;
 552:     struct in_addr *servAddrPtr;
 553:     struct in_addr addr;
 554: 
 555:     /* Skip escape character */
 556:     if (host[0] == '\\')
 557:     host++;
 558: 
 559:     /*
 560:      *  If the user gives us an address for an address query,
 561:      *  silently treat it as a PTR query. If the query type is already
 562:      *  PTR, then convert the address into the in-addr.arpa format.
 563:      *
 564:      *  Use the address of the server if it exists, otherwise use the
 565:      *	address of a server who knows about this domain.
 566:      *  XXX For now, just use the first address in the list.
 567:      */
 568: 
 569:     if (servPtr->addrList != NULL) {
 570:     servAddrPtr = (struct in_addr *) servPtr->addrList[0];
 571:     } else {
 572:     servAddrPtr = (struct in_addr *) servPtr->servers[0]->addrList[0];
 573:     }
 574: 
 575:     /*
 576:      * RFC1123 says we "SHOULD check the string syntactically for a
 577:      * dotted-decimal number before looking it up [...]" (p. 13).
 578:      */
 579:     if (queryType == T_A && IsAddr(host, &addr.s_addr)) {
 580:     result = GetHostInfoByAddr(servAddrPtr, &addr, &curHostInfo);
 581:     } else {
 582:     if (queryType == T_PTR) {
 583:         CvtAddrToPtr(host);
 584:     }
 585:     result = GetHostInfoByName(servAddrPtr, queryClass, queryType, host,
 586:             &curHostInfo, 0);
 587:     }
 588: 
 589:     switch (result) {
 590:     case SUCCESS:
 591:         /*
 592: 	     *  If the query was for an address, then the &curHostInfo
 593: 	     *  variable can be used by Finger.
 594: 	     *  There's no need to print anything for other query types
 595: 	     *  because the info has already been printed.
 596: 	     */
 597:         if (queryType == T_A) {
 598:         curHostValid = TRUE;
 599:         PrintHostInfo(filePtr, "Name:", &curHostInfo);
 600:         }
 601:         break;
 602: 
 603:     /*
 604: 	 * No Authoritative answer was available but we got names
 605: 	 * of servers who know about the host.
 606: 	 */
 607:     case NONAUTH:
 608:         PrintHostInfo(filePtr, "Name:", &curHostInfo);
 609:         break;
 610: 
 611:     case NO_INFO:
 612:         fprintf(stderr, "*** No %s (%s) records available for %s\n",
 613:             DecodeType(queryType), p_type(queryType), host);
 614:         break;
 615: 
 616:     case TIME_OUT:
 617:         fprintf(stderr, "*** Request to %s timed-out\n", serverName);
 618:         break;
 619: 
 620:     default:
 621:         fprintf(stderr, "*** %s can't find %s: %s\n", serverName, host,
 622:             DecodeError(result));
 623:     }
 624:     return result;
 625: }
 626: 
 627: /*
 628:  *******************************************************************************
 629:  *
 630:  *  LookupHost --
 631:  *
 632:  *	Asks the default name server for information about the
 633:  *	specified host or domain. The information is printed
 634:  *	if the lookup was successful.
 635:  *
 636:  *  Results:
 637:  *	ERROR		- the output file could not be opened.
 638:  *	+ results of DoLookup
 639:  *
 640:  *******************************************************************************
 641:  */
 642: 
 643: int
 644: LookupHost(string, putToFile)
 645:     char    *string;
 646:     Boolean putToFile;
 647: {
 648:     char    host[NAME_LEN];
 649:     char    file[NAME_LEN];
 650:     int     result;
 651: 
 652:     /*
 653:      *  Invalidate the current host information to prevent Finger
 654:      *  from using bogus info.
 655:      */
 656: 
 657:     curHostValid = FALSE;
 658: 
 659:     /*
 660:      *	 Parse the command string into the host and
 661:      *	 optional output file name.
 662:      *
 663:      */
 664: 
 665:     sscanf(string, " %s", host);    /* removes white space */
 666:     if (!putToFile) {
 667:     filePtr = stdout;
 668:     } else {
 669:     filePtr = OpenFile(string, file);
 670:     if (filePtr == NULL) {
 671:         fprintf(stderr, "*** Can't open %s for writing\n", file);
 672:         return(ERROR);
 673:     }
 674:     fprintf(filePtr,"> %s\n", string);
 675:     }
 676: 
 677:     PrintHostInfo(filePtr, "Server:", defaultPtr);
 678: 
 679:     result = DoLookup(host, defaultPtr, defaultServer);
 680: 
 681:     if (putToFile) {
 682:     fclose(filePtr);
 683:     filePtr = NULL;
 684:     }
 685:     return(result);
 686: }
 687: 
 688: /*
 689:  *******************************************************************************
 690:  *
 691:  *  LookupHostWithServer --
 692:  *
 693:  *	Asks the name server specified in the second argument for
 694:  *	information about the host or domain specified in the first
 695:  *	argument. The information is printed if the lookup was successful.
 696:  *
 697:  *	Address info about the requested name server is obtained
 698:  *	from the default name server. This routine will return an
 699:  *	error if the default server doesn't have info about the
 700:  *	requested server. Thus an error return status might not
 701:  *	mean the requested name server doesn't have info about the
 702:  *	requested host.
 703:  *
 704:  *	Comments from LookupHost apply here, too.
 705:  *
 706:  *  Results:
 707:  *	ERROR		- the output file could not be opened.
 708:  *	+ results of DoLookup
 709:  *
 710:  *******************************************************************************
 711:  */
 712: 
 713: int
 714: LookupHostWithServer(string, putToFile)
 715:     char    *string;
 716:     Boolean putToFile;
 717: {
 718:     char    file[NAME_LEN];
 719:     char    host[NAME_LEN];
 720:     char    server[NAME_LEN];
 721:     int     result;
 722:     static HostInfo serverInfo;
 723: 
 724:     curHostValid = FALSE;
 725: 
 726:     sscanf(string, " %s %s", host, server);
 727:     if (!putToFile) {
 728:     filePtr = stdout;
 729:     } else {
 730:     filePtr = OpenFile(string, file);
 731:     if (filePtr == NULL) {
 732:         fprintf(stderr, "*** Can't open %s for writing\n", file);
 733:         return(ERROR);
 734:     }
 735:     fprintf(filePtr,"> %s\n", string);
 736:     }
 737: 
 738:     result = GetHostInfoByName(
 739:         defaultPtr->addrList ?
 740:             (struct in_addr *) defaultPtr->addrList[0] :
 741:             (struct in_addr *) defaultPtr->servers[0]->addrList[0],
 742:         C_IN, T_A, server, &serverInfo, 1);
 743: 
 744:     if (result != SUCCESS) {
 745:     fprintf(stderr,"*** Can't find address for server %s: %s\n", server,
 746:          DecodeError(result));
 747:     } else {
 748:     PrintHostInfo(filePtr, "Server:", &serverInfo);
 749: 
 750:     result = DoLookup(host, &serverInfo, server);
 751:     }
 752:     if (putToFile) {
 753:     fclose(filePtr);
 754:     filePtr = NULL;
 755:     }
 756:     return(result);
 757: }
 758: 
 759: /*
 760:  *******************************************************************************
 761:  *
 762:  *  SetOption --
 763:  *
 764:  *	This routine is used to change the state information
 765:  *	that affect the lookups. The command format is
 766:  *	   set keyword[=value]
 767:  *	Most keywords can be abbreviated. Parsing is very simplistic--
 768:  *	A value must not be separated from its keyword by white space.
 769:  *
 770:  *	Valid keywords:		Meaning:
 771:  *	all			lists current values of options.
 772:  *	ALL			lists current values of options, including
 773:  *				  hidden options.
 774:  *	[no]d2			turn on/off extra debugging mode.
 775:  *	[no]debug		turn on/off debugging mode.
 776:  *	[no]defname		use/don't use default domain name.
 777:  *	[no]search		use/don't use domain search list.
 778:  *	domain=NAME		set default domain name to NAME.
 779:  *	[no]ignore		ignore/don't ignore trunc. errors.
 780:  *	query=value		set default query type to value,
 781:  *				value is one of the query types in RFC883
 782:  *				without the leading T_.	(e.g., A, HINFO)
 783:  *	[no]recurse		use/don't use recursive lookup.
 784:  *	retry=#			set number of retries to #.
 785:  *	root=NAME		change root server to NAME.
 786:  *	time=#			set timeout length to #.
 787:  *	[no]vc			use/don't use virtual circuit.
 788:  *	port			TCP/UDP port to server.
 789:  *
 790:  * 	Deprecated:
 791:  *	[no]primary		use/don't use primary server.
 792:  *
 793:  *  Results:
 794:  *	SUCCESS		the command was parsed correctly.
 795:  *	ERROR		the command was not parsed correctly.
 796:  *
 797:  *******************************************************************************
 798:  */
 799: 
 800: int
 801: SetOption(option)
 802:     register char *option;
 803: {
 804:     char    type[NAME_LEN];
 805:     char    *ptr;
 806:     int     tmp;
 807: 
 808:     while (isspace(*option))
 809:     ++option;
 810:     if (strncmp (option, "set ", 4) == 0)
 811:     option += 4;
 812:     while (isspace(*option))
 813:     ++option;
 814: 
 815:     if (*option == 0) {
 816:     fprintf(stderr, "*** Invalid set command\n");
 817:     return(ERROR);
 818:     } else {
 819:     if (strncmp(option, "all", 3) == 0) {
 820:         ShowOptions();
 821:     } else if (strncmp(option, "ALL", 3) == 0) {
 822:         ShowOptions();
 823:     } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */
 824:         _res.options |= (RES_DEBUG | RES_DEBUG2);
 825:     } else if (strncmp(option, "nod2", 4) == 0) {
 826:         _res.options &= ~RES_DEBUG2;
 827:         printf("d2 mode disabled; still in debug mode\n");
 828:     } else if (strncmp(option, "def", 3) == 0) {    /* defname */
 829:         _res.options |= RES_DEFNAMES;
 830:     } else if (strncmp(option, "nodef", 5) == 0) {
 831:         _res.options &= ~RES_DEFNAMES;
 832:     } else if (strncmp(option, "do", 2) == 0) { /* domain */
 833:         ptr = strchr(option, '=');
 834:         if (ptr != NULL) {
 835:         sscanf(++ptr, "%s", _res.defdname);
 836:         res_re_init();
 837:         }
 838:     } else if (strncmp(option, "deb", 1) == 0) {    /* debug */
 839:         _res.options |= RES_DEBUG;
 840:     } else if (strncmp(option, "nodeb", 5) == 0) {
 841:         _res.options &= ~(RES_DEBUG | RES_DEBUG2);
 842:     } else if (strncmp(option, "ig", 2) == 0) { /* ignore */
 843:         _res.options |= RES_IGNTC;
 844:     } else if (strncmp(option, "noig", 4) == 0) {
 845:         _res.options &= ~RES_IGNTC;
 846:     } else if (strncmp(option, "po", 2) == 0) { /* port */
 847:         ptr = strchr(option, '=');
 848:         if (ptr != NULL) {
 849:         sscanf(++ptr, "%hu", &nsport);
 850:         }
 851: #ifdef deprecated
 852:     } else if (strncmp(option, "pri", 3) == 0) {    /* primary */
 853:         _res.options |= RES_PRIMARY;
 854:     } else if (strncmp(option, "nopri", 5) == 0) {
 855:         _res.options &= ~RES_PRIMARY;
 856: #endif
 857:     } else if (strncmp(option, "q", 1) == 0 ||  /* querytype */
 858:       strncmp(option, "ty", 2) == 0) {      /* type */
 859:         ptr = strchr(option, '=');
 860:         if (ptr != NULL) {
 861:         sscanf(++ptr, "%s", type);
 862:         queryType = StringToType(type, queryType);
 863:         }
 864:     } else if (strncmp(option, "cl", 2) == 0) { /* query class */
 865:         ptr = strchr(option, '=');
 866:         if (ptr != NULL) {
 867:         sscanf(++ptr, "%s", type);
 868:         queryClass = StringToClass(type, queryClass);
 869:         }
 870:     } else if (strncmp(option, "rec", 3) == 0) {    /* recurse */
 871:         _res.options |= RES_RECURSE;
 872:     } else if (strncmp(option, "norec", 5) == 0) {
 873:         _res.options &= ~RES_RECURSE;
 874:     } else if (strncmp(option, "ret", 3) == 0) {    /* retry */
 875:         ptr = strchr(option, '=');
 876:         if (ptr != NULL) {
 877:         sscanf(++ptr, "%d", &tmp);
 878:         if (tmp >= 0) {
 879:             _res.retry = tmp;
 880:         }
 881:         }
 882:     } else if (strncmp(option, "ro", 2) == 0) { /* root */
 883:         ptr = strchr(option, '=');
 884:         if (ptr != NULL) {
 885:         sscanf(++ptr, "%s", rootServerName);
 886:         }
 887:     } else if (strncmp(option, "sea", 3) == 0) {    /* search list */
 888:         _res.options |= RES_DNSRCH;
 889:     } else if (strncmp(option, "nosea", 5) == 0) {
 890:         _res.options &= ~RES_DNSRCH;
 891:     } else if (strncmp(option, "srchl", 5) == 0) {  /* domain search list */
 892:         ptr = strchr(option, '=');
 893:         if (ptr != NULL) {
 894:         res_dnsrch(++ptr);
 895:         }
 896:     } else if (strncmp(option, "ti", 2) == 0) { /* timeout */
 897:         ptr = strchr(option, '=');
 898:         if (ptr != NULL) {
 899:         sscanf(++ptr, "%d", &tmp);
 900:         if (tmp >= 0) {
 901:             _res.retrans = tmp;
 902:         }
 903:         }
 904:     } else if (strncmp(option, "v", 1) == 0) {  /* vc */
 905:         _res.options |= RES_USEVC;
 906:     } else if (strncmp(option, "nov", 3) == 0) {
 907:         _res.options &= ~RES_USEVC;
 908:     } else {
 909:         fprintf(stderr, "*** Invalid option: %s\n",  option);
 910:         return(ERROR);
 911:     }
 912:     }
 913:     return(SUCCESS);
 914: }
 915: 
 916: /*
 917:  * Fake a reinitialization when the domain is changed.
 918:  */
 919: res_re_init()
 920: {
 921:     register char *cp, **pp;
 922:     int n;
 923: 
 924:     /* find components of local domain that might be searched */
 925:     pp = _res.dnsrch;
 926:     *pp++ = _res.defdname;
 927:     for (cp = _res.defdname, n = 0; *cp; cp++)
 928:     if (*cp == '.')
 929:         n++;
 930:     cp = _res.defdname;
 931:     for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) {
 932:     cp = strchr(cp, '.');
 933:     *pp++ = ++cp;
 934:     }
 935:     *pp = 0;
 936:     _res.options |= RES_INIT;
 937: }
 938: 
 939: #define SRCHLIST_SEP '/'
 940: 
 941: res_dnsrch(cp)
 942:     register char *cp;
 943: {
 944:     register char **pp;
 945:     int n;
 946: 
 947:     (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
 948:     if ((cp = strchr(_res.defdname, '\n')) != NULL)
 949:         *cp = '\0';
 950:     /*
 951:      * Set search list to be blank-separated strings
 952:      * on rest of line.
 953:      */
 954:     cp = _res.defdname;
 955:     pp = _res.dnsrch;
 956:     *pp++ = cp;
 957:     for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
 958:         if (*cp == SRCHLIST_SEP) {
 959:             *cp = '\0';
 960:             n = 1;
 961:         } else if (n) {
 962:             *pp++ = cp;
 963:             n = 0;
 964:         }
 965:     }
 966:     if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) {
 967:     *cp = '\0';
 968:     }
 969:     *pp = NULL;
 970: }
 971: 
 972: 
 973: /*
 974:  *******************************************************************************
 975:  *
 976:  *  ShowOptions --
 977:  *
 978:  *	Prints out the state information used by the resolver
 979:  *	library and other options set by the user.
 980:  *
 981:  *******************************************************************************
 982:  */
 983: 
 984: void
 985: ShowOptions()
 986: {
 987:     register char **cp;
 988: 
 989:     PrintHostInfo(stdout, "Default Server:", defaultPtr);
 990:     if (curHostValid) {
 991:     PrintHostInfo(stdout, "Host:", &curHostInfo);
 992:     }
 993: 
 994:     printf("Set options:\n");
 995:     printf("  %sdebug  \t", (_res.options & RES_DEBUG) ? "" : "no");
 996:     printf("  %sdefname\t", (_res.options & RES_DEFNAMES) ? "" : "no");
 997:     printf("  %ssearch\t", (_res.options & RES_DNSRCH) ? "" : "no");
 998:     printf("  %srecurse\n", (_res.options & RES_RECURSE) ? "" : "no");
 999: 
1000:     printf("  %sd2\t\t", (_res.options & RES_DEBUG2) ? "" : "no");
1001:     printf("  %svc\t\t", (_res.options & RES_USEVC) ? "" : "no");
1002:     printf("  %signoretc\t", (_res.options & RES_IGNTC) ? "" : "no");
1003:     printf("  port=%u\n", nsport);
1004: 
1005:     printf("  querytype=%s\t", p_type(queryType));
1006:     printf("  class=%s\t", p_class(queryClass));
1007:     printf("  timeout=%d\t", _res.retrans);
1008:     printf("  retry=%d\n", _res.retry);
1009:     printf("  root=%s\n", rootServerName);
1010:     printf("  domain=%s\n", _res.defdname);
1011: 
1012:     if (cp = _res.dnsrch) {
1013:     printf("  srchlist=%s", *cp);
1014:     for (cp++; *cp; cp++) {
1015:         printf("%c%s", SRCHLIST_SEP, *cp);
1016:     }
1017:     putchar('\n');
1018:     }
1019:     putchar('\n');
1020: }
1021: #undef SRCHLIST_SEP
1022: 
1023: /*
1024:  *******************************************************************************
1025:  *
1026:  *  PrintHelp --
1027:  *
1028:  *	Prints out the help file.
1029:  *	(Code taken from Mail.)
1030:  *
1031:  *******************************************************************************
1032:  */
1033: 
1034: void
1035: PrintHelp()
1036: {
1037:     register int c;
1038:     register FILE *helpFilePtr;
1039: 
1040:     if ((helpFilePtr = fopen(_PATH_HELPFILE, "r")) == NULL) {
1041:         perror(_PATH_HELPFILE);
1042:         return;
1043:     }
1044:     while ((c = getc(helpFilePtr)) != EOF) {
1045:         putchar((char) c);
1046:     }
1047:     fclose(helpFilePtr);
1048: }
1049: 
1050: /*
1051:  *******************************************************************************
1052:  *
1053:  * CvtAddrToPtr --
1054:  *
1055:  *	Convert a dotted-decimal Internet address into the standard
1056:  *	PTR format (reversed address with .in-arpa. suffix).
1057:  *
1058:  *	Assumes the argument buffer is large enougth to hold the result.
1059:  *
1060:  *******************************************************************************
1061:  */
1062: 
1063: static void
1064: CvtAddrToPtr(name)
1065:     char *name;
1066: {
1067:     char *p;
1068:     int ip[4];
1069:     struct in_addr addr;
1070: 
1071:     if (IsAddr(name, &addr.s_addr)) {
1072:     p = inet_ntoa(addr);
1073:     if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
1074:         sprintf(name, "%d.%d.%d.%d.in-addr.arpa.",
1075:         ip[3], ip[2], ip[1], ip[0]);
1076:     }
1077:     }
1078: }
1079: 
1080: /*
1081:  *******************************************************************************
1082:  *
1083:  * ReadRC --
1084:  *
1085:  *	Use the contents of ~/.nslookuprc as options.
1086:  *
1087:  *******************************************************************************
1088:  */
1089: 
1090: static void
1091: ReadRC()
1092: {
1093:     register FILE *fp;
1094:     register char *cp;
1095:     char buf[NAME_LEN];
1096: 
1097:     if ((cp = getenv("HOME")) != NULL) {
1098:     (void) strcpy(buf, cp);
1099:     (void) strcat(buf, "/.nslookuprc");
1100: 
1101:     if ((fp = fopen(buf, "r")) != NULL) {
1102:         while (fgets(buf, sizeof(buf), fp) != NULL) {
1103:         if ((cp = strchr(buf, '\n')) != NULL) {
1104:             *cp = '\0';
1105:         }
1106:         (void) SetOption(buf);
1107:         }
1108:         (void) fclose(fp);
1109:     }
1110:     }
1111: }

Defined functions

CvtAddrToPtr defined in line 1063; used 2 times
DoLookup defined in line 545; used 2 times
LocalServer defined in line 322; used 2 times
LookupHost defined in line 643; used 1 times
LookupHostWithServer defined in line 713; never used
PrintHelp defined in line 1034; never used
ReadRC defined in line 1090; used 2 times
SetDefaultServer defined in line 444; never used
SetOption defined in line 800; used 2 times
ShowOptions defined in line 984; used 3 times
Usage defined in line 362; used 1 times
main defined in line 137; never used
res_dnsrch defined in line 941; used 1 times
res_re_init defined in line 919; used 1 times

Defined variables

copyright defined in line 21; never used
curHostValid defined in line 90; used 5 times
defaultAddr defined in line 99; used 6 times
defaultServer defined in line 98; used 4 times
env defined in line 119; used 1 times
queryClass defined in line 107; used 6 times
queryType defined in line 106; used 10 times
rootServerName defined in line 75; used 2 times
sccsid defined in line 25; never used

Defined macros

LOCALHOST defined in line 63; used 1 times
ROOT_SERVER defined in line 73; used 2 times
SRCHLIST_SEP defined in line 939; used 4 times
Last modified: 1993-04-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 6007
Valid CSS Valid XHTML 1.0 Strict