mirror of https://github.com/getdnsapi/getdns.git
Add recursive and stub support
This commit is contained in:
parent
d608d3b670
commit
c53c00ee2b
133
src/context.c
133
src/context.c
|
@ -37,6 +37,7 @@
|
||||||
#include <event2/event.h>
|
#include <event2/event.h>
|
||||||
#include <unbound.h>
|
#include <unbound.h>
|
||||||
#include <unbound-event.h>
|
#include <unbound-event.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
/* stuff to make it compile pedantically */
|
/* stuff to make it compile pedantically */
|
||||||
#define UNUSED_PARAM(x) ((void)(x))
|
#define UNUSED_PARAM(x) ((void)(x))
|
||||||
|
@ -60,6 +61,34 @@ static struct getdns_list* create_default_root_servers() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getdns_return_t add_ip_str(getdns_dict* ip) {
|
||||||
|
struct sockaddr_storage storage;
|
||||||
|
char buff[256];
|
||||||
|
getdns_return_t r = dict_to_sockaddr(ip, &storage);
|
||||||
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (storage.ss_family == AF_INET) {
|
||||||
|
struct sockaddr_in* addr = (struct sockaddr_in*) &storage;
|
||||||
|
const char* ipStr = inet_ntop(AF_INET, &(addr->sin_addr), buff, 256);
|
||||||
|
if (!ipStr) {
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
getdns_dict_util_set_string(ip, GETDNS_STR_ADDRESS_STRING, ipStr);
|
||||||
|
} else if (storage.ss_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6* addr = (struct sockaddr_in6*) &storage;
|
||||||
|
const char* ipStr = inet_ntop(AF_INET6, &(addr->sin6_addr), buff, 256);
|
||||||
|
if (!ipStr) {
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
getdns_dict_util_set_string(ip, GETDNS_STR_ADDRESS_STRING, ipStr);
|
||||||
|
} else {
|
||||||
|
/* unknown */
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
}
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
static struct getdns_dict* create_ipaddr_dict_from_rdf(ldns_rdf* rdf) {
|
static struct getdns_dict* create_ipaddr_dict_from_rdf(ldns_rdf* rdf) {
|
||||||
ldns_rdf_type rt = ldns_rdf_get_type(rdf);
|
ldns_rdf_type rt = ldns_rdf_get_type(rdf);
|
||||||
size_t sz = ldns_rdf_size(rdf);
|
size_t sz = ldns_rdf_size(rdf);
|
||||||
|
@ -73,6 +102,7 @@ static struct getdns_dict* create_ipaddr_dict_from_rdf(ldns_rdf* rdf) {
|
||||||
/* set data */
|
/* set data */
|
||||||
getdns_bindata data_bin = { sz, ldns_rdf_data(rdf) };
|
getdns_bindata data_bin = { sz, ldns_rdf_data(rdf) };
|
||||||
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_DATA, &data_bin);
|
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_DATA, &data_bin);
|
||||||
|
add_ip_str(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +194,7 @@ getdns_return_t getdns_context_create(
|
||||||
/* create the async one also so options are kept up to date */
|
/* create the async one also so options are kept up to date */
|
||||||
result->unbound_async = ub_ctx_create_event(result->event_base_sync);
|
result->unbound_async = ub_ctx_create_event(result->event_base_sync);
|
||||||
result->async_set = 0;
|
result->async_set = 0;
|
||||||
|
result->resolution_type_set = 0;
|
||||||
|
|
||||||
result->resolution_type = GETDNS_CONTEXT_RECURSING;
|
result->resolution_type = GETDNS_CONTEXT_RECURSING;
|
||||||
result->namespaces = create_default_namespaces();
|
result->namespaces = create_default_namespaces();
|
||||||
|
@ -261,6 +292,15 @@ static void set_ub_number_opt(getdns_context_t ctx, char* opt, uint16_t value) {
|
||||||
set_ub_string_opt(ctx, opt, buffer);
|
set_ub_string_opt(ctx, opt, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the resolution type set flag if needed
|
||||||
|
*/
|
||||||
|
static inline void clear_resolution_type_set_flag(getdns_context_t context, uint16_t type) {
|
||||||
|
if (context->resolution_type_set == type) {
|
||||||
|
context->resolution_type_set = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getdns_context_set_context_update
|
* getdns_context_set_context_update
|
||||||
*
|
*
|
||||||
|
@ -418,6 +458,7 @@ getdns_context_set_follow_redirects(
|
||||||
{
|
{
|
||||||
context->follow_redirects = value;
|
context->follow_redirects = value;
|
||||||
|
|
||||||
|
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_RECURSING);
|
||||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS);
|
dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS);
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
@ -434,15 +475,40 @@ getdns_context_set_dns_root_servers(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
getdns_list *copy = NULL;
|
getdns_list *copy = NULL;
|
||||||
|
size_t count = 0;
|
||||||
if (addresses != NULL) {
|
if (addresses != NULL) {
|
||||||
if (getdns_list_copy(addresses, ©) != GETDNS_RETURN_GOOD) {
|
if (getdns_list_copy(addresses, ©) != GETDNS_RETURN_GOOD) {
|
||||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
}
|
}
|
||||||
addresses = copy;
|
addresses = copy;
|
||||||
|
getdns_list_get_length(addresses, &count);
|
||||||
|
if (count == 0) {
|
||||||
|
getdns_list_destroy(addresses);
|
||||||
|
addresses = NULL;
|
||||||
|
} else {
|
||||||
|
size_t i = 0;
|
||||||
|
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||||
|
/* validate and add ip str */
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
getdns_dict* dict = NULL;
|
||||||
|
getdns_list_get_dict(addresses, i, &dict);
|
||||||
|
r = add_ip_str(dict);
|
||||||
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
getdns_list_destroy(addresses);
|
||||||
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getdns_list_destroy(context->dns_root_servers);
|
getdns_list_destroy(context->dns_root_servers);
|
||||||
context->dns_root_servers = addresses;
|
context->dns_root_servers = addresses;
|
||||||
|
|
||||||
|
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_RECURSING);
|
||||||
|
|
||||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS);
|
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS);
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
@ -492,6 +558,8 @@ getdns_context_set_suffix(
|
||||||
getdns_list_destroy(context->suffix);
|
getdns_list_destroy(context->suffix);
|
||||||
context->suffix = value;
|
context->suffix = value;
|
||||||
|
|
||||||
|
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_STUB);
|
||||||
|
|
||||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX);
|
dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX);
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
@ -549,7 +617,10 @@ getdns_context_set_stub_resolution(
|
||||||
struct getdns_list *upstream_list
|
struct getdns_list *upstream_list
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (upstream_list == NULL) {
|
size_t count = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
getdns_return_t r = getdns_list_get_length(upstream_list, &count);
|
||||||
|
if (count == 0 || r != GETDNS_RETURN_GOOD) {
|
||||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
}
|
}
|
||||||
getdns_list *copy = NULL;
|
getdns_list *copy = NULL;
|
||||||
|
@ -557,12 +628,26 @@ getdns_context_set_stub_resolution(
|
||||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
}
|
}
|
||||||
upstream_list = copy;
|
upstream_list = copy;
|
||||||
|
/* validate and add ip str */
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
getdns_dict* dict = NULL;
|
||||||
|
getdns_list_get_dict(upstream_list, i, &dict);
|
||||||
|
r = add_ip_str(dict);
|
||||||
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getdns_context_set_resolution_type(context, GETDNS_CONTEXT_STUB);
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
getdns_list_destroy(upstream_list);
|
||||||
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
getdns_list_destroy(context->upstream_list);
|
getdns_list_destroy(context->upstream_list);
|
||||||
context->upstream_list = upstream_list;
|
context->upstream_list = upstream_list;
|
||||||
|
|
||||||
|
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_STUB);
|
||||||
|
|
||||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
|
dispatch_updated(context, GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
@ -727,4 +812,48 @@ getdns_cancel_callback(
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
} /* getdns_cancel_callback */
|
} /* getdns_cancel_callback */
|
||||||
|
|
||||||
|
static void ub_setup_stub(struct ub_ctx* ctx, getdns_list* upstreams, size_t count) {
|
||||||
|
size_t i;
|
||||||
|
/* reset forwarding servers */
|
||||||
|
ub_ctx_set_fwd(ctx, NULL);
|
||||||
|
for (i = 0 ; i < count; ++i) {
|
||||||
|
getdns_dict* dict = NULL;
|
||||||
|
char* ip_str = NULL;
|
||||||
|
getdns_list_get_dict(upstreams, i, &dict);
|
||||||
|
getdns_dict_util_get_string(dict, GETDNS_STR_ADDRESS_STRING, &ip_str);
|
||||||
|
ub_ctx_set_fwd(ctx, ip_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getdns_return_t getdns_context_prepare_for_resolution(getdns_context_t context) {
|
||||||
|
if (context->resolution_type_set == context->resolution_type) {
|
||||||
|
/* already set and no config changes have caused this to be
|
||||||
|
* bad.
|
||||||
|
*/
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
if (context->resolution_type == GETDNS_CONTEXT_STUB) {
|
||||||
|
size_t upstream_len = 0;
|
||||||
|
getdns_return_t r = getdns_list_get_length(context->upstream_list, &upstream_len);
|
||||||
|
if (r != GETDNS_RETURN_GOOD || upstream_len == 0) {
|
||||||
|
return GETDNS_RETURN_BAD_CONTEXT;
|
||||||
|
}
|
||||||
|
/* set upstreams */
|
||||||
|
ub_setup_stub(context->unbound_async, context->upstream_list, upstream_len);
|
||||||
|
ub_setup_stub(context->unbound_sync, context->upstream_list, upstream_len);
|
||||||
|
|
||||||
|
} else if (context->resolution_type == GETDNS_CONTEXT_RECURSING) {
|
||||||
|
/* set recursive */
|
||||||
|
/* TODO: use the root servers via root hints file */
|
||||||
|
ub_ctx_set_fwd(context->unbound_async, NULL);
|
||||||
|
ub_ctx_set_fwd(context->unbound_sync, NULL);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* bogus? */
|
||||||
|
return GETDNS_RETURN_BAD_CONTEXT;
|
||||||
|
}
|
||||||
|
context->resolution_type_set = context->resolution_type;
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
/* getdns_context.c */
|
/* getdns_context.c */
|
||||||
|
|
|
@ -70,9 +70,21 @@ struct getdns_context_t {
|
||||||
the real work */
|
the real work */
|
||||||
struct ub_ctx *unbound_sync;
|
struct ub_ctx *unbound_sync;
|
||||||
struct ub_ctx *unbound_async;
|
struct ub_ctx *unbound_async;
|
||||||
|
/* whether an async event base was set */
|
||||||
uint8_t async_set;
|
uint8_t async_set;
|
||||||
|
/* which resolution type the contexts are configured for
|
||||||
|
* 0 means nothing set
|
||||||
|
*/
|
||||||
|
uint8_t resolution_type_set;
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
/** internal functions **/
|
||||||
|
/**
|
||||||
|
* Sets up the unbound contexts with stub or recursive behavior
|
||||||
|
* if needed.
|
||||||
|
*/
|
||||||
|
getdns_return_t getdns_context_prepare_for_resolution(getdns_context_t context);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,8 @@ getdns_general_ub(
|
||||||
req->userarg = userarg;
|
req->userarg = userarg;
|
||||||
req->callback = callbackfn;
|
req->callback = callbackfn;
|
||||||
|
|
||||||
|
getdns_context_prepare_for_resolution(context);
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
setup root or stub
|
setup root or stub
|
||||||
handle immediate callback
|
handle immediate callback
|
||||||
|
|
|
@ -248,6 +248,7 @@ struct event_base;
|
||||||
#define GETDNS_STR_IPV6 "IPv6"
|
#define GETDNS_STR_IPV6 "IPv6"
|
||||||
#define GETDNS_STR_ADDRESS_TYPE "address_type"
|
#define GETDNS_STR_ADDRESS_TYPE "address_type"
|
||||||
#define GETDNS_STR_ADDRESS_DATA "address_data"
|
#define GETDNS_STR_ADDRESS_DATA "address_data"
|
||||||
|
#define GETDNS_STR_ADDRESS_STRING "address_string"
|
||||||
#define GETDNS_STR_PORT "port"
|
#define GETDNS_STR_PORT "port"
|
||||||
#define GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6 "return_both_v4_and_v6"
|
#define GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6 "return_both_v4_and_v6"
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,11 @@ getdns_list_copy(struct getdns_list *srclist, struct getdns_list **dstlist)
|
||||||
else
|
else
|
||||||
retval = GETDNS_RETURN_GENERIC_ERROR;
|
retval = GETDNS_RETURN_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
else if (srclist->items[i].dtype == t_dict)
|
||||||
|
{
|
||||||
|
retval = getdns_dict_copy(srclist->items[index].data.dict,
|
||||||
|
&((*dstlist)->items[i].data.dict));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
retval = GETDNS_RETURN_GENERIC_ERROR;
|
retval = GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
|
|
||||||
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
|
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
|
||||||
char* value) {
|
const char* value) {
|
||||||
/* account for the null term */
|
/* account for the null term */
|
||||||
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) value };
|
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) value };
|
||||||
return getdns_dict_set_bindata(dict, name, &type_bin);
|
return getdns_dict_set_bindata(dict, name, &type_bin);
|
||||||
|
|
|
@ -51,7 +51,7 @@ getdns_dict *create_getdns_response(ldns_pkt* pkt);
|
||||||
/* dict util */
|
/* dict util */
|
||||||
/* set a string as bindata */
|
/* set a string as bindata */
|
||||||
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
|
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
|
||||||
char* value);
|
const char* value);
|
||||||
|
|
||||||
/* get a string from a dict. result is valid as long as dict is valid */
|
/* get a string from a dict. result is valid as long as dict is valid */
|
||||||
getdns_return_t getdns_dict_util_get_string(getdns_dict* dict, char* name,
|
getdns_return_t getdns_dict_util_get_string(getdns_dict* dict, char* name,
|
||||||
|
|
Loading…
Reference in New Issue