mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-02-18 18:25:10 -05:00
Made it possible to change queries into _deleg queries
This commit is contained in:
parent
86fe9cbce5
commit
011c5a0e0f
1 changed files with 195 additions and 9 deletions
|
|
@ -32,7 +32,33 @@
|
|||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
// @JESSE: Iterator (this file) is the module that does all the needed DNS
|
||||
// iterations and walking the DNS tree to try and find an answer.
|
||||
// It includes but not limited to:
|
||||
// 1. Finding the closest known delegation point
|
||||
// (root at startup, or configured zones)
|
||||
// 2. Sends a query (the original query if no qname-minimisation)
|
||||
// to that and gets either an answer or a referral answer.
|
||||
// 3. In case of referral answer goes back to 1.
|
||||
//
|
||||
// A lot more is happening here, like fallbacks and retries. Don't try
|
||||
// to understand everything at once, it's better to go with the flow
|
||||
// and see what is relevant for you.
|
||||
|
||||
// @JESSE: We do not use '//' comments in the Unbound code base. I explicitly
|
||||
// use them to identify non-relevant parts or WIP comments.
|
||||
|
||||
// @JESSE: Some tips:
|
||||
// - For printf kind of debug logging it's easier to use log_err();
|
||||
// these are printed on all verbosity levels.
|
||||
// - For domain name manipulation methods you can have a look at
|
||||
// dname.c/h.
|
||||
// - If you need to do allocations; for your case everything should
|
||||
// have the lifetime of the query state (qstate); you can use
|
||||
// qstate->region as your arena allocator and pass that region to
|
||||
// functions that require one. You can then alloc items there and
|
||||
// forget about them. The whole region is freed when the qstate is
|
||||
// no more.
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
|
|
@ -70,6 +96,7 @@
|
|||
#include "sldns/parseutil.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
|
||||
|
||||
/* in msec */
|
||||
int UNKNOWN_SERVER_NICENESS = 376;
|
||||
/* in msec */
|
||||
|
|
@ -136,6 +163,8 @@ iter_deinit(struct module_env* env, int id)
|
|||
static int
|
||||
iter_new(struct module_qstate* qstate, int id)
|
||||
{
|
||||
// @JESSE: each module can have its own query state. The iter_qstate
|
||||
// struct below is the state for the iterator.
|
||||
struct iter_qstate* iq = (struct iter_qstate*)regional_alloc(
|
||||
qstate->region, sizeof(struct iter_qstate));
|
||||
qstate->minfo[id] = iq;
|
||||
|
|
@ -164,7 +193,11 @@ iter_new(struct module_qstate* qstate, int id)
|
|||
iq->dnssec_lame_query = 0;
|
||||
iq->chase_flags = qstate->query_flags;
|
||||
/* Start with the (current) qname. */
|
||||
// @JESSE: iq->qchase will be the qinfo iterator will be working on and
|
||||
// updating through the iteration process. It is set here to
|
||||
// the initial query (qstate->qinfo) that started all this.
|
||||
iq->qchase = qstate->qinfo;
|
||||
iq->deleg_state = 0;
|
||||
outbound_list_init(&iq->outlist);
|
||||
iq->minimise_count = 0;
|
||||
iq->timeout_count = 0;
|
||||
|
|
@ -172,7 +205,7 @@ iter_new(struct module_qstate* qstate, int id)
|
|||
iq->minimisation_state = INIT_MINIMISE_STATE;
|
||||
else
|
||||
iq->minimisation_state = DONOT_MINIMISE_STATE;
|
||||
|
||||
// @JESSE: iq->qinfo_out is the qinfo that will be sent out.
|
||||
memset(&iq->qinfo_out, 0, sizeof(struct query_info));
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1596,8 +1629,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
delname = iq->dp->name;
|
||||
delnamelen = iq->dp->namelen;
|
||||
} else {
|
||||
delname = iq->qchase.qname;
|
||||
delnamelen = iq->qchase.qname_len;
|
||||
// @JESSE: Here we set the delegation name to be the original
|
||||
// one ...
|
||||
delname = iq->qchase.qname;
|
||||
delnamelen = iq->qchase.qname_len;
|
||||
}
|
||||
if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue ||
|
||||
(iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway
|
||||
|
|
@ -1618,8 +1653,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
|
||||
/* Lookup the delegation in the cache. If null, then the
|
||||
* cache needs to be primed for the qclass. */
|
||||
// @JESSE: ... and here we'll try to get the closest delegation
|
||||
// from cache.
|
||||
if(delname)
|
||||
iq->dp = dns_cache_find_delegation(qstate->env, delname,
|
||||
iq->dp = dns_cache_find_delegation(qstate->env, delname,
|
||||
delnamelen, iq->qchase.qtype, iq->qchase.qclass,
|
||||
qstate->region, &iq->deleg_msg,
|
||||
*qstate->env->now+qstate->prefetch_leeway, 1,
|
||||
|
|
@ -1950,6 +1987,7 @@ generate_parentside_target_query(struct module_qstate* qstate,
|
|||
* @param qclass: target qclass.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
//JESSE Use this to generate new query?
|
||||
static int
|
||||
generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int id, uint8_t* name, size_t namelen, uint16_t qtype, uint16_t qclass)
|
||||
|
|
@ -2384,6 +2422,7 @@ check_waiting_queries(struct iter_qstate* iq, struct module_qstate* qstate,
|
|||
}
|
||||
}
|
||||
|
||||
// @JESSE: This is where most of the iteration time will be spent.
|
||||
/**
|
||||
* This is the request event state where the request will be sent to one of
|
||||
* its current query targets. This state also handles issuing target lookup
|
||||
|
|
@ -2538,6 +2577,57 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
delegpt_no_ipv4(iq->dp);
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
|
||||
uint8_t root_len = iq->qchase.qname[0];
|
||||
//NICE point
|
||||
if (iq->deleg_state == 0 && root_len > 0) {
|
||||
//we have to add _deleg after the first label
|
||||
//for ex. jesse.nlnetlabs.nl becomes jesse._deleg.nlnetlabs.nl
|
||||
uint8_t deleg_wireformat[] = {6, 95, 100, 101, 108, 101, 103}; //{06}_deleg
|
||||
size_t delnamelen = iq->qchase.qname_len + sizeof(deleg_wireformat);
|
||||
log_err("deleg wireformat size: %d, original qname size: %d, qname len (variable): %d, size of first label orginal qname: %d allocated space: %d", sizeof(deleg_wireformat), sizeof(iq->qchase.qname), iq->qchase.qname_len, iq->qchase.qname[0], delnamelen);
|
||||
// delnamelen = iq->qchase.qname_len + sizeof(deleg_wireformat);
|
||||
// delname = (uint8_t *)malloc(delnamelen);
|
||||
uint8_t *delname = (uint8_t *)malloc(delnamelen);
|
||||
if (delname == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
}
|
||||
//put first label of original qname
|
||||
uint8_t first_label_len = iq->qchase.qname[0];
|
||||
log_err("First label length: %d", first_label_len);
|
||||
uint8_t *qname_minus_first_label = iq->qchase.qname + first_label_len + 1;
|
||||
uint8_t leftover_len = iq->qchase.qname_len - first_label_len - 1;
|
||||
// memcpy(delname, iq->qchase.qname, sizeof(iq->qchase.qname)); //memcpy 1st label into delname
|
||||
memcpy(delname, iq->qchase.qname, first_label_len + 1); //memcpy 1st label into delname
|
||||
memcpy(delname + first_label_len + 1, deleg_wireformat, sizeof(deleg_wireformat)); //memcpy _deleg label in delname
|
||||
memcpy(delname + first_label_len + sizeof(deleg_wireformat) + 1, qname_minus_first_label, leftover_len); //memcpy other labels in delname
|
||||
log_err("Old delegation point: %s", iq->qchase.qname);
|
||||
log_err("cname without first label: %s", qname_minus_first_label);
|
||||
|
||||
// log_err("delegation name in bytes:");
|
||||
// for (size_t i = 0; i < delnamelen; ++i) {
|
||||
// log_err("%u ", delname[i]);
|
||||
// }
|
||||
|
||||
log_err("The _deleg delegation point: %s", delname);
|
||||
|
||||
//uncomment if not onlys used in stub zone
|
||||
iq->deleg_state = 1;
|
||||
|
||||
//left here
|
||||
iq->dp->namelen = delnamelen;
|
||||
// iq->dp->namelabs++;
|
||||
iq->qchase.qtype = 64;
|
||||
iq->qchase.qname = delname;
|
||||
iq->qchase.qname_len = delnamelen;
|
||||
|
||||
iq->qinfo_out.qtype = 64;
|
||||
iq->qinfo_out.qname = delname;
|
||||
iq->qinfo_out.qname_len = delnamelen;
|
||||
// iq->deleg_original_qname = qstate->qinfo.qname;
|
||||
// qstate->qinfo.qname = delname;
|
||||
// generate_target_query(qstate, iq, id, uint8_t* name, size_t namelen, uint16_t qtype, uint16_t qclass)
|
||||
}
|
||||
|
||||
if(iq->num_current_queries>0) {
|
||||
/* already busy answering a query, this restart is because
|
||||
* more delegpt addrs became available, wait for existing
|
||||
|
|
@ -2547,6 +2637,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
//DELEG first check if _deleg in delegation point
|
||||
//if no _deleg let unbound handle it
|
||||
// @JESSE: The following ifs is where most qname-minimisation happens.
|
||||
// We need something similar (adding a label at a time) but
|
||||
// without the best-effort nature of qname-minimisation and its
|
||||
// fallback. You can take inspiration from here on how to
|
||||
// correctly set iq->qinfo_out.
|
||||
if(iq->minimisation_state == INIT_MINIMISE_STATE
|
||||
&& !(iq->chase_flags & BIT_RD)) {
|
||||
/* (Re)set qinfo_out to (new) delegation point, except when
|
||||
|
|
@ -3031,7 +3128,10 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
log_name_addr(VERB_QUERY, "applied NAT64:",
|
||||
iq->dp->name, &real_addr, real_addrlen);
|
||||
}
|
||||
|
||||
// @JESSE: This is where a query is finally going out, hopefully.
|
||||
log_err("JESSE send qname: %s", qstate->qinfo.qname);
|
||||
log_err("JESSE send type: %d", qstate->qinfo.qtype);
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
|
||||
outq = (*qstate->env->send_query)(&iq->qinfo_out,
|
||||
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
|
||||
|
|
@ -3085,7 +3185,7 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// @JESSE: This is where responses are read.
|
||||
/**
|
||||
* Process the query response. All queries end up at this state first. This
|
||||
* process generally consists of analyzing the response and routing the
|
||||
|
|
@ -3180,8 +3280,83 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
dnsseclame = 1;
|
||||
}
|
||||
} else iq->dnssec_lame_query = 0;
|
||||
// @JESSE: Answers to _deleg queries would end up here. You need to
|
||||
// make sure you identify those answers correclty and treat
|
||||
// them the same way as referrals below.
|
||||
/* handle each of the type cases */
|
||||
//check deleg and change to referal type TODO add check to see if _deleg in name
|
||||
uint16_t SVCB_QTYPE = 64;
|
||||
log_err("JESSE: the qtype of the answer is: %d ", iq->qchase.qtype);
|
||||
log_err("JESSE: the type is: %d", type);
|
||||
if (iq->qchase.qtype == SVCB_QTYPE) {
|
||||
struct ub_packed_rrset_key* rrset_key;
|
||||
log_err("JESSE: the returnmsg: %s", iq->response->rep);
|
||||
rrset_key = reply_find_answer_rrset(&iq->qchase, iq->response->rep);
|
||||
// struct packed_rrset_key rr_records = rrset->rk;
|
||||
|
||||
if(rrset_key) {
|
||||
struct packed_rrset_data* rrset_data = (struct packed_rrset_data*) rrset_key->entry.data;
|
||||
|
||||
size_t data_len = rrset_data->rr_len[0];
|
||||
uint8_t* svcb_data = rrset_data->rr_data[0];
|
||||
log_err("JESSE: The wireformat SVCB name:");
|
||||
for (size_t i = 0; i < data_len; ++i) {
|
||||
log_err("%u ", svcb_data[i]);
|
||||
}
|
||||
size_t index = 4;
|
||||
while(svcb_data[index] != 0) { //loop through dns labels, label length 0 mean root so stop looping
|
||||
index = index + svcb_data[index] + 1;
|
||||
}
|
||||
index = index + 1;//add 1 for the root label
|
||||
//Reference https://datatracker.ietf.org/doc/rfc9460/ section 2.2
|
||||
uint8_t *ipv4;
|
||||
uint8_t *ipv6;
|
||||
while(index < data_len && (ipv4 == NULL || ipv6 == NULL)) {
|
||||
uint16_t svcParamkey = (svcb_data[index] << 8) | svcb_data[index+1];
|
||||
uint16_t svcParamValLen = (svcb_data[index+2] << 8) | svcb_data[index+3];
|
||||
index = index + 4;
|
||||
//logic fault, will never enter the paramkey checks TODOOOOOOOO
|
||||
if (svcParamkey == 4) { //parse IPv4
|
||||
ipv4 = (uint8_t *)malloc(4 * sizeof(uint8_t));
|
||||
memcpy(ipv4, svcb_data + index, 4);
|
||||
log_err("Parsed IPv4 Hint:");
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
log_err("%u ", ipv4[i]);
|
||||
}
|
||||
} else if (svcParamkey == 6) { //parse ipv6
|
||||
ipv6 = (uint8_t *)malloc(16 * sizeof(uint8_t));
|
||||
memcpy(ipv6, svcb_data + index, 16);
|
||||
log_err("Parsed IPv6 Hint:");
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
log_err("%u ", ipv6[i]);
|
||||
}
|
||||
}
|
||||
index = index + svcParamValLen;
|
||||
}
|
||||
} else {
|
||||
log_err("TESTTTTTTT2");
|
||||
//this means no _deleg record found
|
||||
iq->qchase.qtype = 1;
|
||||
qstate->qinfo.qtype = 1;
|
||||
// iq->deleg_state = 0;
|
||||
qstate->qinfo.qname = iq->deleg_original_qname;
|
||||
}
|
||||
// log_err("RRset result in bytes:");
|
||||
// if(rrset) {
|
||||
// for (size_t i = 0; i < rr_records->count; ++i) {
|
||||
// size_t len = rr_records->rr_len[i];
|
||||
// log_err("Resource record %d:", i);
|
||||
// for (size_t j = 0; j < len; ++i) {
|
||||
// log_err("%u ", rr_records->rr_data[i][j]);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//set new delegation point
|
||||
// iq->dp = delegpt_from_message(iq->response, qstate->region);
|
||||
}
|
||||
/* see if referral brings us close to the target */
|
||||
if(type == RESPONSE_TYPE_REFERRAL) {
|
||||
if(type == RESPONSE_TYPE_REFERRAL){
|
||||
// iq->deleg_state = 0;
|
||||
struct ub_packed_rrset_key* ns = find_NS(
|
||||
iq->response->rep, iq->response->rep->an_numrrsets,
|
||||
iq->response->rep->an_numrrsets
|
||||
|
|
@ -3224,8 +3399,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
/* handle each of the type cases */
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
if(type == RESPONSE_TYPE_ANSWER ){
|
||||
/* ANSWER type responses terminate the query algorithm,
|
||||
* so they sent on their */
|
||||
if(verbosity >= VERB_DETAIL) {
|
||||
|
|
@ -3235,6 +3409,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
(iq->response->rep->an_numrrsets?"ANSWER":
|
||||
"nodata ANSWER"));
|
||||
}
|
||||
|
||||
/* if qtype is DS, check we have the right level of answer,
|
||||
* like grandchild answer but we need the middle, reject it */
|
||||
if(iq->qchase.qtype == LDNS_RR_TYPE_DS && !iq->dsns_point
|
||||
|
|
@ -3323,8 +3498,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
return final_state(iq);
|
||||
// @JESSE: I guess for the test environemnt we mostly don't care about
|
||||
// referrals; these are traditional DNS referral responses.
|
||||
} else if(type == RESPONSE_TYPE_REFERRAL) {
|
||||
//added code
|
||||
// iq->deleg_state = 0;
|
||||
struct delegpt* old_dp = NULL;
|
||||
|
||||
/* REFERRAL type responses get a reset of the
|
||||
* delegation point, and back to the QUERYTARGETS_STATE. */
|
||||
verbose(VERB_DETAIL, "query response was REFERRAL");
|
||||
|
|
@ -4140,6 +4320,12 @@ iter_inform_super(struct module_qstate* qstate, int id,
|
|||
else processTargetResponse(qstate, id, super);
|
||||
}
|
||||
|
||||
// @JESSE: These are all the available states the iterator could be for a given
|
||||
// query. You should not worry about the following cases:
|
||||
// - COLLECT_CLASS_STATE (it has to do with ANY queries)
|
||||
// - DSNS_FIND_STATE (it tries to find the correct parent for a DS
|
||||
// query; I think it is not relevant since the
|
||||
// _deleg stuff always live at the parent)
|
||||
/**
|
||||
* Handle iterator state.
|
||||
* Handle events. This is the real processing loop for events, responsible
|
||||
|
|
|
|||
Loading…
Reference in a new issue