diff --git a/ChangeLog b/ChangeLog index d6a2633c..12f94aae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ * 2015-06-??: Version 0.?.? * Unit test for spurious execute bits. Thanks Paul Wouters. + * Added new transport list options in API. The option is now an ordered list of + GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP, GETDNS_TRANSPORT_TLS, + GETDNS_TRANSPORT_STARTTLS. + * Added new context setting for idle_timeout * 2015-05-21: Version 0.2.0 * Fix libversion numbering: Thanks Daniel Kahn Gillmor diff --git a/spec/index.html b/spec/index.html index 5b25f8e1..b6ead3e1 100644 --- a/spec/index.html +++ b/spec/index.html @@ -2198,6 +2198,20 @@ The value is GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN>, or GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN> +
+getdns_return_t +getdns_context_set_dns_transport_list( + size_t transport_list, + getdns_transport_list_t *transports +);
+

The transports array contains an ordered list +of transports that will be used for DNS lookups. The +values are +GETDNS_TRANSPORT_UDP, +GETDNS_TRANSPORT_TCP, +GETDNS_TRANSPORT_TLS>, or +GETDNS_TRANSPORT_STARTTLS> +

getdns_return_t getdns_context_set_limit_outstanding_queries( @@ -2219,6 +2233,16 @@ getdns_context_set_timeout(

Specifies number of milliseconds the API will wait for request to return. The default is not specified.

+
+getdns_return_t +getdns_context_set_idle_timeout( + getdns_context *context, + uint64_t timeout +);
+

Specifies number of milliseconds the API will leave an idle TCP, TLS or STARTTLS +connection open for (idle means no outstanding responses and no pending queries). +The default is 0.

+

8.4 Context for Recursive Resolvers

@@ -2430,7 +2454,8 @@ The response dicts inherit the custom memory management functions and the value

Change related to getdns_context_set_memory_functions

GETDNS_CONTEXT_CODE_TIMEOUT

Change related to getdns_context_set_timeout

- +

GETDNS_CONTEXT_CODE_IDLE_TIMEOUT

+

Change related to getdns_context_set_idle_timeout

8.11 Getting API information and current Contexts

An application might want to see information about the API itself and inspect the current context. diff --git a/src/const-info.c b/src/const-info.c index 026d5da8..ecad9e5b 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -63,6 +63,7 @@ static struct const_info consts_info[] = { { 614, "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT }, { 615, "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT }, { 616, "GETDNS_CONTEXT_CODE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_TEXT }, + { 617, "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", GETDNS_CONTEXT_CODE_TIMEOUT_IDLE_TEXT }, { 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT }, { 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT }, { 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT }, @@ -79,6 +80,11 @@ static struct const_info consts_info[] = { { 1100, "GETDNS_BAD_DNS_CNAME_IN_TARGET", GETDNS_BAD_DNS_CNAME_IN_TARGET_TEXT }, { 1101, "GETDNS_BAD_DNS_ALL_NUMERIC_LABEL", GETDNS_BAD_DNS_ALL_NUMERIC_LABEL_TEXT }, { 1102, "GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE_TEXT }, + { 1200, "GETDNS_TRANSPORT_UDP", GETDNS_TRANSPORT_UDP_TEXT }, + { 1201, "GETDNS_TRANSPORT_TCP", GETDNS_TRANSPORT_TCP_TEXT }, + { 1202, "GETDNS_TRANSPORT_TLS", GETDNS_TRANSPORT_TLS_TEXT }, + { 1203, "GETDNS_TRANSPORT_STARTTLS", GETDNS_TRANSPORT_STARTTLS_TEXT }, + }; static int const_info_cmp(const void *a, const void *b) diff --git a/src/context.c b/src/context.c index 3558e13d..f0a3631a 100644 --- a/src/context.c +++ b/src/context.c @@ -102,7 +102,7 @@ static void cancel_outstanding_requests(struct getdns_context*, int); 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 getdns_return_t set_ub_dns_transport(struct getdns_context*); static void set_ub_limit_outstanding_queries(struct getdns_context*, uint16_t); static void set_ub_dnssec_allowed_skew(struct getdns_context*, uint32_t); @@ -139,6 +139,44 @@ create_default_namespaces(struct getdns_context *context) return GETDNS_RETURN_GOOD; } +static getdns_transport_list_t * +get_dns_transport_list(getdns_context *context, int *count) +{ + if (context == NULL) + return NULL; + + /* Count how many we have*/ + for (*count = 0; *count < GETDNS_BASE_TRANSPORT_MAX; (*count)++) { + if (context->dns_base_transports[*count] == GETDNS_BASE_TRANSPORT_NONE) + break; + } + + // use normal malloc here so users can do normal free + getdns_transport_list_t * transports = malloc(*count * sizeof(getdns_transport_list_t)); + + if(transports == NULL) + return NULL; + for (int i = 0; i < (int)*count; i++) { + switch(context->dns_base_transports[i]) { + case GETDNS_BASE_TRANSPORT_UDP: + transports[i] = GETDNS_TRANSPORT_UDP; + break; + case GETDNS_BASE_TRANSPORT_TCP: + transports[i] = GETDNS_TRANSPORT_TCP; + break; + case GETDNS_BASE_TRANSPORT_TLS: + transports[i] = GETDNS_TRANSPORT_TLS; + break; + case GETDNS_BASE_TRANSPORT_STARTTLS: + transports[i] = GETDNS_TRANSPORT_STARTTLS; + break; + default: + break; + } + } + return transports; +} + static inline void canonicalize_dname(uint8_t *dname) { uint8_t *next_label; @@ -809,6 +847,7 @@ getdns_context_create_with_extended_memory_functions( goto error; result->timeout = 5000; + result->idle_timeout = 0; result->follow_redirects = GETDNS_REDIRECTS_FOLLOW; result->dns_root_servers = create_default_root_servers(); result->append_name = GETDNS_APPEND_NAME_ALWAYS; @@ -834,8 +873,8 @@ getdns_context_create_with_extended_memory_functions( result->dnssec_allowed_skew = 0; result->edns_maximum_udp_payload_size = -1; - result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP; - priv_set_base_dns_transports(result->dns_base_transports, result->dns_transport); + result->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP; + result->dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; result->limit_outstanding_queries = 0; result->has_ta = priv_getdns_parse_ta_file(NULL, NULL); result->return_dnssec_status = GETDNS_EXTENSION_FALSE; @@ -1065,8 +1104,7 @@ rebuild_ub_ctx(struct getdns_context* 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_ub_dns_transport(context); /* Set default trust anchor */ if (context->has_ta) { @@ -1159,75 +1197,71 @@ getdns_context_set_namespaces(struct getdns_context *context, return GETDNS_RETURN_GOOD; } /* getdns_context_set_namespaces */ -/* TODO[TLS]: Modify further when API changed.*/ -getdns_return_t -priv_set_base_dns_transports(getdns_base_transport_t *dns_base_transports, - getdns_transport_t value) +static getdns_return_t +getdns_set_base_dns_transports(struct getdns_context *context, + size_t transport_count, getdns_transport_list_t *transports) { - for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++) - dns_base_transports[i] = GETDNS_BASE_TRANSPORT_NONE; - switch (value) { - case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP; - dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP_SINGLE; - break; - case GETDNS_TRANSPORT_UDP_ONLY: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP; - break; - case GETDNS_TRANSPORT_TCP_ONLY: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TCP_SINGLE; - break; - case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TCP; - break; - case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS; - break; - case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS; - dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; - break; - case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: - dns_base_transports[0] = GETDNS_BASE_TRANSPORT_STARTTLS; - dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; - break; + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++) + context->dns_base_transports[i] = GETDNS_BASE_TRANSPORT_NONE; - default: - return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; - } - return GETDNS_RETURN_GOOD; + if ((int)transport_count == 0 || transports == NULL || + (int)transport_count > GETDNS_BASE_TRANSPORT_MAX) { + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } + + for (size_t j = 0; j < transport_count; j++) { + switch(transports[j]) { + case GETDNS_TRANSPORT_UDP: + context->dns_base_transports[j] = GETDNS_BASE_TRANSPORT_UDP; + break; + case GETDNS_TRANSPORT_TCP: + context->dns_base_transports[j] = GETDNS_BASE_TRANSPORT_TCP; + break; + case GETDNS_TRANSPORT_TLS: + context->dns_base_transports[j] = GETDNS_BASE_TRANSPORT_TLS; + break; + case GETDNS_TRANSPORT_STARTTLS: + context->dns_base_transports[j] = GETDNS_BASE_TRANSPORT_STARTTLS; + break; + default: + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } + } + return GETDNS_RETURN_GOOD; } static getdns_return_t -set_ub_dns_transport(struct getdns_context* context, - getdns_transport_t value) { - switch (value) { - case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP: +set_ub_dns_transport(struct getdns_context* context) { + /* These mappings are not exact because Unbound is configured differently, + so just map as close as possible from the first 1 or 2 transports. */ + switch (context->dns_base_transports[0]) { + case GETDNS_BASE_TRANSPORT_UDP: set_ub_string_opt(context, "do-udp:", "yes"); - set_ub_string_opt(context, "do-tcp:", "yes"); + if (context->dns_base_transports[1] == GETDNS_BASE_TRANSPORT_TCP) + set_ub_string_opt(context, "do-tcp:", "yes"); + else + set_ub_string_opt(context, "do-tcp:", "no"); break; - case GETDNS_TRANSPORT_UDP_ONLY: - set_ub_string_opt(context, "do-udp:", "yes"); - set_ub_string_opt(context, "do-tcp:", "no"); - break; - case GETDNS_TRANSPORT_TCP_ONLY: - /* Note: no pipelining available directly in unbound.*/ - case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN: + case GETDNS_BASE_TRANSPORT_TLS: + /* Note: If TLS is used in recursive mode this will try TLS on port + * 53... So this is prohibited when preparing for resolution.*/ + if (context->dns_base_transports[1] == GETDNS_BASE_TRANSPORT_NONE) { + set_ub_string_opt(context, "ssl-upstream:", "yes"); + set_ub_string_opt(context, "do-udp:", "no"); + set_ub_string_opt(context, "do-tcp:", "yes"); + break; + } + if (context->dns_base_transports[1] != GETDNS_BASE_TRANSPORT_TCP) + break; + /* Fallthrough */ + case GETDNS_BASE_TRANSPORT_STARTTLS: + case GETDNS_BASE_TRANSPORT_TCP: + /* Note: no STARTTLS or fallback to TCP available directly in unbound, so we just + * use TCP for now to make sure the messages are sent. */ set_ub_string_opt(context, "do-udp:", "no"); set_ub_string_opt(context, "do-tcp:", "yes"); break; - case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN: - /* Note: If TLS is used in recursive mode this will try TLS on port - * 53... So this is prohibited when preparing for resolution.*/ - set_ub_string_opt(context, "ssl-upstream:", "yes"); - /* Fall through */ - case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: - case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: - /* Note: no fallback to TCP available directly in unbound, so we just - * use TCP for now to make sure the messages are sent. */ - set_ub_string_opt(context, "do-udp:", "no"); - set_ub_string_opt(context, "do-tcp:", "yes"); - break; default: return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } @@ -1242,25 +1276,71 @@ getdns_return_t getdns_context_set_dns_transport(struct getdns_context *context, getdns_transport_t value) { - /* TODO[TLS]: Modify further when API changed.*/ RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + + for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++) + context->dns_base_transports[i] = GETDNS_BASE_TRANSPORT_NONE; + + switch (value) { + case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP; + context->dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; + break; + case GETDNS_TRANSPORT_UDP_ONLY: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP; + break; + case GETDNS_TRANSPORT_TCP_ONLY: + case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TCP; + break; + case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS; + break; + case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS; + context->dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; + break; + case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: + context->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_STARTTLS; + context->dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP; + break; + default: + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } /* Note that the call below does not have any effect in unbound after the * ctx is finalised so for recursive mode or stub + dnssec only the first * transport specified on the first query is used. * However the method returns success as otherwise the transport could not * be reset for stub mode. * Also, not all transport options supported in libunbound yet */ - if (set_ub_dns_transport(context, value) != GETDNS_RETURN_GOOD) { + if (set_ub_dns_transport(context) != GETDNS_RETURN_GOOD) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } - if (value != context->dns_transport) { - /*TODO[TLS]: remove this line when API updated*/ - context->dns_transport = value; - if (priv_set_base_dns_transports(context->dns_base_transports, value) != GETDNS_RETURN_GOOD) - return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; - dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT); - } + dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT); + return GETDNS_RETURN_GOOD; +} +/* + * getdns_context_set_dns_transport + * + */ +getdns_return_t +getdns_context_set_dns_transport_list(getdns_context *context, + size_t transport_count, getdns_transport_list_t *transports) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + if (getdns_set_base_dns_transports(context, transport_count, transports) != GETDNS_RETURN_GOOD) + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + /* Note that the call below does not have any effect in unbound after the + * ctx is finalised so for recursive mode or stub + dnssec only the first + * transport specified on the first query is used. + * However the method returns success as otherwise the transport could not + * be reset for stub mode. + * Also, not all transport options supported in libunbound yet */ + if (set_ub_dns_transport(context) != GETDNS_RETURN_GOOD) { + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } + dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT); return GETDNS_RETURN_GOOD; } /* getdns_context_set_dns_transport */ @@ -1308,6 +1388,27 @@ getdns_context_set_timeout(struct getdns_context *context, uint64_t timeout) return GETDNS_RETURN_GOOD; } /* getdns_context_set_timeout */ +/* + * getdns_context_set_idle_timeout + * + */ +getdns_return_t +getdns_context_set_idle_timeout(struct getdns_context *context, uint64_t timeout) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + + if (timeout == 0) { + return GETDNS_RETURN_INVALID_PARAMETER; + } + + context->idle_timeout = timeout; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_IDLE_TIMEOUT); + + return GETDNS_RETURN_GOOD; +} /* getdns_context_set_timeout */ + + /* * getdns_context_set_follow_redirects * @@ -1568,7 +1669,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, if (base_transport != GETDNS_BASE_TRANSPORT_TLS) (void) getdns_dict_get_int(dict, "port", &port); else - (void) getdns_dict_get_int(dict, "tls-port", &port); + (void) getdns_dict_get_int(dict, "tls_port", &port); (void) snprintf(portstr, 1024, "%d", (int)port); if (getaddrinfo(addrstr, portstr, &hints, &ai)) @@ -1918,17 +2019,14 @@ getdns_context_prepare_for_resolution(struct getdns_context *context, /* Create client context, use TLS v1.2 only for now */ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); #endif - /* TODO[TLS]: Check if TLS is the only option in the list*/ - // if(!context->tls_ctx && context->dns_transport == - // GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) { - // return GETDNS_RETURN_BAD_CONTEXT; - // } + if(context->tls_ctx == NULL) + return GETDNS_RETURN_BAD_CONTEXT; } } /* Block use of TLS ONLY in recursive mode as it won't work */ - /* TODO[TLS]: Check if TLS is the only option in the list*/ if (context->resolution_type == GETDNS_RESOLUTION_RECURSING && - context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) + context->dns_base_transports[0] == GETDNS_BASE_TRANSPORT_TLS && + context->dns_base_transports[1] == GETDNS_BASE_TRANSPORT_NONE) return GETDNS_RETURN_BAD_CONTEXT; if (context->resolution_type_set == context->resolution_type) @@ -2192,8 +2290,7 @@ priv_get_context_settings(getdns_context* context) { return NULL; } /* int fields */ - r = getdns_dict_set_int(result, "dns_transport", context->dns_transport); - r |= getdns_dict_set_int(result, "timeout", context->timeout); + r = getdns_dict_set_int(result, "timeout", context->timeout); r |= getdns_dict_set_int(result, "limit_outstanding_queries", context->limit_outstanding_queries); r |= getdns_dict_set_int(result, "dnssec_allowed_skew", context->dnssec_allowed_skew); r |= getdns_dict_set_int(result, "follow_redirects", context->follow_redirects); @@ -2224,6 +2321,18 @@ priv_get_context_settings(getdns_context* context) { upstreams); getdns_list_destroy(upstreams); } + /* create a transport list */ + getdns_list* transports = getdns_list_create_with_context(context); + if (transports) { + int transport_count; + getdns_transport_list_t *transport_list = + get_dns_transport_list(context, &transport_count); + for (int i = 0; i < transport_count; i++) { + r |= getdns_list_set_int(transports, i, transport_list[i]); + } + r |= getdns_dict_set_list(result, "dns_transport_list", transports); + free(transport_list); + } if (context->namespace_count > 0) { /* create a namespace list */ size_t i; @@ -2416,10 +2525,60 @@ getdns_context_get_dns_transport(getdns_context *context, getdns_transport_t* value) { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); - *value = context->dns_transport; + int count; + getdns_transport_list_t *transport_list = + get_dns_transport_list(context, &count); + if (!count) + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + + /* Best effort mapping for backwards compatibility*/ + if (transport_list[0] == GETDNS_TRANSPORT_UDP) { + if (count == 1) + *value = GETDNS_TRANSPORT_UDP_ONLY; + else if (count == 2 && transport_list[1] == GETDNS_TRANSPORT_TCP) + *value = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP; + else + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + if (transport_list[0] == GETDNS_TRANSPORT_TCP) { + if (count == 1) + *value = GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN; + } + if (transport_list[0] == GETDNS_TRANSPORT_TLS) { + if (count == 1) + *value = GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN; + else if (count == 2 && transport_list[1] == GETDNS_TRANSPORT_TCP) + *value = GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN; + else + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + if (transport_list[0] == GETDNS_TRANSPORT_STARTTLS) { + if (count == 2 && transport_list[1] == GETDNS_TRANSPORT_TCP) + *value = GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN; + else + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_dns_transport_list(getdns_context *context, + size_t* transport_count, getdns_transport_list_t **transports) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(transport_count, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(transports, GETDNS_RETURN_INVALID_PARAMETER); + + int count; + getdns_transport_list_t *transport_list = + get_dns_transport_list(context, &count); + *transport_count = count; + if (!transport_count) { + *transports = NULL; + return GETDNS_RETURN_GOOD; + } + *transports = transport_list; + return GETDNS_RETURN_GOOD; +} getdns_return_t getdns_context_get_limit_outstanding_queries(getdns_context *context, @@ -2438,6 +2597,14 @@ getdns_context_get_timeout(getdns_context *context, uint64_t* value) { return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_idle_timeout(getdns_context *context, uint64_t* value) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); + *value = context->idle_timeout; + return GETDNS_RETURN_GOOD; +} + getdns_return_t getdns_context_get_follow_redirects(getdns_context *context, getdns_redirects_t* value) { diff --git a/src/context.h b/src/context.h index 3ad6b342..040f18d3 100644 --- a/src/context.h +++ b/src/context.h @@ -131,13 +131,13 @@ struct getdns_context { getdns_namespace_t *namespaces; int namespace_count; uint64_t timeout; + uint64_t idle_timeout; getdns_redirects_t follow_redirects; struct getdns_list *dns_root_servers; getdns_append_name_t append_name; struct getdns_list *suffix; struct getdns_list *dnssec_trust_anchors; getdns_upstreams *upstreams; - getdns_transport_t dns_transport; getdns_base_transport_t dns_base_transports[GETDNS_BASE_TRANSPORT_MAX]; uint16_t limit_outstanding_queries; uint32_t dnssec_allowed_skew; @@ -234,9 +234,6 @@ int filechg_check(struct getdns_context *context, struct filechg *fchg); void priv_getdns_context_ub_read_cb(void *userarg); -getdns_return_t priv_set_base_dns_transports(getdns_base_transport_t *, - getdns_transport_t); - void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams); #endif /* _GETDNS_CONTEXT_H_ */ diff --git a/src/dict.c b/src/dict.c index 76b07939..11723899 100644 --- a/src/dict.c +++ b/src/dict.c @@ -608,14 +608,14 @@ static const char *unknown_str_l[] = {" ", " null", "null"}; * @param buf buffer to write to * @param indent number of spaces to append after newline * @param list the to list print - * @param for_namespaces The list is a list of namespace literals. + * @param for_literals The list is a list of literals. * Show the literal instead of the value. * @return on success the number of written characters * if an output error is encountered, a negative value */ static int getdns_pp_list(gldns_buffer *buf, size_t indent, const getdns_list *list, - int for_namespaces, int json) + int for_literals, int json) { size_t i, length, p = gldns_buffer_position(buf); getdns_data_type dtype; @@ -651,7 +651,7 @@ getdns_pp_list(gldns_buffer *buf, size_t indent, const getdns_list *list, if (getdns_list_get_int(list, i, &int_item)) return -1; - if (!json && for_namespaces && + if (!json && for_literals && (strval = priv_getdns_get_const_info(int_item)->name)) { if (gldns_buffer_printf(buf, "%s", strval) < 0) @@ -829,7 +829,6 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent, strcmp(item->node.key, "dnssec_status") == 0 || strcmp(item->node.key, "status") == 0 || strcmp(item->node.key, "append_name") == 0 || - strcmp(item->node.key, "dns_transport") == 0 || strcmp(item->node.key, "follow_redirects") == 0 || strcmp(item->node.key, "resolution_type") == 0) && (strval = @@ -893,7 +892,8 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent, getdns_indent(indent)) < 0) return -1; if (getdns_pp_list(buf, indent, item->data.list, - (strcmp(item->node.key, "namespaces") == 0), + (strcmp(item->node.key, "namespaces") == 0 || + strcmp(item->node.key, "dns_transport_list") == 0), json) < 0) return -1; break; diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index a2d6ea49..3f133a4f 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -180,6 +180,26 @@ typedef enum getdns_transport_t { #define GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" #define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" #define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()" +/** @} +*/ + + +/* Base transports for use in transport list */ +typedef enum getdns_transport_list_t { + GETDNS_TRANSPORT_UDP = 1200, + GETDNS_TRANSPORT_TCP = 1201, + GETDNS_TRANSPORT_TLS = 1202, + GETDNS_TRANSPORT_STARTTLS = 1203 +} getdns_transport_list_t; + +/** + * \defgroup Base transport texts + * @{ + */ +#define GETDNS_TRANSPORT_UDP_TEXT "See getdns_context_set_dns_transport()" +#define GETDNS_TRANSPORT_TCP_TEXT "See getdns_context_set_dns_transport()" +#define GETDNS_TRANSPORT_TLS_TEXT "See getdns_context_set_dns_transport()" +#define GETDNS_TRANSPORT_STARTTLS_TEXT "See getdns_context_set_dns_transport()" /** @} */ @@ -222,7 +242,8 @@ typedef enum getdns_context_code_t { GETDNS_CONTEXT_CODE_EDNS_DO_BIT = 613, GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW = 614, GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS = 615, - GETDNS_CONTEXT_CODE_TIMEOUT = 616 + GETDNS_CONTEXT_CODE_TIMEOUT = 616, + GETDNS_CONTEXT_CODE_IDLE_TIMEOUT = 617 } getdns_context_code_t; /** @@ -246,6 +267,7 @@ typedef enum getdns_context_code_t { #define GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW_TEXT "Change related to getdns_context_set_dnssec_allowed_skew" #define GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT "Change related to getdns_context_set_memory_functions" #define GETDNS_CONTEXT_CODE_TIMEOUT_TEXT "Change related to getdns_context_set_timeout" +#define GETDNS_CONTEXT_CODE_TIMEOUT_IDLE_TEXT "Change related to getdns_context_set_idle_timeout" /** @} */ @@ -942,6 +964,10 @@ getdns_return_t getdns_context_set_dns_transport(getdns_context *context, getdns_transport_t value); +getdns_return_t +getdns_context_set_dns_transport_list(getdns_context *context, + size_t transport_count, getdns_transport_list_t *transports); + getdns_return_t getdns_context_set_limit_outstanding_queries(getdns_context *context, uint16_t limit); @@ -949,6 +975,9 @@ getdns_context_set_limit_outstanding_queries(getdns_context *context, getdns_return_t getdns_context_set_timeout(getdns_context *context, uint64_t timeout); +getdns_return_t +getdns_context_set_idle_timeout(getdns_context *context, uint64_t timeout); + getdns_return_t getdns_context_set_follow_redirects(getdns_context *context, getdns_redirects_t value); diff --git a/src/getdns/getdns_extra.h b/src/getdns/getdns_extra.h index b27e9086..36e0497d 100644 --- a/src/getdns/getdns_extra.h +++ b/src/getdns/getdns_extra.h @@ -139,6 +139,10 @@ getdns_return_t getdns_context_get_dns_transport(getdns_context *context, getdns_transport_t* value); +getdns_return_t +getdns_context_get_dns_transport_list(getdns_context *context, + size_t* transport_count, getdns_transport_list_t **transports); + getdns_return_t getdns_context_get_limit_outstanding_queries(getdns_context *context, uint16_t* limit); @@ -146,6 +150,9 @@ getdns_context_get_limit_outstanding_queries(getdns_context *context, getdns_return_t getdns_context_get_timeout(getdns_context *context, uint64_t* timeout); +getdns_return_t +getdns_context_get_idle_timeout(getdns_context *context, uint64_t* timeout); + getdns_return_t getdns_context_get_follow_redirects(getdns_context *context, getdns_redirects_t* value); diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index b68062ee..656c29be 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -12,6 +12,7 @@ getdns_context_get_dns_root_servers getdns_context_get_dnssec_allowed_skew getdns_context_get_dnssec_trust_anchors getdns_context_get_dns_transport +getdns_context_get_dns_transport_list getdns_context_get_edns_do_bit getdns_context_get_edns_extended_rcode getdns_context_get_edns_maximum_udp_payload_size @@ -23,6 +24,7 @@ getdns_context_get_num_pending_requests getdns_context_get_resolution_type getdns_context_get_suffix getdns_context_get_timeout +getdns_context_get_idle_timeout getdns_context_get_update_callback getdns_context_get_upstream_recursive_servers getdns_context_process_async @@ -33,6 +35,7 @@ getdns_context_set_dns_root_servers getdns_context_set_dnssec_allowed_skew getdns_context_set_dnssec_trust_anchors getdns_context_set_dns_transport +getdns_context_set_dns_transport_list getdns_context_set_edns_do_bit getdns_context_set_edns_extended_rcode getdns_context_set_edns_maximum_udp_payload_size @@ -47,6 +50,7 @@ getdns_context_set_resolution_type getdns_context_set_return_dnssec_status getdns_context_set_suffix getdns_context_set_timeout +getdns_context_set_idle_timeout getdns_context_set_update_callback getdns_context_set_upstream_recursive_servers getdns_context_set_use_threads diff --git a/src/stub.c b/src/stub.c index c671b81d..b667ee64 100644 --- a/src/stub.c +++ b/src/stub.c @@ -530,6 +530,7 @@ stub_timeout_cb(void *userarg) netreq->upstream->tls_hs_state = GETDNS_HS_FAILED; stub_next_upstream(netreq); stub_cleanup(netreq); + return; } stub_next_upstream(netreq); @@ -538,6 +539,26 @@ stub_timeout_cb(void *userarg) (void) getdns_context_request_timed_out(netreq->owner); } +static void +upstream_idle_timeout_cb(void *userarg) +{ + DEBUG_STUB("%s\n", __FUNCTION__); + getdns_upstream *upstream = (getdns_upstream *)userarg; + /*There is a race condition with a new request being scheduled while this happens + so take ownership of the fd asap*/ + int fd = upstream->fd; + upstream->fd = -1; + upstream->event.timeout_cb = NULL; + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); + upstream->tls_hs_state = GETDNS_HS_NONE; + if (upstream->tls_obj != NULL) { + SSL_shutdown(upstream->tls_obj); + SSL_free(upstream->tls_obj); + } + close(fd); +} + + static void upstream_tls_timeout_cb(void *userarg) { @@ -1049,10 +1070,11 @@ stub_udp_read_cb(void *userarg) return; /* Client cookie didn't match? */ close(netreq->fd); - /*TODO[TLS]: Switch this to use the transport fallback list*/ + /* TODO: check not past end of transports*/ + getdns_base_transport_t next_transport = + netreq->dns_base_transports[netreq->transport + 1]; if (GLDNS_TC_WIRE(netreq->response) && - dnsreq->context->dns_transport == - GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP) { + next_transport == GETDNS_BASE_TRANSPORT_TCP) { if ((netreq->fd = socket( upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) @@ -1203,6 +1225,7 @@ upstream_read_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq; getdns_dns_req *dnsreq; + uint64_t idle_timeout; int q; uint16_t query_id; intptr_t query_id_intptr; @@ -1242,6 +1265,8 @@ upstream_read_cb(void *userarg) upstream->tcp.read_pos - upstream->tcp.read_buf; upstream->tcp.read_buf = NULL; upstream->upstreams->current = 0; + /* netreq may die before setting timeout*/ + idle_timeout = netreq->owner->context->idle_timeout; /* TODO: DNSSEC */ netreq->secure = 0; @@ -1295,6 +1320,12 @@ upstream_read_cb(void *userarg) GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, &upstream->event); + else { + upstream->event.timeout_cb = upstream_idle_timeout_cb; + GETDNS_SCHEDULE_EVENT(upstream->loop, + upstream->fd, idle_timeout, + &upstream->event); + } } } } @@ -1655,6 +1686,7 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) /* Append netreq to write_queue */ if (!upstream->write_queue) { upstream->write_queue = upstream->write_queue_last = netreq; + upstream->event.timeout_cb = NULL; GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); if (upstream->tls_hs_state == GETDNS_HS_WRITE || (upstream->starttls_req && diff --git a/src/test/check_getdns_context_set_timeout.c b/src/test/check_getdns_context_set_timeout.c index e10b6b1a..45a9c321 100644 --- a/src/test/check_getdns_context_set_timeout.c +++ b/src/test/check_getdns_context_set_timeout.c @@ -77,6 +77,39 @@ START_TEST (getdns_context_set_timeout_2) } END_TEST +START_TEST (getdns_context_set_idle_timeout_1) +{ + /* + * context is NULL + * expect: GETDNS_RETURN_INVALID_PARAMETER + */ + + struct getdns_context *context = NULL; + + ASSERT_RC(getdns_context_set_idle_timeout(context, 1000), + GETDNS_RETURN_INVALID_PARAMETER, "Return code from getdns_context_set_timeout()"); + +} +END_TEST + +START_TEST (getdns_context_set_idle_timeout_2) +{ + /* + * timeout is 0 + * expect: GETDNS_RETURN_INVALID_PARAMETER + */ + + struct getdns_context *context = NULL; + CONTEXT_CREATE(TRUE); + + ASSERT_RC(getdns_context_set_idle_timeout(context, 0), + GETDNS_RETURN_INVALID_PARAMETER, "Return code from getdns_context_set_timeout()"); + + CONTEXT_DESTROY; + +} +END_TEST + #define GETDNS_STR_IPV4 "IPv4" #define GETDNS_STR_IPV6 "IPv6" #define GETDNS_STR_ADDRESS_TYPE "address_type" @@ -270,6 +303,8 @@ getdns_context_set_timeout_suite (void) TCase *tc_neg = tcase_create("Negative"); tcase_add_test(tc_neg, getdns_context_set_timeout_1); tcase_add_test(tc_neg, getdns_context_set_timeout_2); + tcase_add_test(tc_neg, getdns_context_set_idle_timeout_1); + tcase_add_test(tc_neg, getdns_context_set_idle_timeout_2); suite_add_tcase(s, tc_neg); /* Positive test cases */ diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 3fcf0920..83064557 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -32,6 +32,7 @@ #include #include #include +#include static int quiet = 0; static int batch_mode = 0; @@ -92,13 +93,40 @@ ipaddr_dict(getdns_context *context, char *ipstr) if (*portstr) getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); if (*tls_portstr) - getdns_dict_set_int(r, "tls-port", (int32_t)atoi(tls_portstr)); + getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); if (*scope_id_str) getdns_dict_util_set_string(r, "scope_id", scope_id_str); return r; } +static getdns_return_t +fill_transport_list(getdns_context *context, char *transport_list_str, + getdns_transport_list_t *transports, size_t *transport_count) +{ + for (size_t i = 0; i < strlen(transport_list_str); i++, (*transport_count)++) { + switch(*(transport_list_str + i)) { + case 'U': + transports[i] = GETDNS_TRANSPORT_UDP; + break; + case 'T': + transports[i] = GETDNS_TRANSPORT_TCP; + break; + case 'L': + transports[i] = GETDNS_TRANSPORT_TLS; + break; + case 'S': + transports[i] = GETDNS_TRANSPORT_STARTTLS; + break; + default: + fprintf(stderr, "Unrecognised transport '%c' in string %s\n", + *(transport_list_str + i), transport_list_str); + return GETDNS_RETURN_GENERIC_ERROR; + } + } + return GETDNS_RETURN_GOOD; +} + void print_usage(FILE *out, const char *progname) { @@ -124,6 +152,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); fprintf(out, "\t-S\tservice lookup ( is ignored)\n"); fprintf(out, "\t-t \tSet timeout in miliseconds\n"); + fprintf(out, "\t-e \tSet idle timeout in miliseconds\n"); fprintf(out, "\t-T\tSet transport to TCP only\n"); fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n"); fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n"); @@ -131,6 +160,8 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-R\tSet transport to STARTTLS with TCP fallback only keep connections open\n"); fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n"); fprintf(out, "\t-U\tSet transport to UDP only\n"); + fprintf(out, "\t-l \tSet transport list. List can contain 1 of each of the characters\n"); + fprintf(out, "\t\t\t U T L S for UDP, TCP, TLS or STARTTLS e.g 'UT' or 'LST' \n"); fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n"); fprintf(out, "\t-q\tQuiet mode - don't print response\n"); } @@ -347,20 +378,36 @@ getdns_return_t parse_args(int argc, char **argv) break; case 't': if (c[1] != 0 || ++i >= argc || !*argv[i]) { - fprintf(stderr, "ttl expected " + fprintf(stderr, "timeout expected " "after -t\n"); return GETDNS_RETURN_GENERIC_ERROR; } timeout = strtol(argv[i], &endptr, 10); if (*endptr || timeout < 0) { fprintf(stderr, "positive " - "numeric ttl expected " + "numeric timeout expected " "after -t\n"); return GETDNS_RETURN_GENERIC_ERROR; } getdns_context_set_timeout( context, timeout); goto next; + case 'e': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + timeout = strtol(argv[i], &endptr, 10); + if (*endptr || timeout < 0) { + fprintf(stderr, "positive " + "numeric idle timeout expected " + "after -t\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_context_set_idle_timeout( + context, timeout); + goto next; case 'T': getdns_context_set_dns_transport(context, GETDNS_TRANSPORT_TCP_ONLY); @@ -389,6 +436,21 @@ getdns_return_t parse_args(int argc, char **argv) getdns_context_set_dns_transport(context, GETDNS_TRANSPORT_UDP_ONLY); break; + case 'l': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "transport list expected " + "after -l\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + size_t transport_count = 0; + getdns_transport_list_t transports[GETDNS_BASE_TRANSPORT_MAX]; + if ((r = fill_transport_list(context, argv[i], transports, &transport_count)) || + (r = getdns_context_set_dns_transport_list(context, + transport_count, transports))){ + fprintf(stderr, "Could not set transports\n"); + return r; + } + break; case 'B': batch_mode = 1; break; diff --git a/src/test/tests_stub_async.c b/src/test/tests_stub_async.c index fb0baf63..ceaa54d6 100644 --- a/src/test/tests_stub_async.c +++ b/src/test/tests_stub_async.c @@ -42,10 +42,12 @@ #include #define TRANSPORT_UDP "udp" +#define TRANSPORT_UDP_TCP "udp_tcp" #define TRANSPORT_TCP "tcp" #define TRANSPORT_PIPELINE "pipeline" #define TRANSPORT_TLS_KEEPOPEN "tls" #define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls" +#define TRANSPORT_STARTTLS_TCP_KEEPOPEN "starttls" #define RESOLUTION_STUB "stub" #define RESOLUTION_REC "rec" @@ -76,16 +78,16 @@ int main(int argc, char** argv) { - const char *transport = argc > 2 ? argv[2] : "udp"; + const char *transport = argc > 2 ? argv[2] : "udp_tcp"; const char *resolution = argc > 3 ? argv[3] : "stub"; /* Create the DNS context for this call */ struct getdns_context *this_context = NULL; - getdns_return_t context_create_return = + getdns_return_t return_value = getdns_context_create(&this_context, 1); - if (context_create_return != GETDNS_RETURN_GOOD) { + if (return_value != GETDNS_RETURN_GOOD) { fprintf(stderr, "Trying to create the context failed: %d", - context_create_return); + return_value); return (GETDNS_RETURN_GENERIC_ERROR); } @@ -96,16 +98,23 @@ main(int argc, char** argv) exit(EXIT_FAILURE); } + /* Order matters*/ if (strncmp(transport, TRANSPORT_TCP, 3) == 0) getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY); + else if (strncmp(transport, TRANSPORT_UDP_TCP, 7) == 0) + getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP); + else if (strncmp(transport, TRANSPORT_UDP, 3) == 0) + getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_UDP_ONLY); else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0) getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN); else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0) getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN); else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0) getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); - else if (strncmp(transport, TRANSPORT_UDP, 3) != 0) { - fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport); + else if (strncmp(transport, TRANSPORT_STARTTLS_TCP_KEEPOPEN, 8) == 0) + getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN); + else if (strncmp(transport, TRANSPORT_UDP_TCP, 3) != 0) { + fprintf(stderr, "Invalid transport %s, must be one of udp, udp_tcp, tcp or pipeline\n", transport); exit(EXIT_FAILURE); } @@ -129,6 +138,29 @@ main(int argc, char** argv) else { getdns_context_run(this_context); } + + getdns_transport_t get_transport; + return_value = getdns_context_get_dns_transport(this_context, &get_transport); + if (return_value != GETDNS_RETURN_GOOD) { + fprintf(stderr, "Trying to get transport type failed: %d\n", + return_value); + return (GETDNS_RETURN_GENERIC_ERROR); + } + fprintf(stderr, "Transport type is %d\n", get_transport); + + size_t transport_count = 0; + getdns_transport_list_t *get_transport_list; + return_value = getdns_context_get_dns_transport_list(this_context, &transport_count, &get_transport_list); + if (return_value != GETDNS_RETURN_GOOD) { + fprintf(stderr, "Trying to get transport type failed: %d\n", + return_value); + return (GETDNS_RETURN_GENERIC_ERROR); + } + for (size_t i = 0; i < transport_count; i++) { + fprintf(stderr, "Transport %d is %d\n", (int)i, get_transport_list[i]); + } + free(get_transport_list); + /* Clean up */ getdns_context_destroy(this_context); /* Assuming we get here, leave gracefully */