Exemplo n.º 1
0
int
diff_read_file(namedb_type* db, nsd_options_t* opt, struct diff_log** log,
	size_t child_count)
{
	const char* filename = opt->difffile;
	FILE *df;
	uint32_t type, timestamp[2], curr_timestamp[2];
	struct diff_read_data* data = diff_read_data_create();
	off_t startpos;

	df = fopen(filename, "r");
	if(!df) {
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for reading: %s",
			filename, strerror(errno)));
		region_destroy(data->region);
		return 1;
	}

	/* check timestamp */
	curr_timestamp[0] = (uint32_t) db->diff_timestamp.tv_sec;
	curr_timestamp[1] = (uint32_t) db->diff_timestamp.tv_usec;

	if(!diff_read_32(df, &type)) {
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "difffile %s is empty",
			filename));
		db->diff_skip = 0;
		db->diff_pos = 0;
	}
	else if (!diff_read_32(df, &timestamp[0]) ||
		 !diff_read_32(df, &timestamp[1])) {
		log_msg(LOG_ERR, "difffile %s bad first part: no timestamp",
			filename);
		region_destroy(data->region);
		fclose(df);
		return 0;
	}
	else if (curr_timestamp[0] != timestamp[0] ||
		 curr_timestamp[1] != timestamp[1]) {
		/* new timestamp, no skipping */
		db->diff_timestamp.tv_sec = (time_t) timestamp[0];
		db->diff_timestamp.tv_usec = (suseconds_t) timestamp[1];

		if (db->diff_skip) {
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "new timestamp on "
				"difffile %s, restoring diff_skip and diff_pos "
				"[old timestamp: %u.%u; new timestamp: %u.%u]",
				filename, curr_timestamp[0], curr_timestamp[1],
				timestamp[0], timestamp[1]));
			db->diff_skip = 0;
			db->diff_pos = 0;
		}
	}

	/* Always seek, to diff_pos or to beginning of the file. */
	if (fseeko(df, 0, SEEK_SET)==-1) {
		log_msg(LOG_INFO, "could not fseeko file %s: %s.", filename,
				strerror(errno));
		region_destroy(data->region);
		fclose(df);
		return 0;
	}
	if(db->diff_skip) {
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skip diff file"));
		if(fseeko(df, db->diff_pos, SEEK_SET)==-1) {
			log_msg(LOG_INFO, "could not fseeko file %s: %s. "
					  "Reread from start.", filename,
				strerror(errno));
		}
	}

	startpos = ftello(df);
	if(startpos == -1) {
		log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
		region_destroy(data->region);
		fclose(df);
		return 0;
	}

	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "start of diff file read at pos %u",
		(uint32_t) db->diff_pos));
	while(diff_read_32(df, &type))
	{
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "iter loop"));

		/* read timestamp */
		if(!diff_read_32(df, &timestamp[0]) ||
			!diff_read_32(df, &timestamp[1])) {
			log_msg(LOG_INFO, "could not read timestamp: %s.",
				strerror(errno));
			region_destroy(data->region);
			fclose(df);
			return 0;
		}

		if(!read_process_part(db, df, type, opt, data, log,
			child_count, &startpos))
		{
			log_msg(LOG_INFO, "error processing diff file");
			region_destroy(data->region);
			fclose(df);
			return 0;
		}
		startpos = ftello(df);
		if(startpos == -1) {
			log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
			region_destroy(data->region);
			fclose(df);
			return 0;
		}
	}
	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "end of diff file read"));

	if(find_smallest_offset(data, &db->diff_pos)) {
		/* can skip to the first unused element */
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file"));
		db->diff_skip = 1;
	} else {
		/* all processed, can skip to here next time */
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file"));
		db->diff_skip = 1;
		db->diff_pos = ftello(df);
		if(db->diff_pos == -1) {
			log_msg(LOG_INFO, "could not ftello: %s.",
				strerror(errno));
			db->diff_skip = 0;
		}
	}

	region_destroy(data->region);
	fclose(df);
	return 1;
}
Exemplo n.º 2
0
/* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */
static int
apply_ixfr(namedb_type* db, FILE *in, const off_t* startpos,
	const char* zone, uint32_t serialno, nsd_options_t* opt,
	uint16_t id, uint32_t seq_nr, uint32_t seq_total,
	int* is_axfr, int* delete_mode, int* rr_count,
	size_t child_count)
{
	uint32_t filelen, msglen, pkttype, timestamp[2];
	int qcount, ancount, counter;
	buffer_type* packet;
	region_type* region;
	int i;
	uint16_t rrlen;
	const dname_type *dname_zone, *dname;
	zone_type* zone_db;
	domain_type* last_in_list;
	char file_zone_name[3072];
	uint32_t file_serial, file_seq_nr;
	uint16_t file_id;
	off_t mempos;

	memmove(&mempos, startpos, sizeof(off_t));
	if(fseeko(in, mempos, SEEK_SET) == -1) {
		log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno));
		return 0;
	}
	/* read ixfr packet RRs and apply to in memory db */

	if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_IXFR) {
		log_msg(LOG_ERR, "could not read type or wrong type");
		return 0;
	}
	if(!diff_read_32(in, &timestamp[0]) ||
	   !diff_read_32(in, &timestamp[1])) {
		log_msg(LOG_ERR, "could not read timestamp");
		return 0;
	}

	if(!diff_read_32(in, &filelen)) {
		log_msg(LOG_ERR, "could not read len");
		return 0;
	}

	/* read header */
	if(filelen < QHEADERSZ + sizeof(uint32_t)*3 + sizeof(uint16_t)) {
		log_msg(LOG_ERR, "msg too short");
		return 0;
	}

	region = region_create(xalloc, free);
	if(!region) {
		log_msg(LOG_ERR, "out of memory");
		return 0;
	}

	if(!diff_read_str(in, file_zone_name, sizeof(file_zone_name)) ||
		!diff_read_32(in, &file_serial) ||
		!diff_read_16(in, &file_id) ||
		!diff_read_32(in, &file_seq_nr))
	{
		log_msg(LOG_ERR, "could not part data");
		region_destroy(region);
		return 0;
	}

	if(strcmp(file_zone_name, zone) != 0 || serialno != file_serial ||
		id != file_id || seq_nr != file_seq_nr) {
		log_msg(LOG_ERR, "internal error: reading part with changed id");
		region_destroy(region);
		return 0;
	}
	msglen = filelen - sizeof(uint32_t)*3 - sizeof(uint16_t)
		- strlen(file_zone_name);
	packet = buffer_create(region, QIOBUFSZ);
	dname_zone = dname_parse(region, zone);
	zone_db = find_zone(db, dname_zone, opt, child_count);
	if(!zone_db) {
		log_msg(LOG_ERR, "no zone exists");
		region_destroy(region);
		/* break out and stop the IXFR, ignore it */
		return 2;
	}

	if(msglen > QIOBUFSZ) {
		log_msg(LOG_ERR, "msg too long");
		region_destroy(region);
		return 0;
	}
	buffer_clear(packet);
	if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
		log_msg(LOG_ERR, "short fread: %s", strerror(errno));
		region_destroy(region);
		return 0;
	}
	buffer_set_limit(packet, msglen);

	/* only answer section is really used, question, additional and
	   authority section RRs are skipped */
	qcount = QDCOUNT(packet);
	ancount = ANCOUNT(packet);
	buffer_skip(packet, QHEADERSZ);

	/* skip queries */
	for(i=0; i<qcount; ++i)
		if(!packet_skip_rr(packet, 1)) {
			log_msg(LOG_ERR, "bad RR in question section");
			region_destroy(region);
			return 0;
		}

	DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s",
			dname_to_string(dname_zone, 0)));
	/* first RR: check if SOA and correct zone & serialno */
	if(*rr_count == 0) {
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR",
			dname_to_string(dname_zone, 0)));
		dname = dname_make_from_packet(region, packet, 1, 1);
		if(!dname) {
			log_msg(LOG_ERR, "could not parse dname");
			region_destroy(region);
			return 0;
		}
		if(dname_compare(dname_zone, dname) != 0) {
			log_msg(LOG_ERR, "SOA dname %s not equal to zone",
				dname_to_string(dname,0));
			log_msg(LOG_ERR, "zone dname is %s",
				dname_to_string(dname_zone,0));
			region_destroy(region);
			return 0;
		}
		if(!buffer_available(packet, 10)) {
			log_msg(LOG_ERR, "bad SOA RR");
			region_destroy(region);
			return 0;
		}
		if(buffer_read_u16(packet) != TYPE_SOA ||
			buffer_read_u16(packet) != CLASS_IN) {
			log_msg(LOG_ERR, "first RR not SOA IN");
			region_destroy(region);
			return 0;
		}
		buffer_skip(packet, sizeof(uint32_t)); /* ttl */
		if(!buffer_available(packet, buffer_read_u16(packet)) ||
			!packet_skip_dname(packet) /* skip prim_ns */ ||
			!packet_skip_dname(packet) /* skip email */) {
			log_msg(LOG_ERR, "bad SOA RR");
			region_destroy(region);
			return 0;
		}
		if(buffer_read_u32(packet) != serialno) {
			buffer_skip(packet, -4);
			log_msg(LOG_ERR, "SOA serial %d different from commit %d",
				buffer_read_u32(packet), serialno);
			region_destroy(region);
			return 0;
		}
		buffer_skip(packet, sizeof(uint32_t)*4);
		counter = 1;
		*rr_count = 1;
		*is_axfr = 0;
		*delete_mode = 0;

		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d",
			dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
	}
	else  counter = 0;

	last_in_list = zone_db->apex;
	for(; counter < ancount; ++counter,++(*rr_count))
	{
		uint16_t type, klass;
		uint32_t ttl;

		if(!(dname=dname_make_from_packet(region, packet, 1,1))) {
			log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count);
			region_destroy(region);
			return 0;
		}
		if(!buffer_available(packet, 10)) {
			log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count);
			region_destroy(region);
			return 0;
		}
		type = buffer_read_u16(packet);
		klass = buffer_read_u16(packet);
		ttl = buffer_read_u32(packet);
		rrlen = buffer_read_u16(packet);
		if(!buffer_available(packet, rrlen)) {
			log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d",
				*rr_count, rrlen, (int)buffer_remaining(packet));
			region_destroy(region);
			return 0;
		}
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d",
			dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));

		if(*rr_count == 1 && type != TYPE_SOA) {
			/* second RR: if not SOA: this is an AXFR; delete all zone contents */
			delete_zone_rrs(db, zone_db);
			/* add everything else (incl end SOA) */
			*delete_mode = 0;
			*is_axfr = 1;
			DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d",
				dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
		}
		if(*rr_count == 1 && type == TYPE_SOA) {
			/* if the serial no of the SOA equals the serialno, then AXFR */
			size_t bufpos = buffer_position(packet);
			uint32_t thisserial;
			if(!packet_skip_dname(packet) ||
				!packet_skip_dname(packet) ||
				buffer_remaining(packet) < sizeof(uint32_t)*5)
			{
				log_msg(LOG_ERR, "bad xfr SOA RR formerr.");
				region_destroy(region);
				return 0;
			}
			thisserial = buffer_read_u32(packet);
			if(thisserial == serialno) {
				/* AXFR */
				delete_zone_rrs(db, zone_db);
				*delete_mode = 0;
				*is_axfr = 1;
			}
			/* must have stuff in memory for a successful IXFR,
			 * the serial number of the SOA has been checked
			 * previously (by check_for_bad_serial) if it exists */
			if(!*is_axfr && !domain_find_rrset(zone_db->apex,
				zone_db, TYPE_SOA)) {
				log_msg(LOG_ERR, "%s SOA serial %d is not "
					"in memory, skip IXFR", zone, serialno);
				region_destroy(region);
				/* break out and stop the IXFR, ignore it */
				return 2;
			}
			buffer_set_position(packet, bufpos);
		}
		if(type == TYPE_SOA && !*is_axfr) {
			/* switch from delete-part to add-part and back again,
			   just before soa - so it gets deleted and added too */
			/* this means we switch to delete mode for the final SOA */
			*delete_mode = !*delete_mode;
			DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d",
				dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode));
		}
		if(type == TYPE_TSIG || type == TYPE_OPT) {
			/* ignore pseudo RRs */
			buffer_skip(packet, rrlen);
			continue;
		}

		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s",
			*delete_mode?"del":"add",
			dname_to_string(dname,0), rrtype_to_string(type)));
		if(*delete_mode) {
			/* delete this rr */
			if(!*is_axfr && type == TYPE_SOA && counter==ancount-1
				&& seq_nr == seq_total-1) {
				continue; /* do not delete final SOA RR for IXFR */
			}
			if(!delete_RR(db, dname, type, klass, last_in_list, packet,
				rrlen, zone_db, region, *is_axfr)) {
				region_destroy(region);
				return 0;
			}
			if (!*is_axfr && last_in_list->nextdiff) {
				last_in_list = last_in_list->nextdiff;
			}
		}
		else
		{
			/* add this rr */
			if(!add_RR(db, dname, type, klass, ttl, packet,
				rrlen, zone_db, *is_axfr)) {
				region_destroy(region);
				return 0;
			}
		}
	}
	fix_empty_terminals(zone_db);
	region_destroy(region);
	return 1;
}
Exemplo n.º 3
0
static int
read_sure_part(namedb_type* db, FILE *in, nsd_options_t* opt,
	struct diff_read_data* data, struct diff_log** log,
	size_t child_count)
{
	char zone_buf[3072];
	char log_buf[5120];
	uint32_t old_serial, new_serial, num_parts;
	uint16_t id;
	uint8_t committed;
	struct diff_zone *zp;
	uint32_t i;
	int have_all_parts = 1;
	struct diff_log* thislog = 0;
	off_t commitpos;

	/* read zone name and serial */
	if(!diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
		!diff_read_32(in, &old_serial) ||
		!diff_read_32(in, &new_serial) ||
		!diff_read_16(in, &id) ||
		!diff_read_32(in, &num_parts)) {
		log_msg(LOG_ERR, "diff file bad commit part");
		return 0;
	}
	commitpos = ftello(in); /* position of commit byte */
	if(commitpos == -1) {
		log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
		return 0;
	}
	if(!diff_read_8(in, &committed) ||
		!diff_read_str(in, log_buf, sizeof(log_buf)) )
	{
		log_msg(LOG_ERR, "diff file bad commit part");
		return 0;
	}

	if(log) {
		thislog = (struct diff_log*)region_alloc(db->region, sizeof(struct diff_log));
		if(!thislog) {
			log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
			exit(1);
		}
		thislog->zone_name = region_strdup(db->region, zone_buf);
		thislog->comment = region_strdup(db->region, log_buf);
		thislog->error = 0;
		thislog->next = *log;
		*log = thislog;
	}

	/* has been read in completely */
	zp = diff_read_find_zone(data, zone_buf);
	if(!zp) {
		log_msg(LOG_ERR, "diff file commit without IXFR");
		if(thislog)
			thislog->error = "error no IXFR parts";
		return 1;
	}
	if(committed && check_for_bad_serial(db, zone_buf, old_serial)) {
		DEBUG(DEBUG_XFRD,1, (LOG_ERR,
			"skipping diff file commit with bad serial"));
		zp->parts->root = RBTREE_NULL;
		zp->parts->count = 0;
		if(thislog)
			thislog->error = "error bad serial";
		return 1;
	}
	for(i=0; i<num_parts; i++) {
		struct diff_xfrpart *xp = diff_read_find_part(zp, i);
		if(!xp || xp->id != id || xp->new_serial != new_serial) {
			have_all_parts = 0;
		}
	}
	if(!have_all_parts) {
		DEBUG(DEBUG_XFRD,1, (LOG_ERR,
			"skipping diff file commit without all parts"));
		if(thislog)
			thislog->error = "error missing parts";
	}

	if(committed && have_all_parts)
	{
		int is_axfr=0, delete_mode=0, rr_count=0;
		off_t resume_pos;

#ifdef NSEC3
#ifndef FULL_PREHASH
		struct region *region;
		dname_type const *zone_dname;
		struct zone *zone;

		region = region_create(xalloc, free);
		if (region == NULL) {
			log_msg(LOG_ERR, "out of memory");
			return 0;
		}
		zone_dname = dname_parse(region, zone_buf);
		if (zone_dname == NULL) {
			log_msg(LOG_ERR, "out of memory");
		        region_destroy(region);
			return 0;
		}
		zone = find_zone(db, zone_dname, opt, child_count);
		region_destroy(region);
		if (zone == NULL) {
			log_msg(LOG_ERR, "no zone exists");
			/* just stop trying applying ixfr */
			return 1;
		}
		if (0 != namedb_nsec3_mod_domains_create(db)) {
			log_msg(LOG_ERR,
				"unable to allocate space "
				"for modified NSEC3 domains");
			return 0;
		}
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", log_buf));

		resume_pos = ftello(in);
		if(resume_pos == -1) {
			log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno));
			return 0;
		}
		for(i=0; i<num_parts; i++) {
			struct diff_xfrpart *xp = diff_read_find_part(zp, i);
			int ret;
			DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i));
			ret = apply_ixfr(db, in, &xp->file_pos, zone_buf, new_serial, opt,
				id, xp->seq_nr, num_parts, &is_axfr, &delete_mode,
				&rr_count, child_count);
			if(ret == 0) {
				log_msg(LOG_ERR, "bad ixfr packet part %d in %s", (int)i,
					opt->difffile);
				mark_and_exit(opt, in, commitpos, log_buf);
			} else if(ret == 2) {
				break;
			}
		}
