From c53c00ee2be3daf152966d27f975b03edcd4e0c1 Mon Sep 17 00:00:00 2001 From: Neel Goyal Date: Wed, 16 Oct 2013 14:45:43 -0400 Subject: [PATCH] Add recursive and stub support --- src/context.c | 137 ++++++++++++++++++++++++++++++++++++++++++-- src/context.h | 12 ++++ src/general.c | 2 + src/getdns/getdns.h | 1 + src/list.c | 5 ++ src/util-internal.c | 2 +- src/util-internal.h | 2 +- 7 files changed, 155 insertions(+), 6 deletions(-) diff --git a/src/context.c b/src/context.c index f9fad1ce..d80825dd 100644 --- a/src/context.c +++ b/src/context.c @@ -37,6 +37,7 @@ #include #include #include +#include /* 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, ©) != 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, ©) != 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 */ diff --git a/src/context.h b/src/context.h index d6991a0c..32c9bff7 100644 --- a/src/context.h +++ b/src/context.h @@ -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 diff --git a/src/general.c b/src/general.c index 7a6f3f55..5ef4a612 100644 --- a/src/general.c +++ b/src/general.c @@ -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 diff --git a/src/getdns/getdns.h b/src/getdns/getdns.h index 0152bbf9..deb86fa6 100644 --- a/src/getdns/getdns.h +++ b/src/getdns/getdns.h @@ -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" diff --git a/src/list.c b/src/list.c index 41b04e76..9140ecd3 100644 --- a/src/list.c +++ b/src/list.c @@ -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; diff --git a/src/util-internal.c b/src/util-internal.c index 746fa239..05be6ef4 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -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); diff --git a/src/util-internal.h b/src/util-internal.h index 740358f4..b5e826bf 100644 --- a/src/util-internal.h +++ b/src/util-internal.h @@ -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,