Some more uniform _getdns_rrset usage

This commit is contained in:
Willem Toorop 2016-06-09 15:03:51 +02:00
parent e27bfcedb6
commit 49840c9a85
5 changed files with 114 additions and 198 deletions

View File

@ -814,13 +814,7 @@ static void add_question2val_chain(struct mem_funcs *mf,
const uint8_t *qname, uint16_t qtype, uint16_t qclass, const uint8_t *qname, uint16_t qtype, uint16_t qclass,
getdns_network_req *netreq) getdns_network_req *netreq)
{ {
_getdns_rrset q_rrset; _getdns_rrset_spc q_rrset;
uint8_t cname_spc[256];
size_t cname_len = sizeof(cname_spc);
size_t anti_loop;
_getdns_rdf_iter rdf_spc, *rdf;
_getdns_rrtype_iter *rr, rr_spc;
chain_head *head; chain_head *head;
assert(pkt); assert(pkt);
@ -828,43 +822,26 @@ static void add_question2val_chain(struct mem_funcs *mf,
assert(qname); assert(qname);
/* First find the canonical name for the question */ /* First find the canonical name for the question */
q_rrset.name = qname; q_rrset.rrset.name = qname;
q_rrset.rr_type = GETDNS_RRTYPE_CNAME; q_rrset.rrset.rr_type = qtype;
q_rrset.rr_class = qclass; q_rrset.rrset.rr_class = qclass;
q_rrset.pkt = pkt; q_rrset.rrset.pkt = pkt;
q_rrset.pkt_len = pkt_len; q_rrset.rrset.pkt_len = pkt_len;
q_rrset.sections = SECTION_ANSWER; q_rrset.rrset.sections = SECTION_ANSWER;
for (anti_loop = MAX_CNAME_REFERRALS; anti_loop; anti_loop--) { if (_getdns_initialized_rrset_answer(&q_rrset))
if (!(rr = _getdns_rrtype_iter_init(&rr_spc, &q_rrset)))
break;
if (!(rdf = _getdns_rdf_iter_init(&rdf_spc, &rr->rr_i)))
break;
q_rrset.name = _getdns_rdf_if_or_as_decompressed(
rdf, cname_spc, &cname_len);
}
/* If the qtype was a CNAME, and we got one, we'r done.
* We asked for it directly, so no redirection applies.
* Otherwise we have to check the referred to name/qtype.
*/
if (qtype == GETDNS_RRTYPE_CNAME && q_rrset.name != qname)
return; return;
q_rrset.rr_type = qtype;
if (!(rr = _getdns_rrtype_iter_init(&rr_spc, &q_rrset))) {
/* No answer for the question. Add a head for this rrset /* No answer for the question. Add a head for this rrset
* anyway, to validate proof of non-existance, or to find * anyway, to validate proof of non-existance, or to find
* proof that the packet is insecure. * proof that the packet is insecure.
*/ */
debug_sec_print_rrset("Adding NX rrset: ", &q_rrset); debug_sec_print_rrset("Adding NX rrset: ", &q_rrset.rrset);
head = add_rrset2val_chain(mf, chain_p, &q_rrset, netreq); head = add_rrset2val_chain(mf, chain_p, &q_rrset.rrset, netreq);
/* On empty packet, find SOA (zonecut) for the qname */ /* On empty packet, find SOA (zonecut) for the qname */
if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0) if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0)
val_chain_sched_soa(head, q_rrset.rrset.name);
val_chain_sched_soa(head, q_rrset.name);
}
} }

View File

