From: Wouter Wijngaards Date: Thu, 24 May 2007 13:24:44 +0000 (+0000) Subject: preparatory work for iterator. X-Git-Tag: release-0.4~130 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a2c15be5861890f9acba6731206e9970cbb3032;p=thirdparty%2Funbound.git preparatory work for iterator. git-svn-id: file:///svn/unbound/trunk@336 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 165cc9a59..908939583 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -76,6 +76,30 @@ worker_send_cmd(struct worker* worker, ldns_buffer* buffer, log_err("write socket: %s", strerror(errno)); } +/** delete subrequest */ +static void +qstate_free(struct worker* worker, struct module_qstate* qstate) +{ + int i; + if(!qstate) + return; + /* remove subqueries */ + while(qstate->subquery_first) { + qstate_free(worker, qstate->subquery_first); + } + log_assert(qstate->subquery_first == NULL); + /* call de-init while all is OK */ + for(i=0; idaemon->num_modules; i++) + (*worker->daemon->modfunc[i]->clear)(qstate, i); + /* cleanup this query */ + region_free_all(qstate->region); + query_info_clear(&qstate->qinfo); + if(qstate->parent) { + module_subreq_remove(qstate); + free(qstate); + } +} + /** release workrequest back to the freelist, * note that the w->qinfo still needs to be cleared after this. */ @@ -138,33 +162,50 @@ replyerror(int r, struct work_query* w) /** process incoming request */ static void worker_process_query(struct worker* worker, struct work_query* w, - enum module_ev event, struct outbound_entry* entry) + struct module_qstate* qstate, enum module_ev event, + struct outbound_entry* entry) { int i; + enum module_ext_state s; if(event == module_event_new) { - w->state.curmod = 0; + qstate->curmod = 0; for(i=0; idaemon->num_modules; i++) - w->state.ext_state[i] = module_state_initial; + qstate->ext_state[i] = module_state_initial; } /* allow current module to run */ - (*worker->daemon->modfunc[w->state.curmod]->operate)(&w->state, event, - w->state.curmod, entry); + (*worker->daemon->modfunc[qstate->curmod]->operate)(qstate, event, + qstate->curmod, entry); + s = qstate->ext_state[qstate->curmod]; /* TODO examine results, start further modules, etc. * assume it went to sleep */ region_free_all(worker->scratchpad); - if(w->state.ext_state[w->state.curmod] == module_error) { - region_free_all(w->state.region); + /* subrequest done */ + /* TODO properly delete subquery */ + if(s == module_error && qstate->parent) { + qstate_free(worker, qstate); + worker_process_query(worker, w, qstate->parent, + module_event_error, NULL); + return; + } + if(s == module_finished && qstate->parent) { + qstate_free(worker, qstate); + worker_process_query(worker, w, qstate->parent, + module_event_subq_done, NULL); + return; + } + /* request done */ + if(s == module_error) { + qstate_free(worker, qstate); replyerror(LDNS_RCODE_SERVFAIL, w); return; } - if(w->state.ext_state[w->state.curmod] == module_finished) { + if(s == module_finished) { memcpy(ldns_buffer_begin(w->query_reply.c->buffer), &w->query_id, sizeof(w->query_id)); comm_point_send_reply(&w->query_reply); - region_free_all(w->state.region); + qstate_free(worker, qstate); req_release(w); - query_info_clear(&w->state.qinfo); return; } /* suspend, waits for wakeup callback */ @@ -180,7 +221,8 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, w->state.reply = reply_info; if(error != 0) { - worker_process_query(worker, w, module_event_timeout, NULL); + worker_process_query(worker, w, &w->state, + module_event_timeout, NULL); w->state.reply = NULL; return 0; } @@ -191,11 +233,12 @@ worker_handle_reply(struct comm_point* c, void* arg, int error, || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ - worker_process_query(worker, w, module_event_timeout, NULL); + worker_process_query(worker, w, &w->state, + module_event_timeout, NULL); w->state.reply = NULL; return 0; } - worker_process_query(worker, w, module_event_reply, NULL); + worker_process_query(worker, w, &w->state, module_event_reply, NULL); w->state.reply = NULL; return 0; } @@ -211,7 +254,8 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error, w->state.reply = reply_info; if(error != 0) { - worker_process_query(worker, w, module_event_timeout, e); + worker_process_query(worker, w, e->qstate, + module_event_timeout, e); w->state.reply = NULL; return 0; } @@ -222,11 +266,12 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error, || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { /* error becomes timeout for the module as if this reply * never arrived. */ - worker_process_query(worker, w, module_event_timeout, e); + worker_process_query(worker, w, e->qstate, + module_event_timeout, e); w->state.reply = NULL; return 0; } - worker_process_query(worker, w, module_event_reply, e); + worker_process_query(worker, w, e->qstate, module_event_reply, e); w->state.reply = NULL; return 0; } @@ -477,7 +522,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, /* answer it */ w->state.buf = c->buffer; - worker_process_query(worker, w, module_event_new, NULL); + worker_process_query(worker, w, &w->state, module_event_new, NULL); return 0; } @@ -582,7 +627,7 @@ reqs_delete(struct worker* worker) n = q->all_next; log_assert(q->state.env->worker == worker); /* comm_reply closed in outside_network_delete */ - query_info_clear(&q->state.qinfo); + qstate_free(worker, &q->state); region_destroy(q->state.region); free(q); q = n; diff --git a/doc/Changelog b/doc/Changelog index c667f19d6..b7178909f 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,9 @@ +24 May 2007: Wouter + - small changes to prepare for subqueries. + - iterator forwarder feature separated out. + - iterator hints stub code, config file stub code, so that first + testing can proceed locally. + 23 May 2007: Wouter - outside network does precise timers for roundtrip estimates for rtt and for setting timeout for UDP. Pending_udp takes milliseconds. diff --git a/iterator/iter_delegpt.c b/iterator/iter_delegpt.c index feba9cab5..e4e0569b8 100644 --- a/iterator/iter_delegpt.c +++ b/iterator/iter_delegpt.c @@ -98,15 +98,20 @@ delegpt_add_target(struct delegpt* dp, struct region* region, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, socklen_t addrlen) { - struct delegpt_addr* a; struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); if(!ns) { /* ignore it */ return 1; } ns->resolved = 1; - - a = (struct delegpt_addr*)region_alloc(region, + return delegpt_add_addr(dp, region, addr, addrlen); +} + +int +delegpt_add_addr(struct delegpt* dp, struct region* region, + struct sockaddr_storage* addr, socklen_t addrlen) +{ + struct delegpt_addr* a = (struct delegpt_addr*)region_alloc(region, sizeof(struct delegpt_addr)); if(!a) return 0; @@ -118,7 +123,6 @@ delegpt_add_target(struct delegpt* dp, struct region* region, memcpy(&a->addr, addr, addrlen); a->addrlen = addrlen; return 1; - } void delegpt_log(struct delegpt* dp) @@ -127,6 +131,10 @@ void delegpt_log(struct delegpt* dp) struct delegpt_ns* ns; struct delegpt_addr* a; dname_str(dp->name, buf); + if(dp->nslist == NULL && dp->target_list == NULL) { + log_info("DelegationPoint<%s>: empty", buf); + return; + } log_info("DelegationPoint<%s>:", buf); for(ns = dp->nslist; ns; ns = ns->next) { dname_str(ns->name, buf); diff --git a/iterator/iter_delegpt.h b/iterator/iter_delegpt.h index b1ef8acb0..827f93b64 100644 --- a/iterator/iter_delegpt.h +++ b/iterator/iter_delegpt.h @@ -128,7 +128,7 @@ int delegpt_set_name(struct delegpt* dp, struct region* region, uint8_t* name); int delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name); /** - * Add address to the delegation point. + * Add target address to the delegation point. * @param dp: delegation point. * @param region: where to allocate the info. * @param name: name for which target was found (must be in nslist). @@ -142,6 +142,17 @@ int delegpt_add_target(struct delegpt* dp, struct region* region, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, socklen_t addrlen); +/** + * Add address to the delegation point. No servername is associated or checked. + * @param dp: delegation point. + * @param region: where to allocate the info. + * @param addr: the address. + * @param addrlen: the length of addr. + * @return false on error. + */ +int delegpt_add_addr(struct delegpt* dp, struct region* region, + struct sockaddr_storage* addr, socklen_t addrlen); + /** * Print the delegation point to the log. For debugging. * @param dp: delegation point. diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index 78b74c977..def25eb81 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -44,6 +44,7 @@ #include "iterator/iter_delegpt.h" #include "util/region-allocator.h" #include "util/log.h" +#include "util/config_file.h" #include "util/net_help.h" #include "util/data/dname.h" @@ -147,8 +148,7 @@ compile_time_root_prime(struct region* r) /** insert new hint info into hint structure */ static int -hints_insert(struct iter_hints* hints, uint16_t c, uint8_t* name, - size_t namelen, int namelabs, struct delegpt* dp) +hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp) { struct iter_hints_stub* node = region_alloc(hints->region, sizeof(struct iter_hints_stub)); @@ -156,11 +156,11 @@ hints_insert(struct iter_hints* hints, uint16_t c, uint8_t* name, return 0; node->node.key = node; node->hint_class = c; - node->name = region_alloc_init(hints->region, name, namelen); + node->name = region_alloc_init(hints->region, dp->name, dp->namelen); if(!node->name) return 0; - node->namelen = namelen; - node->namelabs = namelabs; + node->namelen = dp->namelen; + node->namelabs = dp->namelabs; node->dp = dp; if(!rbtree_insert(hints->tree, &node->node)) { log_err("second hints ignored."); @@ -197,24 +197,123 @@ init_parents(struct iter_hints* hints) } } +/** set stub name */ +static int +read_stubs_name(struct iter_hints* hints, struct config_stub* s, + struct delegpt* dp) +{ + ldns_rdf* rdf; + if(!s->name) { + log_err("stub zone without a name"); + return 0; + } + rdf = ldns_dname_new_frm_str(s->name); + if(!rdf) { + log_err("cannot parse stub zone name %s", s->name); + return 0; + } + if(!delegpt_set_name(dp, hints->region, ldns_rdf_data(rdf))) { + ldns_rdf_deep_free(rdf); + log_err("out of memory"); + return 0; + } + ldns_rdf_deep_free(rdf); + return 1; +} + +/** set stub host names */ +static int +read_stubs_host(struct iter_hints* hints, struct config_stub* s, + struct delegpt* dp) +{ + struct config_strlist* p; + ldns_rdf* rdf; + for(p = s->hosts; p; p = p->next) { + log_assert(p->str); + rdf = ldns_dname_new_frm_str(p->str); + if(!rdf) { + log_err("cannot parse stub %s nameserver name: '%s'", + s->name, p->str); + return 0; + } + if(!delegpt_add_ns(dp, hints->region, ldns_rdf_data(rdf))) { + ldns_rdf_deep_free(rdf); + log_err("out of memory"); + return 0; + } + ldns_rdf_deep_free(rdf); + } + return 1; +} + +/** set stub server addresses */ +static int +read_stubs_addr(struct iter_hints* hints, struct config_stub* s, + struct delegpt* dp) +{ + struct config_strlist* p; + struct sockaddr_storage addr; + socklen_t addrlen; + for(p = s->addrs; p; p = p->next) { + log_assert(p->str); + if(!ipstrtoaddr(p->str, UNBOUND_DNS_PORT, &addr, &addrlen)) { + log_err("cannot parse stub %s ip address: '%s'", + s->name, p->str); + return 0; + } + if(!delegpt_add_addr(dp, hints->region, &addr, addrlen)) { + log_err("out of memory"); + return 0; + } + } + return 1; +} + +/** read stubs config */ +static int +read_stubs(struct iter_hints* hints, struct config_file* cfg) +{ + struct config_stub* s; + for(s = cfg->stubs; s; s = s->next) { + struct delegpt* dp = delegpt_create(hints->region); + if(!dp) { + log_err("out of memory"); + return 0; + } + if(!read_stubs_name(hints, s, dp) || + !read_stubs_host(hints, s, dp) || + !read_stubs_addr(hints, s, dp)) + return 0; + if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp)) + return 0; + delegpt_log(dp); + } + return 1; +} + int -hints_apply_cfg(struct iter_hints* hints, struct config_file* ATTR_UNUSED(cfg)) +hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg) { - struct delegpt* dp; free(hints->tree); hints->tree = rbtree_create(stub_cmp); if(!hints->tree) return 0; - /* TODO: read hints from file named in cfg */ + /* TODO: read root hints from file named in cfg */ - /* use fallback compiletime root hints */ - dp = compile_time_root_prime(hints->region); - if(!dp) - return 0; - if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp->name, dp->namelen, - dp->namelabs, dp)) + /* read stub hints */ + if(!read_stubs(hints, cfg)) return 0; - delegpt_log(dp); + + /* use fallback compiletime root hints */ + if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) { + struct delegpt* dp = compile_time_root_prime(hints->region); + verbose(VERB_ALGO, "no config, using builtin root hints."); + if(!dp) + return 0; + if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp)) + return 0; + delegpt_log(dp); + } init_parents(hints); return 1; @@ -235,3 +334,44 @@ hints_lookup_root(struct iter_hints* hints, uint16_t qclass) return NULL; return stub->dp; } + +struct delegpt* +hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, + uint16_t qclass, struct delegpt* cache_dp) +{ + /* first lookup the stub */ + rbnode_t* res = NULL; + struct iter_hints_stub *result; + struct iter_hints_stub key; + key.node.key = &key; + key.hint_class = qclass; + key.name = qname; + key.namelabs = dname_count_size_labels(qname, &key.namelen); + if(rbtree_find_less_equal(hints->tree, &key, &res)) { + /* exact */ + result = (struct iter_hints_stub*)res; + } else { + /* smaller element (or no element) */ + int m; + result = (struct iter_hints_stub*)res; + if(!result || result->hint_class != qclass) + return NULL; + /* count number of labels matched */ + (void)dname_lab_cmp(result->name, result->namelabs, key.name, + key.namelabs, &m); + while(result) { /* go up until qname is subdomain of stub */ + if(result->namelabs <= m) + break; + result = result->parent; + } + if(!result) + return NULL; + } + /* + * If our cached delegation point is above the hint, we need to prime. + */ + if(dname_strict_subdomain(result->dp->name, result->dp->namelabs, + cache_dp->name, cache_dp->namelabs)) + return result->dp; /* need to prime this stub */ + return NULL; +} diff --git a/iterator/iter_hints.h b/iterator/iter_hints.h index 61cf1d96f..6b8d106e7 100644 --- a/iterator/iter_hints.h +++ b/iterator/iter_hints.h @@ -112,4 +112,18 @@ int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg); */ struct delegpt* hints_lookup_root(struct iter_hints* hints, uint16_t qclass); +/** + * Given a qname/qclass combination, and the delegation point from the cache + * for this qname/qclass, determine if this combination indicates that a + * stub hint exists and must be primed. + * + * @param qname The qname that generated the delegation point. + * @param qclass The qclass that generated the delegation point. + * @param dp The cache generated delegation point. + * @return A priming delegation point if there is a stub hint that must + * be primed, otherwise null. + */ +struct delegpt* hints_lookup_stub(struct iter_hints* hints, + uint8_t* qname, uint16_t qclass, struct delegpt* dp); + #endif /* ITERATOR_ITER_HINTS_H */ diff --git a/iterator/iterator.c b/iterator/iterator.c index 1f6e033e1..0dc26bdb7 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -180,18 +180,12 @@ iter_handlereply(struct module_qstate* qstate, int id, return 1; } -/** iterator operate on a query */ +/** perform forwarder functionality */ static void -iter_operate(struct module_qstate* qstate, enum module_ev event, int id, +perform_forward(struct module_qstate* qstate, enum module_ev event, int id, struct outbound_entry* outbound) { - verbose(VERB_ALGO, "iterator[module %d] operate: extstate:%s event:%s", - id, strextstate(qstate->ext_state[id]), strmodulevent(event)); - if(event == module_event_new) { - if(!iter_new(qstate, id)) - qstate->ext_state[id] = module_error; - return; - } + verbose(VERB_ALGO, "iterator: forwarding"); /* it must be a query reply */ if(!outbound) { verbose(VERB_ALGO, "query reply was not serviced"); @@ -211,6 +205,25 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, qstate->ext_state[id] = module_error; } +/** iterator operate on a query */ +static void +iter_operate(struct module_qstate* qstate, enum module_ev event, int id, + struct outbound_entry* outbound) +{ + struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id]; + verbose(VERB_ALGO, "iterator[module %d] operate: extstate:%s event:%s", + id, strextstate(qstate->ext_state[id]), strmodulevent(event)); + if(event == module_event_new) { + if(!iter_new(qstate, id)) + qstate->ext_state[id] = module_error; + return; + } + if(ie->fwd_addrlen != 0) { + perform_forward(qstate, event, id, outbound); + return; + } +} + /** iterator cleanup query state */ static void iter_clear(struct module_qstate* qstate, int id) diff --git a/iterator/iterator.h b/iterator/iterator.h index 482ee413d..bb79b8bb5 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -138,7 +138,8 @@ enum iter_state { * Per query state for the iterator module. */ struct iter_qstate { - /** state of the iterator module + /** + * State of the iterator module. * This is the state that event is in or should sent to -- all * requests should start with the INIT_REQUEST_STATE. All * responses should start with QUERY_RESP_STATE. Subsequent @@ -146,7 +147,8 @@ struct iter_qstate { */ enum iter_state state; - /** final state for the iterator module + /** + * Final state for the iterator module. * This is the state that responses should be routed to once the * response is final. For externally initiated queries, this * will be FINISHED_STATE, locally initiated queries will have @@ -159,6 +161,8 @@ struct iter_qstate { * ANSWER section of a response before being sent upstream. */ struct packed_rrset_list* prepend_list; + /** Last element of the prepend list */ + struct packed_rrset_list* prepend_last; /** * This is the current delegation point for an in-progress query. This @@ -167,6 +171,11 @@ struct iter_qstate { */ struct delegpt* dp; + /** + * Current address target. + */ + struct delegpt_addr* current_target; + /** number of outstanding target sub queries */ int num_target_queries; @@ -192,6 +201,7 @@ struct iter_qstate { /** * Get the iterator function block. + * @return: function block with function pointers to iterator methods. */ struct module_func_block* iter_get_funcblock(); diff --git a/testcode/unitdname.c b/testcode/unitdname.c index 570709d95..8789d2b66 100644 --- a/testcode/unitdname.c +++ b/testcode/unitdname.c @@ -361,6 +361,42 @@ dname_test_dname_lab_cmp() unit_assert(ml == 4); } +/** test dname_strict_subdomain */ +static void +dname_test_strict_subdomain() +{ + unit_assert(!dname_strict_subdomain( + (uint8_t*)"", 1, + (uint8_t*)"", 1)); + unit_assert(dname_strict_subdomain( + (uint8_t*)"\003com", 2, + (uint8_t*)"", 1)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"", 1, + (uint8_t*)"\003com", 2)); + unit_assert(dname_strict_subdomain( + (uint8_t*)"\007example\003com", 3, + (uint8_t*)"\003com", 2)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"\003com", 2, + (uint8_t*)"\007example\003com", 3)); + unit_assert(dname_strict_subdomain( + (uint8_t*)"\007example\003com", 3, + (uint8_t*)"", 1)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"\003net", 2, + (uint8_t*)"\003com", 2)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"\003net", 2, + (uint8_t*)"\003org", 2)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"\007example\003net", 3, + (uint8_t*)"\003org", 2)); + unit_assert(!dname_strict_subdomain( + (uint8_t*)"\003net", 2, + (uint8_t*)"\007example\003org", 3)); +} + void dname_test() { ldns_buffer* buff = ldns_buffer_new(65800); @@ -372,5 +408,6 @@ void dname_test() dname_test_count_size_labels(); dname_test_dname_lab_cmp(); dname_test_pkt_dname_len(buff); + dname_test_strict_subdomain(); ldns_buffer_free(buff); } diff --git a/util/config_file.c b/util/config_file.c index 23b1fcd4c..42fb8bf2f 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -98,6 +98,7 @@ config_create() cfg->do_daemonize = 1; cfg->num_ifs = 0; cfg->ifs = NULL; + cfg->stubs = NULL; return cfg; error_exit: config_delete(cfg); @@ -141,6 +142,19 @@ config_read(struct config_file* cfg, const char* filename) return 1; } +/** delete config strlist */ +static void +config_delstrlist(struct config_strlist* p) +{ + struct config_strlist *np; + while(p) { + np = p->next; + free(p->str); + free(p); + p = np; + } +} + void config_delete(struct config_file* cfg) { @@ -157,6 +171,16 @@ config_delete(struct config_file* cfg) free(cfg->ifs[i]); free(cfg->ifs); } + if(cfg->stubs) { + struct config_stub* p = cfg->stubs, *np; + while(p) { + np = p->next; + free(p->name); + config_delstrlist(p->hosts); + config_delstrlist(p->addrs); + p = np; + } + } free(cfg); } diff --git a/util/config_file.h b/util/config_file.h index 8444a594d..4df0c88d4 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -41,6 +41,8 @@ #ifndef UTIL_CONFIG_FILE_H #define UTIL_CONFIG_FILE_H +struct config_stub; +struct config_strlist; /** * The configuration options. @@ -102,6 +104,9 @@ struct config_file { /** interface description strings (IP addresses) */ char **ifs; + /** the stub definitions, linked list */ + struct config_stub* stubs; + /** chrootdir, if not "" or chroot will be done */ char* chrootdir; /** username to change to, if not "". */ @@ -117,6 +122,30 @@ struct config_file { int do_daemonize; }; +/** + * Stub config options + */ +struct config_stub { + /** next in list */ + struct config_stub* next; + /** domain name (in text) of the stub apex domain */ + char* name; + /** list of stub nameserver hosts (domain name) */ + struct config_strlist* hosts; + /** list of stub nameserver addresses (IP address) */ + struct config_strlist* addrs; +}; + +/** + * List of strings for config options + */ +struct config_strlist { + /** next item in list */ + struct config_strlist* next; + /** config option string */ + char* str; +}; + /** * Create config file structure. Filled with default values. * @return: the new structure or NULL on memory error. diff --git a/util/configlexer.lex b/util/configlexer.lex index 1ab5ffa91..8f3a42c42 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -127,6 +127,10 @@ infra-cache-slabs{COLON} { YDOUT; return VAR_INFRA_CACHE_SLABS;} infra-cache-numhosts{COLON} { YDOUT; return VAR_INFRA_CACHE_NUMHOSTS;} infra-cache-numlame{COLON} { YDOUT; return VAR_INFRA_CACHE_NUMLAME;} num-queries-per-thread{COLON} { YDOUT; return VAR_NUM_QUERIES_PER_THREAD;} +stub-zone{COLON} { YDOUT; return VAR_STUB_ZONE;} +name{COLON} { YDOUT; return VAR_NAME;} +stub-addr{COLON} { YDOUT; return VAR_STUB_ADDR;} +stub-host{COLON} { YDOUT; return VAR_STUB_HOST;} {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} /* Quoted strings. Strip leading and ending quotes */ diff --git a/util/configparser.y b/util/configparser.y index 08c7dfa55..919d3016e 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -75,7 +75,8 @@ extern struct config_parser_state* cfg_parser; %token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD %token VAR_RRSET_CACHE_SIZE VAR_RRSET_CACHE_SLABS VAR_OUTGOING_NUM_TCP %token VAR_INFRA_HOST_TTL VAR_INFRA_LAME_TTL VAR_INFRA_CACHE_SLABS -%token VAR_INFRA_CACHE_NUMHOSTS VAR_INFRA_CACHE_NUMLAME +%token VAR_INFRA_CACHE_NUMHOSTS VAR_INFRA_CACHE_NUMLAME VAR_NAME +%token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -102,7 +103,23 @@ content_server: server_num_threads | server_verbosity | server_port | server_rrset_cache_slabs | server_outgoing_num_tcp | server_infra_host_ttl | server_infra_lame_ttl | server_infra_cache_slabs | server_infra_cache_numhosts | - server_infra_cache_numlame + server_infra_cache_numlame | stubstart contents_stub + ; +stubstart: VAR_STUB_ZONE + { + struct config_stub* s; + OUTYY(("\nP(stub_zone:)\n")); + s = (struct config_stub*)calloc(1, sizeof(struct config_stub)); + if(s) { + s->next = cfg_parser->cfg->stubs; + cfg_parser->cfg->stubs = s; + } else + yyerror("out of memory"); + } + ; +contents_stub: contents_stub content_stub + | ; +content_stub: stub_name | stub_host | stub_addr ; server_num_threads: VAR_NUM_THREADS STRING { @@ -360,6 +377,38 @@ server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING free($2); } ; +stub_name: VAR_NAME STRING + { + OUTYY(("P(name:%s)\n", $2)); + cfg_parser->cfg->stubs->name = $2; + } + ; +stub_host: VAR_STUB_HOST STRING + { + struct config_strlist *s = (struct config_strlist*)calloc(1, + sizeof(struct config_strlist)); + OUTYY(("P(stub-host:%s)\n", $2)); + if(s) { + s->str = $2; + s->next = cfg_parser->cfg->stubs->hosts; + cfg_parser->cfg->stubs->hosts = s; + } else + yyerror("out of memory"); + } + ; +stub_addr: VAR_STUB_ADDR STRING + { + struct config_strlist *s = (struct config_strlist*)calloc(1, + sizeof(struct config_strlist)); + OUTYY(("P(stub-addr:%s)\n", $2)); + if(s) { + s->str = $2; + s->next = cfg_parser->cfg->stubs->addrs; + cfg_parser->cfg->stubs->addrs = s; + } else + yyerror("out of memory"); + } + ; %% /* parse helper routines could be here */ diff --git a/util/data/dname.c b/util/data/dname.c index 38ce5fa80..60c3e7bce 100644 --- a/util/data/dname.c +++ b/util/data/dname.c @@ -509,3 +509,18 @@ void dname_str(uint8_t* dname, char* str) } *s = 0; } + +int +dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2) +{ + int m; + /* check subdomain: d1: www.example.com. and d2: example.com. */ + if(labs2 >= labs1) + return 0; + if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) { + /* subdomain if all labels match */ + return (m == labs2); + } + return 0; +} + diff --git a/util/data/dname.h b/util/data/dname.h index f25754dfc..278ebe16e 100644 --- a/util/data/dname.h +++ b/util/data/dname.h @@ -154,6 +154,17 @@ int dname_count_size_labels(uint8_t* dname, size_t* size); */ int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs); +/** + * See if domain name d1 is a strict subdomain of d2. + * That is a subdomain, but not equal. + * @param d1: domain name, uncompressed wireformat + * @param labs1: number of labels in d1, including root label. + * @param d2: domain name, uncompressed wireformat + * @param labs2: number of labels in d2, including root label. + * @return true if d1 is a subdomain of d2, but not equal to d2. + */ +int dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2); + /** * Debug helper. Print wireformat dname to output. * @param out: like stdout or a file. diff --git a/util/module.c b/util/module.c index 52f6bdc11..f14ca8a5b 100644 --- a/util/module.c +++ b/util/module.c @@ -68,3 +68,22 @@ strmodulevent(enum module_ev e) } return "bad_event_value"; } + +void +module_subreq_remove(struct module_qstate* sub) +{ + struct module_qstate* p, *prev = NULL; + if(!sub || !sub->parent) + return; + p = sub->parent->subquery_first; + while(p) { + if(p == sub) { + /* snip it off */ + if(prev) prev->subquery_next = p->subquery_next; + else sub->parent->subquery_first = p->subquery_next; + return; + } + prev = p; + p = p->subquery_next; + } +} diff --git a/util/module.h b/util/module.h index b3cb8bca2..288606e5c 100644 --- a/util/module.h +++ b/util/module.h @@ -268,4 +268,11 @@ const char* strextstate(enum module_ext_state s); */ const char* strmodulevent(enum module_ev e); +/** + * Remove subqrequest from list. + * @param sub: subrequest. Parent pointer used to access list. + * It is snipped off. + */ +void module_subreq_remove(struct module_qstate* sub); + #endif /* UTIL_MODULE_H */ diff --git a/util/net_help.c b/util/net_help.c index efe82281d..79b676e27 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -142,7 +142,7 @@ log_addr(const char* str, struct sockaddr_storage* addr, socklen_t addrlen) strncpy(dest, "(inet_ntop error)", sizeof(dest)); } port = ntohs(((struct sockaddr_in*)addr)->sin_port); - verbose(VERB_DETAIL, "%s %s %s:%d (len %d)", + verbose(VERB_DETAIL, "%s %s %s %d (len %d)", str, family, dest, (int)port, (int)addrlen); }