diff options
author | pst <pst@FreeBSD.org> | 1994-09-22 21:33:31 +0000 |
---|---|---|
committer | pst <pst@FreeBSD.org> | 1994-09-22 21:33:31 +0000 |
commit | 3b7634fcc510de1e18498c5626f5b502b438c970 (patch) | |
tree | f2c68b1cfec09fff9ab9c7bfaf7b6cd13d76ff92 /usr.bin/dig | |
parent | 3866fef02d12ce18b3b81e010ac2af997ce350a8 (diff) | |
download | FreeBSD-src-3b7634fcc510de1e18498c5626f5b502b438c970.zip FreeBSD-src-3b7634fcc510de1e18498c5626f5b502b438c970.tar.gz |
dig(1) from BIND 4.9.3BETA9pl1
Diffstat (limited to 'usr.bin/dig')
-rw-r--r-- | usr.bin/dig/dig.1 | 364 | ||||
-rw-r--r-- | usr.bin/dig/dig.c | 1185 |
2 files changed, 1549 insertions, 0 deletions
diff --git a/usr.bin/dig/dig.1 b/usr.bin/dig/dig.1 new file mode 100644 index 0000000..3f97311 --- /dev/null +++ b/usr.bin/dig/dig.1 @@ -0,0 +1,364 @@ +.\" $Id: dig.1,v 4.9.1.2 1993/09/08 00:00:49 vixie Exp $ +.\" +.\" ++Copyright++ 1993 +.\" - +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" - +.\" Portions Copyright (c) 1993 by Digital Equipment Corporation. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies, and that +.\" the name of Digital Equipment Corporation not be used in advertising or +.\" publicity pertaining to distribution of the document or software without +.\" specific, written prior permission. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +.\" WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +.\" CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +.\" SOFTWARE. +.\" - +.\" --Copyright-- +.\" +.\" Distributed with 'dig' version 2.0 from University of Southern +.\" California Information Sciences Institute (USC-ISI). +.\" +.\" dig.1 2.0 (USC-ISI) 8/30/90 +.\" +.\" Man page reformatted for this release by Andrew Cherenson +.\" (arc@sgi.com) +.\" +.TH DIG @CMD_EXT_U@ "August 30, 1990" +.SH NAME +dig \- send domain name query packets to name servers +.SH SYNOPSIS +.B dig +.RI [ @\fIserver\fP ] +.I domain +.RI [ "<query-type>" ] +.RI [ "<query-class>" ] +.RI [ "+<query-option>" ] +.RI [ "\-<dig-option>" ] +.RI [ "%comment" ] +.SH DESCRIPTION +\fIDig\fP (domain information groper) is a flexible command line tool +which can be used to gather information from the Domain +Name System servers. \fIDig\fP has two modes: simple interactive mode +which makes a single query, and batch which executes a query for +each in a list of several query lines. All query options are +accessible from the command line. +.PP +The usual simple use of \fIdig\fP will take the form: +.sp 1 + dig @server domain query-type query-class +.sp 1 +where: +.IP \fIserver\fP +may be either a domain name or a dot-notation +Internet address. If this optional field is omitted, \fIdig\fP +will attempt to use the default name server for your machine. +.sp 1 +\fBNote:\fP If a domain name is specified, this will be resolved +using the domain name system resolver (i.e., BIND). If your +system does not support DNS, you may \fIhave\fP to specify a +dot-notation address. Alternatively, if there is a server +at your disposal somewhere, all that is required is that +/etc/resolv.conf be present and indicate where the default +name servers reside, so that \fIserver\fP itself can be +resolved. See +.IR resolver (@FORMAT_EXT@) +for information on /etc/resolv.conf. +(WARNING: Changing /etc/resolv.conf will affect +the standard resolver library and potentially several +programs which use it.) As an option, the user may set the +environment variable LOCALRES to name a file which is to +be used instead of /etc/resolv.conf (LOCALRES is specific +to the \fIdig\fP resolver and not referenced by the standard +resolver). If the LOCALRES variable is not set or the file +is not readable then /etc/resolv.conf will be used. +.IP \fIdomain\fP +is the domain name for which you are requesting information. +See OPTIONS [-x] for convenient way to specify inverse address +query. +.IP \fIquery-type\fP +is the type of information (DNS query type) that +you are requesting. If omitted, the default is "a" (T_A = address). +The following types are recognized: +.sp 1 +.ta \w'hinfoXX'u +\w'T_HINFOXX'u +.nf +a T_A network address +any T_ANY all/any information about specified domain +mx T_MX mail exchanger for the domain +ns T_NS name servers +soa T_SOA zone of authority record +hinfo T_HINFO host information +axfr T_AXFR zone transfer + (must ask an authoritative server) +txt T_TXT arbitrary number of strings +.fi +.sp 1 +(See RFC 1035 for the complete list.) +.IP \fIquery-class\fP +is the network class requested in the query. If +omitted, the default is "in" (C_IN = Internet). +The following classes are recognized: +.sp 1 +.ta \w'hinfoXX'u +\w'T_HINFOXX'u +.nf +in C_IN Internet class domain +any C_ANY all/any class information +.fi +.sp 1 +(See RFC 1035 for the complete list.) +.sp 1 +\fBNote:\fP +"Any" can be used to specify a class and/or a type of +query. \fIDig\fP will parse the first occurrence of "any" +to mean query-type = T_ANY. To specify query-class = +C_ANY you must either specify "any" twice, or set +query-class using "\-c" option (see below). +.SH OTHER OPTIONS +.IP "%ignored-comment" +"%" is used to included an argument that is simply not +parsed. This may be useful if running \fIdig\fP in batch +mode. Instead of resolving every @server-domain-name in +a list of queries, you can avoid the overhead of doing +so, and still have the domain name on the command line +as a reference. Example: +.sp 1 + dig @128.9.0.32 %venera.isi.edu mx isi.edu +.sp 1 +.IP "\-<dig option>" +"\-" is used to specify an option which effects the +operation of \fIdig\fP. The following options are currently +available (although not guaranteed to be useful): +.RS +.IP "\-x \fIdot-notation-address\fP" +Convenient form to specify inverse address mapping. +Instead of "dig 32.0.9.128.in-addr.arpa" one can +simply "dig -x 128.9.0.32". +.IP "\-f \fIfile\fP" +File for \fIdig\fP batch mode. The file contains a list +of query specifications (\fIdig\fP command lines) which +are to be executed successively. Lines beginning +with ';', '#', or '\\n' are ignored. Other options +may still appear on command line, and will be in +effect for each batch query. +.IP "\-T \fItime\fP" +Time in seconds between start of successive +queries when running in batch mode. Can be used +to keep two or more batch \fIdig\fP commands running +roughly in sync. Default is zero. +.IP "\-p \fIport\fP" +Port number. Query a name server listening to a +non-standard port number. Default is 53. +.IP "\-P[\fIping-string\fP]" +After query returns, execute a +.IR ping (@SYS_OPS_EXT@) +command +for response time comparison. This rather +unelegantly makes a call to the shell. The last +three lines of statistics is printed for the +command: +.sp 1 + ping \-s server_name 56 3 +.sp 1 +If the optional "ping string" is present, it +replaces "ping \-s" in the shell command. +.IP "\-t \fIquery-type\fP" +Specify type of query. May specify either an +integer value to be included in the type field +or use the abbreviated mnemonic as discussed +above (i.e., mx = T_MX). +.IP "\-c \fIquery-class\fP" +Specify class of query. May specify either an +integer value to be included in the class field +or use the abbreviated mnemonic as discussed +above (i.e., in = C_IN). +.IP "\-envsav" +This flag specifies that the \fIdig\fP environment +(defaults, print options, etc.), after +all of the arguments are parsed, should be saved +to a file to become the default environment. +Useful if you do not like the standard set of +defaults and do not desire to include a +large number of options each time \fIdig\fP is used. +The environment consists of resolver state +variable flags, timeout, and retries as well as +the flags detailing \fIdig\fP output (see below). +If the shell environment variable LOCALDEF is set +to the name of a file, this is where the default +\fIdig\fP environment is saved. If not, the file +"DiG.env" is created in the current working directory. +.sp 1 +\fBNote:\fP LOCALDEF is specific to the \fIdig\fP resolver, +and will not affect operation of the standard +resolver library. +.sp 1 +Each time \fIdig\fP is executed, it looks for "./DiG.env" +or the file specified by the shell environment variable +LOCALDEF. If such file exists and is readable, then the +environment is restored from this file +before any arguments are parsed. +.IP "\-envset" +This flag only affects +batch query runs. When "\-envset" is +specified on a line in a \fIdig\fP batch file, +the \fIdig\fP environment after the arguments are parsed, +becomes the default environment for the duration of +the batch file, or until the next line which specifies +"\-envset". +.IP "\-[no]stick" +This flag only affects batch query runs. +It specifies that the \fIdig\fP environment (as read initially +or set by "\-envset" switch) is to be restored before each query +(line) in a \fIdig\fP batch file. +The default "\-nostick" means that the \fIdig\fP environment +does not stick, hence options specified on a single line +in a \fIdig\fP batch file will remain in effect for +subsequent lines (i.e. they are not restored to the +"sticky" default). + +.RE +.IP "+<query option>" +"+" is used to specify an option to be changed in the +query packet or to change \fIdig\fP output specifics. Many +of these are the same parameters accepted by +.IR nslookup (@SYS_OPS_EXT@). +If an option requires a parameter, the form is as +follows: +.sp 1 + +keyword[=value] +.sp 1 +Most keywords can be abbreviated. Parsing of the "+" +options is very simplistic \(em a value must not be +separated from its keyword by white space. The following +keywords are currently available: +.sp 1 +.nf +.ta \w'domain=NAMEXX'u +\w'(deb)XXX'u +Keyword Abbrev. Meaning [default] + +[no]debug (deb) turn on/off debugging mode [deb] +[no]d2 turn on/off extra debugging mode [nod2] +[no]recurse (rec) use/don't use recursive lookup [rec] +retry=# (ret) set number of retries to # [4] +time=# (ti) set timeout length to # seconds [4] +[no]ko keep open option (implies vc) [noko] +[no]vc use/don't use virtual circuit [novc] +[no]defname (def) use/don't use default domain name [def] +[no]search (sea) use/don't use domain search list [sea] +domain=NAME (do) set default domain name to NAME +[no]ignore (i) ignore/don't ignore trunc. errors [noi] +[no]primary (pr) use/don't use primary server [nopr] +[no]aaonly (aa) authoritative query only flag [noaa] +[no]sort (sor) sort resource records [nosor] +[no]cmd echo parsed arguments [cmd] +[no]stats (st) print query statistics [st] +[no]Header (H) print basic header [H] +[no]header (he) print header flags [he] +[no]ttlid (tt) print TTLs [tt] +[no]cl print class info [nocl] +[no]qr print outgoing query [noqr] +[no]reply (rep) print reply [rep] +[no]ques (qu) print question section [qu] +[no]answer (an) print answer section [an] +[no]author (au) print authoritative section [au] +[no]addit (ad) print additional section [ad] +pfdef set to default print flags +pfmin set to minimal default print flags +pfset=# set print flags to # + (# can be hex/octal/decimal) +pfand=# bitwise and print flags with # +pfor=# bitwise or print flags with # +.fi +.sp 1 +The retry and time options affect the retransmission strategy used by resolver +library when sending datagram queries. The algorithm is as follows: +.sp 1 +.in +5n +.nf +for i = 0 to retry \- 1 + for j = 1 to num_servers + send_query + wait((time * (2**i)) / num_servers) + end +end +.fi +.in -5n +.sp 1 +(Note: \fIdig\fP always uses a value of 1 for num_servers.) +.SH DETAILS +\fIDig\fP once required a slightly modified version of the BIND +.IR resolver (@LIB_NETWORK_EXT@) +library. BIND's resolver has (as of BIND 4.9) been augmented to work +properly with \fIDig\fP. Essentially, \fIDig\fP is a straight-forward +(albeit not pretty) effort of parsing arguments and setting appropriate +parameters. \fIDig\fP uses resolver routines res_init(), res_mkquery(), +res_send() as well as accessing _res structure. +.SH FILES +.ta \w'/etc/resolv.confXX'u +/etc/resolv.conf initial domain name and name server +\./DiG.env default save file for default options +.br + addresses +.SH ENVIRONMENT +LOCALRES file to use in place of /etc/resolv.conf +.br +LOCALDEF default environment file +.SH AUTHOR +Steve Hotz +hotz@isi.edu +.SH ACKNOWLEDGMENTS +\fIDig\fP uses functions from +.IR nslookup (@SYS_OPS_EXT@) +authored by Andrew Cherenson. +.SH BUGS +\fIDig\fP has a serious case of "creeping featurism" -- the result of +considering several potential uses during it's development. It would +probably benefit from a rigorous diet. Similarly, the print flags +and granularity of the items they specify make evident their +rather ad hoc genesis. +.PP +\fIDig\fP does not consistently exit nicely (with appropriate status) +when a problem occurs somewhere in the resolver (NOTE: most of the common +exit cases are handled). This is particularly annoying when running in +batch mode. If it exits abnormally (and is not caught), the entire +batch aborts; when such an event is trapped, \fIdig\fP simply +continues with the next query. +.SH SEE ALSO +@INDOT@named(@SYS_OPS_EXT@), resolver(@LIB_NETWORK_EXT@), resolver(@FORMAT_EXT@), nslookup(@SYS_OPS_EXT@) diff --git a/usr.bin/dig/dig.c b/usr.bin/dig/dig.c new file mode 100644 index 0000000..6ac5865 --- /dev/null +++ b/usr.bin/dig/dig.c @@ -0,0 +1,1185 @@ +#ifndef lint +static char rcsid[] = "$Id: dig.c,v 4.9.1.17 1994/07/19 22:51:24 vixie Exp $"; +#endif + +/* + * ++Copyright++ 1989 + * - + * Copyright (c) 1989 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +/*********************** Notes for the BIND 4.9 release (Paul Vixie, DEC) + * dig 2.0 was written by copying sections of libresolv.a and nslookup + * and modifying them to be more useful for a general lookup utility. + * as of BIND 4.9, the changes needed to support dig have mostly been + * incorporated into libresolv.a and nslookup; dig now links against + * some of nslookup's .o files rather than #including them or maintaining + * local copies of them. in some sense, dig belongs in the nslookup + * subdirectory rather than up here in "tools", but that's for arc@sgi.com + * (owner of nslookup) to decide. + * + * while merging dig back into the BIND release, i made a number of + * structural changes. for one thing, i put all of dig's private + * library routines into this file rather than maintaining them in + * separate, #included, files. i don't like to #include ".c" files. + * i removed all calls to "bcopy", replacing them with structure + * assignments. i removed all "extern"'s of standard functions, + * replacing them with #include's of standard header files. this + * version of dig is probably as portable as the rest of BIND. + * + * i had to remove the query-time and packet-count statistics since + * the current libresolv.a is a lot harder to modify to maintain these + * than the 4.8 one (used in the original dig) was. for consolation, + * i added a "usage" message with extensive help text. + * + * to save my (limited, albeit) sanity, i ran "indent" over the source. + * i also added the standard berkeley/DEC copyrights, since this file now + * contains a fair amount of non-USC code. note that the berkeley and + * DEC copyrights do not prohibit redistribution, with or without fee; + * we add them only to protect ourselves (you have to claim copyright + * in order to disclaim liability and warranty). + * + * Paul Vixie, Palo Alto, CA, April 1993 + **************************************************************************** + + /******************************************************************* + ** DiG -- Domain Information Groper ** + ** ** + ** dig.c - Version 2.1 (7/12/94) ("BIND takeover") ** + ** ** + ** Developed by: Steve Hotz & Paul Mockapetris ** + ** USC Information Sciences Institute (USC-ISI) ** + ** Marina del Rey, California ** + ** 1989 ** + ** ** + ** dig.c - ** + ** Version 2.0 (9/1/90) ** + ** o renamed difftime() difftv() to avoid ** + ** clash with ANSI C ** + ** o fixed incorrect # args to strcmp,gettimeofday ** + ** o incorrect length specified to strncmp ** + ** o fixed broken -sticky -envsa -envset functions ** + ** o print options/flags redefined & modified ** + ** ** + ** Version 2.0.beta (5/9/90) ** + ** o output format - helpful to `doc` ** + ** o minor cleanup ** + ** o release to beta testers ** + ** ** + ** Version 1.1.beta (10/26/89) ** + ** o hanging zone transer (when REFUSED) fixed ** + ** o trailing dot added to domain names in RDATA ** + ** o ISI internal ** + ** ** + ** Version 1.0.tmp (8/27/89) ** + ** o Error in prnttime() fixed ** + ** o no longer dumps core on large pkts ** + ** o zone transfer (axfr) added ** + ** o -x added for inverse queries ** + ** (i.e. "dig -x 128.9.0.32") ** + ** o give address of default server ** + ** o accept broadcast to server @255.255.255.255 ** + ** ** + ** Version 1.0 (3/27/89) ** + ** o original release ** + ** ** + ** DiG is Public Domain, and may be used for any purpose as ** + ** long as this notice is not removed. ** + **** **** + **** NOTE: Version 2.0.beta is not for public distribution **** + **** **** + *******************************************************************/ + + +#define VERSION 21 +#define VSTRING "2.1" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> + +#include <netdb.h> +#include <stdio.h> +#include <resolv.h> +#include <ctype.h> +#include <errno.h> +#include <string.h> +#include <setjmp.h> +#include <fcntl.h> + +#include "nslookup/res.h" +#include "../conf/portability.h" + +#define PRF_DEF 0x2ff9 +#define PRF_MIN 0xA930 +#define PRF_ZONE 0x24f9 + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif + +int eecode = 0; + +FILE *qfp; +int sockFD; + +#define SAVEENV "DiG.env" +#define DIG_MAXARGS 30 + +char *defsrv, *srvmsg; +char defbuf[40] = "default -- "; +char srvbuf[60]; + +static void Usage(); +static int SetOption(), printZone(), printRR(); +static struct timeval difftv(); +static void prnttime(); + +/* stuff for nslookup modules */ +FILE *filePtr; +jmp_buf env; +HostInfo *defaultPtr = NULL; +HostInfo curHostInfo, defaultRec; +int curHostValid = FALSE; +int queryType = T_A; +int queryClass = C_IN; +extern int StringToClass(), StringToType(); /* subr.c */ +#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) +FILE *yyin = NULL; +void yyrestart(f) { } +#endif +char *pager = NULL; +/* end of nslookup stuff */ + + /* + ** Take arguments appearing in simple string (from file or command line) + ** place in char**. + */ +stackarg(y, l) + char *l; + char **y; +{ + int done=0; + while (!done) { + switch (*l) { + case '\t': + case ' ': + l++; break; + case NULL: + case '\n': + done++; + *y = NULL; + break; + default: + *y++=l; + while (!isspace(*l)) + l++; + if (*l == '\n') + done++; + *l++ = '\0'; + *y = NULL; + } + } +} + +char myhostname[MAXHOSTNAMELEN]; + +main(argc, argv) + int argc; + char **argv; +{ + struct hostent *hp; + short port = htons(NAMESERVER_PORT); + u_char packet[PACKETSZ]; + u_char answer[8*1024]; + int n; + char doping[90]; + char pingstr[50]; + char *afile; + char *addrc, *addrend, *addrbegin; + + struct timeval exectime, tv1, tv2, start_time, end_time, query_time; + + char *srv; + int anyflag = 0; + int sticky = 0; + int tmp; + int qtype = 1, qclass = 1; + int addrflag = 0; + int zone = 0; + int bytes_out, bytes_in; + + char cmd[256]; + char domain[MAXDNAME]; + char msg[120], *msgptr; + char **vtmp; + char *args[DIG_MAXARGS]; + char **ax; + char **ay; + int once = 1, dofile = 0; /* batch -vs- interactive control */ + char fileq[100]; + char *qptr; + int fp; + int wait=0, delay; + int envset=0, envsave=0; + struct __res_state res_x, res_t; + char *pp; + + res_init(); + _res.pfcode = PRF_DEF; + gethostname(myhostname, (sizeof myhostname)); + defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr)); + res_x = _res; + + /* + ** If LOCALDEF in environment, should point to file + ** containing local favourite defaults. Also look for file + ** DiG.env (i.e. SAVEENV) in local directory. + */ + + if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) && + ((fp = open(afile, O_RDONLY)) > 0)) || + ((fp = open(SAVEENV, O_RDONLY)) > 0)) { + read(fp, &res_x, (sizeof res_x)); + close(fp); + _res = res_x; + } + /* + ** check for batch-mode DiG; also pre-scan for 'help' + */ + vtmp = argv; + ax = args; + while (*vtmp != NULL) { + if (strcmp(*vtmp, "-h") == 0 || + strcmp(*vtmp, "-help") == 0 || + strcmp(*vtmp, "-usage") == 0 || + strcmp(*vtmp, "help") == 0) { + Usage(); + exit(0); + } + + if (strcmp(*vtmp, "-f") == 0) { + dofile++; once=0; + if ((qfp = fopen(*++vtmp, "r")) == NULL) { + fflush(stdout); + perror("file open"); + fflush(stderr); + exit(10); + } + } else { + if (ax - args == DIG_MAXARGS) { + fprintf(stderr, "dig: too many arguments\n"); + exit(10); + } + *ax++ = *vtmp; + } + vtmp++; + } + + _res.id = 1; + gettimeofday(&tv1, NULL); + + /* + ** Main section: once if cmd-line query + ** while !EOF if batch mode + */ + *fileq = '\0'; + while ((dofile && (fgets(fileq,100,qfp) != NULL)) || + ((!dofile) && (once--))) + { + if ((*fileq=='\n') || (*fileq=='#') || (*fileq==';')) { + continue; /* ignore blank lines & comments */ + } + +/* + * "sticky" requests that before current parsing args + * return to current "working" environment (X******) + */ + if (sticky) { + printf(";; (using sticky settings)\n"); + _res = res_x; + } + +/* concat cmd-line and file args */ + ay = ax; + qptr = fileq; + stackarg(ay, qptr); + + /* defaults */ + qtype = qclass = 1; + zone = 0; + *pingstr = 0; + srv = NULL; + + sprintf(cmd,"\n; <<>> DiG %s <<>> ",VSTRING); + argv = args; + argc = ax - args; +/* + * More cmd-line options than anyone should ever have to + * deal with .... + */ + while (*(++argv) != NULL && **argv != '\0') { + strcat(cmd,*argv); strcat(cmd," "); + if (**argv == '@') { + srv = (*argv+1); + continue; + } + if (**argv == '%') + continue; + if (**argv == '+') { + SetOption(*argv+1); + continue; + } + + if (strncmp(*argv,"-nost",5) == 0) { + sticky = 0; + continue; + } else if (strncmp(*argv,"-st",3) == 0) { + sticky++; + continue; + } else if (strncmp(*argv,"-envsa",6) == 0) { + envsave++; + continue; + } else if (strncmp(*argv,"-envse",6) == 0) { + envset++; + continue; + } + + if (**argv == '-') { + switch (argv[0][1]) { + case 'T': wait = atoi(*++argv); + break; + case 'c': + if ((tmp = atoi(*++argv)) + || *argv[0]=='0') { + qclass = tmp; + } else if (tmp = StringToClass(*argv, + 0, NULL) + ) { + qclass = tmp; + } else { + printf( + "; invalid class specified\n" + ); + } + break; + case 't': + if ((tmp = atoi(*++argv)) + || *argv[0]=='0') { + qtype = tmp; + } else if (tmp = StringToType(*argv, + 0, NULL) + ) { + qtype = tmp; + } else { + printf( + "; invalid type specified\n" + ); + } + break; + case 'x': + if (qtype == T_A) + qtype = T_ANY; + if (!(addrc = *++argv)) { + printf( + "; no arg for -x?\n" + ); + break; + } + addrend = addrc + strlen(addrc); + if (*addrend == '.') + *addrend = '\0'; + *domain = '\0'; + while (addrbegin = strrchr(addrc,'.')) { + strcat(domain, addrbegin+1); + strcat(domain, "."); + *addrbegin = '\0'; + } + strcat(domain, addrc); + strcat(domain, ".in-addr.arpa."); + break; + case 'p': port = htons(atoi(*++argv)); break; + case 'P': + if (argv[0][2] != '\0') + strcpy(pingstr,&argv[0][2]); + else + strcpy(pingstr,"ping -s"); + break; +#if defined(__RES) && (__RES >= 19931104) + case 'n': + _res.ndots = atoi(&argv[0][2]); + break; +#endif /*__RES*/ + } /* switch - */ + continue; + } /* if '-' */ + + if ((tmp = StringToType(*argv, -1, NULL)) != -1) { + if ((T_ANY == tmp) && anyflag++) { + qclass = C_ANY; + continue; + } + if (T_AXFR == tmp) { + _res.pfcode = PRF_ZONE; + zone++; + } else { + qtype = tmp; + } + } else if ((tmp = StringToClass(*argv, -1, NULL)) + != -1) { + qclass = tmp; + } else { + bzero(domain, (sizeof domain)); + sprintf(domain,"%s",*argv); + } + } /* while argv remains */ + + if (_res.pfcode & 0x80000) + printf("; pfcode: %08x, options: %08x\n", + _res.pfcode, _res.options); + +/* + * Current env. (after this parse) is to become the + * new "working environmnet. Used in conj. with sticky. + */ + if (envset) { + res_x = _res; + envset = 0; + } + +/* + * Current env. (after this parse) is to become the + * new default saved environmnet. Save in user specified + * file if exists else is SAVEENV (== "DiG.env"). + */ + if (envsave) { + afile = (char *) getenv("LOCALDEF"); + if ((afile && + ((fp = open(afile, + O_WRONLY|O_CREAT|O_TRUNC, + S_IREAD|S_IWRITE)) > 0)) + || + ((fp = open(SAVEENV, + O_WRONLY|O_CREAT|O_TRUNC, + S_IREAD|S_IWRITE)) > 0)) { + write(fp, &_res, (sizeof _res)); + close(fp); + } + envsave = 0; + } + + if (_res.pfcode & RES_PRF_CMD) + printf("%s\n", cmd); + + addrflag = anyflag = 0; + +/* + * Find address of server to query. If not dot-notation, then + * try to resolve domain-name (if so, save and turn off print + * options, this domain-query is not the one we want. Restore + * user options when done. + * Things get a bit wierd since we need to use resolver to be + * able to "put the resolver to work". + */ + + srvbuf[0] = 0; + srvmsg = defsrv; + if (srv != NULL) { + struct in_addr addr; + + if (inet_aton(srv, &addr)) { + _res.nscount = 1; + _res.nsaddr.sin_addr = addr; + srvmsg = strcat(srvbuf, srv); + } else { + res_t = _res; + _res.pfcode = 0; + _res.options = RES_DEFAULT; + res_init(); + hp = gethostbyname(srv); + _res = res_t; + if (hp == NULL + || hp->h_addr_list == NULL + || *hp->h_addr_list == NULL) { + fflush(stdout); + fprintf(stderr, + "; Bad server: %s -- using default server and timer opts\n", + srv); + fflush(stderr); + srvmsg = defsrv; + srv = NULL; + } else { + u_int32_t **addr; + + _res.nscount = 0; + for (addr = (u_int32_t**)hp->h_addr_list; + *addr && (_res.nscount < MAXNS); + addr++) { + _res.nsaddr_list[ + _res.nscount++ + ].sin_addr.s_addr = **addr; + } + + srvmsg = strcat(srvbuf,srv); + strcat(srvbuf, " "); + strcat(srvmsg, + inet_ntoa(_res.nsaddr.sin_addr) + ); + } + } + printf("; (%d server%s found)\n", + _res.nscount, (_res.nscount==1)?"":"s"); + _res.id += _res.retry; + } + + { + int i; + + for (i = 0; i < _res.nscount; i++) { + _res.nsaddr_list[i].sin_family = AF_INET; + _res.nsaddr_list[i].sin_port = port; + } + _res.id += _res.retry; + } + + if (zone) { + int i; + + for (i = 0; i < _res.nscount; i++) { + int x = printZone(domain, + &_res.nsaddr_list[i]); + if (_res.pfcode & RES_PRF_STATS) { + struct timeval exectime; + + gettimeofday(&exectime,NULL); + printf(";; FROM: %s to SERVER: %s\n", + myhostname, + inet_ntoa(_res.nsaddr_list[i] + .sin_addr)); + printf(";; WHEN: %s", + ctime(&(exectime.tv_sec))); + } + if (!x) + break; /* success */ + } + fflush(stdout); + continue; + } + + bytes_out = n = res_mkquery(QUERY, domain, qclass, qtype, + NULL, 0, NULL, + packet, sizeof(packet)); + if (n < 0) { + fflush(stderr); + printf(";; res_mkquery: buffer too small\n\n"); + continue; + } + eecode = 0; + __fp_resstat(NULL, stdout); + (void) gettimeofday(&start_time, NULL); + if ((bytes_in = n = res_send(packet, n, + answer, sizeof(answer))) < 0) { + fflush(stdout); + n = 0 - n; + msg[0]=0; + strcat(msg,";; res_send to server "); + strcat(msg,srvmsg); + perror(msg); + fflush(stderr); + + if (!dofile) { + if (eecode) + exit(eecode); + else + exit(9); + } + } + (void) gettimeofday(&end_time, NULL); + + if (_res.pfcode & RES_PRF_STATS) { + query_time = difftv(start_time, end_time); + printf(";; Total query time: "); + prnttime(query_time); + putchar('\n'); + gettimeofday(&exectime,NULL); + printf(";; FROM: %s to SERVER: %s\n", + myhostname, srvmsg); + printf(";; WHEN: %s", + ctime(&(exectime.tv_sec))); + printf(";; MSG SIZE sent: %d rcvd: %d\n", + bytes_out, bytes_in); + } + + fflush(stdout); +/* + * Argh ... not particularly elegant. Should put in *real* ping code. + * Would necessitate root priviledges for icmp port though! + */ + if (*pingstr) { + sprintf(doping,"%s %s 56 3 | tail -3",pingstr, + (srv==NULL)?(defsrv+10):srv); + system(doping); + } + putchar('\n'); + +/* + * Fairly crude method and low overhead method of keeping two + * batches started at different sites somewhat synchronized. + */ + gettimeofday(&tv2, NULL); + delay = (int)(tv2.tv_sec - tv1.tv_sec); + if (delay < wait) { + sleep(wait - delay); + } + } + return(eecode); +} + + +static void +Usage() +{ + fputs("\ +usage: dig [@server] [domain] [q-type] [q-class] {q-opt} {d-opt} [%comment]\n\ +where: server,\n\ + domain are names in the Domain Name System\n\ + q-class is one of (in,any,...) [default: in]\n\ + q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default: a]\n\ +", stderr); + fputs("\ + q-opt is one of:\n\ + -x dot-notation-address (shortcut to in-addr.arpa lookups)\n\ + -f file (batch mode input file name)\n\ + -T time (batch mode time delay, per query)\n\ + -p port (nameserver is on this port) [53]\n\ + -Pping-string (see man page)\n\ + -t query-type (synonym for q-type)\n\ + -c query-class (synonym for q-class)\n\ + -envsav,-envset (see man page)\n\ + -[no]stick (see man page)\n\ +", stderr); + fputs("\ + d-opt is of the form ``+keyword=value'' where keyword is one of:\n\ + [no]debug [no]d2 [no]recurse retry=# time=# [no]ko [no]vc\n\ + [no]defname [no]search domain=NAME [no]ignore [no]primary\n\ + [no]aaonly [no]sort [no]cmd [no]stats [no]Header [no]header\n\ + [no]ttlid [no]cl [no]qr [no]reply [no]ques [no]answer\n\ + [no]author [no]addit pfdef pfmin pfset=# pfand=# pfor=#\n\ +", stderr); + fputs("\ +notes: defname and search don't work; use fully-qualified names.\n\ +", stderr); +} + + +static int +SetOption(string) + char *string; +{ + char option[NAME_LEN]; + char type[NAME_LEN]; + char *ptr; + int i; + + i = sscanf(string, " %s", option); + if (i != 1) { + fprintf(stderr, ";*** Invalid option: %s\n", option); + return(ERROR); + } + + if (strncmp(option, "aa", 2) == 0) { /* aaonly */ + _res.options |= RES_AAONLY; + } else if (strncmp(option, "noaa", 4) == 0) { + _res.options &= ~RES_AAONLY; + } else if (strncmp(option, "deb", 3) == 0) { /* debug */ + _res.options |= RES_DEBUG; + } else if (strncmp(option, "nodeb", 5) == 0) { + _res.options &= ~(RES_DEBUG | RES_DEBUG2); + } else if (strncmp(option, "ko", 2) == 0) { /* keepopen */ + _res.options |= (RES_STAYOPEN | RES_USEVC); + } else if (strncmp(option, "noko", 4) == 0) { + _res.options &= ~RES_STAYOPEN; + } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ + _res.options |= (RES_DEBUG | RES_DEBUG2); + } else if (strncmp(option, "nod2", 4) == 0) { + _res.options &= ~RES_DEBUG2; + } else if (strncmp(option, "def", 3) == 0) { /* defname */ + _res.options |= RES_DEFNAMES; + } else if (strncmp(option, "nodef", 5) == 0) { + _res.options &= ~RES_DEFNAMES; + } else if (strncmp(option, "sea", 3) == 0) { /* search list */ + _res.options |= RES_DNSRCH; + } else if (strncmp(option, "nosea", 5) == 0) { + _res.options &= ~RES_DNSRCH; + } else if (strncmp(option, "do", 2) == 0) { /* domain */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%s", _res.defdname); + } + } else if (strncmp(option, "ti", 2) == 0) { /* timeout */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%d", &_res.retrans); + } + + } else if (strncmp(option, "ret", 3) == 0) { /* retry */ + ptr = strchr(option, '='); + if (ptr != NULL) { + sscanf(++ptr, "%d", &_res.retry); + } + + } else if (strncmp(option, "i", 1) == 0) { /* ignore */ + _res.options |= RES_IGNTC; + } else if (strncmp(option, "noi", 3) == 0) { + _res.options &= ~RES_IGNTC; + } else if (strncmp(option, "pr", 2) == 0) { /* primary */ + _res.options |= RES_PRIMARY; + } else if (strncmp(option, "nop", 3) == 0) { + _res.options &= ~RES_PRIMARY; + } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ + _res.options |= RES_RECURSE; + } else if (strncmp(option, "norec", 5) == 0) { + _res.options &= ~RES_RECURSE; + } else if (strncmp(option, "v", 1) == 0) { /* vc */ + _res.options |= RES_USEVC; + } else if (strncmp(option, "nov", 3) == 0) { + _res.options &= ~RES_USEVC; + } else if (strncmp(option, "pfset", 5) == 0) { + ptr = strchr(option, '='); + if (ptr != NULL) { + _res.pfcode = xstrtonum(++ptr); + } + } else if (strncmp(option, "pfand", 5) == 0) { + ptr = strchr(option, '='); + if (ptr != NULL) { + _res.pfcode = _res.pfcode & xstrtonum(++ptr); + } + } else if (strncmp(option, "pfor", 4) == 0) { + ptr = strchr(option, '='); + if (ptr != NULL) { + _res.pfcode |= xstrtonum(++ptr); + } + } else if (strncmp(option, "pfmin", 5) == 0) { + _res.pfcode = PRF_MIN; + } else if (strncmp(option, "pfdef", 5) == 0) { + _res.pfcode = PRF_DEF; + } else if (strncmp(option, "an", 2) == 0) { /* answer section */ + _res.pfcode |= RES_PRF_ANS; + } else if (strncmp(option, "noan", 4) == 0) { + _res.pfcode &= ~RES_PRF_ANS; + } else if (strncmp(option, "qu", 2) == 0) { /* question section */ + _res.pfcode |= RES_PRF_QUES; + } else if (strncmp(option, "noqu", 4) == 0) { + _res.pfcode &= ~RES_PRF_QUES; + } else if (strncmp(option, "au", 2) == 0) { /* authority section */ + _res.pfcode |= RES_PRF_AUTH; + } else if (strncmp(option, "noau", 4) == 0) { + _res.pfcode &= ~RES_PRF_AUTH; + } else if (strncmp(option, "ad", 2) == 0) { /* addition section */ + _res.pfcode |= RES_PRF_ADD; + } else if (strncmp(option, "noad", 4) == 0) { + _res.pfcode &= ~RES_PRF_ADD; + } else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */ + _res.pfcode |= RES_PRF_TTLID; + } else if (strncmp(option, "nott", 4) == 0) { + _res.pfcode &= ~RES_PRF_TTLID; + } else if (strncmp(option, "he", 2) == 0) { /* head flags stats */ + _res.pfcode |= RES_PRF_HEAD2; + } else if (strncmp(option, "nohe", 4) == 0) { + _res.pfcode &= ~RES_PRF_HEAD2; + } else if (strncmp(option, "H", 1) == 0) { /* header all */ + _res.pfcode |= RES_PRF_HEADX; + } else if (strncmp(option, "noH", 3) == 0) { + _res.pfcode &= ~(RES_PRF_HEADX); + } else if (strncmp(option, "qr", 2) == 0) { /* query */ + _res.pfcode |= RES_PRF_QUERY; + } else if (strncmp(option, "noqr", 4) == 0) { + _res.pfcode &= ~RES_PRF_QUERY; + } else if (strncmp(option, "rep", 3) == 0) { /* reply */ + _res.pfcode |= RES_PRF_REPLY; + } else if (strncmp(option, "norep", 5) == 0) { + _res.pfcode &= ~RES_PRF_REPLY; + } else if (strncmp(option, "cm", 2) == 0) { /* command line */ + _res.pfcode |= RES_PRF_CMD; + } else if (strncmp(option, "nocm", 4) == 0) { + _res.pfcode &= ~RES_PRF_CMD; + } else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */ + _res.pfcode |= RES_PRF_CLASS; + } else if (strncmp(option, "nocl", 4) == 0) { + _res.pfcode &= ~RES_PRF_CLASS; + } else if (strncmp(option, "st", 2) == 0) { /* stats*/ + _res.pfcode |= RES_PRF_STATS; + } else if (strncmp(option, "nost", 4) == 0) { + _res.pfcode &= ~RES_PRF_STATS; + } else { + fprintf(stderr, "; *** Invalid option: %s\n", option); + return(ERROR); + } + res_re_init(); + return(SUCCESS); +} + + + +/* + * Force a reinitialization when the domain is changed. + */ +res_re_init() +{ + static char localdomain[] = "LOCALDOMAIN"; + char *buf; + long pfcode = _res.pfcode; + + /* this is ugly but putenv() is more portable than setenv() */ + buf = malloc((sizeof localdomain) +strlen(_res.defdname) +10/*fuzz*/); + sprintf(buf, "%s=%s", localdomain, _res.defdname); + putenv(buf); /* keeps the argument, so we won't free it */ + _res.options &= ~RES_INIT; + res_init(); + _res.pfcode = pfcode; +} + + +/* + * convert char string (decimal, octal, or hex) to integer + */ +int +xstrtonum(p) + char *p; +{ + int v = 0; + int i; + int b = 10; + int flag = 0; + while (*p != 0) { + if (!flag++) + if (*p == '0') { + b = 8; p++; + continue; + } + if (isupper(*p)) + *p=tolower(*p); + if (*p == 'x') { + b = 16; p++; + continue; + } + if (isdigit(*p)) { + i = *p - '0'; + } else if (isxdigit(*p)) { + i = *p - 'a' + 10; + } else { + fprintf(stderr, + "; *** Bad char in numeric string..ignored\n"); + i = -1; + } + if (i >= b) { + fprintf(stderr, + "; *** Bad char in numeric string..ignored\n"); + i = -1; + } + if (i >= 0) + v = v * b + i; + p++; + } + return(v); +} + +/* this code was cloned from nslookup/list.c */ + +extern char *_res_resultcodes[]; /* res_debug.c */ + +typedef union { + HEADER qb1; + u_char qb2[PACKETSZ]; +} querybuf; + +static int +printZone(zone, sin) + char *zone; + struct sockaddr_in *sin; +{ + querybuf buf; + HEADER *headerPtr; + int msglen; + int amtToRead; + int numRead; + int numAnswers = 0; + int result; + int soacnt = 0; + int sockFD; + u_short len; + u_char *cp, *nmp; + char dname[2][NAME_LEN]; + char file[NAME_LEN]; + static u_char *answer = NULL; + static int answerLen = 0; + enum { + NO_ERRORS, + ERR_READING_LEN, + ERR_READING_MSG, + ERR_PRINTING + } error = NO_ERRORS; + + /* + * Create a query packet for the requested zone name. + */ + msglen = res_mkquery(QUERY, zone, queryClass, T_AXFR, NULL, + 0, 0, buf.qb2, sizeof(buf)); + if (msglen < 0) { + if (_res.options & RES_DEBUG) { + fprintf(stderr, ";; res_mkquery failed\n"); + } + return (ERROR); + } + + /* + * Set up a virtual circuit to the server. + */ + if ((sockFD = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { + int e = errno; + perror(";; socket"); + return(e); + } + if (connect(sockFD, (struct sockaddr *)sin, sizeof(*sin)) < 0) { + int e = errno; + perror(";; connect"); + (void) close(sockFD); + sockFD = -1; + return e; + } + + /* + * Send length & message for zone transfer + */ + + __putshort(msglen, (u_char *)&len); + + if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ || + write(sockFD, (char *) &buf, msglen) != msglen) { + int e = errno; + perror(";; write"); + (void) close(sockFD); + sockFD = -1; + return(e); + } + + dname[0][0] = '\0'; + while (1) { + u_int16_t tmp; + + /* + * Read the length of the response. + */ + + cp = (u_char *) &tmp; + amtToRead = INT16SZ; + while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0){ + cp += numRead; + amtToRead -= numRead; + } + if (numRead <= 0) { + error = ERR_READING_LEN; + break; + } + + if ((len = _getshort((u_char*)&tmp)) == 0) { + break; /* nothing left to read */ + } + + /* + * The server sent too much data to fit the existing buffer -- + * allocate a new one. + */ + if (len > answerLen) { + if (answerLen != 0) { + free(answer); + } + answerLen = len; + answer = (u_char *)Malloc(answerLen); + } + + /* + * Read the response. + */ + + amtToRead = len; + cp = answer; + while (amtToRead > 0 && (numRead=read(sockFD, cp, amtToRead)) > 0) { + cp += numRead; + amtToRead -= numRead; + } + if (numRead <= 0) { + error = ERR_READING_MSG; + break; + } + + result = printRR(stdout, answer, cp); + if (result != 0) { + error = ERR_PRINTING; + break; + } + + numAnswers++; + cp = answer + HFIXEDSZ; + if (ntohs(((HEADER *)answer)->qdcount) > 0) + cp += dn_skipname((u_char *)cp, + (u_char *)answer + len) + QFIXEDSZ; + nmp = cp; + cp += dn_skipname((u_char *)cp, (u_char *)answer + len); + if ((_getshort((u_char*)cp) == T_SOA)) { + (void) dn_expand(answer, answer + len, nmp, + dname[soacnt], sizeof dname[0]); + if (soacnt) { + if (strcmp(dname[0], dname[1]) == 0) + break; + } else + soacnt++; + } + } + + fprintf(stdout, ";; Received %d record%s.\n", + numAnswers, (numAnswers != 1) ? "s" : ""); + + (void) close(sockFD); + sockFD = -1; + + switch (error) { + case NO_ERRORS: + return (0); + + case ERR_READING_LEN: + return(EMSGSIZE); + + case ERR_PRINTING: + return(result); + + case ERR_READING_MSG: + return(EMSGSIZE); + + default: + return(EFAULT); + } +} + +static int +printRR(file, msg, eom) + FILE *file; + u_char *msg, *eom; +{ + register u_char *cp; + HEADER *headerPtr; + int type, class, dlen, nameLen; + u_int32_t ttl; + int n, pref; + struct in_addr inaddr; + char name[NAME_LEN]; + char name2[NAME_LEN]; + Boolean stripped; + + /* + * Read the header fields. + */ + headerPtr = (HEADER *)msg; + cp = msg + HFIXEDSZ; + if (headerPtr->rcode != NOERROR) { + return(headerPtr->rcode); + } + + /* + * We are looking for info from answer resource records. + * If there aren't any, return with an error. We assume + * there aren't any question records. + */ + + if (ntohs(headerPtr->ancount) == 0) { + return(NO_INFO); + } else { + if (ntohs(headerPtr->qdcount) > 0) { + nameLen = dn_skipname(cp, eom); + if (nameLen < 0) + return (ERROR); + cp += nameLen + QFIXEDSZ; + } + cp = (u_char*) p_rr(cp, msg, stdout); + } + return(SUCCESS); +} + +static +struct timeval +difftv(a, b) + struct timeval a, b; +{ + static struct timeval diff; + + diff.tv_sec = b.tv_sec - a.tv_sec; + if ((diff.tv_usec = b.tv_usec - a.tv_usec) < 0) { + diff.tv_sec--; + diff.tv_usec += 1000000; + } + return(diff); +} + +static +void +prnttime(t) + struct timeval t; +{ + printf("%u msec", t.tv_sec * 1000 + (t.tv_usec / 1000)); +} |