Exemple #1
0
void
key_options_add_modify(nsd_options_t* opt, key_options_t* key)
{
	key_options_t* orig = key_options_find(opt, key->name);
	if(!orig) {
		/* needs to be copied to opt region */
		orig = key_options_create(opt->region);
		orig->name = region_strdup(opt->region, key->name);
		orig->algorithm = region_strdup(opt->region, key->algorithm);
		orig->secret = region_strdup(opt->region, key->secret);
		key_options_setup(opt->region, orig);
		tsig_add_key(orig->tsig_key);
		key_options_insert(opt, orig);
	} else {
		/* modify entries in existing key, and copy to opt region */
		key_options_desetup(opt->region, orig);
		region_recycle(opt->region, orig->algorithm,
			strlen(orig->algorithm)+1);
		orig->algorithm = region_strdup(opt->region, key->algorithm);
		region_recycle(opt->region, orig->secret,
			strlen(orig->secret)+1);
		orig->secret = region_strdup(opt->region, key->secret);
		key_options_setup(opt->region, orig);
	}
}
Exemple #2
0
void
pattern_options_add_modify(nsd_options_t* opt, pattern_options_t* p)
{
	pattern_options_t* orig = pattern_options_find(opt, p->pname);
	if(!orig) {
		/* needs to be copied to opt region */
		orig = pattern_options_create(opt->region);
		orig->pname = region_strdup(opt->region, p->pname);
		copy_pat_fixed(opt->region, orig, p);
		orig->allow_notify = copy_acl_list(opt, p->allow_notify);
		orig->request_xfr = copy_acl_list(opt, p->request_xfr);
		orig->notify = copy_acl_list(opt, p->notify);
		orig->provide_xfr = copy_acl_list(opt, p->provide_xfr);
		orig->outgoing_interface = copy_acl_list(opt,
			p->outgoing_interface);
		nsd_options_insert_pattern(opt, orig);
	} else {
		/* modify in place so pointers stay valid (and copy
		   into region). Do not touch unchanged acls. */
		if(orig->zonefile)
			region_recycle(opt->region, (char*)orig->zonefile,
				strlen(orig->zonefile)+1);
		if(orig->zonestats)
			region_recycle(opt->region, (char*)orig->zonestats,
				strlen(orig->zonestats)+1);
		copy_pat_fixed(opt->region, orig, p);
		copy_changed_acl(opt, &orig->allow_notify, p->allow_notify);
		copy_changed_acl(opt, &orig->request_xfr, p->request_xfr);
		copy_changed_acl(opt, &orig->notify, p->notify);
		copy_changed_acl(opt, &orig->provide_xfr, p->provide_xfr);
		copy_changed_acl(opt, &orig->outgoing_interface,
			p->outgoing_interface);
	}
}
Exemple #3
0
zone_options_t*
zone_list_zone_insert(nsd_options_t* opt, const char* nm, const char* patnm,
	int linesize, off_t off)
{
	pattern_options_t* pat = pattern_options_find(opt, patnm);
	zone_options_t* zone;
	if(!pat) {
		log_msg(LOG_ERR, "pattern does not exist for zone %s "
			"pattern %s", nm, patnm);
		return NULL;
	}
	zone = zone_options_create(opt->region);
	zone->part_of_config = 0;
	zone->name = region_strdup(opt->region, nm);
	zone->linesize = linesize;
	zone->off = off;
	zone->pattern = pat;
	if(!nsd_options_insert_zone(opt, zone)) {
		log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
			"pattern %s", nm, patnm);
		region_recycle(opt->region, (void*)zone->name, strlen(nm)+1);
		region_recycle(opt->region, zone, sizeof(*zone));
		return NULL;
	}
	return zone;
}
Exemple #4
0
static acl_options_t*
copy_acl(region_type* region, acl_options_t* a)
{
	acl_options_t* b;
	if(!a) return NULL;
	b = (acl_options_t*)region_alloc(region, sizeof(*b));
	/* copy the whole lot */
	*b = *a;
	/* fix the pointers */
	if(a->ip_address_spec)
		b->ip_address_spec = region_strdup(region, a->ip_address_spec);
	if(a->key_name)
		b->key_name = region_strdup(region, a->key_name);
	b->next = NULL;
	b->key_options = NULL;
	return b;
}
Exemple #5
0
static void
copy_pat_fixed(region_type* region, pattern_options_t* orig,
	pattern_options_t* p)
{
	orig->allow_axfr_fallback = p->allow_axfr_fallback;
	orig->allow_axfr_fallback_is_default =
		p->allow_axfr_fallback_is_default;
	orig->notify_retry = p->notify_retry;
	orig->notify_retry_is_default = p->notify_retry_is_default;
	orig->implicit = p->implicit;
	if(p->zonefile)
		orig->zonefile = region_strdup(region, p->zonefile);
	else orig->zonefile = NULL;
	if(p->zonestats)
		orig->zonestats = region_strdup(region, p->zonestats);
	else orig->zonestats = NULL;
#ifdef RATELIMIT
	orig->rrl_whitelist = p->rrl_whitelist;
#endif
}
Exemple #6
0
static char*
unmarshal_str(region_type* r, struct buffer* b)
{
	uint8_t nonnull = unmarshal_u8(b);
	if(nonnull) {
		char* result = region_strdup(r, (char*)buffer_current(b));
		size_t len = strlen((char*)buffer_current(b));
		buffer_skip(b, len+1);
		return result;
	} else return NULL;
}
Exemple #7
0
void
config_apply_pattern(const char* name)
{
	/* find the pattern */
	pattern_options_t* pat = pattern_options_find(cfg_parser->opt, name);
	pattern_options_t* a = cfg_parser->current_pattern;
	if(!pat) {
		c_error_msg("could not find pattern %s", name);
		return;
	}

	/* apply settings */
	if(pat->zonefile)
		a->zonefile = region_strdup(cfg_parser->opt->region,
			pat->zonefile);
	if(pat->zonestats)
		a->zonestats = region_strdup(cfg_parser->opt->region,
			pat->zonestats);
	if(!pat->allow_axfr_fallback_is_default) {
		a->allow_axfr_fallback = pat->allow_axfr_fallback;
		a->allow_axfr_fallback_is_default = 0;
	}
	if(!pat->notify_retry_is_default) {
		a->notify_retry = pat->notify_retry;
		a->notify_retry_is_default = 0;
	}
#ifdef RATELIMIT
	a->rrl_whitelist |= pat->rrl_whitelist;
#endif
	/* append acl items */
	append_acl(&a->allow_notify, &cfg_parser->current_allow_notify,
		pat->allow_notify);
	append_acl(&a->request_xfr, &cfg_parser->current_request_xfr,
		pat->request_xfr);
	append_acl(&a->notify, &cfg_parser->current_notify, pat->notify);
	append_acl(&a->provide_xfr, &cfg_parser->current_provide_xfr,
		pat->provide_xfr);
	append_acl(&a->outgoing_interface, &cfg_parser->
		current_outgoing_interface, pat->outgoing_interface);
}
Exemple #8
0
void
namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt)
{
	const char* zfile;
	int notexist = 0;
	zone_type* zone;
	/* if no zone exists, it has no contents or it has no zonefile
	 * configured, then no need to write data to disk */
	if(!zopt->pattern->zonefile)
		return;
	zone = namedb_find_zone(nsd->db, (const dname_type*)zopt->node.key);
	if(!zone || !zone->apex || !zone->soa_rrset)
		return;
	/* write if file does not exist, or if changed */
	/* so, determine filename, create directory components, check exist*/
	zfile = config_make_zonefile(zopt, nsd);
	if(!create_path_components(zfile, &notexist)) {
		log_msg(LOG_ERR, "could not write zone %s to file %s because "
			"the path could not be created", zopt->name, zfile);
		return;
	}

	/* if not changed, do not write. */
	if(notexist || zone->is_changed) {
		char logs[4096];
		char bakfile[4096];
		struct timespec mtime;
		udb_ptr zudb;
		if(nsd->db->udb) {
			if(!udb_zone_search(nsd->db->udb, &zudb,
				dname_name(domain_dname(zone->apex)),
				domain_dname(zone->apex)->name_size))
				return; /* zone does not exist in db */
		}
		/* write to zfile~ first, then rename if that works */
		snprintf(bakfile, sizeof(bakfile), "%s~", zfile);
		if(nsd->db->udb && ZONE(&zudb)->log_str.data) {
			udb_ptr s;
			udb_ptr_new(&s, nsd->db->udb, &ZONE(&zudb)->log_str);
			strlcpy(logs, (char*)udb_ptr_data(&s), sizeof(logs));
			udb_ptr_unlink(&s, nsd->db->udb);
		} else if(zone->logstr) {
			strlcpy(logs, zone->logstr, sizeof(logs));
		} else logs[0] = 0;
		VERBOSITY(1, (LOG_INFO, "writing zone %s to file %s",
			zone->opts->name, zfile));
		if(!write_to_zonefile(zone, bakfile, logs)) {
			if(nsd->db->udb)
				udb_ptr_unlink(&zudb, nsd->db->udb);
			(void)unlink(bakfile); /* delete failed file */
			return; /* error already printed */
		}
		if(rename(bakfile, zfile) == -1) {
			log_msg(LOG_ERR, "rename(%s to %s) failed: %s",
				bakfile, zfile, strerror(errno));
			if(nsd->db->udb)
				udb_ptr_unlink(&zudb, nsd->db->udb);
			(void)unlink(bakfile); /* delete failed file */
			return;
		}
		zone->is_changed = 0;
		/* fetch the mtime of the just created zonefile so we
		 * do not waste effort reading it back in */
		if(!file_get_mtime(zfile, &mtime, &notexist)) {
			get_time(&mtime);
		}
		if(nsd->db->udb) {
			ZONE(&zudb)->mtime = (uint64_t)mtime.tv_sec;
			ZONE(&zudb)->mtime_nsec = (uint64_t)mtime.tv_nsec;
			ZONE(&zudb)->is_changed = 0;
			udb_zone_set_log_str(nsd->db->udb, &zudb, NULL);
			udb_ptr_unlink(&zudb, nsd->db->udb);
		} else {
			zone->mtime = mtime;
			if(zone->filename)
				region_recycle(nsd->db->region, zone->filename,
					strlen(zone->filename)+1);
			zone->filename = region_strdup(nsd->db->region, zfile);
			if(zone->logstr)
				region_recycle(nsd->db->region, zone->logstr,
					strlen(zone->logstr)+1);
			zone->logstr = NULL;
		}
	}
}
Exemple #9
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;
}
Exemple #10
0
acl_options_t*
parse_acl_info(region_type* region, char* ip, const char* key)
{
	char* p;
	acl_options_t* acl = (acl_options_t*)region_alloc(region, sizeof(acl_options_t));
	acl->next = 0;
	/* ip */
	acl->ip_address_spec = region_strdup(region, ip);
	acl->use_axfr_only = 0;
	acl->allow_udp = 0;
	acl->ixfr_disabled = 0;
	acl->bad_xfr_count = 0;
	acl->key_options = 0;
	acl->is_ipv6 = 0;
	acl->port = 0;
	memset(&acl->addr, 0, sizeof(union acl_addr_storage));
	memset(&acl->range_mask, 0, sizeof(union acl_addr_storage));
	if((p=strrchr(ip, '@'))!=0) {
		if(atoi(p+1) == 0) c_error("expected port number after '@'");
		else acl->port = atoi(p+1);
		*p=0;
	}
	acl->rangetype = parse_acl_range_type(ip, &p);
	if(parse_acl_is_ipv6(ip)) {
		acl->is_ipv6 = 1;
#ifdef INET6
		if(inet_pton(AF_INET6, ip, &acl->addr.addr6) != 1)
			c_error_msg("Bad ip6 address '%s'", ip);
		if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax)
			if(inet_pton(AF_INET6, p, &acl->range_mask.addr6) != 1)
				c_error_msg("Bad ip6 address mask '%s'", p);
		if(acl->rangetype==acl_range_subnet)
			parse_acl_range_subnet(p, &acl->range_mask.addr6, 128);
#else
		c_error_msg("encountered IPv6 address '%s'.", ip);
#endif /* INET6 */
	} else {
		acl->is_ipv6 = 0;
		if(inet_pton(AF_INET, ip, &acl->addr.addr) != 1)
			c_error_msg("Bad ip4 address '%s'", ip);
		if(acl->rangetype==acl_range_mask || acl->rangetype==acl_range_minmax)
			if(inet_pton(AF_INET, p, &acl->range_mask.addr) != 1)
				c_error_msg("Bad ip4 address mask '%s'", p);
		if(acl->rangetype==acl_range_subnet)
			parse_acl_range_subnet(p, &acl->range_mask.addr, 32);
	}

	/* key */
	if(strcmp(key, "NOKEY")==0) {
		acl->nokey = 1;
		acl->blocked = 0;
		acl->key_name = 0;
	} else if(strcmp(key, "BLOCKED")==0) {
		acl->nokey = 0;
		acl->blocked = 1;
		acl->key_name = 0;
	} else {
		acl->nokey = 0;
		acl->blocked = 0;
		acl->key_name = region_strdup(region, key);
	}
	return acl;
}
Exemple #11
0
int
parse_options_file(nsd_options_t* opt, const char* file,
	void (*err)(void*,const char*), void* err_arg)
{
	FILE *in = 0;
	pattern_options_t* pat;
	acl_options_t* acl;

	if(!cfg_parser) {
		cfg_parser = (config_parser_state_t*)region_alloc(
			opt->region, sizeof(config_parser_state_t));
		cfg_parser->chroot = 0;
	}
	cfg_parser->err = err;
	cfg_parser->err_arg = err_arg;
	cfg_parser->filename = (char*)file;
	cfg_parser->line = 1;
	cfg_parser->errors = 0;
	cfg_parser->server_settings_seen = 0;
	cfg_parser->opt = opt;
	cfg_parser->current_pattern = 0;
	cfg_parser->current_zone = 0;
	cfg_parser->current_key = 0;
	cfg_parser->current_ip_address_option = opt->ip_addresses;
	while(cfg_parser->current_ip_address_option && cfg_parser->current_ip_address_option->next)
		cfg_parser->current_ip_address_option = cfg_parser->current_ip_address_option->next;
	cfg_parser->current_allow_notify = 0;
	cfg_parser->current_request_xfr = 0;
	cfg_parser->current_notify = 0;
	cfg_parser->current_provide_xfr = 0;
	
	in = fopen(cfg_parser->filename, "r");
	if(!in) {
		if(err) {
			char m[MAXSYSLOGMSGLEN];
			snprintf(m, sizeof(m), "Could not open %s: %s\n",
				file, strerror(errno));
			err(err_arg, m);
		} else {
			fprintf(stderr, "Could not open %s: %s\n",
				file, strerror(errno));
		}
		return 0;
	}
	c_in = in;
	c_parse();
	fclose(in);

	opt->configfile = region_strdup(opt->region, file);
	if(cfg_parser->current_pattern) {
		if(!cfg_parser->current_pattern->pname)
			c_error("last pattern has no name");
		else {
			if(!nsd_options_insert_pattern(cfg_parser->opt,
				cfg_parser->current_pattern))
				c_error("duplicate pattern");
		}
	}
	if(cfg_parser->current_zone) {
		if(!cfg_parser->current_zone->name)
			c_error("last zone has no name");
		else {
			if(!nsd_options_insert_zone(opt,
				cfg_parser->current_zone))
				c_error("duplicate zone");
		}
		if(!cfg_parser->current_zone->pattern)
			c_error("last zone has no pattern");
	}
	if(cfg_parser->current_key)
	{
		if(!cfg_parser->current_key->name)
			c_error("last key has no name");
		if(!cfg_parser->current_key->algorithm)
			c_error("last key has no algorithm");
		if(!cfg_parser->current_key->secret)
			c_error("last key has no secret blob");
		key_options_insert(opt, cfg_parser->current_key);
	}
	RBTREE_FOR(pat, pattern_options_t*, opt->patterns)
	{
		/* lookup keys for acls */
		for(acl=pat->allow_notify; acl; acl=acl->next)
		{
			if(acl->nokey || acl->blocked)
				continue;
			acl->key_options = key_options_find(opt, acl->key_name);
			if(!acl->key_options)
				c_error_msg("key %s in pattern %s could not be found",
					acl->key_name, pat->pname);
		}
		for(acl=pat->notify; acl; acl=acl->next)
		{
			if(acl->nokey || acl->blocked)
				continue;
			acl->key_options = key_options_find(opt, acl->key_name);
			if(!acl->key_options)
				c_error_msg("key %s in pattern %s could not be found",
					acl->key_name, pat->pname);
		}
		for(acl=pat->request_xfr; acl; acl=acl->next)
		{
			if(acl->nokey || acl->blocked)
				continue;
			acl->key_options = key_options_find(opt, acl->key_name);
			if(!acl->key_options)
				c_error_msg("key %s in pattern %s could not be found",
					acl->key_name, pat->pname);
		}
		for(acl=pat->provide_xfr; acl; acl=acl->next)
		{
			if(acl->nokey || acl->blocked)
				continue;
			acl->key_options = key_options_find(opt, acl->key_name);
			if(!acl->key_options)
				c_error_msg("key %s in pattern %s could not be found",
					acl->key_name, pat->pname);
		}
	}

	if(cfg_parser->errors > 0)
	{
		if(err) {
			char m[MAXSYSLOGMSGLEN];
			snprintf(m, sizeof(m), "read %s failed: %d errors in "
				"configuration file\n", file,
				cfg_parser->errors);
			err(err_arg, m);
		} else {
			fprintf(stderr, "read %s failed: %d errors in "
				"configuration file\n", file,
				cfg_parser->errors);
		}
		return 0;
	}
	return 1;
}
Exemple #12
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;
}