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.
*/
/** 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 */
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;
}
|| 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;
}
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;
}
|| 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;
}
/* 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;
}
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;
+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.
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;
memcpy(&a->addr, addr, addrlen);
a->addrlen = addrlen;
return 1;
-
}
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);
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).
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.
#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"
/** 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));
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.");
}
}
+/** 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;
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;
+}
*/
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 */
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");
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)
* 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
*/
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
* 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
*/
struct delegpt* dp;
+ /**
+ * Current address target.
+ */
+ struct delegpt_addr* current_target;
+
/** number of outstanding target sub queries */
int num_target_queries;
/**
* Get the iterator function block.
+ * @return: function block with function pointers to iterator methods.
*/
struct module_func_block* iter_get_funcblock();
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);
dname_test_count_size_labels();
dname_test_dname_lab_cmp();
dname_test_pkt_dname_len(buff);
+ dname_test_strict_subdomain();
ldns_buffer_free(buff);
}
cfg->do_daemonize = 1;
cfg->num_ifs = 0;
cfg->ifs = NULL;
+ cfg->stubs = NULL;
return cfg;
error_exit:
config_delete(cfg);
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)
{
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);
}
#ifndef UTIL_CONFIG_FILE_H
#define UTIL_CONFIG_FILE_H
+struct config_stub;
+struct config_strlist;
/**
* The configuration options.
/** 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 "". */
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.
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 */
%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 ;
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
{
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 */
}
*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;
+}
+
*/
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.
}
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;
+ }
+}
*/
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 */
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);
}