Commit addition of transport list to the API.

- set and get functions are added.
- Existing transport functions retained for backwards compatibility.
- Basic combinations work as before, but underlying functional changes and cleanup are not complete yet...
- Context level options for timeouts and max_transactions_per_tcp_connection coming soon...
This commit is contained in:
Sara Dickinson 2015-06-17 17:18:09 +01:00
parent d5f70ab904
commit 8dd8d90e74
12 changed files with 362 additions and 97 deletions

View File

@ -1,5 +1,8 @@
* 2015-06-??: Version 0.?.? * 2015-06-??: Version 0.?.?
* Unit test for spurious execute bits. Thanks Paul Wouters. * 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.
* 2015-05-21: Version 0.2.0 * 2015-05-21: Version 0.2.0
* Fix libversion numbering: Thanks Daniel Kahn Gillmor * Fix libversion numbering: Thanks Daniel Kahn Gillmor

View File

@ -2198,6 +2198,20 @@ The value is <span class=default>
<code>GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN></code>, or <code>GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN></code>, or
<code>GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN></code> <code>GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN></code>
<div class=forh>
getdns_return_t
getdns_context_set_dns_transport_list(
size_t transport_list,
getdns_transport_list_t *transports
);</div>
<p class=cont>The <code>transports</code> array contains an ordered list
of transports that will be used for DNS lookups. The
values are <span class=default>
<code>GETDNS_TRANSPORT_UDP</code></span>,
<code>GETDNS_TRANSPORT_TCP</code>,
<code>GETDNS_TRANSPORT_TLS></code>, or
<code>GETDNS_TRANSPORT_STARTTLS></code>
<div class=forh> <div class=forh>
getdns_return_t getdns_return_t
getdns_context_set_limit_outstanding_queries( getdns_context_set_limit_outstanding_queries(

View File

@ -79,6 +79,11 @@ static struct const_info consts_info[] = {
{ 1100, "GETDNS_BAD_DNS_CNAME_IN_TARGET", GETDNS_BAD_DNS_CNAME_IN_TARGET_TEXT }, { 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 }, { 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 }, { 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) static int const_info_cmp(const void *a, const void *b)

View File

@ -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 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_string_opt(struct getdns_context *, char *, char *);
static void set_ub_number_opt(struct getdns_context *, char *, uint16_t); 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*, static void set_ub_limit_outstanding_queries(struct getdns_context*,
uint16_t); uint16_t);
static void set_ub_dnssec_allowed_skew(struct getdns_context*, uint32_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; 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) static inline void canonicalize_dname(uint8_t *dname)
{ {
uint8_t *next_label; uint8_t *next_label;
@ -834,8 +872,8 @@ getdns_context_create_with_extended_memory_functions(
result->dnssec_allowed_skew = 0; result->dnssec_allowed_skew = 0;
result->edns_maximum_udp_payload_size = -1; result->edns_maximum_udp_payload_size = -1;
result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP; result->dns_base_transports[0] = GETDNS_BASE_TRANSPORT_UDP;
priv_set_base_dns_transports(result->dns_base_transports, result->dns_transport); result->dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP;
result->limit_outstanding_queries = 0; result->limit_outstanding_queries = 0;
result->has_ta = priv_getdns_parse_ta_file(NULL, NULL); result->has_ta = priv_getdns_parse_ta_file(NULL, NULL);
result->return_dnssec_status = GETDNS_EXTENSION_FALSE; result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
@ -1065,8 +1103,7 @@ rebuild_ub_ctx(struct getdns_context* context) {
context->dnssec_allowed_skew); context->dnssec_allowed_skew);
set_ub_edns_maximum_udp_payload_size(context, set_ub_edns_maximum_udp_payload_size(context,
context->edns_maximum_udp_payload_size); context->edns_maximum_udp_payload_size);
set_ub_dns_transport(context, set_ub_dns_transport(context);
context->dns_transport);
/* Set default trust anchor */ /* Set default trust anchor */
if (context->has_ta) { if (context->has_ta) {
@ -1159,71 +1196,67 @@ getdns_context_set_namespaces(struct getdns_context *context,
return GETDNS_RETURN_GOOD; return GETDNS_RETURN_GOOD;
} /* getdns_context_set_namespaces */ } /* getdns_context_set_namespaces */
/* TODO[TLS]: Modify further when API changed.*/ static getdns_return_t
getdns_return_t getdns_set_base_dns_transports(struct getdns_context *context,
priv_set_base_dns_transports(getdns_base_transport_t *dns_base_transports, size_t transport_count, getdns_transport_list_t *transports)
getdns_transport_t value)
{ {
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++) for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
dns_base_transports[i] = GETDNS_BASE_TRANSPORT_NONE; context->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;
default: if ((int)transport_count == 0 || transports == NULL ||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; (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; return GETDNS_RETURN_GOOD;
} }
static getdns_return_t static getdns_return_t
set_ub_dns_transport(struct getdns_context* context, set_ub_dns_transport(struct getdns_context* context) {
getdns_transport_t value) { /* These mappings are not exact because Unbound is configured differently,
switch (value) { so just map as close as possible from the first 1 or 2 transports. */
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP: 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-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; break;
case GETDNS_TRANSPORT_UDP_ONLY: case GETDNS_BASE_TRANSPORT_TLS:
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:
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 /* Note: If TLS is used in recursive mode this will try TLS on port
* 53... So this is prohibited when preparing for resolution.*/ * 53... So this is prohibited when preparing for resolution.*/
set_ub_string_opt(context, "ssl-upstream:", "yes"); if (context->dns_base_transports[1] == GETDNS_BASE_TRANSPORT_NONE) {
/* Fall through */ set_ub_string_opt(context, "ssl-upstream:", "yes");
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: set_ub_string_opt(context, "do-udp:", "no");
case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN: set_ub_string_opt(context, "do-tcp:", "yes");
/* Note: no fallback to TCP available directly in unbound, so we just 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. */ * 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-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes"); set_ub_string_opt(context, "do-tcp:", "yes");
@ -1242,25 +1275,71 @@ getdns_return_t
getdns_context_set_dns_transport(struct getdns_context *context, getdns_context_set_dns_transport(struct getdns_context *context,
getdns_transport_t value) getdns_transport_t value)
{ {
/* TODO[TLS]: Modify further when API changed.*/
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); 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 /* 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 * ctx is finalised so for recursive mode or stub + dnssec only the first
* transport specified on the first query is used. * transport specified on the first query is used.
* However the method returns success as otherwise the transport could not * However the method returns success as otherwise the transport could not
* be reset for stub mode. * be reset for stub mode.
* Also, not all transport options supported in libunbound yet */ * 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; return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
} }
if (value != context->dns_transport) { dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT);
/*TODO[TLS]: remove this line when API updated*/ return GETDNS_RETURN_GOOD;
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);
}
/*
* 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; return GETDNS_RETURN_GOOD;
} /* getdns_context_set_dns_transport */ } /* getdns_context_set_dns_transport */
@ -1568,7 +1647,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
if (base_transport != GETDNS_BASE_TRANSPORT_TLS) if (base_transport != GETDNS_BASE_TRANSPORT_TLS)
(void) getdns_dict_get_int(dict, "port", &port); (void) getdns_dict_get_int(dict, "port", &port);
else 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); (void) snprintf(portstr, 1024, "%d", (int)port);
if (getaddrinfo(addrstr, portstr, &hints, &ai)) if (getaddrinfo(addrstr, portstr, &hints, &ai))
@ -1918,17 +1997,14 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
/* Create client context, use TLS v1.2 only for now */ /* Create client context, use TLS v1.2 only for now */
context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method()); context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
#endif #endif
/* TODO[TLS]: Check if TLS is the only option in the list*/ if(context->tls_ctx == NULL)
// if(!context->tls_ctx && context->dns_transport == return GETDNS_RETURN_BAD_CONTEXT;
// GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
// return GETDNS_RETURN_BAD_CONTEXT;
// }
} }
} }
/* Block use of TLS ONLY in recursive mode as it won't work */ /* 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 && 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; return GETDNS_RETURN_BAD_CONTEXT;
if (context->resolution_type_set == context->resolution_type) if (context->resolution_type_set == context->resolution_type)
@ -2192,8 +2268,7 @@ priv_get_context_settings(getdns_context* context) {
return NULL; return NULL;
} }
/* int fields */ /* 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, "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, "dnssec_allowed_skew", context->dnssec_allowed_skew);
r |= getdns_dict_set_int(result, "follow_redirects", context->follow_redirects); r |= getdns_dict_set_int(result, "follow_redirects", context->follow_redirects);
@ -2224,6 +2299,18 @@ priv_get_context_settings(getdns_context* context) {
upstreams); upstreams);
getdns_list_destroy(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) { if (context->namespace_count > 0) {
/* create a namespace list */ /* create a namespace list */
size_t i; size_t i;
@ -2416,10 +2503,60 @@ getdns_context_get_dns_transport(getdns_context *context,
getdns_transport_t* value) { getdns_transport_t* value) {
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(value, 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; 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_return_t
getdns_context_get_limit_outstanding_queries(getdns_context *context, getdns_context_get_limit_outstanding_queries(getdns_context *context,

View File

@ -137,7 +137,6 @@ struct getdns_context {
struct getdns_list *suffix; struct getdns_list *suffix;
struct getdns_list *dnssec_trust_anchors; struct getdns_list *dnssec_trust_anchors;
getdns_upstreams *upstreams; getdns_upstreams *upstreams;
getdns_transport_t dns_transport;
getdns_base_transport_t dns_base_transports[GETDNS_BASE_TRANSPORT_MAX]; getdns_base_transport_t dns_base_transports[GETDNS_BASE_TRANSPORT_MAX];
uint16_t limit_outstanding_queries; uint16_t limit_outstanding_queries;
uint32_t dnssec_allowed_skew; uint32_t dnssec_allowed_skew;
@ -234,9 +233,6 @@ int filechg_check(struct getdns_context *context, struct filechg *fchg);
void priv_getdns_context_ub_read_cb(void *userarg); 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); void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams);
#endif /* _GETDNS_CONTEXT_H_ */ #endif /* _GETDNS_CONTEXT_H_ */

View File

@ -608,14 +608,14 @@ static const char *unknown_str_l[] = {" <unknown>", " null", "null"};
* @param buf buffer to write to * @param buf buffer to write to
* @param indent number of spaces to append after newline * @param indent number of spaces to append after newline
* @param list the to list print * @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. * Show the literal instead of the value.
* @return on success the number of written characters * @return on success the number of written characters
* if an output error is encountered, a negative value * if an output error is encountered, a negative value
*/ */
static int static int
getdns_pp_list(gldns_buffer *buf, size_t indent, const getdns_list *list, 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); size_t i, length, p = gldns_buffer_position(buf);
getdns_data_type dtype; 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)) if (getdns_list_get_int(list, i, &int_item))
return -1; return -1;
if (!json && for_namespaces && if (!json && for_literals &&
(strval = (strval =
priv_getdns_get_const_info(int_item)->name)) { priv_getdns_get_const_info(int_item)->name)) {
if (gldns_buffer_printf(buf, "%s", strval) < 0) 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, "dnssec_status") == 0 ||
strcmp(item->node.key, "status") == 0 || strcmp(item->node.key, "status") == 0 ||
strcmp(item->node.key, "append_name") == 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, "follow_redirects") == 0 ||
strcmp(item->node.key, "resolution_type") == 0) && strcmp(item->node.key, "resolution_type") == 0) &&
(strval = (strval =
@ -893,7 +892,8 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent,
getdns_indent(indent)) < 0) getdns_indent(indent)) < 0)
return -1; return -1;
if (getdns_pp_list(buf, indent, item->data.list, 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) json) < 0)
return -1; return -1;
break; break;

