diff options
Diffstat (limited to 'contrib/bind/bin/dig/dig.c')
-rw-r--r-- | contrib/bind/bin/dig/dig.c | 1806 |
1 files changed, 0 insertions, 1806 deletions
diff --git a/contrib/bind/bin/dig/dig.c b/contrib/bind/bin/dig/dig.c deleted file mode 100644 index 5bb6e7aee06c..000000000000 --- a/contrib/bind/bin/dig/dig.c +++ /dev/null @@ -1,1806 +0,0 @@ -#ifndef lint -static const char rcsid[] = "$Id: dig.c,v 8.57 2002/06/18 02:26:49 marka Exp $"; -#endif - -/* - * 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. - */ - -/* - * Portions Copyright (c) 1996-1999 by Internet Software Consortium - * - * 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. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM 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. - */ - -/*********************** 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. - * - * 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. * - ******************************************************************/ - -/* Import. */ - -#include "port_before.h" - -#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 <sys/wait.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <arpa/nameser.h> - -#include <isc/dst.h> - -#include <assert.h> -#include <ctype.h> -#include <errno.h> -#include <fcntl.h> -#include <netdb.h> -#include <setjmp.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "port_after.h" - -#include <resolv.h> - -#include "../nslookup/res.h" - -/* Global. */ - -#define VERSION 83 -#define VSTRING "8.3" - -#define PRF_DEF (RES_PRF_STATS | RES_PRF_CMD | RES_PRF_QUES | \ - RES_PRF_ANS | RES_PRF_AUTH | RES_PRF_ADD | \ - RES_PRF_HEAD1 | RES_PRF_HEAD2 | RES_PRF_TTLID | \ - RES_PRF_HEADX | RES_PRF_REPLY | RES_PRF_TRUNC) -#define PRF_MIN (RES_PRF_QUES | RES_PRF_ANS | RES_PRF_HEAD1 | \ - RES_PRF_HEADX | RES_PRF_REPLY | RES_PRF_TRUNC) -#define PRF_ZONE (RES_PRF_STATS | RES_PRF_CMD | RES_PRF_QUES | \ - RES_PRF_ANS | RES_PRF_AUTH | RES_PRF_ADD | \ - RES_PRF_TTLID | RES_PRF_REPLY | RES_PRF_TRUNC) - -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 256 -#endif - -#define SAVEENV "DiG.env" -#define DIG_MAXARGS 30 - -static int eecode = 0; -static FILE * qfp; -static char *defsrv, *srvmsg; -static char defbuf[40] = "default -- "; -static char srvbuf[1024]; -static char myhostname[MAXHOSTNAMELEN]; -static struct sockaddr_in myaddress; -static struct sockaddr_in6 myaddress6; -static u_int32_t ixfr_serial; - -/* stuff for nslookup modules */ -struct __res_state res; -FILE *filePtr; -jmp_buf env; -HostInfo *defaultPtr = NULL; -HostInfo curHostInfo, defaultRec; -int curHostValid = FALSE; -int queryType, queryClass; -extern int StringToClass(), StringToType(); /* subr.c */ -#if defined(BSD) && BSD >= 199006 && !defined(RISCOS_BSD) -FILE *yyin = NULL; -void yyrestart(FILE *f) { UNUSED(f); } -#endif -char *pager = NULL; -/* end of nslookup stuff */ - -/* Forward. */ - -static void Usage(void); -static int setopt(const char *); -static void res_re_init(void); -static int xstrtonum(char *); -static int printZone(ns_type, const char *, - const struct sockaddr_in *, ns_tsig_key *); -static int print_axfr(FILE *output, const u_char *msg, - size_t msglen); -static struct timeval difftv(struct timeval, struct timeval); -static void prnttime(struct timeval); -static void stackarg(char *, char **); -static void reverse6(char *, struct in6_addr *); - -/* Public. */ - -int -main(int argc, char **argv) { - short port = htons(NAMESERVER_PORT); - short lport; - /* Wierd stuff for SPARC alignment, hurts nothing else. */ - union { - HEADER header_; - u_char packet_[PACKETSZ]; - } packet_; -#define header (packet_.header_) -#define packet (packet_.packet_) - u_char answer[64*1024]; - int n; - char doping[90]; - char pingstr[50]; - char *afile; - char *addrc, *addrend, *addrbegin; - - time_t exectime; - struct timeval tv1, tv2, start_time, end_time, query_time; - - char *srv; - int anyflag = 0; - int sticky = 0; - int tmp; - int qtypeSet; - int addrflag = 0; - ns_type xfr = ns_t_invalid; - int bytes_out, bytes_in; - - char cmd[512]; - char domain[MAXDNAME]; - char msg[120], **vtmp; - char *args[DIG_MAXARGS]; - char **ax; - int once = 1, dofile = 0; /* batch -vs- interactive control */ - char fileq[384]; - int fp; - int wait=0, delay; - int envset=0, envsave=0; - struct __res_state res_x, res_t; - int r; - struct in6_addr in6; - - ns_tsig_key key; - char *keyfile = NULL, *keyname = NULL; - - res_ninit(&res); - res.pfcode = PRF_DEF; - qtypeSet = 0; - memset(domain, 0, sizeof domain); - gethostname(myhostname, (sizeof myhostname)); -#ifdef HAVE_SA_LEN - myaddress.sin_len = sizeof(struct sockaddr_in); -#endif - myaddress.sin_family = AF_INET; - myaddress.sin_addr.s_addr = INADDR_ANY; - myaddress.sin_port = 0; /*INPORT_ANY*/; - -#ifdef HAVE_SA_LEN - myaddress6.sin6_len = sizeof(struct sockaddr_in6); -#endif - myaddress6.sin6_family = AF_INET6; - myaddress6.sin6_addr = in6addr_any; - myaddress6.sin6_port = 0; /*INPORT_ANY*/; - - 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, (char *)&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, sizeof fileq, qfp) != NULL) || - (!dofile && once--)) - { - if (*fileq == '\n' || *fileq == '#' || *fileq==';') { - printf("%s", fileq); /* echo but otherwise ignore */ - continue; /* blank lines and 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. - */ - stackarg(fileq, ax); - - /* defaults */ - queryType = ns_t_ns; - queryClass = ns_c_in; - xfr = ns_t_invalid; - *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 == '+') { - setopt(*argv+1); - continue; - } - if (**argv == '=') { - ixfr_serial = strtoul(*argv+1, NULL, 0); - 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': - if (*++argv == NULL) - printf("; no arg for -T?\n"); - else - wait = atoi(*argv); - break; - case 'c': - if(*++argv == NULL) - printf("; no arg for -c?\n"); - else if ((tmp = atoi(*argv)) - || *argv[0] == '0') { - queryClass = tmp; - } else if ((tmp = StringToClass(*argv, - 0, NULL) - ) != 0) { - queryClass = tmp; - } else { - printf( - "; invalid class specified\n" - ); - } - break; - case 't': - if (*++argv == NULL) - printf("; no arg for -t?\n"); - else if ((tmp = atoi(*argv)) - || *argv[0]=='0') { - if (ns_t_xfr_p(tmp)) { - xfr = tmp; - } else { - queryType = tmp; - qtypeSet++; - } - } else if ((tmp = StringToType(*argv, - 0, NULL) - ) != 0) { - if (ns_t_xfr_p(tmp)) { - xfr = tmp; - } else { - queryType = tmp; - qtypeSet++; - } - } else { - printf( - "; invalid type specified\n" - ); - } - break; - case 'x': - if (!qtypeSet) { - queryType = T_ANY; - qtypeSet++; - } - if ((addrc = *++argv) == NULL) { - printf("; no arg for -x?\n"); - break; - } - r = inet_pton(AF_INET6, addrc, &in6); - if (r > 0) { - reverse6(domain, &in6); - 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': - if (argv[0][2] != '\0') - port = htons(atoi(argv[0]+2)); - else if (*++argv == NULL) - printf("; no arg for -p?\n"); - else - port = htons(atoi(*argv)); - break; - case 'P': - if (argv[0][2] != '\0') - strcpy(pingstr, argv[0]+2); - else - strcpy(pingstr, "ping -s"); - break; - case 'n': - if (argv[0][2] != '\0') - res.ndots = atoi(argv[0]+2); - else if (*++argv == NULL) - printf("; no arg for -n?\n"); - else - res.ndots = atoi(*argv); - break; - case 'b': { - char *a, *p; - - if (argv[0][2] != '\0') - a = argv[0]+2; - else if (*++argv == NULL) { - printf("; no arg for -b?\n"); - break; - } else - a = *argv; - if ((p = strchr(a, ':')) != NULL) { - *p++ = '\0'; - lport = htons(atoi(p)); - } else - lport = htons(0); - if (inet_pton(AF_INET6, a, - &myaddress6.sin6_addr) == 1) { - myaddress6.sin6_port = lport; - } else if (!inet_aton(a, - &myaddress.sin_addr)) { - fprintf(stderr, - ";; bad -b addr\n"); - exit(1); - } else - myaddress.sin_port = lport; - } - break; - case 'k': - /* -k keydir:keyname */ - - if (argv[0][2] != '\0') - keyfile = argv[0]+2; - else if (*++argv == NULL) { - printf("; no arg for -k?\n"); - break; - } else - keyfile = *argv; - - keyname = strchr(keyfile, ':'); - if (keyname == NULL) { - fprintf(stderr, - "key option argument should be keydir:keyname\n"); - exit(1); - } - *keyname++='\0'; - break; - } /* switch - */ - continue; - } /* if '-' */ - - if ((tmp = StringToType(*argv, -1, NULL)) != -1) { - if ((T_ANY == tmp) && anyflag++) { - queryClass = C_ANY; - continue; - } - if (ns_t_xfr_p(tmp) && - (tmp == ns_t_axfr || - (res.options & RES_USEVC) != 0) - ) { - res.pfcode = PRF_ZONE; - xfr = (ns_type)tmp; - } else { - queryType = tmp; - qtypeSet++; - } - } else if ((tmp = StringToClass(*argv, -1, NULL)) - != -1) { - queryClass = tmp; - } else { - memset(domain, 0, sizeof domain); - sprintf(domain,"%s",*argv); - } - } /* while argv remains */ - - /* process key options */ - if (keyfile) { -#ifdef PARSE_KEYFILE - int i, n1; - char buf[BUFSIZ], *p; - FILE *fp = NULL; - int file_major, file_minor, alg; - - fp = fopen(keyfile, "r"); - if (fp == NULL) { - perror(keyfile); - exit(1); - } - /* Now read the header info from the file. */ - i = fread(buf, 1, BUFSIZ, fp); - if (i < 5) { - fclose(fp); - exit(1); - } - fclose(fp); - - p = buf; - - n=strlen(p); /* get length of strings */ - n1=strlen("Private-key-format: v"); - if (n1 > n || - strncmp(buf, "Private-key-format: v", n1)) { - fprintf(stderr, "Invalid key file format\n"); - exit(1); /* not a match */ - } - p+=n1; /* advance pointer */ - sscanf((char *)p, "%d.%d", &file_major, &file_minor); - /* should do some error checking with these someday */ - while (*p++!='\n'); /* skip to end of line */ - - n=strlen(p); /* get length of strings */ - n1=strlen("Algorithm: "); - if (n1 > n || strncmp(p, "Algorithm: ", n1)) { - fprintf(stderr, "Invalid key file format\n"); - exit(1); /* not a match */ - } - p+=n1; /* advance pointer */ - if (sscanf((char *)p, "%d", &alg)!=1) { - fprintf(stderr, "Invalid key file format\n"); - exit(1); - } - while (*p++!='\n'); /* skip to end of line */ - - n=strlen(p); /* get length of strings */ - n1=strlen("Key: "); - if (n1 > n || strncmp(p, "Key: ", n1)) { - fprintf(stderr, "Invalid key file format\n"); - exit(1); /* not a match */ - } - p+=n1; /* advance pointer */ - pp=p; - while (*pp++!='\n'); /* skip to end of line, - * terminate it */ - *--pp='\0'; - - key.data=malloc(1024*sizeof(char)); - key.len=b64_pton(p, key.data, 1024); - - strcpy(key.name, keyname); - strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); -#else - /* use the dst* routines to parse the key files - * - * This requires that both the .key and the .private - * files exist in your cwd, so the keyfile parmeter - * here is assumed to be a path in which the - * K*.{key,private} files exist. - */ - DST_KEY *dst_key; - char cwd[PATH_MAX+1]; - - if (getcwd(cwd, PATH_MAX)==NULL) { - perror("unable to get current directory"); - exit(1); - } - if (chdir(keyfile)<0) { - fprintf(stderr, - "unable to chdir to %s: %s\n", keyfile, - strerror(errno)); - exit(1); - } - - dst_init(); - dst_key = dst_read_key(keyname, - 0 /* not used for priv keys */, - KEY_HMAC_MD5, DST_PRIVATE); - if (!dst_key) { - fprintf(stderr, - "dst_read_key: error reading key\n"); - exit(1); - } - key.data=malloc(1024*sizeof(char)); - dst_key_to_buffer(dst_key, key.data, 1024); - key.len=dst_key->dk_key_size; - - strcpy(key.name, keyname); - strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); - - if (chdir(cwd)<0) { - fprintf(stderr, "unable to chdir to %s: %s\n", - cwd, strerror(errno)); - exit(1); - } -#endif - } - - if (res.pfcode & 0x80000) - printf("; pfcode: %08lx, options: %08lx\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, (char *)&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) { - int nscount = 0; - union res_sockaddr_union u[MAXNS]; - struct addrinfo *answer = NULL; - struct addrinfo *cur = NULL; - struct addrinfo hint; - - memset(u, 0, sizeof(u)); - res_t = res; - res_ninit(&res); - res.pfcode = 0; - res.options = RES_DEFAULT; - memset(&hint, 0, sizeof(hint)); - hint.ai_socktype = SOCK_DGRAM; - if (!getaddrinfo(srv, NULL, &hint, &answer)) { - res = res_t; - cur = answer; - for (cur = answer; - cur != NULL; - cur = cur->ai_next) { - if (nscount == MAXNS) - break; - switch (cur->ai_addr->sa_family) { - case AF_INET6: - u[nscount].sin6 = - *(struct sockaddr_in6*)cur->ai_addr; - u[nscount++].sin6.sin6_port = - port; - break; - case AF_INET: - u[nscount].sin = - *(struct sockaddr_in*)cur->ai_addr; - u[nscount++].sin6.sin6_port = - port; - break; - } - } - if (nscount != 0) { - char buf[80]; - res_setservers(&res, u, nscount); - srvmsg = strcat(srvbuf, srv); - strcat(srvbuf, " "); - buf[0] = '\0'; - switch (u[0].sin.sin_family) { - case AF_INET: - inet_ntop(AF_INET, - &u[0].sin.sin_addr, - buf, sizeof(buf)); - break; - case AF_INET6: - inet_ntop(AF_INET6, - &u[0].sin6.sin6_addr, - buf, sizeof(buf)); - break; - } - strcat(srvbuf, buf); - } - freeaddrinfo(answer); - } else { - res = res_t; - fflush(stdout); - fprintf(stderr, - "; Bad server: %s -- using default server and timer opts\n", - srv); - fflush(stderr); - srvmsg = defsrv; - srv = NULL; - } - printf("; (%d server%s found)\n", - res.nscount, (res.nscount==1)?"":"s"); - res.id += res.retry; - } - - if (ns_t_xfr_p(xfr)) { - int i; - int nscount; - union res_sockaddr_union u[MAXNS]; - nscount = res_getservers(&res, u, MAXNS); - for (i = 0; i < res.nscount; i++) { - int x; - - if (keyfile) - x = printZone(xfr, domain, - &u[i].sin, - &key); - else - x = printZone(xfr, domain, - &u[i].sin, - NULL); - if (res.pfcode & RES_PRF_STATS) { - char buf[80]; - exectime = time(NULL); - buf[0] = '\0'; - switch (u[i].sin.sin_family) { - case AF_INET: - inet_ntop(AF_INET, - &u[i].sin.sin_addr, - buf, sizeof(buf)); - break; - case AF_INET6: - inet_ntop(AF_INET6, - &u[i].sin6.sin6_addr, - buf, sizeof(buf)); - break; - } - printf(";; FROM: %s to SERVER: %s\n", - myhostname, - buf); - printf(";; WHEN: %s", ctime(&exectime)); - } - if (!x) - break; /* success */ - } - fflush(stdout); - continue; - } - - if (*domain && !qtypeSet) { - queryType = T_A; - qtypeSet++; - } - - bytes_out = n = res_nmkquery(&res, QUERY, domain, - queryClass, queryType, - NULL, 0, NULL, - packet, sizeof packet); - if (n < 0) { - fflush(stderr); - printf(";; res_nmkquery: buffer too small\n\n"); - fflush(stdout); - continue; - } - if (queryType == T_IXFR) { - HEADER *hp = (HEADER *) packet; - u_char *cpp = packet + bytes_out; - - hp->nscount = htons(1+ntohs(hp->nscount)); - n = dn_comp(domain, cpp, - (sizeof packet) - (cpp - packet), - NULL, NULL); - cpp += n; - PUTSHORT(T_SOA, cpp); /* type */ - PUTSHORT(C_IN, cpp); /* class */ - PUTLONG(0, cpp); /* ttl */ - PUTSHORT(22, cpp); /* dlen */ - *cpp++ = 0; /* mname */ - *cpp++ = 0; /* rname */ - PUTLONG(ixfr_serial, cpp); - PUTLONG(0xDEAD, cpp); /* Refresh */ - PUTLONG(0xBEEF, cpp); /* Retry */ - PUTLONG(0xABCD, cpp); /* Expire */ - PUTLONG(0x1776, cpp); /* Min TTL */ - bytes_out = n = cpp - packet; - }; - -#if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC) - if (n > 0 && - (res.options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) - bytes_out = n = res_nopt(&res, n, packet, - sizeof(packet), 4096); -#endif - - eecode = 0; - if (res.pfcode & RES_PRF_HEAD1) - fp_resstat(&res, stdout); - (void) gettimeofday(&start_time, NULL); - if (keyfile) - n = res_nsendsigned(&res, packet, n, &key, answer, sizeof answer); - else - n = res_nsend(&res, packet, n, answer, sizeof answer); - if ((bytes_in = n) < 0) { - fflush(stdout); - n = 0 - n; - msg[0]=0; - if (keyfile) - strcat(msg,";; res_nsendsigned to server "); - else - strcat(msg,";; res_nsend 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'); - exectime = time(NULL); - printf(";; FROM: %s to SERVER: %s\n", - myhostname, srvmsg); - printf(";; WHEN: %s", ctime(&exectime)); - 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); - } - tv1 = tv2; - } - return (eecode); -} - -/* Private. */ - -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\ - -b addr[:port] (bind to this tcp address) [*]\n\ - -P[ping-string] (see man page)\n\ - -t query-type (synonym for q-type)\n\ - -c query-class (synonym for q-class)\n\ - -k keydir:keyname (sign the query with this TSIG key)\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]cmd [no]stats [no]Header [no]header [no]trunc\n\ - [no]ttlid [no]cl [no]qr [no]reply [no]ques [no]answer\n\ - [no]author [no]addit [no]dnssec pfdef pfmin\n\ - pfset=# pfand=# pfor=#\n\ -", stderr); - fputs("\ -notes: defname and search don't work; use fully-qualified names.\n\ - this is DiG version " VSTRING "\n\ - $Id: dig.c,v 8.57 2002/06/18 02:26:49 marka Exp $\n\ -", stderr); -} - -static int -setopt(const char *string) { - char option[NAME_LEN], *ptr; - int i; - - i = pickString(string, option, sizeof option); - if (i == 0) { - fprintf(stderr, ";*** Invalid option: %s\n", string); - - /* this is ugly, but fixing the caller to behave - properly with an error return value would require a major - cleanup. */ - exit(9); - } - - 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, "dn", 2) == 0) { /* dnssec */ - res.options |= RES_USE_DNSSEC; - } else if (strncmp(option, "nodn", 4) == 0) { - res.options &= ~RES_USE_DNSSEC; - } 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) { - i = pickString(++ptr, res.defdname, sizeof res.defdname); - if (i == 0) { /* value's too long or non-existant. This actually - shouldn't happen due to pickString() - above */ - fprintf(stderr, "*** Invalid domain: %s\n", ptr) ; - exit(9); /* see comment at previous call to exit()*/ - } - } - } 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, "tr", 2) == 0) { /* TTL & ID */ - res.pfcode |= RES_PRF_TRUNC; - } else if (strncmp(option, "notr", 4) == 0) { - res.pfcode &= ~RES_PRF_TRUNC; - } 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. - */ -static void -res_re_init() { - static char localdomain[] = "LOCALDOMAIN"; - u_long pfcode = res.pfcode, options = res.options; - unsigned ndots = res.ndots; - int retrans = res.retrans, retry = res.retry; - char *buf; - - /* - * 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_ninit(&res); - res.pfcode = pfcode; - res.options = options; - res.ndots = ndots; - res.retrans = retrans; - res.retry = retry; -} - -/* - * convert char string (decimal, octal, or hex) to integer - */ -static int -xstrtonum(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); -} - -typedef union { - HEADER qb1; - u_char qb2[PACKETSZ]; -} querybuf; - -static int -printZone(ns_type xfr, const char *zone, const struct sockaddr_in *sin, - ns_tsig_key *key) -{ - static u_char *answer = NULL; - static int answerLen = 0; - - querybuf buf; - int msglen, amtToRead, numRead, result, sockFD, len; - int count, type, class, rlen, done, n; - int numAnswers, numRecords, soacnt; - u_char *cp, tmp[NS_INT16SZ]; - char dname[2][NS_MAXDNAME]; - enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } - error; - pid_t zpid = -1; - u_char *newmsg; - int newmsglen; - ns_tcp_tsig_state tsig_state; - int tsig_ret, tsig_required, tsig_present; - - switch (xfr) { - case ns_t_axfr: - case ns_t_zxfr: - break; - default: - fprintf(stderr, ";; %s - transfer type not supported\n", - p_type(xfr)); - return (ERROR); - } - - /* - * Create a query packet for the requested zone name. - */ - msglen = res_nmkquery(&res, ns_o_query, zone, - queryClass, ns_t_axfr, NULL, - 0, 0, buf.qb2, sizeof buf); - if (msglen < 0) { - if (res.options & RES_DEBUG) - fprintf(stderr, ";; res_nmkquery failed\n"); - return (ERROR); - } - - /* - * Sign the message if a key was sent - */ - if (key == NULL) { - newmsg = (u_char *)&buf; - newmsglen = msglen; - } else { - DST_KEY *dstkey; - int bufsize, siglen; - u_char sig[64]; - int ret; - - /* ns_sign() also calls dst_init(), but there is no harm - * doing it twice - */ - dst_init(); - - bufsize = msglen + 1024; - newmsg = (u_char *) malloc(bufsize); - if (newmsg == NULL) { - errno = ENOMEM; - return (-1); - } - memcpy(newmsg, (u_char *)&buf, msglen); - newmsglen = msglen; - - if (strcmp(key->alg, NS_TSIG_ALG_HMAC_MD5) != 0) - dstkey = NULL; - else - dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, - NS_KEY_TYPE_AUTH_ONLY, - NS_KEY_PROT_ANY, - key->data, key->len); - if (dstkey == NULL) { - errno = EINVAL; - if (key) - free(newmsg); - return (-1); - } - - siglen = sizeof(sig); -/* newmsglen++; */ - ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, - sig, &siglen, 0); - if (ret < 0) { - if (key) - free (newmsg); - if (ret == NS_TSIG_ERROR_NO_SPACE) - errno = EMSGSIZE; - else if (ret == -1) - errno = EINVAL; - return (ret); - } - ns_verify_tcp_init(dstkey, sig, siglen, &tsig_state); - } - - /* - * 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); - } - - switch (sin->sin_family) { - case AF_INET: - if (bind(sockFD, (struct sockaddr *)&myaddress, - sizeof myaddress) < 0){ - int e = errno; - - fprintf(stderr, ";; bind(%s:%u): %s\n", - inet_ntoa(myaddress.sin_addr), - ntohs(myaddress.sin_port), - strerror(e)); - (void) close(sockFD); - sockFD = -1; - return (e); - } - if (connect(sockFD, (const struct sockaddr *)sin, - sizeof *sin) < 0) { - int e = errno; - - perror(";; connect"); - (void) close(sockFD); - sockFD = -1; - return (e); - } - break; - case AF_INET6: - if (bind(sockFD, (struct sockaddr *)&myaddress6, - sizeof myaddress6) < 0){ - int e = errno; - char buf[80]; - - fprintf(stderr, ";; bind(%s:%u): %s\n", - inet_ntop(AF_INET6, &myaddress6.sin6_addr, - buf, sizeof(buf)), - ntohs(myaddress6.sin6_port), - strerror(e)); - (void) close(sockFD); - sockFD = -1; - return (e); - } - if (connect(sockFD, (const struct sockaddr *)sin, - sizeof(struct sockaddr_in6)) < 0) { - int e = errno; - - perror(";; connect"); - (void) close(sockFD); - sockFD = -1; - return (e); - } - break; - } - - /* - * Send length & message for zone transfer - */ - - ns_put16(newmsglen, tmp); - if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ || - write(sockFD, (char *)newmsg, newmsglen) != newmsglen) { - int e = errno; - if (key) - free (newmsg); - perror(";; write"); - (void) close(sockFD); - sockFD = -1; - return (e); - } else if (key) - free (newmsg); - - /* - * If we're compressing, push a gzip into the pipeline. - */ - if (xfr == ns_t_zxfr) { - enum { rd = 0, wr = 1 }; - int z[2]; - - if (pipe(z) < 0) { - int e = errno; - - perror(";; pipe"); - (void) close(sockFD); - sockFD = -1; - return (e); - } - zpid = vfork(); - if (zpid < 0) { - int e = errno; - - perror(";; fork"); - (void) close(sockFD); - sockFD = -1; - return (e); - } else if (zpid == 0) { - /* Child. */ - (void) close(z[rd]); - (void) dup2(sockFD, STDIN_FILENO); - (void) close(sockFD); - (void) dup2(z[wr], STDOUT_FILENO); - (void) close(z[wr]); - execlp("gzip", "gzip", "-d", "-v", NULL); - perror(";; child: execlp(gunzip)"); - _exit(1); - } - /* Parent. */ - (void) close(z[wr]); - (void) dup2(z[rd], sockFD); - (void) close(z[rd]); - } - result = 0; - numAnswers = 0; - numRecords = 0; - soacnt = 0; - error = NO_ERRORS; - - dname[0][0] = '\0'; - for (done = 0; !done; (void)NULL) { - /* - * Read the length of the response. - */ - - cp = tmp; - amtToRead = INT16SZ; - while (amtToRead > 0 && - (numRead = read(sockFD, cp, amtToRead)) > 0) { - cp += numRead; - amtToRead -= numRead; - } - if (numRead <= 0) { - error = ERR_READING_LEN; - break; - } - - len = ns_get16(tmp); - if (len == 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 = print_axfr(stdout, answer, len); - if (result != 0) { - error = ERR_PRINTING; - break; - } - numRecords += htons(((HEADER *)answer)->ancount); - numAnswers++; - - /* Header. */ - cp = answer + HFIXEDSZ; - /* Question. */ - for (count = ntohs(((HEADER *)answer)->qdcount); - count > 0; - count--) { - n = dn_skipname(cp, answer + len); - if (n < 0) { - error = ERR_PRINTING; - done++; - break; - } - cp += n + QFIXEDSZ; - if (cp > answer + len) { - error = ERR_PRINTING; - done++; - break; - } - } - /* Answer. */ - for (count = ntohs(((HEADER *)answer)->ancount); - count > 0 && !done; - count--) { - n = dn_expand(answer, answer + len, cp, - dname[soacnt], sizeof dname[0]); - if (n < 0) { - error = ERR_PRINTING; - done++; - break; - } - cp += n; - if (cp + 3 * INT16SZ + INT32SZ > answer + len) { - error = ERR_PRINTING; - done++; - break; - } - GETSHORT(type, cp); - GETSHORT(class, cp); - cp += INT32SZ; /* ttl */ - GETSHORT(rlen, cp); - cp += rlen; - if (cp > answer + len) { - error = ERR_PRINTING; - done++; - break; - } - if (type == T_SOA && soacnt++ && - ns_samename(dname[0], dname[1]) == 1) { - done++; - break; - } - } - - /* - * Verify the TSIG - */ - - if (key) { - if (ns_find_tsig(answer, answer + len) != NULL) - tsig_present = 1; - else - tsig_present = 0; - if (numAnswers == 1 || soacnt > 1) - tsig_required = 1; - else - tsig_required = 0; - tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, - tsig_required); - if (tsig_ret == 0) { - if (tsig_present) - printf("; TSIG ok\n"); - } - else - printf("; TSIG invalid\n"); - } - - } - - printf(";; Received %d answer%s (%d record%s).\n", - numAnswers, (numAnswers != 1) ? "s" : "", - numRecords, (numRecords != 1) ? "s" : ""); - - (void) close(sockFD); - sockFD = -1; - - /* - * If we were uncompressing, reap the uncompressor. - */ - if (xfr == ns_t_zxfr) { - pid_t pid; - int status; - - pid = wait(&status); - if (pid < 0) { - int e = errno; - - perror(";; wait"); - return (e); - } - if (pid != zpid) { - fprintf(stderr, ";; wrong pid (%lu != %lu)\n", - (u_long)pid, (u_long)zpid); - return (ERROR); - } - printf(";; pid %lu: exit %d, signal %d, core %c\n", - (u_long)pid, WEXITSTATUS(status), - WIFSIGNALED(status) ? WTERMSIG(status) : 0, - WCOREDUMP(status) ? 't' : 'f'); - } - - 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 -print_axfr(FILE *file, const u_char *msg, size_t msglen) { - ns_msg handle; - - if (ns_initparse(msg, msglen, &handle) < 0) { - fprintf(file, ";; ns_initparse: %s\n", strerror(errno)); - return (ns_r_formerr); - } - if (ns_msg_getflag(handle, ns_f_rcode) != ns_r_noerror) - return (ns_msg_getflag(handle, ns_f_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 (ns_msg_count(handle, ns_s_an) == 0) - return (NO_INFO); - -#ifdef PROTOCOLDEBUG - printf(";;; (message of %d octets has %d answers)\n", - msglen, ns_msg_count(handle, ns_s_an)); -#endif - for (;;) { - static char origin[NS_MAXDNAME], name_ctx[NS_MAXDNAME]; - const char *name; - char buf[2048]; /* XXX need to malloc/realloc. */ - ns_rr rr; - - if (ns_parserr(&handle, ns_s_an, -1, &rr)) { - if (errno != ENODEV) { - fprintf(file, ";; ns_parserr: %s\n", - strerror(errno)); - return (FORMERR); - } - break; - } - name = ns_rr_name(rr); - if (origin[0] == '\0' && name[0] != '\0') { - if (strcmp(name, ".") != 0) - strcpy(origin, name); - fprintf(file, "$ORIGIN %s.\n", origin); - if (strcmp(name, ".") == 0) - strcpy(origin, name); - if (res.pfcode & RES_PRF_TRUNC) - strcpy(name_ctx, "@"); - } - if (ns_sprintrr(&handle, &rr, - (res.pfcode & RES_PRF_TRUNC) ? name_ctx : NULL, - (res.pfcode & RES_PRF_TRUNC) ? origin : NULL, - buf, sizeof buf) < 0) { - fprintf(file, ";; ns_sprintrr: %s\n", strerror(errno)); - return (FORMERR); - } - strcpy(name_ctx, name); - fputs(buf, file); - fputc('\n', file); - } - return (SUCCESS); -} - -static struct timeval -difftv(struct timeval a, struct timeval 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(struct timeval t) { - printf("%lu msec", (u_long)(t.tv_sec * 1000 + (t.tv_usec / 1000))); -} - -/* - * Take arguments appearing in simple string (from file or command line) - * place in char**. - */ -static void -stackarg(char *l, char **y) { - int done = 0; - - while (!done) { - switch (*l) { - case '\t': - case ' ': - l++; - break; - case '\0': - case '\n': - done++; - *y = NULL; - break; - default: - *y++ = l; - while (!isspace(*l)) - l++; - if (*l == '\n') - done++; - *l++ = '\0'; - *y = NULL; - } - } -} - -static void -reverse6(char *domain, struct in6_addr *in6) { - sprintf(domain, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.arpa", - in6->s6_addr[15] & 0x0f, (in6->s6_addr[15] >> 4) & 0x0f, - in6->s6_addr[14] & 0x0f, (in6->s6_addr[14] >> 4) & 0x0f, - in6->s6_addr[13] & 0x0f, (in6->s6_addr[13] >> 4) & 0x0f, - in6->s6_addr[12] & 0x0f, (in6->s6_addr[12] >> 4) & 0x0f, - in6->s6_addr[11] & 0x0f, (in6->s6_addr[11] >> 4) & 0x0f, - in6->s6_addr[10] & 0x0f, (in6->s6_addr[10] >> 4) & 0x0f, - in6->s6_addr[9] & 0x0f, (in6->s6_addr[9] >> 4) & 0x0f, - in6->s6_addr[8] & 0x0f, (in6->s6_addr[8] >> 4) & 0x0f, - in6->s6_addr[7] & 0x0f, (in6->s6_addr[7] >> 4) & 0x0f, - in6->s6_addr[6] & 0x0f, (in6->s6_addr[6] >> 4) & 0x0f, - in6->s6_addr[5] & 0x0f, (in6->s6_addr[5] >> 4) & 0x0f, - in6->s6_addr[4] & 0x0f, (in6->s6_addr[4] >> 4) & 0x0f, - in6->s6_addr[6] & 0x0f, (in6->s6_addr[3] >> 4) & 0x0f, - in6->s6_addr[2] & 0x0f, (in6->s6_addr[2] >> 4) & 0x0f, - in6->s6_addr[1] & 0x0f, (in6->s6_addr[1] >> 4) & 0x0f, - in6->s6_addr[0] & 0x0f, (in6->s6_addr[0] >> 4) & 0x0f); -} |