#ifdef NSEC3
#ifndef FULL_PREHASH
		if (is_axfr != 0)
			prehash_zone(db, zone);
		else
			prehash_zone_incremental(db, zone);
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

		if(fseeko(in, resume_pos, SEEK_SET) == -1) {
			log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno));
			return 0;
		}
	}
	else {
	 	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf));
	}

	/* clean out the parts for the zone after the commit/rollback */
	zp->parts->root = RBTREE_NULL;
	zp->parts->count = 0;
	return 1;
}
Exemplo n.º 4
0
void
nsd_options_destroy(nsd_options_t* opt)
{
	region_destroy(opt->region);
}
Exemplo n.º 5
0
ssize_t
rdata_wireformat_to_rdata_atoms(region_type *region,
				domain_table_type *owners,
				uint16_t rrtype,
				uint16_t data_size,
				buffer_type *packet,
				rdata_atom_type **rdatas)
{
	size_t end = buffer_position(packet) + data_size;
	size_t i;
	rdata_atom_type temp_rdatas[MAXRDATALEN];
	rrtype_descriptor_type *descriptor = rrtype_descriptor_by_type(rrtype);
	region_type *temp_region;

	assert(descriptor->maximum <= MAXRDATALEN);

	if (!buffer_available(packet, data_size)) {
		return -1;
	}

	temp_region = region_create(xalloc, free);

	for (i = 0; i < descriptor->maximum; ++i) {
		int is_domain = 0;
		int is_normalized = 0;
		int is_wirestore = 0;
		size_t length = 0;
		int required = i < descriptor->minimum;

		switch (rdata_atom_wireformat_type(rrtype, i)) {
		case RDATA_WF_COMPRESSED_DNAME:
		case RDATA_WF_UNCOMPRESSED_DNAME:
			is_domain = 1;
			is_normalized = 1;
			break;
		case RDATA_WF_LITERAL_DNAME:
			is_domain = 1;
			is_wirestore = 1;
			break;
		case RDATA_WF_BYTE:
			length = sizeof(uint8_t);
			break;
		case RDATA_WF_SHORT:
			length = sizeof(uint16_t);
			break;
		case RDATA_WF_LONG:
			length = sizeof(uint32_t);
			break;
		case RDATA_WF_TEXTS:
		case RDATA_WF_LONG_TEXT:
			length = end - buffer_position(packet);
			break;
		case RDATA_WF_TEXT:
		case RDATA_WF_BINARYWITHLENGTH:
			/* Length is stored in the first byte.  */
			length = 1;
			if (buffer_position(packet) + length <= end) {
				length += buffer_current(packet)[length - 1];
			}
			break;
		case RDATA_WF_A:
			length = sizeof(in_addr_t);
			break;
		case RDATA_WF_AAAA:
			length = IP6ADDRLEN;
			break;
		case RDATA_WF_ILNP64:
			length = IP6ADDRLEN/2;
			break;
		case RDATA_WF_EUI48:
			length = EUI48ADDRLEN;
			break;
		case RDATA_WF_EUI64:
			length = EUI64ADDRLEN;
			break;
		case RDATA_WF_BINARY:
			/* Remaining RDATA is binary.  */
			length = end - buffer_position(packet);
			break;
		case RDATA_WF_APL:
			length = (sizeof(uint16_t)    /* address family */
				  + sizeof(uint8_t)   /* prefix */
				  + sizeof(uint8_t)); /* length */
			if (buffer_position(packet) + length <= end) {
				/* Mask out negation bit.  */
				length += (buffer_current(packet)[length - 1]
					   & APL_LENGTH_MASK);
			}
			break;
		case RDATA_WF_IPSECGATEWAY:
			switch(rdata_atom_data(temp_rdatas[1])[0]) /* gateway type */ {
			default:
			case IPSECKEY_NOGATEWAY:
				length = 0;
				break;
			case IPSECKEY_IP4:
				length = IP4ADDRLEN;
				break;
			case IPSECKEY_IP6:
				length = IP6ADDRLEN;
				break;
			case IPSECKEY_DNAME:
				is_domain = 1;
				is_normalized = 1;
				is_wirestore = 1;
				break;
			}
			break;
		}

		if (is_domain) {
			const dname_type *dname;

			if (!required && buffer_position(packet) == end) {
				break;
			}

			dname = dname_make_from_packet(
				temp_region, packet, 1, is_normalized);
			if (!dname || buffer_position(packet) > end) {
				/* Error in domain name.  */
				region_destroy(temp_region);
				return -1;
			}
			if(is_wirestore) {
				temp_rdatas[i].data = (uint16_t *) region_alloc(
                                	region, sizeof(uint16_t) + dname->name_size);
				temp_rdatas[i].data[0] = dname->name_size;
				memcpy(temp_rdatas[i].data+1, dname_name(dname),
					dname->name_size);
			} else {
				temp_rdatas[i].domain
					= domain_table_insert(owners, dname);
				temp_rdatas[i].domain->usage ++;
			}
		} else {
			if (buffer_position(packet) + length > end) {
				if (required) {
					/* Truncated RDATA.  */
					region_destroy(temp_region);
					return -1;
				} else {
					break;
				}
			}
			if (!required && buffer_position(packet) == end) {
				break;
			}

			temp_rdatas[i].data = (uint16_t *) region_alloc(
				region, sizeof(uint16_t) + length);
			temp_rdatas[i].data[0] = length;
			buffer_read(packet, temp_rdatas[i].data + 1, length);
		}
	}

	if (buffer_position(packet) < end) {
		/* Trailing garbage.  */
		region_destroy(temp_region);
		return -1;
	}

	*rdatas = (rdata_atom_type *) region_alloc_init(
		region, temp_rdatas, i * sizeof(rdata_atom_type));
	region_destroy(temp_region);
	return (ssize_t)i;
}
Exemplo n.º 6
0
struct namedb *
namedb_open (const char *filename, nsd_options_t* opt, size_t num_children)
{
    namedb_type *db;

    /*
     * Temporary region used while loading domain names from the
     * database.  The region is freed after each time a dname is
     * read from the database.
     */
    region_type *dname_region;

    /*
     * Temporary region used to store array of domains and zones
     * while loading the database.  The region is freed before
     * returning.
     */
    region_type *temp_region;

    uint32_t dname_count;
    domain_type **domains;	/* Indexed by domain number.  */

    uint32_t zone_count;
    zone_type **zones;	/* Indexed by zone number.  */

    uint32_t i;
    uint32_t rrset_count = 0;
    uint32_t rr_count = 0;

    rrset_type *rrset;

    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(namedb_type) = %lu\n", (unsigned long) sizeof(namedb_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(zone_type) = %lu\n", (unsigned long) sizeof(zone_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(domain_type) = %lu\n", (unsigned long) sizeof(domain_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(rrset_type) = %lu\n", (unsigned long) sizeof(rrset_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(rr_type) = %lu\n", (unsigned long) sizeof(rr_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(rdata_atom_type) = %lu\n", (unsigned long) sizeof(rdata_atom_type)));
    DEBUG(DEBUG_DBACCESS, 2,
          (LOG_INFO, "sizeof(rbnode_t) = %lu\n", (unsigned long) sizeof(rbnode_t)));

    if ((db = namedb_create()) == NULL) {
        log_msg(LOG_ERR,
                "insufficient memory to create database");
        return NULL;
    }
    db->filename = region_strdup(db->region, filename);

    if (gettimeofday(&(db->diff_timestamp), NULL) != 0) {
        log_msg(LOG_ERR, "unable to load %s: cannot initialize"
                "timestamp", db->filename);
        namedb_destroy(db);
        return NULL;
    }

    /* Open it... */
    db->fd = fopen(db->filename, "r");
    if (db->fd == NULL) {
        log_msg(LOG_ERR, "unable to load %s: %s",
                db->filename, strerror(errno));
        namedb_destroy(db);
        return NULL;
    }

    if (!read_magic(db)) {
        log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename);
        log_msg(LOG_ERR, "cannot load database, incompatible version "
                "number. Please rebuild database and "
                "start again.");
        namedb_close(db);
        return NULL;
    }

    if (!read_size(db, &zone_count)) {
        log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
        namedb_close(db);
        return NULL;
    }

    DEBUG(DEBUG_DBACCESS, 1,
          (LOG_INFO, "Retrieving %lu zones\n", (unsigned long) zone_count));

    temp_region = region_create(xalloc, free);
    dname_region = region_create(xalloc, free);

    db->zone_count = zone_count;
    zones = (zone_type **) region_alloc(temp_region,
                                        zone_count * sizeof(zone_type *));
    for (i = 0; i < zone_count; ++i) {
        const dname_type *dname = read_dname(db->fd, dname_region);
        if (!dname) {
            log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename);
            region_destroy(dname_region);
            region_destroy(temp_region);
            namedb_close(db);
            return NULL;
        }
        zones[i] = (zone_type *) region_alloc(db->region,
                                              sizeof(zone_type));
        zones[i]->next = db->zones;
        db->zones = zones[i];
        zones[i]->apex = domain_table_insert(db->domains, dname);
        zones[i]->soa_rrset = NULL;
        zones[i]->soa_nx_rrset = NULL;
        zones[i]->ns_rrset = NULL;
