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(¬->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)); }
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)); }
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; }
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); } }
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); } }
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; }
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)); }
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)); }
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); }
/* 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)); }
/** 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; } }
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)); }
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)); }
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, ¬exist)) { 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, ¬exist)) { 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; } } }
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; }
/* 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; }
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; }
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; }