summaryrefslogtreecommitdiff
path: root/contrib/unbound/util/data
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 12:57:34 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-12 12:57:34 +0000
commitbc89214039cbcc96f25c54c9829392068547de84 (patch)
tree78a89aa4e3eba1c22fc47f0d139a3af81f4adfde /contrib/unbound/util/data
parent986ba33c7a3bc8f5ba13c7a9d6512602f6e32c61 (diff)
parentbd51c20871bac7a49ea0adc443050f2894cfd5f3 (diff)
downloadsrc-test2-bc89214039cbcc96f25c54c9829392068547de84.tar.gz
src-test2-bc89214039cbcc96f25c54c9829392068547de84.zip
Notes
Diffstat (limited to 'contrib/unbound/util/data')
-rw-r--r--contrib/unbound/util/data/msgencode.c73
-rw-r--r--contrib/unbound/util/data/msgparse.c19
-rw-r--r--contrib/unbound/util/data/msgparse.h9
-rw-r--r--contrib/unbound/util/data/msgreply.c153
-rw-r--r--contrib/unbound/util/data/msgreply.h149
5 files changed, 372 insertions, 31 deletions
diff --git a/contrib/unbound/util/data/msgencode.c b/contrib/unbound/util/data/msgencode.c
index 034bb24bd6e4..5d3a24762178 100644
--- a/contrib/unbound/util/data/msgencode.c
+++ b/contrib/unbound/util/data/msgencode.c
@@ -48,6 +48,7 @@
#include "util/regional.h"
#include "util/net_help.h"
#include "sldns/sbuffer.h"
+#include "services/localzone.h"
/** return code that means the function ran out of memory. negative so it does
* not conflict with DNS rcodes. */
@@ -534,7 +535,11 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
{
int r;
size_t i, setstart;
- *num_rrs = 0;
+ /* we now allow this function to be called multiple times for the
+ * same section, incrementally updating num_rrs. The caller is
+ * responsible for initializing it (which is the case in the current
+ * implementation). */
+
if(s != LDNS_SECTION_ADDITIONAL) {
if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY)
dnssec = 1; /* include all types in ANY answer */
@@ -581,17 +586,20 @@ static int
insert_query(struct query_info* qinfo, struct compress_tree_node** tree,
sldns_buffer* buffer, struct regional* region)
{
+ uint8_t* qname = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname : qinfo->qname;
+ size_t qname_len = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
if(sldns_buffer_remaining(buffer) <
qinfo->qname_len+sizeof(uint16_t)*2)
return RETVAL_TRUNC; /* buffer too small */
/* the query is the first name inserted into the tree */
- if(!compress_tree_store(qinfo->qname,
- dname_count_labels(qinfo->qname),
+ if(!compress_tree_store(qname, dname_count_labels(qname),
sldns_buffer_position(buffer), region, NULL, tree))
return RETVAL_OUTMEM;
- if(sldns_buffer_current(buffer) == qinfo->qname)
- sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len);
- else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
+ if(sldns_buffer_current(buffer) == qname)
+ sldns_buffer_skip(buffer, (ssize_t)qname_len);
+ else sldns_buffer_write(buffer, qname, qname_len);
sldns_buffer_write_u16(buffer, qinfo->qtype);
sldns_buffer_write_u16(buffer, qinfo->qclass);
return RETVAL_OK;
@@ -662,6 +670,33 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
* for different roundrobins for sequential id client senders. */
rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;
+ /* "prepend" any local alias records in the answer section if this
+ * response is supposed to be authoritative. Currently it should
+ * be a single CNAME record (sanity-checked in worker_handle_request())
+ * but it can be extended if and when we support more variations of
+ * aliases. */
+ if(qinfo->local_alias && (flags & BIT_AA)) {
+ struct reply_info arep;
+ time_t timezero = 0; /* to use the 'authoritative' TTL */
+ memset(&arep, 0, sizeof(arep));
+ arep.flags = rep->flags;
+ arep.an_numrrsets = 1;
+ arep.rrset_count = 1;
+ arep.rrsets = &qinfo->local_alias->rrset;
+ if((r=insert_section(&arep, 1, &ancount, buffer, 0,
+ timezero, region, &tree, LDNS_SECTION_ANSWER,
+ qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
+ if(r == RETVAL_TRUNC) {
+ /* create truncated message */
+ sldns_buffer_write_u16_at(buffer, 6, ancount);
+ LDNS_TC_SET(sldns_buffer_begin(buffer));
+ sldns_buffer_flip(buffer);
+ return 1;
+ }
+ return 0;
+ }
+ }
+
/* insert answer section */
if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
@@ -782,6 +817,15 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
}
if(secure && (dnssec || (qflags&BIT_AD)))
flags |= BIT_AD;
+ /* restore AA bit if we have a local alias and the response can be
+ * authoritative. Also clear AD bit if set as the local data is the
+ * primary answer. */
+ if(qinf->local_alias &&
+ (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR ||
+ FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) {
+ flags |= BIT_AA;
+ flags &= ~BIT_AD;
+ }
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
if(udpsize < LDNS_HEADER_SIZE)
return 0;
@@ -807,13 +851,17 @@ void
qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
{
uint16_t flags = 0; /* QUERY, NOERROR */
+ const uint8_t* qname = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname : qinfo->qname;
+ size_t qname_len = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len;
sldns_buffer_clear(pkt);
log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
sldns_buffer_skip(pkt, 2); /* id done later */
sldns_buffer_write_u16(pkt, flags);
sldns_buffer_write_u16(pkt, 1); /* query count */
sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
- sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
+ sldns_buffer_write(pkt, qname, qname_len);
sldns_buffer_write_u16(pkt, qinfo->qtype);
sldns_buffer_write_u16(pkt, qinfo->qclass);
sldns_buffer_flip(pkt);
@@ -838,9 +886,14 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
sldns_buffer_write(buf, &flags, sizeof(uint16_t));
sldns_buffer_write(buf, &flags, sizeof(uint16_t));
if(qinfo) {
- if(sldns_buffer_current(buf) == qinfo->qname)
- sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
- else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
+ const uint8_t* qname = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname : qinfo->qname;
+ size_t qname_len = qinfo->local_alias ?
+ qinfo->local_alias->rrset->rk.dname_len :
+ qinfo->qname_len;
+ if(sldns_buffer_current(buf) == qname)
+ sldns_buffer_skip(buf, (ssize_t)qname_len);
+ else sldns_buffer_write(buf, qname, qname_len);
sldns_buffer_write_u16(buf, qinfo->qtype);
sldns_buffer_write_u16(buf, qinfo->qclass);
}
diff --git a/contrib/unbound/util/data/msgparse.c b/contrib/unbound/util/data/msgparse.c
index 1d565c1ea280..3774054f5700 100644
--- a/contrib/unbound/util/data/msgparse.c
+++ b/contrib/unbound/util/data/msgparse.c
@@ -1072,3 +1072,22 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
return 0;
}
+
+void
+log_edns_opt_list(enum verbosity_value level, const char* info_str,
+ struct edns_option* list)
+{
+ if(verbosity >= level && list) {
+ char str[128], *s;
+ size_t slen;
+ verbose(level, "%s", info_str);
+ while(list) {
+ s = str;
+ slen = sizeof(str);
+ (void)sldns_wire2str_edns_option_print(&s, &slen, list->opt_code,
+ list->opt_data, list->opt_len);
+ verbose(level, " %s", str);
+ list = list->next;
+ }
+ }
+}
diff --git a/contrib/unbound/util/data/msgparse.h b/contrib/unbound/util/data/msgparse.h
index cae988ff9950..594517b2db11 100644
--- a/contrib/unbound/util/data/msgparse.h
+++ b/contrib/unbound/util/data/msgparse.h
@@ -322,4 +322,13 @@ struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg,
*/
void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset);
+/**
+ * Log the edns options in the edns option list.
+ * @param level: the verbosity level.
+ * @param info_str: the informational string to be printed before the options.
+ * @param list: the edns option list.
+ */
+void log_edns_opt_list(enum verbosity_value level, const char* info_str,
+ struct edns_option* list);
+
#endif /* UTIL_DATA_MSGPARSE_H */
diff --git a/contrib/unbound/util/data/msgreply.c b/contrib/unbound/util/data/msgreply.c
index f8a24918dcad..2caee7789fde 100644
--- a/contrib/unbound/util/data/msgreply.c
+++ b/contrib/unbound/util/data/msgreply.c
@@ -52,6 +52,8 @@
#include "util/data/msgencode.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
+#include "util/module.h"
+#include "util/fptr_wlist.h"
/** MAX TTL default for messages and rrsets */
time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
@@ -76,6 +78,7 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
qinf->qname_len = msg->qname_len;
qinf->qtype = msg->qtype;
qinf->qclass = msg->qclass;
+ qinf->local_alias = NULL;
return 1;
}
@@ -451,6 +454,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
int ret;
qinf->qname = NULL;
+ qinf->local_alias = NULL;
*rep = NULL;
if(!(msg = regional_alloc(region, sizeof(*msg)))) {
return LDNS_RCODE_SERVFAIL;
@@ -542,6 +546,7 @@ query_info_parse(struct query_info* m, sldns_buffer* query)
return 0; /* need qtype, qclass */
m->qtype = sldns_buffer_read_u16(query);
m->qclass = sldns_buffer_read_u16(query);
+ m->local_alias = NULL;
return 1;
}
@@ -871,9 +876,12 @@ int edns_opt_append(struct edns_data* edns, struct regional* region,
opt->next = NULL;
opt->opt_code = code;
opt->opt_len = len;
- opt->opt_data = regional_alloc_init(region, data, len);
- if(!opt->opt_data)
- return 0;
+ opt->opt_data = NULL;
+ if(len > 0) {
+ opt->opt_data = regional_alloc_init(region, data, len);
+ if(!opt->opt_data)
+ return 0;
+ }
/* append at end of list */
prevp = &edns->opt_list;
@@ -883,13 +891,138 @@ int edns_opt_append(struct edns_data* edns, struct regional* region,
return 1;
}
-int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region)
+int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
+ uint8_t* data, struct regional* region)
+{
+ struct edns_option** prevp;
+ struct edns_option* opt;
+
+ /* allocate new element */
+ opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
+ if(!opt)
+ return 0;
+ opt->next = NULL;
+ opt->opt_code = code;
+ opt->opt_len = len;
+ opt->opt_data = NULL;
+ if(len > 0) {
+ opt->opt_data = regional_alloc_init(region, data, len);
+ if(!opt->opt_data)
+ return 0;
+ }
+
+ /* append at end of list */
+ prevp = list;
+ while(*prevp != NULL) {
+ prevp = &((*prevp)->next);
+ }
+ *prevp = opt;
+ return 1;
+}
+
+int edns_opt_list_remove(struct edns_option** list, uint16_t code)
+{
+ /* The list should already be allocated in a region. Freeing the
+ * allocated space in a region is not possible. We just unlink the
+ * required elements and they will be freed together with the region. */
+
+ struct edns_option* prev;
+ struct edns_option* curr;
+ if(!list || !(*list)) return 0;
+
+ /* Unlink and repoint if the element(s) are first in list */
+ while(list && *list && (*list)->opt_code == code) {
+ *list = (*list)->next;
+ }
+
+ if(!list || !(*list)) return 1;
+ /* Unlink elements and reattach the list */
+ prev = *list;
+ curr = (*list)->next;
+ while(curr != NULL) {
+ if(curr->opt_code == code) {
+ prev->next = curr->next;
+ curr = curr->next;
+ } else {
+ prev = curr;
+ curr = curr->next;
+ }
+ }
+ return 1;
+}
+
+static int inplace_cb_reply_call_generic(
+ struct inplace_cb_reply* callback_list, enum inplace_cb_list_type type,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
{
- (void)region;
- /* remove all edns options from the reply, because only the
- * options that we understand should be in the reply
- * (sec 6.1.2 RFC 6891) */
- edns->opt_list = NULL;
+ struct inplace_cb_reply* cb;
+ struct edns_option* opt_list_out = NULL;
+ if(qstate)
+ opt_list_out = qstate->edns_opts_front_out;
+ for(cb=callback_list; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_reply_generic(cb->cb, type));
+ (void)(*cb->cb)(qinfo, qstate, rep, rcode, edns, &opt_list_out, region,
+ cb->cb_arg);
+ }
+ edns->opt_list = opt_list_out;
+ return 1;
+}
+
+int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
+ struct module_qstate* qstate, struct reply_info* rep, int rcode,
+ struct edns_data* edns, struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
+ qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_cache_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
+ qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_local_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
+ qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_reply_servfail_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region)
+{
+ /* We are going to servfail. Remove any potential edns options. */
+ if(qstate)
+ qstate->edns_opts_front_out = NULL;
+ return inplace_cb_reply_call_generic(
+ env->inplace_cb_lists[inplace_cb_reply_servfail],
+ inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region);
+}
+
+int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
+ uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
+ struct regional* region)
+{
+ struct inplace_cb_query* cb = env->inplace_cb_lists[inplace_cb_query];
+ for(; cb; cb=cb->next) {
+ fptr_ok(fptr_whitelist_inplace_cb_query(cb->cb));
+ (void)(*cb->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen,
+ region, cb->cb_arg);
+ }
return 1;
}
@@ -1000,7 +1133,7 @@ struct edns_option* edns_opt_copy_alloc(struct edns_option* list)
return result;
}
-struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code)
+struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code)
{
struct edns_option* p;
for(p=list; p; p=p->next) {
diff --git a/contrib/unbound/util/data/msgreply.h b/contrib/unbound/util/data/msgreply.h
index b542b75e6970..cc0216133377 100644
--- a/contrib/unbound/util/data/msgreply.h
+++ b/contrib/unbound/util/data/msgreply.h
@@ -49,8 +49,14 @@ struct alloc_cache;
struct iovec;
struct regional;
struct edns_data;
+struct edns_option;
+struct inplace_cb_reply;
+struct inplace_cb_query;
+struct module_qstate;
+struct module_env;
struct msg_parse;
struct rrset_parse;
+struct local_rrset;
/** calculate the prefetch TTL as 90% of original. Calculation
* without numerical overflow (uin32_t) */
@@ -73,6 +79,23 @@ struct query_info {
uint16_t qtype;
/** qclass, host byte order */
uint16_t qclass;
+ /**
+ * Alias local answer(s) for the qname. If 'qname' is an alias defined
+ * in a local zone, this field will be set to the corresponding local
+ * RRset when the alias is determined.
+ * In the initial implementation this can only be a single CNAME RR
+ * (or NULL), but it could possibly be extended to be a DNAME or a
+ * chain of aliases.
+ * Users of this structure are responsible to initialize this field
+ * to be NULL; otherwise other part of query handling code may be
+ * confused.
+ * Users also have to be careful about the lifetime of data. On return
+ * from local zone lookup, it may point to data derived from
+ * configuration that may be dynamically invalidated or data allocated
+ * in an ephemeral regional allocator. A deep copy of the data may
+ * have to be generated if it has to be kept during iterative
+ * resolution. */
+ struct local_rrset* local_alias;
};
/**
@@ -439,29 +462,133 @@ void log_query_info(enum verbosity_value v, const char* str,
/**
* Append edns option to edns data structure
+ * @param edns: the edns data structure to append the edns option to.
+ * @param region: region to allocate the new edns option.
+ * @param code: the edns option's code.
+ * @param len: the edns option's length.
+ * @param data: the edns option's data.
+ * @return false on failure.
*/
int edns_opt_append(struct edns_data* edns, struct regional* region,
uint16_t code, size_t len, uint8_t* data);
/**
+ * Append edns option to edns option list
+ * @param list: the edns option list to append the edns option to.
+ * @param code: the edns option's code.
+ * @param len: the edns option's length.
+ * @param data: the edns option's data.
+ * @param region: region to allocate the new edns option.
+ * @return false on failure.
+ */
+int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
+ uint8_t* data, struct regional* region);
+
+/**
+ * Remove any option found on the edns option list that matches the code.
+ * @param list: the list of edns options.
+ * @param code: the opt code to remove.
+ * @return true when at least one edns option was removed, false otherwise.
+ */
+int edns_opt_list_remove(struct edns_option** list, uint16_t code);
+
+/**
* Find edns option in edns list
* @param list: list of edns options (eg. edns.opt_list)
* @param code: opt code to find.
* @return NULL or the edns_option element.
*/
-struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code);
+struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code);
/**
- * Transform edns data structure from query structure into reply structure.
- * In place transform, for errors and cache replies.
- * @param edns: on input contains the edns from the query. On output contains
- * the edns for the answer. Add new options to the opt_list to put them
- * in the answer (allocated in the region, with edns_opt_append).
- * @param region: to allocate stuff in.
- * @return false on failure (servfail to client, or for some error encodings,
- * no EDNS options in the answer).
- */
-int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region);
+ * Call the registered functions in the inplace_cb_reply linked list.
+ * This function is going to get called while answering with a resolved query.
+ * @param env: module environment.
+ * @param qinfo: query info.
+ * @param qstate: module qstate.
+ * @param rep: Reply info. Could be NULL.
+ * @param rcode: return code.
+ * @param edns: edns data of the reply.
+ * @param region: region to store data.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
+ struct module_qstate* qstate, struct reply_info* rep, int rcode,
+ struct edns_data* edns, struct regional* region);
+
+/**
+ * Call the registered functions in the inplace_cb_reply_cache linked list.
+ * This function is going to get called while answering from cache.
+ * @param env: module environment.
+ * @param qinfo: query info.
+ * @param qstate: module qstate. NULL when replying from cache.
+ * @param rep: Reply info.
+ * @param rcode: return code.
+ * @param edns: edns data of the reply. Edns input can be found here.
+ * @param region: region to store data.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_reply_cache_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region);
+
+/**
+ * Call the registered functions in the inplace_cb_reply_local linked list.
+ * This function is going to get called while answering with local data.
+ * @param env: module environment.
+ * @param qinfo: query info.
+ * @param qstate: module qstate. NULL when replying from cache.
+ * @param rep: Reply info.
+ * @param rcode: return code.
+ * @param edns: edns data of the reply. Edns input can be found here.
+ * @param region: region to store data.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_reply_local_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region);
+
+/**
+ * Call the registered functions in the inplace_cb_reply linked list.
+ * This function is going to get called while answering with a servfail.
+ * @param env: module environment.
+ * @param qinfo: query info.
+ * @param qstate: module qstate. Contains the edns option lists. Could be NULL.
+ * @param rep: Reply info. NULL when servfail.
+ * @param rcode: return code. LDNS_RCODE_SERVFAIL.
+ * @param edns: edns data of the reply. Edns input can be found here if qstate
+ * is NULL.
+ * @param region: region to store data.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_reply_servfail_call(struct module_env* env,
+ struct query_info* qinfo, struct module_qstate* qstate,
+ struct reply_info* rep, int rcode, struct edns_data* edns,
+ struct regional* region);
+
+/**
+ * Call the registered functions in the inplace_cb_query linked list.
+ * This function is going to get called just before sending a query to a
+ * nameserver.
+ * @param env: module environment.
+ * @param qinfo: query info.
+ * @param flags: flags of the query.
+ * @param addr: to which server to send the query.
+ * @param addrlen: length of addr.
+ * @param zone: name of the zone of the delegation point. wireformat dname.
+ * This is the delegation point name for which the server is deemed
+ * authoritative.
+ * @param zonelen: length of zone.
+ * @param qstate: module qstate.
+ * @param region: region to store data.
+ * @return false on failure (a callback function returned an error).
+ */
+int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
+ uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
+ struct regional* region);
/**
* Copy edns option list allocated to the new region