mirror of https://github.com/getdnsapi/getdns.git
Add another transport option as proof of concept for STARTTLS.
This commit is contained in:
parent
b533bc59c5
commit
79b3412fbf
|
@ -41,6 +41,7 @@ static struct const_info consts_info[] = {
|
||||||
{ 543, "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
|
{ 543, "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
|
||||||
{ 544, "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
|
{ 544, "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
|
||||||
{ 545, "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT },
|
{ 545, "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT },
|
||||||
|
{ 546, "GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT },
|
||||||
{ 550, "GETDNS_APPEND_NAME_ALWAYS", GETDNS_APPEND_NAME_ALWAYS_TEXT },
|
{ 550, "GETDNS_APPEND_NAME_ALWAYS", GETDNS_APPEND_NAME_ALWAYS_TEXT },
|
||||||
{ 551, "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT },
|
{ 551, "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT },
|
||||||
{ 552, "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT },
|
{ 552, "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT },
|
||||||
|
|
|
@ -53,6 +53,13 @@
|
||||||
#include "stub.h"
|
#include "stub.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
|
#define GETDNS_PORT_ZERO 0
|
||||||
|
#define GETDNS_PORT_TCP 53
|
||||||
|
#define GETDNS_PORT_TLS 1021
|
||||||
|
#define GETDNS_STR_PORT_ZERO "0"
|
||||||
|
#define GETDNS_STR_PORT_TCP "53"
|
||||||
|
#define GETDNS_STR_PORT_TLS "1021"
|
||||||
|
|
||||||
void *plain_mem_funcs_user_arg = MF_PLAIN;
|
void *plain_mem_funcs_user_arg = MF_PLAIN;
|
||||||
|
|
||||||
typedef struct host_name_addrs {
|
typedef struct host_name_addrs {
|
||||||
|
@ -63,15 +70,23 @@ typedef struct host_name_addrs {
|
||||||
} host_name_addrs;
|
} host_name_addrs;
|
||||||
|
|
||||||
static in_port_t
|
static in_port_t
|
||||||
getdns_port_array[GETDNS_PORT_LAST] = {
|
getdns_port_array[GETDNS_BASE_TRANSPORT_MAX] = {
|
||||||
GETDNS_PORT_NUM_TCP,
|
GETDNS_PORT_ZERO,
|
||||||
GETDNS_PORT_NUM_TLS
|
GETDNS_PORT_ZERO,
|
||||||
|
GETDNS_PORT_ZERO,
|
||||||
|
GETDNS_PORT_TCP,
|
||||||
|
GETDNS_PORT_TLS,
|
||||||
|
GETDNS_PORT_TCP
|
||||||
};
|
};
|
||||||
|
|
||||||
char*
|
char*
|
||||||
getdns_port_str_array[] = {
|
getdns_port_str_array[] = {
|
||||||
GETDNS_PORT_STR_TCP,
|
GETDNS_STR_PORT_ZERO,
|
||||||
GETDNS_PORT_STR_TLS
|
GETDNS_STR_PORT_ZERO,
|
||||||
|
GETDNS_STR_PORT_ZERO,
|
||||||
|
GETDNS_STR_PORT_TCP,
|
||||||
|
GETDNS_STR_PORT_TLS,
|
||||||
|
GETDNS_STR_PORT_TCP
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Private functions */
|
/* Private functions */
|
||||||
|
@ -252,7 +267,7 @@ sockaddr_dict(getdns_context *context, struct sockaddr *sa)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
port = ntohs(((struct sockaddr_in *)sa)->sin_port);
|
port = ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||||
if (port != 0 && port != GETDNS_PORT_NUM_TCP &&
|
if (port != 0 && port != GETDNS_PORT_TCP &&
|
||||||
getdns_dict_set_int(address, "port", (uint32_t)port))
|
getdns_dict_set_int(address, "port", (uint32_t)port))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -268,7 +283,7 @@ sockaddr_dict(getdns_context *context, struct sockaddr *sa)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
|
port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
|
||||||
if (port != 0 && port != GETDNS_PORT_NUM_TCP &&
|
if (port != 0 && port != GETDNS_PORT_TCP &&
|
||||||
getdns_dict_set_int(address, "port", (uint32_t)port))
|
getdns_dict_set_int(address, "port", (uint32_t)port))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -538,7 +553,7 @@ upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
|
||||||
if (upstream_scope_id(upstream))
|
if (upstream_scope_id(upstream))
|
||||||
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
||||||
"%%%d", (int)*upstream_scope_id(upstream));
|
"%%%d", (int)*upstream_scope_id(upstream));
|
||||||
else if (upstream_port(upstream) != GETDNS_PORT_NUM_TCP && upstream_port(upstream) != 0)
|
else if (upstream_port(upstream) != GETDNS_PORT_TCP && upstream_port(upstream) != 0)
|
||||||
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
||||||
"@%d", (int)upstream_port(upstream));
|
"@%d", (int)upstream_port(upstream));
|
||||||
}
|
}
|
||||||
|
@ -565,8 +580,8 @@ upstream_init(getdns_upstream *upstream,
|
||||||
/* For sharing a socket to this upstream with TCP */
|
/* For sharing a socket to this upstream with TCP */
|
||||||
upstream->fd = -1;
|
upstream->fd = -1;
|
||||||
upstream->tls_obj = NULL;
|
upstream->tls_obj = NULL;
|
||||||
upstream->dns_base_transport = (upstream_port(upstream) == GETDNS_PORT_NUM_TLS ?
|
upstream->starttls_req = NULL;
|
||||||
GETDNS_BASE_TRANSPORT_TLS : GETDNS_BASE_TRANSPORT_TCP);
|
upstream->dns_base_transport = GETDNS_BASE_TRANSPORT_TCP;
|
||||||
upstream->tls_hs_state = GETDNS_HS_NONE;
|
upstream->tls_hs_state = GETDNS_HS_NONE;
|
||||||
upstream->loop = NULL;
|
upstream->loop = NULL;
|
||||||
(void) getdns_eventloop_event_init(
|
(void) getdns_eventloop_event_init(
|
||||||
|
@ -670,9 +685,12 @@ set_os_defaults(struct getdns_context *context)
|
||||||
token = parse + strcspn(parse, " \t\r\n");
|
token = parse + strcspn(parse, " \t\r\n");
|
||||||
*token = 0;
|
*token = 0;
|
||||||
|
|
||||||
getdns_port_type_t port_type = GETDNS_PORT_FIRST;
|
getdns_base_transport_t base_transport = GETDNS_BASE_TRANSPORT_MIN;
|
||||||
for (; port_type < GETDNS_PORT_LAST; port_type++) {
|
for (; base_transport < GETDNS_BASE_TRANSPORT_MAX; base_transport++) {
|
||||||
if ((s = getaddrinfo(parse, getdns_port_str_array[port_type], &hints, &result)))
|
char * port_str = getdns_port_str_array[base_transport];
|
||||||
|
if (strncmp(port_str, GETDNS_STR_PORT_ZERO, 1) == 0)
|
||||||
|
continue;
|
||||||
|
if ((s = getaddrinfo(parse, port_str, &hints, &result)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* No lookups, so maximal 1 result */
|
/* No lookups, so maximal 1 result */
|
||||||
|
@ -686,6 +704,7 @@ set_os_defaults(struct getdns_context *context)
|
||||||
upstream = &context->upstreams->
|
upstream = &context->upstreams->
|
||||||
upstreams[context->upstreams->count++];
|
upstreams[context->upstreams->count++];
|
||||||
upstream_init(upstream, context->upstreams, result);
|
upstream_init(upstream, context->upstreams, result);
|
||||||
|
upstream->dns_base_transport = base_transport;
|
||||||
}
|
}
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
}
|
}
|
||||||
|
@ -1167,6 +1186,11 @@ priv_set_base_dns_transports(getdns_base_transport_t *dns_base_transports,
|
||||||
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS;
|
dns_base_transports[0] = GETDNS_BASE_TRANSPORT_TLS;
|
||||||
dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP;
|
dns_base_transports[1] = GETDNS_BASE_TRANSPORT_TCP;
|
||||||
break;
|
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:
|
default:
|
||||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -1197,6 +1221,7 @@ set_ub_dns_transport(struct getdns_context* context,
|
||||||
set_ub_string_opt(context, "ssl-upstream:", "yes");
|
set_ub_string_opt(context, "ssl-upstream:", "yes");
|
||||||
/* Fall through*/
|
/* Fall through*/
|
||||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
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
|
/* Note: no 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");
|
||||||
|
@ -1482,11 +1507,12 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
hints.ai_addr = NULL;
|
hints.ai_addr = NULL;
|
||||||
hints.ai_next = NULL;
|
hints.ai_next = NULL;
|
||||||
|
|
||||||
upstreams = upstreams_create(context, count*2);
|
/* TODO[TLS]: Resize on the fly to avoid hardcoding this*/
|
||||||
|
upstreams = upstreams_create(context, count*3);
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
/* Loop twice to create TCP and TLS upstreams*/
|
/* Loop to create upstreams as needed*/
|
||||||
getdns_port_type_t port_type = GETDNS_PORT_FIRST;
|
getdns_base_transport_t base_transport = GETDNS_BASE_TRANSPORT_MIN;
|
||||||
for (; port_type < GETDNS_PORT_LAST; port_type++) {
|
for (; base_transport < GETDNS_BASE_TRANSPORT_MAX; base_transport++) {
|
||||||
getdns_dict *dict;
|
getdns_dict *dict;
|
||||||
getdns_bindata *address_type;
|
getdns_bindata *address_type;
|
||||||
getdns_bindata *address_data;
|
getdns_bindata *address_data;
|
||||||
|
@ -1495,6 +1521,11 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai;
|
||||||
getdns_upstream *upstream;
|
getdns_upstream *upstream;
|
||||||
|
|
||||||
|
/* So should we be throwing away the port the user set?*/
|
||||||
|
port = getdns_port_array[base_transport];
|
||||||
|
if (port == GETDNS_PORT_ZERO)
|
||||||
|
continue;
|
||||||
|
|
||||||
upstream = &upstreams->upstreams[upstreams->count];
|
upstream = &upstreams->upstreams[upstreams->count];
|
||||||
if ((r = getdns_list_get_dict(upstream_list, i, &dict)))
|
if ((r = getdns_list_get_dict(upstream_list, i, &dict)))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1522,8 +1553,6 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
addrstr, 1024) == NULL)
|
addrstr, 1024) == NULL)
|
||||||
goto invalid_parameter;
|
goto invalid_parameter;
|
||||||
|
|
||||||
/* So should we be throwing away the port the user set?*/
|
|
||||||
port = (uint32_t)(int)getdns_port_array[port_type];
|
|
||||||
(void) getdns_dict_get_int(dict, "port", &port);
|
(void) getdns_dict_get_int(dict, "port", &port);
|
||||||
(void) snprintf(portstr, 1024, "%d", (int)port);
|
(void) snprintf(portstr, 1024, "%d", (int)port);
|
||||||
|
|
||||||
|
@ -1541,6 +1570,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
goto invalid_parameter;
|
goto invalid_parameter;
|
||||||
|
|
||||||
upstream_init(upstream, upstreams, ai);
|
upstream_init(upstream, upstreams, ai);
|
||||||
|
upstream->dns_base_transport = base_transport;
|
||||||
upstreams->count++;
|
upstreams->count++;
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
}
|
}
|
||||||
|
@ -1764,9 +1794,9 @@ ub_setup_stub(struct ub_ctx *ctx, getdns_context *context)
|
||||||
upstream = &upstreams->upstreams[i];
|
upstream = &upstreams->upstreams[i];
|
||||||
/*[TLS]: Use only the subset of upstreams that match the first transport */
|
/*[TLS]: Use only the subset of upstreams that match the first transport */
|
||||||
if (context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
|
if (context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
|
||||||
if (upstream_port(upstream) != GETDNS_PORT_NUM_TLS)
|
if (upstream_port(upstream) != GETDNS_PORT_TLS)
|
||||||
continue;
|
continue;
|
||||||
} else if (upstream_port(upstream) != GETDNS_PORT_NUM_TCP)
|
} else if (upstream_port(upstream) != GETDNS_PORT_TCP)
|
||||||
continue;
|
continue;
|
||||||
upstream_ntop_buf(upstream, addr, 1024);
|
upstream_ntop_buf(upstream, addr, 1024);
|
||||||
ub_ctx_set_fwd(ctx, addr);
|
ub_ctx_set_fwd(ctx, addr);
|
||||||
|
|
|
@ -49,10 +49,6 @@ struct ub_ctx;
|
||||||
|
|
||||||
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
|
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
|
||||||
#define GETDNS_FN_HOSTS "/etc/hosts"
|
#define GETDNS_FN_HOSTS "/etc/hosts"
|
||||||
#define GETDNS_PORT_NUM_TCP 53
|
|
||||||
#define GETDNS_PORT_NUM_TLS 1021
|
|
||||||
#define GETDNS_PORT_STR_TCP "53"
|
|
||||||
#define GETDNS_PORT_STR_TLS "1021"
|
|
||||||
|
|
||||||
enum filechgs { GETDNS_FCHG_ERRORS = -1
|
enum filechgs { GETDNS_FCHG_ERRORS = -1
|
||||||
, GETDNS_FCHG_NOERROR = 0
|
, GETDNS_FCHG_NOERROR = 0
|
||||||
|
@ -75,13 +71,6 @@ struct filechg {
|
||||||
struct stat *prevstat;
|
struct stat *prevstat;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum getdns_port_type {
|
|
||||||
GETDNS_PORT_FIRST = 0,
|
|
||||||
GETDNS_PORT_TCP = 0,
|
|
||||||
GETDNS_PORT_TLS = 1,
|
|
||||||
GETDNS_PORT_LAST = 2
|
|
||||||
} getdns_port_type_t;
|
|
||||||
|
|
||||||
typedef enum getdns_tls_hs_state {
|
typedef enum getdns_tls_hs_state {
|
||||||
GETDNS_HS_NONE,
|
GETDNS_HS_NONE,
|
||||||
GETDNS_HS_WRITE,
|
GETDNS_HS_WRITE,
|
||||||
|
@ -102,9 +91,10 @@ typedef struct getdns_upstream {
|
||||||
|
|
||||||
/* For sharing a TCP socket to this upstream */
|
/* For sharing a TCP socket to this upstream */
|
||||||
int fd;
|
int fd;
|
||||||
SSL* tls_obj;
|
|
||||||
getdns_base_transport_t dns_base_transport;
|
getdns_base_transport_t dns_base_transport;
|
||||||
|
SSL* tls_obj;
|
||||||
getdns_tls_hs_state_t tls_hs_state;
|
getdns_tls_hs_state_t tls_hs_state;
|
||||||
|
getdns_dns_req * starttls_req;
|
||||||
getdns_eventloop_event event;
|
getdns_eventloop_event event;
|
||||||
getdns_eventloop *loop;
|
getdns_eventloop *loop;
|
||||||
getdns_tcp_state tcp;
|
getdns_tcp_state tcp;
|
||||||
|
|
|
@ -165,7 +165,8 @@ typedef enum getdns_transport_t {
|
||||||
GETDNS_TRANSPORT_TCP_ONLY = 542,
|
GETDNS_TRANSPORT_TCP_ONLY = 542,
|
||||||
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN = 543,
|
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN = 543,
|
||||||
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN = 544,
|
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN = 544,
|
||||||
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN = 545
|
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN = 545,
|
||||||
|
GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN = 546
|
||||||
} getdns_transport_t;
|
} getdns_transport_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -178,6 +179,7 @@ typedef enum getdns_transport_t {
|
||||||
#define GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
|
#define GETDNS_TRANSPORT_TCP_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_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()"
|
||||||
/** @}
|
/** @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -89,8 +89,8 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
||||||
|
|
||||||
net_req->upstream = NULL;
|
net_req->upstream = NULL;
|
||||||
net_req->fd = -1;
|
net_req->fd = -1;
|
||||||
priv_set_base_dns_transports(net_req->dns_base_transports,
|
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
|
||||||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
net_req->dns_base_transports[i] = owner->context->dns_base_transports[i];
|
||||||
net_req->dns_base_transport = net_req->dns_base_transports;
|
net_req->dns_base_transport = net_req->dns_base_transports;
|
||||||
memset(&net_req->event, 0, sizeof(net_req->event));
|
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||||
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
||||||
|
|
533
src/stub.c
533
src/stub.c
|
@ -36,17 +36,17 @@
|
||||||
#include "stub.h"
|
#include "stub.h"
|
||||||
#include "gldns/gbuffer.h"
|
#include "gldns/gbuffer.h"
|
||||||
#include "gldns/pkthdr.h"
|
#include "gldns/pkthdr.h"
|
||||||
|
#include "gldns/rrdef.h"
|
||||||
|
#include "gldns/str2wire.h"
|
||||||
|
#include "rr-iter.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include <ldns/util.h>
|
#include <ldns/util.h>
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
|
|
||||||
#define STUB_TLS_SETUP_ERROR -3
|
#define STUB_TLS_SETUP_ERROR -4
|
||||||
#define STUB_TCP_AGAIN -2
|
#define STUB_TCP_AGAIN -3
|
||||||
#define STUB_TCP_ERROR -1
|
#define STUB_TCP_ERROR -2
|
||||||
|
|
||||||
/*TODO[TLS]: REMOVE!!!!!*/
|
|
||||||
#define TLS_DEBUG 1
|
|
||||||
|
|
||||||
static time_t secret_rollover_time = 0;
|
static time_t secret_rollover_time = 0;
|
||||||
static uint32_t secret = 0;
|
static uint32_t secret = 0;
|
||||||
|
@ -54,14 +54,11 @@ static uint32_t prev_secret = 0;
|
||||||
|
|
||||||
static void upstream_read_cb(void *userarg);
|
static void upstream_read_cb(void *userarg);
|
||||||
static void upstream_write_cb(void *userarg);
|
static void upstream_write_cb(void *userarg);
|
||||||
static int tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport);
|
|
||||||
static int connect_to_upstream(getdns_upstream *upstream,
|
|
||||||
getdns_base_transport_t transport,
|
|
||||||
getdns_context *context);
|
|
||||||
static void upstream_schedule_netreq(getdns_upstream *upstream,
|
static void upstream_schedule_netreq(getdns_upstream *upstream,
|
||||||
getdns_network_req *netreq);
|
getdns_network_req *netreq);
|
||||||
static void netreq_upstream_read_cb(void *userarg);
|
static void netreq_upstream_read_cb(void *userarg);
|
||||||
static void netreq_upstream_write_cb(void *userarg);
|
static void netreq_upstream_write_cb(void *userarg);
|
||||||
|
static int fallback_on_write(getdns_network_req *netreq);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rollover_secret()
|
rollover_secret()
|
||||||
|
@ -233,6 +230,108 @@ match_and_process_server_cookie(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_starttls_request(getdns_dns_req *dnsreq, getdns_upstream *upstream,
|
||||||
|
getdns_eventloop *loop)
|
||||||
|
{
|
||||||
|
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||||
|
getdns_dict* extensions = getdns_dict_create_with_context(dnsreq->context);
|
||||||
|
if (!extensions) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
r = getdns_dict_set_int(extensions, "specify_class", GLDNS_RR_CLASS_CH);
|
||||||
|
if (r != GETDNS_RETURN_GOOD) {
|
||||||
|
getdns_dict_destroy(extensions);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
upstream->starttls_req = dns_req_new(dnsreq->context, loop,
|
||||||
|
"STARTTLS", GETDNS_RRTYPE_TXT, extensions);
|
||||||
|
/*TODO[STARTTLS]: TO BIT*/
|
||||||
|
if (upstream->starttls_req == NULL)
|
||||||
|
return 0;
|
||||||
|
getdns_dict_destroy(extensions);
|
||||||
|
|
||||||
|
upstream->starttls_req->netreqs[0]->upstream = upstream;
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dname_equal(uint8_t *s1, uint8_t *s2)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
for (;;) {
|
||||||
|
if (*s1 != *s2)
|
||||||
|
return 0;
|
||||||
|
else if (!*s1)
|
||||||
|
return 1;
|
||||||
|
for (i = *s1++, s2++; i > 0; i--, s1++, s2++)
|
||||||
|
if ((*s1 & 0xDF) != (*s2 & 0xDF))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_starttls_response(getdns_network_req *netreq) {
|
||||||
|
|
||||||
|
priv_getdns_rr_iter rr_iter_storage, *rr_iter;
|
||||||
|
priv_getdns_rdf_iter rdf_iter_storage, *rdf_iter;
|
||||||
|
uint16_t rr_type;
|
||||||
|
gldns_pkt_section section;
|
||||||
|
uint8_t starttls_name_space[256],
|
||||||
|
*starttls_name = starttls_name_space;
|
||||||
|
uint8_t owner_name_space[256], *owner_name;
|
||||||
|
size_t starttls_name_len = 256, owner_name_len;
|
||||||
|
|
||||||
|
/* Servers that are not STARTTLS aware will refuse the CH query*/
|
||||||
|
if (LDNS_RCODE_NOERROR !=
|
||||||
|
GLDNS_RCODE_WIRE(netreq->response)) {
|
||||||
|
fprintf(stderr, "[STARTTLS] STARTTLS response had error %d\n", GLDNS_RCODE_WIRE(netreq->response));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GLDNS_ANCOUNT(netreq->response) != 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
(void) gldns_str2wire_dname_buf(
|
||||||
|
netreq->owner->name, starttls_name_space, &starttls_name_len);
|
||||||
|
|
||||||
|
for ( rr_iter = priv_getdns_rr_iter_init(&rr_iter_storage
|
||||||
|
, netreq->response
|
||||||
|
, netreq->response_len)
|
||||||
|
; rr_iter
|
||||||
|
; rr_iter = priv_getdns_rr_iter_next(rr_iter)) {
|
||||||
|
|
||||||
|
section = priv_getdns_rr_iter_section(rr_iter);
|
||||||
|
rr_type = gldns_read_uint16(rr_iter->rr_type);
|
||||||
|
if (section != GLDNS_SECTION_ANSWER || rr_type != GETDNS_RRTYPE_TXT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
owner_name = priv_getdns_owner_if_or_as_decompressed(
|
||||||
|
rr_iter, owner_name_space, &owner_name_len);
|
||||||
|
if (!dname_equal(starttls_name, owner_name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(rdf_iter = priv_getdns_rdf_iter_init(
|
||||||
|
&rdf_iter_storage, rr_iter)))
|
||||||
|
continue;
|
||||||
|
/* re-use the starttls_name for the response dname*/
|
||||||
|
starttls_name = priv_getdns_rdf_if_or_as_decompressed(
|
||||||
|
rdf_iter,starttls_name_space,&starttls_name_len);
|
||||||
|
if (dname_equal(starttls_name, owner_name)) {
|
||||||
|
fprintf(stderr, "[STARTTLS] STARTTLS response received :%s:\n", (char*)starttls_name);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[STARTTLS] NO_TLS response received :%s:\n", (char*)starttls_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** best effort to set nonblocking */
|
/** best effort to set nonblocking */
|
||||||
static void
|
static void
|
||||||
getdns_sock_nonblock(int sockfd)
|
getdns_sock_nonblock(int sockfd)
|
||||||
|
@ -323,9 +422,9 @@ static void
|
||||||
upstream_erred(getdns_upstream *upstream)
|
upstream_erred(getdns_upstream *upstream)
|
||||||
{
|
{
|
||||||
getdns_network_req *netreq;
|
getdns_network_req *netreq;
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: ERROR(upstream_erred)\n");
|
fprintf(stderr,"[TLS]: ERROR(upstream_erred)\n");
|
||||||
#endif
|
|
||||||
while ((netreq = upstream->write_queue)) {
|
while ((netreq = upstream->write_queue)) {
|
||||||
stub_cleanup(netreq);
|
stub_cleanup(netreq);
|
||||||
netreq->state = NET_REQ_FINISHED;
|
netreq->state = NET_REQ_FINISHED;
|
||||||
|
@ -347,6 +446,13 @@ upstream_erred(getdns_upstream *upstream)
|
||||||
upstream->fd = -1;
|
upstream->fd = -1;
|
||||||
/*TODO[TLS]: Upstream errors don't trigger the user callback....*/
|
/*TODO[TLS]: Upstream errors don't trigger the user callback....*/
|
||||||
}
|
}
|
||||||
|
static void
|
||||||
|
message_erred(getdns_network_req *netreq)
|
||||||
|
{
|
||||||
|
stub_cleanup(netreq);
|
||||||
|
netreq->state = NET_REQ_FINISHED;
|
||||||
|
priv_getdns_check_dns_req_complete(netreq->owner);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
priv_getdns_cancel_stub_request(getdns_network_req *netreq)
|
priv_getdns_cancel_stub_request(getdns_network_req *netreq)
|
||||||
|
@ -358,9 +464,9 @@ priv_getdns_cancel_stub_request(getdns_network_req *netreq)
|
||||||
static void
|
static void
|
||||||
stub_erred(getdns_network_req *netreq)
|
stub_erred(getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: ERROR(stub_erred)\n");
|
fprintf(stderr,"[TLS]: ERROR(stub_erred)\n");
|
||||||
#endif
|
|
||||||
stub_next_upstream(netreq);
|
stub_next_upstream(netreq);
|
||||||
stub_cleanup(netreq);
|
stub_cleanup(netreq);
|
||||||
/* TODO[TLS]: When we get an error (which is probably a timeout) and are
|
/* TODO[TLS]: When we get an error (which is probably a timeout) and are
|
||||||
|
@ -373,9 +479,9 @@ stub_erred(getdns_network_req *netreq)
|
||||||
static void
|
static void
|
||||||
stub_timeout_cb(void *userarg)
|
stub_timeout_cb(void *userarg)
|
||||||
{
|
{
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: TIMEOUT(stub_timeout_cb)\n");
|
fprintf(stderr,"[TLS]: TIMEOUT(stub_timeout_cb)\n");
|
||||||
#endif
|
|
||||||
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||||
|
|
||||||
stub_next_upstream(netreq);
|
stub_next_upstream(netreq);
|
||||||
|
@ -488,13 +594,17 @@ stub_udp_write_cb(void *userarg)
|
||||||
stub_udp_read_cb, NULL, stub_timeout_cb));
|
stub_udp_read_cb, NULL, stub_timeout_cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO[TLS]: Optimise to re-use TCP (or failed STARTTLS) where possible.*/
|
||||||
static int
|
static int
|
||||||
transport_valid(struct getdns_upstream *upstream, getdns_base_transport_t transport) {
|
transport_valid(struct getdns_upstream *upstream, getdns_base_transport_t transport) {
|
||||||
|
if (transport == GETDNS_BASE_TRANSPORT_UDP ||
|
||||||
|
transport == GETDNS_BASE_TRANSPORT_TCP_SINGLE)
|
||||||
|
return 1;
|
||||||
if (upstream->dns_base_transport != transport)
|
if (upstream->dns_base_transport != transport)
|
||||||
return 0;
|
return 0;
|
||||||
if (transport == GETDNS_BASE_TRANSPORT_TLS &&
|
if ((transport == GETDNS_BASE_TRANSPORT_TLS ||
|
||||||
upstream->tls_hs_state == GETDNS_HS_FAILED)
|
transport == GETDNS_BASE_TRANSPORT_STARTTLS)
|
||||||
|
&& upstream->tls_hs_state == GETDNS_HS_FAILED)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -663,9 +773,8 @@ create_tls_object(getdns_context *context, int fd)
|
||||||
static int
|
static int
|
||||||
do_tls_handshake(getdns_upstream *upstream)
|
do_tls_handshake(getdns_upstream *upstream)
|
||||||
{
|
{
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: TLS(do_tls_handshake)\n");
|
fprintf(stderr,"[TLS]: TLS(do_tls_handshake)\n");
|
||||||
#endif
|
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
int want;
|
int want;
|
||||||
|
@ -708,85 +817,11 @@ do_tls_handshake(getdns_upstream *upstream)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO[TLS]: Make generic function for switching transport */
|
|
||||||
static getdns_upstream*
|
|
||||||
pick_and_connect_to_fallback_upstream(getdns_network_req *netreq)
|
|
||||||
{
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: FALLBACK(pick_and_connect_to_fallback_upstream)\n");
|
|
||||||
#endif
|
|
||||||
getdns_base_transport_t *next_transport = netreq->dns_base_transport;
|
|
||||||
if (*(++next_transport) != GETDNS_BASE_TRANSPORT_TCP)
|
|
||||||
/* TODO[TLS]: Fallback through upstreams....?*/
|
|
||||||
return NULL;
|
|
||||||
getdns_upstream *new_upstream = pick_upstream(netreq, *next_transport);
|
|
||||||
/* TODO[TLS]: Fallback through upstreams....?*/
|
|
||||||
if (!new_upstream)
|
|
||||||
return NULL;
|
|
||||||
int fd = connect_to_upstream(new_upstream, *next_transport, netreq->owner->context);
|
|
||||||
if (fd == -1)
|
|
||||||
return NULL;
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: FALLBACK(pick_and_connect_to_fallback_upstream): now using fd %d \n", new_upstream->fd);
|
|
||||||
#endif
|
|
||||||
return new_upstream;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
move_netreq(getdns_network_req *netreq, getdns_upstream *upstream, getdns_upstream *new_upstream)
|
tls_handshake_active(getdns_tls_hs_state_t hs_state)
|
||||||
{
|
{
|
||||||
/* Remove from queue, clearing event and fd if we are the last*/
|
return (hs_state == GETDNS_HS_FAILED ||
|
||||||
#ifdef TLS_DEBUG
|
hs_state == GETDNS_HS_NONE) ? 0 : 1;
|
||||||
fprintf(stderr,"[TLS]: FALLBACK(move_netreq)\n");
|
|
||||||
#endif
|
|
||||||
if (!(upstream->write_queue = netreq->write_queue_tail)) {
|
|
||||||
upstream->write_queue_last = NULL;
|
|
||||||
upstream->event.write_cb = NULL;
|
|
||||||
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
|
|
||||||
close(upstream->fd);
|
|
||||||
upstream->fd = -1;
|
|
||||||
}
|
|
||||||
netreq->write_queue_tail = NULL;
|
|
||||||
|
|
||||||
/* Schedule with the new upstream */
|
|
||||||
netreq->upstream = new_upstream;
|
|
||||||
upstream_schedule_netreq(new_upstream, netreq);
|
|
||||||
|
|
||||||
/* TODO[TLS]: Timout need to be adjusted and rescheduled on the new fd ....*/
|
|
||||||
/* Note, setup timeout should be shorter than message timeout for
|
|
||||||
* messages with fallback or don't have time to re-try. */
|
|
||||||
|
|
||||||
/* For sync messages we must re-schedule the events here.*/
|
|
||||||
if (netreq->owner->loop != upstream->loop) {
|
|
||||||
/* Create an event for the new upstream*/
|
|
||||||
GETDNS_CLEAR_EVENT(netreq->owner->loop, &netreq->event);
|
|
||||||
GETDNS_SCHEDULE_EVENT(
|
|
||||||
netreq->owner->loop, new_upstream->fd, netreq->owner->context->timeout,
|
|
||||||
getdns_eventloop_event_init(&netreq->event, netreq,
|
|
||||||
( new_upstream->netreq_by_query_id.count ?
|
|
||||||
netreq_upstream_read_cb : NULL ),
|
|
||||||
( new_upstream->write_queue ?
|
|
||||||
netreq_upstream_write_cb : NULL),
|
|
||||||
stub_timeout_cb));
|
|
||||||
|
|
||||||
/* Now one for the old upstream. Must schedule this last to make sure
|
|
||||||
* it is called back first....?*/
|
|
||||||
if (upstream->write_queue) {
|
|
||||||
GETDNS_CLEAR_EVENT(netreq->owner->loop, &upstream->write_queue->event);
|
|
||||||
GETDNS_SCHEDULE_EVENT(
|
|
||||||
upstream->write_queue->owner->loop, upstream->fd,
|
|
||||||
upstream->write_queue->owner->context->timeout,
|
|
||||||
getdns_eventloop_event_init(&upstream->write_queue->event,
|
|
||||||
upstream->write_queue,
|
|
||||||
( upstream->netreq_by_query_id.count ?
|
|
||||||
netreq_upstream_read_cb : NULL ),
|
|
||||||
( upstream->write_queue ?
|
|
||||||
netreq_upstream_write_cb : NULL),
|
|
||||||
stub_timeout_cb));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return STUB_TCP_AGAIN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -811,9 +846,8 @@ check_tls(getdns_upstream* upstream)
|
||||||
if (error == EINPROGRESS || error == EWOULDBLOCK)
|
if (error == EINPROGRESS || error == EWOULDBLOCK)
|
||||||
return STUB_TCP_AGAIN; /* try again */
|
return STUB_TCP_AGAIN; /* try again */
|
||||||
else if (error != 0) {
|
else if (error != 0) {
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: TLS(check_tls): died gettting connection\n");
|
fprintf(stderr,"[TLS]: TLS(check_tls): died gettting connection\n");
|
||||||
#endif
|
|
||||||
SSL_free(upstream->tls_obj);
|
SSL_free(upstream->tls_obj);
|
||||||
upstream->tls_obj = NULL;
|
upstream->tls_obj = NULL;
|
||||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||||
|
@ -914,12 +948,13 @@ upstream_read_cb(void *userarg)
|
||||||
uint16_t query_id;
|
uint16_t query_id;
|
||||||
intptr_t query_id_intptr;
|
intptr_t query_id_intptr;
|
||||||
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: **********CALLBACK***********\n");
|
fprintf(stderr,"[TLS]: **********CALLBACK***********\n");
|
||||||
fprintf(stderr,"[TLS]: READ(upstream_read_cb): on %d\n", upstream->fd);
|
fprintf(stderr,"[TLS]: READ(upstream_read_cb): on %d\n", upstream->fd);
|
||||||
#endif
|
|
||||||
|
|
||||||
if (upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS)
|
if (upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS ||
|
||||||
|
(upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_STARTTLS &&
|
||||||
|
tls_handshake_active(upstream->tls_hs_state)))
|
||||||
q = stub_tls_read(upstream, &upstream->tcp,
|
q = stub_tls_read(upstream, &upstream->tcp,
|
||||||
&upstream->upstreams->mf);
|
&upstream->upstreams->mf);
|
||||||
else
|
else
|
||||||
|
@ -978,7 +1013,32 @@ upstream_read_cb(void *userarg)
|
||||||
netreq_upstream_write_cb : NULL),
|
netreq_upstream_write_cb : NULL),
|
||||||
stub_timeout_cb));
|
stub_timeout_cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (netreq->owner == upstream->starttls_req) {
|
||||||
|
dnsreq = netreq->owner;
|
||||||
|
fprintf(stderr, "[STARTTLS] processing STARTTLS response!\n");
|
||||||
|
if (is_starttls_response(netreq)) {
|
||||||
|
upstream->tls_obj = create_tls_object(dnsreq->context, upstream->fd);
|
||||||
|
if (upstream->tls_obj == NULL) {
|
||||||
|
fprintf(stderr,"[TLS]: could not create tls object\n");
|
||||||
|
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||||
|
}
|
||||||
|
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
||||||
|
} else
|
||||||
|
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||||
|
dns_req_free(upstream->starttls_req);
|
||||||
|
upstream->starttls_req = NULL;
|
||||||
|
|
||||||
|
// Now reschedule the writes on this connection
|
||||||
|
upstream->event.write_cb = upstream_write_cb;
|
||||||
|
fprintf(stderr, "[STARTTLS] method: upstream_schedule_netreq -> re-instating writes\n");
|
||||||
|
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
|
||||||
|
GETDNS_SCHEDULE_EVENT(upstream->loop,
|
||||||
|
upstream->fd, TIMEOUT_FOREVER, &upstream->event);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "[STARTTLS] processing standard response....\n");
|
||||||
priv_getdns_check_dns_req_complete(netreq->owner);
|
priv_getdns_check_dns_req_complete(netreq->owner);
|
||||||
|
}
|
||||||
|
|
||||||
/* Nothing more to read? Then deschedule the reads.*/
|
/* Nothing more to read? Then deschedule the reads.*/
|
||||||
if (! upstream->netreq_by_query_id.count) {
|
if (! upstream->netreq_by_query_id.count) {
|
||||||
|
@ -1005,7 +1065,6 @@ netreq_upstream_read_cb(void *userarg)
|
||||||
static int
|
static int
|
||||||
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
getdns_dns_req *dnsreq = netreq->owner;
|
|
||||||
|
|
||||||
size_t pkt_len = netreq->response - netreq->query;
|
size_t pkt_len = netreq->response - netreq->query;
|
||||||
ssize_t written;
|
ssize_t written;
|
||||||
|
@ -1024,9 +1083,8 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
||||||
* the write_queue) for that upstream. Register this netreq
|
* the write_queue) for that upstream. Register this netreq
|
||||||
* by query_id in the process.
|
* by query_id in the process.
|
||||||
*/
|
*/
|
||||||
if ((dnsreq->context->dns_transport == GETDNS_TRANSPORT_TCP_ONLY) ||
|
if ((*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_TCP_SINGLE) ||
|
||||||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_ONLY) ||
|
(*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_UDP))
|
||||||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP))
|
|
||||||
query_id = arc4random();
|
query_id = arc4random();
|
||||||
else do {
|
else do {
|
||||||
query_id = arc4random();
|
query_id = arc4random();
|
||||||
|
@ -1142,7 +1200,8 @@ stub_tcp_write_cb(void *userarg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, getdns_network_req *netreq)
|
stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
|
||||||
|
getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
size_t pkt_len = netreq->response - netreq->query;
|
size_t pkt_len = netreq->response - netreq->query;
|
||||||
ssize_t written;
|
ssize_t written;
|
||||||
|
@ -1198,17 +1257,18 @@ static void
|
||||||
upstream_write_cb(void *userarg)
|
upstream_write_cb(void *userarg)
|
||||||
{
|
{
|
||||||
getdns_upstream *upstream = (getdns_upstream *)userarg;
|
getdns_upstream *upstream = (getdns_upstream *)userarg;
|
||||||
getdns_upstream *new_upstream;
|
|
||||||
getdns_network_req *netreq = upstream->write_queue;
|
getdns_network_req *netreq = upstream->write_queue;
|
||||||
getdns_dns_req *dnsreq = netreq->owner;
|
getdns_dns_req *dnsreq = netreq->owner;
|
||||||
int q;
|
int q;
|
||||||
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: **********CALLBACK***********\n");
|
|
||||||
fprintf(stderr,"[TLS]: WRITE(upstream_write_cb): upstream fd %d, SEND netreq %p \n", upstream->fd, netreq);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (upstream->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS)
|
fprintf(stderr,"[TLS]: **********CALLBACK***********\n");
|
||||||
|
fprintf(stderr,"[TLS]: WRITE(upstream_write_cb): upstream fd %d, SEND"
|
||||||
|
" netreq %p \n", upstream->fd, netreq);
|
||||||
|
|
||||||
|
if (*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_TLS ||
|
||||||
|
(*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_STARTTLS &&
|
||||||
|
upstream->tls_hs_state != GETDNS_HS_NONE))
|
||||||
q = stub_tls_write(upstream, &upstream->tcp, netreq);
|
q = stub_tls_write(upstream, &upstream->tcp, netreq);
|
||||||
else
|
else
|
||||||
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
|
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
|
||||||
|
@ -1222,17 +1282,11 @@ upstream_write_cb(void *userarg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case STUB_TLS_SETUP_ERROR:
|
case STUB_TLS_SETUP_ERROR:
|
||||||
/* Could not complete the TLS set up. Need to fallback on this upstream
|
/* Could not complete the TLS set up. Need to fallback.*/
|
||||||
* if possible.*/
|
if (fallback_on_write(netreq) == STUB_TCP_ERROR) {
|
||||||
new_upstream = pick_and_connect_to_fallback_upstream(netreq);
|
fprintf(stderr,"[TLS]: Fallback failed.\n");
|
||||||
if (!new_upstream) {
|
message_erred(netreq);
|
||||||
//TODO[TLS]: Need a different error case here for msg_erred?
|
|
||||||
stub_erred(netreq);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (move_netreq(netreq, upstream, new_upstream) == STUB_TCP_ERROR)
|
|
||||||
//TODO[TLS]: Need a different error case here for msg_erred?
|
|
||||||
stub_erred(netreq);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1259,6 +1313,16 @@ upstream_write_cb(void *userarg)
|
||||||
GETDNS_SCHEDULE_EVENT(upstream->loop,
|
GETDNS_SCHEDULE_EVENT(upstream->loop,
|
||||||
upstream->fd, TIMEOUT_FOREVER, &upstream->event);
|
upstream->fd, TIMEOUT_FOREVER, &upstream->event);
|
||||||
}
|
}
|
||||||
|
if (upstream->starttls_req) {
|
||||||
|
/* Now deschedule any further writes on this connection until we get
|
||||||
|
the STARTTLS answer*/
|
||||||
|
fprintf(stderr, "[STARTTLS] method: upstream_write_cb -> STARTTTLS -"
|
||||||
|
"clearing upstream->event.write_cb\n");
|
||||||
|
upstream->event.write_cb = NULL;
|
||||||
|
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
|
||||||
|
GETDNS_SCHEDULE_EVENT(upstream->loop,
|
||||||
|
upstream->fd, TIMEOUT_FOREVER, &upstream->event);
|
||||||
|
}
|
||||||
/* With synchonous lookups, schedule the read locally too */
|
/* With synchonous lookups, schedule the read locally too */
|
||||||
if (netreq->event.write_cb) {
|
if (netreq->event.write_cb) {
|
||||||
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
|
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
|
||||||
|
@ -1266,7 +1330,7 @@ upstream_write_cb(void *userarg)
|
||||||
dnsreq->loop, upstream->fd, dnsreq->context->timeout,
|
dnsreq->loop, upstream->fd, dnsreq->context->timeout,
|
||||||
getdns_eventloop_event_init(&netreq->event, netreq,
|
getdns_eventloop_event_init(&netreq->event, netreq,
|
||||||
netreq_upstream_read_cb,
|
netreq_upstream_read_cb,
|
||||||
( upstream->write_queue ?
|
(upstream->write_queue && !upstream->starttls_req ?
|
||||||
netreq_upstream_write_cb : NULL),
|
netreq_upstream_write_cb : NULL),
|
||||||
stub_timeout_cb));
|
stub_timeout_cb));
|
||||||
}
|
}
|
||||||
|
@ -1287,9 +1351,8 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
|
||||||
assert(upstream->fd >= 0);
|
assert(upstream->fd >= 0);
|
||||||
assert(upstream->loop);
|
assert(upstream->loop);
|
||||||
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: SCHEDULE(upstream_schedule_netreq): fd %d\n", upstream->fd);
|
fprintf(stderr,"[TLS]: SCHEDULE(upstream_schedule_netreq): fd %d\n", upstream->fd);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Append netreq to write_queue */
|
/* Append netreq to write_queue */
|
||||||
if (!upstream->write_queue) {
|
if (!upstream->write_queue) {
|
||||||
|
@ -1331,25 +1394,40 @@ tcp_connect(getdns_upstream *upstream, getdns_base_transport_t transport)
|
||||||
|
|
||||||
int
|
int
|
||||||
connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport,
|
connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport,
|
||||||
getdns_context *context)
|
getdns_dns_req *dnsreq)
|
||||||
{
|
{
|
||||||
|
/* First check if existing connection can be used, which may still be being
|
||||||
if (transport == GETDNS_BASE_TRANSPORT_TCP && upstream->fd != -1) {
|
* set up. */
|
||||||
#ifdef TLS_DEBUG
|
switch(transport) {
|
||||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): tcp_connect using existing TCP fd %d\n", upstream->fd);
|
case GETDNS_BASE_TRANSPORT_TCP:
|
||||||
#endif
|
if (upstream->fd != -1) {
|
||||||
|
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream):"
|
||||||
|
"tcp_connect using existing TCP fd %d\n", upstream->fd);
|
||||||
return upstream->fd;
|
return upstream->fd;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
if (transport == GETDNS_BASE_TRANSPORT_TLS &&
|
case GETDNS_BASE_TRANSPORT_TLS:
|
||||||
!(upstream->tls_hs_state == GETDNS_HS_FAILED
|
if (tls_handshake_active(upstream->tls_hs_state)) {
|
||||||
|| upstream->tls_hs_state == GETDNS_HS_NONE)) {
|
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream):"
|
||||||
#ifdef TLS_DEBUG
|
"tcp_connect using existing TLS fd %d\n", upstream->fd);
|
||||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): tcp_connect using existing TLS fd %d\n", upstream->fd);
|
|
||||||
#endif
|
|
||||||
return upstream->fd;
|
return upstream->fd;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case GETDNS_BASE_TRANSPORT_STARTTLS:
|
||||||
|
/* Either negotiating, or doing handshake*/
|
||||||
|
if ((upstream->starttls_req != NULL) ||
|
||||||
|
(upstream->starttls_req == NULL &&
|
||||||
|
tls_handshake_active(upstream->tls_hs_state))) {
|
||||||
|
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream):"
|
||||||
|
"tcp_connect using existing STARTTLS fd %d\n", upstream->fd);
|
||||||
|
return upstream->fd;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If not, create a new one */
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
switch(transport) {
|
switch(transport) {
|
||||||
case GETDNS_BASE_TRANSPORT_UDP:
|
case GETDNS_BASE_TRANSPORT_UDP:
|
||||||
|
@ -1362,63 +1440,175 @@ connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport
|
||||||
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
|
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
|
||||||
case GETDNS_BASE_TRANSPORT_TCP:
|
case GETDNS_BASE_TRANSPORT_TCP:
|
||||||
fd = tcp_connect(upstream, transport);
|
fd = tcp_connect(upstream, transport);
|
||||||
|
upstream->loop = dnsreq->context->extension;
|
||||||
|
upstream->fd = fd;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GETDNS_BASE_TRANSPORT_TLS:
|
case GETDNS_BASE_TRANSPORT_TLS:
|
||||||
fd = tcp_connect(upstream, transport);
|
fd = tcp_connect(upstream, transport);
|
||||||
if (fd == -1) return -1;
|
if (fd == -1) return -1;
|
||||||
upstream->tls_obj = create_tls_object(context, fd);
|
upstream->tls_obj = create_tls_object(dnsreq->context, fd);
|
||||||
if (upstream->tls_obj == NULL) {
|
if (upstream->tls_obj == NULL) {
|
||||||
fprintf(stderr,"[TLS]: could not create tls object\n");
|
fprintf(stderr,"[TLS]: could not create tls object\n");
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
||||||
|
upstream->loop = dnsreq->context->extension;
|
||||||
|
upstream->fd = fd;
|
||||||
|
break;
|
||||||
|
case GETDNS_BASE_TRANSPORT_STARTTLS:
|
||||||
|
fd = tcp_connect(upstream, transport);
|
||||||
|
if (fd == -1) return -1;
|
||||||
|
if (!create_starttls_request(dnsreq, upstream, dnsreq->loop))
|
||||||
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
getdns_network_req *starttls_netreq = upstream->starttls_req->netreqs[0];
|
||||||
|
upstream->loop = dnsreq->context->extension;
|
||||||
|
upstream->fd = fd;
|
||||||
|
upstream_schedule_netreq(upstream, starttls_netreq);
|
||||||
|
/* Schedule at least the timeout locally.
|
||||||
|
* And also the write if we perform a synchronous lookup */
|
||||||
|
/* TODO[TLS]: How should we handle timeout on STARTTLS negotiation?*/
|
||||||
|
GETDNS_SCHEDULE_EVENT(
|
||||||
|
dnsreq->loop, upstream->fd, dnsreq->context->timeout,
|
||||||
|
getdns_eventloop_event_init(&starttls_netreq->event,
|
||||||
|
starttls_netreq, NULL, (dnsreq->loop != upstream->loop
|
||||||
|
? netreq_upstream_write_cb : NULL), stub_timeout_cb));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
/* Nothing to do*/
|
/* Nothing to do*/
|
||||||
}
|
}
|
||||||
if (fd != -1) {
|
|
||||||
upstream->loop = context->extension;
|
|
||||||
upstream->fd = fd;
|
|
||||||
}
|
|
||||||
#ifdef TLS_DEBUG
|
|
||||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): created new connection %d\n", fd);
|
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): created new connection %d\n", fd);
|
||||||
#endif
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getdns_upstream*
|
||||||
|
pick_and_connect_to_upstream(getdns_network_req *netreq,
|
||||||
|
getdns_base_transport_t transport,
|
||||||
|
int *fd)
|
||||||
|
{
|
||||||
|
/* TODO[TLS]: Fallback through upstreams....?*/
|
||||||
|
getdns_upstream *upstream = pick_upstream(netreq, transport);
|
||||||
|
if (!upstream)
|
||||||
|
return NULL;
|
||||||
|
*fd = connect_to_upstream(upstream, transport, netreq->owner);
|
||||||
|
return upstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_upstream_for_netreq(getdns_network_req *netreq)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
for (int i = 0; i < GETDNS_BASE_TRANSPORT_MAX &&
|
||||||
|
netreq->dns_base_transports[i] != GETDNS_BASE_TRANSPORT_NONE; i++) {
|
||||||
|
netreq->upstream = pick_and_connect_to_upstream(netreq,
|
||||||
|
netreq->dns_base_transports[i],
|
||||||
|
&fd);
|
||||||
|
if (fd == -1)
|
||||||
|
continue;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
move_netreq(getdns_network_req *netreq, getdns_upstream *upstream,
|
||||||
|
getdns_upstream *new_upstream)
|
||||||
|
{
|
||||||
|
/* Remove from queue, clearing event and fd if we are the last*/
|
||||||
|
|
||||||
|
fprintf(stderr,"[TLS]: FALLBACK(move_netreq)\n");
|
||||||
|
|
||||||
|
if (!(upstream->write_queue = netreq->write_queue_tail)) {
|
||||||
|
upstream->write_queue_last = NULL;
|
||||||
|
upstream->event.write_cb = NULL;
|
||||||
|
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
|
||||||
|
close(upstream->fd);
|
||||||
|
upstream->fd = -1;
|
||||||
|
}
|
||||||
|
netreq->write_queue_tail = NULL;
|
||||||
|
|
||||||
|
/* Schedule with the new upstream */
|
||||||
|
netreq->upstream = new_upstream;
|
||||||
|
upstream_schedule_netreq(new_upstream, netreq);
|
||||||
|
|
||||||
|
/* TODO[TLS]: Timout need to be adjusted and rescheduled on the new fd ...*/
|
||||||
|
/* Note, setup timeout should be shorter than message timeout for
|
||||||
|
* messages with fallback or don't have time to re-try. */
|
||||||
|
|
||||||
|
/* For sync messages we must re-schedule the events here.*/
|
||||||
|
if (netreq->owner->loop != upstream->loop) {
|
||||||
|
/* Create an event for the new upstream*/
|
||||||
|
GETDNS_CLEAR_EVENT(netreq->owner->loop, &netreq->event);
|
||||||
|
GETDNS_SCHEDULE_EVENT(
|
||||||
|
netreq->owner->loop, new_upstream->fd, netreq->owner->context->timeout,
|
||||||
|
getdns_eventloop_event_init(&netreq->event, netreq,
|
||||||
|
( new_upstream->netreq_by_query_id.count ?
|
||||||
|
netreq_upstream_read_cb : NULL ),
|
||||||
|
( new_upstream->write_queue ?
|
||||||
|
netreq_upstream_write_cb : NULL),
|
||||||
|
stub_timeout_cb));
|
||||||
|
|
||||||
|
/* Now one for the old upstream. Must schedule this last to make sure
|
||||||
|
* it is called back first....?*/
|
||||||
|
if (upstream->write_queue) {
|
||||||
|
GETDNS_CLEAR_EVENT(netreq->owner->loop, &upstream->write_queue->event);
|
||||||
|
GETDNS_SCHEDULE_EVENT(
|
||||||
|
upstream->write_queue->owner->loop, upstream->fd,
|
||||||
|
upstream->write_queue->owner->context->timeout,
|
||||||
|
getdns_eventloop_event_init(&upstream->write_queue->event,
|
||||||
|
upstream->write_queue,
|
||||||
|
( upstream->netreq_by_query_id.count ?
|
||||||
|
netreq_upstream_read_cb : NULL ),
|
||||||
|
( upstream->write_queue ?
|
||||||
|
netreq_upstream_write_cb : NULL),
|
||||||
|
stub_timeout_cb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netreq->dns_base_transport++;
|
||||||
|
return upstream->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
fallback_on_write(getdns_network_req *netreq)
|
||||||
|
{
|
||||||
|
|
||||||
|
fprintf(stderr,"[TLS]: FALLBACK(fallback_on_write)\n");
|
||||||
|
|
||||||
|
/* TODO[TLS]: Fallback through all transports.*/
|
||||||
|
getdns_base_transport_t *next_transport = netreq->dns_base_transport;
|
||||||
|
if (*(++next_transport) == GETDNS_BASE_TRANSPORT_NONE)
|
||||||
|
return STUB_TCP_ERROR;
|
||||||
|
|
||||||
|
if (*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_STARTTLS &&
|
||||||
|
*next_transport == GETDNS_BASE_TRANSPORT_TCP) {
|
||||||
|
fprintf(stderr,"[TLS]: FALLBACK(fallback_on_write) STARTTLS->TCP\n");
|
||||||
|
/* Special case where can stay on same upstream*/
|
||||||
|
netreq->dns_base_transport++;
|
||||||
|
return netreq->upstream->fd;
|
||||||
|
}
|
||||||
|
getdns_upstream *upstream = netreq->upstream;
|
||||||
|
int fd;
|
||||||
|
getdns_upstream *new_upstream =
|
||||||
|
pick_and_connect_to_upstream(netreq, *next_transport, &fd);
|
||||||
|
if (!new_upstream)
|
||||||
|
return STUB_TCP_ERROR;
|
||||||
|
return move_netreq(netreq, upstream, new_upstream);
|
||||||
|
}
|
||||||
|
|
||||||
getdns_return_t
|
getdns_return_t
|
||||||
priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
int i;
|
|
||||||
getdns_dns_req *dnsreq = netreq->owner;
|
getdns_dns_req *dnsreq = netreq->owner;
|
||||||
getdns_upstream *upstream = NULL;
|
|
||||||
|
|
||||||
/* This loop does a best effort to get a initial fd falling back through
|
/* This does a best effort to get a initial fd.
|
||||||
* transport (then upstream?). All other set up is done async*/
|
* All other set up is done async*/
|
||||||
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
|
fd = find_upstream_for_netreq(netreq);
|
||||||
netreq->dns_base_transports[i] = dnsreq->context->dns_base_transports[i];
|
|
||||||
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX &&
|
|
||||||
netreq->dns_base_transports[i] != GETDNS_BASE_TRANSPORT_NONE; i++) {
|
|
||||||
/*TODO[TLS]: Loop over upstreams, but don't loop more than once*/
|
|
||||||
upstream = pick_upstream(netreq, netreq->dns_base_transports[i]);
|
|
||||||
if (!upstream) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fd = connect_to_upstream(upstream, netreq->dns_base_transports[i],
|
|
||||||
dnsreq->context);
|
|
||||||
if (fd != -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return GETDNS_RETURN_GENERIC_ERROR;
|
return GETDNS_RETURN_GENERIC_ERROR;
|
||||||
|
|
||||||
netreq->upstream = upstream;
|
|
||||||
netreq->dns_base_transport = &(netreq->dns_base_transports[i]);
|
|
||||||
|
|
||||||
switch(*netreq->dns_base_transport) {
|
switch(*netreq->dns_base_transport) {
|
||||||
case GETDNS_BASE_TRANSPORT_UDP:
|
case GETDNS_BASE_TRANSPORT_UDP:
|
||||||
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
|
case GETDNS_BASE_TRANSPORT_TCP_SINGLE:
|
||||||
|
@ -1430,16 +1620,17 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
||||||
stub_udp_write_cb: stub_tcp_write_cb), stub_timeout_cb));
|
stub_udp_write_cb: stub_tcp_write_cb), stub_timeout_cb));
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
|
||||||
|
case GETDNS_BASE_TRANSPORT_STARTTLS:
|
||||||
case GETDNS_BASE_TRANSPORT_TCP:
|
case GETDNS_BASE_TRANSPORT_TCP:
|
||||||
case GETDNS_BASE_TRANSPORT_TLS:
|
case GETDNS_BASE_TRANSPORT_TLS:
|
||||||
|
|
||||||
upstream_schedule_netreq(upstream, netreq);
|
upstream_schedule_netreq(netreq->upstream, netreq);
|
||||||
/* TODO[TLS]: Timeout handling for async calls must change....
|
/* TODO[TLS]: Timeout handling for async calls must change....
|
||||||
* Maybe even change scheduling for sync calls here too*/
|
* Maybe even change scheduling for sync calls here too*/
|
||||||
GETDNS_SCHEDULE_EVENT(
|
GETDNS_SCHEDULE_EVENT(
|
||||||
dnsreq->loop, upstream->fd, dnsreq->context->timeout,
|
dnsreq->loop, netreq->upstream->fd, dnsreq->context->timeout,
|
||||||
getdns_eventloop_event_init(&netreq->event, netreq, NULL,
|
getdns_eventloop_event_init(&netreq->event, netreq, NULL,
|
||||||
( dnsreq->loop != upstream->loop /* Synchronous lookup? */
|
( dnsreq->loop != netreq->upstream->loop /* Synchronous lookup? */
|
||||||
? netreq_upstream_write_cb : NULL), stub_timeout_cb));
|
? netreq_upstream_write_cb : NULL), stub_timeout_cb));
|
||||||
|
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
|
|
|
@ -121,6 +121,7 @@ print_usage(FILE *out, const char *progname)
|
||||||
fprintf(out, "\t-O\tSet transport to TCP only keep connections open\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");
|
fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n");
|
||||||
fprintf(out, "\t-E\tSet transport to TLS with TCP fallback only keep connections open\n");
|
fprintf(out, "\t-E\tSet transport to TLS 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-B\tBatch mode. Schedule all messages before processing responses.\n");
|
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
|
||||||
|
@ -369,6 +370,10 @@ getdns_return_t parse_args(int argc, char **argv)
|
||||||
getdns_context_set_dns_transport(context,
|
getdns_context_set_dns_transport(context,
|
||||||
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
|
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
getdns_context_set_dns_transport(context,
|
||||||
|
GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
|
||||||
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
getdns_context_set_dns_transport(context,
|
getdns_context_set_dns_transport(context,
|
||||||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
||||||
|
|
|
@ -165,12 +165,13 @@ typedef struct getdns_tcp_state {
|
||||||
} getdns_tcp_state;
|
} getdns_tcp_state;
|
||||||
|
|
||||||
typedef enum getdns_base_transport {
|
typedef enum getdns_base_transport {
|
||||||
GETDNS_BASE_TRANSPORT_NONE,
|
GETDNS_BASE_TRANSPORT_MIN = 0,
|
||||||
|
GETDNS_BASE_TRANSPORT_NONE = 0,
|
||||||
GETDNS_BASE_TRANSPORT_UDP,
|
GETDNS_BASE_TRANSPORT_UDP,
|
||||||
GETDNS_BASE_TRANSPORT_TCP_SINGLE, /* To be removed? */
|
GETDNS_BASE_TRANSPORT_TCP_SINGLE, /* To be removed? */
|
||||||
GETDNS_BASE_TRANSPORT_TCP,
|
GETDNS_BASE_TRANSPORT_TCP,
|
||||||
GETDNS_BASE_TRANSPORT_TLS,
|
GETDNS_BASE_TRANSPORT_TLS,
|
||||||
GETDNS_BASE_TRANSPORT_STARTTLS, /* Not yet implemented*/
|
GETDNS_BASE_TRANSPORT_STARTTLS,
|
||||||
GETDNS_BASE_TRANSPORT_MAX
|
GETDNS_BASE_TRANSPORT_MAX
|
||||||
} getdns_base_transport_t;
|
} getdns_base_transport_t;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue