home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / bind / bind-4.001 / bind-4~ / bind-4.9.3-BETA9 / tools / dig.c next >
C/C++ Source or Header  |  1994-07-19  |  33KB  |  1,186 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: dig.c,v 4.9.1.17 1994/07/19 22:51:24 vixie Exp $";
  3. #endif
  4.  
  5. /*
  6.  * ++Copyright++ 1989
  7.  * -
  8.  * Copyright (c) 1989
  9.  *    The Regents of the University of California.  All rights reserved.
  10.  * 
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted provided that the following conditions
  13.  * are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  * 2. Redistributions in binary form must reproduce the above copyright
  17.  *    notice, this list of conditions and the following disclaimer in the
  18.  *    documentation and/or other materials provided with the distribution.
  19.  * 3. All advertising materials mentioning features or use of this software
  20.  *    must display the following acknowledgement:
  21.  *     This product includes software developed by the University of
  22.  *     California, Berkeley and its contributors.
  23.  * 4. Neither the name of the University nor the names of its contributors
  24.  *    may be used to endorse or promote products derived from this software
  25.  *    without specific prior written permission.
  26.  * 
  27.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  28.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  31.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  33.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  34.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  36.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  37.  * SUCH DAMAGE.
  38.  * -
  39.  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  40.  * 
  41.  * Permission to use, copy, modify, and distribute this software for any
  42.  * purpose with or without fee is hereby granted, provided that the above
  43.  * copyright notice and this permission notice appear in all copies, and that
  44.  * the name of Digital Equipment Corporation not be used in advertising or
  45.  * publicity pertaining to distribution of the document or software without
  46.  * specific, written prior permission.
  47.  * 
  48.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  49.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  50.  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  51.  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  52.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  53.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  54.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  55.  * SOFTWARE.
  56.  * -
  57.  * --Copyright--
  58.  */
  59.  
  60. /*********************** Notes for the BIND 4.9 release (Paul Vixie, DEC)
  61.  *    dig 2.0 was written by copying sections of libresolv.a and nslookup
  62.  *    and modifying them to be more useful for a general lookup utility.
  63.  *    as of BIND 4.9, the changes needed to support dig have mostly been
  64.  *    incorporated into libresolv.a and nslookup; dig now links against
  65.  *    some of nslookup's .o files rather than #including them or maintaining
  66.  *    local copies of them.  in some sense, dig belongs in the nslookup
  67.  *    subdirectory rather than up here in "tools", but that's for arc@sgi.com
  68.  *    (owner of nslookup) to decide.
  69.  *
  70.  *    while merging dig back into the BIND release, i made a number of
  71.  *    structural changes.  for one thing, i put all of dig's private
  72.  *    library routines into this file rather than maintaining them in
  73.  *    separate, #included, files.  i don't like to #include ".c" files.
  74.  *    i removed all calls to "bcopy", replacing them with structure
  75.  *    assignments.  i removed all "extern"'s of standard functions,
  76.  *    replacing them with #include's of standard header files.  this
  77.  *    version of dig is probably as portable as the rest of BIND.
  78.  *
  79.  *    i had to remove the query-time and packet-count statistics since
  80.  *    the current libresolv.a is a lot harder to modify to maintain these
  81.  *    than the 4.8 one (used in the original dig) was.  for consolation,
  82.  *    i added a "usage" message with extensive help text.
  83.  *
  84.  *    to save my (limited, albeit) sanity, i ran "indent" over the source.
  85.  *    i also added the standard berkeley/DEC copyrights, since this file now
  86.  *    contains a fair amount of non-USC code.  note that the berkeley and
  87.  *    DEC copyrights do not prohibit redistribution, with or without fee;
  88.  *    we add them only to protect ourselves (you have to claim copyright
  89.  *    in order to disclaim liability and warranty).
  90.  *
  91.  *    Paul Vixie, Palo Alto, CA, April 1993
  92.  ****************************************************************************
  93.  
  94.  /*******************************************************************
  95.  **      DiG -- Domain Information Groper                          **
  96.  **                                                                **
  97.  **        dig.c - Version 2.1 (7/12/94) ("BIND takeover")         **
  98.  **                                                                **
  99.  **        Developed by: Steve Hotz & Paul Mockapetris             **
  100.  **        USC Information Sciences Institute (USC-ISI)            **
  101.  **        Marina del Rey, California                              **
  102.  **        1989                                                    **
  103.  **                                                                **
  104.  **        dig.c -                                                 **
  105.  **           Version 2.0 (9/1/90)                                 **
  106.  **               o renamed difftime() difftv() to avoid           **
  107.  **                 clash with ANSI C                              **
  108.  **               o fixed incorrect # args to strcmp,gettimeofday  **
  109.  **               o incorrect length specified to strncmp          **
  110.  **               o fixed broken -sticky -envsa -envset functions  **
  111.  **               o print options/flags redefined & modified       **
  112.  **                                                                **
  113.  **           Version 2.0.beta (5/9/90)                            **
  114.  **               o output format - helpful to `doc`               **
  115.  **               o minor cleanup                                  **
  116.  **               o release to beta testers                        **
  117.  **                                                                **
  118.  **           Version 1.1.beta (10/26/89)                          **
  119.  **               o hanging zone transer (when REFUSED) fixed      **
  120.  **               o trailing dot added to domain names in RDATA    **
  121.  **               o ISI internal                                   **
  122.  **                                                                **
  123.  **           Version 1.0.tmp  (8/27/89)                           **
  124.  **               o Error in prnttime() fixed                      **
  125.  **               o no longer dumps core on large pkts             **
  126.  **               o zone transfer (axfr) added                     **
  127.  **               o -x added for inverse queries                   **
  128.  **                               (i.e. "dig -x 128.9.0.32")       **
  129.  **               o give address of default server                 **
  130.  **               o accept broadcast to server @255.255.255.255    **
  131.  **                                                                **
  132.  **           Version 1.0  (3/27/89)                               **
  133.  **               o original release                               **
  134.  **                                                                **
  135.  **     DiG is Public Domain, and may be used for any purpose as   **
  136.  **     long as this notice is not removed.                        **
  137.  ****                                                            ****
  138.  ****   NOTE: Version 2.0.beta is not for public distribution    ****
  139.  ****                                                            ****
  140.  *******************************************************************/
  141.  
  142.  
  143. #define VERSION 21
  144. #define VSTRING "2.1"
  145.  
  146. #include <sys/types.h>
  147. #include <sys/param.h>
  148. #include <sys/file.h>
  149. #include <sys/stat.h>
  150. #include <sys/socket.h>
  151. #include <sys/time.h>
  152.  
  153. #include <netinet/in.h>
  154. #include <arpa/inet.h>
  155. #include <arpa/nameser.h>
  156.  
  157. #include <netdb.h>
  158. #include <stdio.h>
  159. #include <resolv.h>
  160. #include <ctype.h> 
  161. #include <errno.h>
  162. #include <string.h>
  163. #include <setjmp.h>
  164. #include <fcntl.h>
  165.  
  166. #include "nslookup/res.h"
  167. #include "../conf/portability.h"
  168.  
  169. #define PRF_DEF        0x2ff9
  170. #define PRF_MIN        0xA930
  171. #define PRF_ZONE        0x24f9
  172.  
  173. #ifndef MAXHOSTNAMELEN
  174. #define MAXHOSTNAMELEN 256
  175. #endif
  176.  
  177. int eecode = 0;
  178.  
  179. FILE *qfp;
  180. int sockFD;
  181.  
  182. #define SAVEENV "DiG.env"
  183. #define DIG_MAXARGS 30
  184.  
  185. char *defsrv, *srvmsg;
  186. char defbuf[40] = "default -- ";
  187. char srvbuf[60];
  188.  
  189. static void Usage();
  190. static int SetOption(), printZone(), printRR();
  191. static struct timeval difftv();
  192. static void prnttime();
  193.  
  194. /* stuff for nslookup modules */
  195. FILE        *filePtr;
  196. jmp_buf        env;
  197. HostInfo    *defaultPtr = NULL;
  198. HostInfo    curHostInfo, defaultRec;
  199. int        curHostValid = FALSE;
  200. int        queryType = T_A;
  201. int        queryClass = C_IN;
  202. extern int    StringToClass(), StringToType();    /* subr.c */
  203. #if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD)
  204. FILE        *yyin = NULL;
  205. void        yyrestart(f) { }
  206. #endif
  207. char        *pager = NULL;
  208. /* end of nslookup stuff */
  209.  
  210.  /*
  211.  ** Take arguments appearing in simple string (from file or command line)
  212.  ** place in char**.
  213.  */
  214. stackarg(y, l)
  215.     char *l;
  216.     char **y;
  217. {
  218.     int done=0;
  219.     while (!done) {
  220.         switch (*l) {
  221.         case '\t':
  222.         case ' ':
  223.             l++;    break;
  224.         case NULL:
  225.         case '\n':
  226.             done++;
  227.             *y = NULL;
  228.             break;
  229.         default:
  230.             *y++=l;
  231.             while (!isspace(*l))
  232.                 l++;
  233.             if (*l == '\n')
  234.                 done++;
  235.             *l++ = '\0';
  236.             *y = NULL;
  237.         }
  238.     }
  239. }
  240.  
  241. char myhostname[MAXHOSTNAMELEN];
  242.  
  243. main(argc, argv)
  244.     int argc;
  245.     char **argv;
  246. {
  247.     struct hostent *hp;
  248.     short port = htons(NAMESERVER_PORT);
  249.     u_char packet[PACKETSZ];
  250.     u_char answer[8*1024];
  251.     int n;
  252.     char doping[90];
  253.     char pingstr[50];
  254.     char *afile;
  255.     char *addrc, *addrend, *addrbegin;
  256.  
  257.     struct timeval exectime, tv1, tv2, start_time, end_time, query_time;
  258.  
  259.     char *srv;
  260.     int anyflag = 0;
  261.     int sticky = 0;
  262.     int tmp; 
  263.     int qtype = 1, qclass = 1;
  264.     int addrflag = 0;
  265.     int zone = 0;
  266.         int bytes_out, bytes_in;
  267.  
  268.     char cmd[256];
  269.     char domain[MAXDNAME];
  270.         char msg[120], *msgptr;
  271.     char **vtmp;
  272.     char *args[DIG_MAXARGS];
  273.     char **ax;
  274.     char **ay;
  275.     int once = 1, dofile = 0; /* batch -vs- interactive control */
  276.     char fileq[100];
  277.     char *qptr;
  278.     int  fp;
  279.     int wait=0, delay;
  280.     int envset=0, envsave=0;
  281.     struct __res_state res_x, res_t;
  282.     char *pp;
  283.  
  284.     res_init();
  285.     _res.pfcode = PRF_DEF;
  286.     gethostname(myhostname, (sizeof myhostname));
  287.     defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr));
  288.     res_x = _res;
  289.  
  290.  /*
  291.  ** If LOCALDEF in environment, should point to file
  292.  ** containing local favourite defaults.  Also look for file
  293.  ** DiG.env (i.e. SAVEENV) in local directory.
  294.  */
  295.  
  296.     if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) &&
  297.          ((fp = open(afile, O_RDONLY)) > 0)) ||
  298.         ((fp = open(SAVEENV, O_RDONLY)) > 0)) {
  299.         read(fp, &res_x, (sizeof res_x));
  300.         close(fp);
  301.         _res = res_x;
  302.     }
  303.  /*
  304.  **   check for batch-mode DiG; also pre-scan for 'help'
  305.  */
  306.     vtmp = argv;
  307.     ax = args;
  308.     while (*vtmp != NULL) {
  309.         if (strcmp(*vtmp, "-h") == 0 ||
  310.             strcmp(*vtmp, "-help") == 0 ||
  311.             strcmp(*vtmp, "-usage") == 0 ||
  312.             strcmp(*vtmp, "help") == 0) {
  313.             Usage();
  314.             exit(0);
  315.         }
  316.  
  317.         if (strcmp(*vtmp, "-f") == 0) {
  318.             dofile++; once=0;
  319.             if ((qfp = fopen(*++vtmp, "r")) == NULL) {
  320.                 fflush(stdout);
  321.                 perror("file open");
  322.                 fflush(stderr);
  323.                 exit(10);
  324.             }
  325.         } else {
  326.             if (ax - args == DIG_MAXARGS) {
  327.                 fprintf(stderr, "dig: too many arguments\n");
  328.                 exit(10);
  329.             }
  330.             *ax++ = *vtmp;
  331.         }
  332.         vtmp++;
  333.     }
  334.  
  335.     _res.id = 1;
  336.     gettimeofday(&tv1, NULL);
  337.  
  338.  /*
  339.  **  Main section: once if cmd-line query
  340.  **                while !EOF if batch mode
  341.  */
  342.     *fileq = '\0';
  343.     while ((dofile && (fgets(fileq,100,qfp) != NULL)) || 
  344.            ((!dofile) && (once--))) 
  345.     {
  346.         if ((*fileq=='\n') || (*fileq=='#') || (*fileq==';')) {
  347.             continue; /* ignore blank lines & comments */
  348.         }
  349.  
  350. /*
  351.  * "sticky" requests that before current parsing args
  352.  * return to current "working" environment (X******)
  353.  */
  354.         if (sticky) {
  355.             printf(";; (using sticky settings)\n");
  356.             _res = res_x;
  357.         }
  358.  
  359. /* concat cmd-line and file args */
  360.         ay = ax;
  361.         qptr = fileq;
  362.         stackarg(ay, qptr);
  363.  
  364.         /* defaults */
  365.         qtype = qclass = 1;
  366.         zone = 0;
  367.         *pingstr = 0;
  368.         srv = NULL;
  369.  
  370.         sprintf(cmd,"\n; <<>> DiG %s <<>> ",VSTRING);
  371.         argv = args;
  372.         argc = ax - args;
  373. /*
  374.  * More cmd-line options than anyone should ever have to
  375.  * deal with ....
  376.  */
  377.         while (*(++argv) != NULL && **argv != '\0') { 
  378.             strcat(cmd,*argv); strcat(cmd," ");
  379.             if (**argv == '@') {
  380.                 srv = (*argv+1);
  381.                 continue;
  382.             }
  383.             if (**argv == '%')
  384.                 continue;
  385.             if (**argv == '+') {
  386.                 SetOption(*argv+1);
  387.                 continue;
  388.             }
  389.      
  390.             if (strncmp(*argv,"-nost",5) == 0) {
  391.                 sticky = 0;
  392.                 continue;
  393.             } else if (strncmp(*argv,"-st",3) == 0) {
  394.                 sticky++;
  395.                 continue;
  396.             } else if (strncmp(*argv,"-envsa",6) == 0) {
  397.                 envsave++;
  398.                 continue;
  399.             } else if (strncmp(*argv,"-envse",6) == 0) {
  400.                 envset++;
  401.                 continue;
  402.             }
  403.  
  404.             if (**argv == '-') {
  405.                 switch (argv[0][1]) { 
  406.                 case 'T': wait = atoi(*++argv);
  407.                     break;
  408.                 case 'c': 
  409.                     if ((tmp = atoi(*++argv))
  410.                         || *argv[0]=='0') {
  411.                         qclass = tmp;
  412.                     } else if (tmp = StringToClass(*argv,
  413.                                        0, NULL)
  414.                            ) {
  415.                         qclass = tmp;
  416.                     } else {
  417.                         printf(
  418.                           "; invalid class specified\n"
  419.                                );
  420.                     }
  421.                     break;
  422.                 case 't': 
  423.                     if ((tmp = atoi(*++argv))
  424.                         || *argv[0]=='0') {
  425.                         qtype = tmp;
  426.                     } else if (tmp = StringToType(*argv,
  427.                                       0, NULL)
  428.                            ) {
  429.                         qtype = tmp;
  430.                     } else {
  431.                         printf(
  432.                            "; invalid type specified\n"
  433.                                );
  434.                         }
  435.                     break;
  436.                 case 'x':
  437.                     if (qtype == T_A)
  438.                         qtype = T_ANY;
  439.                     if (!(addrc = *++argv)) {
  440.                         printf(
  441.                                "; no arg for -x?\n"
  442.                                );
  443.                         break;
  444.                     }
  445.                     addrend = addrc + strlen(addrc);
  446.                     if (*addrend == '.')
  447.                         *addrend = '\0';
  448.                     *domain = '\0';
  449.                     while (addrbegin = strrchr(addrc,'.')) {
  450.                         strcat(domain, addrbegin+1);
  451.                         strcat(domain, ".");
  452.                         *addrbegin = '\0';
  453.                     }
  454.                     strcat(domain, addrc);
  455.                     strcat(domain, ".in-addr.arpa.");
  456.                     break;
  457.                 case 'p': port = htons(atoi(*++argv)); break;
  458.                 case 'P':
  459.                     if (argv[0][2] != '\0')
  460.                         strcpy(pingstr,&argv[0][2]);
  461.                     else
  462.                         strcpy(pingstr,"ping -s");
  463.                     break;
  464. #if defined(__RES) && (__RES >= 19931104)
  465.                 case 'n':
  466.                     _res.ndots = atoi(&argv[0][2]);
  467.                     break;
  468. #endif /*__RES*/
  469.                 } /* switch - */
  470.                 continue;
  471.             } /* if '-'   */
  472.  
  473.             if ((tmp = StringToType(*argv, -1, NULL)) != -1) { 
  474.                 if ((T_ANY == tmp) && anyflag++) {  
  475.                     qclass = C_ANY;     
  476.                     continue; 
  477.                 }
  478.                 if (T_AXFR == tmp) {
  479.                     _res.pfcode = PRF_ZONE;
  480.                     zone++;
  481.                 } else {
  482.                     qtype = tmp; 
  483.                 }
  484.             } else if ((tmp = StringToClass(*argv, -1, NULL))
  485.                    != -1) { 
  486.                 qclass = tmp; 
  487.             } else {
  488.                 bzero(domain, (sizeof domain));
  489.                 sprintf(domain,"%s",*argv);
  490.             }
  491.         } /* while argv remains */
  492.  
  493.         if (_res.pfcode & 0x80000)
  494.             printf("; pfcode: %08x, options: %08x\n",
  495.                    _res.pfcode, _res.options);
  496.       
  497. /*
  498.  * Current env. (after this parse) is to become the
  499.  * new "working environmnet. Used in conj. with sticky.
  500.  */
  501.         if (envset) {
  502.             res_x = _res;
  503.             envset = 0;
  504.         }
  505.  
  506. /*
  507.  * Current env. (after this parse) is to become the
  508.  * new default saved environmnet. Save in user specified
  509.  * file if exists else is SAVEENV (== "DiG.env").
  510.  */
  511.         if (envsave) {
  512.             afile = (char *) getenv("LOCALDEF");
  513.             if ((afile &&
  514.                  ((fp = open(afile,
  515.                      O_WRONLY|O_CREAT|O_TRUNC,
  516.                      S_IREAD|S_IWRITE)) > 0))
  517.                 ||
  518.                 ((fp = open(SAVEENV,
  519.                     O_WRONLY|O_CREAT|O_TRUNC,
  520.                     S_IREAD|S_IWRITE)) > 0)) {
  521.                 write(fp, &_res, (sizeof _res));
  522.                 close(fp);
  523.             }
  524.             envsave = 0;
  525.         }
  526.  
  527.         if (_res.pfcode & RES_PRF_CMD)
  528.             printf("%s\n", cmd);
  529.  
  530.         addrflag = anyflag = 0;
  531.  
  532. /*
  533.  * Find address of server to query. If not dot-notation, then
  534.  * try to resolve domain-name (if so, save and turn off print 
  535.  * options, this domain-query is not the one we want. Restore
  536.  * user options when done.
  537.  * Things get a bit wierd since we need to use resolver to be
  538.  * able to "put the resolver to work".
  539.  */
  540.  
  541.         srvbuf[0] = 0;
  542.         srvmsg = defsrv;
  543.         if (srv != NULL) {
  544.             struct in_addr addr;
  545.  
  546.             if (inet_aton(srv, &addr)) {
  547.                 _res.nscount = 1;
  548.                 _res.nsaddr.sin_addr = addr;
  549.                 srvmsg = strcat(srvbuf, srv);
  550.             } else {
  551.                 res_t = _res;
  552.                 _res.pfcode = 0;
  553.                 _res.options = RES_DEFAULT;
  554.                 res_init();
  555.                 hp = gethostbyname(srv);
  556.                 _res = res_t;
  557.                 if (hp == NULL
  558.                     || hp->h_addr_list == NULL
  559.                     || *hp->h_addr_list == NULL) {
  560.                     fflush(stdout);
  561.                     fprintf(stderr,
  562.         "; Bad server: %s -- using default server and timer opts\n",
  563.                         srv);
  564.                     fflush(stderr);
  565.                     srvmsg = defsrv;
  566.                     srv = NULL;
  567.                 } else {
  568.                     u_int32_t **addr;
  569.  
  570.                     _res.nscount = 0;
  571.                     for (addr = (u_int32_t**)hp->h_addr_list;
  572.                          *addr && (_res.nscount < MAXNS);
  573.                          addr++) {
  574.                         _res.nsaddr_list[
  575.                             _res.nscount++
  576.                         ].sin_addr.s_addr = **addr;
  577.                     }
  578.  
  579.                     srvmsg = strcat(srvbuf,srv);
  580.                     strcat(srvbuf, "  ");
  581.                     strcat(srvmsg,
  582.                            inet_ntoa(_res.nsaddr.sin_addr)
  583.                            );
  584.                 }
  585.             }
  586.             printf("; (%d server%s found)\n",
  587.                    _res.nscount, (_res.nscount==1)?"":"s");
  588.             _res.id += _res.retry;
  589.         }
  590.  
  591.         {
  592.             int i;
  593.  
  594.             for (i = 0;  i < _res.nscount;  i++) {
  595.                 _res.nsaddr_list[i].sin_family = AF_INET;
  596.                 _res.nsaddr_list[i].sin_port = port;
  597.             }
  598.             _res.id += _res.retry;
  599.         }
  600.  
  601.         if (zone) {
  602.             int i;
  603.  
  604.             for (i = 0;  i < _res.nscount;  i++) {
  605.                 int x = printZone(domain,
  606.                           &_res.nsaddr_list[i]);
  607.                 if (_res.pfcode & RES_PRF_STATS) {
  608.                     struct timeval exectime;
  609.  
  610.                     gettimeofday(&exectime,NULL);
  611.                     printf(";; FROM: %s to SERVER: %s\n",
  612.                            myhostname,
  613.                            inet_ntoa(_res.nsaddr_list[i]
  614.                              .sin_addr));
  615.                     printf(";; WHEN: %s",
  616.                            ctime(&(exectime.tv_sec)));
  617.                 }
  618.                 if (!x)
  619.                     break;    /* success */
  620.             }
  621.             fflush(stdout);
  622.             continue;
  623.         }
  624.  
  625.         bytes_out = n = res_mkquery(QUERY, domain, qclass, qtype,
  626.                         NULL, 0, NULL,
  627.                         packet, sizeof(packet));
  628.         if (n < 0) {
  629.             fflush(stderr);
  630.             printf(";; res_mkquery: buffer too small\n\n");
  631.             continue;
  632.         }
  633.         eecode = 0;
  634.         __fp_resstat(NULL, stdout);
  635.         (void) gettimeofday(&start_time, NULL);
  636.         if ((bytes_in = n = res_send(packet, n,
  637.                          answer, sizeof(answer))) < 0) {
  638.             fflush(stdout);
  639.             n = 0 - n;
  640.             msg[0]=0;
  641.             strcat(msg,";; res_send to server ");
  642.             strcat(msg,srvmsg);
  643.             perror(msg);
  644.             fflush(stderr);
  645.  
  646.             if (!dofile) {
  647.                 if (eecode)
  648.                     exit(eecode);
  649.                 else
  650.                     exit(9);
  651.             }
  652.         }
  653.         (void) gettimeofday(&end_time, NULL);
  654.  
  655.         if (_res.pfcode & RES_PRF_STATS) {
  656.             query_time = difftv(start_time, end_time);
  657.             printf(";; Total query time: ");
  658.             prnttime(query_time);
  659.             putchar('\n');
  660.             gettimeofday(&exectime,NULL);
  661.             printf(";; FROM: %s to SERVER: %s\n",
  662.                    myhostname, srvmsg);
  663.             printf(";; WHEN: %s",
  664.                    ctime(&(exectime.tv_sec)));
  665.             printf(";; MSG SIZE  sent: %d  rcvd: %d\n",
  666.                    bytes_out, bytes_in);
  667.         }
  668.       
  669.         fflush(stdout);
  670. /*
  671.  *   Argh ... not particularly elegant. Should put in *real* ping code.
  672.  *   Would necessitate root priviledges for icmp port though!
  673.  */
  674.         if (*pingstr) {
  675.             sprintf(doping,"%s %s 56 3 | tail -3",pingstr,
  676.                 (srv==NULL)?(defsrv+10):srv);
  677.             system(doping);
  678.         }
  679.         putchar('\n');
  680.  
  681. /*
  682.  * Fairly crude method and low overhead method of keeping two
  683.  * batches started at different sites somewhat synchronized.
  684.  */
  685.         gettimeofday(&tv2, NULL);
  686.         delay = (int)(tv2.tv_sec - tv1.tv_sec);
  687.         if (delay < wait) {
  688.             sleep(wait - delay);
  689.         }
  690.     }
  691.     return(eecode);
  692. }
  693.  
  694.  
  695. static void
  696. Usage()
  697. {
  698.     fputs("\
  699. usage:  dig [@server] [domain] [q-type] [q-class] {q-opt} {d-opt} [%comment]\n\
  700. where:    server,\n\
  701.     domain    are names in the Domain Name System\n\
  702.     q-class    is one of (in,any,...) [default: in]\n\
  703.     q-type    is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default: a]\n\
  704. ", stderr);
  705.     fputs("\
  706.     q-opt    is one of:\n\
  707.         -x dot-notation-address    (shortcut to in-addr.arpa lookups)\n\
  708.         -f file            (batch mode input file name)\n\
  709.         -T time            (batch mode time delay, per query)\n\
  710.         -p port            (nameserver is on this port) [53]\n\
  711.         -Pping-string        (see man page)\n\
  712.         -t query-type        (synonym for q-type)\n\
  713.         -c query-class        (synonym for q-class)\n\
  714.         -envsav,-envset        (see man page)\n\
  715.         -[no]stick        (see man page)\n\
  716. ", stderr);
  717.     fputs("\
  718.     d-opt    is of the form ``+keyword=value'' where keyword is one of:\n\
  719.         [no]debug [no]d2 [no]recurse retry=# time=# [no]ko [no]vc\n\
  720.         [no]defname [no]search domain=NAME [no]ignore [no]primary\n\
  721.         [no]aaonly [no]sort [no]cmd [no]stats [no]Header [no]header\n\
  722.         [no]ttlid [no]cl [no]qr [no]reply [no]ques [no]answer\n\
  723.         [no]author [no]addit pfdef pfmin pfset=# pfand=# pfor=#\n\
  724. ", stderr);
  725.     fputs("\
  726. notes:    defname and search don't work; use fully-qualified names.\n\
  727. ", stderr);
  728. }
  729.  
  730.  
  731. static int
  732. SetOption(string)
  733.     char *string;
  734. {
  735.     char     option[NAME_LEN];
  736.     char     type[NAME_LEN];
  737.     char     *ptr;
  738.     int     i;
  739.  
  740.     i = sscanf(string, " %s", option);
  741.     if (i != 1) {
  742.     fprintf(stderr, ";*** Invalid option: %s\n",  option);
  743.     return(ERROR);
  744.     } 
  745.    
  746.     if (strncmp(option, "aa", 2) == 0) {    /* aaonly */
  747.         _res.options |= RES_AAONLY;
  748.     } else if (strncmp(option, "noaa", 4) == 0) {
  749.         _res.options &= ~RES_AAONLY;
  750.     } else if (strncmp(option, "deb", 3) == 0) {    /* debug */
  751.         _res.options |= RES_DEBUG;
  752.     } else if (strncmp(option, "nodeb", 5) == 0) {
  753.         _res.options &= ~(RES_DEBUG | RES_DEBUG2);
  754.     } else if (strncmp(option, "ko", 2) == 0) {    /* keepopen */
  755.         _res.options |= (RES_STAYOPEN | RES_USEVC);
  756.     } else if (strncmp(option, "noko", 4) == 0) {
  757.         _res.options &= ~RES_STAYOPEN;
  758.     } else if (strncmp(option, "d2", 2) == 0) {    /* d2 (more debug) */
  759.         _res.options |= (RES_DEBUG | RES_DEBUG2);
  760.     } else if (strncmp(option, "nod2", 4) == 0) {
  761.         _res.options &= ~RES_DEBUG2;
  762.     } else if (strncmp(option, "def", 3) == 0) {    /* defname */
  763.         _res.options |= RES_DEFNAMES;
  764.     } else if (strncmp(option, "nodef", 5) == 0) {
  765.         _res.options &= ~RES_DEFNAMES;
  766.     } else if (strncmp(option, "sea", 3) == 0) {    /* search list */
  767.         _res.options |= RES_DNSRCH;
  768.     } else if (strncmp(option, "nosea", 5) == 0) {
  769.         _res.options &= ~RES_DNSRCH;
  770.     } else if (strncmp(option, "do", 2) == 0) {    /* domain */
  771.         ptr = strchr(option, '=');
  772.         if (ptr != NULL) {
  773.         sscanf(++ptr, "%s", _res.defdname);
  774.         }
  775.       } else if (strncmp(option, "ti", 2) == 0) {      /* timeout */
  776.         ptr = strchr(option, '=');
  777.         if (ptr != NULL) {
  778.           sscanf(++ptr, "%d", &_res.retrans);
  779.         }
  780.  
  781.       } else if (strncmp(option, "ret", 3) == 0) {    /* retry */
  782.         ptr = strchr(option, '=');
  783.         if (ptr != NULL) {
  784.           sscanf(++ptr, "%d", &_res.retry);
  785.         }
  786.  
  787.     } else if (strncmp(option, "i", 1) == 0) {    /* ignore */
  788.         _res.options |= RES_IGNTC;
  789.     } else if (strncmp(option, "noi", 3) == 0) {
  790.         _res.options &= ~RES_IGNTC;
  791.     } else if (strncmp(option, "pr", 2) == 0) {    /* primary */
  792.         _res.options |= RES_PRIMARY;
  793.     } else if (strncmp(option, "nop", 3) == 0) {
  794.         _res.options &= ~RES_PRIMARY;
  795.     } else if (strncmp(option, "rec", 3) == 0) {    /* recurse */
  796.         _res.options |= RES_RECURSE;
  797.     } else if (strncmp(option, "norec", 5) == 0) {
  798.         _res.options &= ~RES_RECURSE;
  799.     } else if (strncmp(option, "v", 1) == 0) {    /* vc */
  800.         _res.options |= RES_USEVC;
  801.     } else if (strncmp(option, "nov", 3) == 0) {
  802.         _res.options &= ~RES_USEVC;
  803.     } else if (strncmp(option, "pfset", 5) == 0) {
  804.         ptr = strchr(option, '=');
  805.         if (ptr != NULL) {
  806.           _res.pfcode = xstrtonum(++ptr);
  807.         }
  808.     } else if (strncmp(option, "pfand", 5) == 0) {
  809.         ptr = strchr(option, '=');
  810.         if (ptr != NULL) {
  811.           _res.pfcode = _res.pfcode & xstrtonum(++ptr);
  812.         }
  813.     } else if (strncmp(option, "pfor", 4) == 0) {
  814.         ptr = strchr(option, '=');
  815.         if (ptr != NULL) {
  816.           _res.pfcode |= xstrtonum(++ptr);
  817.         }
  818.     } else if (strncmp(option, "pfmin", 5) == 0) {
  819.           _res.pfcode = PRF_MIN;
  820.     } else if (strncmp(option, "pfdef", 5) == 0) {
  821.           _res.pfcode = PRF_DEF;
  822.     } else if (strncmp(option, "an", 2) == 0) {  /* answer section */
  823.           _res.pfcode |= RES_PRF_ANS;
  824.     } else if (strncmp(option, "noan", 4) == 0) {
  825.           _res.pfcode &= ~RES_PRF_ANS;
  826.     } else if (strncmp(option, "qu", 2) == 0) {  /* question section */
  827.           _res.pfcode |= RES_PRF_QUES;
  828.     } else if (strncmp(option, "noqu", 4) == 0) {  
  829.           _res.pfcode &= ~RES_PRF_QUES;
  830.     } else if (strncmp(option, "au", 2) == 0) {  /* authority section */
  831.           _res.pfcode |= RES_PRF_AUTH;
  832.     } else if (strncmp(option, "noau", 4) == 0) {  
  833.           _res.pfcode &= ~RES_PRF_AUTH;
  834.     } else if (strncmp(option, "ad", 2) == 0) {  /* addition section */
  835.           _res.pfcode |= RES_PRF_ADD;
  836.     } else if (strncmp(option, "noad", 4) == 0) {  
  837.           _res.pfcode &= ~RES_PRF_ADD;
  838.     } else if (strncmp(option, "tt", 2) == 0) {  /* TTL & ID */
  839.           _res.pfcode |= RES_PRF_TTLID;
  840.     } else if (strncmp(option, "nott", 4) == 0) {  
  841.           _res.pfcode &= ~RES_PRF_TTLID;
  842.     } else if (strncmp(option, "he", 2) == 0) {  /* head flags stats */
  843.           _res.pfcode |= RES_PRF_HEAD2;
  844.     } else if (strncmp(option, "nohe", 4) == 0) {  
  845.           _res.pfcode &= ~RES_PRF_HEAD2;
  846.     } else if (strncmp(option, "H", 1) == 0) {  /* header all */
  847.           _res.pfcode |= RES_PRF_HEADX;
  848.     } else if (strncmp(option, "noH", 3) == 0) {  
  849.           _res.pfcode &= ~(RES_PRF_HEADX);
  850.     } else if (strncmp(option, "qr", 2) == 0) {  /* query */
  851.           _res.pfcode |= RES_PRF_QUERY;
  852.     } else if (strncmp(option, "noqr", 4) == 0) {  
  853.           _res.pfcode &= ~RES_PRF_QUERY;
  854.     } else if (strncmp(option, "rep", 3) == 0) {  /* reply */
  855.           _res.pfcode |= RES_PRF_REPLY;
  856.     } else if (strncmp(option, "norep", 5) == 0) {  
  857.           _res.pfcode &= ~RES_PRF_REPLY;
  858.     } else if (strncmp(option, "cm", 2) == 0) {  /* command line */
  859.           _res.pfcode |= RES_PRF_CMD;
  860.     } else if (strncmp(option, "nocm", 4) == 0) {  
  861.           _res.pfcode &= ~RES_PRF_CMD;
  862.     } else if (strncmp(option, "cl", 2) == 0) {  /* class mnemonic */
  863.           _res.pfcode |= RES_PRF_CLASS;
  864.     } else if (strncmp(option, "nocl", 4) == 0) {  
  865.           _res.pfcode &= ~RES_PRF_CLASS;
  866.     } else if (strncmp(option, "st", 2) == 0) {  /* stats*/
  867.           _res.pfcode |= RES_PRF_STATS;
  868.     } else if (strncmp(option, "nost", 4) == 0) {  
  869.           _res.pfcode &= ~RES_PRF_STATS;
  870.     } else {
  871.         fprintf(stderr, "; *** Invalid option: %s\n",  option);
  872.         return(ERROR);
  873.     }
  874.     res_re_init();
  875.     return(SUCCESS);
  876. }
  877.  
  878.  
  879.  
  880. /*
  881.  * Force a reinitialization when the domain is changed.
  882.  */
  883. res_re_init()
  884. {
  885.     static char localdomain[] = "LOCALDOMAIN";
  886.     char *buf;
  887.     long pfcode = _res.pfcode;
  888.  
  889.     /* this is ugly but putenv() is more portable than setenv() */
  890.     buf = malloc((sizeof localdomain) +strlen(_res.defdname) +10/*fuzz*/);
  891.     sprintf(buf, "%s=%s", localdomain, _res.defdname);
  892.     putenv(buf);    /* keeps the argument, so we won't free it */
  893.     _res.options &= ~RES_INIT;
  894.     res_init();
  895.     _res.pfcode = pfcode;
  896. }
  897.  
  898.  
  899. /*
  900.  * convert char string (decimal, octal, or hex) to integer
  901.  */
  902. int
  903. xstrtonum(p)
  904.     char *p;
  905. {
  906.     int v = 0;
  907.     int i;
  908.     int b = 10;
  909.     int flag = 0;
  910.     while (*p != 0) {
  911.         if (!flag++)
  912.             if (*p == '0') {
  913.                 b = 8; p++;
  914.                 continue;
  915.             }
  916.         if (isupper(*p))
  917.             *p=tolower(*p);
  918.         if (*p == 'x') {
  919.             b = 16; p++;
  920.             continue;
  921.         }
  922.         if (isdigit(*p)) {
  923.             i = *p - '0';
  924.         } else if (isxdigit(*p)) {
  925.             i = *p - 'a' + 10;
  926.         } else {
  927.             fprintf(stderr,
  928.                 "; *** Bad char in numeric string..ignored\n");
  929.             i = -1;
  930.         }
  931.         if (i >= b) {
  932.             fprintf(stderr,
  933.                 "; *** Bad char in numeric string..ignored\n");
  934.             i = -1;
  935.         }
  936.         if (i >= 0)
  937.             v = v * b + i;
  938.         p++;
  939.     }
  940.     return(v);
  941. }
  942.  
  943. /* this code was cloned from nslookup/list.c */
  944.  
  945. extern char *_res_resultcodes[];    /* res_debug.c */
  946.  
  947. typedef union {
  948.     HEADER qb1;
  949.     u_char qb2[PACKETSZ];
  950. } querybuf;
  951.  
  952. static int
  953. printZone(zone, sin)
  954.     char *zone;
  955.     struct sockaddr_in *sin;
  956. {
  957.     querybuf        buf;
  958.     HEADER            *headerPtr;
  959.     int            msglen;
  960.     int            amtToRead;
  961.     int            numRead;
  962.     int            numAnswers = 0;
  963.     int            result;
  964.     int            soacnt = 0;
  965.     int            sockFD;
  966.     u_short            len;
  967.     u_char            *cp, *nmp;
  968.     char            dname[2][NAME_LEN];
  969.     char            file[NAME_LEN];
  970.     static u_char        *answer = NULL;
  971.     static int        answerLen = 0;
  972.     enum {
  973.         NO_ERRORS,
  974.         ERR_READING_LEN,
  975.         ERR_READING_MSG,
  976.         ERR_PRINTING
  977.     } error = NO_ERRORS;
  978.  
  979.     /*
  980.      *  Create a query packet for the requested zone name.
  981.      */
  982.     msglen = res_mkquery(QUERY, zone, queryClass, T_AXFR, NULL,
  983.                  0, 0, buf.qb2, sizeof(buf));
  984.     if (msglen < 0) {
  985.         if (_res.options & RES_DEBUG) {
  986.         fprintf(stderr, ";; res_mkquery failed\n");
  987.         }
  988.         return (ERROR);
  989.     }
  990.  
  991.     /*
  992.      *  Set up a virtual circuit to the server.
  993.      */
  994.     if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
  995.         int e = errno;
  996.         perror(";; socket");
  997.         return(e);
  998.     }
  999.     if (connect(sockFD, (struct sockaddr *)sin, sizeof(*sin)) < 0) {
  1000.         int e = errno;
  1001.         perror(";; connect");
  1002.         (void) close(sockFD);
  1003.         sockFD = -1;
  1004.         return e;
  1005.     }
  1006.  
  1007.     /*
  1008.      * Send length & message for zone transfer
  1009.      */
  1010.  
  1011.     __putshort(msglen, (u_char *)&len);
  1012.  
  1013.         if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ ||
  1014.             write(sockFD, (char *) &buf, msglen) != msglen) {
  1015.         int e = errno;
  1016.         perror(";; write");
  1017.         (void) close(sockFD);
  1018.         sockFD = -1;
  1019.         return(e);
  1020.     }
  1021.  
  1022.     dname[0][0] = '\0';
  1023.     while (1) {
  1024.         u_int16_t tmp;
  1025.  
  1026.         /*
  1027.          * Read the length of the response.
  1028.          */
  1029.  
  1030.         cp = (u_char *) &tmp;
  1031.         amtToRead = INT16SZ;
  1032.         while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0){
  1033.         cp      += numRead;
  1034.         amtToRead -= numRead;
  1035.         }
  1036.         if (numRead <= 0) {
  1037.         error = ERR_READING_LEN;
  1038.         break;
  1039.         }
  1040.  
  1041.         if ((len = _getshort((u_char*)&tmp)) == 0) {
  1042.         break;    /* nothing left to read */
  1043.         }
  1044.  
  1045.         /*
  1046.          * The server sent too much data to fit the existing buffer --
  1047.          * allocate a new one.
  1048.          */
  1049.         if (len > answerLen) {
  1050.         if (answerLen != 0) {
  1051.             free(answer);
  1052.         }
  1053.         answerLen = len;
  1054.         answer = (u_char *)Malloc(answerLen);
  1055.         }
  1056.  
  1057.         /*
  1058.          * Read the response.
  1059.          */
  1060.  
  1061.         amtToRead = len;
  1062.         cp = answer;
  1063.         while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) {
  1064.         cp += numRead;
  1065.         amtToRead -= numRead;
  1066.         }
  1067.         if (numRead <= 0) {
  1068.         error = ERR_READING_MSG;
  1069.         break;
  1070.         }
  1071.  
  1072.         result = printRR(stdout, answer, cp);
  1073.         if (result != 0) {
  1074.         error = ERR_PRINTING;
  1075.         break;
  1076.         }
  1077.  
  1078.         numAnswers++;
  1079.         cp = answer + HFIXEDSZ;
  1080.         if (ntohs(((HEADER *)answer)->qdcount) > 0)
  1081.         cp += dn_skipname((u_char *)cp,
  1082.             (u_char *)answer + len) + QFIXEDSZ;
  1083.         nmp = cp;
  1084.         cp += dn_skipname((u_char *)cp, (u_char *)answer + len);
  1085.         if ((_getshort((u_char*)cp) == T_SOA)) {
  1086.         (void) dn_expand(answer, answer + len, nmp,
  1087.                  dname[soacnt], sizeof dname[0]);
  1088.             if (soacnt) {
  1089.             if (strcmp(dname[0], dname[1]) == 0)
  1090.             break;
  1091.         } else
  1092.             soacnt++;
  1093.         }
  1094.     }
  1095.  
  1096.     fprintf(stdout, ";; Received %d record%s.\n",
  1097.         numAnswers, (numAnswers != 1) ? "s" : "");
  1098.  
  1099.     (void) close(sockFD);
  1100.     sockFD = -1;
  1101.  
  1102.     switch (error) {
  1103.         case NO_ERRORS:
  1104.         return (0);
  1105.  
  1106.         case ERR_READING_LEN:
  1107.         return(EMSGSIZE);
  1108.  
  1109.         case ERR_PRINTING:
  1110.         return(result);
  1111.  
  1112.         case ERR_READING_MSG:
  1113.         return(EMSGSIZE);
  1114.  
  1115.         default:
  1116.         return(EFAULT);
  1117.     }
  1118. }
  1119.  
  1120. static int
  1121. printRR(file, msg, eom)
  1122.     FILE    *file;
  1123.     u_char    *msg, *eom;
  1124. {
  1125.     register u_char    *cp;
  1126.     HEADER        *headerPtr;
  1127.     int            type, class, dlen, nameLen;
  1128.     u_int32_t        ttl;
  1129.     int            n, pref;
  1130.     struct in_addr    inaddr;
  1131.     char        name[NAME_LEN];
  1132.     char        name2[NAME_LEN];
  1133.     Boolean        stripped;
  1134.  
  1135.     /*
  1136.      * Read the header fields.
  1137.      */
  1138.     headerPtr = (HEADER *)msg;
  1139.     cp = msg + HFIXEDSZ;
  1140.     if (headerPtr->rcode != NOERROR) {
  1141.     return(headerPtr->rcode);
  1142.     }
  1143.  
  1144.     /*
  1145.      *  We are looking for info from answer resource records.
  1146.      *  If there aren't any, return with an error. We assume
  1147.      *  there aren't any question records.
  1148.      */
  1149.  
  1150.     if (ntohs(headerPtr->ancount) == 0) {
  1151.     return(NO_INFO);
  1152.     } else {
  1153.     if (ntohs(headerPtr->qdcount) > 0) {
  1154.         nameLen = dn_skipname(cp, eom);
  1155.         if (nameLen < 0)
  1156.         return (ERROR);
  1157.         cp += nameLen + QFIXEDSZ;
  1158.     }
  1159.     cp = (u_char*) p_rr(cp, msg, stdout);
  1160.     }
  1161.     return(SUCCESS);
  1162. }
  1163.  
  1164. static
  1165. struct timeval
  1166. difftv(a, b)
  1167.     struct timeval a, b;
  1168. {
  1169.     static struct timeval diff;
  1170.  
  1171.     diff.tv_sec = b.tv_sec - a.tv_sec;
  1172.     if ((diff.tv_usec = b.tv_usec - a.tv_usec) < 0) {
  1173.         diff.tv_sec--;
  1174.         diff.tv_usec += 1000000;
  1175.     }
  1176.     return(diff);
  1177. }
  1178.  
  1179. static
  1180. void
  1181. prnttime(t)
  1182.     struct timeval t;
  1183. {
  1184.     printf("%u msec", t.tv_sec * 1000 + (t.tv_usec / 1000));
  1185. }
  1186.