예제 #1
0
/** create and write a zone */
int
write_zone_to_udb(udb_base* udb, zone_type* zone, struct timespec* mtime,
	const char* file_str)
{
	udb_ptr z;
	/* make udb dirty */
	udb_base_set_userflags(udb, 1);
	/* find or create zone */
	if(udb_zone_search(udb, &z, dname_name(domain_dname(zone->apex)),
		domain_dname(zone->apex)->name_size)) {
		/* wipe existing contents */
		udb_zone_clear(udb, &z);
	} else {
		if(!udb_zone_create(udb, &z, dname_name(domain_dname(
			zone->apex)), domain_dname(zone->apex)->name_size)) {
			udb_base_set_userflags(udb, 0);
			return 0;
		}
	}
	/* set mtime */
	ZONE(&z)->mtime = (uint64_t)mtime->tv_sec;
	ZONE(&z)->mtime_nsec = (uint64_t)mtime->tv_nsec;
	ZONE(&z)->is_changed = 0;
	udb_zone_set_log_str(udb, &z, NULL);
	udb_zone_set_file_str(udb, &z, file_str);
	/* write zone */
	if(!write_zone(udb, &z, zone)) {
		udb_base_set_userflags(udb, 0);
		return 0;
	}
	udb_ptr_unlink(&z, udb);
	udb_base_set_userflags(udb, 0);
	return 1;
}
예제 #2
0
static void
encode_dname(query_type *q, domain_type *domain)
{
	while (domain->parent && query_get_dname_offset(q, domain) == 0) {
		query_put_dname_offset(q, domain, buffer_position(q->packet));
		DEBUG(DEBUG_NAME_COMPRESSION, 2,
		      (LOG_INFO, "dname: %s, number: %lu, offset: %u\n",
		       dname_to_string(domain_dname(domain), NULL),
		       (unsigned long) domain->number,
		       query_get_dname_offset(q, domain)));
		buffer_write(q->packet, dname_name(domain_dname(domain)),
			     label_length(dname_name(domain_dname(domain))) + 1U);
		domain = domain->parent;
	}
	if (domain->parent) {
		DEBUG(DEBUG_NAME_COMPRESSION, 2,
		      (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n",
		       dname_to_string(domain_dname(domain), NULL),
		       (unsigned long) domain->number,
		       query_get_dname_offset(q, domain)));
		assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET);
		buffer_write_u16(q->packet,
				 0xc000 | query_get_dname_offset(q, domain));
	} else {
		buffer_write_u8(q->packet, 0);
	}
}
예제 #3
0
/** delete an RR */
void
udb_del_rr(udb_base* udb, udb_ptr* z, rr_type* rr)
{
	/* marshal the rdata (uncompressed) into a buffer */
	uint8_t rdata[MAX_RDLENGTH];
	size_t rdatalen = rr_marshal_rdata(rr, rdata, sizeof(rdata));
	assert(udb);
	udb_zone_del_rr(udb, z, dname_name(domain_dname(rr->owner)),
		domain_dname(rr->owner)->name_size, rr->type, rr->klass,
		rdata, rdatalen);
}
예제 #4
0
static void
delete_zone_rrs(namedb_type* db, zone_type* zone)
{
	rrset_type *rrset;
	domain_type *domain = zone->apex;
	domain_type *next = NULL;
	zone->updated = 1;
#ifdef NSEC3
#ifndef FULL_PREHASH
	zone_nsec3_domains_destroy(db, zone);
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

	/* go through entire tree below the zone apex (incl subzones) */
	while(domain && dname_is_subdomain(
		domain_dname(domain), domain_dname(zone->apex)))
	{
		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s",
			dname_to_string(domain_dname(domain),0)));
		/* delete all rrsets of the zone */
		while((rrset = domain_find_any_rrset(domain, zone))) {
			(void)rrset_delete(db, domain, rrset);
		}
		next = domain_next(domain);
		domain->nextdiff = next;
		domain = next;
	}
#ifdef NSEC3
#ifndef FULL_PREHASH
	if (0 != zone_nsec3_domains_create(db, zone)) {
		log_msg(LOG_ERR,
			"Zone %s: unable to create zone NSEC3 prehash table",
			dname_to_string(domain_dname(zone->apex),
			NULL));
	}
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */

	DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes",
		(unsigned long) region_get_recycle_size(db->region)));
#ifndef NDEBUG
	if(nsd_debug_level >= 1)
		region_log_stats(db->region);