#ifdef NSEC3
        zones[i]->nsec3_soa_rr = NULL;
        zones[i]->nsec3_last = NULL;
#endif
        zones[i]->opts = zone_options_find(opt, domain_dname(zones[i]->apex));
        zones[i]->number = i + 1;
        zones[i]->is_secure = 0;
        zones[i]->updated = 1;
        zones[i]->is_ok = 0;
        zones[i]->dirty = region_alloc(db->region, sizeof(uint8_t)*num_children);
        memset(zones[i]->dirty, 0, sizeof(uint8_t)*num_children);
        if(!zones[i]->opts) {
            log_msg(LOG_ERR, "cannot load database. Zone %s in db "
                    "%s, but not in config file (might "
                    "happen if you edited the config "
                    "file). Please rebuild database and "
                    "start again.",
                    dname_to_string(dname, NULL), db->filename);
            region_destroy(dname_region);
            region_destroy(temp_region);
            namedb_close(db);
            return NULL;
        }
#ifdef NSEC3
#ifndef FULL_PREHASH
        zones[i]->nsec3_domains = NULL;
        if (0 != zone_nsec3_domains_create(db, zones[i])) {
            log_msg(LOG_ERR,
                    "insufficient memory for NSEC3 tree, "
                    "unable to read database");
            region_destroy(dname_region);
            region_destroy(temp_region);
            namedb_close(db);
            return NULL;
        }
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */
        region_free_all(dname_region);
    }

    if (!read_size(db, &dname_count)) {
        log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
        region_destroy(dname_region);
        region_destroy(temp_region);
        namedb_close(db);
        return NULL;
    }

    DEBUG(DEBUG_DBACCESS, 1,
          (LOG_INFO, "Retrieving %lu domain names\n", (unsigned long) dname_count));

    domains = (domain_type **) region_alloc(
                  temp_region, dname_count * sizeof(domain_type *));
    for (i = 0; i < dname_count; ++i) {
        const dname_type *dname = read_dname(db->fd, dname_region);
        if (!dname) {
            log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename);
            region_destroy(dname_region);
            region_destroy(temp_region);
            namedb_close(db);
            return NULL;
        }
        domains[i] = domain_table_insert(db->domains, dname);
        region_free_all(dname_region);
    }

    region_destroy(dname_region);

