diff --git a/src/context.c b/src/context.c index 6bd34347..83efc0a8 100644 --- a/src/context.c +++ b/src/context.c @@ -62,13 +62,22 @@ static struct getdns_list *create_from_ldns_list(struct getdns_context *, static getdns_return_t set_os_defaults(struct getdns_context *); static int transaction_id_cmp(const void *, const void *); static int timeout_cmp(const void *, const void *); -static void set_ub_string_opt(struct getdns_context *, char *, char *); -static void set_ub_number_opt(struct getdns_context *, char *, uint16_t); -static inline void clear_resolution_type_set_flag(struct getdns_context *, uint16_t); static void dispatch_updated(struct getdns_context *, uint16_t); static void cancel_dns_req(getdns_dns_req *); static void cancel_outstanding_requests(struct getdns_context*, int); +/* unbound helpers */ +static getdns_return_t rebuild_ub_ctx(struct getdns_context* context); +static void set_ub_string_opt(struct getdns_context *, char *, char *); +static void set_ub_number_opt(struct getdns_context *, char *, uint16_t); +static getdns_return_t set_ub_dns_transport(struct getdns_context*, getdns_transport_t); +static void set_ub_limit_outstanding_queries(struct getdns_context*, + uint16_t); +static void set_ub_dnssec_allowed_skew(struct getdns_context*, uint32_t); +static void set_ub_edns_maximum_udp_payload_size(struct getdns_context*, + uint16_t); + + /* Stuff to make it compile pedantically */ #define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code; @@ -408,8 +417,6 @@ getdns_context_create_with_extended_memory_functions( result->mf.mf.ext.realloc = realloc; result->mf.mf.ext.free = free; - result->unbound_ctx = ub_ctx_create(); - result->resolution_type_set = 0; result->outbound_requests = ldns_rbtree_create(transaction_id_cmp); @@ -444,22 +451,20 @@ getdns_context_create_with_extended_memory_functions( return GETDNS_RETURN_GENERIC_ERROR; } } + result->dnssec_allowed_skew = 0; + result->edns_maximum_udp_payload_size = 512; + result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP; + result->limit_outstanding_queries = 0; + result->has_ta = priv_getdns_parse_ta_file(NULL, NULL); + /* unbound context is initialized here */ + result->unbound_ctx = NULL; + if (GETDNS_RETURN_GOOD != rebuild_ub_ctx(result)) { + getdns_context_destroy(result); + return GETDNS_RETURN_GENERIC_ERROR; + } *context = result; - /* other opts */ - getdns_context_set_dnssec_allowed_skew(result, 0); - getdns_context_set_edns_maximum_udp_payload_size(result, 512); - getdns_context_set_dns_transport(result, - GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP); - - /* Set default trust anchor */ - result->has_ta = priv_getdns_parse_ta_file(NULL, NULL); - if (result->has_ta) { - (void) ub_ctx_add_ta_file( - result->unbound_ctx, TRUST_ANCHOR_FILE); - } - return GETDNS_RETURN_GOOD; } /* getdns_context_create_with_extended_memory_functions */ @@ -525,7 +530,7 @@ getdns_context_destroy(struct getdns_context *context) GETDNS_FREE(context->my_mf, context->fchg_hosts); } - cancel_outstanding_requests(context, 0); + cancel_outstanding_requests(context, 1); getdns_extension_detach_eventloop(context); getdns_list_destroy(context->dns_root_servers); @@ -534,7 +539,8 @@ getdns_context_destroy(struct getdns_context *context) getdns_list_destroy(context->upstream_list); /* destroy the ub context */ - ub_ctx_delete(context->unbound_ctx); + if (context->unbound_ctx) + ub_ctx_delete(context->unbound_ctx); ldns_rbtree_free(context->outbound_requests); ldns_rbtree_free(context->timeouts_by_id); @@ -565,7 +571,8 @@ getdns_context_set_context_update_callback(struct getdns_context *context, static void set_ub_string_opt(struct getdns_context *ctx, char *opt, char *value) { - ub_ctx_set_option(ctx->unbound_ctx, opt, value); + if (ctx->unbound_ctx) + ub_ctx_set_option(ctx->unbound_ctx, opt, value); } static void @@ -576,15 +583,32 @@ set_ub_number_opt(struct getdns_context *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(struct getdns_context *context, uint16_t type) -{ - if (context->resolution_type_set == type) { - context->resolution_type_set = 0; +static getdns_return_t +rebuild_ub_ctx(struct getdns_context* context) { + if (context->unbound_ctx != NULL) { + /* cancel all requests and delete */ + cancel_outstanding_requests(context, 1); + ub_ctx_delete(context->unbound_ctx); + context->unbound_ctx = NULL; } + /* setup */ + context->unbound_ctx = ub_ctx_create(); + if (!context->unbound_ctx) { + return GETDNS_RETURN_MEMORY_ERROR; + } + set_ub_dnssec_allowed_skew(context, + context->dnssec_allowed_skew); + set_ub_edns_maximum_udp_payload_size(context, + context->edns_maximum_udp_payload_size); + set_ub_dns_transport(context, + context->dns_transport); + + /* Set default trust anchor */ + if (context->has_ta) { + (void) ub_ctx_add_ta_file( + context->unbound_ctx, TRUST_ANCHOR_FILE); + } + return GETDNS_RETURN_GOOD; } /** @@ -610,8 +634,11 @@ getdns_context_set_resolution_type(struct getdns_context *context, if (value != GETDNS_RESOLUTION_STUB && value != GETDNS_RESOLUTION_RECURSING) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } + if (context->resolution_type_set != 0) { + /* already setup */ + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } context->resolution_type = value; - clear_resolution_type_set_flag(context, value); dispatch_updated(context, GETDNS_CONTEXT_CODE_RESOLUTION_TYPE); @@ -632,6 +659,9 @@ getdns_context_set_namespaces(struct getdns_context *context, if (namespace_count == 0 || namespaces == NULL) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } + if (context->resolution_type_set != 0) { + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } for(i=0; idns_transport) { + context->dns_transport = value; + dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT); + } return GETDNS_RETURN_GOOD; } /* getdns_context_set_dns_transport */ +static void +set_ub_limit_outstanding_queries(struct getdns_context* context, uint16_t value) { + /* num-queries-per-thread */ + set_ub_number_opt(context, "num-queries-per-thread", value); +} /* * getdns_context_set_limit_outstanding_queries * @@ -697,11 +742,12 @@ getdns_context_set_limit_outstanding_queries(struct getdns_context *context, uint16_t limit) { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - /* num-queries-per-thread */ - set_ub_number_opt(context, "num-queries-per-thread", limit); - - dispatch_updated(context, - GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES); + set_ub_limit_outstanding_queries(context, limit); + if (limit != context->limit_outstanding_queries) { + context->limit_outstanding_queries = limit; + dispatch_updated(context, + GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES); + } return GETDNS_RETURN_GOOD; } /* getdns_context_set_limit_outstanding_queries */ @@ -736,10 +782,12 @@ getdns_context_set_follow_redirects(struct getdns_context *context, { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); context->follow_redirects = value; + if (context->resolution_type_set != 0) { + /* already setup */ + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } - clear_resolution_type_set_flag(context, GETDNS_RESOLUTION_RECURSING); dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS); - return GETDNS_RETURN_GOOD; } /* getdns_context_set_follow_redirects */ @@ -754,6 +802,10 @@ getdns_context_set_dns_root_servers(struct getdns_context *context, struct getdns_list *copy = NULL; size_t count = 0; RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + if (context->resolution_type_set != 0) { + /* already setup */ + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } if (addresses != NULL) { if (getdns_list_copy(addresses, ©) != GETDNS_RETURN_GOOD) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; @@ -785,8 +837,6 @@ getdns_context_set_dns_root_servers(struct getdns_context *context, getdns_list_destroy(context->dns_root_servers); context->dns_root_servers = addresses; - clear_resolution_type_set_flag(context, GETDNS_RESOLUTION_RECURSING); - dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS); return GETDNS_RETURN_GOOD; @@ -824,6 +874,10 @@ getdns_context_set_suffix(struct getdns_context *context, struct getdns_list * v { struct getdns_list *copy = NULL; RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + if (context->resolution_type_set != 0) { + /* already setup */ + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } if (value != NULL) { if (getdns_list_copy(value, ©) != GETDNS_RETURN_GOOD) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; @@ -833,8 +887,6 @@ getdns_context_set_suffix(struct getdns_context *context, struct getdns_list * v getdns_list_destroy(context->suffix); context->suffix = value; - clear_resolution_type_set_flag(context, GETDNS_RESOLUTION_STUB); - dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX); return GETDNS_RETURN_GOOD; @@ -864,6 +916,11 @@ getdns_context_set_dnssec_trust_anchors(struct getdns_context *context, return GETDNS_RETURN_GOOD; } /* getdns_context_set_dnssec_trust_anchors */ +static void +set_ub_dnssec_allowed_skew(struct getdns_context* context, uint32_t value) { + set_ub_number_opt(context, "val-sig-skew-min", value); + set_ub_number_opt(context, "val-sig-skew-max", value); +} /* * getdns_context_set_dnssec_allowed_skew * @@ -873,9 +930,11 @@ getdns_context_set_dnssec_allowed_skew(struct getdns_context *context, uint32_t value) { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - set_ub_number_opt(context, "val-sig-skew-min", value); - set_ub_number_opt(context, "val-sig-skew-max", value); - dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW); + set_ub_dnssec_allowed_skew(context, value); + if (value != context->dnssec_allowed_skew) { + context->dnssec_allowed_skew = value; + dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW); + } return GETDNS_RETURN_GOOD; } /* getdns_context_set_dnssec_allowed_skew */ @@ -896,6 +955,10 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, if (count == 0 || r != GETDNS_RETURN_GOOD) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } + if (context->resolution_type_set != 0) { + /* already setup */ + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } struct getdns_list *copy = NULL; if (getdns_list_copy(upstream_list, ©) != GETDNS_RETURN_GOOD) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; @@ -919,14 +982,19 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, getdns_list_destroy(context->upstream_list); context->upstream_list = upstream_list; - clear_resolution_type_set_flag(context, GETDNS_RESOLUTION_STUB); - dispatch_updated(context, GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS); return GETDNS_RETURN_GOOD; } /* getdns_context_set_upstream_recursive_servers */ + +static void +set_ub_edns_maximum_udp_payload_size(struct getdns_context* context, + uint16_t value) { + /* max-udp-size */ + set_ub_number_opt(context, "max-udp-size", value); +} /* * getdns_context_set_edns_maximum_udp_payload_size * @@ -940,12 +1008,12 @@ getdns_context_set_edns_maximum_udp_payload_size(struct getdns_context *context, if (value < 512) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } - - /* max-udp-size */ - set_ub_number_opt(context, "max-udp-size", value); - - dispatch_updated(context, - GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE); + set_ub_edns_maximum_udp_payload_size(context, value); + if (value != context->edns_maximum_udp_payload_size) { + context->edns_maximum_udp_payload_size = value; + dispatch_updated(context, + GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE); + } return GETDNS_RETURN_GOOD; } /* getdns_context_set_edns_maximum_udp_payload_size */ @@ -1243,6 +1311,7 @@ getdns_context_prepare_for_resolution(struct getdns_context *context, * so we need to respect that order */ + if (! usenamespaces) { r = priv_getdns_ns_dns_setup(context); if (r == GETDNS_RETURN_GOOD) diff --git a/src/context.h b/src/context.h index e2b3f586..c335f5b4 100644 --- a/src/context.h +++ b/src/context.h @@ -78,10 +78,14 @@ struct getdns_context { struct getdns_list *suffix; struct getdns_list *dnssec_trust_anchors; struct getdns_list *upstream_list; + getdns_transport_t dns_transport; + uint16_t limit_outstanding_queries; + uint32_t dnssec_allowed_skew; uint8_t edns_extended_rcode; uint8_t edns_version; uint8_t edns_do_bit; + uint16_t edns_maximum_udp_payload_size; getdns_update_callback update_callback;