#endif

	assert(zone->soa_rrset == 0);
	/* keep zone->soa_nx_rrset alloced */
	assert(zone->ns_rrset == 0);
	assert(zone->is_secure == 0);
	assert(zone->updated == 1);
}
예제 #5
0
/* this routine determines if below a domain there exist names with
 * data (is_existing) or no names below the domain have data.
 */
static int
has_data_below(domain_type* top)
{
	domain_type* d = top;
	assert(d != NULL);
	/* in the canonical ordering subdomains are after this name */
	d = domain_next(d);
	while(d != NULL && dname_is_subdomain(domain_dname(d), domain_dname(top))) {
		if(d->is_existing)
			return 1;
		d = domain_next(d);
	}
	return 0;
}
예제 #6
0
int
packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr)
{
	size_t truncation_mark;
	uint16_t rdlength = 0;
	size_t rdlength_pos;
	uint16_t j;

	assert(q);
	assert(owner);
	assert(rr);

	/*
	 * If the record does not in fit in the packet the packet size
	 * will be restored to the mark.
	 */
	truncation_mark = buffer_position(q->packet);

	encode_dname(q, owner);
	buffer_write_u16(q->packet, rr->type);
	buffer_write_u16(q->packet, rr->klass);
	buffer_write_u32(q->packet, rr->ttl);

	/* Reserve space for rdlength. */
	rdlength_pos = buffer_position(q->packet);
	buffer_skip(q->packet, sizeof(rdlength));

	for (j = 0; j < rr->rdata_count; ++j) {
		switch (rdata_atom_wireformat_type(rr->type, j)) {
		case RDATA_WF_COMPRESSED_DNAME:
			encode_dname(q, rdata_atom_domain(rr->rdatas[j]));
			break;
		case RDATA_WF_UNCOMPRESSED_DNAME:
		{
			const dname_type *dname = domain_dname(
				rdata_atom_domain(rr->rdatas[j]));
			buffer_write(q->packet,
				     dname_name(dname), dname->name_size);
			break;
		}
		default:
			buffer_write(q->packet,
				     rdata_atom_data(rr->rdatas[j]),
				     rdata_atom_size(rr->rdatas[j]));
			break;
		}
	}

	if (!query_overflow(q)) {
		rdlength = (buffer_position(q->packet) - rdlength_pos
			    - sizeof(rdlength));
		buffer_write_u16_at(q->packet, rdlength_pos, rdlength);
		return 1;
	} else {
		buffer_set_position(q->packet, truncation_mark);
		query_clear_dname_offsets(q, truncation_mark);
		assert(!query_overflow(q));
		return 0;
	}
}
예제 #7
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;
}
예제 #8
0
/** write rr */
int
udb_write_rr(udb_base* udb, udb_ptr* z, rr_type* rr)
{
	/* marshal the rdata (uncompressed) into a buffer */
	uint8_t rdata[MAX_RDLENGTH];
	size_t rdatalen = 0;
	unsigned i;
	assert(rr);
	for(i=0; i<rr->rdata_count; i++) {
		rdatalen += add_rdata(rr, i, rdata+rdatalen,
			sizeof(rdata)-rdatalen);
	}
	assert(udb);
	return udb_zone_add_rr(udb, z, dname_name(domain_dname(rr->owner)),
		domain_dname(rr->owner)->name_size, rr->type, rr->klass,
		rr->ttl, rdata, rdatalen);
}
예제 #9
0
static int
rdata_dname_to_string(buffer_type *output, rdata_atom_type rdata,
	rr_type* ATTR_UNUSED(rr))
{
	buffer_printf(output,
		      "%s",
		      dname_to_string(domain_dname(rdata_atom_domain(rdata)),
				      NULL));
	return 1;
}
예제 #10
0
/** setup for string parse */
void
zonec_setup_string_parser(region_type* region, domain_table_type* domains)
{
	assert(parser); /* global parser must be setup */
	orig_domains = parser->db->domains;
	orig_region = parser->region;
	orig_dbregion = parser->db->region;
	parser->region = region;
	parser->db->region = region;
	parser->db->domains = domains;
	zparser_init("string", 3600, CLASS_IN, domain_dname(domains->root));
}
예제 #11
0
static int
rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type)
{
	int k;
	for(k = 0; k < num; k++)
	{
		if(rdata_atom_is_domain(type, k)) {
			if(dname_compare(domain_dname(a[k].domain),
				domain_dname(b[k].domain))!=0)
				return 0;
		} else {
			/* check length */
			if(a[k].data[0] != b[k].data[0])
				return 0;
			/* check data */
			if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0)
				return 0;
		}
	}
	return 1;
}
예제 #12
0
void
xfrd_copy_soa(xfrd_soa_t* soa, rr_type* rr)
{
	const uint8_t* rr_ns_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[0])));
	uint8_t rr_ns_len = domain_dname(rdata_atom_domain(rr->rdatas[0]))->name_size;
	const uint8_t* rr_em_wire = dname_name(domain_dname(rdata_atom_domain(rr->rdatas[1])));
	uint8_t rr_em_len = domain_dname(rdata_atom_domain(rr->rdatas[1]))->name_size;

	if(rr->type != TYPE_SOA || rr->rdata_count != 7) {
		log_msg(LOG_ERR, "xfrd: copy_soa called with bad rr, type %d rrs %u.",
			rr->type, rr->rdata_count);
		return;
	}
	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: copy_soa rr, type %d rrs %u, ttl %u.",
			rr->type, rr->rdata_count, rr->ttl));
	soa->type = htons(rr->type);
	soa->klass = htons(rr->klass);
	soa->ttl = htonl(rr->ttl);
	soa->rdata_count = htons(rr->rdata_count);

	/* copy dnames */
	soa->prim_ns[0] = rr_ns_len;
	memcpy(soa->prim_ns+1, rr_ns_wire, rr_ns_len);
	soa->email[0] = rr_em_len;
	memcpy(soa->email+1, rr_em_wire, rr_em_len);

	/* already in network format */
	memcpy(&soa->serial, rdata_atom_data(rr->rdatas[2]), sizeof(uint32_t));
	memcpy(&soa->refresh, rdata_atom_data(rr->rdatas[3]), sizeof(uint32_t));
	memcpy(&soa->retry, rdata_atom_data(rr->rdatas[4]), sizeof(uint32_t));
	memcpy(&soa->expire, rdata_atom_data(rr->rdatas[5]), sizeof(uint32_t));
	memcpy(&soa->minimum, rdata_atom_data(rr->rdatas[6]), sizeof(uint32_t));
	DEBUG(DEBUG_XFRD,1, (LOG_INFO,
		"xfrd: copy_soa rr, serial %u refresh %u retry %u expire %u",
		ntohl(soa->serial), ntohl(soa->refresh), ntohl(soa->retry),
		ntohl(soa->expire)));
}
예제 #13
0
size_t
rdata_maximum_wireformat_size(rrtype_descriptor_type *descriptor,
			      size_t rdata_count,
			      rdata_atom_type *rdatas)
{
	size_t result = 0;
	size_t i;
	for (i = 0; i < rdata_count; ++i) {
		if (rdata_atom_is_domain(descriptor->type, i)) {
			result += domain_dname(rdata_atom_domain(rdatas[i]))->name_size;
		} else {
			result += rdata_atom_size(rdatas[i]);
		}
	}
	return result;
}
예제 #14
0
int
rdata_atoms_to_unknown_string(buffer_type *output,
			      rrtype_descriptor_type *descriptor,
			      size_t rdata_count,
			      rdata_atom_type *rdatas)
{
	size_t i;
	size_t size =
		rdata_maximum_wireformat_size(descriptor, rdata_count, rdatas);
	buffer_printf(output, " \\# %lu ", (unsigned long) size);
	for (i = 0; i < rdata_count; ++i) {
		if (rdata_atom_is_domain(descriptor->type, i)) {
			const dname_type *dname =
				domain_dname(rdata_atom_domain(rdatas[i]));
			hex_to_string(
				output, dname_name(dname), dname->name_size);
		} else {
			hex_to_string(output, rdata_atom_data(rdatas[i]),
				rdata_atom_size(rdatas[i]));
		}
	}
	return 1;
}
예제 #15
0
/** add an rdata (uncompressed) to the destination */
static size_t
add_rdata(rr_type* rr, unsigned i, uint8_t* buf, size_t buflen)
{
	switch(rdata_atom_wireformat_type(rr->type, i)) {
		case RDATA_WF_COMPRESSED_DNAME:
		case RDATA_WF_UNCOMPRESSED_DNAME:
		{
			const dname_type* dname = domain_dname(
				rdata_atom_domain(rr->rdatas[i]));
			if(dname->name_size > buflen)
				return 0;
			memmove(buf, dname_name(dname), dname->name_size);
			return dname->name_size;
		}
		default:
			break;
	}
	if(rdata_atom_size(rr->rdatas[i]) > buflen)
		return 0;
	memmove(buf, rdata_atom_data(rr->rdatas[i]),
		rdata_atom_size(rr->rdatas[i]));
	return rdata_atom_size(rr->rdatas[i]);
}
예제 #16
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;
}
예제 #17
0
/*
 * Reads the specified zone into the memory
 * nsd_options can be NULL if no config file is passed.
 */
