static int check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) { /* see if serial OK with in-memory serial */ domain_type* domain; region_type* region = region_create(xalloc, free); const dname_type* zone_name = dname_parse(region, zone_str); zone_type* zone = 0; domain = domain_table_find(db->domains, zone_name); if(domain) zone = domain_find_zone(domain); if(zone && zone->apex == domain && zone->soa_rrset && old_serial) { uint32_t memserial; memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), sizeof(uint32_t)); if(old_serial != ntohl(memserial)) { region_destroy(region); return 1; } } region_destroy(region); return 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)); }
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; }
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; }
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; }