home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / named / tools / nslookup / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-24  |  29.0 KB  |  1,125 lines

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