diff options
Diffstat (limited to 'usr.sbin/nsd/udbzone.c')
-rw-r--r-- | usr.sbin/nsd/udbzone.c | 786 |
1 files changed, 786 insertions, 0 deletions
diff --git a/usr.sbin/nsd/udbzone.c b/usr.sbin/nsd/udbzone.c new file mode 100644 index 00000000000..bd5929b3929 --- /dev/null +++ b/usr.sbin/nsd/udbzone.c @@ -0,0 +1,786 @@ +/* + * udbzone -- store zone and rrset information in udb file. + * + * Copyright (c) 2011, NLnet Labs. See LICENSE for license. + */ +#include "config.h" +#include "udbzone.h" +#include "util.h" +#include "iterated_hash.h" +#include "dns.h" +#include "dname.h" +#include "difffile.h" +#include <string.h> + +/** delete the zone plain its own data */ +static void +udb_zone_delete_plain(udb_base* udb, udb_ptr* zone) +{ + udb_ptr dtree; + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + udb_zone_clear(udb, zone); + udb_rptr_zero(&ZONE(zone)->node, udb); + udb_rptr_zero(&ZONE(zone)->nsec3param, udb); + udb_rptr_zero(&ZONE(zone)->log_str, udb); + udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); + udb_rptr_zero(&ZONE(zone)->domains, udb); + udb_radix_tree_delete(udb, &dtree); + udb_ptr_free_space(zone, udb, + sizeof(struct zone_d)+ZONE(zone)->namelen); +} + +int +udb_dns_init_file(udb_base* udb) +{ + udb_ptr ztree; + if(!udb_radix_tree_create(udb, &ztree)) { + return 0; + } + udb_base_set_userdata(udb, ztree.data); + udb_ptr_unlink(&ztree, udb); + return 1; +} + +void +udb_dns_deinit_file(udb_base* udb) +{ + udb_ptr ztree; + udb_ptr z; + udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); + if(udb_ptr_is_null(&ztree)) { + return; + } + assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); + /* delete all zones */ + for(udb_radix_first(udb, &ztree, &z); z.data; udb_radix_next(udb, &z)){ + udb_ptr zone; + udb_ptr_new(&zone, udb, &RADNODE(&z)->elem); + udb_rptr_zero(&RADNODE(&z)->elem, udb); + udb_zone_delete_plain(udb, &zone); + } + udb_ptr_unlink(&z, udb); + + udb_base_set_userdata(udb, 0); + udb_radix_tree_delete(udb, &ztree); +} + +int +udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname, + size_t dlen) +{ + udb_ptr ztree, z, node, dtree; + udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); + assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); + udb_ptr_init(result, udb); + if(udb_zone_search(udb, &z, dname, dlen)) { + udb_ptr_unlink(&ztree, udb); + udb_ptr_unlink(&z, udb); + /* duplicate */ + return 0; + } + if(!udb_ptr_alloc_space(&z, udb, udb_chunk_type_zone, + sizeof(struct zone_d)+dlen)) { + udb_ptr_unlink(&ztree, udb); + /* failed alloc */ + return 0; + } + /* init the zone object */ + udb_rel_ptr_init(&ZONE(&z)->node); + udb_rel_ptr_init(&ZONE(&z)->domains); + udb_rel_ptr_init(&ZONE(&z)->nsec3param); + udb_rel_ptr_init(&ZONE(&z)->log_str); + ZONE(&z)->rrset_count = 0; + ZONE(&z)->rr_count = 0; + ZONE(&z)->expired = 0; + ZONE(&z)->mtime = 0; + ZONE(&z)->namelen = dlen; + memmove(ZONE(&z)->name, dname, dlen); + if(!udb_radix_tree_create(udb, &dtree)) { + udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); + udb_ptr_unlink(&ztree, udb); + /* failed alloc */ + return 0; + } + udb_rptr_set_ptr(&ZONE(&z)->domains, udb, &dtree); + + /* insert it */ + if(!udb_radname_insert(udb, &ztree, dname, dlen, &z, &node)) { + udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); + udb_ptr_unlink(&ztree, udb); + udb_radix_tree_delete(udb, &dtree); + udb_ptr_unlink(&dtree, udb); + /* failed alloc */ + return 0; + } + udb_rptr_set_ptr(&ZONE(&z)->node, udb, &node); + udb_ptr_set_ptr(result, udb, &z); + udb_ptr_unlink(&z, udb); + udb_ptr_unlink(&dtree, udb); + udb_ptr_unlink(&ztree, udb); + udb_ptr_unlink(&node, udb); + return 1; +} + +/** delete an RR */ +static void +rr_delete(udb_base* udb, udb_ptr* rr) +{ + assert(udb_ptr_get_type(rr) == udb_chunk_type_rr); + udb_rptr_zero(&RR(rr)->next, udb); + udb_ptr_free_space(rr, udb, sizeof(struct rr_d)+RR(rr)->len); +} + +/** delete an rrset */ +static void +rrset_delete(udb_base* udb, udb_ptr* rrset) +{ + udb_ptr rr, n; + assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); + + /* free RRs */ + udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); + udb_ptr_init(&n, udb); + udb_rptr_zero(&RRSET(rrset)->rrs, udb); + while(!udb_ptr_is_null(&rr)) { + udb_ptr_set_rptr(&n, udb, &RR(&rr)->next); + rr_delete(udb, &rr); + udb_ptr_set_ptr(&rr, udb, &n); + udb_ptr_zero(&n, udb); + } + udb_ptr_unlink(&n, udb); + udb_ptr_unlink(&rr, udb); + + udb_rptr_zero(&RRSET(rrset)->next, udb); + udb_ptr_free_space(rrset, udb, sizeof(struct rrset_d)); +} + +/** clear a domain of its rrsets, rrs */ +static void +domain_clear(udb_base* udb, udb_ptr* d) +{ + udb_ptr rrset, n; + assert(udb_ptr_get_type(d) == udb_chunk_type_domain); + udb_ptr_new(&rrset, udb, &DOMAIN(d)->rrsets); + udb_ptr_init(&n, udb); + udb_rptr_zero(&DOMAIN(d)->rrsets, udb); + while(!udb_ptr_is_null(&rrset)) { + udb_ptr_set_rptr(&n, udb, &RRSET(&rrset)->next); + rrset_delete(udb, &rrset); + udb_ptr_set_ptr(&rrset, udb, &n); + udb_ptr_zero(&n, udb); + } + udb_ptr_unlink(&n, udb); + udb_ptr_unlink(&rrset, udb); +} + +/** delete a domain and all its rrsets, rrs */ +static void +domain_delete(udb_base* udb, udb_ptr* d) +{ + domain_clear(udb, d); + udb_rptr_zero(&DOMAIN(d)->node, udb); + udb_ptr_free_space(d, udb, + sizeof(struct domain_d)+DOMAIN(d)->namelen); +} + +/** delete domain but also unlink from tree at zone */ +static void +domain_delete_unlink(udb_base* udb, udb_ptr* z, udb_ptr* d) +{ + udb_ptr dtree, n; + udb_ptr_new(&dtree, udb, &ZONE(z)->domains); + udb_ptr_new(&n, udb, &DOMAIN(d)->node); + udb_rptr_zero(&DOMAIN(d)->node, udb); + udb_radix_delete(udb, &dtree, &n); + udb_ptr_unlink(&dtree, udb); + udb_ptr_unlink(&n, udb); + domain_delete(udb, d); +} + +void +udb_zone_clear(udb_base* udb, udb_ptr* zone) +{ + udb_ptr dtree, d; + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); + udb_rptr_zero(&ZONE(zone)->nsec3param, udb); + udb_zone_set_log_str(udb, zone, NULL); + + /* walk and delete all domains, rrsets, rrs, but keep tree */ + for(udb_radix_first(udb, &dtree, &d); d.data; udb_radix_next(udb, &d)){ + udb_ptr domain; + udb_ptr_new(&domain, udb, &RADNODE(&d)->elem); + udb_rptr_zero(&RADNODE(&d)->elem, udb); + domain_delete(udb, &domain); + } + udb_ptr_unlink(&d, udb); + udb_radix_tree_clear(udb, &dtree); + ZONE(zone)->rrset_count = 0; + ZONE(zone)->rr_count = 0; + ZONE(zone)->expired = 0; + ZONE(zone)->mtime = 0; + udb_ptr_unlink(&dtree, udb); +} + +void +udb_zone_delete(udb_base* udb, udb_ptr* zone) +{ + udb_ptr ztree, n; + udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); + udb_ptr_new(&n, udb, &ZONE(zone)->node); + udb_rptr_zero(&ZONE(zone)->node, udb); + udb_radix_delete(udb, &ztree, &n); + udb_ptr_unlink(&ztree, udb); + udb_ptr_unlink(&n, udb); + udb_zone_delete_plain(udb, zone); +} + +int +udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname, + size_t dname_len) +{ + udb_ptr ztree; + udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); + assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); + if(udb_radname_search(udb, &ztree, dname, dname_len, result)) { + if(result->data) + udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); + udb_ptr_unlink(&ztree, udb); + return (result->data != 0); + } + udb_ptr_unlink(&ztree, udb); + return 0; +} + +uint64_t udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen) +{ + udb_ptr z; + if(udb_zone_search(udb, &z, dname, dlen)) { + uint64_t t = ZONE(&z)->mtime; + udb_ptr_unlink(&z, udb); + return t; + } + return 0; +} + +void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str) +{ + /* delete original log str (if any) */ + if(ZONE(zone)->log_str.data) { + udb_ptr s; + size_t sz; + udb_ptr_new(&s, udb, &ZONE(zone)->log_str); + udb_rptr_zero(&ZONE(zone)->log_str, udb); + sz = strlen((char*)udb_ptr_data(&s))+1; + udb_ptr_free_space(&s, udb, sz); + } + + /* set new log str */ + if(str) { + udb_ptr s; + size_t sz = strlen(str)+1; + if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) { + return; /* failed to allocate log string */ + } + memmove(udb_ptr_data(&s), str, sz); + udb_rptr_set_ptr(&ZONE(zone)->log_str, udb, &s); + udb_ptr_unlink(&s, udb); + } +} + +#ifdef NSEC3 +/** select the nsec3param for nsec3 usage */ +static void +select_nsec3_param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) +{ + udb_ptr rr; + udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); + while(rr.data) { + if(RR(&rr)->len >= 5 && RR(&rr)->wire[0] == NSEC3_SHA1_HASH && + RR(&rr)->wire[1] == 0) { + udb_rptr_set_ptr(&ZONE(zone)->nsec3param, udb, &rr); + udb_ptr_unlink(&rr, udb); + return; + } + udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); + } + udb_ptr_unlink(&rr, udb); +} + +const char* +udb_nsec3param_string(udb_ptr* rr) +{ + /* max saltlenth plus first couple of numbers (3+1+5+1+3+1) */ + static char params[MAX_RDLENGTH*2+16]; + char* p; + assert(RR(rr)->len >= 5); + p = params + snprintf(params, sizeof(params), "%u %u %u ", + (unsigned)RR(rr)->wire[0], (unsigned)RR(rr)->wire[1], + (unsigned)read_uint16(&RR(rr)->wire[2])); + if(RR(rr)->wire[4] == 0) { + *p++ = '-'; + } else { + assert(RR(rr)->len >= 5+RR(rr)->wire[4]); + p += hex_ntop(&RR(rr)->wire[5], RR(rr)->wire[4], p, + sizeof(params)-strlen(params)-1); + } + *p = 0; + return params; +} + +/** look in zone for new selected nsec3param record from rrset */ +static void +zone_hash_nsec3param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) +{ + select_nsec3_param(udb, zone, rrset); + if(ZONE(zone)->nsec3param.data == 0) + return; + /* prettyprint the nsec3 parameters we are using */ + if(2 <= verbosity) { + udb_ptr par; + udb_ptr_new(&par, udb, &ZONE(zone)->nsec3param); + VERBOSITY(1, (LOG_INFO, "rehash of zone %s with parameters %s", + wiredname2str(ZONE(zone)->name), + udb_nsec3param_string(&par))); + udb_ptr_unlink(&par, udb); + } +} +#endif /* NSEC3 */ + +/** create a new domain name */ +static int +domain_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, + udb_ptr* result) +{ + udb_ptr dtree, node; + /* create domain chunk */ + if(!udb_ptr_alloc_space(result, udb, udb_chunk_type_domain, + sizeof(struct domain_d)+nmlen)) + return 0; + udb_rel_ptr_init(&DOMAIN(result)->node); + udb_rel_ptr_init(&DOMAIN(result)->rrsets); + DOMAIN(result)->namelen = nmlen; + memmove(DOMAIN(result)->name, nm, nmlen); + + /* insert into domain tree */ + udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); + if(!udb_radname_insert(udb, &dtree, nm, nmlen, result, &node)) { + udb_ptr_free_space(result, udb, sizeof(struct domain_d)+nmlen); + udb_ptr_unlink(&dtree, udb); + return 0; + } + udb_rptr_set_ptr(&DOMAIN(result)->node, udb, &node); + udb_ptr_unlink(&dtree, udb); + udb_ptr_unlink(&node, udb); + return 1; +} + +int +udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, + udb_ptr* result) +{ + int r; + udb_ptr dtree; + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); + r = udb_radname_search(udb, &dtree, nm, nmlen, result); + if(result->data) + udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); + udb_ptr_unlink(&dtree, udb); + return r && result->data; +} + +/** find or create a domain name in the zone domain tree */ +static int +domain_find_or_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, + size_t nmlen, udb_ptr* result) +{ + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + if(udb_domain_find(udb, zone, nm, nmlen, result)) + return 1; + return domain_create(udb, zone, nm, nmlen, result); +} + +/** remove rrset from the domain name rrset-list */ +static void +domain_remove_rrset(udb_base* udb, udb_ptr* domain, uint16_t t) +{ + udb_ptr p, prev; + assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); + udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); + udb_ptr_init(&prev, udb); + while(p.data) { + if(RRSET(&p)->type == t) { + /* remove it */ + if(prev.data == 0) { + /* first rrset */ + udb_rptr_set_rptr(&DOMAIN(domain)->rrsets, + udb, &RRSET(&p)->next); + } else { + udb_rptr_set_rptr(&RRSET(&prev)->next, + udb, &RRSET(&p)->next); + } + udb_ptr_unlink(&prev, udb); + rrset_delete(udb, &p); + return; + } + udb_ptr_set_ptr(&prev, udb, &p); + udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); + } + /* rrset does not exist */ + udb_ptr_unlink(&prev, udb); + udb_ptr_unlink(&p, udb); +} + +/** create rrset in the domain rrset list */ +static int +rrset_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) +{ + /* create it */ + if(!udb_ptr_alloc_space(res, udb, udb_chunk_type_rrset, + sizeof(struct rrset_d))) + return 0; + udb_rel_ptr_init(&RRSET(res)->next); + udb_rel_ptr_init(&RRSET(res)->rrs); + RRSET(res)->type = t; + +#if 0 + /* link it in, at the front */ + udb_rptr_set_rptr(&RRSET(res)->next, udb, &DOMAIN(domain)->rrsets); + udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); +#else + /* preserve RRset order, link at end */ + if(DOMAIN(domain)->rrsets.data == 0) { + udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); + } else { + udb_ptr p; + udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); + while(RRSET(&p)->next.data) + udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); + udb_rptr_set_ptr(&RRSET(&p)->next, udb, res); + udb_ptr_unlink(&p, udb); + } +#endif + return 1; +} + +int +udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) +{ + assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); + udb_ptr_init(res, udb); + udb_ptr_set_rptr(res, udb, &DOMAIN(domain)->rrsets); + while(res->data) { + if(RRSET(res)->type == t) + return 1; + udb_ptr_set_rptr(res, udb, &RRSET(res)->next); + } + /* rrset does not exist and res->data is conveniently zero */ + return 0; +} + +/** find or create rrset in the domain rrset list */ +static int +rrset_find_or_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) +{ + if(udb_rrset_find(udb, domain, t, res)) + return 1; + return rrset_create(udb, domain, t, res); +} + +/** see if RR matches type, class and rdata */ +static int +rr_match(udb_ptr* rr, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) +{ + return RR(rr)->type == t && RR(rr)->klass == k && + RR(rr)->len == rdatalen && + memcmp(RR(rr)->wire, rdata, rdatalen) == 0; +} + +/** see if RR exists in the RR list that matches the rdata, and return it */ +static int +rr_search(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, + uint8_t* rdata, size_t rdatalen, udb_ptr* result) +{ + assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); + udb_ptr_init(result, udb); + udb_ptr_set_rptr(result, udb, &RRSET(rrset)->rrs); + while(result->data) { + if(rr_match(result, t, k, rdata, rdatalen)) + return 1; /* found */ + udb_ptr_set_rptr(result, udb, &RR(result)->next); + } + /* not found and result->data is conveniently zero */ + return 0; +} + +/** create RR chunk */ +static int +rr_create(udb_base* udb, uint16_t t, uint16_t k, uint32_t ttl, + uint8_t* rdata, size_t rdatalen, udb_ptr* rr) +{ + if(!udb_ptr_alloc_space(rr, udb, udb_chunk_type_rr, + sizeof(struct rr_d)+rdatalen)) + return 0; + udb_rel_ptr_init(&RR(rr)->next); + RR(rr)->type = t; + RR(rr)->klass = k; + RR(rr)->ttl = ttl; + RR(rr)->len = rdatalen; + memmove(RR(rr)->wire, rdata, rdatalen); + return 1; +} + +/** add an RR to an RRset. */ +static int +rrset_add_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, + uint32_t ttl, uint8_t* rdata, size_t rdatalen) +{ + udb_ptr rr; + assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); + /* create it */ + if(!rr_create(udb, t, k, ttl, rdata, rdatalen, &rr)) + return 0; + + /* add at end, to preserve order of RRs */ + if(RRSET(rrset)->rrs.data == 0) { + udb_rptr_set_ptr(&RRSET(rrset)->rrs, udb, &rr); + } else { + udb_ptr lastrr; + udb_ptr_new(&lastrr, udb, &RRSET(rrset)->rrs); + while(RR(&lastrr)->next.data) + udb_ptr_set_rptr(&lastrr, udb, &RR(&lastrr)->next); + udb_rptr_set_ptr(&RR(&lastrr)->next, udb, &rr); + udb_ptr_unlink(&lastrr, udb); + } + udb_ptr_unlink(&rr, udb); + return 1; +} + +/** remove an RR from an RRset. return 0 if RR did not exist. */ +static int +rrset_del_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, + uint8_t* rdata, size_t rdatalen) +{ + udb_ptr p, prev; + assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); + udb_ptr_new(&p, udb, &RRSET(rrset)->rrs); + udb_ptr_init(&prev, udb); + while(p.data) { + if(rr_match(&p, t, k, rdata, rdatalen)) { + /* remove it */ + if(prev.data == 0) { + /* first in list */ + udb_rptr_set_rptr(&RRSET(rrset)->rrs, udb, + &RR(&p)->next); + } else { + udb_rptr_set_rptr(&RR(&prev)->next, udb, + &RR(&p)->next); + } + udb_ptr_unlink(&prev, udb); + rr_delete(udb, &p); + return 1; + } + udb_ptr_set_ptr(&prev, udb, &p); + udb_ptr_set_rptr(&p, udb, &RR(&p)->next); + } + /* not found */ + udb_ptr_unlink(&prev, udb); + udb_ptr_unlink(&p, udb); + return 0; +} + +int +udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, + uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen) +{ + udb_ptr domain, rrset, rr; + int created_rrset = 0; + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + + /* find or create domain */ + if(!domain_find_or_create(udb, zone, nm, nmlen, &domain)) { + return 0; + } + /* find or create rrset(type) */ + if(!rrset_find_or_create(udb, &domain, t, &rrset)) { + goto exit_clean_domain; + } + if(RRSET(&rrset)->rrs.data == 0) + created_rrset = 1; + /* test for duplicate RRs */ + if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { + udb_ptr_unlink(&rr, udb); + goto exit_clean_domain_rrset; + } + /* add RR to rrset */ + if(!rrset_add_rr(udb, &rrset, t, k, ttl, rdata, rdatalen)) { + exit_clean_domain_rrset: + /* if rrset was created, remove it */ + if(RRSET(&rrset)->rrs.data == 0) { + udb_ptr_zero(&rrset, udb); + domain_remove_rrset(udb, &domain, t); + } + udb_ptr_unlink(&rrset, udb); + exit_clean_domain: + /* if domain created, delete it */ + if(DOMAIN(&domain)->rrsets.data == 0) + domain_delete_unlink(udb, zone, &domain); + udb_ptr_unlink(&domain, udb); + return 0; + } + /* success, account changes */ + if(created_rrset) + ZONE(zone)->rrset_count ++; + ZONE(zone)->rr_count ++; +#ifdef NSEC3 + if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0) + zone_hash_nsec3param(udb, zone, &rrset); +#endif /* NSEC3 */ + udb_ptr_unlink(&domain, udb); + udb_ptr_unlink(&rrset, udb); + return 1; +} + +void +udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, + uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) +{ + udb_ptr domain, rrset; + assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); + /* find the domain */ + if(!udb_domain_find(udb, zone, nm, nmlen, &domain)) + return; + /* find the rrset */ + if(!udb_rrset_find(udb, &domain, t, &rrset)) { + udb_ptr_unlink(&domain, udb); + return; + } + /* remove the RR */ +#ifdef NSEC3 + if(t == TYPE_NSEC3PARAM) { + udb_ptr rr; + if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { + if(rr.data == ZONE(zone)->nsec3param.data) { + udb_rptr_zero(&ZONE(zone)->nsec3param, udb); + } + udb_ptr_unlink(&rr, udb); + } + } +#endif /* NSEC3 */ + if(!rrset_del_rr(udb, &rrset, t, k, rdata, rdatalen)) { + /* rr did not exist */ + udb_ptr_unlink(&domain, udb); + udb_ptr_unlink(&rrset, udb); + return; + } + ZONE(zone)->rr_count --; +#ifdef NSEC3 + if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0 && + RRSET(&rrset)->rrs.data != 0) { + zone_hash_nsec3param(udb, zone, &rrset); + } +#endif /* NSEC3 */ + /* see we we can remove the rrset too */ + if(RRSET(&rrset)->rrs.data == 0) { + udb_ptr_zero(&rrset, udb); + domain_remove_rrset(udb, &domain, t); + ZONE(zone)->rrset_count --; + } + /* see if we can remove the domain name too */ + if(DOMAIN(&domain)->rrsets.data == 0) { + domain_delete_unlink(udb, zone, &domain); + } + udb_ptr_unlink(&rrset, udb); + udb_ptr_unlink(&domain, udb); +} + +void +udb_zone_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, + void* arg) +{ + struct zone_d* p = (struct zone_d*)d; + assert(s >= sizeof(struct zone_d)+p->namelen); + (void)s; + (*cb)(base, &p->node, arg); + (*cb)(base, &p->domains, arg); + (*cb)(base, &p->nsec3param, arg); + (*cb)(base, &p->log_str, arg); +} + +void +udb_domain_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, + void* arg) +{ + struct domain_d* p = (struct domain_d*)d; + assert(s >= sizeof(struct domain_d)+p->namelen); + (void)s; + (*cb)(base, &p->node, arg); + (*cb)(base, &p->rrsets, arg); +} + +void +udb_rrset_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, + void* arg) +{ + struct rrset_d* p = (struct rrset_d*)d; + assert(s >= sizeof(struct rrset_d)); + (void)s; + (*cb)(base, &p->next, arg); + (*cb)(base, &p->rrs, arg); +} + +void +udb_rr_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, + void* arg) +{ + struct rr_d* p = (struct rr_d*)d; + assert(s >= sizeof(struct rr_d)+p->len); + (void)s; + (*cb)(base, &p->next, arg); +} + +void +udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, + void* arg) +{ + struct task_list_d* p = (struct task_list_d*)d; + assert(s >= p->size); + (void)s; + (*cb)(base, &p->next, arg); +} + +void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, + udb_walk_relptr_cb* cb, void* arg) +{ + (void)warg; + switch(t) { + case udb_chunk_type_radtree: + udb_radix_tree_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_radnode: + udb_radix_node_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_radarray: + udb_radix_array_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_zone: + udb_zone_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_domain: + udb_domain_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_rrset: + udb_rrset_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_rr: + udb_rr_walk_chunk(base, d, s, cb, arg); + break; + case udb_chunk_type_task: + udb_task_walk_chunk(base, d, s, cb, arg); + break; + default: + /* no rel ptrs */ + break; + } +} |