Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
Archivo: nsupdate.c Proyecto: aosm/bind
/*
 * format of file read by nsupdate is kept the same as the log
 * file generated by updates, so that the log file can be fed
 * to nsupdate to reconstruct lost updates.
 * 
 * file is read on line at a time using fgets() rather than
 * one word at a time using getword() so that it is easy to
 * adapt nsupdate to read piped input from other scripts
 *
 * overloading of class/type has to be deferred to res_update()
 * because class is needed by res_update() to determined the
 * zone to which a resource record belongs
 */
int
main(int argc, char **argv) {
	FILE *fp = NULL;
	char buf[BUFSIZ], buf2[BUFSIZ];
	char dnbuf[MAXDNAME], data[MAXDATA];
	char *r_dname, *cp, *startp, *endp, *svstartp;
	char section[15], opcode[10];
	int i, c, n, n1, inside, lineno = 0, vc = 0,
		debug = 0, r_size, r_section, r_opcode,
		prompt = 0, ret = 0, stringtobin = 0;
	int16_t r_class, r_type;
	u_int32_t r_ttl;
	struct map *mp;
	ns_updrec *rrecp;
	ns_updque listuprec;
	extern int getopt();
	extern char *optarg;
	extern int optind, opterr, optopt;
	ns_tsig_key key;
	char *keyfile=NULL, *keyname=NULL;

	progname = argv[0];

	while ((c = getopt(argc, argv, "dsvk:n:")) != -1) {
		switch (c) {
		case 'v':
			vc = 1;
			break;
		case 'd':
			debug = 1;
			break;
		case 's':
			stringtobin = 1;
			break;
		case 'k': {
			/* -k keydir:keyname */
			char *colon;
   
			if ((colon=strchr(optarg, ':'))==NULL) {
				fprintf(stderr, "key option argument should be keydir:keyname\n");
				exit(1);
			}
			keyname=colon+1;
			keyfile=optarg;
			*colon='\0';
			break;
		}
		case 'n':
			keyname=optarg;
			break;
		default:
			usage();
		}
	}

	INIT_LIST(listuprec);

	if (keyfile) {
#ifdef PARSE_KEYFILE
		if ((fp=fopen(keyfile, "r"))==NULL) {
			perror("open keyfile");
			exit(1);
		}
		/* now read the header info from the file */
		if ((i=fread(buf, 1, BUFSIZ, fp)) < 5) {
			fclose(fp);
                	exit(1);
        	}
		fclose(fp);
		fp=NULL;

		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 private 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 ((argc - optind) == 0) {
	    /* no file specified, read from stdin */
	    ret = system("tty -s");
	    if (ret == 0) /* terminal */
		prompt = 1;
	    else /* stdin redirect from a file or a pipe */
		prompt = 0;
	} else {
	    /* file specified, open it */
	    /* XXX - currently accepts only one filename */
	    if ((fp = fopen(argv[optind], "r")) == NULL) {
		fprintf(stderr, "error opening file: %s\n", argv[optind]);
		exit (1);
	    }
	}
	for (;;) {

	    inside = 1;
	    if (prompt)
		fprintf(stdout, "> ");
	    if (!fp)
		cp = fgets(buf, sizeof buf, stdin);
	    else
	        cp = fgets(buf, sizeof buf, fp);
	    if (cp == NULL) /* EOF */
		break;
	    lineno++;

	    /* get rid of the trailing newline */
	    n = strlen(buf);
	    buf[--n] = '\0';
 
	    startp = cp;
	    endp = strchr(cp, ';');
	    if (endp != NULL)
		endp--;
	    else
		endp = cp + n - 1;

	    /* verify section name */
	    if (!getword_str(section, sizeof section, &startp, endp)) {
		/* empty line */
		inside = 0;
	    }
	    if (inside) {
		/* inside the same update packet,
		 * continue accumulating records */
		r_section = -1;
		n1 = strlen(section);
		if (section[n1-1] == ':')
		    section[--n1] = '\0';
		for (mp = section_strs; mp < section_strs+M_SECTION_CNT; mp++)
		    if (!strcasecmp(section, mp->token)) {
			r_section = mp->val;
			break;
		    }
		if (r_section == -1) {
		    fprintf(stderr, "incorrect section name: %s\n", section);
		    exit (1);
		}
		if (r_section == S_ZONE) {
		    fprintf(stderr, "section ZONE not permitted\n");
		    exit (1);
		}
		/* read operation code */
		if (!getword_str(opcode, sizeof opcode, &startp, endp)) {
			fprintf(stderr, "failed to read operation code\n");
			exit (1);
		}
		r_opcode = -1;
		if (opcode[0] == '{') {
		    n1 = strlen(opcode);
		    for (i = 0; i < n1; i++)
			opcode[i] = opcode[i+1];
		    if (opcode[n1-2] == '}')
			opcode[n1-2] = '\0';
		}
		for (mp = opcode_strs; mp < opcode_strs+M_OPCODE_CNT; mp++) {
		    if (!strcasecmp(opcode, mp->token)) {
			r_opcode = mp->val;
			break;
		    }
		}
		if (r_opcode == -1) {
		    fprintf(stderr, "incorrect operation code: %s\n", opcode);
		    exit (1);
		}
		/* read owner's domain name */
		if (!getword_str(dnbuf, sizeof dnbuf, &startp, endp)) {
		    fprintf(stderr, "failed to read owner name\n");
		    exit (1);
		}
		r_dname = dnbuf;
		r_ttl = (r_opcode == ADD) ? (~0U) : 0;
		r_type = -1;
		r_class = C_IN; /* default to IN */
		r_size = 0;

		(void) getword_str(buf2, sizeof buf2, &startp, endp);

		if (isdigit(buf2[0])) { /* ttl */
		    r_ttl = strtoul(buf2, 0, 10);
		    if (errno == ERANGE && r_ttl == ULONG_MAX) {
			fprintf(stderr, "oversized ttl: %s\n", buf2);
			exit (1);
		    }
		    (void) getword_str(buf2, sizeof buf2, &startp, endp);
		}

		if (buf2[0]) { /* possibly class */
		    for (mp = class_strs; mp < class_strs+M_CLASS_CNT; mp++) {
			if (!strcasecmp(buf2, mp->token)) {
			    r_class = mp->val;
			    (void) getword_str(buf2, sizeof buf2, &startp, endp);
			    break;
			}
		    }
		}
		/*
		 * type and rdata field may or may not be required depending
		 * on the section and operation
		 */
		switch (r_section) {
		case S_PREREQ:
		    if (r_ttl) {
			fprintf(stderr, "nonzero ttl in prereq section: %lu\n",
				(u_long)r_ttl);
			r_ttl = 0;
		    }
		    switch (r_opcode) {
		    case NXDOMAIN:
		    case YXDOMAIN:
			if (buf2[0]) {
			    fprintf (stderr, "invalid field: %s, ignored\n",
				     buf2);
			    exit (1);
			}
			break;
		    case NXRRSET:
		    case YXRRSET:
			if (buf2[0])
			    for (mp = type_strs; mp < type_strs+M_TYPE_CNT; mp++)
				if (!strcasecmp(buf2, mp->token)) {
				    r_type = mp->val;
				    break;
				}
			if (r_type == -1) {
			    fprintf (stderr, "invalid type for RRset: %s\n",
				     buf2);
			    exit (1);
			}
			if (r_opcode == NXRRSET)
			    break;
			/*
			 * for RRset exists (value dependent) case,
			 * nonempty rdata field will be present.
			 * simply copy the whole string now and let
			 * res_update() interpret the various fields
			 * depending on type
			 */
			cp = startp;
			while (cp <= endp && isspace(*cp))
			    cp++;
			r_size = endp - cp + 1;
			break;
		    default:
			fprintf (stderr,
				 "unknown operation in prereq section\"%s\"\n",
				 opcode);
			exit (1);
		    }
		    break;
		case S_UPDATE:
		    switch (r_opcode) {
		    case DELETE:
			r_ttl = 0;
			r_type = T_ANY;
			/* read type, if specified */
			if (buf2[0])
			    for (mp = type_strs; mp < type_strs+M_TYPE_CNT; mp++)
				if (!strcasecmp(buf2, mp->token)) {
				    r_type = mp->val;
				    svstartp = startp;
				    (void) getword_str(buf2, sizeof buf2,
						       &startp, endp);
				    if (buf2[0]) /* unget preference */
					startp = svstartp;
				    break;
				}
			/* read rdata portion, if specified */
			cp = startp;
			while (cp <= endp && isspace(*cp))
			    cp++;
			r_size = endp - cp + 1;
			break;
		    case ADD:
			if (r_ttl == ~0U) {
			    fprintf (stderr,
		"ttl must be specified for record to be added: %s\n", buf);
			    exit (1);
			}
			/* read type */
			if (buf2[0])
			    for (mp = type_strs; mp < type_strs+M_TYPE_CNT; mp++)
				if (!strcasecmp(buf2, mp->token)) {
				    r_type = mp->val;
				    break;
				}
			if (r_type == -1) {
			    fprintf(stderr,
		"invalid type for record to be added: %s\n", buf2);
			    exit (1);
			}
			/* read rdata portion */
			cp = startp;
			while (cp < endp && isspace(*cp))
			    cp++;
			r_size = endp - cp + 1;
			if (r_size <= 0) {
			    fprintf(stderr,
		"nonempty rdata field needed to add the record at line %d\n",
				    lineno);
			    exit (1);
			}
			break;
		    default:
			fprintf(stderr,
		"unknown operation in update section \"%s\"\n", opcode);
			exit (1);
		    }
		    break;
		default:
		    fprintf(stderr,
			    "unknown section identifier \"%s\"\n", section);
		    exit (1);
		}

		if ( !(rrecp = res_mkupdrec(r_section, r_dname, r_class,
					    r_type, r_ttl)) ||
		     (r_size > 0 && !(rrecp->r_data = (u_char *)malloc(r_size))) ) {
			if (rrecp)
				res_freeupdrec(rrecp);
			fprintf(stderr, "saverrec error\n");
			exit (1);
		}
        if (stringtobin) {
             switch(r_opcode)  {
             case T_HINFO:
                  if (!getcharstring(buf,(char *)data,2,2,lineno))
                       exit(1);
                  cp = data;
                  break;
             case T_ISDN:
                  if (!getcharstring(buf,(char *)data,1,2,lineno))
                       exit(1);
                  cp = data;
                  break;
             case T_TXT:
                  if (!getcharstring(buf,(char *)data,1,0,lineno))
                       exit(1);
                  cp = data;
                  break;
             case T_X25:
                  if (!getcharstring(buf,(char *)data,1,1,lineno))
                       exit(1);
                  cp = data;
                  break;
             default:
		  break;
             }
        }
		rrecp->r_opcode = r_opcode;
		rrecp->r_size = r_size;
		(void) strncpy((char *)rrecp->r_data, cp, r_size);
		APPEND(listuprec, rrecp, r_link);
	    } else { /* end of an update packet */
		(void) res_ninit(&res);
		if (vc)
		    res.options |= RES_USEVC | RES_STAYOPEN;
		if (debug)
		    res.options |= RES_DEBUG;
		if (!EMPTY(listuprec)) {
			n = res_nupdate(&res, HEAD(listuprec),
					keyfile != NULL ? &key : NULL);
			if (n < 0)
				fprintf(stderr, "failed update packet\n");
			while (!EMPTY(listuprec)) {
				ns_updrec *tmprrecp = HEAD(listuprec);

				UNLINK(listuprec, tmprrecp, r_link);
				if (tmprrecp->r_size != 0)
					free((char *)tmprrecp->r_data);
				res_freeupdrec(tmprrecp);
			}
		}
	    }
	} /* for */
	return (0);
}