#ifndef NDEBUG
    fprintf(stderr, "database region after loading domain names: ");
    region_dump_stats(db->region, stderr);
    fprintf(stderr, "\n");
#endif

    while ((rrset = read_rrset(db, dname_count, domains, zone_count, zones))) {
        ++rrset_count;
        rr_count += rrset->rr_count;
    }

    DEBUG(DEBUG_DBACCESS, 1,
          (LOG_INFO, "Retrieved %lu RRs in %lu RRsets\n",
           (unsigned long) rr_count, (unsigned long) rrset_count));

    region_destroy(temp_region);

    if ((db->crc_pos = ftello(db->fd)) == -1) {
        log_msg(LOG_ERR, "ftello %s failed: %s",
                db->filename, strerror(errno));
        namedb_close(db);
        return NULL;
    }
    if (!read_size(db, &db->crc)) {
        log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename);
        namedb_close(db);
        return NULL;
    }
    if (!read_magic(db)) {
        log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename);
        log_msg(LOG_ERR, "cannot load database, incompatible version "
                "number. Please rebuild database and "
                "start again.");
        namedb_close(db);
        return NULL;
    }

    fclose(db->fd);
    db->fd = NULL;

#ifndef NDEBUG
    fprintf(stderr, "database region after loading database: ");
    region_dump_stats(db->region, stderr);
    fprintf(stderr, "\n");
