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