mirror of https://github.com/getdnsapi/getdns.git
Validate replies with getdns_validate_dnssec
You can feed it the replies_tree as the records to validate list
This commit is contained in:
parent
f92dd5ac0d
commit
6cffc4792b
157
src/dnssec.c
157
src/dnssec.c
|
@ -698,7 +698,6 @@ static int bitmap_contains_rrtype(priv_getdns_rdf_iter *bitmap, uint16_t rr_type
|
||||||
uint8_t window = rr_type >> 8;
|
uint8_t window = rr_type >> 8;
|
||||||
uint8_t subtype = rr_type & 0xFF;
|
uint8_t subtype = rr_type & 0xFF;
|
||||||
|
|
||||||
DEBUG_SEC("bitmap: %p, type: %d\n", bitmap, (int)rr_type);
|
|
||||||
if (!bitmap)
|
if (!bitmap)
|
||||||
return 0;
|
return 0;
|
||||||
dptr = bitmap->pos;
|
dptr = bitmap->pos;
|
||||||
|
@ -884,14 +883,28 @@ static uint8_t *name2nsec3_label(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t *_dname_label_copy(uint8_t *dst, uint8_t *src, size_t dst_len)
|
||||||
|
{
|
||||||
|
uint8_t *r = dst, i;
|
||||||
|
|
||||||
|
if (!src || *src + 1 > dst_len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = *src + 1; i > 0; i--)
|
||||||
|
*dst++ = tolower(*src++);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int nsec3_matches_name(getdns_rrset *nsec3, uint8_t *name)
|
static int nsec3_matches_name(getdns_rrset *nsec3, uint8_t *name)
|
||||||
{
|
{
|
||||||
uint8_t label[64];
|
uint8_t label[64], owner[64];
|
||||||
|
|
||||||
if (name2nsec3_label(nsec3, name, label, sizeof(label)))
|
if (name2nsec3_label(nsec3, name, label, sizeof(label))
|
||||||
|
&& _dname_label_copy(owner, nsec3->name, sizeof(owner)))
|
||||||
|
|
||||||
return *nsec3->name == label[0] /* Labels same size? */
|
return *nsec3->name == label[0] /* Labels same size? */
|
||||||
&& memcmp(nsec3->name + 1, label + 1, label[0]) == 0;
|
&& memcmp(owner + 1, label + 1, label[0]) == 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -913,7 +926,7 @@ static int nsec3_covers_name(getdns_rrset *nsec3, uint8_t *name, int *opt_out)
|
||||||
|| (nsz = gldns_b32_ntop_extended_hex(rdf->pos + 1, *rdf->pos,
|
|| (nsz = gldns_b32_ntop_extended_hex(rdf->pos + 1, *rdf->pos,
|
||||||
(char *)next + 1, sizeof(next)-2)) < 0
|
(char *)next + 1, sizeof(next)-2)) < 0
|
||||||
|| *nsec3->name > sizeof(owner) - 2
|
|| *nsec3->name > sizeof(owner) - 2
|
||||||
|| !memcpy(owner, nsec3->name, *nsec3->name + 1)) {
|
|| !_dname_label_copy(owner, nsec3->name, sizeof(owner)-1)) {
|
||||||
|
|
||||||
DEBUG_SEC("Error getting NSEC3 owner & next labels\n");
|
DEBUG_SEC("Error getting NSEC3 owner & next labels\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1583,6 +1596,7 @@ static void val_chain_node_soa_cb(getdns_dns_req *dnsreq)
|
||||||
! priv_getdns_dname_equal(node->ds.name, rrset->name))
|
! priv_getdns_dname_equal(node->ds.name, rrset->name))
|
||||||
node = node->parent;
|
node = node->parent;
|
||||||
|
|
||||||
|
if (node)
|
||||||
val_chain_sched_node(node);
|
val_chain_sched_node(node);
|
||||||
} else
|
} else
|
||||||
val_chain_sched_soa_node(node->parent);
|
val_chain_sched_soa_node(node->parent);
|
||||||
|
@ -1614,6 +1628,14 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
|
||||||
max_head = NULL;
|
max_head = NULL;
|
||||||
max_labels = 0;
|
max_labels = 0;
|
||||||
for (head = *chain_p; head; head = head->next) {
|
for (head = *chain_p; head; head = head->next) {
|
||||||
|
/* Also, try to prevent adding double rrsets */
|
||||||
|
if ( rrset->rr_class == head->rrset.rr_class
|
||||||
|
&& rrset->rr_type == head->rrset.rr_type
|
||||||
|
&& rrset->pkt == head->rrset.pkt
|
||||||
|
&& rrset->pkt_len == head->rrset.pkt_len
|
||||||
|
&& priv_getdns_dname_equal(rrset->name, head->rrset.name))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (label = labels; label < last_label; label++) {
|
for (label = labels; label < last_label; label++) {
|
||||||
if (! is_subdomain(*label, head->rrset.name))
|
if (! is_subdomain(*label, head->rrset.name))
|
||||||
break;
|
break;
|
||||||
|
@ -1715,7 +1737,6 @@ static chain_head *add_rrset2val_chain(struct mem_funcs *mf,
|
||||||
*/
|
*/
|
||||||
static void add_pkt2val_chain(struct mem_funcs *mf,
|
static void add_pkt2val_chain(struct mem_funcs *mf,
|
||||||
chain_head **chain_p, uint8_t *pkt, size_t pkt_len,
|
chain_head **chain_p, uint8_t *pkt, size_t pkt_len,
|
||||||
uint8_t *qname, uint16_t qtype, uint16_t qclass,
|
|
||||||
getdns_network_req *netreq)
|
getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
rrset_iter *i, i_spc;
|
rrset_iter *i, i_spc;
|
||||||
|
@ -1723,36 +1744,14 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
|
||||||
rrsig_iter *rrsig, rrsig_spc;
|
rrsig_iter *rrsig, rrsig_spc;
|
||||||
size_t n_rrsigs;
|
size_t n_rrsigs;
|
||||||
chain_head *head;
|
chain_head *head;
|
||||||
getdns_rrset empty_rrset;
|
|
||||||
|
|
||||||
getdns_rrset q_rrset;
|
|
||||||
uint8_t cname_spc[256];
|
|
||||||
size_t cname_len = sizeof(cname_spc);
|
|
||||||
size_t anti_loop;
|
|
||||||
priv_getdns_rdf_iter rdf_spc, *rdf;
|
|
||||||
rrtype_iter *rr, rr_spc;
|
|
||||||
|
|
||||||
assert(pkt);
|
assert(pkt);
|
||||||
assert(pkt_len >= GLDNS_HEADER_SIZE);
|
assert(pkt_len >= GLDNS_HEADER_SIZE);
|
||||||
|
|
||||||
/* On empty packet, find SOA (zonecut) for the qname and query DS */
|
|
||||||
|
|
||||||
/* For all things with signatures, create a chain */
|
/* For all things with signatures, create a chain */
|
||||||
|
|
||||||
/* For all things without signature, find SOA (zonecut) and query DS */
|
/* For all things without signature, find SOA (zonecut) and query DS */
|
||||||
|
|
||||||
if (GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0 && qname) {
|
|
||||||
|
|
||||||
empty_rrset.name = qname;
|
|
||||||
empty_rrset.rr_class = qclass;
|
|
||||||
empty_rrset.rr_type = qtype;
|
|
||||||
empty_rrset.pkt = pkt;
|
|
||||||
empty_rrset.pkt_len = pkt_len;
|
|
||||||
|
|
||||||
head = add_rrset2val_chain(mf, chain_p, &empty_rrset, netreq);
|
|
||||||
val_chain_sched_soa(head, empty_rrset.name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for ( i = rrset_iter_init(&i_spc, pkt, pkt_len)
|
for ( i = rrset_iter_init(&i_spc, pkt, pkt_len)
|
||||||
; i
|
; i
|
||||||
; i = rrset_iter_next(i)) {
|
; i = rrset_iter_next(i)) {
|
||||||
|
@ -1760,7 +1759,9 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
|
||||||
rrset = rrset_iter_value(i);
|
rrset = rrset_iter_value(i);
|
||||||
debug_sec_print_rrset("rrset: ", rrset);
|
debug_sec_print_rrset("rrset: ", rrset);
|
||||||
|
|
||||||
head = add_rrset2val_chain(mf, chain_p, rrset, netreq);
|
if (!(head = add_rrset2val_chain(mf, chain_p, rrset, netreq)))
|
||||||
|
continue;
|
||||||
|
|
||||||
for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset), n_rrsigs = 0
|
for ( rrsig = rrsig_iter_init(&rrsig_spc, rrset), n_rrsigs = 0
|
||||||
; rrsig
|
; rrsig
|
||||||
; rrsig = rrsig_iter_next(rrsig), n_rrsigs++) {
|
; rrsig = rrsig_iter_next(rrsig), n_rrsigs++) {
|
||||||
|
@ -1772,16 +1773,35 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
|
||||||
|
|
||||||
if (rrset->rr_type == GETDNS_RRTYPE_SOA)
|
if (rrset->rr_type == GETDNS_RRTYPE_SOA)
|
||||||
val_chain_sched(head, rrset->name);
|
val_chain_sched(head, rrset->name);
|
||||||
|
else if (rrset->rr_type == GETDNS_RRTYPE_CNAME)
|
||||||
|
val_chain_sched_soa(head, rrset->name + *rrset->name + 1);
|
||||||
else
|
else
|
||||||
val_chain_sched_soa(head, rrset->name);
|
val_chain_sched_soa(head, rrset->name);
|
||||||
}
|
}
|
||||||
/* For NOERROR/NODATA or NXDOMAIN responses add extra rrset to
|
}
|
||||||
|
|
||||||
|
/* For NOERROR/NODATA or NXDOMAIN responses add extra rrset to
|
||||||
* the validation chain so the denial of existence will be
|
* the validation chain so the denial of existence will be
|
||||||
* checked eventually.
|
* checked eventually.
|
||||||
* But only if we knew the question of course...
|
* But only if we know the question of course...
|
||||||
*/
|
*/
|
||||||
if (!qname)
|
static void add_question2val_chain(struct mem_funcs *mf,
|
||||||
return;
|
chain_head **chain_p, uint8_t *pkt, size_t pkt_len,
|
||||||
|
uint8_t *qname, uint16_t qtype, uint16_t qclass,
|
||||||
|
getdns_network_req *netreq)
|
||||||
|
{
|
||||||
|
getdns_rrset q_rrset;
|
||||||
|
uint8_t cname_spc[256];
|
||||||
|
size_t cname_len = sizeof(cname_spc);
|
||||||
|
size_t anti_loop;
|
||||||
|
priv_getdns_rdf_iter rdf_spc, *rdf;
|
||||||
|
rrtype_iter *rr, rr_spc;
|
||||||
|
|
||||||
|
chain_head *head;
|
||||||
|
|
||||||
|
assert(pkt);
|
||||||
|
assert(pkt_len >= GLDNS_HEADER_SIZE);
|
||||||
|
assert(qname);
|
||||||
|
|
||||||
/* First find the canonical name for the question */
|
/* First find the canonical name for the question */
|
||||||
q_rrset.name = qname;
|
q_rrset.name = qname;
|
||||||
|
@ -1798,25 +1818,37 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
|
||||||
q_rrset.name = priv_getdns_rdf_if_or_as_decompressed(
|
q_rrset.name = priv_getdns_rdf_if_or_as_decompressed(
|
||||||
rdf, cname_spc, &cname_len);
|
rdf, cname_spc, &cname_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
q_rrset.rr_type = qtype;
|
q_rrset.rr_type = qtype;
|
||||||
if (!(rr = rrtype_iter_init(&rr_spc, &q_rrset))) {
|
if (!(rr = rrtype_iter_init(&rr_spc, &q_rrset))) {
|
||||||
|
/* No answer for the question. Add a head for this rrset
|
||||||
|
* anyway, to validate proof of non-existance, or to find
|
||||||
|
* proof that the packet is insecure.
|
||||||
|
*/
|
||||||
debug_sec_print_rrset("Adding NX rrset: ", &q_rrset);
|
debug_sec_print_rrset("Adding NX rrset: ", &q_rrset);
|
||||||
add_rrset2val_chain(mf, chain_p, &q_rrset, netreq);
|
head = add_rrset2val_chain(mf, chain_p, &q_rrset, netreq);
|
||||||
|
|
||||||
|
/* On empty packet, find SOA (zonecut) for the qname */
|
||||||
|
if (head && GLDNS_ANCOUNT(pkt) == 0 && GLDNS_NSCOUNT(pkt) == 0)
|
||||||
|
|
||||||
|
val_chain_sched_soa(head, q_rrset.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_val_chain(getdns_dns_req *dnsreq)
|
void priv_getdns_get_validation_chain(getdns_dns_req *dnsreq)
|
||||||
{
|
{
|
||||||
getdns_network_req *netreq, **netreq_p;
|
getdns_network_req *netreq, **netreq_p;
|
||||||
chain_head *chain = NULL;
|
chain_head *chain = NULL;
|
||||||
|
|
||||||
for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p) ; netreq_p++) {
|
for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p) ; netreq_p++) {
|
||||||
add_pkt2val_chain( &dnsreq->my_mf, &chain
|
add_pkt2val_chain( &dnsreq->my_mf, &chain
|
||||||
|
, netreq->response, netreq->response_len
|
||||||
|
, netreq
|
||||||
|
);
|
||||||
|
add_question2val_chain( &dnsreq->my_mf, &chain
|
||||||
, netreq->response, netreq->response_len
|
, netreq->response, netreq->response_len
|
||||||
, netreq->owner->name
|
, netreq->owner->name
|
||||||
, netreq->request_type, netreq->request_class
|
, netreq->request_type
|
||||||
|
, netreq->request_class
|
||||||
, netreq
|
, netreq
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1828,18 +1860,6 @@ static void get_val_chain(getdns_dns_req *dnsreq)
|
||||||
create_getdns_response(dnsreq));
|
create_getdns_response(dnsreq));
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/***************************** *******************************/
|
|
||||||
/***************************** NEW CHAIN CODE *******************************/
|
|
||||||
/***************************** (above) *******************************/
|
|
||||||
/***************************** *******************************/
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
void priv_getdns_get_validation_chain(getdns_dns_req *dns_req)
|
|
||||||
{
|
|
||||||
get_val_chain(dns_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getdns_validate_dnssec
|
* getdns_validate_dnssec
|
||||||
*
|
*
|
||||||
|
@ -1878,7 +1898,7 @@ getdns_validate_dnssec(getdns_list *records_to_validate,
|
||||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||||
mf = &records_to_validate->mf;
|
mf = &records_to_validate->mf;
|
||||||
|
|
||||||
/* First convert everything to wire formatxi
|
/* First convert everything to wire format
|
||||||
*/
|
*/
|
||||||
if (!(to_val = _getdns_list2wire(records_to_validate,
|
if (!(to_val = _getdns_list2wire(records_to_validate,
|
||||||
to_val_buf, &to_val_len, mf)))
|
to_val_buf, &to_val_len, mf)))
|
||||||
|
@ -1892,19 +1912,39 @@ getdns_validate_dnssec(getdns_list *records_to_validate,
|
||||||
tas_buf, &tas_len, mf)))
|
tas_buf, &tas_len, mf)))
|
||||||
goto exit_free_support;
|
goto exit_free_support;
|
||||||
|
|
||||||
if (GLDNS_QDCOUNT(to_val) > 0
|
if (GLDNS_QDCOUNT(to_val) == 0 && GLDNS_ANCOUNT(to_val) == 0) {
|
||||||
&& (rr = priv_getdns_rr_iter_init(&rr_spc, to_val, to_val_len))
|
r = GETDNS_RETURN_GENERIC_ERROR;
|
||||||
&& (qname = priv_getdns_owner_if_or_as_decompressed(
|
goto exit_free_tas;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain = NULL;
|
||||||
|
/* First create a chain (head + nodes) for each rr in the answer and
|
||||||
|
* authority section of the fake to_val packet.
|
||||||
|
*/
|
||||||
|
add_pkt2val_chain(mf, &chain, to_val, to_val_len, NULL);
|
||||||
|
|
||||||
|
/* When records_to_validate contained replies, like the replies_tree
|
||||||
|
* list in a response dict, the returned wireformat packet may contain
|
||||||
|
* multiple questions in the question section. For each reply one
|
||||||
|
* question.
|
||||||
|
*
|
||||||
|
* For each question in the question section add a chain head.
|
||||||
|
*/
|
||||||
|
for ( rr = priv_getdns_rr_iter_init(&rr_spc, to_val, to_val_len)
|
||||||
|
; rr && priv_getdns_rr_iter_section(rr) == GLDNS_SECTION_QUESTION
|
||||||
|
; rr = priv_getdns_rr_iter_next(rr) ) {
|
||||||
|
|
||||||
|
if ((qname = priv_getdns_owner_if_or_as_decompressed(
|
||||||
rr, qname_spc, &qname_len))
|
rr, qname_spc, &qname_len))
|
||||||
&& rr->nxt >= rr->rr_type + 4) {
|
&& rr->nxt >= rr->rr_type + 4) {
|
||||||
|
|
||||||
qtype = gldns_read_uint16(rr->rr_type);
|
qtype = gldns_read_uint16(rr->rr_type);
|
||||||
qclass = gldns_read_uint16(rr->rr_type + 2);
|
qclass = gldns_read_uint16(rr->rr_type + 2);
|
||||||
}
|
|
||||||
/* Create the chain hierarchy where all head's need to be validated. */
|
add_question2val_chain(mf, &chain, to_val, to_val_len,
|
||||||
chain = NULL;
|
|
||||||
add_pkt2val_chain(mf, &chain, to_val, to_val_len,
|
|
||||||
qname, qtype, qclass, NULL);
|
qname, qtype, qclass, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Now equip the nodes with the support records wireformat */
|
/* Now equip the nodes with the support records wireformat */
|
||||||
for (head = chain; head; head = head->next) {
|
for (head = chain; head; head = head->next) {
|
||||||
|
@ -1921,6 +1961,7 @@ getdns_validate_dnssec(getdns_list *records_to_validate,
|
||||||
r = (getdns_return_t)chain_validate_dnssec(
|
r = (getdns_return_t)chain_validate_dnssec(
|
||||||
chain, rrset_iter_init(&tas_iter, tas, tas_len));
|
chain, rrset_iter_init(&tas_iter, tas, tas_len));
|
||||||
|
|
||||||
|
exit_free_tas:
|
||||||
if (tas != tas_buf)
|
if (tas != tas_buf)
|
||||||
GETDNS_FREE(*mf, tas);
|
GETDNS_FREE(*mf, tas);
|
||||||
exit_free_support:
|
exit_free_support:
|
||||||
|
|
|
@ -141,11 +141,14 @@ static getdns_return_t validate_chain(getdns_dict *response)
|
||||||
getdns_list *validation_chain;
|
getdns_list *validation_chain;
|
||||||
getdns_list *replies_tree;
|
getdns_list *replies_tree;
|
||||||
getdns_dict *reply;
|
getdns_dict *reply;
|
||||||
getdns_list *answer;
|
getdns_list *to_validate;
|
||||||
getdns_list *trust_anchor;
|
getdns_list *trust_anchor;
|
||||||
size_t i;
|
size_t i;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
if (!(to_validate = getdns_list_create()))
|
||||||
|
return GETDNS_RETURN_MEMORY_ERROR;
|
||||||
|
|
||||||
if (!(trust_anchor = getdns_root_trust_anchor(NULL)))
|
if (!(trust_anchor = getdns_root_trust_anchor(NULL)))
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
|
@ -157,16 +160,39 @@ static getdns_return_t validate_chain(getdns_dict *response)
|
||||||
response, "replies_tree", &replies_tree)))
|
response, "replies_tree", &replies_tree)))
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
fprintf(stdout, "replies_tree %zu, dnssec_status: ", i);
|
||||||
|
switch ((s = getdns_validate_dnssec(
|
||||||
|
replies_tree, validation_chain, trust_anchor))) {
|
||||||
|
|
||||||
|
case GETDNS_DNSSEC_SECURE:
|
||||||
|
fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
|
||||||
|
break;
|
||||||
|
case GETDNS_DNSSEC_BOGUS:
|
||||||
|
fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n");
|
||||||
|
break;
|
||||||
|
case GETDNS_DNSSEC_INDETERMINATE:
|
||||||
|
fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n");
|
||||||
|
break;
|
||||||
|
case GETDNS_DNSSEC_INSECURE:
|
||||||
|
fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n");
|
||||||
|
break;
|
||||||
|
case GETDNS_DNSSEC_NOT_PERFORMED:
|
||||||
|
fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stdout, "%d\n", (int)s);
|
||||||
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) {
|
while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) {
|
||||||
|
|
||||||
if ((r = getdns_dict_get_list(reply, "answer", &answer)))
|
if ((r = getdns_list_set_dict(to_validate, 0, reply)))
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
fprintf( stdout
|
fprintf( stdout
|
||||||
, "reply %zu, getdns_validate_dnssec returned: ", i);
|
, "reply %zu, dnssec_status: ", i);
|
||||||
switch ((s = getdns_validate_dnssec(
|
switch ((s = getdns_validate_dnssec(
|
||||||
answer, validation_chain, trust_anchor))) {
|
to_validate, validation_chain, trust_anchor))) {
|
||||||
|
|
||||||
case GETDNS_DNSSEC_SECURE:
|
case GETDNS_DNSSEC_SECURE:
|
||||||
fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
|
fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
|
||||||
|
|
|
@ -992,9 +992,10 @@ priv_getdns_validate_dname(const char* dname) {
|
||||||
|
|
||||||
static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
||||||
{
|
{
|
||||||
getdns_dict *rr_dict;
|
getdns_dict *rr_dict, *q_dict;
|
||||||
|
getdns_list *section;
|
||||||
getdns_return_t r;
|
getdns_return_t r;
|
||||||
size_t i, pkt_start, ancount;
|
size_t i, j, pkt_start, ancount, qdcount;
|
||||||
uint32_t qtype, qclass;
|
uint32_t qtype, qclass;
|
||||||
getdns_bindata *qname;
|
getdns_bindata *qname;
|
||||||
|
|
||||||
|
@ -1004,7 +1005,7 @@ static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
||||||
gldns_buffer_write_u32(buf, 0);
|
gldns_buffer_write_u32(buf, 0);
|
||||||
gldns_buffer_write_u32(buf, 0);
|
gldns_buffer_write_u32(buf, 0);
|
||||||
|
|
||||||
for ( i = 0
|
for ( i = 0, qdcount = 0
|
||||||
; (r = getdns_list_get_dict(l, i, &rr_dict))
|
; (r = getdns_list_get_dict(l, i, &rr_dict))
|
||||||
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
||||||
; i++ ) {
|
; i++ ) {
|
||||||
|
@ -1015,6 +1016,14 @@ static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (getdns_dict_get_dict(rr_dict, "question", &q_dict)
|
||||||
|
== GETDNS_RETURN_GOOD) {
|
||||||
|
|
||||||
|
/* rr_dict was actually a reply
|
||||||
|
* with a question section/rr_dict
|
||||||
|
*/
|
||||||
|
rr_dict = q_dict;
|
||||||
|
}
|
||||||
if (getdns_dict_get_int(rr_dict, "qtype", &qtype) ||
|
if (getdns_dict_get_int(rr_dict, "qtype", &qtype) ||
|
||||||
getdns_dict_get_bindata(rr_dict, "qname", &qname))
|
getdns_dict_get_bindata(rr_dict, "qname", &qname))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1022,9 +1031,9 @@ static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
||||||
gldns_buffer_write(buf, qname->data, qname->size);
|
gldns_buffer_write(buf, qname->data, qname->size);
|
||||||
gldns_buffer_write_u16(buf, (uint16_t)qtype);
|
gldns_buffer_write_u16(buf, (uint16_t)qtype);
|
||||||
gldns_buffer_write_u16(buf, (uint16_t)qclass);
|
gldns_buffer_write_u16(buf, (uint16_t)qclass);
|
||||||
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_QDCOUNT_OFF, 1);
|
qdcount++;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_QDCOUNT_OFF, qdcount);
|
||||||
for ( i = 0, ancount = 0
|
for ( i = 0, ancount = 0
|
||||||
; (r = getdns_list_get_dict(l, i, &rr_dict))
|
; (r = getdns_list_get_dict(l, i, &rr_dict))
|
||||||
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
||||||
|
@ -1036,8 +1045,54 @@ static void _getdns_list2wire_buf(gldns_buffer *buf, getdns_list *l)
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (priv_getdns_rr_dict2wire(rr_dict, buf) == GETDNS_RETURN_GOOD)
|
if (priv_getdns_rr_dict2wire(rr_dict, buf)
|
||||||
|
== GETDNS_RETURN_GOOD) {
|
||||||
|
|
||||||
ancount++;
|
ancount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (getdns_dict_get_list(rr_dict, "answer", §ion)
|
||||||
|
== GETDNS_RETURN_GOOD) {
|
||||||
|
|
||||||
|
for ( j = 0
|
||||||
|
; (r = getdns_list_get_dict(section, j, &q_dict))
|
||||||
|
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
||||||
|
; j++ ) {
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
if (r ==
|
||||||
|
GETDNS_RETURN_WRONG_TYPE_REQUESTED)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (priv_getdns_rr_dict2wire(q_dict, buf)
|
||||||
|
== GETDNS_RETURN_GOOD)
|
||||||
|
|
||||||
|
ancount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getdns_dict_get_list(rr_dict, "authority", §ion)
|
||||||
|
== GETDNS_RETURN_GOOD) {
|
||||||
|
|
||||||
|
for ( j = 0
|
||||||
|
; (r = getdns_list_get_dict(section, j, &q_dict))
|
||||||
|
!= GETDNS_RETURN_NO_SUCH_LIST_ITEM
|
||||||
|
; j++ ) {
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
if (r ==
|
||||||
|
GETDNS_RETURN_WRONG_TYPE_REQUESTED)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (priv_getdns_rr_dict2wire(q_dict, buf)
|
||||||
|
== GETDNS_RETURN_GOOD)
|
||||||
|
|
||||||
|
ancount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_ANCOUNT_OFF, ancount);
|
gldns_buffer_write_u16_at(buf, pkt_start+GLDNS_ANCOUNT_OFF, ancount);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue