Пример #1
0
void
xfrd_del_notify(xfrd_state_t* xfrd, const dname_type* dname)
{
	/* find it */
	struct notify_zone_t* not = (struct notify_zone_t*)rbtree_delete(
		xfrd->notify_zones, dname);
	if(!not)
		return;

	/* waiting list */
	if(not->is_waiting) {
		if(not->waiting_prev)
			not->waiting_prev->waiting_next = not->waiting_next;
		else	xfrd->notify_waiting_first = not->waiting_next;
		if(not->waiting_next)
			not->waiting_next->waiting_prev = not->waiting_prev;
		else	xfrd->notify_waiting_last = not->waiting_prev;
		not->is_waiting = 0;
	}

	/* event */
	if(not->notify_send_enable) {
		notify_disable(not);
	}

	/* del tsig */
	tsig_delete_record(&not->notify_tsig, NULL);

	/* free it */
	region_recycle(xfrd->region, not->current_soa, sizeof(xfrd_soa_t));
	/* the apex is recycled when the zone_options.node.key is removed */
	region_recycle(xfrd->region, not, sizeof(*not));
}
Пример #2
0
void
pattern_options_remove(nsd_options_t* opt, const char* name)
{
	pattern_options_t* p = (pattern_options_t*)rbtree_delete(
		opt->patterns, name);
	/* delete p and its contents */
	if (!p)
		return;
	if(p->pname)
		region_recycle(opt->region, (void*)p->pname,
			strlen(p->pname)+1);
	if(p->zonefile)
		region_recycle(opt->region, (void*)p->zonefile,
			strlen(p->zonefile)+1);
	if(p->zonestats)
		region_recycle(opt->region, (void*)p->zonestats,
			strlen(p->zonestats)+1);
	acl_list_delete(opt->region, p->allow_notify);
	acl_list_delete(opt->region, p->request_xfr);
	acl_list_delete(opt->region, p->notify);
	acl_list_delete(opt->region, p->provide_xfr);
	acl_list_delete(opt->region, p->outgoing_interface);

	region_recycle(opt->region, p, sizeof(pattern_options_t));
}
Пример #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;
}
Пример #4
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);
	}
}
Пример #5
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);
	}
}
Пример #6
0
static domain_type*
rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
{
	int i;
	/* find previous */
	rrset_type** pp = &domain->rrsets;
	while(*pp && *pp != rrset) {
		pp = &( (*pp)->next );
	}
	if(!*pp) {
		/* rrset does not exist for domain */
		return NULL;
	}
	*pp = rrset->next;

	DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s",
		dname_to_string(domain_dname(domain),0),
		rrtype_to_string(rrset_rrtype(rrset))));

	/* is this a SOA rrset ? */
	if(rrset->zone->soa_rrset == rrset) {
		rrset->zone->soa_rrset = 0;
		rrset->zone->updated = 1;
		domain->has_SOA = 0;
	}
	if(rrset->zone->ns_rrset == rrset) {
		rrset->zone->ns_rrset = 0;
	}
	if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) {
		for (i = 0; i < rrset->rr_count; ++i) {
			if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) {
				rrset->zone->is_secure = 0;
				break;
			}
		}
	}