@ -84,77 +84,16 @@ static int
no_answer(getdns_dns_req *dns_req) no_answer(getdns_dns_req *dns_req)
{ {
getdns_network_req **netreq_p, *netreq; getdns_network_req **netreq_p, *netreq;
int new_canonical = 0, cnames_followed;
uint8_t canon_spc[256];
const uint8_t *canon;
size_t canon_len;
uint8_t owner_spc[256];
const uint8_t *owner;
size_t owner_len;
_getdns_rr_iter rr_spc, *rr;
_getdns_rdf_iter rdf_spc, *rdf;
for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) { for (netreq_p = dns_req->netreqs; (netreq = *netreq_p); netreq_p++) {
if (netreq->response_len == 0 || _getdns_rrset_spc answer;
GLDNS_ANCOUNT(netreq->response) == 0)
continue;
canon = netreq->owner->name;
canon_len = netreq->owner->name_len;
if (netreq->request_type != GETDNS_RRTYPE_CNAME
&& GLDNS_ANCOUNT(netreq->response) > 1) do {
new_canonical = 0, cnames_followed = 0;
for ( rr = _getdns_rr_iter_init(&rr_spc
, netreq->response
, netreq->response_len)
; rr && _getdns_rr_iter_section(rr)
<= SECTION_ANSWER
; rr = _getdns_rr_iter_next(rr)) {
if (_getdns_rr_iter_section(rr) != if (netreq->response_len > 0 &&
SECTION_ANSWER) GLDNS_ANCOUNT(netreq->response) > 0 &&
continue; _getdns_rrset_answer(&answer, netreq->response
, netreq->response_len))
if (gldns_read_uint16(rr->rr_type) !=
GETDNS_RRTYPE_CNAME)
continue;
owner = _getdns_owner_if_or_as_decompressed(
rr, owner_spc, &owner_len);
if (!_getdns_dname_equal(canon, owner))
continue;
if (!(rdf = _getdns_rdf_iter_init(
&rdf_spc, rr)))
continue;
canon = _getdns_rdf_if_or_as_decompressed(
rdf, canon_spc, &canon_len);
new_canonical = 1;
cnames_followed++;
}
} while (new_canonical && cnames_followed<MAX_CNAME_REFERRALS);
for ( rr = _getdns_rr_iter_init(&rr_spc
, netreq->response
, netreq->response_len)
; rr && _getdns_rr_iter_section(rr)
<= SECTION_ANSWER
; rr = _getdns_rr_iter_next(rr)) {
if (_getdns_rr_iter_section(rr) !=
SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr->rr_type) !=
netreq->request_type)
continue;
owner = _getdns_owner_if_or_as_decompressed(
rr, owner_spc, &owner_len);
if (_getdns_dname_equal(canon, owner))
return 0; return 0;
} }
}
return 1; return 1;
} }

View File

@ -240,6 +240,62 @@ _getdns_owner_if_or_as_decompressed(_getdns_rr_iter *i,
ff_bytes, len, 0); ff_bytes, len, 0);
} }
_getdns_rrset *
_getdns_initialized_rrset_answer(_getdns_rrset_spc *query_rrset)
{
_getdns_rrset *rrset = &query_rrset->rrset;
uint16_t qtype = rrset->rr_type;
size_t cname_loop_protection;
assert(query_rrset);
/* Follow CNAMEs */
rrset->rr_type = GETDNS_RRTYPE_CNAME;
for ( cname_loop_protection = MAX_CNAME_REFERRALS
; cname_loop_protection > 0
; cname_loop_protection-- ) {
_getdns_rrtype_iter rr_spc, *rr;
_getdns_rdf_iter rdf_spc, *rdf;
if (!(rr = _getdns_rrtype_iter_init(&rr_spc, rrset)))
break;
if (!(rdf = _getdns_rdf_iter_init(&rdf_spc, &rr->rr_i)))
break;
query_rrset->name_len = sizeof(query_rrset->name_spc);
rrset->name = _getdns_rdf_if_or_as_decompressed(
rdf, query_rrset->name_spc, &query_rrset->name_len);
}
rrset->rr_type = qtype;
if (qtype == GETDNS_RRTYPE_CNAME &&
cname_loop_protection < MAX_CNAME_REFERRALS)
return rrset; /* The CNAME was the answer */
return _getdns_rrset_has_rrs(rrset) ? rrset : NULL;
}
_getdns_rrset *
_getdns_rrset_answer(_getdns_rrset_spc *spc, const uint8_t *pkt, size_t len)
{
_getdns_rr_iter rr_spc, *rr;
assert(spc);
spc->rrset.name = NULL;
spc->name_len = sizeof(spc->name_spc);
if ( !(rr = _getdns_rr_iter_init(&rr_spc, pkt, len))
|| _getdns_rr_iter_section(rr) != SECTION_QUESTION
|| !(spc->rrset.name = _getdns_owner_if_or_as_decompressed(
rr, spc->name_spc, &spc->name_len))
|| rr->nxt < rr->rr_type + 4)
return NULL;
spc->rrset.rr_class = rr_iter_class(rr);
spc->rrset.rr_type = rr_iter_type(rr);
spc->rrset.pkt = pkt;
spc->rrset.pkt_len = len;
spc->rrset.sections = SECTION_ANSWER;
return _getdns_initialized_rrset_answer(spc);
}
/* Utility function to compare owner name of rr with name */ /* Utility function to compare owner name of rr with name */
static int rr_owner_equal(_getdns_rr_iter *rr, const uint8_t *name) static int rr_owner_equal(_getdns_rr_iter *rr, const uint8_t *name)