unsigned int
zonec_read(const char* name, const char* zonefile, zone_type* zone)
{
	const dname_type *dname;

	totalrrs = 0;
	startzonec = time(NULL);
	parser->errors = 0;

	dname = dname_parse(parser->rr_region, name);
	if (!dname) {
		zc_error("incorrect zone name '%s'", name);
		return 1;
	}

#ifndef ROOT_SERVER
	/* Is it a root zone? Are we a root server then? Idiot proof. */
	if (dname->label_count == 1) {
		zc_error("not configured as a root server");
		return 1;
	}
#endif

	/* Open the zone file */
	if (!zone_open(zonefile, 3600, CLASS_IN, dname)) {
		zc_error("cannot open '%s': %s", zonefile, strerror(errno));
		return 1;
	}
	parser->current_zone = zone;

	/* Parse and process all RRs.  */
	yyparse();

	/* remove origin if it was unused */
	if(parser->origin != error_domain)
		domain_table_deldomain(parser->db, parser->origin);
	/* rr_region has been emptied by now */
	dname = dname_parse(parser->rr_region, name);

	/* check if zone file contained a correct SOA record */
	if (!parser->current_zone) {
		zc_error("zone configured as '%s' has no content.", name);
	} else if(!parser->current_zone->soa_rrset ||
		parser->current_zone->soa_rrset->rr_count == 0) {
		zc_error("zone configured as '%s' has no SOA record.", name);
	} else if(dname_compare(domain_dname(
		parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) {
		zc_error("zone configured as '%s', but SOA has owner '%s'.",
			name, domain_to_string(
			parser->current_zone->soa_rrset->rrs[0].owner));
	}
	region_free_all(parser->rr_region);

	parser_flush();
	fclose(yyin);
	if(!zone_is_slave(zone->opts))
		check_dname(zone);

	parser->filename = NULL;
	return parser->errors;
}
예제 #18
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;
		}
	}
}
예제 #19
0
static void
xfrd_init_zones()
{
	zone_type *dbzone;
	zone_options_t *zone_opt;
	xfrd_zone_t *xzone;
	const dname_type* dname;

	assert(xfrd->zones == 0);
	assert(xfrd->nsd->db != 0);

	xfrd->zones = rbtree_create(xfrd->region,
		(int (*)(const void *, const void *)) dname_compare);
	xfrd->notify_zones = rbtree_create(xfrd->region,
		(int (*)(const void *, const void *)) dname_compare);

	RBTREE_FOR(zone_opt, zone_options_t*, xfrd->nsd->options->zone_options)
	{
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Zone %s\n", zone_opt->name));
		dname = dname_parse(xfrd->region, zone_opt->name);
		if(!dname) {
			log_msg(LOG_ERR, "xfrd: Could not parse zone name %s.", zone_opt->name);
			continue;
		}

		dbzone = domain_find_zone(domain_table_find(xfrd->nsd->db->domains, dname));
		if(dbzone && dname_compare(dname, domain_dname(dbzone->apex)) != 0)
			dbzone = 0; /* we found a parent zone */
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: adding %s zone %s\n",
			dbzone?"filled":"empty", zone_opt->name));

		init_notify_send(xfrd->notify_zones, xfrd->netio,
			xfrd->region, dname, zone_opt, dbzone);
		if(!zone_is_slave(zone_opt)) {
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, master zone has no outgoing xfr requests", zone_opt->name));
			continue;
		}

		xzone = (xfrd_zone_t*)region_alloc(xfrd->region, sizeof(xfrd_zone_t));
		memset(xzone, 0, sizeof(xfrd_zone_t));
		xzone->apex = dname;
		xzone->apex_str = zone_opt->name;
		xzone->state = xfrd_zone_refreshing;
		xzone->dirty = 0;
		xzone->zone_options = zone_opt;
		/* first retry will use first master */
		xzone->master = 0;
		xzone->master_num = 0;
		xzone->next_master = 0;
		xzone->fresh_xfr_timeout = XFRD_TRANSFER_TIMEOUT_START;

		xzone->soa_nsd_acquired = 0;
		xzone->soa_disk_acquired = 0;
		xzone->soa_notified_acquired = 0;
		/* [0]=1, [1]=0; "." domain name */
		xzone->soa_nsd.prim_ns[0] = 1;
		xzone->soa_nsd.email[0] = 1;
		xzone->soa_disk.prim_ns[0]=1;
		xzone->soa_disk.email[0]=1;
		xzone->soa_notified.prim_ns[0]=1;
		xzone->soa_notified.email[0]=1;

		xzone->zone_handler.fd = -1;
		xzone->zone_handler.timeout = 0;
		xzone->zone_handler.user_data = xzone;
		xzone->zone_handler.event_types =
			NETIO_EVENT_READ|NETIO_EVENT_TIMEOUT;
		xzone->zone_handler.event_handler = xfrd_handle_zone;
		netio_add_handler(xfrd->netio, &xzone->zone_handler);
		xzone->tcp_conn = -1;
		xzone->tcp_waiting = 0;
		xzone->udp_waiting = 0;

		tsig_create_record_custom(&xzone->tsig, xfrd->region, 0, 0, 4);

		if(dbzone && dbzone->soa_rrset && dbzone->soa_rrset->rrs) {
			xzone->soa_nsd_acquired = xfrd_time();
			xzone->soa_disk_acquired = xfrd_time();
			/* we only use the first SOA in the rrset */
			xfrd_copy_soa(&xzone->soa_nsd, dbzone->soa_rrset->rrs);
			xfrd_copy_soa(&xzone->soa_disk, dbzone->soa_rrset->rrs);
		}
		/* set refreshing anyway, we have data but it may be old */
		xfrd_set_refresh_now(xzone);

		xzone->node.key = dname;
		rbtree_insert(xfrd->zones, (rbnode_t*)xzone);
	}
	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: started server %d secondary zones", (int)xfrd->zones->count));
}
예제 #20
0
static zone_type*
find_zone(namedb_type* db, const dname_type* zone_name, nsd_options_t* opt,
	size_t child_count)
{
	domain_type *domain;
	zone_type* zone;
	zone_options_t* opts;
	domain = domain_table_find(db->domains, zone_name);
	if(!domain) {
		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating domain %s",
			dname_to_string(zone_name,0)));
		/* create the zone and domain of apex (zone has config options) */
		domain = domain_table_insert(db->domains, zone_name);
	} else {
		/* O(1) if SOA exists */
		zone = domain_find_zone(domain);
		/* if domain was empty (no rrsets, empty zone) search in zonelist */
		/* check apex to make sure we don't find a parent zone */
		if(!zone || zone->apex != domain)
			zone = namedb_find_zone(db, domain);
		if(zone) {
			assert(zone->apex == domain);
			return zone;
		}
	}
	/* lookup in config */
	opts = zone_options_find(opt, domain_dname(domain));
	if(!opts) {
		log_msg(LOG_ERR, "xfr: zone %s not in config.",
			dname_to_string(zone_name,0));
		return 0;
	}
	/* create the zone */
	DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating zone_type %s",
		dname_to_string(zone_name,0)));
	zone = (zone_type *) region_alloc(db->region, sizeof(zone_type));
	if(!zone) {
		log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
		exit(1);
	}
	zone->next = db->zones;
	zone->opts = opts;
	db->zones = zone;
	db->zone_count++;
	zone->apex = domain;
	zone->soa_rrset = 0;
	zone->soa_nx_rrset = 0;
	zone->ns_rrset = 0;