View File

@ -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_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_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()" #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()"
/** @} /** @}
*/ */
@ -942,6 +962,10 @@ getdns_return_t
getdns_context_set_dns_transport(getdns_context *context, getdns_context_set_dns_transport(getdns_context *context,
getdns_transport_t value); 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_return_t
getdns_context_set_limit_outstanding_queries(getdns_context *context, getdns_context_set_limit_outstanding_queries(getdns_context *context,
uint16_t limit); uint16_t limit);

View File

@ -139,6 +139,10 @@ getdns_return_t
getdns_context_get_dns_transport(getdns_context *context, getdns_context_get_dns_transport(getdns_context *context,
getdns_transport_t* value); 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_return_t
getdns_context_get_limit_outstanding_queries(getdns_context *context, getdns_context_get_limit_outstanding_queries(getdns_context *context,
uint16_t* limit); uint16_t* limit);

View File

@ -12,6 +12,7 @@ getdns_context_get_dns_root_servers
getdns_context_get_dnssec_allowed_skew getdns_context_get_dnssec_allowed_skew
getdns_context_get_dnssec_trust_anchors getdns_context_get_dnssec_trust_anchors
getdns_context_get_dns_transport getdns_context_get_dns_transport
getdns_context_get_dns_transport_list
getdns_context_get_edns_do_bit getdns_context_get_edns_do_bit
getdns_context_get_edns_extended_rcode getdns_context_get_edns_extended_rcode
getdns_context_get_edns_maximum_udp_payload_size getdns_context_get_edns_maximum_udp_payload_size
@ -33,6 +34,7 @@ getdns_context_set_dns_root_servers
getdns_context_set_dnssec_allowed_skew getdns_context_set_dnssec_allowed_skew
getdns_context_set_dnssec_trust_anchors getdns_context_set_dnssec_trust_anchors
getdns_context_set_dns_transport getdns_context_set_dns_transport
getdns_context_set_dns_transport_list
getdns_context_set_edns_do_bit getdns_context_set_edns_do_bit
getdns_context_set_edns_extended_rcode getdns_context_set_edns_extended_rcode
getdns_context_set_edns_maximum_udp_payload_size getdns_context_set_edns_maximum_udp_payload_size

View File

@ -530,6 +530,7 @@ stub_timeout_cb(void *userarg)
netreq->upstream->tls_hs_state = GETDNS_HS_FAILED; netreq->upstream->tls_hs_state = GETDNS_HS_FAILED;
stub_next_upstream(netreq); stub_next_upstream(netreq);
stub_cleanup(netreq); stub_cleanup(netreq);
return;
} }
stub_next_upstream(netreq); stub_next_upstream(netreq);
@ -1049,10 +1050,11 @@ stub_udp_read_cb(void *userarg)
return; /* Client cookie didn't match? */ return; /* Client cookie didn't match? */
close(netreq->fd); 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) && if (GLDNS_TC_WIRE(netreq->response) &&
dnsreq->context->dns_transport == next_transport == GETDNS_BASE_TRANSPORT_TCP) {
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP) {
if ((netreq->fd = socket( if ((netreq->fd = socket(
upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)

View File

@ -32,6 +32,7 @@
#include <dirent.h> #include <dirent.h>
#include <getdns/getdns.h> #include <getdns/getdns.h>
#include <getdns/getdns_extra.h> #include <getdns/getdns_extra.h>
#include <types-internal.h>
static int quiet = 0; static int quiet = 0;
static int batch_mode = 0; static int batch_mode = 0;
@ -92,13 +93,40 @@ ipaddr_dict(getdns_context *context, char *ipstr)
if (*portstr) if (*portstr)
getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); getdns_dict_set_int(r, "port", (int32_t)atoi(portstr));
if (*tls_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) if (*scope_id_str)
getdns_dict_util_set_string(r, "scope_id", scope_id_str); getdns_dict_util_set_string(r, "scope_id", scope_id_str);
return r; 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 void
print_usage(FILE *out, const char *progname) print_usage(FILE *out, const char *progname)
{ {
@ -131,6 +159,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-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 with TCP fallback\n");
fprintf(out, "\t-U\tSet transport to UDP only\n"); fprintf(out, "\t-U\tSet transport to UDP only\n");
fprintf(out, "\t-l <transports>\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-B\tBatch mode. Schedule all messages before processing responses.\n");
fprintf(out, "\t-q\tQuiet mode - don't print response\n"); fprintf(out, "\t-q\tQuiet mode - don't print response\n");
} }
@ -389,6 +419,21 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_dns_transport(context, getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_UDP_ONLY); GETDNS_TRANSPORT_UDP_ONLY);
break; 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': case 'B':
batch_mode = 1; batch_mode = 1;
break; break;

View File

@ -42,10 +42,12 @@
#include <sys/time.h> #include <sys/time.h>
#define TRANSPORT_UDP "udp" #define TRANSPORT_UDP "udp"
#define TRANSPORT_UDP_TCP "udp_tcp"
#define TRANSPORT_TCP "tcp" #define TRANSPORT_TCP "tcp"
#define TRANSPORT_PIPELINE "pipeline" #define TRANSPORT_PIPELINE "pipeline"
#define TRANSPORT_TLS_KEEPOPEN "tls" #define TRANSPORT_TLS_KEEPOPEN "tls"
#define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls" #define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls"
#define TRANSPORT_STARTTLS_TCP_KEEPOPEN "starttls"
#define RESOLUTION_STUB "stub" #define RESOLUTION_STUB "stub"
#define RESOLUTION_REC "rec" #define RESOLUTION_REC "rec"
@ -76,16 +78,16 @@ int
main(int argc, char** argv) 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"; const char *resolution = argc > 3 ? argv[3] : "stub";
/* Create the DNS context for this call */ /* Create the DNS context for this call */
struct getdns_context *this_context = NULL; struct getdns_context *this_context = NULL;
getdns_return_t context_create_return = getdns_return_t return_value =
getdns_context_create(&this_context, 1); 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", fprintf(stderr, "Trying to create the context failed: %d",
context_create_return); return_value);
return (GETDNS_RETURN_GENERIC_ERROR); return (GETDNS_RETURN_GENERIC_ERROR);
} }
@ -96,16 +98,23 @@ main(int argc, char** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Order matters*/
if (strncmp(transport, TRANSPORT_TCP, 3) == 0) if (strncmp(transport, TRANSPORT_TCP, 3) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY); 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) else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN); getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0) else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN); getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0) 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); 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) { else if (strncmp(transport, TRANSPORT_STARTTLS_TCP_KEEPOPEN, 8) == 0)
fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport); 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); exit(EXIT_FAILURE);
} }
@ -129,6 +138,30 @@ main(int argc, char** argv)
else { else {
getdns_context_run(this_context); getdns_context_run(this_context);
} }
getdns_transport_t get_transport = GETDNS_TRANSPORT_UDP_ONLY;
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;
getdns_transport_list_t tmp[1] = {GETDNS_TRANSPORT_UDP};
get_transport_list = tmp;
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]);
}
/* Clean up */ /* Clean up */
getdns_context_destroy(this_context); getdns_context_destroy(this_context);
/* Assuming we get here, leave gracefully */ /* Assuming we get here, leave gracefully */