#ifdef NSEC3
#ifndef FULL_PREHASH
	if (rrset->rrs[0].type == TYPE_NSEC3) {
		namedb_del_nsec3_domain(db, domain, rrset->zone);
	}
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

	/* recycle the memory space of the rrset */
	for (i = 0; i < rrset->rr_count; ++i)
		add_rdata_to_recyclebin(db, &rrset->rrs[i]);
	region_recycle(db->region, rrset->rrs,
		sizeof(rr_type) * rrset->rr_count);
	rrset->rr_count = 0;
	region_recycle(db->region, rrset, sizeof(rrset_type));

	/* is the node now an empty node (completely deleted) */
	if (domain->rrsets == 0) {
		return domain;
	}
	return NULL;
}
Пример #7
0
void
zone_options_delete(nsd_options_t* opt, zone_options_t* zone)
{
	rbtree_delete(opt->zone_options, zone->node.key);
	region_recycle(opt->region, (void*)zone->node.key, dname_total_size(
		(dname_type*)zone->node.key));
	region_recycle(opt->region, zone, sizeof(*zone));
}
Пример #8
0
static void
acl_delete(region_type* region, acl_options_t* acl)
{
	if(acl->ip_address_spec)
		region_recycle(region, (void*)acl->ip_address_spec,
			strlen(acl->ip_address_spec)+1);
	if(acl->key_name)
		region_recycle(region, (void*)acl->key_name,
			strlen(acl->key_name)+1);
	/* key_options is a convenience pointer, not owned by the acl */
	region_recycle(region, acl, sizeof(*acl));
}
Пример #9
0
static void
add_rdata_to_recyclebin(namedb_type* db, rr_type* rr)
{
	/* add rdatas to recycle bin. */
	size_t i;
	for(i=0; i<rr->rdata_count; i++)
	{
		if(!rdata_atom_is_domain(rr->type, i))
			region_recycle(db->region, rr->rdatas[i].data,
				rdata_atom_size(rr->rdatas[i])
				+ sizeof(uint16_t));
	}
	region_recycle(db->region, rr->rdatas,
		sizeof(rdata_atom_type)*rr->rdata_count);
}
Пример #10
0
/* postorder delete of zonelist free space tree */
static void
delbucket(region_type* region, struct zonelist_bucket* b)
{
	struct zonelist_free* e, *f;
	if(!b || (rbnode_t*)b==RBTREE_NULL)
		return;
	delbucket(region, (struct zonelist_bucket*)b->node.left);
	delbucket(region, (struct zonelist_bucket*)b->node.right);
	e = b->list;
	while(e) {
		f = e->next;
		region_recycle(region, e, sizeof(*e));
		e = f;
	}
	region_recycle(region, b, sizeof(*b));
}
Пример #11
0
/** remove tsig_key contents */
void
key_options_desetup(region_type* region, key_options_t* key)
{
	/* keep tsig_key pointer so that existing references keep valid */
	if(!key->tsig_key)
		return;
	/* name stays the same */
	if(key->tsig_key->data) {
		/* wipe secret! */
		memset(key->tsig_key->data, 0xdd, key->tsig_key->size);
		region_recycle(region, key->tsig_key->data,
			key->tsig_key->size);
		key->tsig_key->data = NULL;
		key->tsig_key->size = 0;
	}
}
Пример #12
0
void
parse_unknown_rdata(uint16_t type, uint16_t *wireformat)
{
	buffer_type packet;
	uint16_t size;
	ssize_t rdata_count;
	ssize_t i;
	rdata_atom_type *rdatas;

	if (wireformat) {
		size = *wireformat;
	} else {
		return;
	}

	buffer_create_from(&packet, wireformat + 1, *wireformat);
	rdata_count = rdata_wireformat_to_rdata_atoms(parser->region,
						      parser->db->domains,
						      type,
						      size,
						      &packet,
						      &rdatas);
	if (rdata_count == -1) {
		zc_error_prev_line("bad unknown RDATA");
		return;
	}

	for (i = 0; i < rdata_count; ++i) {
		if (rdata_atom_is_domain(type, i)) {
			zadd_rdata_domain(rdatas[i].domain);
		} else {
			zadd_rdata_wireformat(rdatas[i].data);
		}
	}
	region_recycle(parser->region, rdatas,
		rdata_count*sizeof(rdata_atom_type));
}
Пример #13
0
void
key_options_remove(nsd_options_t* opt, const char* name)
{
	key_options_t* k = key_options_find(opt, name);
	if(!k) return;
	(void)rbtree_delete(opt->keys, name);
	if(k->name)
		region_recycle(opt->region, k->name, strlen(k->name)+1);
	if(k->algorithm)
		region_recycle(opt->region, k->algorithm, strlen(k->algorithm)+1);
	if(k->secret) {
		memset(k->secret, 0xdd, strlen(k->secret)); /* wipe secret! */
		region_recycle(opt->region, k->secret, strlen(k->secret)+1);
	}
	if(k->tsig_key) {
		tsig_del_key(k->tsig_key);
		if(k->tsig_key->name)
			region_recycle(opt->region, (void*)k->tsig_key->name,
				dname_total_size(k->tsig_key->name));
		key_options_desetup(opt->region, k);
		region_recycle(opt->region, k->tsig_key, sizeof(tsig_key_type));
	}
	region_recycle(opt->region, k, sizeof(key_options_t));
}
Пример #14
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;
		}
	}
}
Пример #15
0
void *
region_alloc(region_type *region, size_t size)
{
	size_t aligned_size;
	void *result;

	if (size == 0) {
		size = 1;
	}
	aligned_size = REGION_ALIGN_UP(size, ALIGNMENT);

	if (aligned_size >= region->large_object_size) {
		result = region->allocator(size + sizeof(struct large_elem));
		if (!result)
			return NULL;
		((struct large_elem*)result)->prev = NULL;
		((struct large_elem*)result)->next = region->large_list;
		if(region->large_list)
			region->large_list->prev = (struct large_elem*)result;
		region->large_list = (struct large_elem*)result;

		region->total_allocated += size;
		++region->large_objects;

		return result + sizeof(struct large_elem);
	}

	if (region->recycle_bin && region->recycle_bin[aligned_size]) {
		result = (void*)region->recycle_bin[aligned_size];
		region->recycle_bin[aligned_size] = region->recycle_bin[aligned_size]->next;
		region->recycle_size -= aligned_size;
		region->unused_space += aligned_size - size;
		return result;
	}

	if (region->allocated + aligned_size > region->chunk_size) {
		void *chunk = region->allocator(region->chunk_size);
		size_t wasted;
		if (!chunk)
			return NULL;

		wasted = (region->chunk_size - region->allocated) & (~(ALIGNMENT-1));
		if(
#ifndef PACKED_STRUCTS
			wasted >= ALIGNMENT
#else
			wasted >= SIZEOF_VOIDP
#endif
			) {
			/* put wasted part in recycle bin for later use */
			region->total_allocated += wasted;
			++region->small_objects;
			region_recycle(region, region->data+region->allocated, wasted);
			region->allocated += wasted;
		}
		++region->chunk_count;
		region->unused_space += region->chunk_size - region->allocated;

		if(!region_add_cleanup(region, region->deallocator, chunk)) {
			region->deallocator(chunk);
			region->chunk_count--;
			region->unused_space -=
                                region->chunk_size - region->allocated;
			return NULL;
		}
		region->allocated = 0;
		region->data = (char *) chunk;
	}

	result = region->data + region->allocated;
	region->allocated += aligned_size;

	region->total_allocated += aligned_size;
	region->unused_space += aligned_size - size;
	++region->small_objects;

	return result;
}
Пример #16
0
/* add a new zone to the zonelist */
zone_options_t*
zone_list_add(nsd_options_t* opt, const char* zname, const char* pname)
{
	int r;
	struct zonelist_free* e;
	struct zonelist_bucket* b;
	int linesize = 6 + strlen(zname) + strlen(pname);
	/* create zone entry */
	zone_options_t* zone = zone_list_zone_insert(opt, zname, pname,
		linesize, 0);
	if(!zone)
		return NULL;

	/* use free entry or append to file or create new file */
	if(!opt->zonelist || opt->zonelist_off == 0) {
		/* create new file */
		if(opt->zonelist) fclose(opt->zonelist);
		opt->zonelist = fopen(opt->zonelistfile, "w+");
		if(!opt->zonelist) {
			log_msg(LOG_ERR, "could not create zone list %s: %s",
				opt->zonelistfile, strerror(errno));
			log_msg(LOG_ERR, "zone %s could not be added", zname);
			zone_options_delete(opt, zone);
			return NULL;
		}
		r = fprintf(opt->zonelist, ZONELIST_HEADER);
		if(r != strlen(ZONELIST_HEADER)) {
			if(r == -1)
				log_msg(LOG_ERR, "could not write to %s: %s",
					opt->zonelistfile, strerror(errno));
			else log_msg(LOG_ERR, "partial write to %s: disk full",
				opt->zonelistfile);
			log_msg(LOG_ERR, "zone %s could not be added", zname);
			zone_options_delete(opt, zone);
			return NULL;
		}
		zone->off = ftello(opt->zonelist);
		if(zone->off == -1)
			log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno));
		r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
		if(r != zone->linesize) {
			if(r == -1)
				log_msg(LOG_ERR, "could not write to %s: %s",
					opt->zonelistfile, strerror(errno));
			else log_msg(LOG_ERR, "partial write to %s: disk full",
				opt->zonelistfile);
			log_msg(LOG_ERR, "zone %s could not be added", zname);
			zone_options_delete(opt, zone);
			return NULL;
		}
		opt->zonelist_off = ftello(opt->zonelist);
		if(opt->zonelist_off == -1)
			log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno));
		if(fflush(opt->zonelist) != 0) {
			log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
		}
		return zone;
	}
	b = (struct zonelist_bucket*)rbtree_search(opt->zonefree,
		&zone->linesize);
	if(!b || b->list == NULL) {
		/* no empty place, append to file */
		zone->off = opt->zonelist_off;
		if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) {
			log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno));
			log_msg(LOG_ERR, "zone %s could not be added", zname);
			zone_options_delete(opt, zone);
			return NULL;
		}
		r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
		if(r != zone->linesize) {
			if(r == -1)
				log_msg(LOG_ERR, "could not write to %s: %s",
					opt->zonelistfile, strerror(errno));
			else log_msg(LOG_ERR, "partial write to %s: disk full",
				opt->zonelistfile);
			log_msg(LOG_ERR, "zone %s could not be added", zname);
			zone_options_delete(opt, zone);
			return NULL;
		}
		opt->zonelist_off += linesize;
		if(fflush(opt->zonelist) != 0) {
			log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
		}
		return zone;
	}
	/* reuse empty spot */
	e = b->list;
	zone->off = e->off;
	if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) {
		log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno));
		log_msg(LOG_ERR, "zone %s could not be added", zname);
		zone_options_delete(opt, zone);
		return NULL;
	}
	r = fprintf(opt->zonelist, "add %s %s\n", zname, pname);
	if(r != zone->linesize) {
		if(r == -1)
			log_msg(LOG_ERR, "could not write to %s: %s",
				opt->zonelistfile, strerror(errno));
		else log_msg(LOG_ERR, "partial write to %s: disk full",
			opt->zonelistfile);
		log_msg(LOG_ERR, "zone %s could not be added", zname);
		zone_options_delete(opt, zone);
		return NULL;
	}
	if(fflush(opt->zonelist) != 0) {
		log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno));
	}

	/* snip off and recycle element */
	b->list = e->next;
	region_recycle(opt->region, e, sizeof(*e));
	if(b->list == NULL) {
		rbtree_delete(opt->zonefree, &b->linesize);
		region_recycle(opt->region, b, sizeof(*b));
	}
	opt->zonefree_number--;
	return zone;
}
Пример #17
0
static int
add_RR(namedb_type* db, const dname_type* dname,
	uint16_t type, uint16_t klass, uint32_t ttl,
	buffer_type* packet, size_t rdatalen, zone_type *zone,
	int is_axfr)
{
	domain_type* domain;
	rrset_type* rrset;
	rdata_atom_type *rdatas;
	rr_type *rrs_old;
	ssize_t rdata_num;
	int rrnum;
	domain = domain_table_find(db->domains, dname);
	if(!domain) {
		/* create the domain */
		domain = domain_table_insert(db->domains, dname);
	}
	rrset = domain_find_rrset(domain, zone, type);
	if(!rrset) {
		/* create the rrset */
		rrset = region_alloc(db->region, sizeof(rrset_type));
		if(!rrset) {
			log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
			exit(1);
		}
		rrset->zone = zone;
		rrset->rrs = 0;
		rrset->rr_count = 0;
		domain_add_rrset(domain, rrset);
	}

	/* dnames in rdata are normalized, conform RFC 4035,
	 * Section 6.2
	 */
	rdata_num = rdata_wireformat_to_rdata_atoms(
		db->region, db->domains, type, rdatalen, packet, &rdatas);
	if(rdata_num == -1) {
		log_msg(LOG_ERR, "diff: bad rdata for %s",
			dname_to_string(dname,0));
		return 0;
	}
	rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num);
	if(rrnum != -1) {
		DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists",
			dname_to_string(dname,0), rrtype_to_string(type)));
		/* ignore already existing RR: lenient accepting of messages */
		return 1;
	}

	/* re-alloc the rrs and add the new */
	rrs_old = rrset->rrs;
	rrset->rrs = region_alloc(db->region,
		(rrset->rr_count+1) * sizeof(rr_type));
	if(!rrset->rrs) {
		log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
		exit(1);
	}
	if(rrs_old)
		memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type));
	region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count);
	rrset->rr_count ++;

	rrset->rrs[rrset->rr_count - 1].owner = domain;
	rrset->rrs[rrset->rr_count - 1].rdatas = rdatas;
	rrset->rrs[rrset->rr_count - 1].ttl = ttl;
	rrset->rrs[rrset->rr_count - 1].type = type;
	rrset->rrs[rrset->rr_count - 1].klass = klass;
	rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num;

	/* see if it is a SOA */
	if(domain == zone->apex) {
		if(type == TYPE_SOA) {
			uint32_t soa_minimum;
			zone->soa_rrset = rrset;
			zone->updated = 1;
			/* BUG #103 tweaked SOA ttl value */
			if(zone->soa_nx_rrset == 0) {
				zone->soa_nx_rrset = region_alloc(db->region,
					sizeof(rrset_type));
				if(!zone->soa_nx_rrset) {
					log_msg(LOG_ERR, "out of memory, %s:%d",
						__FILE__, __LINE__);
					exit(1);
				}
				zone->soa_nx_rrset->rr_count = 1;
				zone->soa_nx_rrset->next = 0;
				zone->soa_nx_rrset->zone = zone;
				zone->soa_nx_rrset->rrs = region_alloc(db->region,
					sizeof(rr_type));
				if(!zone->soa_nx_rrset->rrs) {
					log_msg(LOG_ERR, "out of memory, %s:%d",
						__FILE__, __LINE__);
					exit(1);
				}
			}
			memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type));
			memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]),
				rdata_atom_size(rrset->rrs->rdatas[6]));
			if (rrset->rrs->ttl > ntohl(soa_minimum)) {
				rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum);
			}
			domain->has_SOA = 1;
		}
		if(type == TYPE_NS) {
			zone->ns_rrset = rrset;
		}
		if(type == TYPE_RRSIG) {
			int i;
			for (i = 0; i < rrset->rr_count; ++i) {
				if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) {
					zone->is_secure = 1;
					break;
				}
			}
		}
	}

