/** check wire data parse */
static int
-check_data(const char* data)
+check_data(const char* data, const struct config_strlist* head)
{
char buf[65536];
uint8_t rr[LDNS_RR_BUF_SIZE];
size_t len = sizeof(rr);
int res;
- snprintf(buf, sizeof(buf), "%s %s", "example.com.", data);
+ /* '.' is sufficient for validation, and it makes the call to
+ * sldns_wirerr_get_type() simpler below.
+ * (once adopted, this comment can be removed) */
+ snprintf(buf, sizeof(buf), "%s %s", ".", data);
res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0,
NULL, 0);
+
+ /* Reject it if we would end up having CNAME and other data (including
+ * another CNAME) for the same tag. */
+ if(res == 0 && head) {
+ const char* err_data = NULL;
+
+ if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) {
+ /* adding CNAME while other data already exists. */
+ err_data = data;
+ } else {
+ snprintf(buf, sizeof(buf), "%s %s", ".", head->str);
+ len = sizeof(rr);
+ res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
+ NULL, 0, NULL, 0);
+ if(res != 0) {
+ /* This should be impossible here as head->str
+ * has been validated, but we check it just in
+ * case. */
+ return 0;
+ }
+ if(sldns_wirerr_get_type(rr, len, 1) ==
+ LDNS_RR_TYPE_CNAME) /* already have CNAME */
+ err_data = head->str;
+ }
+ if(err_data) {
+ log_err("redirect tag data '%s' must not coexist with "
+ "other data.", err_data);
+ return 0;
+ }
+ }
if(res == 0)
return 1;
log_err("rr data [char %d] parse error %s",
}
/* check data? */
- if(!check_data(data)) {
+ if(!check_data(data, node->tag_datas[tagid])) {
log_err("cannot parse access-control-tag data: %s %s '%s'",
str, tag, data);
return 0;
if(!dp) { /* no delegation, need to reprime */
return 0;
}
+ /* In case we have a local alias, copy it into the delegation message.
+ * Shallow copy should be fine, as we'll be done with msg in this
+ * function. */
+ msg->qinfo.local_alias = qinfo->local_alias;
if(must_validate) {
switch(check_delegation_secure(msg->rep)) {
case sec_status_unchecked:
&repinfo->addr, repinfo->addrlen);
goto send_reply;
}
+
+ /* If we've found a local alias, replace the qname with the alias
+ * target before resolving it. */
+ if(qinfo.local_alias) {
+ struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset;
+ struct packed_rrset_data* d = rrset->entry.data;
+
+ /* Sanity check: our current implementation only supports
+ * a single CNAME RRset as a local alias. */
+ if(qinfo.local_alias->next ||
+ rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) ||
+ d->count != 1) {
+ log_err("assumption failure: unexpected local alias");
+ regional_free_all(worker->scratchpad);
+ return 0; /* drop it */
+ }
+ qinfo.qname = d->rr_data[0] + 2;
+ qinfo.qname_len = d->rr_len[0] - 2;
+ }
+
h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
+18 October 2016: Wouter
+ - Patch that resolves CNAMEs entered in local-data conf statements that
+ point to data on the internet, from Jinmei Tatuya (Infoblox).
+
17 October 2016: Wouter
- Re-fix #839 from view commit overwrite.
- Fixup const void cast warning.
qinf.qname_len = qnamelen;
qinf.qtype = qtype;
qinf.qclass = qclass;
+ qinf.local_alias = NULL;
/* RD should be set only when sending the query back through the INIT
* state. */
if(!qinfo->qname) {
return 0;
}
+ qinfo->local_alias = NULL;
edns->edns_present = 1;
edns->ext_rcode = 0;
edns->edns_version = 0;
* Find an rrset in local data structure.
* @param data: local data domain name structure.
* @param type: type to look for (host order).
+ * @param alias_ok: 1 if matching a non-exact, alias type such as CNAME is
+ * allowed. otherwise 0.
* @return rrset pointer or NULL if not found.
*/
static struct local_rrset*
-local_data_find_type(struct local_data* data, uint16_t type)
+local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
{
struct local_rrset* p;
type = htons(type);
for(p = data->rrsets; p; p = p->next) {
if(p->rrset->rk.type == type)
return p;
+ if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
+ return p;
}
return NULL;
}
log_assert(node);
free(nm);
- rrset = local_data_find_type(node, rrtype);
+ /* Reject it if we would end up having CNAME and other data (including
+ * another CNAME) for a redirect zone. */
+ if(z->type == local_zone_redirect && node->rrsets) {
+ const char* othertype = NULL;
+ if (rrtype == LDNS_RR_TYPE_CNAME)
+ othertype = "other";
+ else if (node->rrsets->rrset->rk.type ==
+ htons(LDNS_RR_TYPE_CNAME)) {
+ othertype = "CNAME";
+ }
+ if(othertype) {
+ log_err("local-data '%s' in redirect zone must not "
+ "coexist with %s local-data", rrstr, othertype);
+ return 0;
+ }
+ }
+ rrset = local_data_find_type(node, rrtype, 0);
if(!rrset) {
rrset = new_local_rrset(z->region, node, rrtype, rrclass);
if(!rrset)
int res;
struct packed_rrset_data* d;
for(p=list; p; p=p->next) {
+ uint16_t rdr_type;
+
len = sizeof(rr);
/* does this element match the type? */
snprintf(buf, sizeof(buf), ". %s", p->str);
continue;
if(len < 1 /* . */ + 8 /* typeclassttl*/ + 2 /*rdatalen*/)
continue;
- if(sldns_wirerr_get_type(rr, len, 1) != qinfo->qtype)
+ rdr_type = sldns_wirerr_get_type(rr, len, 1);
+ if(rdr_type != qinfo->qtype && rdr_type != LDNS_RR_TYPE_CNAME)
continue;
/* do we have entries already? if not setup key */
r->entry.key = r;
r->rk.dname = qinfo->qname;
r->rk.dname_len = qinfo->qname_len;
- r->rk.type = htons(qinfo->qtype);
+ r->rk.type = htons(rdr_type);
r->rk.rrset_class = htons(qinfo->qclass);
r->rk.flags = 0;
d = (struct packed_rrset_data*)regional_alloc_zero(
if(!d) return 0; /* out of memory */
d->count++;
}
+ /* If we've found a non-exact alias type of local data, make a shallow
+ * copy of the RRset and remember it in qinfo to complete the alias
+ * chain later. */
+ if(r->rk.dname && qinfo->qtype != LDNS_RR_TYPE_CNAME &&
+ r->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
+ qinfo->local_alias =
+ regional_alloc_zero(temp, sizeof(struct local_rrset));
+ if(!qinfo->local_alias)
+ return 0; /* out of memory */
+ qinfo->local_alias->rrset =
+ regional_alloc_init(temp, r, sizeof(*r));
+ if(!qinfo->local_alias->rrset)
+ return 0; /* out of memory */
+ }
if(r->rk.dname)
return 1;
return 0;
z->name, z->namelen)) {
verbose(VERB_ALGO, "redirect with tag data [%d] %s",
tag, (tag<num_tags?tagname[tag]:"null"));
+
+ /* If we found a matching alias, we should
+ * use it as part of the answer, but we can't
+ * encode it until we complete the alias
+ * chain. */
+ if(qinfo->local_alias)
+ return 1;
return local_encode(qinfo, edns, buf, temp,
&r, 1, LDNS_RCODE_NOERROR);
}
if(!ld) {
return 0;
}
- lr = local_data_find_type(ld, qinfo->qtype);
+ lr = local_data_find_type(ld, qinfo->qtype, 1);
if(!lr)
return 0;
+
+ /* Special case for alias matching. See local_data_answer(). */
+ if(lz_type == local_zone_redirect &&
+ qinfo->qtype != LDNS_RR_TYPE_CNAME &&
+ lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
+ qinfo->local_alias =
+ regional_alloc_zero(temp, sizeof(struct local_rrset));
+ if(!qinfo->local_alias)
+ return 0; /* out of memory */
+ qinfo->local_alias->rrset =
+ regional_alloc_init(temp, lr->rrset, sizeof(*lr->rrset));
+ if(!qinfo->local_alias->rrset)
+ return 0; /* out of memory */
+ qinfo->local_alias->rrset->rk.dname = qinfo->qname;
+ qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
+ return 1;
+ }
if(lz_type == local_zone_redirect) {
/* convert rrset name to query name; like a wildcard */
struct ub_packed_rrset_key r = *lr->rrset;
&& local_data_answer(z, qinfo, edns, buf, temp, labs, &ld, lzt,
tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock);
- return 1;
+ /* We should tell the caller that encode is deferred if we found
+ * a local alias. */
+ return !qinfo->local_alias;
}
r = lz_zone_answer(z, qinfo, edns, buf, temp, ld, lzt);
lock_rw_unlock(&z->lock);
- return r;
+ return r && !qinfo->local_alias; /* see above */
}
const char* local_zone_type2str(enum localzone_type t)
* @return true if answer is in buffer. false if query is not answered
* by authority data. If the reply should be dropped altogether, the return
* value is true, but the buffer is cleared (empty).
+ * It can also return true if a non-exact alias answer is found. In this
+ * case qinfo->local_alias points to the corresponding alias RRset but the
+ * answer is NOT encoded in buffer. It's the caller's responsibility to
+ * complete the alias chain (if needed) and encode the final set of answer.
+ * Data pointed to by qinfo->local_alias is allocated in 'temp' or refers to
+ * configuration data. So the caller will need to make a deep copy of it
+ * if it needs to keep it beyond the lifetime of 'temp' or a dynamic update
+ * to local zone data.
*/
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp,
#include "util/alloc.h"
#include "util/config_file.h"
#include "sldns/sbuffer.h"
+#include "services/localzone.h"
+#include "util/data/dname.h"
/** subtract timers and the values do not overflow or become negative */
static void
if(!s->reply_list && !s->cb_list)
was_noreply = 1;
/* add reply to s */
- if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) {
+ if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
log_err("mesh_new_client: out of memory; SERVFAIL");
if(!edns_opt_inplace_reply(edns, mesh->env->scratch))
edns->opt_list = NULL;
struct timeval end_time;
struct timeval duration;
int secure;
+ /* Copy the client's EDNS for later restore to fix a bug of the
+ * original code. See unbound bug #1125. Once NLNet Labs fixes it
+ * we should replace this local fix with the upstream one. */
+ struct edns_data edns_bak = r->edns;
/* examine security status */
if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
m->s.env->cfg->ignore_cd) && rep &&
if(!rep && rcode == LDNS_RCODE_NOERROR)
rcode = LDNS_RCODE_SERVFAIL;
/* send the reply */
+ /* We don't reuse the encoded answer if either the previous or current
+ * response has a local alias. We could compare the alias records
+ * and still reuse the previous answer if they are the same, but that
+ * would be complicated and error prone for the relatively minor case.
+ * So we err on the side of safety. */
if(prev && prev->qflags == r->qflags &&
+ !prev->local_alias && !r->local_alias &&
prev->edns.edns_present == r->edns.edns_present &&
prev->edns.bits == r->edns.bits &&
prev->edns.udp_size == r->edns.udp_size &&
m->s.qinfo.qname = r->qname;
if(!edns_opt_inplace_reply(&r->edns, m->s.region))
r->edns.opt_list = NULL;
+ m->s.qinfo.local_alias = r->local_alias;
error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
r->qid, r->qflags, &r->edns);
comm_point_send_reply(&r->query_reply);
r->edns.ext_rcode = 0;
r->edns.bits &= EDNS_DO;
m->s.qinfo.qname = r->qname;
+ m->s.qinfo.local_alias = r->local_alias;
if(!edns_opt_inplace_reply(&r->edns, m->s.region) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->query_reply.c->buffer, 0, 1,
LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
}
+ r->edns = edns_bak; /* Fix unbound bug #1125. See above. */
comm_point_send_reply(&r->query_reply);
}
/* account */
}
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
- struct comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname)
+ struct comm_reply* rep, uint16_t qid, uint16_t qflags,
+ const struct query_info* qinfo)
{
struct mesh_reply* r = regional_alloc(s->s.region,
sizeof(struct mesh_reply));
r->qflags = qflags;
r->start_time = *s->s.env->now_tv;
r->next = s->reply_list;
- r->qname = regional_alloc_init(s->s.region, qname,
+ r->qname = regional_alloc_init(s->s.region, qinfo->qname,
s->s.qinfo.qname_len);
if(!r->qname)
return 0;
+
+ /* Data related to local alias stored in 'qinfo' (if any) is ephemeral
+ * and can be different for different original queries (even if the
+ * replaced query name is the same). So we need to make a deep copy
+ * and store the copy for each reply info. */
+ if(qinfo->local_alias) {
+ struct packed_rrset_data* d;
+ struct packed_rrset_data* dsrc;
+ r->local_alias = regional_alloc_zero(s->s.region,
+ sizeof(*qinfo->local_alias));
+ if(!r->local_alias)
+ return 0;
+ r->local_alias->rrset = regional_alloc_init(s->s.region,
+ qinfo->local_alias->rrset,
+ sizeof(*qinfo->local_alias->rrset));
+ if(!r->local_alias->rrset)
+ return 0;
+ dsrc = qinfo->local_alias->rrset->entry.data;
+
+ /* In the current implementation, a local alias must be
+ * a single CNAME RR (see worker_handle_request()). */
+ log_assert(!qinfo->local_alias->next && dsrc->count == 1 &&
+ qinfo->local_alias->rrset->rk.type ==
+ htons(LDNS_RR_TYPE_CNAME));
+ /* Technically, we should make a local copy for the owner
+ * name of the RRset, but in the case of the first (and
+ * currently only) local alias RRset, the owner name should
+ * point to the qname of the corresponding query, which should
+ * be valid throughout the lifetime of this mesh_reply. So
+ * we can skip copying. */
+ log_assert(qinfo->local_alias->rrset->rk.dname ==
+ sldns_buffer_at(rep->c->buffer, LDNS_HEADER_SIZE));
+
+ d = regional_alloc_init(s->s.region, dsrc,
+ sizeof(struct packed_rrset_data)
+ + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t));
+ if(!d)
+ return 0;
+ r->local_alias->rrset->entry.data = d;
+ d->rr_len = (size_t*)((uint8_t*)d +
+ sizeof(struct packed_rrset_data));
+ d->rr_data = (uint8_t**)&(d->rr_len[1]);
+ d->rr_ttl = (time_t*)&(d->rr_data[1]);
+ d->rr_len[0] = dsrc->rr_len[0];
+ d->rr_ttl[0] = dsrc->rr_ttl[0];
+ d->rr_data[0] = regional_alloc_init(s->s.region,
+ dsrc->rr_data[0], d->rr_len[0]);
+ if(!d->rr_data[0])
+ return 0;
+ } else
+ r->local_alias = NULL;
+
s->reply_list = r;
return 1;
}
uint16_t qflags;
/** qname from this query. len same as mesh qinfo. */
uint8_t* qname;
+ /** same as that in query_info. */
+ struct local_rrset* local_alias;
};
/**
* @param qid: ID of reply.
* @param qflags: original query flags.
* @param qname: original query name.
+ * @param qinfo: original query info.
* @return: 0 on alloc error.
*/
-int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
- struct comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname);
+int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
+ struct comm_reply* rep, uint16_t qid, uint16_t qflags,
+ const struct query_info* qinfo);
/**
* Create new callback structure and attach it to a mesh state.
qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len);
if(!qinfo.qname)
return 0;
+ qinfo.local_alias = NULL;
qinfo_query_encode(buf, &qinfo);
sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */
if(rec) LDNS_RD_SET(sldns_buffer_begin(buf));
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
+ /* clear local alias */
+ qinfo.local_alias = NULL;
+
/* make query */
qinfo_query_encode(buf, &qinfo);
sldns_buffer_write_u16_at(buf, 0, id);
#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. */
{
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).
+ * Note: once approved, this comment and the following line should be
+ * removed. */
+ /**num_rrs = 0;*/
+
if(s != LDNS_SECTION_ADDITIONAL) {
if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY)
dnssec = 1; /* include all types in ANY answer */
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;
* 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,
}
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;
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);
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);
}
qinf->qname_len = msg->qname_len;
qinf->qtype = msg->qtype;
qinf->qclass = msg->qclass;
+ qinf->local_alias = NULL;
return 1;
}
int ret;
qinf->qname = NULL;
+ qinf->local_alias = NULL;
*rep = NULL;
if(!(msg = regional_alloc(region, sizeof(*msg)))) {
return LDNS_RCODE_SERVFAIL;
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;
}
struct edns_data;
struct msg_parse;
struct rrset_parse;
+struct local_rrset;
/** calculate the prefetch TTL as 90% of original. Calculation
* without numerical overflow (uin32_t) */
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;
};
/**
qinfo.qname_len = tp->namelen;
qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
qinfo.qclass = tp->dclass;
+ qinfo.local_alias = NULL;
log_query_info(VERB_ALGO, "autotrust probe", &qinfo);
verbose(VERB_ALGO, "retry probe set in %d seconds",
(int)tp->autr->next_probe_time - (int)*env->now);
ask.qname_len = namelen;
ask.qtype = qtype;
ask.qclass = qclass;
+ ask.local_alias = NULL;
log_query_info(VERB_ALGO, "generate request", &ask);
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
/* enable valrec flag to avoid recursion to the same validation