mirror of https://github.com/getdnsapi/getdns.git
Successive suffix append retries
This commit is contained in:
parent
89b6c04d4f
commit
875ef3f9d4
|
@ -1866,7 +1866,7 @@ getdns_context_set_suffix(getdns_context *context, getdns_list *value)
|
|||
else
|
||||
break;
|
||||
|
||||
gldns_buffer_write_u8(&gbuf, 0);
|
||||
gldns_buffer_write_u8(&gbuf, 1);
|
||||
gldns_buffer_write_u8(&gbuf, 0);
|
||||
|
||||
if (gldns_buffer_begin(&gbuf) != buf_spc)
|
||||
|
|
146
src/general.c
146
src/general.c
|
@ -44,6 +44,7 @@
|
|||
#include "util-internal.h"
|
||||
#include "dnssec.h"
|
||||
#include "stub.h"
|
||||
#include "general.h"
|
||||
|
||||
/* cancel, cleanup and send timeout to callback */
|
||||
static void
|
||||
|
@ -72,6 +73,83 @@ void _getdns_call_user_callback(getdns_dns_req *dns_req,
|
|||
context->processing = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
no_answer(getdns_dns_req *dns_req)
|
||||
{
|
||||
getdns_network_req **netreq_p, *netreq;
|
||||
int new_canonical = 0;
|
||||
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++) {
|
||||
if (netreq->response_len == 0 ||
|
||||
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;
|
||||
for ( rr = _getdns_rr_iter_init(&rr_spc
|
||||
, netreq->response
|
||||
, netreq->response_len)
|
||||
; rr && _getdns_rr_iter_section(rr)
|
||||
<= GLDNS_SECTION_ANSWER
|
||||
; rr = _getdns_rr_iter_next(rr)) {
|
||||
|
||||
if (_getdns_rr_iter_section(rr) !=
|
||||
GLDNS_SECTION_ANSWER)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
} while (new_canonical);
|
||||
for ( rr = _getdns_rr_iter_init(&rr_spc
|
||||
, netreq->response
|
||||
, netreq->response_len)
|
||||
; rr && _getdns_rr_iter_section(rr)
|
||||
<= GLDNS_SECTION_ANSWER
|
||||
; rr = _getdns_rr_iter_next(rr)) {
|
||||
|
||||
if (_getdns_rr_iter_section(rr) !=
|
||||
GLDNS_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 1;
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_check_dns_req_complete(getdns_dns_req *dns_req)
|
||||
{
|
||||
|
@ -85,6 +163,74 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req)
|
|||
else if (netreq->response_len > 0)
|
||||
results_found = 1;
|
||||
|
||||
/* Do we have to check more suffixes on nxdomain/nodata?
|
||||
*/
|
||||
if (dns_req->suffix_appended && /* Something was appended */
|
||||
dns_req->suffix_len > 1 && /* Next suffix available */
|
||||
no_answer(dns_req)) {
|
||||
/* Remove suffix from name */
|
||||
dns_req->name_len -= dns_req->suffix_len - 1;
|
||||
dns_req->name[dns_req->name_len - 1] = 0;
|
||||
do {
|
||||
dns_req->suffix += dns_req->suffix_len;
|
||||
dns_req->suffix_len = *dns_req->suffix++;
|
||||
if (dns_req->suffix_len + dns_req->name_len - 1 <
|
||||
sizeof(dns_req->name)) {
|
||||
memcpy(dns_req->name + dns_req->name_len - 1,
|
||||
dns_req->suffix, dns_req->suffix_len);
|
||||
dns_req->name_len += dns_req->suffix_len - 1;
|
||||
dns_req->suffix_appended = 1;
|
||||
break;
|
||||
}
|
||||
} while (dns_req->suffix_len > 1 && *dns_req->suffix);
|
||||
if (dns_req->append_name == GETDNS_APPEND_NAME_ALWAYS ||
|
||||
(dns_req->suffix_len > 1 && *dns_req->suffix)) {
|
||||
for ( netreq_p = dns_req->netreqs
|
||||
; (netreq = *netreq_p)
|
||||
; netreq_p++ ) {
|
||||
_getdns_netreq_reinit(netreq);
|
||||
if (_getdns_submit_netreq(netreq))
|
||||
netreq->state = NET_REQ_FINISHED;
|
||||
}
|
||||
_getdns_check_dns_req_complete(dns_req);
|
||||
return;
|
||||
}
|
||||
} else if (
|
||||
( dns_req->append_name ==
|
||||
GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE ||
|
||||
dns_req->append_name ==
|
||||
GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE
|
||||
) &&
|
||||
!dns_req->suffix_appended &&
|
||||
dns_req->suffix_len > 1 &&
|
||||
no_answer(dns_req)) {
|
||||
/* Initial suffix append */
|
||||
for (
|
||||
; dns_req->suffix_len > 1 && *dns_req->suffix
|
||||
; dns_req->suffix += dns_req->suffix_len
|
||||
, dns_req->suffix_len = *dns_req->suffix++) {
|
||||
|
||||
if (dns_req->suffix_len + dns_req->name_len - 1 <
|
||||
sizeof(dns_req->name)) {
|
||||
memcpy(dns_req->name + dns_req->name_len - 1,
|
||||
dns_req->suffix, dns_req->suffix_len);
|
||||
dns_req->name_len += dns_req->suffix_len - 1;
|
||||
dns_req->suffix_appended = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dns_req->suffix_appended) {
|
||||
for ( netreq_p = dns_req->netreqs
|
||||
; (netreq = *netreq_p)
|
||||
; netreq_p++ ) {
|
||||
_getdns_netreq_reinit(netreq);
|
||||
if (_getdns_submit_netreq(netreq))
|
||||
netreq->state = NET_REQ_FINISHED;
|
||||
}
|
||||
_getdns_check_dns_req_complete(dns_req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dns_req->internal_cb)
|
||||
dns_req->internal_cb(dns_req);
|
||||
else if (! results_found)
|
||||
|
|
|
@ -110,6 +110,33 @@ network_req_cleanup(getdns_network_req *net_req)
|
|||
GETDNS_FREE(net_req->owner->my_mf, net_req->response);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
netreq_reset(getdns_network_req *net_req)
|
||||
{
|
||||
uint8_t *buf;
|
||||
/* variables that need to be reset on reinit
|
||||
*/
|
||||
net_req->unbound_id = -1;
|
||||
net_req->state = NET_REQ_NOT_SENT;
|
||||
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->query_id = 0;
|
||||
net_req->response_len = 0;
|
||||
/* Some fields to record info for return_call_reporting */
|
||||
net_req->debug_start_time = 0;
|
||||
net_req->debug_end_time = 0;
|
||||
if (!net_req->query)
|
||||
return NULL;
|
||||
|
||||
buf = net_req->query + GLDNS_HEADER_SIZE;
|
||||
(void) memcpy(buf, net_req->owner->name, net_req->owner->name_len);
|
||||
buf += net_req->owner->name_len;
|
||||
|
||||
gldns_write_uint16(buf, net_req->request_type);
|
||||
gldns_write_uint16(buf + 2, net_req->owner->request_class);
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
static int
|
||||
network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
||||
uint16_t request_type, int dnssec_extension_set, int with_opt,
|
||||
|
@ -125,48 +152,45 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
size_t i;
|
||||
int r = 0;
|
||||
|
||||
/* variables that stay the same on reinit, don't touch
|
||||
*/
|
||||
net_req->request_type = request_type;
|
||||
net_req->unbound_id = -1;
|
||||
net_req->state = NET_REQ_NOT_SENT;
|
||||
net_req->owner = owner;
|
||||
|
||||
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE;
|
||||
|
||||
net_req->upstream = NULL;
|
||||
net_req->fd = -1;
|
||||
net_req->transport_count = owner->context->dns_transport_count;
|
||||
net_req->transport_current = 0;
|
||||
memcpy(net_req->transports, owner->context->dns_transports,
|
||||
net_req->transport_count * sizeof(getdns_transport_list_t));
|
||||
net_req->tls_auth_min = owner->context->tls_auth_min;
|
||||
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
||||
net_req->query_id = 0;
|
||||
net_req->edns_maximum_udp_payload_size = edns_maximum_udp_payload_size;
|
||||
net_req->max_udp_payload_size = edns_maximum_udp_payload_size != -1
|
||||
? edns_maximum_udp_payload_size : 1432;
|
||||
net_req->base_query_option_sz = opt_options_size;
|
||||
net_req->wire_data_sz = wire_data_sz;
|
||||
|
||||
net_req->transport_count = owner->context->dns_transport_count;
|
||||
memcpy(net_req->transports, owner->context->dns_transports,
|
||||
net_req->transport_count * sizeof(getdns_transport_list_t));
|
||||
net_req->tls_auth_min = owner->context->tls_auth_min;
|
||||
|
||||
/* state variables from the resolver, don't touch
|
||||
*/
|
||||
net_req->upstream = NULL;
|
||||
net_req->fd = -1;
|
||||
net_req->transport_current = 0;
|
||||
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
||||
net_req->keepalive_sent = 0;
|
||||
net_req->write_queue_tail = NULL;
|
||||
net_req->response_len = 0;
|
||||
net_req->base_query_option_sz = opt_options_size;
|
||||
|
||||
/* Some fields to record info for return_call_reporting */
|
||||
net_req->debug_start_time = 0;
|
||||
net_req->debug_end_time = 0;
|
||||
net_req->debug_tls_auth_status = 0;
|
||||
net_req->debug_udp = 0;
|
||||
|
||||
net_req->wire_data_sz = wire_data_sz;
|
||||
if (max_query_sz == 0) {
|
||||
net_req->query = NULL;
|
||||
net_req->opt = NULL;
|
||||
net_req->response = net_req->wire_data;
|
||||
netreq_reset(net_req);
|
||||
return r;
|
||||
}
|
||||
/* first two bytes will contain query length (for tcp) */
|
||||
buf = net_req->query = net_req->wire_data + 2;
|
||||
net_req->query = net_req->wire_data + 2;
|
||||
|
||||
buf = net_req->query;
|
||||
gldns_write_uint16(buf + 2, 0); /* reset all flags */
|
||||
GLDNS_RD_SET(buf);
|
||||
if (dnssec_extension_set) /* We will do validation ourselves */
|
||||
|
@ -177,14 +201,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
gldns_write_uint16(buf + GLDNS_NSCOUNT_OFF, 0); /* 0 authorities */
|
||||
gldns_write_uint16(buf + GLDNS_ARCOUNT_OFF, with_opt ? 1 : 0);
|
||||
|
||||
buf += GLDNS_HEADER_SIZE;
|
||||
memcpy(buf, owner->name, owner->name_len);
|
||||
buf += owner->name_len;
|
||||
|
||||
gldns_write_uint16(buf, request_type);
|
||||
gldns_write_uint16(buf + 2, owner->request_class);
|
||||
buf += 4;
|
||||
|
||||
buf = netreq_reset(net_req);
|
||||
if (with_opt) {
|
||||
net_req->opt = buf;
|
||||
buf[0] = 0; /* dname for . */
|
||||
|
@ -242,6 +259,39 @@ _getdns_network_req_clear_upstream_options(getdns_network_req * req)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
_getdns_netreq_reinit(getdns_network_req *netreq)
|
||||
{
|
||||
uint8_t *base_opt_backup;
|
||||
size_t base_opt_rr_sz;
|
||||
|
||||
if (!netreq->query) {
|
||||
(void) netreq_reset(netreq);
|
||||
return;
|
||||
|
||||
} else if (!netreq->opt) {
|
||||
/* Remove TSIG (if any) */
|
||||
gldns_write_uint16(netreq->query + GLDNS_ARCOUNT_OFF, 0);
|
||||
netreq->response = netreq_reset(netreq);
|
||||
gldns_write_uint16(netreq->wire_data,
|
||||
netreq->response - netreq->query);
|
||||
return;
|
||||
}
|
||||
_getdns_network_req_clear_upstream_options(netreq);
|
||||
base_opt_rr_sz = netreq->base_query_option_sz + 11;
|
||||
base_opt_backup = netreq->wire_data + netreq->wire_data_sz
|
||||
- base_opt_rr_sz;
|
||||
(void) memcpy(base_opt_backup, netreq->opt, base_opt_rr_sz);
|
||||
netreq->opt = netreq_reset(netreq);
|
||||
(void) memcpy(netreq->opt, base_opt_backup, base_opt_rr_sz);
|
||||
netreq->response = netreq->opt + base_opt_rr_sz;
|
||||
/* Remove TSIG (if any), but leave the opt RR */
|
||||
gldns_write_uint16(netreq->query + GLDNS_ARCOUNT_OFF, 1);
|
||||
gldns_write_uint16(netreq->wire_data,
|
||||
netreq->response - netreq->query);
|
||||
}
|
||||
|
||||
|
||||
/* add_upstream_option appends an option that is derived at send time.
|
||||
(you can send data as NULL and it will fill with all zeros) */
|
||||
getdns_return_t
|
||||
|
|
|
@ -398,5 +398,7 @@ size_t _getdns_network_req_add_tsig(getdns_network_req *req);
|
|||
|
||||
void _getdns_network_validate_tsig(getdns_network_req *req);
|
||||
|
||||
void _getdns_netreq_reinit(getdns_network_req *netreq);
|
||||
|
||||
#endif
|
||||
/* types-internal.h */
|
||||
|
|
Loading…
Reference in New Issue