#ifdef NSEC3
	zone->nsec3_soa_rr = NULL;
	zone->nsec3_last = NULL;
#endif
	zone->dirty = region_alloc(db->region, sizeof(uint8_t)*child_count);
	if(!zone->dirty) {
		log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
		exit(1);
	}
	memset(zone->dirty, 0, sizeof(uint8_t)*child_count);
#ifdef NSEC3
#ifndef FULL_PREHASH
	zone->nsec3_domains = NULL;

	if (0 != zone_nsec3_domains_create(db, zone)) {
		log_msg(LOG_ERR,
			"xfr: zone NSEC3 domains "
			"memory allocation failure");
		return 0;
	}
#endif /* !FULL_PREHASH */
#endif /* NSEC3 */
	zone->number = db->zone_count;
	zone->is_secure = 0;
	zone->updated = 1;
	zone->is_ok = 0;
	return zone;
}
예제 #21
0
int
print_rr(FILE *out,
         struct state_pretty_rr *state,
         rr_type *record)
{
	region_type *region = region_create(xalloc, free);
        buffer_type *output = buffer_create(region, MAX_RDLENGTH);
        rrtype_descriptor_type *descriptor
                = rrtype_descriptor_by_type(record->type);
        int result;
        const dname_type *owner = domain_dname(record->owner);
        const dname_type *owner_origin
                = dname_origin(region, owner);
        int owner_changed
                = (!state->previous_owner
                   || dname_compare(state->previous_owner, owner) != 0);
        if (owner_changed) {
                int origin_changed = (!state->previous_owner_origin
                                      || dname_compare(
                                              state->previous_owner_origin,
                                              owner_origin) != 0);
                if (origin_changed) {
                        buffer_printf(
                                output,
                                "$ORIGIN %s\n",
                                dname_to_string(owner_origin, NULL));
                }

                set_previous_owner(state, owner);
                buffer_printf(output,
                              "%s",
                              dname_to_string(owner,
                                              state->previous_owner_origin));
        }

        buffer_printf(output,
                      "\t%lu\t%s\t%s",
                      (unsigned long) record->ttl,
                      rrclass_to_string(record->klass),
                      rrtype_to_string(record->type));

        result = print_rdata(output, descriptor, record);
        if (!result) {
                /*
                 * Some RDATA failed to print, so print the record's
                 * RDATA in unknown format.
                 */
                result = rdata_atoms_to_unknown_string(output,
                                                       descriptor,
                                                       record->rdata_count,
                                                       record->rdatas);
        }

        if (result) {
                buffer_printf(output, "\n");
                buffer_flip(output);
		(void)write_data(out, buffer_current(output), buffer_remaining(output));
/*              fflush(out); */
        }

	region_destroy(region);
        return result;
}
예제 #22
0
/** classify the query in a number of different types, each has separate
 * ratelimiting, so that positive queries are not impeded by others */
