diff options
Diffstat (limited to 'testcode/harvest.c')
-rw-r--r-- | testcode/harvest.c | 857 |
1 files changed, 0 insertions, 857 deletions
diff --git a/testcode/harvest.c b/testcode/harvest.c deleted file mode 100644 index 1952dc2a221f..000000000000 --- a/testcode/harvest.c +++ /dev/null @@ -1,857 +0,0 @@ -/* - * testcode/harvest.c - debug program to get relevant data to a set of queries. - * - * Copyright (c) 2008, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * This program downloads relevant DNS data to a set of queries. - * This means that the queries are asked to root, TLD, SLD servers and - * the results stored per zone. - * The following data is pertinent: - * - * At each label: - * SOA - * NS - * DNSKEY - * DS - * For the whole query: - * the result. - * For NS-records: - * their label data - * and the A and AAAA records for it. - * (as if the name, with A and AAAA query type is in the list, - * referred to as recursion depth+1) - * Any NSEC, NSEC3, SOA records or additional data found in answers. - * - * All of this is data that would be encountered during an iterative lookup - * for the queries in the list. It is saved to enable a replay of iterative - * lookups for performance testing. - * - * A number of assumptions are made. - * 1) configuration is correct. - * The parent has the same NS records as the child. - * All nameservers carry the same data. - * 2) EDNS/nonEDNS responses and other behaviour is ignored. - * Only the data is saved. - * This creates a snapshot that represents the data as this resolver saw it. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#include <ldns/ldns.h> -#include <signal.h> -#include "libunbound/unbound.h" -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef UNBOUND_ALLOC_LITE -#undef malloc -#undef calloc -#undef realloc -#undef free -#undef strdup -#define unbound_lite_wrapstr(s) s -#endif -struct todo_item; -struct labdata; - -/** this represents the data that has been collected - * as well as a todo list and some settings */ -struct harvest_data { - /** the unbound context */ - struct ub_ctx* ctx; - - /** a tree per label; thus this first one is one root entry, - * that has a tree of TLD labels. Those have trees of SLD labels. */ - struct labdata* root; - /** the original query list */ - struct todo_item* orig_list; - /** the query list todo */ - struct todo_item* todo_list; - /** last item in todo list */ - struct todo_item* todo_last; - /** number of todo items */ - int numtodo; - - /** where to store the results */ - char* resultdir; - /** maximum recursion depth */ - int maxdepth; - /** current recursion depth */ - int curdepth; - - /** max depth of labels */ - int maxlabels; - /** number of RRs stored */ - int num_rrs; - /** number of zones written */ - int num_zones; -}; - -/** - * Todo item - */ -struct todo_item { - /** the next item */ - struct todo_item* next; - - /** query as rdf */ - ldns_rdf* qname; - /** the query type */ - int qtype; - /** query class */ - int qclass; - - /** recursion depth of todo item (orig list is 0) */ - int depth; - /** the label associated with the query */ - struct labdata* lab; -}; - -/** - * Every label has a sest of sublabels, that have sets of sublabels ... - * Per label is stored also a set of data items, and todo information - */ -struct labdata { - /** node in ldns rbtree */ - ldns_rbnode_t node; - /** the name of this label */ - ldns_rdf* label; - /** full name of point in domain tree */ - ldns_rdf* name; - - /** parent in label tree (NULL for root) */ - struct labdata* parent; - /** tree of sublabels (if any) */ - ldns_rbtree_t* sublabels; - - /** list of RRs for this label */ - ldns_rr_list* rrlist; - /** have queries for this label been queued */ - int done; -}; - -/** usage information for harvest */ -static void usage(char* nm) -{ - printf("usage: %s [options]\n", nm); - printf("-f fnm query list to read from file\n"); - printf(" every line has format: qname qclass qtype\n"); - printf("-v verbose (-v -v even more)\n"); - printf("-C cfg config file with resolver options\n"); - exit(1); -} - -/** verbosity for harvest */ -static int hverb = 0; - -/** exit with error */ -static void error_exit(const char* str) -{ - printf("error: %s\n", str); - exit(1); -} - -/** read a query file */ -static void -qlist_read_file(struct harvest_data* data, char* fname) -{ - char buf[1024]; - char nm[1024], cl[1024], tp[1024]; - int r; - int num = 0; - FILE* in = fopen(fname, "r"); - struct todo_item* t; - if(!in) { - perror(fname); - error_exit("could not open file"); - } - while(fgets(buf, (int)sizeof(buf), in)) { - if(buf[0] == 0) continue; - if(buf[0] == '\n') continue; - /* allow some comments */ - if(buf[0] == ';') continue; - if(buf[0] == '#') continue; - nm[0] = 0; cl[0] = 0; tp[0] = 0; - r = sscanf(buf, " %1023s %1023s %1023s", nm, cl, tp); - if(r == 0) continue; - t = (struct todo_item*)calloc(1, sizeof(*t)); - if(!t) error_exit("out of memory"); - t->qname = ldns_dname_new_frm_str(nm); - if(!t->qname) { - printf("parse error: %s\n", nm); - error_exit("bad qname"); - } - t->depth = 0; - t->qtype = LDNS_RR_TYPE_A; - t->qclass = LDNS_RR_CLASS_IN; - if(r >= 2) { - if(strcmp(cl, "IN") == 0 || strcmp(cl, "CH") == 0) - t->qclass = ldns_get_rr_class_by_name(cl); - else t->qtype = ldns_get_rr_type_by_name(cl); - } - if(r >= 3) { - if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) - t->qclass = ldns_get_rr_class_by_name(tp); - else t->qtype = ldns_get_rr_type_by_name(tp); - } - num++; - - t->next = data->orig_list; - data->orig_list = t; - } - printf("read %s: %d queries\n", fname, num); - fclose(in); -} - -/** compare two labels */ -static int -lab_cmp(const void *x, const void *y) -{ - return ldns_dname_compare((const ldns_rdf*)x, (const ldns_rdf*)y); -} - -/** create label entry */ -static struct labdata* -lab_create(const char* name) -{ - struct labdata* lab = (struct labdata*)calloc(1, sizeof(*lab)); - if(!lab) error_exit("out of memory"); - lab->label = ldns_dname_new_frm_str(name); - if(!lab->label) error_exit("out of memory"); - lab->name = ldns_dname_new_frm_str(name); - if(!lab->name) error_exit("out of memory"); - lab->node.key = lab->label; - lab->node.data = lab; - lab->sublabels = ldns_rbtree_create(lab_cmp); - if(!lab->sublabels) error_exit("out of memory"); - lab->rrlist = ldns_rr_list_new(); - if(!lab->rrlist) error_exit("out of memory"); - - return lab; -} - -/** for this name, lookup the label, create if does not exist */ -static struct labdata* -find_create_lab(struct harvest_data* data, ldns_rdf* name) -{ - struct labdata* lab = data->root; - struct labdata* nextlab; - ldns_rdf* next; - uint8_t numlab = ldns_dname_label_count(name); - if((int)numlab > data->maxlabels) - data->maxlabels = (int)numlab; - while(numlab--) { - next = ldns_dname_label(name, numlab); - if(!next) error_exit("ldns_dname_label"); - - nextlab = (struct labdata*) - ldns_rbtree_search(lab->sublabels, next); - if(!nextlab) { - /* create it */ - nextlab = (struct labdata*)calloc(1, sizeof(*lab)); - if(!nextlab) error_exit("out of memory"); - nextlab->label = ldns_rdf_clone(next); - if(!nextlab->label) error_exit("out of memory"); - nextlab->node.key = nextlab->label; - nextlab->node.data = nextlab; - nextlab->sublabels = ldns_rbtree_create(lab_cmp); - if(!nextlab->sublabels) error_exit("out of memory"); - nextlab->parent = lab; - nextlab->name = ldns_rdf_clone(next); - if(!nextlab->name) error_exit("out of memory"); - if(ldns_dname_cat(nextlab->name, lab->name) - != LDNS_STATUS_OK) error_exit("outofmem"); - nextlab->rrlist = ldns_rr_list_new(); - if(!nextlab->rrlist) error_exit("out of memory"); - (void)ldns_rbtree_insert(lab->sublabels, - &nextlab->node); - if(hverb) { - printf("new label: "); - ldns_rdf_print(stdout, nextlab->name); - printf("\n"); - } - } - lab = nextlab; - ldns_rdf_deep_free(next); - } - return lab; -} - -/** for given query, create todo items, and labels if needed */ -static void -new_todo_item(struct harvest_data* data, ldns_rdf* qname, int qtype, - int qclass, int depth) -{ - struct labdata* lab = find_create_lab(data, qname); - struct todo_item* it; - if(!lab) error_exit("out of memory creating new label"); - it = (struct todo_item*)calloc(1, sizeof(*it)); - it->qname = ldns_rdf_clone(qname); - it->qtype = qtype; - it->qclass = qclass; - it->depth = depth; - it->lab = lab; - it->next = NULL; - if(data->todo_last) - data->todo_last->next = it; - else data->todo_list = it; - data->todo_last = it; - data->numtodo ++; - if(hverb >= 2) { - printf("new todo: "); - ldns_rdf_print(stdout, it->qname); - if(ldns_rr_descript((uint16_t)it->qtype) && - ldns_rr_descript((uint16_t)it->qtype)->_name) - printf(" %s", ldns_rr_descript((uint16_t) - it->qtype)->_name); - if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) && - ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name) - printf(" %s", ldns_lookup_by_id(ldns_rr_classes, - it->qclass)->name); - printf("\n"); - } -} - -/** add infra todo items for this query */ -static void -new_todo_infra(struct harvest_data* data, struct labdata* startlab, int depth) -{ - struct labdata* lab; - for(lab = startlab; lab; lab = lab->parent) { - if(lab->done) - return; - new_todo_item(data, lab->name, LDNS_RR_TYPE_NS, - LDNS_RR_CLASS_IN, depth); - new_todo_item(data, lab->name, LDNS_RR_TYPE_SOA, - LDNS_RR_CLASS_IN, depth); - new_todo_item(data, lab->name, LDNS_RR_TYPE_DNSKEY, - LDNS_RR_CLASS_IN, depth); - new_todo_item(data, lab->name, LDNS_RR_TYPE_DS, - LDNS_RR_CLASS_IN, depth); - new_todo_item(data, lab->name, LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, depth); - new_todo_item(data, lab->name, LDNS_RR_TYPE_AAAA, - LDNS_RR_CLASS_IN, depth); - lab->done = 1; - } -} - -/** make todo items for initial data */ -static void -make_todo(struct harvest_data* data) -{ - struct todo_item* it; - for(it=data->orig_list; it; it = it->next) { - /* create todo item for this query itself */ - new_todo_item(data, it->qname, it->qtype, it->qclass, 0); - /* create todo items for infra queries to support it */ - new_todo_infra(data, data->todo_list->lab, - data->todo_list->depth); - } -} - -/** store RR and make new work items for it if needed */ -static void -process_rr(struct harvest_data* data, ldns_rr* rr, int depth) -{ - /* must free or store rr */ - struct labdata* lab = find_create_lab(data, ldns_rr_owner(rr)); - if(!lab) error_exit("cannot find/create label"); - /* generate extra queries */ - if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) { - new_todo_infra(data, find_create_lab(data, - ldns_rr_ns_nsdname(rr)), depth+1); - } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_MX) { - new_todo_infra(data, find_create_lab(data, - ldns_rr_mx_exchange(rr)), depth+1); - } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { - new_todo_infra(data, find_create_lab(data, - ldns_rr_rdf(rr, 0)), depth+1); - } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_CNAME) { - int t = ldns_rr_get_type(rr); - if(t!=LDNS_RR_TYPE_A && t!=LDNS_RR_TYPE_AAAA && - t!=LDNS_RR_TYPE_SOA && t!=LDNS_RR_TYPE_NS && - t!=LDNS_RR_TYPE_DS && t!=LDNS_RR_TYPE_DNSKEY) - new_todo_item(data, ldns_rr_rdf(rr, 0), t, - ldns_rr_get_class(rr), depth+1); - /* can get caught in CNAME loop, but depth will - * catch that; unbound cache helps too(servfails on - * a cname loop) */ - new_todo_infra(data, find_create_lab(data, - ldns_rr_rdf(rr, 0)), depth+1); - } - /* store it */ - if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC) { - /* find correct zone to store NSEC in (for delegation zones) */ - if(ldns_dname_compare(ldns_rr_rdf(rr, 0), ldns_rr_owner(rr)) - == 0) { - /* store at the single name = apex */ - } else if(!ldns_dname_is_subdomain(ldns_rr_rdf(rr, 0), - ldns_rr_owner(rr)) && lab->parent) { - /* if owner NSEC subdomain-of-owner then - * store at owner (owner is apex or empty nonterminal). - * Otherwise at owner parent. */ - lab = lab->parent; - } - } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) { - /* store DSes in parent zone */ - if(lab->parent) - lab = lab->parent; - } else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3) { - /* store NSEC3s one label up at zone apex */ - if(lab->parent) - lab = lab->parent; - } - /* we assume NS set is equal across parent-child border. */ - - if(!ldns_rr_list_contains_rr(lab->rrlist, rr)) { - if(hverb >= 2) { - printf("store RR "); - ldns_rr_print(stdout, rr); - printf("\n"); - } - if(!ldns_rr_list_push_rr(lab->rrlist, rr)) - error_exit("outofmem ldns_rr_list_push_rr"); - data->num_rrs++; - } else { - if(hverb >= 2) { - printf("duplicate RR "); - ldns_rr_print(stdout, rr); - printf("\n"); - } - ldns_rr_free(rr); - } -} - -/** store RRs and make new work items if needed */ -static void -process_pkt(struct harvest_data* data, ldns_pkt* pkt, int depth) -{ - size_t i; - ldns_rr_list* list; - list = ldns_pkt_get_section_clone(pkt, LDNS_SECTION_ANY_NOQUESTION); - if(!list) error_exit("outofmemory"); - for(i=0; i<ldns_rr_list_rr_count(list); i++) { - process_rr(data, ldns_rr_list_rr(list, i), depth); - } - ldns_rr_list_free(list); -} - -/** process a todo item */ -static void -process(struct harvest_data* data, struct todo_item* it) -{ - int r; - char* nm; - struct ub_result* result = NULL; - ldns_pkt* pkt = NULL; - ldns_status s; - if(hverb) { - printf("process: "); - ldns_rdf_print(stdout, it->qname); - if(ldns_rr_descript((uint16_t)it->qtype) && - ldns_rr_descript((uint16_t)it->qtype)->_name) - printf(" %s", ldns_rr_descript((uint16_t) - it->qtype)->_name); - if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) && - ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name) - printf(" %s", ldns_lookup_by_id(ldns_rr_classes, - it->qclass)->name); - printf("\n"); - } - /* do lookup */ - nm = ldns_rdf2str(it->qname); - if(!nm) error_exit("ldns_rdf2str"); - r = ub_resolve(data->ctx, nm, it->qtype, it->qclass, &result); - if(r != 0) { - printf("ub_resolve(%s, %d, %d): %s\n", nm, it->qtype, - it->qclass, ub_strerror(r)); - free(nm); - return; - } - if(result->rcode == LDNS_RCODE_SERVFAIL) { - free(nm); - return; - } - /* even if result is a negative, try to store resulting SOA/NSEC */ - - /* create ldns pkt */ - s = ldns_wire2pkt(&pkt, result->answer_packet, - (size_t)result->answer_len); - if(s != LDNS_STATUS_OK) { - printf("ldns_wire2pkt failed! %s %d %d %s %d\n", nm, - it->qtype, it->qclass, ldns_get_errorstr_by_id(s), - result->answer_len); - free(nm); - return; - } - if(hverb >= 2) { - printf("answer: "); - ldns_pkt_print(stdout, pkt); - printf("\n"); - } - /* process results */ - process_pkt(data, pkt, it->depth); - - ldns_pkt_free(pkt); - free(nm); - ub_resolve_free(result); -} - -/** perform main harvesting */ -static void -harvest_main(struct harvest_data* data) -{ - struct todo_item* it; - int numdone = 0; - /* register todo queries for all original queries */ - make_todo(data); - printf("depth 0: done %d todo %d\n", 0, data->numtodo); - /* pick up a todo item and process it */ - while(data->todo_list) { - numdone++; - it = data->todo_list; - data->todo_list = it->next; - if(!data->todo_list) data->todo_last = NULL; - if(numdone%1000==0 || it->depth > data->curdepth) { - data->curdepth = it->depth; - printf("depth %d: done %d todo %d, %d rrs\n", - it->depth, numdone, data->numtodo, - data->num_rrs); - } - if(it->depth >= data->maxdepth) { - printf("obtained %d rrs to a max of %d labels.\n", - data->num_rrs, data->maxlabels); - return; - } - data->numtodo--; - process(data, it); - usleep(1000000/100); - } -} - -/** create directory if it does not exist */ -static void -hv_mkdir(char* dir) -{ -#ifdef MKDIR_HAS_ONE_ARG - if(mkdir(dir) == -1) { -#else - if(mkdir(dir, 0755) == -1) { -#endif - if(errno == EEXIST) - return; - perror(dir); - error_exit("mkdir failed"); - } -} - - -/** see if rrlist contains a SOA record */ -static ldns_rr* -has_SOA(ldns_rr_list* list) -{ - size_t i; - for(i=0; i<ldns_rr_list_rr_count(list); i++) { - if(ldns_rr_get_type(ldns_rr_list_rr(list, i)) - == LDNS_RR_TYPE_SOA) - return ldns_rr_list_rr(list, i); - } - return NULL; -} - -/** write moredata for a zone*/ -static void -write_moredata(struct harvest_data* data, struct labdata* zone, - FILE *f, struct labdata* thislab, ldns_rr* nslist) -{ - struct labdata* lab; - size_t i; - ldns_rr* ns; - LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) { - if(has_SOA(lab->rrlist)) { - /* copy only NS glue */ - for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) { - ns = ldns_rr_list_rr(lab->rrlist, i); - if(ldns_rr_get_type(ns) == LDNS_RR_TYPE_NS) { - ldns_rr_print(f, ns); - if(ldns_dname_is_subdomain( - ldns_rr_ns_nsdname(ns), - lab->name)) { - ldns_rr_push_rdf(nslist, - ldns_rdf_clone( - ldns_rr_ns_nsdname(ns))); - } - } - } - } else { - /* copy all, recurse */ - for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) { - ldns_rr_print(f, - ldns_rr_list_rr(lab->rrlist, i)); - } - write_moredata(data, zone, f, lab, nslist); - } - } -} - -/** find and write glue into zone file */ -static void -write_glue(struct harvest_data* data, struct labdata* thislab, FILE* f, - ldns_rdf* name, int dep) -{ - size_t i; - struct labdata* lab; - ldns_rr* rr; - if(ldns_dname_compare(name, thislab->name) == 0) { - /* this is it! Did we go outside the zone? */ - if(dep == 0) - return; - /* find A and AAAA */ - for(i=0; i<ldns_rr_list_rr_count(thislab->rrlist); i++) { - rr = ldns_rr_list_rr(thislab->rrlist, i); - if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A || - ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) { - ldns_rr_print(f, rr); - } - } - return; - } - /* recurse deeper */ - LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) { - if(has_SOA(lab->rrlist)) { - write_glue(data, lab, f, name, dep+1); - } else { - write_glue(data, lab, f, name, dep); - } - } -} - -/** write zonefile for zone at this apex */ -static void -write_zonefile(struct harvest_data* data, int dep, FILE* zlist, - struct labdata* apex, ldns_rr* soa) -{ - FILE *f; - char fname[1024]; - char* zname = ldns_rdf2str(apex->name); - time_t tm = time(NULL); - size_t i; - ldns_rr* nslist; - if(!zname) error_exit("out of mem ldns_rdf2str"); - if(strcmp(zname, ".") == 0) - snprintf(fname, sizeof(fname), "l%d/root.zone", dep); - else snprintf(fname, sizeof(fname), "l%d/%szone", dep, zname); - - fprintf(zlist, "zone: name: \"%s\" %s%szonefile: \"%s\"\n", - zname, - strlen(zname)/8<1?"\t":"", - strlen(zname)/8<2?"\t":"", - fname); - - if(hverb) printf("writing %s\n", fname); - f = fopen(fname, "w"); - if(!f) { - perror(fname); - error_exit("cannot open zone file"); - } - fprintf(f, "; %s - generated by harvest program.\n", fname); - fprintf(f, "; zone name %s - this is a partial snapshot of " - "data relevant to the query list.\n", zname); - fprintf(f, "; created %u - date %s\n", (unsigned)tm, ctime(&tm)); - ldns_rr_print(f, soa); - fprintf(f, "\n"); - for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) { - if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i)) - == LDNS_RR_TYPE_SOA) continue; - ldns_rr_print(f, ldns_rr_list_rr(apex->rrlist, i)); - } - /* search for more data - subdomains inside the zone, NS glue */ - nslist = ldns_rr_new(); - if(!nslist) error_exit("out of memory"); - fprintf(f, "; end of apex, more data follows\n"); - write_moredata(data, apex, f, apex, nslist); - - /* add NS from apex that need glue too */ - for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) { - if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i)) != - LDNS_RR_TYPE_NS) - continue; - /* these are only added again if in a subzone */ - if(ldns_dname_is_subdomain(ldns_rr_ns_nsdname( - ldns_rr_list_rr(apex->rrlist, i)), apex->name)) { - ldns_rr_push_rdf(nslist, ldns_rdf_clone( - ldns_rr_ns_nsdname(ldns_rr_list_rr( - apex->rrlist, i)))); - } - } - - fprintf(f, "; glue data follows\n"); - /* lookup and add glue (if not already in zone) */ - for(i=0; i<ldns_rr_rd_count(nslist); i++) { - write_glue(data, apex, f, ldns_rr_rdf(nslist, i), 0); - } - - fclose(f); - ldns_rr_free(nslist); - free(zname); -} - -/** create zones at depth d in label tree */ -static void -create_zones(struct harvest_data* data, int dep, FILE* zlist, - struct labdata* labnow, int depnow) -{ - struct labdata* s; - ldns_rr* soa; - if(depnow == dep) { - /* see if this is a zone start - a SOA */ - if((soa=has_SOA(labnow->rrlist))) { - write_zonefile(data, dep, zlist, labnow, soa); - data->num_zones++; - } - return; - } - /* recurse */ - LDNS_RBTREE_FOR(s, struct labdata*, labnow->sublabels) { - create_zones(data, dep, zlist, s, depnow+1); - } -} - -/** sort rrlists */ -static void -harvest_sort(struct labdata* lab) -{ - struct labdata* s; - /* prettier output if sorted here */ - ldns_rr_list_sort(lab->rrlist); - /* and recurse */ - LDNS_RBTREE_FOR(s, struct labdata*, lab->sublabels) { - harvest_sort(s); - } -} - -/** output harvested results */ -static void -harvest_output(struct harvest_data* data) -{ - int d; - char buf[20]; - FILE* zlist; - int lastzones; - hv_mkdir(data->resultdir); - if(chdir(data->resultdir) == -1) { - perror(data->resultdir); - error_exit("cannot chdir"); - } - harvest_sort(data->root); - /* create zones */ - for(d = 0; d<data->maxlabels; d++) { - lastzones = data->num_zones; - printf("creating zones %d\n", d); - snprintf(buf, sizeof(buf), "l%d", d); - hv_mkdir(buf); - snprintf(buf, sizeof(buf), "l%d.zones", d); - zlist = fopen(buf, "w"); - if(!zlist) { - perror(buf); - error_exit("cannot write zonelist file"); - } - fprintf(zlist, "# partial zones at depth %d\n", d); - create_zones(data, d, zlist, data->root, 0); - fclose(zlist); - printf("creating zones %d - %d zones written\n", d, - data->num_zones - lastzones); - } -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** main program for harvest */ -int main(int argc, char* argv[]) -{ - struct harvest_data data; - char* nm = argv[0]; - int c; - - /* defaults */ - memset(&data, 0, sizeof(data)); - data.ctx = ub_ctx_create(); - data.resultdir = strdup("harvested_zones"); - if(!data.resultdir) error_exit("out of memory"); - data.maxdepth = 2; - - /* parse the options */ - while( (c=getopt(argc, argv, "hf:vC:")) != -1) { - switch(c) { - case 'C': - if(ub_ctx_config(data.ctx, optarg) != 0) - error_exit("config read failed"); - break; - case 'f': - qlist_read_file(&data, optarg); - break; - case 'v': - hverb++; - break; - case '?': - case 'h': - default: - usage(nm); - } - } - argc -= optind; - argv += optind; - if(argc != 0) - usage(nm); - if(data.orig_list == NULL) - error_exit("No queries to make, use -f (help with -h)."); - data.root = lab_create("."); - if(!data.root) error_exit("out of memory"); - - /* harvest the data */ - harvest_main(&data); - harvest_output(&data); - - /* no cleanup except the context (to close open sockets) */ - ub_ctx_delete(data.ctx); - return 0; -} |