示例#1
0
int
res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
	ns_updrec *rrecp;
	u_char answer[PACKETSZ];
	u_char *packet;
	struct zonegrp *zptr, tgrp;
	LIST(struct zonegrp) zgrps;
	int nzones = 0, nscount = 0, n;
	union res_sockaddr_union nsaddrs[MAXNS];

	packet = malloc(NS_MAXMSG);
	if (packet == NULL) {
		DPRINTF(("malloc failed"));
		return (0);
	}
	/* Thread all of the updates onto a list of groups. */
	INIT_LIST(zgrps);
	memset(&tgrp, 0, sizeof (tgrp));
	for (rrecp = rrecp_in; rrecp;
	     rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
		int nscnt;
		/* Find the origin for it if there is one. */
		tgrp.z_class = rrecp->r_class;
		nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
					 RES_EXHAUSTIVE, tgrp.z_origin,
					 sizeof tgrp.z_origin, 
					 tgrp.z_nsaddrs, MAXNS);
		if (nscnt <= 0) {
			DPRINTF(("res_findzonecut failed (%d)", nscnt));
			goto done;
		}
		tgrp.z_nscount = nscnt;
		/* Find the group for it if there is one. */
		for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
			if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
			    tgrp.z_class == zptr->z_class)
				break;
		/* Make a group for it if there isn't one. */
		if (zptr == NULL) {
			zptr = malloc(sizeof *zptr);
			if (zptr == NULL) {
				DPRINTF(("malloc failed"));
				goto done;
			}
			*zptr = tgrp;
			zptr->z_flags = 0;
			INIT_LINK(zptr, z_link);
			INIT_LIST(zptr->z_rrlist);
			APPEND(zgrps, zptr, z_link);
		}
		/* Thread this rrecp onto the right group. */
		APPEND(zptr->z_rrlist, rrecp, r_glink);
	}

	for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
		/* Construct zone section and prepend it. */
		rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
				     zptr->z_class, ns_t_soa, 0);
		if (rrecp == NULL) {
			DPRINTF(("res_mkupdrec failed"));
			goto done;
		}
		PREPEND(zptr->z_rrlist, rrecp, r_glink);
		zptr->z_flags |= ZG_F_ZONESECTADDED;

		/* Marshall the update message. */
		n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
				  packet, NS_MAXMSG);
		DPRINTF(("res_mkupdate -> %d", n));
		if (n < 0)
			goto done;

		/* Temporarily replace the resolver's nameserver set. */
		nscount = res_getservers(statp, nsaddrs, MAXNS);
		res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);

		/* Send the update and remember the result. */
		if (key != NULL)
			n = res_nsendsigned(statp, packet, n, key,
					    answer, sizeof answer);
		else
			n = res_nsend(statp, packet, n, answer, sizeof answer);
		if (n < 0) {
			DPRINTF(("res_nsend: send error, n=%d (%s)\n",
				 n, strerror(errno)));
			goto done;
		}
		if (((HEADER *)answer)->rcode == NOERROR)
			nzones++;

		/* Restore resolver's nameserver set. */
		res_setservers(statp, nsaddrs, nscount);
		nscount = 0;
	}
 done:
	while (!EMPTY(zgrps)) {
		zptr = HEAD(zgrps);
		if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
			res_freeupdrec(HEAD(zptr->z_rrlist));
		UNLINK(zgrps, zptr, z_link);
		free(zptr);
	}
	if (nscount != 0)
		res_setservers(statp, nsaddrs, nscount);

	free(packet);
	return (nzones);
}
示例#2
0
isc_result_t
res_nupdate(res_state statp, ns_updrec *rrecp_in) {
	ns_updrec *rrecp;
	double answer[PACKETSZ / sizeof (double)];
	double packet[2*PACKETSZ / sizeof (double)];
	struct zonegrp *zptr, tgrp;
	int nscount = 0;
	unsigned n;
	unsigned rval;
	struct sockaddr_in nsaddrs[MAXNS];
	ns_tsig_key *key;
	void *zcookie = 0;
	void *zcookp = &zcookie;
	isc_result_t rcode;

      again:
	/* Make sure all the updates are in the same zone, and find out
	   what zone they are in. */
	zptr = NULL;
	for (rrecp = rrecp_in; rrecp; rrecp = ISC_LIST_NEXT(rrecp, r_link)) {
		/* Find the origin for it if there is one. */
		tgrp.z_class = rrecp->r_class;
		rcode = res_findzonecut(statp, rrecp->r_dname, tgrp.z_class,
					RES_EXHAUSTIVE,
					tgrp.z_origin,
					sizeof tgrp.z_origin,
					tgrp.z_nsaddrs, MAXNS, &tgrp.z_nscount,
					zcookp);
		if (rcode != ISC_R_SUCCESS)
			goto done;
		if (tgrp.z_nscount <= 0) {
			rcode = ISC_R_NOTZONE;
			goto done;
		}
		/* Make a group for it if there isn't one. */
		if (zptr == NULL) {
			zptr = malloc(sizeof *zptr);
			if (zptr == NULL) {
				rcode = ISC_R_NOMEMORY;
				goto done;
			}
			*zptr = tgrp;
			zptr->z_flags = 0;
			ISC_LIST_INIT(zptr->z_rrlist);
		} else if (ns_samename(tgrp.z_origin, zptr->z_origin) == 0 ||
			   tgrp.z_class != zptr->z_class) {
			/* Some of the records are in different zones. */
			rcode = ISC_R_CROSSZONE;
			goto done;
		}
		/* Thread this rrecp onto the zone group. */
		ISC_LIST_APPEND(zptr->z_rrlist, rrecp, r_glink);
	}

	/* Construct zone section and prepend it. */
	rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
			     zptr->z_class, ns_t_soa, 0);
	if (rrecp == NULL) {
		rcode = ISC_R_UNEXPECTED;
		goto done;
	}
	ISC_LIST_PREPEND(zptr->z_rrlist, rrecp, r_glink);
	zptr->z_flags |= ZG_F_ZONESECTADDED;

	/* Marshall the update message. */
	n = sizeof packet;
	rcode = res_nmkupdate(statp,
			      ISC_LIST_HEAD(zptr->z_rrlist), packet, &n);
	if (rcode != ISC_R_SUCCESS)
		goto done;

	/* Temporarily replace the resolver's nameserver set. */
	nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount);
	statp->nscount = nsprom(statp->nsaddr_list,
				zptr->z_nsaddrs, zptr->z_nscount);

	/* Send the update and remember the result. */
	key = (ns_tsig_key *)0;
	rcode = find_tsig_key (&key, zptr->z_origin, zcookie);
	if (rcode == ISC_R_SUCCESS) {
		rcode = res_nsendsigned(statp, packet, n, key,
					answer, sizeof answer, &rval);
		tkey_free (&key);
	} else if (rcode == ISC_R_NOTFOUND || rcode == ISC_R_KEY_UNKNOWN) {
		rcode = res_nsend(statp, packet, n,
				  answer, sizeof answer, &rval);
	}
	if (rcode != ISC_R_SUCCESS)
		goto undone;

	rcode = ns_rcode_to_isc (((HEADER *)answer)->rcode);
	if (zcookie && rcode == ISC_R_BADSIG) {
		repudiate_zone (&zcookie);
	}

 undone:
	/* Restore resolver's nameserver set. */
	statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount);
	nscount = 0;
 done:
	if (zptr) {
		if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
			res_freeupdrec(ISC_LIST_HEAD(zptr->z_rrlist));
		free(zptr);
	}

	/* If the update failed because we used a cached zone and it
	   didn't work, try it again without the cached zone. */
	if (zcookp && (rcode == ISC_R_NOTZONE || rcode == ISC_R_BADSIG)) {
		zcookp = 0;
		goto again;
	}

	if (zcookie)
		forget_zone (&zcookie);
	return rcode;
}
示例#3
0
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_)
	union {
		HEADER u;
		u_char b[NS_MAXMSG];
	} answer;
	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;
	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;
	const char *pingfmt = NULL;

	UNUSED(argc);

	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*/;

	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++;
	}

	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 (libbind %d) <<>> ",
			VSTRING, __RES);
		argv = args;
		/* argc = ax - args; */
