/* * 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; } }
/* * 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; } }
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; }
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; }