mirror of https://github.com/getdnsapi/getdns.git
timed synchronous resolves
Also returns an response dict with status GETDNS_RESPSTATUS_ALL_TIMEOUT on timeout
This commit is contained in:
parent
a0c2c05811
commit
fc2f091f05
|
@ -77,7 +77,7 @@ EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@
|
|||
|
||||
GETDNS_OBJ=sync.lo context.lo list.lo dict.lo convert.lo general.lo \
|
||||
hostname.lo service.lo request-internal.lo util-internal.lo \
|
||||
getdns_error.lo rr-dict.lo dnssec.lo const-info.lo
|
||||
getdns_error.lo rr-dict.lo dnssec.lo const-info.lo ub_timed_resolve.lo
|
||||
|
||||
.SUFFIXES: .c .o .a .lo .h
|
||||
|
||||
|
|
24
src/dnssec.c
24
src/dnssec.c
|
@ -47,6 +47,7 @@
|
|||
#include "types-internal.h"
|
||||
#include "dnssec.h"
|
||||
#include "rr-dict.h"
|
||||
#include "ub_timed_resolve.h"
|
||||
|
||||
void priv_getdns_call_user_callback(getdns_dns_req *, struct getdns_dict *);
|
||||
|
||||
|
@ -56,6 +57,7 @@ struct validation_chain {
|
|||
getdns_dns_req *dns_req;
|
||||
size_t lock;
|
||||
struct getdns_dict **sync_response;
|
||||
uint64_t *timeout;
|
||||
};
|
||||
|
||||
struct chain_response {
|
||||
|
@ -200,8 +202,8 @@ resolve(char* name, int rrtype, struct chain_response *response)
|
|||
|
||||
if (response->chain->sync_response) {
|
||||
ub_res = NULL;
|
||||
r = ub_resolve(response->chain->dns_req->context->unbound_ctx,
|
||||
name, rrtype, LDNS_RR_CLASS_IN, &ub_res);
|
||||
r = ub_timed_resolve(response->chain->dns_req->context->unbound_ctx,
|
||||
name, rrtype, LDNS_RR_CLASS_IN, &ub_res, response->chain->timeout);
|
||||
ub_chain_response_callback(response, r, ub_res);
|
||||
return r;
|
||||
} else
|
||||
|
@ -243,8 +245,8 @@ launch_chain_link_lookup(struct validation_chain *chain, char *name)
|
|||
chain->lock--;
|
||||
}
|
||||
|
||||
static struct validation_chain *create_chain(
|
||||
getdns_dns_req *dns_req, struct getdns_dict **sync_response)
|
||||
static struct validation_chain *create_chain(getdns_dns_req *dns_req,
|
||||
struct getdns_dict **sync_response, uint64_t *timeout)
|
||||
{
|
||||
struct validation_chain *chain = GETDNS_MALLOC(
|
||||
dns_req->context->mf, struct validation_chain);
|
||||
|
@ -261,6 +263,7 @@ static struct validation_chain *create_chain(
|
|||
chain->dns_req = dns_req;
|
||||
chain->lock = 0;
|
||||
chain->sync_response = sync_response;
|
||||
chain->timeout = timeout;
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
@ -284,11 +287,12 @@ static void destroy_chain(struct validation_chain *chain)
|
|||
|
||||
/* Do some additional requests to fetch the complete validation chain */
|
||||
static void
|
||||
getdns_get_validation_chain(
|
||||
getdns_dns_req *dns_req, struct getdns_dict **sync_response)
|
||||
getdns_get_validation_chain(getdns_dns_req *dns_req,
|
||||
struct getdns_dict **sync_response, uint64_t *timeout)
|
||||
{
|
||||
getdns_network_req *netreq = dns_req->first_req;
|
||||
struct validation_chain *chain = create_chain(dns_req, sync_response);
|
||||
struct validation_chain *chain = create_chain(
|
||||
dns_req, sync_response, timeout);
|
||||
|
||||
if (! chain) {
|
||||
if (sync_response)
|
||||
|
@ -315,14 +319,14 @@ getdns_get_validation_chain(
|
|||
|
||||
void priv_getdns_get_validation_chain(getdns_dns_req *dns_req)
|
||||
{
|
||||
getdns_get_validation_chain(dns_req, NULL);
|
||||
getdns_get_validation_chain(dns_req, NULL, NULL);
|
||||
}
|
||||
|
||||
struct getdns_dict *
|
||||
priv_getdns_get_validation_chain_sync(getdns_dns_req *dns_req)
|
||||
priv_getdns_get_validation_chain_sync(getdns_dns_req *dns_req, uint64_t *timeout)
|
||||
{
|
||||
struct getdns_dict *sync_response = NULL;
|
||||
getdns_get_validation_chain(dns_req, &sync_response);
|
||||
getdns_get_validation_chain(dns_req, &sync_response, timeout);
|
||||
return sync_response;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
void priv_getdns_get_validation_chain(getdns_dns_req *dns_req);
|
||||
|
||||
struct getdns_dict * priv_getdns_get_validation_chain_sync(
|
||||
getdns_dns_req *dns_req);
|
||||
getdns_dns_req *dns_req, uint64_t *timeout);
|
||||
|
||||
int priv_getdns_parse_ta_file(time_t *ta_mtime, ldns_rr_list *ta_rrs);
|
||||
|
||||
|
|
30
src/sync.c
30
src/sync.c
|
@ -42,30 +42,35 @@
|
|||
#include "types-internal.h"
|
||||
#include "util-internal.h"
|
||||
#include "dnssec.h"
|
||||
#include "ub_timed_resolve.h"
|
||||
|
||||
/* stuff to make it compile pedantically */
|
||||
#define UNUSED_PARAM(x) ((void)(x))
|
||||
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
|
||||
|
||||
getdns_return_t submit_request_sync(getdns_dns_req* req) {
|
||||
static getdns_return_t submit_request_sync(
|
||||
getdns_dns_req* req, uint64_t *timeout)
|
||||
{
|
||||
struct ub_result* ub_res = NULL;
|
||||
getdns_return_t gr = GETDNS_RETURN_GOOD;
|
||||
getdns_network_req *netreq = req->first_req;
|
||||
|
||||
while (netreq) {
|
||||
int r = ub_resolve(req->context->unbound_ctx,
|
||||
int r = ub_timed_resolve(req->context->unbound_ctx,
|
||||
req->name,
|
||||
netreq->request_type,
|
||||
netreq->request_class,
|
||||
&ub_res);
|
||||
if (r != 0) {
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
&ub_res,
|
||||
timeout);
|
||||
gr = getdns_apply_network_result(netreq, ub_res);
|
||||
ub_resolve_free(ub_res);
|
||||
ub_res = NULL;
|
||||
if (gr != GETDNS_RETURN_GOOD) {
|
||||
|
||||
if (r != GETDNS_RETURN_GOOD)
|
||||
return r;
|
||||
else if (gr != GETDNS_RETURN_GOOD)
|
||||
return gr;
|
||||
}
|
||||
|
||||
netreq = netreq->next;
|
||||
}
|
||||
return gr;
|
||||
|
@ -80,6 +85,7 @@ getdns_general_sync(struct getdns_context *context,
|
|||
{
|
||||
getdns_dns_req *req;
|
||||
getdns_return_t response_status;
|
||||
uint64_t timeout = context->timeout;
|
||||
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
RETURN_IF_NULL(response, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
|
@ -104,14 +110,16 @@ getdns_general_sync(struct getdns_context *context,
|
|||
if (!req)
|
||||
return GETDNS_RETURN_MEMORY_ERROR;
|
||||
|
||||
response_status = submit_request_sync(req);
|
||||
response_status = submit_request_sync(req, &timeout);
|
||||
if (response_status == GETDNS_RETURN_GOOD) {
|
||||
if (is_extension_set(req->extensions,
|
||||
"dnssec_return_validation_chain"))
|
||||
*response = priv_getdns_get_validation_chain_sync(req);
|
||||
*response = priv_getdns_get_validation_chain_sync(req, &timeout);
|
||||
else
|
||||
*response = create_getdns_response(req);
|
||||
}
|
||||
|
||||
} else if (response_status == GETDNS_RESPSTATUS_ALL_TIMEOUT)
|
||||
*response = create_getdns_response(req);
|
||||
|
||||
dns_req_free(req);
|
||||
return response_status;
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
*
|
||||
* /brief A timed synchronous unbound resolve function
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2014, NLnet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
#include "ub_timed_resolve.h"
|
||||
|
||||
static struct ub_result error_result;
|
||||
|
||||
static void cb_timed_resolve(void *my_arg, int err, struct ub_result *result)
|
||||
{
|
||||
struct ub_result **to_return = (struct ub_result **)my_arg;
|
||||
*to_return = err ? &error_result : result;
|
||||
}
|
||||
|
||||
int ub_timed_resolve(struct ub_ctx* ctx, char* name,
|
||||
int rrtype, int rrclass, struct ub_result** result, uint64_t *timeout)
|
||||
{
|
||||
fd_set rfds;
|
||||
struct timeval tv, now, prev;
|
||||
int r;
|
||||
int ubfd;
|
||||
int async_id;
|
||||
uint64_t elapsed;
|
||||
|
||||
assert(ctx != NULL);
|
||||
assert(name != NULL);
|
||||
assert(result != NULL);
|
||||
assert(timeout != NULL);
|
||||
|
||||
*result = NULL;
|
||||
if (ub_resolve_async(ctx, name, rrtype, rrclass,
|
||||
result, cb_timed_resolve, &async_id))
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
if (*result == &error_result) {
|
||||
*result = NULL;
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
} else if (*result)
|
||||
return GETDNS_RETURN_GOOD; /* result came from cache */
|
||||
|
||||
ubfd = ub_fd(ctx);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ubfd, &rfds);
|
||||
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
ub_cancel(ctx, async_id);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
for (;;) {
|
||||
/* timeout is in miliseconds, so map to seconds and microseconds */
|
||||
tv.tv_sec = *timeout / 1000;
|
||||
tv.tv_usec = (*timeout % 1000) * 1000;
|
||||
|
||||
r = select(ubfd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (r <= 0)
|
||||
ub_cancel(ctx, async_id);
|
||||
if (r < 0)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
else if (r == 0)
|
||||
return GETDNS_RESPSTATUS_ALL_TIMEOUT;
|
||||
|
||||
prev = now;
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
ub_cancel(ctx, async_id);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
elapsed = now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||
elapsed -= prev.tv_sec * 1000 + prev.tv_usec / 1000;
|
||||
if (elapsed > *timeout) {
|
||||
*timeout = 0;
|
||||
ub_cancel(ctx, async_id);
|
||||
return GETDNS_RESPSTATUS_ALL_TIMEOUT;
|
||||
}
|
||||
*timeout -= elapsed;
|
||||
|
||||
/* We have readiness */
|
||||
if (! ub_poll(ctx))
|
||||
continue;
|
||||
if (ub_process(ctx)) {
|
||||
ub_cancel(ctx, async_id);
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
}
|
||||
if (*result == &error_result) {
|
||||
*result = NULL;
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
} else if (*result)
|
||||
return GETDNS_RETURN_GOOD; /* result came from cache */
|
||||
}
|
||||
}
|
||||
|
||||
/* ub_timed_resolve.c */
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
*
|
||||
* /brief A timed synchronous unbound resolve function
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2014, NLnet Labs, Verisign, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the names of the copyright holders nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UB_TIMED_RESOLVE_H_
|
||||
#define UB_TIMED_RESOLVE_H_
|
||||
|
||||
#include "getdns/getdns.h"
|
||||
#include <unbound.h>
|
||||
|
||||
int ub_timed_resolve(struct ub_ctx *ctx, char *name,
|
||||
int rrtype, int rrclass, struct ub_result **result, uint64_t *timeout);
|
||||
|
||||
#endif
|
||||
|
||||
/* ub_timed_resolve.h */
|
|
@ -556,9 +556,10 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
completed_request->extensions, "dnssec_return_status") ||
|
||||
completed_request->return_dnssec_status == GETDNS_EXTENSION_TRUE;
|
||||
|
||||
if (completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
|
||||
if (completed_request->first_req &&
|
||||
(completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
|
||||
completed_request->first_req->request_class ==
|
||||
GETDNS_RRTYPE_AAAA) {
|
||||
GETDNS_RRTYPE_AAAA)) {
|
||||
just_addrs = getdns_list_create_with_context(
|
||||
completed_request->context);
|
||||
}
|
||||
|
@ -581,6 +582,9 @@ create_getdns_response(struct getdns_dns_req * completed_request)
|
|||
; netreq && r == GETDNS_RETURN_GOOD
|
||||
; netreq = netreq->next ) {
|
||||
|
||||
if (! netreq->result)
|
||||
continue;
|
||||
|
||||
nreplies++;
|
||||
if (netreq->secure)
|
||||
nsecure++;
|
||||
|
@ -771,16 +775,28 @@ validate_extensions(struct getdns_dict * extensions)
|
|||
getdns_return_t
|
||||
getdns_apply_network_result(getdns_network_req* netreq,
|
||||
struct ub_result* ub_res) {
|
||||
if (ub_res->answer_packet == NULL) {
|
||||
/* Likely to be because libunbound refused the request
|
||||
* so ub_res->answer_packet=NULL, ub_res->answer_len=0
|
||||
* So we need to create an answer packet.
|
||||
*/
|
||||
netreq->result = ldns_pkt_query_new(
|
||||
ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, netreq->owner->name),
|
||||
netreq->request_type,
|
||||
netreq->request_class,LDNS_QR|LDNS_RD|LDNS_RA);
|
||||
ldns_pkt_set_rcode(netreq->result, ub_res->rcode);
|
||||
|
||||
if (ub_res == NULL) { /* Timeout */
|
||||
netreq->result = NULL;
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
||||
} else if (ub_res->answer_packet == NULL) {
|
||||
if (ub_res->rcode == GETDNS_RCODE_SERVFAIL) {
|
||||
/* Likely to be caused by timeout from a synchronous
|
||||
* lookup. Don't forge a packet.
|
||||
*/
|
||||
netreq->result = NULL;
|
||||
} else {
|
||||
/* Likely to be because libunbound refused the request
|
||||
* so ub_res->answer_packet=NULL, ub_res->answer_len=0
|
||||
* So we need to create an answer packet.
|
||||
*/
|
||||
netreq->result = ldns_pkt_query_new(
|
||||
ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, netreq->owner->name),
|
||||
netreq->request_type,
|
||||
netreq->request_class,LDNS_QR|LDNS_RD|LDNS_RA);
|
||||
ldns_pkt_set_rcode(netreq->result, ub_res->rcode);
|
||||
}
|
||||
} else {
|
||||
ldns_status r =
|
||||
ldns_wire2pkt(&(netreq->result), ub_res->answer_packet, ub_res->answer_len);
|
||||
|
|
Loading…
Reference in New Issue