示例#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
文件: nsupdate.c 项目: 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);
}