/** list zone contents */ static void list_zone_contents(udb_base* udb, udb_ptr* zone) { udb_ptr dtree; udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); if(v) { time_t t = (time_t)ZONE(zone)->mtime; uint32_t serial; printf("# %llu domains, %llu RRsets, %llu RRs%s, ", ULL RADTREE(&dtree)->count, ULL ZONE(zone)->rrset_count, ULL ZONE(zone)->rr_count, ZONE(zone)->expired?", is_expired":""); if(udb_zone_get_serial(udb, zone, &serial)) { printf("%u, ", (unsigned)serial); } printf("%s", ctime(&t)); if(ZONE(zone)->nsec3param.data) { udb_ptr n3; udb_ptr_new(&n3, udb, &ZONE(zone)->nsec3param); #ifdef NSEC3 printf("# nsec3param %s\n", udb_nsec3param_string(&n3)); #else printf("# nsec3param "); print_udb_rr(ZONE(zone)->name, &n3); #endif udb_ptr_unlink(&n3, udb); } } if(v >= 2) { list_domains(udb, &dtree); } udb_ptr_unlink(&dtree, udb); }
/** list domain RRs */ static void list_domains(udb_base* udb, udb_ptr* dtree) { udb_ptr d; 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); list_rrsets(udb, &domain); udb_ptr_unlink(&domain, udb); } udb_ptr_unlink(&d, udb); }
/** list zones in zone tree */ static void list_zones(udb_base* udb, udb_ptr* ztree) { udb_ptr z; 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); printf("zone: name: \""); print_dname(ZONE(&zone)->name, ZONE(&zone)->namelen); printf("\"\n"); if(v) list_zone_contents(udb, &zone); udb_ptr_unlink(&zone, udb); } udb_ptr_unlink(&z, udb); }
/** create and write a zone */ int write_zone_to_udb(udb_base* udb, zone_type* zone, struct timespec* mtime, const char* file_str) { udb_ptr z; /* make udb dirty */ udb_base_set_userflags(udb, 1); /* find or create zone */ if(udb_zone_search(udb, &z, dname_name(domain_dname(zone->apex)), domain_dname(zone->apex)->name_size)) { /* wipe existing contents */ udb_zone_clear(udb, &z); } else { if(!udb_zone_create(udb, &z, dname_name(domain_dname( zone->apex)), domain_dname(zone->apex)->name_size)) { udb_base_set_userflags(udb, 0); return 0; } } /* set mtime */ ZONE(&z)->mtime = (uint64_t)mtime->tv_sec; ZONE(&z)->mtime_nsec = (uint64_t)mtime->tv_nsec; ZONE(&z)->is_changed = 0; udb_zone_set_log_str(udb, &z, NULL); udb_zone_set_file_str(udb, &z, file_str); /* write zone */ if(!write_zone(udb, &z, zone)) { udb_base_set_userflags(udb, 0); return 0; } udb_ptr_unlink(&z, udb); udb_base_set_userflags(udb, 0); return 1; }
/** list contents of NSD.DB file */ static void list_file(char* fname) { udb_base* udb; udb_ptr ztree; log_init("udb-inspect"); udb = udb_base_create_read(fname, &namedb_walkfunc, NULL); if(!udb) { printf("cannot open udb %s\n", fname); exit(1); } udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); if(udb_ptr_is_null(&ztree)) { printf("file is not inited\n"); exit(1); } /* print header info */ printf("%s: %llu zones, %llu bytes\n", fname, ULL RADTREE(&ztree)->count, ULL udb->alloc->disk->nextgrow); if(udb_base_get_userflags(udb)) { printf("file is corrupted! (%u)\n", (unsigned)udb_base_get_userflags(udb)); } /* print detail info */ list_zones(udb, &ztree); udb_ptr_unlink(&ztree, udb); udb_base_free(udb); }
/** list RRsets */ static void list_rrsets(udb_base* udb, udb_ptr* domain) { udb_ptr rrset; udb_ptr_new(&rrset, udb, &DOMAIN(domain)->rrsets); while(rrset.data) { list_rrs(udb, &rrset, domain); udb_ptr_set_rptr(&rrset, udb, &RRSET(&rrset)->next); } udb_ptr_unlink(&rrset, udb); }
/** list rrs */ static void list_rrs(udb_base* udb, udb_ptr* rrset, udb_ptr* domain) { udb_ptr rr; udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); while(rr.data) { print_udb_rr(DOMAIN(domain)->name, &rr); udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); } udb_ptr_unlink(&rr, udb); }
/** find soa serial (if any) */ static int udb_zone_get_serial(udb_base* udb, udb_ptr* zone, uint32_t* serial) { udb_ptr domain, rrset, rr; buffer_type buffer; if(!udb_domain_find(udb, zone, ZONE(zone)->name, ZONE(zone)->namelen, &domain)) return 0; if(!udb_rrset_find(udb, &domain, TYPE_SOA, &rrset)) { udb_ptr_unlink(&domain, udb); return 0; } /* got SOA rrset, use first RR */ if(!RRSET(&rrset)->rrs.data) { udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); return 0; } udb_ptr_new(&rr, udb, &RRSET(&rrset)->rrs); udb_ptr_unlink(&domain, udb); udb_ptr_unlink(&rrset, udb); /* find serial */ buffer_create_from(&buffer, RR(&rr)->wire, RR(&rr)->len); /* skip two dnames */ if(!packet_skip_dname(&buffer) || !packet_skip_dname(&buffer)) { udb_ptr_unlink(&rr, udb); return 0; } if(!buffer_available(&buffer, 4*5)) { /* soa rdata u32s */ udb_ptr_unlink(&rr, udb); return 0; } *serial = buffer_read_u32(&buffer); udb_ptr_unlink(&rr, udb); return 1; }
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; } } }