diff options
Diffstat (limited to 'contrib/bind/bin/dig/dig.c')
-rw-r--r-- | contrib/bind/bin/dig/dig.c | 707 |
1 files changed, 549 insertions, 158 deletions
diff --git a/contrib/bind/bin/dig/dig.c b/contrib/bind/bin/dig/dig.c index 7db8ba0..4e75c13 100644 --- a/contrib/bind/bin/dig/dig.c +++ b/contrib/bind/bin/dig/dig.c @@ -1,5 +1,5 @@ #ifndef lint -static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; +static const char rcsid[] = "$Id: dig.c,v 8.36 1999/11/05 05:05:14 vixie Exp $"; #endif /* @@ -56,7 +56,7 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; */ /* - * Copyright (c) 1996 by Internet Software Consortium + * 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 @@ -159,11 +159,14 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; #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 <ctype.h> #include <errno.h> #include <fcntl.h> @@ -179,12 +182,10 @@ static char rcsid[] = "$Id: dig.c,v 8.19 1998/03/19 19:30:18 halley Exp $"; #include "../nslookup/res.h" -extern char *_res_resultcodes[]; /* res_debug.c */ - /* Global. */ -#define VERSION 81 -#define VSTRING "8.1" +#define VERSION 82 +#define VSTRING "8.2" #define PRF_DEF 0x2ff9 #define PRF_MIN 0xA930 @@ -194,20 +195,21 @@ extern char *_res_resultcodes[]; /* res_debug.c */ #define MAXHOSTNAMELEN 256 #endif -int eecode = 0; - -FILE *qfp; -int sockFD; - #define SAVEENV "DiG.env" #define DIG_MAXARGS 30 +static int eecode = 0; +static FILE * qfp; +static int sockFD; static char *defsrv, *srvmsg; static char defbuf[40] = "default -- "; static char srvbuf[60]; static char myhostname[MAXHOSTNAMELEN]; +static struct sockaddr_in myaddress; +static u_int32_t ixfr_serial; /* stuff for nslookup modules */ +struct __res_state res; FILE *filePtr; jmp_buf env; HostInfo *defaultPtr = NULL; @@ -228,7 +230,8 @@ static void Usage(void); static int SetOption(const char *); static void res_re_init(void); static int xstrtonum(char *); -static int printZone(const char *, const struct sockaddr_in *); +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); @@ -246,15 +249,17 @@ main(int argc, char **argv) { HEADER header_; u_char packet_[PACKETSZ]; } packet_; -#define packet (packet_.packet_) - u_char answer[8*1024]; +#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; - struct timeval exectime, tv1, tv2, start_time, end_time, query_time; + time_t exectime; + struct timeval tv1, tv2, start_time, end_time, query_time; char *srv; int anyflag = 0; @@ -262,7 +267,7 @@ main(int argc, char **argv) { int tmp; int qtypeSet; int addrflag = 0; - int zone = 0; + ns_type xfr = ns_t_invalid; int bytes_out, bytes_in; char cmd[256]; @@ -279,13 +284,22 @@ main(int argc, char **argv) { struct __res_state res_x, res_t; char *pp; - res_init(); - _res.pfcode = PRF_DEF; + 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)); - defsrv = strcat(defbuf, inet_ntoa(_res.nsaddr.sin_addr)); - res_x = _res; +#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*/; + defsrv = strcat(defbuf, inet_ntoa(res.nsaddr.sin_addr)); + res_x = res; /* * If LOCALDEF in environment, should point to file @@ -298,7 +312,7 @@ main(int argc, char **argv) { ((fp = open(SAVEENV, O_RDONLY)) > 0)) { read(fp, (char *)&res_x, (sizeof res_x)); close(fp); - _res = res_x; + res = res_x; } /* * Check for batch-mode DiG; also pre-scan for 'help'. @@ -332,7 +346,7 @@ main(int argc, char **argv) { vtmp++; } - _res.id = 1; + res.id = 1; gettimeofday(&tv1, NULL); /* @@ -352,7 +366,7 @@ main(int argc, char **argv) { */ if (sticky) { printf(";; (using sticky settings)\n"); - _res = res_x; + res = res_x; } /* @@ -363,7 +377,7 @@ main(int argc, char **argv) { /* defaults */ queryType = ns_t_ns; queryClass = ns_c_in; - zone = 0; + xfr = ns_t_invalid; *pingstr = 0; srv = NULL; @@ -387,7 +401,10 @@ main(int argc, char **argv) { SetOption(*argv+1); continue; } - + if (**argv == '=') { + ixfr_serial = strtoul(*argv+1, NULL, 0); + continue; + } if (strncmp(*argv, "-nost", 5) == 0) { sticky = 0; continue; @@ -460,15 +477,57 @@ main(int argc, char **argv) { strcat(domain, addrc); strcat(domain, ".in-addr.arpa."); break; - case 'p': port = htons(atoi(*++argv)); break; + case 'p': + if (argv[0][2] != '\0') + port = ntohs(atoi(argv[0]+2)); + else + port = htons(atoi(*++argv)); + break; case 'P': if (argv[0][2] != '\0') - strcpy(pingstr,&argv[0][2]); + strcpy(pingstr, argv[0]+2); else - strcpy(pingstr,"ping -s"); + strcpy(pingstr, "ping -s"); break; case 'n': - _res.ndots = atoi(&argv[0][2]); + if (argv[0][2] != '\0') + res.ndots = atoi(argv[0]+2); + else + res.ndots = atoi(*++argv); + break; + case 'b': { + char *a, *p; + + if (argv[0][2] != '\0') + a = argv[0]+2; + else + a = *++argv; + if ((p = strchr(a, ':')) != NULL) { + *p++ = '\0'; + myaddress.sin_port = + ntohs(atoi(p)); + } + if (!inet_aton(a,&myaddress.sin_addr)){ + fprintf(stderr, + ";; bad -b addr\n"); + exit(1); + } + } + case 'k': + /* -k keydir:keyname */ + + if (argv[0][2] != '\0') + keyfile = argv[0]+2; + 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; @@ -479,9 +538,12 @@ main(int argc, char **argv) { queryClass = C_ANY; continue; } - if (T_AXFR == tmp) { - _res.pfcode = PRF_ZONE; - zone++; + 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++; @@ -495,16 +557,127 @@ main(int argc, char **argv) { } } /* while argv remains */ - if (_res.pfcode & 0x80000) + /* 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); + 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; + res_x = res; envset = 0; } @@ -523,13 +696,13 @@ main(int argc, char **argv) { ((fp = open(SAVEENV, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) { - write(fp, (char *)&_res, (sizeof _res)); + write(fp, (char *)&res, (sizeof res)); close(fp); } envsave = 0; } - if (_res.pfcode & RES_PRF_CMD) + if (res.pfcode & RES_PRF_CMD) printf("%s\n", cmd); addrflag = anyflag = 0; @@ -549,16 +722,16 @@ main(int argc, char **argv) { struct in_addr addr; if (inet_aton(srv, &addr)) { - _res.nscount = 1; - _res.nsaddr.sin_addr = 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(); + res_t = res; + res_ninit(&res); + res.pfcode = 0; + res.options = RES_DEFAULT; hp = gethostbyname(srv); - _res = res_t; + res = res_t; if (hp == NULL || hp->h_addr_list == NULL || *hp->h_addr_list == NULL) { @@ -572,54 +745,57 @@ main(int argc, char **argv) { } else { u_int32_t **addr; - _res.nscount = 0; + res.nscount = 0; for (addr = (u_int32_t**)hp->h_addr_list; - *addr && (_res.nscount < MAXNS); + *addr && (res.nscount < MAXNS); addr++) { - _res.nsaddr_list[ - _res.nscount++ + res.nsaddr_list[ + res.nscount++ ].sin_addr.s_addr = **addr; } srvmsg = strcat(srvbuf,srv); strcat(srvbuf, " "); strcat(srvmsg, - inet_ntoa(_res.nsaddr.sin_addr) - ); + inet_ntoa(res.nsaddr.sin_addr)); } } printf("; (%d server%s found)\n", - _res.nscount, (_res.nscount==1)?"":"s"); - _res.id += _res.retry; + 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; + 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; + res.id += res.retry; } - if (zone) { + if (ns_t_xfr_p(xfr)) { 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; - time_t t; + for (i = 0; i < res.nscount; i++) { + int x; + if (keyfile) + x = printZone(xfr, domain, + &res.nsaddr_list[i], + &key); + else + x = printZone(xfr, domain, + &res.nsaddr_list[i], + NULL); + if (res.pfcode & RES_PRF_STATS) { + exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, - inet_ntoa(_res.nsaddr_list[i] + inet_ntoa(res.nsaddr_list[i] .sin_addr)); - gettimeofday(&exectime, NULL); - t = (time_t)exectime.tv_sec; - printf(";; WHEN: %s", ctime(&t)); + printf(";; WHEN: %s", ctime(&exectime)); } if (!x) break; /* success */ @@ -633,25 +809,54 @@ main(int argc, char **argv) { qtypeSet++; } - bytes_out = n = res_mkquery(QUERY, domain, - queryClass, queryType, - NULL, 0, NULL, - packet, sizeof packet); + bytes_out = n = res_nmkquery(&res, QUERY, domain, + queryClass, queryType, + NULL, 0, NULL, + packet, sizeof packet); if (n < 0) { fflush(stderr); - printf(";; res_mkquery: buffer too small\n\n"); + printf(";; res_nmkquery: buffer too small\n\n"); 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; + }; + eecode = 0; - if (_res.pfcode & RES_PRF_HEAD1) - __fp_resstat(NULL, stdout); + if (res.pfcode & RES_PRF_HEAD1) + fp_resstat(&res, stdout); (void) gettimeofday(&start_time, NULL); - if ((bytes_in = n = res_send(packet, n, - answer, sizeof answer)) < 0) { + 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; - strcat(msg,";; res_send to server "); + if (keyfile) + strcat(msg,";; res_nsendsigned to server "); + else + strcat(msg,";; res_nsend to server "); strcat(msg,srvmsg); perror(msg); fflush(stderr); @@ -665,18 +870,17 @@ main(int argc, char **argv) { } (void) gettimeofday(&end_time, NULL); - if (_res.pfcode & RES_PRF_STATS) { + if (res.pfcode & RES_PRF_STATS) { time_t t; 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); - gettimeofday(&exectime,NULL); - t = (time_t)exectime.tv_sec; - printf(";; WHEN: %s", ctime(&t)); + printf(";; WHEN: %s", ctime(&exectime)); printf(";; MSG SIZE sent: %d rcvd: %d\n", bytes_out, bytes_in); } @@ -723,9 +927,11 @@ where: server,\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\ + -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); @@ -739,6 +945,8 @@ where: server,\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.36 1999/11/05 05:05:14 vixie Exp $\n\ ", stderr); } @@ -747,128 +955,139 @@ SetOption(const char *string) { char option[NAME_LEN], type[NAME_LEN], *ptr; int i; - i = sscanf(string, " %s", option); - if (i != 1) { - fprintf(stderr, ";*** Invalid option: %s\n", option); - return (ERROR); + 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; + res.options |= RES_AAONLY; } else if (strncmp(option, "noaa", 4) == 0) { - _res.options &= ~RES_AAONLY; + res.options &= ~RES_AAONLY; } else if (strncmp(option, "deb", 3) == 0) { /* debug */ - _res.options |= RES_DEBUG; + res.options |= RES_DEBUG; } else if (strncmp(option, "nodeb", 5) == 0) { - _res.options &= ~(RES_DEBUG | RES_DEBUG2); + res.options &= ~(RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "ko", 2) == 0) { /* keepopen */ - _res.options |= (RES_STAYOPEN | RES_USEVC); + res.options |= (RES_STAYOPEN | RES_USEVC); } else if (strncmp(option, "noko", 4) == 0) { - _res.options &= ~RES_STAYOPEN; + res.options &= ~RES_STAYOPEN; } else if (strncmp(option, "d2", 2) == 0) { /* d2 (more debug) */ - _res.options |= (RES_DEBUG | RES_DEBUG2); + res.options |= (RES_DEBUG | RES_DEBUG2); } else if (strncmp(option, "nod2", 4) == 0) { - _res.options &= ~RES_DEBUG2; + res.options &= ~RES_DEBUG2; } else if (strncmp(option, "def", 3) == 0) { /* defname */ - _res.options |= RES_DEFNAMES; + res.options |= RES_DEFNAMES; } else if (strncmp(option, "nodef", 5) == 0) { - _res.options &= ~RES_DEFNAMES; + res.options &= ~RES_DEFNAMES; } else if (strncmp(option, "sea", 3) == 0) { /* search list */ - _res.options |= RES_DNSRCH; + res.options |= RES_DNSRCH; } else if (strncmp(option, "nosea", 5) == 0) { - _res.options &= ~RES_DNSRCH; + res.options &= ~RES_DNSRCH; } else if (strncmp(option, "do", 2) == 0) { /* domain */ ptr = strchr(option, '='); - if (ptr != NULL) - sscanf(++ptr, "%s", _res.defdname); + 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); + sscanf(++ptr, "%d", &res.retrans); } else if (strncmp(option, "ret", 3) == 0) { /* retry */ ptr = strchr(option, '='); if (ptr != NULL) - sscanf(++ptr, "%d", &_res.retry); + sscanf(++ptr, "%d", &res.retry); } else if (strncmp(option, "i", 1) == 0) { /* ignore */ - _res.options |= RES_IGNTC; + res.options |= RES_IGNTC; } else if (strncmp(option, "noi", 3) == 0) { - _res.options &= ~RES_IGNTC; + res.options &= ~RES_IGNTC; } else if (strncmp(option, "pr", 2) == 0) { /* primary */ - _res.options |= RES_PRIMARY; + res.options |= RES_PRIMARY; } else if (strncmp(option, "nop", 3) == 0) { - _res.options &= ~RES_PRIMARY; + res.options &= ~RES_PRIMARY; } else if (strncmp(option, "rec", 3) == 0) { /* recurse */ - _res.options |= RES_RECURSE; + res.options |= RES_RECURSE; } else if (strncmp(option, "norec", 5) == 0) { - _res.options &= ~RES_RECURSE; + res.options &= ~RES_RECURSE; } else if (strncmp(option, "v", 1) == 0) { /* vc */ - _res.options |= RES_USEVC; + res.options |= RES_USEVC; } else if (strncmp(option, "nov", 3) == 0) { - _res.options &= ~RES_USEVC; + res.options &= ~RES_USEVC; } else if (strncmp(option, "pfset", 5) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode = xstrtonum(++ptr); + res.pfcode = xstrtonum(++ptr); } else if (strncmp(option, "pfand", 5) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode = _res.pfcode & xstrtonum(++ptr); + res.pfcode = res.pfcode & xstrtonum(++ptr); } else if (strncmp(option, "pfor", 4) == 0) { ptr = strchr(option, '='); if (ptr != NULL) - _res.pfcode |= xstrtonum(++ptr); + res.pfcode |= xstrtonum(++ptr); } else if (strncmp(option, "pfmin", 5) == 0) { - _res.pfcode = PRF_MIN; + res.pfcode = PRF_MIN; } else if (strncmp(option, "pfdef", 5) == 0) { - _res.pfcode = PRF_DEF; + res.pfcode = PRF_DEF; } else if (strncmp(option, "an", 2) == 0) { /* answer section */ - _res.pfcode |= RES_PRF_ANS; + res.pfcode |= RES_PRF_ANS; } else if (strncmp(option, "noan", 4) == 0) { - _res.pfcode &= ~RES_PRF_ANS; + res.pfcode &= ~RES_PRF_ANS; } else if (strncmp(option, "qu", 2) == 0) { /* question section */ - _res.pfcode |= RES_PRF_QUES; + res.pfcode |= RES_PRF_QUES; } else if (strncmp(option, "noqu", 4) == 0) { - _res.pfcode &= ~RES_PRF_QUES; + res.pfcode &= ~RES_PRF_QUES; } else if (strncmp(option, "au", 2) == 0) { /* authority section */ - _res.pfcode |= RES_PRF_AUTH; + res.pfcode |= RES_PRF_AUTH; } else if (strncmp(option, "noau", 4) == 0) { - _res.pfcode &= ~RES_PRF_AUTH; + res.pfcode &= ~RES_PRF_AUTH; } else if (strncmp(option, "ad", 2) == 0) { /* addition section */ - _res.pfcode |= RES_PRF_ADD; + res.pfcode |= RES_PRF_ADD; } else if (strncmp(option, "noad", 4) == 0) { - _res.pfcode &= ~RES_PRF_ADD; + res.pfcode &= ~RES_PRF_ADD; } else if (strncmp(option, "tt", 2) == 0) { /* TTL & ID */ - _res.pfcode |= RES_PRF_TTLID; + res.pfcode |= RES_PRF_TTLID; } else if (strncmp(option, "nott", 4) == 0) { - _res.pfcode &= ~RES_PRF_TTLID; + res.pfcode &= ~RES_PRF_TTLID; } else if (strncmp(option, "he", 2) == 0) { /* head flags stats */ - _res.pfcode |= RES_PRF_HEAD2; + res.pfcode |= RES_PRF_HEAD2; } else if (strncmp(option, "nohe", 4) == 0) { - _res.pfcode &= ~RES_PRF_HEAD2; + res.pfcode &= ~RES_PRF_HEAD2; } else if (strncmp(option, "H", 1) == 0) { /* header all */ - _res.pfcode |= RES_PRF_HEADX; + res.pfcode |= RES_PRF_HEADX; } else if (strncmp(option, "noH", 3) == 0) { - _res.pfcode &= ~(RES_PRF_HEADX); + res.pfcode &= ~(RES_PRF_HEADX); } else if (strncmp(option, "qr", 2) == 0) { /* query */ - _res.pfcode |= RES_PRF_QUERY; + res.pfcode |= RES_PRF_QUERY; } else if (strncmp(option, "noqr", 4) == 0) { - _res.pfcode &= ~RES_PRF_QUERY; + res.pfcode &= ~RES_PRF_QUERY; } else if (strncmp(option, "rep", 3) == 0) { /* reply */ - _res.pfcode |= RES_PRF_REPLY; + res.pfcode |= RES_PRF_REPLY; } else if (strncmp(option, "norep", 5) == 0) { - _res.pfcode &= ~RES_PRF_REPLY; + res.pfcode &= ~RES_PRF_REPLY; } else if (strncmp(option, "cm", 2) == 0) { /* command line */ - _res.pfcode |= RES_PRF_CMD; + res.pfcode |= RES_PRF_CMD; } else if (strncmp(option, "nocm", 4) == 0) { - _res.pfcode &= ~RES_PRF_CMD; + res.pfcode &= ~RES_PRF_CMD; } else if (strncmp(option, "cl", 2) == 0) { /* class mnemonic */ - _res.pfcode |= RES_PRF_CLASS; + res.pfcode |= RES_PRF_CLASS; } else if (strncmp(option, "nocl", 4) == 0) { - _res.pfcode &= ~RES_PRF_CLASS; + res.pfcode &= ~RES_PRF_CLASS; } else if (strncmp(option, "st", 2) == 0) { /* stats*/ - _res.pfcode |= RES_PRF_STATS; + res.pfcode |= RES_PRF_STATS; } else if (strncmp(option, "nost", 4) == 0) { - _res.pfcode &= ~RES_PRF_STATS; + res.pfcode &= ~RES_PRF_STATS; } else { fprintf(stderr, "; *** Invalid option: %s\n", option); return (ERROR); @@ -881,22 +1100,22 @@ SetOption(const char *string) { * Force a reinitialization when the domain is changed. */ static void -res_re_init() -{ +res_re_init() { static char localdomain[] = "LOCALDOMAIN"; - long pfcode = _res.pfcode; - long ndots = _res.ndots; + u_long pfcode = res.pfcode, options = res.options; + unsigned ndots = res.ndots; 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); + 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_init(); - _res.pfcode = pfcode; - _res.ndots = ndots; + res_ninit(&res); + res.pfcode = pfcode; + res.options = options; + res.ndots = ndots; } /* @@ -947,7 +1166,9 @@ typedef union { } querybuf; static int -printZone(const char *zone, const struct sockaddr_in *sin) { +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; @@ -960,19 +1181,91 @@ printZone(const char *zone, const struct sockaddr_in *sin) { char dname[2][NS_MAXDNAME], file[NAME_LEN]; enum { NO_ERRORS, ERR_READING_LEN, ERR_READING_MSG, ERR_PRINTING } error = NO_ERRORS; + pid_t zpid; + u_char *newmsg; + int newmsglen; + ns_tcp_tsig_state tsig_state; + int tsig_ret; + + 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_mkquery(ns_o_query, zone, queryClass, ns_t_axfr, NULL, - 0, 0, buf.qb2, sizeof buf); + 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_mkquery failed\n"); + 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) { @@ -981,29 +1274,86 @@ printZone(const char *zone, const struct sockaddr_in *sin) { perror(";; socket"); return (e); } + 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, (struct sockaddr *)sin, sizeof *sin) < 0) { int e = errno; perror(";; connect"); (void) close(sockFD); sockFD = -1; - return e; + return (e); } /* * Send length & message for zone transfer */ - ns_put16(msglen, tmp); + ns_put16(newmsglen, tmp); if (write(sockFD, (char *)tmp, NS_INT16SZ) != NS_INT16SZ || - write(sockFD, (char *)&buf, msglen) != msglen) { + write(sockFD, (char *)newmsg, newmsglen) != newmsglen) { int e = errno; + if (key) + free (newmsg); perror(";; write"); (void) close(sockFD); sockFD = -1; return (e); } + /* + * 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; + if (key) + free (newmsg); + + perror(";; pipe"); + (void) close(sockFD); + sockFD = -1; + return (e); + } + zpid = vfork(); + if (zpid < 0) { + int e = errno; + if (key) + free (newmsg); + + 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]); + } + dname[0][0] = '\0'; for (done = 0; !done; (void)NULL) { /* @@ -1053,7 +1403,19 @@ printZone(const char *zone, const struct sockaddr_in *sin) { break; } - result = print_axfr(stdout, answer, cp - answer); + /* + * Verify the TSIG + */ + + if (key) { + tsig_ret = ns_verify_tcp(answer, &len, &tsig_state, 1); + if (tsig_ret == 0) + printf("; TSIG ok\n"); + else + printf("; TSIG invalid\n"); + } + + result = print_axfr(stdout, answer, len); if (result != 0) { error = ERR_PRINTING; break; @@ -1108,7 +1470,7 @@ printZone(const char *zone, const struct sockaddr_in *sin) { break; } if (type == T_SOA && soacnt++ && - !strcasecmp(dname[0], dname[1])) { + ns_samename(dname[0], dname[1]) == 1) { done++; break; } @@ -1122,6 +1484,35 @@ printZone(const char *zone, const struct sockaddr_in *sin) { (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", + pid, WEXITSTATUS(status), + WIFSIGNALED(status) ? WTERMSIG(status) : 0, + WCOREDUMP(status) ? 't' : 'f'); + } + + /* XXX This should probably happen sooner than here */ + if (key) + free (newmsg); + switch (error) { case NO_ERRORS: return (0); |