View File

@ -108,7 +108,6 @@ static inline uint16_t rr_iter_type(_getdns_rr_iter *rr)
static inline uint16_t rr_iter_class(_getdns_rr_iter *rr) static inline uint16_t rr_iter_class(_getdns_rr_iter *rr)
{ return rr->rr_type + 4 <= rr->nxt ? gldns_read_uint16(rr->rr_type + 2) : 0; } { return rr->rr_type + 4 <= rr->nxt ? gldns_read_uint16(rr->rr_type + 2) : 0; }
typedef struct _getdns_rrset { typedef struct _getdns_rrset {
const uint8_t *name; const uint8_t *name;
uint16_t rr_class; uint16_t rr_class;
@ -118,6 +117,18 @@ typedef struct _getdns_rrset {
_getdns_section sections; _getdns_section sections;
} _getdns_rrset; } _getdns_rrset;
typedef struct _getdns_rrset_spc {
_getdns_rrset rrset;
uint8_t name_spc[256];
size_t name_len;
} _getdns_rrset_spc;
_getdns_rrset *_getdns_rrset_answer(
_getdns_rrset_spc *rrset2init, const uint8_t *pkt, size_t pkt_len);
_getdns_rrset *_getdns_initialized_rrset_answer(
_getdns_rrset_spc *query_rrset);
typedef struct _getdns_rrtype_iter { typedef struct _getdns_rrtype_iter {
_getdns_rr_iter rr_i; _getdns_rr_iter rr_i;
_getdns_rrset *rrset; _getdns_rrset *rrset;
@ -164,6 +175,8 @@ _getdns_rrset_iter *_getdns_rrset_iter_init(_getdns_rrset_iter *i,
const uint8_t *pkt, size_t pkt_len, _getdns_section sections); const uint8_t *pkt, size_t pkt_len, _getdns_section sections);
_getdns_rrset_iter *_getdns_rrset_iter_next(_getdns_rrset_iter *i); _getdns_rrset_iter *_getdns_rrset_iter_next(_getdns_rrset_iter *i);
static inline _getdns_rrset *_getdns_rrset_iter_value(_getdns_rrset_iter *i) static inline _getdns_rrset *_getdns_rrset_iter_value(_getdns_rrset_iter *i)
{ return i && i->rr_i.pos ? &i->rrset : NULL; } { return i && i->rr_i.pos ? &i->rrset : NULL; }

View File

@ -553,17 +553,16 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
size_t bin_size; size_t bin_size;
const uint8_t *bin_data; const uint8_t *bin_data;
_getdns_section section; _getdns_section section;
uint8_t canonical_name_space[256], owner_name_space[256], uint8_t owner_name_space[256], query_name_space[256];
query_name_space[256]; const uint8_t *owner_name, *query_name;
const uint8_t *canonical_name, *owner_name, *query_name; size_t owner_name_len = sizeof(owner_name_space),
size_t canonical_name_len = sizeof(canonical_name_space),
owner_name_len = sizeof(owner_name_space),
query_name_len = sizeof(query_name_space); query_name_len = sizeof(query_name_space);
int new_canonical = 0, cnames_followed, int all_numeric_label;
request_answered, all_numeric_label;
uint16_t rr_type; uint16_t rr_type;
getdns_dict *header = NULL; getdns_dict *header = NULL;
getdns_list *bad_dns = NULL; getdns_list *bad_dns = NULL;
_getdns_rrset_spc answer_spc;
_getdns_rrset *answer;
if (!result) if (!result)
goto error; goto error;
@ -593,9 +592,6 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
goto error; goto error;
header = NULL; header = NULL;
canonical_name = req->owner->name;
canonical_name_len = req->owner->name_len;
if (req->query && if (req->query &&
(rr_iter = _getdns_rr_iter_init(&rr_iter_storage, req->query (rr_iter = _getdns_rr_iter_init(&rr_iter_storage, req->query
, req->response - req->query))) , req->response - req->query)))
@ -652,23 +648,6 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
goto error; goto error;
else rr_dict = NULL; else rr_dict = NULL;
if (rr_type == GETDNS_RRTYPE_CNAME) {
owner_name_len = sizeof(owner_name_space);
owner_name = _getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = _getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
new_canonical = 1;
canonical_name = _getdns_rdf_if_or_as_decompressed(
rdf_iter,canonical_name_space,&canonical_name_len);
continue;
}
if (srvs->capacity && rr_type == GETDNS_RRTYPE_SRV) { if (srvs->capacity && rr_type == GETDNS_RRTYPE_SRV) {
if (srvs->count >= srvs->capacity && if (srvs->count >= srvs->capacity &&
!_grow_srvs(&context->mf, srvs)) !_grow_srvs(&context->mf, srvs))
@ -724,42 +703,14 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS)) if (getdns_dict_set_int(result, "answer_type", GETDNS_NAMETYPE_DNS))
goto error; goto error;
cnames_followed = new_canonical;
while (cnames_followed < MAX_CNAME_REFERRALS && new_canonical) {
new_canonical = 0;
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage answer = _getdns_rrset_answer(&answer_spc, req->response
, req->response , req->response_len);
, req->response_len)
; rr_iter && _getdns_rr_iter_section(rr_iter)
<= SECTION_ANSWER
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
if (_getdns_rr_iter_section(rr_iter) != if (answer_spc.rrset.name &&
SECTION_ANSWER) _getdns_dict_set_const_bindata(result, "canonical_name"
continue; , answer_spc.name_len
, answer_spc.rrset.name))
if (gldns_read_uint16(rr_iter->rr_type) !=
GETDNS_RRTYPE_CNAME)
continue;
owner_name = _getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space, &owner_name_len);
if (!_getdns_dname_equal(canonical_name, owner_name))
continue;
if (!(rdf_iter = _getdns_rdf_iter_init(
&rdf_iter_storage, rr_iter)))
continue;
canonical_name = _getdns_rdf_if_or_as_decompressed(
rdf_iter,canonical_name_space,&canonical_name_len);
new_canonical = 1;
cnames_followed++;
}
}
if (_getdns_dict_set_const_bindata(
result, "canonical_name", canonical_name_len, canonical_name))
goto error; goto error;
if (!req->owner->add_warning_for_bad_dns) if (!req->owner->add_warning_for_bad_dns)
@ -768,35 +719,15 @@ _getdns_create_reply_dict(getdns_context *context, getdns_network_req *req,
if (!(bad_dns = getdns_list_create_with_context(context))) if (!(bad_dns = getdns_list_create_with_context(context)))
goto error; goto error;
if (cnames_followed && req->request_type != GETDNS_RRTYPE_CNAME) { if ( !answer
request_answered = 0; && req->request_type != GETDNS_RRTYPE_CNAME
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage && query_name
, req->response && answer_spc.rrset.name
, req->response_len) && !_getdns_dname_equal(query_name, answer_spc.rrset.name)
; rr_iter && _getdns_rr_iter_section(rr_iter) && _getdns_list_append_int(bad_dns
<= SECTION_ANSWER , GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
; rr_iter = _getdns_rr_iter_next(rr_iter)) {
if (_getdns_rr_iter_section(rr_iter) !=
SECTION_ANSWER)
continue;
if (gldns_read_uint16(rr_iter->rr_type) !=
req->request_type)
continue;
owner_name=_getdns_owner_if_or_as_decompressed(
rr_iter, owner_name_space,&owner_name_len);
if (_getdns_dname_equal(
canonical_name, owner_name)) {
request_answered = 1;
break;
}
}
if (!request_answered &&
_getdns_list_append_int(bad_dns,
GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE))
goto error; goto error;
}
all_numeric_label = 0; all_numeric_label = 0;
for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage for ( rr_iter = _getdns_rr_iter_init(&rr_iter_storage
, req->response , req->response