]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
preparatory work for iterator.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 24 May 2007 13:24:44 +0000 (13:24 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 24 May 2007 13:24:44 +0000 (13:24 +0000)
git-svn-id: file:///svn/unbound/trunk@336 be551aaa-1e26-0410-a405-d3ace91eadb9

18 files changed:
daemon/worker.c
doc/Changelog
iterator/iter_delegpt.c
iterator/iter_delegpt.h
iterator/iter_hints.c
iterator/iter_hints.h
iterator/iterator.c
iterator/iterator.h
testcode/unitdname.c
util/config_file.c
util/config_file.h
util/configlexer.lex
util/configparser.y
util/data/dname.c
util/data/dname.h
util/module.c
util/module.h
util/net_help.c

index 165cc9a593c7200261a45af14ea24351247f53fe..908939583acefe51382f40de376b93f914a57c29 100644 (file)
@@ -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; i<worker->daemon->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; i<worker->daemon->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;
index c667f19d6a9a306348df02f21aa026422468be01..b7178909f1139db1ddae140c6c60138d54fe56fb 100644 (file)
@@ -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.
index feba9cab5f238561a00dedbccd194bf235af8304..e4e0569b8bf637d0762f67231183b0c8e5375ec2 100644 (file)
@@ -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);
index b1ef8acb03dc1d9e86880a24ed42f256355a4c2a..827f93b64fbc5f8303ee0212907b13b61e6ae0d0 100644 (file)
@@ -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.
index 78b74c977d8c90940c365444262b709b90a6f776..def25eb815e38e833a0fe7c9ed1fae7295d59de9 100644 (file)
@@ -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;
+}
index 61cf1d96fe7126ab178ba30bcfb92f5594808fe3..6b8d106e7dbc0b10dd4a999027645b24d0d1dd72 100644 (file)
@@ -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 */
index 1f6e033e1ad894a87bb8c139a1b8f5c5fa97af62..0dc26bdb768a8bc0d35509313b435f320c9bd7b0 100644 (file)
@@ -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)
index 482ee413d0c54386e74063d1ba5c8ee6662639b0..bb79b8bb5280fab1bd8b871a3f71cd8550b9c0a4 100644 (file)
@@ -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();
 
index 570709d958a491e4e7d0ffdbe6e615c7409de8f9..8789d2b66fd794b581136eb9994659d2145057d1 100644 (file)
@@ -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);
 }
index 23b1fcd4c1fc5d70ece2c7761c5b7312b54dd8c0..42fb8bf2f454706d198b4ecb262dcb51fdd47290 100644 (file)
@@ -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);
 }
 
index 8444a594db650f5e15a892e44de6aa705490dd91..4df0c88d4f47321b0df0e89e9d25060d69537e2e 100644 (file)
@@ -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.
index 1ab5ffa911159297d10b676e38001e5a45e5ac26..8f3a42c42ee2d53cf6890009bf2353e39b3a8d71 100644 (file)
@@ -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 */
index 08c7dfa55217ebacf072499c7cee264a6421d157..919d3016ea9222449bfdaca71c0da145ecf9db42 100644 (file)
@@ -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 */
index 38ce5fa80faa0fc13833abd15d025d263a51d04a..60c3e7bce1e924ec3521621eb74c1516c6b98fea 100644 (file)
@@ -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;
+}
+
index f25754dfc56da927c6934f211f40b2664d233fcf..278ebe16eb5f9444b46f480a5fb3def1d2c84429 100644 (file)
@@ -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.
index 52f6bdc111032cccd4f4e1bf91972ce497bb3257..f14ca8a5b733cb7e4490e276b28ca25bfaa261c0 100644 (file)
@@ -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;
+       }
+}
index b3cb8bca26cafd023782141043898960bba99c1e..288606e5c3944e1e02469d281f129c542974b7f0 100644 (file)
@@ -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 */
index efe82281d4a94e1c67573c2b26f87da9595f1e29..79b676e2786b350336b4b3c513bbbac7ad8df87e 100644 (file)
@@ -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);
 }