#ifdef NSEC3
#ifndef FULL_PREHASH
	if ((type == TYPE_NSEC3) &&
	    (rrset->rr_count == 1)) {
		/* NSEC3 RRset just added */
		if (0 != namedb_add_nsec3_domain(db, domain, zone))
			return 0;
	}
	if (is_axfr == 0) {
		struct domain *parent = domain;
		do {
			if (0 != namedb_add_nsec3_mod_domain(db, parent))
				return 0;
			parent = parent->parent;
		} while (parent != zone->apex->parent);
	}
#else
	(void)is_axfr;
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

	return 1;
}
Пример #18
0
static int
delete_RR(namedb_type* db, const dname_type* dname,
	uint16_t type, uint16_t klass,
	domain_type* prevdomain,
	buffer_type* packet, size_t rdatalen, zone_type *zone,
	region_type* temp_region, int is_axfr)
{
	domain_type *domain;
	rrset_type *rrset;
	domain = domain_table_find(db->domains, dname);
	if(!domain) {
		log_msg(LOG_WARNING, "diff: domain %s does not exist",
			dname_to_string(dname,0));
		buffer_skip(packet, rdatalen);
		return 1; /* not fatal error */
	}
	rrset = domain_find_rrset(domain, zone, type);
	if(!rrset) {
		log_msg(LOG_WARNING, "diff: rrset %s does not exist",
			dname_to_string(dname,0));
		buffer_skip(packet, rdatalen);
		return 1; /* not fatal error */
	} else {
		/* find the RR in the rrset */
		domain_table_type *temptable;
		rdata_atom_type *rdatas;
		ssize_t rdata_num;
		int rrnum;
		temptable = domain_table_create(temp_region);
		/* This will ensure that the dnames in rdata are
		 * normalized, conform RFC 4035, section 6.2
		 */
		rdata_num = rdata_wireformat_to_rdata_atoms(
			temp_region, temptable, type, rdatalen, packet, &rdatas);
		if(rdata_num == -1) {
			log_msg(LOG_ERR, "diff: bad rdata for %s",
				dname_to_string(dname,0));
			return 0;
		}
		rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num);
		if(rrnum == -1) {
			log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist",
				dname_to_string(dname,0), rrtype_to_string(type));
			return 1; /* not fatal error */
		}
