Example #1
0
/*
 * Answer if this is an AXFR or IXFR query.
 */
query_state_type
answer_axfr_ixfr(struct nsd *nsd, struct query *q)
{
	struct acl_options *acl = NULL;
	/* Is it AXFR? */
	switch (q->qtype) {
	case TYPE_AXFR:
		if (q->tcp) {
			struct zone_options* zone_opt;
			zone_opt = zone_options_find(nsd->options, q->qname);
			if(!zone_opt ||
			   acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1)
			{
				if (verbosity >= 2) {
					char a[128];
					addr2str(&q->addr, a, sizeof(a));
					VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s",
						dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches"));
				}
				DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s",
					acl?"blocked":"no acl matches"));
				if (!zone_opt) {
					RCODE_SET(q->packet, RCODE_NOTAUTH);
				} else {
					RCODE_SET(q->packet, RCODE_REFUSE);
				}
				return QUERY_PROCESSED;
			}
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s",
				acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
			if (verbosity >= 1) {
				char a[128];
				addr2str(&q->addr, a, sizeof(a));
				VERBOSITY(1, (LOG_INFO, "%s for %s from %s",
					(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
					dname_to_string(q->qname, NULL), a));
			}
			return query_axfr(nsd, q);
		}
		/** Fallthrough: AXFR over UDP queries are discarded. */
		/* fallthrough */
	case TYPE_IXFR:
		RCODE_SET(q->packet, RCODE_IMPL);
		return QUERY_PROCESSED;
	default:
		return QUERY_DISCARDED;
	}
}
Example #2
0
/*
 * Answer if this is an AXFR or IXFR query.
 */
query_state_type
answer_axfr_ixfr(struct nsd *nsd, struct query *q)
{
	acl_options_t *acl;
	/* Is it AXFR? */
	switch (q->qtype) {
	case TYPE_AXFR:
		if (q->tcp) {
			zone_options_t* zone_opt;
			zone_opt = zone_options_find(nsd->options, q->qname);
			if(!zone_opt ||
			   acl_check_incoming(zone_opt->provide_xfr, q, &acl)==-1)
			{
				if (verbosity > 0) {
					char address[128];
					if (addr2ip(q->addr, address, sizeof(address))) {
						DEBUG(DEBUG_XFRD,1, (LOG_INFO,
							"addr2ip failed"));
						strlcpy(address, "[unknown]", sizeof(address));
					}
					VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s",
						dname_to_string(q->qname, NULL), address, acl?"blocked":"no acl matches"));
				}
				DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s",
					acl?"blocked":"no acl matches"));
				if (!zone_opt) {
					RCODE_SET(q->packet, RCODE_NOTAUTH);
				} else {
					RCODE_SET(q->packet, RCODE_REFUSE);
				}
				return QUERY_PROCESSED;
			}
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s",
				acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
			return query_axfr(nsd, q);
		}
	case TYPE_IXFR:
		RCODE_SET(q->packet, RCODE_IMPL);
		return QUERY_PROCESSED;
	default:
		return QUERY_DISCARDED;
	}
}
Example #3
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;
}
Example #4
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;
}