static uint16_t rrl_classify(query_type* query, const uint8_t** d,	
	size_t* d_len)
{
	if(RCODE(query->packet) == RCODE_NXDOMAIN) {
		if(query->zone && query->zone->apex) {
			*d = dname_name(domain_dname(query->zone->apex));
			*d_len = domain_dname(query->zone->apex)->name_size;
		}
		return rrl_type_nxdomain;
	}
	if(RCODE(query->packet) != RCODE_OK) {
		if(query->zone && query->zone->apex) {
			*d = dname_name(domain_dname(query->zone->apex));
			*d_len = domain_dname(query->zone->apex)->name_size;
		}
		return rrl_type_error;
	}
	if(query->delegation_domain) {
		*d = dname_name(domain_dname(query->delegation_domain));
		*d_len = domain_dname(query->delegation_domain)->name_size;
		return rrl_type_referral;
	}
	if(query->qtype == TYPE_ANY) {
		if(query->qname) {
			*d = dname_name(query->qname);
			*d_len = query->qname->name_size;
		}
		return rrl_type_any;
	}
	if(query->qtype == TYPE_RRSIG) {
		if(query->qname) {
			*d = dname_name(query->qname);
			*d_len = query->qname->name_size;
		}
		return rrl_type_rrsig;
	}
	if(query->wildcard_domain) {
		*d = dname_name(domain_dname(query->wildcard_domain));
		*d_len = domain_dname(query->wildcard_domain)->name_size;
		return rrl_type_wildcard;
	}
	if(ANCOUNT(query->packet) == 0) {
		if(query->zone && query->zone->apex) {
			*d = dname_name(domain_dname(query->zone->apex));
			*d_len = domain_dname(query->zone->apex)->name_size;
		}
		return rrl_type_nodata;
	}
	if(query->qtype == TYPE_DNSKEY) {
		if(query->qname) {
			*d = dname_name(query->qname);
			*d_len = query->qname->name_size;
		}
		return rrl_type_dnskey;
	}
	/* positive */
	if(query->qname) {
		*d = dname_name(query->qname);
		*d_len = query->qname->name_size;
	}
	return rrl_type_positive;
}