#ifdef NSEC3
#ifndef FULL_PREHASH
		if (is_axfr == 0) {
			struct domain *parent = domain;
			do {
				if (0 != namedb_add_nsec3_mod_domain(db,
								    parent)) {
					return 0;
				}
				parent = parent->parent;
			} while (parent != zone->apex->parent);
		}
#else
		(void)is_axfr;
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

		if(rrset->rr_count == 1) {
			/* delete entire rrset */
			domain = rrset_delete(db, domain, rrset);
			if (domain && domain != prevdomain && !domain->nextdiff) {
				/* this domain is not yet in the diff chain */
				prevdomain->nextdiff = domain;
			}
		} else {
			/* swap out the bad RR and decrease the count */
			rr_type* rrs_orig = rrset->rrs;
			add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]);
			if(rrnum < rrset->rr_count-1)
				rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1];
			memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type));
			/* realloc the rrs array one smaller */
			rrset->rrs = region_alloc_init(db->region, rrs_orig,
				sizeof(rr_type) * (rrset->rr_count-1));
			if(!rrset->rrs) {
				log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
				exit(1);
			}
			region_recycle(db->region, rrs_orig,
				sizeof(rr_type) * rrset->rr_count);
			rrset->rr_count --;
		}
	}
	return 1;
}
Пример #19
0
int
process_rr(void)
{
	zone_type *zone = parser->current_zone;
	rr_type *rr = &parser->current_rr;
	rrset_type *rrset;
	size_t max_rdlength;
	int i;
	rrtype_descriptor_type *descriptor
		= rrtype_descriptor_by_type(rr->type);

	/* We only support IN class */
	if (rr->klass != CLASS_IN) {
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("only class IN is supported");
		else
			zc_error_prev_line("only class IN is supported");
		return 0;
	}

	/* Make sure the maximum RDLENGTH does not exceed 65535 bytes.	*/
	max_rdlength = rdata_maximum_wireformat_size(
		descriptor, rr->rdata_count, rr->rdatas);

	if (max_rdlength > MAX_RDLENGTH) {
		zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH);
		return 0;
	}
	/* we have the zone already */
	assert(zone);
	if (rr->type == TYPE_SOA) {
		if (rr->owner != zone->apex) {
			zc_error_prev_line(
				"SOA record with invalid domain name");
			return 0;
		}
		if(has_soa(rr->owner)) {
			if(zone_is_slave(zone->opts))
				zc_warning_prev_line("this SOA record was already encountered");
			else
				zc_error_prev_line("this SOA record was already encountered");
			return 0;
		}
		rr->owner->is_apex = 1;
	}

	if (!domain_is_subdomain(rr->owner, zone->apex))
	{
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("out of zone data");
		else
			zc_error_prev_line("out of zone data");
		return 0;
	}

	/* Do we have this type of rrset already? */
	rrset = domain_find_rrset(rr->owner, zone, rr->type);
	if (!rrset) {
		rrset = (rrset_type *) region_alloc(parser->region,
						    sizeof(rrset_type));
		rrset->zone = zone;
		rrset->rr_count = 1;
		rrset->rrs = (rr_type *) region_alloc(parser->region,
						      sizeof(rr_type));
		rrset->rrs[0] = *rr;

		/* Add it */
		domain_add_rrset(rr->owner, rrset);
	} else {
		rr_type* o;
		if (rr->type != TYPE_RRSIG && rrset->rrs[0].ttl != rr->ttl) {
			zc_warning_prev_line(
				"%s TTL %u does not match the TTL %u of the %s RRset",
				domain_to_string(rr->owner), (unsigned)rr->ttl,
				(unsigned)rrset->rrs[0].ttl,
				rrtype_to_string(rr->type));
		}

		/* Search for possible duplicates... */
		for (i = 0; i < rrset->rr_count; i++) {
			if (!zrdatacmp(rr->type, rr, &rrset->rrs[i])) {
				break;
			}
		}

		/* Discard the duplicates... */
		if (i < rrset->rr_count) {
			return 0;
		}
		if(rrset->rr_count == 65535) {
			zc_error_prev_line("too many RRs for domain RRset");
			return 0;
		}

		/* Add it... */
		o = rrset->rrs;
		rrset->rrs = (rr_type *) region_alloc_array(parser->region,
			(rrset->rr_count + 1), sizeof(rr_type));
		memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type));
		region_recycle(parser->region, o,
			(rrset->rr_count) * sizeof(rr_type));
		rrset->rrs[rrset->rr_count] = *rr;
		++rrset->rr_count;
	}

	if(rr->type == TYPE_DNAME && rrset->rr_count > 1) {
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("multiple DNAMEs at the same name");
		else
			zc_error_prev_line("multiple DNAMEs at the same name");
	}
	if(rr->type == TYPE_CNAME && rrset->rr_count > 1) {
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("multiple CNAMEs at the same name");
		else
			zc_error_prev_line("multiple CNAMEs at the same name");
	}
	if((rr->type == TYPE_DNAME && domain_find_rrset(rr->owner, zone, TYPE_CNAME))
	 ||(rr->type == TYPE_CNAME && domain_find_rrset(rr->owner, zone, TYPE_DNAME))) {
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("DNAME and CNAME at the same name");
		else
			zc_error_prev_line("DNAME and CNAME at the same name");
	}
	if(domain_find_rrset(rr->owner, zone, TYPE_CNAME) &&
		domain_find_non_cname_rrset(rr->owner, zone)) {
		if(zone_is_slave(zone->opts))
			zc_warning_prev_line("CNAME and other data at the same name");
		else
			zc_error_prev_line("CNAME and other data at the same name");
	}

	/* Check we have SOA */
	if(rr->owner == zone->apex)
		apex_rrset_checks(parser->db, rrset, rr->owner);

	if(parser->line % ZONEC_PCT_COUNT == 0 && time(NULL) > startzonec + ZONEC_PCT_TIME) {
		struct stat buf;
		startzonec = time(NULL);
		buf.st_size = 0;
		fstat(fileno(yyin), &buf);
		if(buf.st_size == 0) buf.st_size = 1;
		VERBOSITY(1, (LOG_INFO, "parse %s %d %%",
			parser->current_zone->opts->name,
			(int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size)));
	}
	++totalrrs;
	return 1;
}