#endif

    return db;
}
/*
 * Flash map is a string like "2x16K/l,6x16K,63x128K", where "2x16K"
 * means "two blocks of size 16 Kbytes each", and the "/l" is a flag
 * meaning "locked" (used for boot blocks which can't be programmed
 * without special intervention).  Possible size suffixes are none
 * (bytes), "K" (kilobytes), and "M" (megabytes).  Parse with a little
 * state machine, and add the blocks as a mem_region_t chain that's a
 * child of the given one.
 */
int flash_parse_map(mem_region_t *mr, const char *map)
{
	enum state { S_NBLOCKS, S_SIZE, S_FLAGS, S_END } state = S_NBLOCKS;
	mem_region_t *cur = mr;
	int nblocks = 0;
	tsize_t size = 0;
	taddr_t vma, lma;
	unsigned flags = 0;
	const char *p;

	assert(mr);
	vma = mr->vma;
	lma = mr->lma;
	assert(map);

	/* clear out prior flash blocks */
	region_destroy(mr->children);
	mr->children = NULL;

	p = map;
	goto loop;
	do {
		++p;
	loop:
		if (isspace(*p))
			continue;

		switch (state) {

		case S_NBLOCKS:
			if (isdigit(*p)) {
				nblocks = (nblocks * 10) + (*p - '0');
			} else if (*p == 'x') {
				state = S_SIZE;
			} else {
				bad_map(map, p);
				goto failure;
			}
			break;

		case S_SIZE:
			switch (*p) {
			case '0': case '1': case '2': case '3':
			case '4': case '5': case '6': case '7':
			case '8': case '9':
				size = (size * 10) + (*p - '0');
				break;
			case 'K':
				size *= 1024;
				break;
			case 'M':
				size *= (1024 * 1024);
				break;
			case '/':
				state = S_FLAGS;
				break;
			case ',': case '\0':
				state = S_END;
				break;
			default:
				bad_map(map, p);
				goto failure;
			}
			break;

		case S_FLAGS:
			switch (*p) {
			case 'l':
				flags |= MRF_LOCKED;
				break;
			case ',': case '\0':
				state = S_END;
				break;
			default:
				bad_map(map, p);
				goto failure;
			}
			break;

		default:
			assert(0);
		}

		if (state == S_END) {
			/*
			 * Create one mem_region_t for each flash
			 * block, and link them into a chain.
			 */
			while (nblocks--) {
				mem_region_t *tmp = region_new();
				tmp->name = xstrdup("(anonymous flash block)");
				tmp->type = MEMTYPE_FLASH;
				tmp->size = size;
				tmp->flags = flags;
				tmp->bufsize = mr->bufsize;

				tmp->vma = vma;
				vma += size;
				tmp->lma = lma;
				lma += size;

				if (cur == mr) {
					mr->children = tmp;
					cur = tmp;
				} else {
					cur->next = tmp;
					cur = tmp;
				}
			}
			if(flags != 0) mr->flags |= flags;
			state = S_NBLOCKS;
			nblocks = 0;
			size = 0;
			flags = 0;
		}

	} while (*p);

	return 0;

failure:
	region_destroy(mr->children);
	mr->children = NULL;
	return -1;
}