/*
 * More cmd-line options than anyone should ever have to
 * deal with ....
 */
		while (*(++argv) != NULL && **argv != '\0') { 
			if (strlen(cmd) + strlen(*argv) + 2 > sizeof (cmd)) {
				fprintf(stderr,
				   "Argument too large for input buffer\n");
				exit(1);
			}
			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);
						pingfmt =
							"%s %s 56 3 | %s -3";
					} else {
						strcpy(pingstr, DIG_PING);
						pingfmt = DIG_PINGFMT;
					}
					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",
			       (unsigned long)res.pfcode,
			       (unsigned long)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);

		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".
 */

		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++].sin.sin_port =
							port;
						break;
					}
				}
				if (nscount != 0)
					res_setservers(&res, u, nscount);
				freeaddrinfo(answer);
			} else {
				res = res_t;
				fflush(stdout);
				fprintf(stderr,
		"; Bad server: %s -- using default server and timer opts\n",
						srv);
				fflush(stderr);
				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 < 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) {
					exectime = time(NULL);
					printf(";; FROM: %s to SERVER: %s\n",
					       myhostname,
					       p_sockun(u[i], ubuf,
							sizeof(ubuf)));
					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.b, sizeof(answer.b));
		else
			n = res_nsend(&res, packet, n,
				      answer.b, sizeof(answer.b));
		if ((bytes_in = n) < 0) {
			fflush(stdout);
			n = 0 - n;
			if (keyfile)
				strcpy(msg, ";; res_nsendsigned");
			else
				strcpy(msg, ";; res_nsend");
			perror(msg);
			fflush(stderr);

			if (!dofile) {
				if (eecode)
					exit(eecode);
				else
					exit(9);
			}
		}
		(void) gettimeofday(&end_time, NULL);

		if (res.pfcode & RES_PRF_STATS) {
			union res_sockaddr_union u[MAXNS];

			(void) res_getservers(&res, u, MAXNS);
			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,
			       p_sockun(u[RES_GETLAST(res)],
					ubuf, sizeof(ubuf)));
			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 && srv != NULL) {
			sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL);
			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);
}