mirror of https://github.com/getdnsapi/getdns.git
Enable GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN for libunbound. Should only be used in stub mode.
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN still just does TCP. Also some tidy up of new transport types.
This commit is contained in:
parent
99c1973fae
commit
ab4fb8d9e9
|
@ -521,7 +521,8 @@ upstream_scope_id(getdns_upstream *upstream)
|
|||
}
|
||||
|
||||
static void
|
||||
upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
|
||||
upstream_ntop_buf(getdns_upstream *upstream, getdns_transport_t transport,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
/* Also possible but prints scope_id by name (nor parsed by unbound)
|
||||
*
|
||||
|
@ -533,9 +534,14 @@ 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));
|
||||
if (upstream_port(upstream) != 53 && upstream_port(upstream) != 0)
|
||||
if (transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
|
||||
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
||||
"@%d", (int)upstream_port(upstream));
|
||||
"@%d", GETDNS_TLS_PORT);
|
||||
else {
|
||||
if (upstream_port(upstream) != 53 && upstream_port(upstream) != 0)
|
||||
(void) snprintf(buf + strlen(buf), len - strlen(buf),
|
||||
"@%d", (int)upstream_port(upstream));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -809,6 +815,9 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
|
||||
|
||||
/* unbound context is initialized here */
|
||||
/* Unbound needs SSL to be init'ed this early when TLS is used. However we
|
||||
* don't know that till later so we will have to do this every time. */
|
||||
SSL_library_init();
|
||||
result->unbound_ctx = NULL;
|
||||
if ((r = rebuild_ub_ctx(result)))
|
||||
goto error;
|
||||
|
@ -1125,6 +1134,33 @@ getdns_context_set_namespaces(struct getdns_context *context,
|
|||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_namespaces */
|
||||
|
||||
getdns_transport_t
|
||||
priv_get_transport(getdns_transport_t transport, int level) {
|
||||
if (!(level == 0 || level == 1)) return GETDNS_TRANSPORT_NONE;
|
||||
switch (transport) {
|
||||
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
|
||||
if (level == 0) return GETDNS_TRANSPORT_UDP;
|
||||
if (level == 1) return GETDNS_TRANSPORT_TCP;
|
||||
case GETDNS_TRANSPORT_UDP_ONLY:
|
||||
if (level == 0) return GETDNS_TRANSPORT_UDP;
|
||||
if (level == 1) return GETDNS_TRANSPORT_NONE;
|
||||
case GETDNS_TRANSPORT_TCP_ONLY:
|
||||
if (level == 0) return GETDNS_TRANSPORT_TCP_SINGLE;
|
||||
if (level == 1) return GETDNS_TRANSPORT_NONE;
|
||||
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return GETDNS_TRANSPORT_TCP;
|
||||
if (level == 1) return GETDNS_TRANSPORT_NONE;
|
||||
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return GETDNS_TRANSPORT_TLS;
|
||||
if (level == 1) return GETDNS_TRANSPORT_NONE;
|
||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return GETDNS_TRANSPORT_TLS;
|
||||
if (level == 1) return GETDNS_TRANSPORT_TCP;
|
||||
default:
|
||||
return GETDNS_TRANSPORT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static getdns_return_t
|
||||
set_ub_dns_transport(struct getdns_context* context,
|
||||
getdns_transport_t value) {
|
||||
|
@ -1138,22 +1174,22 @@ set_ub_dns_transport(struct getdns_context* context,
|
|||
set_ub_string_opt(context, "do-tcp:", "no");
|
||||
break;
|
||||
case GETDNS_TRANSPORT_TCP_ONLY:
|
||||
/* Note: no pipelining available directly in unbound.*/
|
||||
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
set_ub_string_opt(context, "do-udp:", "no");
|
||||
set_ub_string_opt(context, "do-tcp:", "yes");
|
||||
break;
|
||||
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
/* Hum. If used in recursive mode this will try TLS on port 53...
|
||||
* So we need to fix or document that or delay setting it until
|
||||
* resolution.*/
|
||||
set_ub_string_opt(context, "ssl-upstream:", "yes");
|
||||
/* Fall through*/
|
||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
/* TODO: Investigate why ssl-upstream in Unbound isn't working (error
|
||||
* that the SSL lib isn't init'ed but that is done in prep_for_res.
|
||||
* Note: no fallback or pipelining available directly in unbound.*/
|
||||
/* Note: no fallback to TCP available directly in unbound, so we just
|
||||
* use TCP for now to make sure the messages are sent. */
|
||||
set_ub_string_opt(context, "do-udp:", "no");
|
||||
set_ub_string_opt(context, "do-tcp:", "yes");
|
||||
/* set_ub_string_opt(context, "ssl-upstream:", "yes");*/
|
||||
/* TODO: Specifying a different port to do TLS on in unbound is a bit
|
||||
* tricky as it involves modifying each fwd upstream defined on the
|
||||
* unbound ctx... And to support fallback this would have to be reset
|
||||
* from the stub code while trying to connect...*/
|
||||
break;
|
||||
default:
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
|
@ -1695,17 +1731,18 @@ getdns_cancel_callback(getdns_context *context,
|
|||
} /* getdns_cancel_callback */
|
||||
|
||||
static getdns_return_t
|
||||
ub_setup_stub(struct ub_ctx *ctx, getdns_upstreams *upstreams)
|
||||
ub_setup_stub(struct ub_ctx *ctx, struct getdns_context *context)
|
||||
{
|
||||
getdns_return_t r = GETDNS_RETURN_GOOD;
|
||||
size_t i;
|
||||
getdns_upstream *upstream;
|
||||
char addr[1024];
|
||||
|
||||
getdns_upstreams *upstreams = context->upstreams;
|
||||
(void) ub_ctx_set_fwd(ctx, NULL);
|
||||
for (i = 0; i < upstreams->count; i++) {
|
||||
upstream = &upstreams->upstreams[i];
|
||||
upstream_ntop_buf(upstream, addr, 1024);
|
||||
upstream_ntop_buf(upstream, context->dns_transport, addr, 1024);
|
||||
ub_ctx_set_fwd(ctx, addr);
|
||||
}
|
||||
|
||||
|
@ -1777,7 +1814,7 @@ priv_getdns_ns_dns_setup(struct getdns_context *context)
|
|||
case GETDNS_RESOLUTION_STUB:
|
||||
if (!context->upstreams || !context->upstreams->count)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
return ub_setup_stub(context->unbound_ctx, context->upstreams);
|
||||
return ub_setup_stub(context->unbound_ctx, context);
|
||||
|
||||
case GETDNS_RESOLUTION_RECURSING:
|
||||
/* TODO: use the root servers via root hints file */
|
||||
|
@ -1805,9 +1842,6 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
|
|||
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
if (context->tls_ctx == NULL) {
|
||||
/* Init the SSL library */
|
||||
SSL_library_init();
|
||||
|
||||
/* Create client context, use TLS v1.2 only for now */
|
||||
SSL_CTX* tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
|
||||
if(!tls_ctx) {
|
||||
|
|
|
@ -49,6 +49,7 @@ struct ub_ctx;
|
|||
|
||||
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
|
||||
#define GETDNS_FN_HOSTS "/etc/hosts"
|
||||
#define GETDNS_TLS_PORT 1021
|
||||
|
||||
enum filechgs { GETDNS_FCHG_ERRORS = -1
|
||||
, GETDNS_FCHG_NOERROR = 0
|
||||
|
@ -71,6 +72,14 @@ struct filechg {
|
|||
struct stat *prevstat;
|
||||
};
|
||||
|
||||
typedef enum getdns_base_transport {
|
||||
GETDNS_TRANSPORT_NONE,
|
||||
GETDNS_TRANSPORT_UDP,
|
||||
GETDNS_TRANSPORT_TCP_SINGLE,
|
||||
GETDNS_TRANSPORT_TCP,
|
||||
GETDNS_TRANSPORT_TLS
|
||||
} getdns_base_transport_t;
|
||||
|
||||
typedef struct getdns_upstream {
|
||||
struct getdns_upstreams *upstreams;
|
||||
|
||||
|
@ -222,4 +231,6 @@ int filechg_check(struct getdns_context *context, struct filechg *fchg);
|
|||
|
||||
void priv_getdns_context_ub_read_cb(void *userarg);
|
||||
|
||||
getdns_transport_t priv_get_transport(getdns_transport_t transport, int level);
|
||||
|
||||
#endif /* _GETDNS_CONTEXT_H_ */
|
||||
|
|
71
src/stub.c
71
src/stub.c
|
@ -41,8 +41,6 @@
|
|||
#include "util-internal.h"
|
||||
#include "general.h"
|
||||
|
||||
#define TLS_PORT 1021
|
||||
|
||||
static time_t secret_rollover_time = 0;
|
||||
static uint32_t secret = 0;
|
||||
static uint32_t prev_secret = 0;
|
||||
|
@ -656,7 +654,7 @@ sock_connected(int sockfd)
|
|||
/* The connection testing and handshake should be handled by integrating this
|
||||
* with the event loop framework, but for now just implement a standalone
|
||||
* handshake method.*/
|
||||
SSL*
|
||||
static SSL*
|
||||
do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
|
||||
{
|
||||
/*Lets make sure the connection is up before we try a handshake*/
|
||||
|
@ -1158,7 +1156,7 @@ get_port(struct sockaddr_storage* addr)
|
|||
: ((struct sockaddr_in6*)addr)->sin6_port);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
set_port(struct sockaddr_storage* addr, in_port_t port)
|
||||
{
|
||||
addr->ss_family == AF_INET
|
||||
|
@ -1166,42 +1164,7 @@ set_port(struct sockaddr_storage* addr, in_port_t port)
|
|||
: (((struct sockaddr_in6*)addr)->sin6_port = htons(port));
|
||||
}
|
||||
|
||||
typedef enum getdns_base_transport {
|
||||
NONE,
|
||||
UDP,
|
||||
TCP_SINGLE,
|
||||
TCP,
|
||||
TLS
|
||||
} getdns_base_transport_t;
|
||||
|
||||
getdns_transport_t
|
||||
get_transport(getdns_transport_t transport, int level) {
|
||||
if (!(level == 0 || level == 1)) return NONE;
|
||||
switch (transport) {
|
||||
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
|
||||
if (level == 0) return UDP;
|
||||
if (level == 1) return TCP;
|
||||
case GETDNS_TRANSPORT_UDP_ONLY:
|
||||
if (level == 0) return UDP;
|
||||
if (level == 1) return NONE;
|
||||
case GETDNS_TRANSPORT_TCP_ONLY:
|
||||
if (level == 0) return TCP_SINGLE;
|
||||
if (level == 1) return NONE;
|
||||
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return TCP;
|
||||
if (level == 1) return NONE;
|
||||
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return TLS;
|
||||
if (level == 1) return NONE;
|
||||
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
|
||||
if (level == 0) return TLS;
|
||||
if (level == 1) return TCP;
|
||||
default:
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
|
||||
|
||||
int fd =-1;
|
||||
|
@ -1210,10 +1173,11 @@ tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
|
|||
socklen_t addr_len = upstream->addr_len;
|
||||
|
||||
/* TODO[TLS]: For now, override the port to a hardcoded value*/
|
||||
if (transport == TLS && (int)get_port(addr) != TLS_PORT) {
|
||||
if (transport == GETDNS_TRANSPORT_TLS &&
|
||||
(int)get_port(addr) != GETDNS_TLS_PORT) {
|
||||
connect_addr = upstream->addr;
|
||||
addr = &connect_addr;
|
||||
set_port(addr, TLS_PORT);
|
||||
set_port(addr, GETDNS_TLS_PORT);
|
||||
}
|
||||
|
||||
if ((fd = socket(addr->ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
|
@ -1222,7 +1186,8 @@ tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
|
|||
getdns_sock_nonblock(fd);
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
/* Leave the connect to the later call to sendto() if using TCP*/
|
||||
if (transport == TCP || transport == TCP_SINGLE)
|
||||
if (transport == GETDNS_TRANSPORT_TCP ||
|
||||
transport == GETDNS_TRANSPORT_TCP_SINGLE)
|
||||
return fd;
|
||||
#endif
|
||||
if (connect(fd, (struct sockaddr *)addr,
|
||||
|
@ -1245,12 +1210,12 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
||||
// Work out the primary and fallback transport options
|
||||
getdns_base_transport_t transport = get_transport(
|
||||
getdns_base_transport_t transport = priv_get_transport(
|
||||
dnsreq->context->dns_transport,0);
|
||||
getdns_base_transport_t fb_transport = get_transport(
|
||||
getdns_base_transport_t fb_transport = priv_get_transport(
|
||||
dnsreq->context->dns_transport,1);
|
||||
switch(transport) {
|
||||
case UDP:
|
||||
case GETDNS_TRANSPORT_UDP:
|
||||
|
||||
if ((netreq->fd = socket(
|
||||
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
|
@ -1266,7 +1231,7 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
||||
case TCP_SINGLE:
|
||||
case GETDNS_TRANSPORT_TCP_SINGLE:
|
||||
|
||||
if ((netreq->fd = tcp_connect(upstream, transport)) == -1)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
@ -1279,8 +1244,8 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
|
||||
case TCP:
|
||||
case TLS:
|
||||
case GETDNS_TRANSPORT_TCP:
|
||||
case GETDNS_TRANSPORT_TLS:
|
||||
|
||||
/* In coming comments, "global" means "context wide" */
|
||||
|
||||
|
@ -1293,7 +1258,7 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
|
||||
/* We are the first. Make global socket and connect. */
|
||||
if ((upstream->fd = tcp_connect(upstream, transport)) == -1) {
|
||||
if (fb_transport == NONE)
|
||||
if (fb_transport == GETDNS_TRANSPORT_NONE)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
|
@ -1302,10 +1267,10 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
|
||||
/* Now do a handshake for TLS. Note waiting for this to succeed or
|
||||
* timeout blocks the scheduling of any messages for this upstream*/
|
||||
if (transport == TLS && (fallback == 0)) {
|
||||
if (transport == GETDNS_TRANSPORT_TLS && (fallback == 0)) {
|
||||
upstream->tls_obj = do_tls_handshake(dnsreq, upstream);
|
||||
if (!upstream->tls_obj) {
|
||||
if (fb_transport == NONE)
|
||||
if (fb_transport == GETDNS_TRANSPORT_NONE)
|
||||
return GETDNS_RETURN_GENERIC_ERROR;
|
||||
close(upstream->fd);
|
||||
if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
|
||||
|
@ -1319,7 +1284,7 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
|
|||
} else {
|
||||
/* Cater for the case of the user downgrading and existing TLS
|
||||
connection to TCP for some reason...*/
|
||||
if (transport == TCP && upstream->tls_obj) {
|
||||
if (transport == GETDNS_TRANSPORT_TCP && upstream->tls_obj) {
|
||||
SSL_shutdown(upstream->tls_obj);
|
||||
SSL_free(upstream->tls_obj);
|
||||
upstream->tls_obj = NULL;
|
||||
|
|
Loading…
Reference in New Issue