Add recursive and stub support

This commit is contained in:
Neel Goyal 2013-10-16 14:45:43 -04:00
parent d608d3b670
commit c53c00ee2b
7 changed files with 155 additions and 6 deletions

View File

@ -37,6 +37,7 @@
#include <event2/event.h>
#include <unbound.h>
#include <unbound-event.h>
#include <arpa/inet.h>
/* stuff to make it compile pedantically */
#define UNUSED_PARAM(x) ((void)(x))
@ -60,6 +61,34 @@ static struct getdns_list* create_default_root_servers() {
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) {
ldns_rdf_type rt = ldns_rdf_get_type(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 */
getdns_bindata data_bin = { sz, ldns_rdf_data(rdf) };
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_DATA, &data_bin);
add_ip_str(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 */
result->unbound_async = ub_ctx_create_event(result->event_base_sync);
result->async_set = 0;
result->resolution_type_set = 0;
result->resolution_type = GETDNS_CONTEXT_RECURSING;
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);
}
/*
* 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
*
@ -418,6 +458,7 @@ getdns_context_set_follow_redirects(
{
context->follow_redirects = value;
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_RECURSING);
dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS);
return GETDNS_RETURN_GOOD;
@ -434,15 +475,40 @@ getdns_context_set_dns_root_servers(
)
{
getdns_list *copy = NULL;
size_t count = 0;
if (addresses != NULL) {
if (getdns_list_copy(addresses, &copy) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
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);
context->dns_root_servers = addresses;
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_RECURSING);
dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS);
return GETDNS_RETURN_GOOD;
@ -492,6 +558,8 @@ getdns_context_set_suffix(
getdns_list_destroy(context->suffix);
context->suffix = value;
clear_resolution_type_set_flag(context, GETDNS_CONTEXT_STUB);
dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX);
return GETDNS_RETURN_GOOD;
@ -549,20 +617,37 @@ getdns_context_set_stub_resolution(
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;
}
getdns_list *copy = NULL;
if (getdns_list_copy(upstream_list, &copy) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
}
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;
}
}
if (r != GETDNS_RETURN_GOOD) {
getdns_list_destroy(upstream_list);
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
getdns_context_set_resolution_type(context, GETDNS_CONTEXT_STUB);
getdns_list_destroy(context->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);
return GETDNS_RETURN_GOOD;
@ -727,4 +812,48 @@ getdns_cancel_callback(
return GETDNS_RETURN_GOOD;
} /* 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 */

View File

@ -70,9 +70,21 @@ struct getdns_context_t {
the real work */
struct ub_ctx *unbound_sync;
struct ub_ctx *unbound_async;
/* whether an async event base was 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

View File

@ -137,6 +137,8 @@ getdns_general_ub(
req->userarg = userarg;
req->callback = callbackfn;
getdns_context_prepare_for_resolution(context);
/* TODO:
setup root or stub
handle immediate callback

View File

@ -248,6 +248,7 @@ struct event_base;
#define GETDNS_STR_IPV6 "IPv6"
#define GETDNS_STR_ADDRESS_TYPE "address_type"
#define GETDNS_STR_ADDRESS_DATA "address_data"
#define GETDNS_STR_ADDRESS_STRING "address_string"
#define GETDNS_STR_PORT "port"
#define GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6 "return_both_v4_and_v6"

View File

@ -214,6 +214,11 @@ getdns_list_copy(struct getdns_list *srclist, struct getdns_list **dstlist)
else
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
retval = GETDNS_RETURN_GENERIC_ERROR;

View File

@ -31,7 +31,7 @@
#include "util-internal.h"
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
char* value) {
const char* value) {
/* account for the null term */
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) value };
return getdns_dict_set_bindata(dict, name, &type_bin);

View File

@ -51,7 +51,7 @@ getdns_dict *create_getdns_response(ldns_pkt* pkt);
/* dict util */
/* set a string as bindata */
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 */
getdns_return_t getdns_dict_util_get_string(getdns_dict* dict, char* name,