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 },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
{ 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 },
|
||||
|
|
|
@ -53,6 +53,13 @@
|
|||
#include "stub.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;
|
||||
|
||||
typedef struct host_name_addrs {
|
||||
|
@ -63,15 +70,23 @@ typedef struct host_name_addrs {
|
|||
} host_name_addrs;
|
||||
|
||||
static in_port_t
|
||||
getdns_port_array[GETDNS_PORT_LAST] = {
|
||||
GETDNS_PORT_NUM_TCP,
|
||||
GETDNS_PORT_NUM_TLS
|
||||
getdns_port_array[GETDNS_BASE_TRANSPORT_MAX] = {
|
||||
GETDNS_PORT_ZERO,
|
||||
GETDNS_PORT_ZERO,
|
||||
GETDNS_PORT_ZERO,
|
||||
GETDNS_PORT_TCP,
|
||||
GETDNS_PORT_TLS,
|
||||
GETDNS_PORT_TCP
|
||||
};
|
||||
|
||||
char*
|
||||
getdns_port_str_array[] = {
|
||||
GETDNS_PORT_STR_TCP,
|
||||
GETDNS_PORT_STR_TLS
|
||||
GETDNS_STR_PORT_ZERO,
|
||||
GETDNS_STR_PORT_ZERO,
|
||||
GETDNS_STR_PORT_ZERO,
|
||||
GETDNS_STR_PORT_TCP,
|
||||
GETDNS_STR_PORT_TLS,
|
||||
GETDNS_STR_PORT_TCP
|
||||
};
|
||||
|
||||
/* Private functions */
|
||||
|
@ -252,7 +267,7 @@ sockaddr_dict(getdns_context *context, struct sockaddr *sa)
|
|||
break;
|
||||
|
||||
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))
|
||||
break;
|
||||
|
||||
|
@ -268,7 +283,7 @@ sockaddr_dict(getdns_context *context, struct sockaddr *sa)
|
|||
break;
|
||||
|
||||
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))
|
||||
break;
|
||||
|
||||
|
@ -538,7 +553,7 @@ upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
|
|||
if (upstream_scope_id(upstream))
|
||||
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
||||
"%%%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),
|
||||
"@%d", (int)upstream_port(upstream));
|
||||
}
|
||||
|
@ -565,8 +580,8 @@ upstream_init(getdns_upstream *upstream,
|
|||
/* For sharing a socket to this upstream with TCP */
|
||||
upstream->fd = -1;
|
||||
upstream->tls_obj = NULL;
|
||||
upstream->dns_base_transport = (upstream_port(upstream) == GETDNS_PORT_NUM_TLS ?
|
||||
GETDNS_BASE_TRANSPORT_TLS : GETDNS_BASE_TRANSPORT_TCP);
|
||||
upstream->starttls_req = NULL;
|
||||
upstream->dns_base_transport = GETDNS_BASE_TRANSPORT_TCP;
|
||||
upstream->tls_hs_state = GETDNS_HS_NONE;
|
||||
upstream->loop = NULL;
|
||||
(void) getdns_eventloop_event_init(
|
||||
|
@ -670,9 +685,12 @@ set_os_defaults(struct getdns_context *context)
|
|||
token = parse + strcspn(parse, " \t\r\n");
|
||||
*token = 0;
|
||||
|
||||
getdns_port_type_t port_type = GETDNS_PORT_FIRST;
|
||||
for (; port_type < GETDNS_PORT_LAST; port_type++) {
|
||||
if ((s = getaddrinfo(parse, getdns_port_str_array[port_type], &hints, &result)))
|
||||
getdns_base_transport_t base_transport = GETDNS_BASE_TRANSPORT_MIN;
|
||||
for (; base_transport < GETDNS_BASE_TRANSPORT_MAX; base_transport++) {
|
||||
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;
|
||||
|
||||
/* No lookups, so maximal 1 result */
|
||||
|
@ -686,6 +704,7 @@ set_os_defaults(struct getdns_context *context)
|
|||
upstream = &context->upstreams->
|
||||
upstreams[context->upstreams->count++];
|
||||
upstream_init(upstream, context->upstreams, result);
|
||||
upstream->dns_base_transport = base_transport;
|
||||
}
|
||||
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[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:
|
||||
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");
|
||||
/* Fall through*/
|
||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
case GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
/* Note: no fallback to TCP available directly in unbound, so we just
|
||||
* use TCP for now to make sure the messages are sent. */
|
||||
set_ub_string_opt(context, "do-udp:", "no");
|
||||
|
@ -1482,11 +1507,12 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
hints.ai_addr = 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++) {
|
||||
/* Loop twice to create TCP and TLS upstreams*/
|
||||
getdns_port_type_t port_type = GETDNS_PORT_FIRST;
|
||||
for (; port_type < GETDNS_PORT_LAST; port_type++) {
|
||||
/* Loop to create upstreams as needed*/
|
||||
getdns_base_transport_t base_transport = GETDNS_BASE_TRANSPORT_MIN;
|
||||
for (; base_transport < GETDNS_BASE_TRANSPORT_MAX; base_transport++) {
|
||||
getdns_dict *dict;
|
||||
getdns_bindata *address_type;
|
||||
getdns_bindata *address_data;
|
||||
|
@ -1495,6 +1521,11 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
struct addrinfo *ai;
|
||||
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];
|
||||
if ((r = getdns_list_get_dict(upstream_list, i, &dict)))
|
||||
goto error;
|
||||
|
@ -1522,8 +1553,6 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
addrstr, 1024) == NULL)
|
||||
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) snprintf(portstr, 1024, "%d", (int)port);
|
||||
|
||||
|
@ -1541,6 +1570,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
goto invalid_parameter;
|
||||
|
||||
upstream_init(upstream, upstreams, ai);
|
||||
upstream->dns_base_transport = base_transport;
|
||||
upstreams->count++;
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
@ -1764,9 +1794,9 @@ ub_setup_stub(struct ub_ctx *ctx, getdns_context *context)
|
|||
upstream = &upstreams->upstreams[i];
|
||||
/*[TLS]: Use only the subset of upstreams that match the first transport */
|
||||
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;
|
||||
} else if (upstream_port(upstream) != GETDNS_PORT_NUM_TCP)
|
||||
} else if (upstream_port(upstream) != GETDNS_PORT_TCP)
|
||||
continue;
|
||||
upstream_ntop_buf(upstream, addr, 1024);
|
||||
ub_ctx_set_fwd(ctx, addr);
|
||||
|
|
|
@ -49,10 +49,6 @@ struct ub_ctx;
|
|||
|
||||
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
|
||||
#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
|
||||
, GETDNS_FCHG_NOERROR = 0
|
||||
|
@ -75,13 +71,6 @@ struct filechg {
|
|||
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 {
|
||||
GETDNS_HS_NONE,
|
||||
GETDNS_HS_WRITE,
|
||||
|
@ -102,9 +91,10 @@ typedef struct getdns_upstream {
|
|||
|
||||
/* For sharing a TCP socket to this upstream */
|
||||
int fd;
|
||||
SSL* tls_obj;
|
||||
getdns_base_transport_t dns_base_transport;
|
||||
SSL* tls_obj;
|
||||
getdns_tls_hs_state_t tls_hs_state;
|
||||
getdns_dns_req * starttls_req;
|
||||
getdns_eventloop_event event;
|
||||
getdns_eventloop *loop;
|
||||
getdns_tcp_state tcp;
|
||||
|
|
|
@ -165,7 +165,8 @@ typedef enum getdns_transport_t {
|
|||
GETDNS_TRANSPORT_TCP_ONLY = 542,
|
||||
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN = 543,
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -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_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
|
||||
#define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
|
||||
#define GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
|
|
@ -89,8 +89,8 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
|
||||
net_req->upstream = NULL;
|
||||
net_req->fd = -1;
|
||||
priv_set_base_dns_transports(net_req->dns_base_transports,
|
||||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
||||
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
|
||||
net_req->dns_base_transports[i] = owner->context->dns_base_transports[i];
|
||||
net_req->dns_base_transport = net_req->dns_base_transports;
|
||||
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
||||
|
|
543
src/stub.c
543
src/stub.c
|
@ -36,17 +36,17 @@
|
|||
#include "stub.h"
|
||||
#include "gldns/gbuffer.h"
|
||||
#include "gldns/pkthdr.h"
|
||||
#include "gldns/rrdef.h"
|
||||
#include "gldns/str2wire.h"
|
||||
#include "rr-iter.h"
|
||||
#include "context.h"
|
||||
#include <ldns/util.h>
|
||||
#include "util-internal.h"
|
||||
#include "general.h"
|
||||
|
||||
#define STUB_TLS_SETUP_ERROR -3
|
||||
#define STUB_TCP_AGAIN -2
|
||||
#define STUB_TCP_ERROR -1
|
||||
|
||||
/*TODO[TLS]: REMOVE!!!!!*/
|
||||
#define TLS_DEBUG 1
|
||||
#define STUB_TLS_SETUP_ERROR -4
|
||||
#define STUB_TCP_AGAIN -3
|
||||
#define STUB_TCP_ERROR -2
|
||||
|
||||
static time_t secret_rollover_time = 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_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,
|
||||
getdns_network_req *netreq);
|
||||
static void netreq_upstream_read_cb(void *userarg);
|
||||
static void netreq_upstream_write_cb(void *userarg);
|
||||
static int fallback_on_write(getdns_network_req *netreq);
|
||||
|
||||
static void
|
||||
rollover_secret()
|
||||
|
@ -233,6 +230,108 @@ match_and_process_server_cookie(
|
|||
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 */
|
||||
static void
|
||||
getdns_sock_nonblock(int sockfd)
|
||||
|
@ -323,9 +422,9 @@ static void
|
|||
upstream_erred(getdns_upstream *upstream)
|
||||
{
|
||||
getdns_network_req *netreq;
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: ERROR(upstream_erred)\n");
|
||||
#endif
|
||||
|
||||
while ((netreq = upstream->write_queue)) {
|
||||
stub_cleanup(netreq);
|
||||
netreq->state = NET_REQ_FINISHED;
|
||||
|
@ -347,6 +446,13 @@ upstream_erred(getdns_upstream *upstream)
|
|||
upstream->fd = -1;
|
||||
/*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
|
||||
priv_getdns_cancel_stub_request(getdns_network_req *netreq)
|
||||
|
@ -358,9 +464,9 @@ priv_getdns_cancel_stub_request(getdns_network_req *netreq)
|
|||
static void
|
||||
stub_erred(getdns_network_req *netreq)
|
||||
{
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: ERROR(stub_erred)\n");
|
||||
#endif
|
||||
|
||||
stub_next_upstream(netreq);
|
||||
stub_cleanup(netreq);
|
||||
/* 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
|
||||
stub_timeout_cb(void *userarg)
|
||||
{
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: TIMEOUT(stub_timeout_cb)\n");
|
||||
#endif
|
||||
|
||||
getdns_network_req *netreq = (getdns_network_req *)userarg;
|
||||
|
||||
stub_next_upstream(netreq);
|
||||
|
@ -488,13 +594,17 @@ stub_udp_write_cb(void *userarg)
|
|||
stub_udp_read_cb, NULL, stub_timeout_cb));
|
||||
}
|
||||
|
||||
|
||||
/* TODO[TLS]: Optimise to re-use TCP (or failed STARTTLS) where possible.*/
|
||||
static int
|
||||
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)
|
||||
return 0;
|
||||
if (transport == GETDNS_BASE_TRANSPORT_TLS &&
|
||||
upstream->tls_hs_state == GETDNS_HS_FAILED)
|
||||
if ((transport == GETDNS_BASE_TRANSPORT_TLS ||
|
||||
transport == GETDNS_BASE_TRANSPORT_STARTTLS)
|
||||
&& upstream->tls_hs_state == GETDNS_HS_FAILED)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -663,9 +773,8 @@ create_tls_object(getdns_context *context, int fd)
|
|||
static int
|
||||
do_tls_handshake(getdns_upstream *upstream)
|
||||
{
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: TLS(do_tls_handshake)\n");
|
||||
#endif
|
||||
|
||||
int r;
|
||||
int want;
|
||||
|
@ -708,85 +817,11 @@ do_tls_handshake(getdns_upstream *upstream)
|
|||
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
|
||||
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*/
|
||||
#ifdef TLS_DEBUG
|
||||
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;
|
||||
return (hs_state == GETDNS_HS_FAILED ||
|
||||
hs_state == GETDNS_HS_NONE) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -811,9 +846,8 @@ check_tls(getdns_upstream* upstream)
|
|||
if (error == EINPROGRESS || error == EWOULDBLOCK)
|
||||
return STUB_TCP_AGAIN; /* try again */
|
||||
else if (error != 0) {
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: TLS(check_tls): died gettting connection\n");
|
||||
#endif
|
||||
SSL_free(upstream->tls_obj);
|
||||
upstream->tls_obj = NULL;
|
||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||
|
@ -914,12 +948,13 @@ upstream_read_cb(void *userarg)
|
|||
uint16_t query_id;
|
||||
intptr_t query_id_intptr;
|
||||
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: **********CALLBACK***********\n");
|
||||
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,
|
||||
&upstream->upstreams->mf);
|
||||
else
|
||||
|
@ -978,7 +1013,32 @@ upstream_read_cb(void *userarg)
|
|||
netreq_upstream_write_cb : NULL),
|
||||
stub_timeout_cb));
|
||||
}
|
||||
priv_getdns_check_dns_req_complete(netreq->owner);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Nothing more to read? Then deschedule the reads.*/
|
||||
if (! upstream->netreq_by_query_id.count) {
|
||||
|
@ -1005,7 +1065,6 @@ netreq_upstream_read_cb(void *userarg)
|
|||
static int
|
||||
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;
|
||||
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
|
||||
* by query_id in the process.
|
||||
*/
|
||||
if ((dnsreq->context->dns_transport == GETDNS_TRANSPORT_TCP_ONLY) ||
|
||||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_ONLY) ||
|
||||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP))
|
||||
if ((*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_TCP_SINGLE) ||
|
||||
(*netreq->dns_base_transport == GETDNS_BASE_TRANSPORT_UDP))
|
||||
query_id = arc4random();
|
||||
else do {
|
||||
query_id = arc4random();
|
||||
|
@ -1142,7 +1200,8 @@ stub_tcp_write_cb(void *userarg)
|
|||
}
|
||||
|
||||
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;
|
||||
ssize_t written;
|
||||
|
@ -1198,17 +1257,18 @@ static void
|
|||
upstream_write_cb(void *userarg)
|
||||
{
|
||||
getdns_upstream *upstream = (getdns_upstream *)userarg;
|
||||
getdns_upstream *new_upstream;
|
||||
getdns_network_req *netreq = upstream->write_queue;
|
||||
getdns_dns_req *dnsreq = netreq->owner;
|
||||
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);
|
||||
else
|
||||
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
|
||||
|
@ -1222,17 +1282,11 @@ upstream_write_cb(void *userarg)
|
|||
return;
|
||||
|
||||
case STUB_TLS_SETUP_ERROR:
|
||||
/* Could not complete the TLS set up. Need to fallback on this upstream
|
||||
* if possible.*/
|
||||
new_upstream = pick_and_connect_to_fallback_upstream(netreq);
|
||||
if (!new_upstream) {
|
||||
//TODO[TLS]: Need a different error case here for msg_erred?
|
||||
stub_erred(netreq);
|
||||
return;
|
||||
/* Could not complete the TLS set up. Need to fallback.*/
|
||||
if (fallback_on_write(netreq) == STUB_TCP_ERROR) {
|
||||
fprintf(stderr,"[TLS]: Fallback failed.\n");
|
||||
message_erred(netreq);
|
||||
}
|
||||
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;
|
||||
|
||||
default:
|
||||
|
@ -1259,6 +1313,16 @@ upstream_write_cb(void *userarg)
|
|||
GETDNS_SCHEDULE_EVENT(upstream->loop,
|
||||
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 */
|
||||
if (netreq->event.write_cb) {
|
||||
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
|
||||
|
@ -1266,7 +1330,7 @@ upstream_write_cb(void *userarg)
|
|||
dnsreq->loop, upstream->fd, dnsreq->context->timeout,
|
||||
getdns_eventloop_event_init(&netreq->event, netreq,
|
||||
netreq_upstream_read_cb,
|
||||
( upstream->write_queue ?
|
||||
(upstream->write_queue && !upstream->starttls_req ?
|
||||
netreq_upstream_write_cb : NULL),
|
||||
stub_timeout_cb));
|
||||
}
|
||||
|
@ -1287,9 +1351,8 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
|
|||
assert(upstream->fd >= 0);
|
||||
assert(upstream->loop);
|
||||
|
||||
#ifdef TLS_DEBUG
|
||||
|
||||
fprintf(stderr,"[TLS]: SCHEDULE(upstream_schedule_netreq): fd %d\n", upstream->fd);
|
||||
#endif
|
||||
|
||||
/* Append netreq to write_queue */
|
||||
if (!upstream->write_queue) {
|
||||
|
@ -1331,25 +1394,40 @@ tcp_connect(getdns_upstream *upstream, getdns_base_transport_t transport)
|
|||
|
||||
int
|
||||
connect_to_upstream(getdns_upstream *upstream, getdns_base_transport_t transport,
|
||||
getdns_context *context)
|
||||
getdns_dns_req *dnsreq)
|
||||
{
|
||||
|
||||
if (transport == GETDNS_BASE_TRANSPORT_TCP && upstream->fd != -1) {
|
||||
#ifdef TLS_DEBUG
|
||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): tcp_connect using existing TCP fd %d\n", upstream->fd);
|
||||
#endif
|
||||
return upstream->fd;
|
||||
}
|
||||
|
||||
if (transport == GETDNS_BASE_TRANSPORT_TLS &&
|
||||
!(upstream->tls_hs_state == GETDNS_HS_FAILED
|
||||
|| upstream->tls_hs_state == GETDNS_HS_NONE)) {
|
||||
#ifdef TLS_DEBUG
|
||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream): tcp_connect using existing TLS fd %d\n", upstream->fd);
|
||||
#endif
|
||||
return upstream->fd;
|
||||
/* First check if existing connection can be used, which may still be being
|
||||
* set up. */
|
||||
switch(transport) {
|
||||
case GETDNS_BASE_TRANSPORT_TCP:
|
||||
if (upstream->fd != -1) {
|
||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream):"
|
||||
"tcp_connect using existing TCP fd %d\n", upstream->fd);
|
||||
return upstream->fd;
|
||||
}
|
||||
break;
|
||||
case GETDNS_BASE_TRANSPORT_TLS:
|
||||
if (tls_handshake_active(upstream->tls_hs_state)) {
|
||||
fprintf(stderr,"[TLS]: CONNECT(connect_to_upstream):"
|
||||
"tcp_connect using existing TLS fd %d\n", 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;
|
||||
switch(transport) {
|
||||
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:
|
||||
fd = tcp_connect(upstream, transport);
|
||||
upstream->loop = dnsreq->context->extension;
|
||||
upstream->fd = fd;
|
||||
break;
|
||||
|
||||
case GETDNS_BASE_TRANSPORT_TLS:
|
||||
fd = tcp_connect(upstream, transport);
|
||||
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) {
|
||||
fprintf(stderr,"[TLS]: could not create tls object\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
default:
|
||||
return -1;
|
||||
/* 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);
|
||||
#endif
|
||||
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
|
||||
priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
||||
{
|
||||
int fd = -1;
|
||||
int i;
|
||||
getdns_dns_req *dnsreq = netreq->owner;
|
||||
getdns_upstream *upstream = NULL;
|
||||
getdns_dns_req *dnsreq = netreq->owner;
|
||||
|
||||
/* This loop does a best effort to get a initial fd falling back through
|
||||
* transport (then upstream?). All other set up is done async*/
|
||||
for (i = 0; i < GETDNS_BASE_TRANSPORT_MAX; i++)
|
||||
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;
|
||||
}
|
||||
/* This does a best effort to get a initial fd.
|
||||
* All other set up is done async*/
|
||||
fd = find_upstream_for_netreq(netreq);
|
||||
if (fd == -1)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
netreq->upstream = upstream;
|
||||
netreq->dns_base_transport = &(netreq->dns_base_transports[i]);
|
||||
|
||||
switch(*netreq->dns_base_transport) {
|
||||
case GETDNS_BASE_TRANSPORT_UDP:
|
||||
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));
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
||||
case GETDNS_BASE_TRANSPORT_STARTTLS:
|
||||
case GETDNS_BASE_TRANSPORT_TCP:
|
||||
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....
|
||||
* Maybe even change scheduling for sync calls here too*/
|
||||
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,
|
||||
( dnsreq->loop != upstream->loop /* Synchronous lookup? */
|
||||
( dnsreq->loop != netreq->upstream->loop /* Synchronous lookup? */
|
||||
? netreq_upstream_write_cb : NULL), stub_timeout_cb));
|
||||
|
||||
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-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-R\tSet transport to STARTTLS with TCP fallback only keep connections open\n");
|
||||
fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n");
|
||||
fprintf(out, "\t-U\tSet transport to UDP only\n");
|
||||
fprintf(out, "\t-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_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
|
||||
break;
|
||||
case 'R':
|
||||
getdns_context_set_dns_transport(context,
|
||||
GETDNS_TRANSPORT_STARTTLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
|
||||
break;
|
||||
case 'u':
|
||||
getdns_context_set_dns_transport(context,
|
||||
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
|
||||
|
|
|
@ -165,12 +165,13 @@ typedef struct getdns_tcp_state {
|
|||
} getdns_tcp_state;
|
||||
|
||||
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_TCP_SINGLE, /* To be removed? */
|
||||
GETDNS_BASE_TRANSPORT_TCP,
|
||||
GETDNS_BASE_TRANSPORT_TLS,
|
||||
GETDNS_BASE_TRANSPORT_STARTTLS, /* Not yet implemented*/
|
||||
GETDNS_BASE_TRANSPORT_STARTTLS,
|
||||
GETDNS_BASE_TRANSPORT_MAX
|
||||
} getdns_base_transport_t;
|
||||
|
||||
|
|
Loading…
Reference in New Issue