From 99aa79b48f24ff3cab28dece6fb1767ee6ba48f9 Mon Sep 17 00:00:00 2001
From: saradickinson
Date: Sun, 7 Dec 2014 19:03:34 +0000
Subject: [PATCH 01/10] First pass at TLS implementation - needs work!
---
spec/index.html | 6 +-
src/const-info.c | 2 +
src/context.c | 78 +++++-
src/context.h | 2 +
src/getdns/getdns.h.in | 6 +-
src/request-internal.c | 1 +
src/stub.c | 469 ++++++++++++++++++++++++++++++++----
src/test/getdns_query.c | 140 ++++++++---
src/test/tests_stub_async.c | 6 +
src/test/tests_stub_sync.c | 6 +
src/types-internal.h | 2 +
11 files changed, 634 insertions(+), 84 deletions(-)
mode change 100644 => 100755 spec/index.html
mode change 100644 => 100755 src/const-info.c
mode change 100644 => 100755 src/getdns/getdns.h.in
mode change 100644 => 100755 src/stub.c
diff --git a/spec/index.html b/spec/index.html
old mode 100644
new mode 100755
index 9e85490f..5b25f8e1
--- a/spec/index.html
+++ b/spec/index.html
@@ -2193,8 +2193,10 @@ getdns_context_set_dns_transport(
The value is
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP
,
GETDNS_TRANSPORT_UDP_ONLY
,
-GETDNS_TRANSPORT_TCP_ONLY
, or
-GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN
.
+
getdns_return_t
diff --git a/src/const-info.c b/src/const-info.c
old mode 100644
new mode 100755
index d759765e..5c5a3d99
--- a/src/const-info.c
+++ b/src/const-info.c
@@ -39,6 +39,8 @@ static struct const_info consts_info[] = {
{ 541, "GETDNS_TRANSPORT_UDP_ONLY", GETDNS_TRANSPORT_UDP_ONLY_TEXT },
{ 542, "GETDNS_TRANSPORT_TCP_ONLY", GETDNS_TRANSPORT_TCP_ONLY_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 },
+ { 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 },
{ 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 },
diff --git a/src/context.c b/src/context.c
index b3c26c48..07c09c75 100644
--- a/src/context.c
+++ b/src/context.c
@@ -470,6 +470,24 @@ upstreams_resize(getdns_upstreams *upstreams, size_t size)
return r;
}
+static void
+upstreams_cleanup(getdns_upstreams *upstreams)
+{
+ if (!upstreams)
+ return;
+ for (int i = 0; i < (int)upstreams->count; i++) {
+ if (upstreams->upstreams[i].tls_obj != NULL) {
+ SSL_shutdown(upstreams->upstreams[i].tls_obj);
+ SSL_free(upstreams->upstreams[i].tls_obj);
+ upstreams->upstreams[i].tls_obj = NULL;
+ }
+ if (upstreams->upstreams[i].fd != -1) {
+ close(upstreams->upstreams[i].fd);
+ upstreams->upstreams[i].fd = -1;
+ }
+ }
+}
+
static void
upstreams_dereference(getdns_upstreams *upstreams)
{
@@ -541,6 +559,7 @@ upstream_init(getdns_upstream *upstream,
/* For sharing a socket to this upstream with TCP */
upstream->fd = -1;
+ upstream->tls_obj = NULL;
upstream->loop = NULL;
(void) getdns_eventloop_event_init(
&upstream->event, upstream, NULL, NULL, NULL);
@@ -770,6 +789,7 @@ getdns_context_create_with_extended_memory_functions(
result->edns_extended_rcode = 0;
result->edns_version = 0;
result->edns_do_bit = 0;
+ result-> tls_ctx = NULL;
result->extension = &result->mini_event.loop;
if ((r = getdns_mini_event_init(result, &result->mini_event)))
@@ -876,6 +896,9 @@ getdns_context_destroy(struct getdns_context *context)
GETDNS_FREE(context->my_mf, context->fchg_hosts->prevstat);
GETDNS_FREE(context->my_mf, context->fchg_hosts);
}
+ if (context->tls_ctx) {
+ SSL_CTX_free(context->tls_ctx);
+ }
getdns_list_destroy(context->dns_root_servers);
getdns_list_destroy(context->suffix);
@@ -887,6 +910,7 @@ getdns_context_destroy(struct getdns_context *context)
getdns_traverse_postorder(&context->local_hosts,
destroy_local_host, context);
+ upstreams_cleanup(context->upstreams);
upstreams_dereference(context->upstreams);
GETDNS_FREE(context->my_mf, context);
@@ -1114,13 +1138,25 @@ set_ub_dns_transport(struct getdns_context* context,
set_ub_string_opt(context, "do-tcp:", "no");
break;
case GETDNS_TRANSPORT_TCP_ONLY:
- case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
+ 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;
- default:
- /* TODO GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN */
- return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
+ case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
+ 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.*/
+ 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;
}
return GETDNS_RETURN_GOOD;
}
@@ -1134,6 +1170,11 @@ getdns_context_set_dns_transport(struct getdns_context *context,
getdns_transport_t value)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
+ /* Note that the call below does not have any effect in unbound after the
+ ctx is finalised. So will not apply for recursive mode or stub + dnssec.
+ However the method returns success as otherwise the transport could not
+ be reset for stub mode..... */
+ /* Also, not all transport options supported in libunbound yet*/
if (set_ub_dns_transport(context, value) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
@@ -1448,6 +1489,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
freeaddrinfo(ai);
}
upstreams_dereference(context->upstreams);
+ /*Don't the existing upstreams need to be handled before overwritting here?*/
context->upstreams = upstreams;
dispatch_updated(context,
GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
@@ -1756,6 +1798,34 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
if (context->destroying) {
return GETDNS_RETURN_BAD_CONTEXT;
}
+
+ /* Transport can in theory be set per query in stub mode so deal with it
+ here */
+ printf("[TLS] preparing for resolution, checking transport type\n");
+ if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
+ switch (context->dns_transport) {
+ 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();
+ /* Load error messages */
+ SSL_load_error_strings();
+
+ /* Create client context, use TLS v1.2 only for now */
+ SSL_CTX* tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
+ if(!tls_ctx) {
+ ERR_print_errors_fp(stderr);
+ return GETDNS_RETURN_BAD_CONTEXT;
+ }
+ context->tls_ctx = tls_ctx;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
if (context->resolution_type_set == context->resolution_type)
/* already set and no config changes
* have caused this to be bad.
diff --git a/src/context.h b/src/context.h
index bc30efb3..816c068b 100644
--- a/src/context.h
+++ b/src/context.h
@@ -83,6 +83,7 @@ typedef struct getdns_upstream {
/* For sharing a TCP socket to this upstream */
int fd;
+ SSL* tls_obj;
getdns_eventloop_event event;
getdns_eventloop *loop;
getdns_tcp_state tcp;
@@ -133,6 +134,7 @@ struct getdns_context {
uint8_t edns_version;
uint8_t edns_do_bit;
int edns_maximum_udp_payload_size; /* -1 is unset */
+ SSL_CTX* tls_ctx;
getdns_update_callback update_callback;
getdns_update_callback2 update_callback2;
diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in
old mode 100644
new mode 100755
index 4b0bf8aa..f69a2dfc
--- a/src/getdns/getdns.h.in
+++ b/src/getdns/getdns.h.in
@@ -163,7 +163,9 @@ typedef enum getdns_transport_t {
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP = 540,
GETDNS_TRANSPORT_UDP_ONLY = 541,
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_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN = 545
} getdns_transport_t;
/**
@@ -174,6 +176,8 @@ typedef enum getdns_transport_t {
#define GETDNS_TRANSPORT_UDP_ONLY_TEXT "See getdns_context_set_dns_transport()"
#define GETDNS_TRANSPORT_TCP_ONLY_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_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
/** @}
*/
diff --git a/src/request-internal.c b/src/request-internal.c
index 99e5c7d6..6709fde9 100644
--- a/src/request-internal.c
+++ b/src/request-internal.c
@@ -98,6 +98,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
net_req->write_queue_tail = NULL;
net_req->query_len = 0;
net_req->response_len = 0;
+ net_req->tls_obj = NULL;
net_req->wire_data_sz = wire_data_sz;
if (max_query_sz) {
diff --git a/src/stub.c b/src/stub.c
old mode 100644
new mode 100755
index bb4277e9..2de8d028
--- a/src/stub.c
+++ b/src/stub.c
@@ -41,6 +41,8 @@
#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;
@@ -318,6 +320,13 @@ upstream_erred(getdns_upstream *upstream)
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
+ // TODO[TLS]: When we get an error (which is probably a timeout) and are
+ // using to keep connections open should we leave the connection up here?
+ if (upstream->tls_obj) {
+ SSL_shutdown(upstream->tls_obj);
+ SSL_free(upstream->tls_obj);
+ upstream->tls_obj = NULL;
+ }
close(upstream->fd);
upstream->fd = -1;
}
@@ -498,6 +507,8 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
uint8_t *buf;
size_t buf_size;
+ fprintf(stderr, "[TLS] method: stub_tcp_read\n");
+
if (!tcp->read_buf) {
/* First time tcp read, create a buffer for reading */
if (!(tcp->read_buf = GETDNS_XMALLOC(*mf, uint8_t, 4096)))
@@ -518,10 +529,11 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
/* TODO: Try to reconnect */
return STUB_TCP_ERROR;
}
+ fprintf(stderr, "[TLS] method: read %d TCP bytes \n", (int)read);
tcp->to_read -= read;
tcp->read_pos += read;
- if (tcp->to_read > 0)
+ if ((int)tcp->to_read > 0)
return STUB_TCP_AGAIN;
read = tcp->read_pos - tcp->read_buf;
@@ -563,13 +575,16 @@ stub_tcp_read_cb(void *userarg)
&dnsreq->context->mf))) {
case STUB_TCP_AGAIN:
+ fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> tcp again\n");
return;
case STUB_TCP_ERROR:
+ fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> tcp error\n");
stub_erred(netreq);
return;
default:
+ fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> All done. close fd %d\n", netreq->fd);
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
if (q != netreq->query_id)
return;
@@ -595,8 +610,200 @@ stub_tcp_read_cb(void *userarg)
}
}
+/** wait for a socket to become ready */
+static int
+sock_wait(int sockfd)
+{
+ int ret;
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(FD_SET_T sockfd, &fds);
+ struct timeval timeout = {2, 0 };
+ ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
+ if(ret == 0)
+ /* timeout expired */
+ return 0;
+ else if(ret == -1)
+ /* error */
+ return 0;
+ return 1;
+}
+
+static int
+sock_connected(int sockfd)
+{
+ fprintf(stderr, "[TLS] connect in progress \n");
+ /* wait(write) until connected or error */
+ while(1) {
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+
+ if(!sock_wait(sockfd)) {
+ close(sockfd);
+ return -1;
+ }
+
+ /* check if there is a pending error for nonblocking connect */
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, &len) < 0) {
+ error = errno; /* on solaris errno is error */
+ }
+ if (error == EINPROGRESS || error == EWOULDBLOCK)
+ continue; /* try again */
+ else if (error != 0) {
+ close(sockfd);
+ return -1;
+ }
+ /* connected */
+ break;
+ }
+ return 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*
+do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
+{
+ /*Lets make sure the connection is up before we try a handshake*/
+ if (errno == EINPROGRESS && sock_connected(upstream->fd) == -1) {
+ fprintf(stderr, "[TLS] connect failed \n");
+ return NULL;
+ }
+ fprintf(stderr, "[TLS] connect done \n");
+
+ /* Create SSL instance */
+ SSL* ssl = SSL_new(dnsreq->context->tls_ctx);
+ if(!ssl) {
+ return NULL;
+ }
+ /* Connect the SSL object with a file descriptor */
+ if(!SSL_set_fd(ssl, upstream->fd)) {
+ SSL_free(ssl);
+ return NULL;
+ }
+ SSL_set_connect_state(ssl);
+ (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
+ int r;
+ int want;
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(upstream->fd, &fds);
+ struct timeval timeout = {dnsreq->context->timeout/1000, 0 };
+ while ((r = SSL_do_handshake(ssl)) != 1)
+ {
+ want = SSL_get_error(ssl, r);
+ fprintf(stderr, "[TLS] in handshake loop %d, want is %d \n", r, want);
+ switch (want) {
+ case SSL_ERROR_WANT_READ:
+ if (select(upstream->fd + 1, &fds, NULL, NULL, &timeout) == 0) {
+ fprintf(stderr, "[TLS] ssl handshake timeout %d\n", want);
+ SSL_free(ssl);
+ return NULL;
+ }
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ if (select(upstream->fd + 1, NULL, &fds, NULL, &timeout) == 0) {
+ fprintf(stderr, "[TLS] ssl handshake timeout %d\n", want);
+ SSL_free(ssl);
+ return NULL;
+ }
+ break;
+ default:
+ fprintf(stderr, "[TLS] got ssl error code %d\n", want);
+ SSL_free(ssl);
+ return NULL;
+ }
+ }
+ fprintf(stderr, "[TLS] got TLS connection\n");
+ return ssl;
+}
+
+static int
+stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
+{
+ ssize_t read;
+ uint8_t *buf;
+ size_t buf_size;
+
+ fprintf(stderr, "[TLS] method: stub_tls_read\n");
+
+ if (!tcp->read_buf) {
+ /* First time tls read, create a buffer for reading */
+ if (!(tcp->read_buf = GETDNS_XMALLOC(*mf, uint8_t, 4096)))
+ return STUB_TCP_ERROR;
+
+ tcp->read_buf_len = 4096;
+ tcp->read_pos = tcp->read_buf;
+ tcp->to_read = 2; /* Packet size */
+ }
+
+ ERR_clear_error();
+ read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read);
+ if (read <= 0) {
+ /* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
+ renegotiation. Need to keep handshake state to do that.*/
+ int want = SSL_get_error(tls_obj, read);
+ if (want == SSL_ERROR_WANT_READ) {
+ return STUB_TCP_AGAIN; /* read more later */
+ } else
+ return STUB_TCP_ERROR;
+ }
+ fprintf(stderr, "[TLS] method: read %d TLS bytes \n", (int)read);
+ tcp->to_read -= read;
+ tcp->read_pos += read;
+
+ if ((int)tcp->to_read > 0)
+ return STUB_TCP_AGAIN;
+
+ read = tcp->read_pos - tcp->read_buf;
+ if (read == 2) {
+ /* Read the packet size short */
+ tcp->to_read = gldns_read_uint16(tcp->read_buf);
+ fprintf(stderr, "[TLS] method: %d TLS bytes to read \n", (int)tcp->to_read);
+
+ if (tcp->to_read < GLDNS_HEADER_SIZE)
+ return STUB_TCP_ERROR;
+
+ /* Resize our buffer if needed */
+ if (tcp->to_read > tcp->read_buf_len) {
+ buf_size = tcp->read_buf_len;
+ while (tcp->to_read > buf_size)
+ buf_size *= 2;
+
+ if (!(buf = GETDNS_XREALLOC(*mf,
+ tcp->read_buf, uint8_t, buf_size)))
+ return STUB_TCP_ERROR;
+
+ tcp->read_buf = buf;
+ tcp->read_buf_len = buf_size;
+ }
+
+ /* Ready to start reading the packet */
+ fprintf(stderr, "[TLS] method: resetting read_pos \n");
+ tcp->read_pos = tcp->read_buf;
+ read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read);
+ if (read <= 0) {
+ /* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
+ renegotiation. Need to keep handshake state to do that.*/
+ int want = SSL_get_error(tls_obj, read);
+ if (want == SSL_ERROR_WANT_READ) {
+ return STUB_TCP_AGAIN; /* read more later */
+ } else
+ return STUB_TCP_ERROR;
+ }
+ tcp->to_read -= read;
+ tcp->read_pos += read;
+ if ((int)tcp->to_read > 0)
+ return STUB_TCP_AGAIN;
+ }
+ return GLDNS_ID_WIRE(tcp->read_buf);
+}
+
static void netreq_upstream_read_cb(void *userarg);
static void netreq_upstream_write_cb(void *userarg);
+static void upstream_write_cb(void *userarg);
static void
upstream_read_cb(void *userarg)
{
@@ -607,9 +814,18 @@ upstream_read_cb(void *userarg)
uint16_t query_id;
intptr_t query_id_intptr;
- switch ((q = stub_tcp_read(upstream->fd, &upstream->tcp,
- &upstream->upstreams->mf))) {
+ fprintf(stderr, "[TLS] method: upstream_read_cb\n");
+
+ if (upstream->tls_obj)
+ q = stub_tls_read(upstream->tls_obj, &upstream->tcp,
+ &upstream->upstreams->mf);
+ else
+ q = stub_tcp_read(upstream->fd, &upstream->tcp,
+ &upstream->upstreams->mf);
+
+ switch (q) {
case STUB_TCP_AGAIN:
+ fprintf(stderr, "[TLS] method: upstream_read_cb -> STUB_TCP_AGAIN\n");
return;
case STUB_TCP_ERROR:
@@ -617,6 +833,8 @@ upstream_read_cb(void *userarg)
return;
default:
+ fprintf(stderr, "[TLS] method: upstream_read_cb -> processing reponse\n");
+
/* Lookup netreq */
query_id = (uint16_t) q;
query_id_intptr = (intptr_t) query_id;
@@ -633,6 +851,7 @@ upstream_read_cb(void *userarg)
netreq->response = upstream->tcp.read_buf;
netreq->response_len =
upstream->tcp.read_pos - upstream->tcp.read_buf;
+ netreq->tls_obj = upstream->tls_obj;
upstream->tcp.read_buf = NULL;
upstream->upstreams->current = 0;
@@ -687,6 +906,7 @@ static int
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
{
getdns_dns_req *dnsreq = netreq->owner;
+ fprintf(stderr, "[TLS] method: stub_tcp_write\n");
size_t pkt_len = netreq->response - netreq->query;
ssize_t written;
@@ -705,9 +925,9 @@ 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_KEEP_CONNECTIONS_OPEN)
-
+ 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))
query_id = arc4random();
else do {
query_id = arc4random();
@@ -822,6 +1042,56 @@ stub_tcp_write_cb(void *userarg)
}
}
+static int
+stub_tls_write(SSL* tls_obj, getdns_tcp_state *tcp, getdns_network_req *netreq)
+{
+ fprintf(stderr, "[TLS] method: stub_tls_write\n");
+
+ size_t pkt_len = netreq->response - netreq->query;
+ ssize_t written;
+ uint16_t query_id;
+ intptr_t query_id_intptr;
+
+ /* Do we have remaining data that we could not write before? */
+ if (! tcp->write_buf) {
+ /* No, this is an initial write. Try to send
+ */
+
+ /* Find a unique query_id not already written (or in
+ * the write_queue) for that upstream. Register this netreq
+ * by query_id in the process.
+ */
+ do {
+ query_id = ldns_get_random();
+ query_id_intptr = (intptr_t)query_id;
+ netreq->node.key = (void *)query_id_intptr;
+
+ } while (!getdns_rbtree_insert(
+ &netreq->upstream->netreq_by_query_id, &netreq->node));
+
+ GLDNS_ID_SET(netreq->query, query_id);
+ if (netreq->opt)
+ /* no limits on the max udp payload size with tcp */
+ gldns_write_uint16(netreq->opt + 3, 65535);
+
+ /* We have an initialized packet buffer.
+ * Lets see how much of it we can write */
+
+ // TODO[TLS]: Handle error cases, partial writes, renegotiation etc.
+ ERR_clear_error();
+ written = SSL_write(tls_obj, netreq->query - 2, pkt_len + 2);
+ if (written <= 0)
+ return STUB_TCP_ERROR;
+
+ /* We were able to write everything! Start reading. */
+ return (int) query_id;
+
+ }
+
+ return STUB_TCP_ERROR;
+}
+
+
static void
upstream_write_cb(void *userarg)
{
@@ -830,7 +1100,14 @@ upstream_write_cb(void *userarg)
getdns_dns_req *dnsreq = netreq->owner;
int q;
- switch ((q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq))) {
+ fprintf(stderr, "[TLS] method: upstream_write_cb for %s with class %d\n", dnsreq->name, (int)netreq->request_class);
+
+ if (upstream->tls_obj)
+ q = stub_tls_write(upstream->tls_obj, &upstream->tcp, netreq);
+ else
+ q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
+
+ switch (q) {
case STUB_TCP_AGAIN:
return;
@@ -902,18 +1179,110 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
}
}
+static in_port_t
+get_port(struct sockaddr_storage* addr)
+{
+ return ntohs(addr->ss_family == AF_INET
+ ? ((struct sockaddr_in *)addr)->sin_port
+ : ((struct sockaddr_in6*)addr)->sin6_port);
+}
+
+void
+set_port(struct sockaddr_storage* addr, in_port_t port)
+{
+ addr->ss_family == AF_INET
+ ? (((struct sockaddr_in *)addr)->sin_port = htons(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
+tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
+
+ int fd =-1;
+ struct sockaddr_storage connect_addr;
+ struct sockaddr_storage* addr = &upstream->addr;
+ 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) {
+ connect_addr = upstream->addr;
+ addr = &connect_addr;
+ set_port(addr, TLS_PORT);
+ fprintf(stderr, "[TLS] Forcing switch to port %d for TLS\n", TLS_PORT);
+ }
+
+ if ((fd = socket(addr->ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ return -1;
+
+ 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)
+ return fd;
+#endif
+ if (connect(fd, (struct sockaddr *)addr,
+ addr_len) == -1) {
+ if (errno != EINPROGRESS) {
+ close(fd);
+ return -1;
+ }
+ }
+ return fd;
+}
+
getdns_return_t
priv_getdns_submit_stub_request(getdns_network_req *netreq)
{
getdns_dns_req *dnsreq = netreq->owner;
getdns_upstream *upstream = pick_upstream(dnsreq);
+ fprintf(stderr, "[TLS] method: priv_getdns_submit_stub_request\n");
+
if (!upstream)
return GETDNS_RETURN_GENERIC_ERROR;
- switch(dnsreq->context->dns_transport) {
- case GETDNS_TRANSPORT_UDP_ONLY:
- case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
+ // Work out the primary and fallback transport options
+ getdns_base_transport_t transport = get_transport(
+ dnsreq->context->dns_transport,0);
+ getdns_base_transport_t fb_transport = get_transport(
+ dnsreq->context->dns_transport,1);
+ switch(transport) {
+ case UDP:
if ((netreq->fd = socket(
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
@@ -929,23 +1298,10 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
return GETDNS_RETURN_GOOD;
- case GETDNS_TRANSPORT_TCP_ONLY:
+ case TCP_SINGLE:
- if ((netreq->fd = socket(
- upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
+ if ((netreq->fd = tcp_connect(upstream, transport)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
-
- getdns_sock_nonblock(netreq->fd);
-#ifdef USE_TCP_FASTOPEN
- /* Leave the connect to the later call to sendto() */
-#else
- if (connect(netreq->fd, (struct sockaddr *)&upstream->addr,
- upstream->addr_len) == -1 && errno != EINPROGRESS) {
-
- close(netreq->fd);
- return GETDNS_RETURN_GENERIC_ERROR;
- }
-#endif
netreq->upstream = upstream;
GETDNS_SCHEDULE_EVENT(
@@ -955,37 +1311,58 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
return GETDNS_RETURN_GOOD;
- case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
+ case TCP:
+ case TLS:
/* In coming comments, "global" means "context wide" */
/* Are we the first? (Is global socket initialized?) */
if (upstream->fd == -1) {
- /* We are the first. Make global socket and connect. */
- if ((upstream->fd = socket(upstream->addr.ss_family,
- SOCK_STREAM, IPPROTO_TCP)) == -1)
- return GETDNS_RETURN_GENERIC_ERROR;
-
- getdns_sock_nonblock(upstream->fd);
-#ifdef USE_TCP_FASTOPEN
- /* Leave the connect to the later call to sendto() */
-#else
- if (connect(upstream->fd,
- (struct sockaddr *)&upstream->addr,
- upstream->addr_len) == -1 && errno != EINPROGRESS){
+ /* TODO[TLS]: We should remember on the context if we had to fallback
+ * for this upstream so when re-connecting from a dropped TCP
+ * connection we don't retry TLS. */
+ int fallback = 0;
- close(upstream->fd);
- upstream->fd = -1;
- return GETDNS_RETURN_GENERIC_ERROR;
+ /* We are the first. Make global socket and connect. */
+ if ((upstream->fd = tcp_connect(upstream, transport)) == -1) {
+ //TODO: Hum, a reset doesn't make the connect fail...
+ if (fb_transport == NONE)
+ return GETDNS_RETURN_GENERIC_ERROR;
+ fprintf(stderr, "[TLS] Connect failed on fd... %d\n", upstream->fd);
+ if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
+ return GETDNS_RETURN_GENERIC_ERROR;
+ fallback = 1;
+ }
+
+ /* 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)) {
+ fprintf(stderr, "[TLS] Doing SSL handshake... %d\n", upstream->fd);
+ upstream->tls_obj = do_tls_handshake(dnsreq, upstream);
+ if (!upstream->tls_obj) {
+ if (fb_transport == NONE)
+ return GETDNS_RETURN_GENERIC_ERROR;
+ close(upstream->fd);
+ if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
+ return GETDNS_RETURN_GENERIC_ERROR;
+ }
+ }
+ } else {
+ /* Cater for the case of the user downgrading and existing TLS
+ connection to TCP for some reason...*/
+ if (transport == TCP && upstream->tls_obj) {
+ SSL_shutdown(upstream->tls_obj);
+ SSL_free(upstream->tls_obj);
+ upstream->tls_obj = NULL;
}
-#endif
- /* Attach to the global event loop
- * so it can do it's own scheduling
- */
- upstream->loop = dnsreq->context->extension;
}
netreq->upstream = upstream;
+ /* Attach to the global event loop
+ * so it can do it's own scheduling
+ */
+ upstream->loop = dnsreq->context->extension;
+
/* We have a context wide socket.
* Now schedule the write request.
*/
diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c
index 524a9a7c..3fc27ffe 100644
--- a/src/test/getdns_query.c
+++ b/src/test/getdns_query.c
@@ -29,9 +29,23 @@
#include
#include
#include
+#include
#include
#include
+static int quiet = 0;
+static int batch_mode = 0;
+static char *query_file = NULL;
+static int json = 0;
+static char *the_root = ".";
+static char *name;
+static getdns_context *context;
+static getdns_dict *extensions;
+static uint16_t request_type = GETDNS_RRTYPE_NS;
+static int timeout, edns0_size;
+static int async = 0, interactive = 0;
+static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
+
int get_rrtype(const char *t);
getdns_dict *
@@ -90,6 +104,7 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-b \tSet edns0 max_udp_payload size\n");
fprintf(out, "\t-D\tSet edns0 do bit\n");
fprintf(out, "\t-d\tclear edns0 do bit\n");
+ fprintf(out, "\t-F \tread the queries from the specified file\n");
fprintf(out, "\t-G\tgeneral lookup\n");
fprintf(out, "\t-H\thostname lookup. ( must be an IP address; is ignored)\n");
fprintf(out, "\t-h\tPrint this help\n");
@@ -104,29 +119,47 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-t \tSet timeout in miliseconds\n");
fprintf(out, "\t-T\tSet transport to TCP only\n");
fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n");
+ fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n");
+ fprintf(out, "\t-E\tSet transport to TLS 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");
+ fprintf(out, "\t-q\tQuiet mode - don't print response\n");
+ fprintf(out, "\t+sit[=cookie]\tSet edns cookie\n");
}
void callback(getdns_context *context, getdns_callback_type_t callback_type,
getdns_dict *response, void *userarg, getdns_transaction_t trans_id)
{
- getdns_dict **response_ptr = (getdns_dict **)userarg;
+ char *response_str;
- if (response)
- *response_ptr = response;
+ if (callback_type == GETDNS_CALLBACK_COMPLETE) {
+ /* This is a callback with data */;
+ if (!quiet) {
+ if (json)
+ response_str = getdns_print_json_dict(
+ response, json == 1);
+ else if ((response_str = getdns_pretty_print_dict(response))) {
+ fprintf(stdout, "ASYNC response:\n%s\n", response_str);
+ free(response_str);
+ }
+ }
+ fprintf(stderr,
+ "The callback with ID %llu was successfull.\n",
+ (unsigned long long)trans_id);
+
+ } else if (callback_type == GETDNS_CALLBACK_CANCEL)
+ fprintf(stderr,
+ "The callback with ID %llu was cancelled. Exiting.\n",
+ (unsigned long long)trans_id);
+ else
+ fprintf(stderr,
+ "The callback got a callback_type of %d. Exiting.\n",
+ callback_type);
+ getdns_dict_destroy(response);
+ response = NULL;
}
-static char *the_root = ".";
-static char *name;
-static getdns_context *context;
-static getdns_dict *extensions;
-static uint16_t request_type = GETDNS_RRTYPE_NS;
-static int timeout, edns0_size;
-static int async = 0, interactive = 0;
-static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
-static int json = 0;
-
#define CONTINUE ((getdns_return_t)-2)
static getdns_return_t set_cookie(getdns_dict *exts, char *cookie)
@@ -259,6 +292,15 @@ getdns_return_t parse_args(int argc, char **argv)
case 'd':
(void) getdns_context_set_edns_do_bit(context, 0);
break;
+ case 'F':
+ if (c[1] != 0 || ++i >= argc || !*argv[i]) {
+ fprintf(stderr, "file name expected "
+ "after -F\n");
+ return GETDNS_RETURN_GENERIC_ERROR;
+ }
+ query_file = argv[i];
+ interactive = 1;
+ break;
case 'G':
calltype = GENERAL;
break;
@@ -282,6 +324,8 @@ getdns_return_t parse_args(int argc, char **argv)
break;
case 'p':
json = 0;
+ case 'q':
+ quiet = 1;
break;
case 'r':
getdns_context_set_resolution_type(
@@ -319,6 +363,14 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
break;
+ case 'L':
+ getdns_context_set_dns_transport(context,
+ GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
+ break;
+ case 'E':
+ getdns_context_set_dns_transport(context,
+ GETDNS_TRANSPORT_TLS_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);
@@ -327,6 +379,9 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_UDP_ONLY);
break;
+ case 'B':
+ batch_mode = 1;
+ break;
default:
@@ -361,6 +416,7 @@ main(int argc, char **argv)
char *response_str;
getdns_return_t r;
getdns_dict *address = NULL;
+ FILE *fp = NULL;
name = the_root;
if ((r = getdns_context_create(&context, 1))) {
@@ -376,14 +432,28 @@ main(int argc, char **argv)
if ((r = parse_args(argc, argv)))
goto done_destroy_context;
+ if (query_file) {
+ fp = fopen(query_file, "rt");
+ if (fp == NULL) {
+ fprintf(stderr, "Could not open query file: %s\n", query_file);
+ goto done_destroy_context;
+ }
+ }
+
/* Make the call */
do {
char line[1024], *token, *linev[256];
int linec;
if (interactive) {
- fprintf(stdout, "> ");
- if (!fgets(line, 1024, stdin) || !*line)
- break;
+ if (!query_file) {
+ fprintf(stdout, "> ");
+ if (!fgets(line, 1024, stdin) || !*line)
+ break;
+ } else {
+ if (!fgets(line, 1024, fp) || !*line)
+ break;
+ fprintf(stdout,"Found query: %s", line);
+ }
linev[0] = argv[0];
linec = 1;
@@ -430,8 +500,8 @@ main(int argc, char **argv)
}
if (r)
goto done_destroy_extensions;
-
- getdns_context_run(context);
+ if (!batch_mode)
+ getdns_context_run(context);
} else {
switch (calltype) {
case GENERAL:
@@ -456,22 +526,27 @@ main(int argc, char **argv)
}
if (r)
goto done_destroy_extensions;
- }
- if (json)
- response_str = getdns_print_json_dict(
- response, json == 1);
- else
- response_str = getdns_pretty_print_dict(response);
-
- if (response_str) {
- fprintf(stdout, "%s\n", response_str);
- free(response_str);
- } else {
- r = GETDNS_RETURN_MEMORY_ERROR;
- fprintf(stderr, "Could not print response\n");
+ if (!quiet) {
+ if (json)
+ response_str = getdns_print_json_dict(
+ response, json == 1);
+ else if ((response_str = getdns_pretty_print_dict(response))) {
+ fprintf(stdout, "SYNC response:\n%s\n", response_str);
+ free(response_str);
+ } else {
+ r = GETDNS_RETURN_MEMORY_ERROR;
+ fprintf(stderr, "Could not print response\n");
+ }
+ } else if (r == GETDNS_RETURN_GOOD)
+ fprintf(stdout, "Response code was: GOOD\n");
+ else if (interactive)
+ fprintf(stderr, "An error occurred: %d\n", r);
}
} while (interactive);
+ if (batch_mode)
+ getdns_context_run(context);
+
/* Clean up */
done_destroy_extensions:
getdns_dict_destroy(extensions);
@@ -479,6 +554,9 @@ done_destroy_context:
if (response) getdns_dict_destroy(response);
getdns_context_destroy(context);
+ if (fp)
+ fclose(fp);
+
if (r == CONTINUE)
return 0;
if (r)
diff --git a/src/test/tests_stub_async.c b/src/test/tests_stub_async.c
index 4c6e0b4a..fb0baf63 100644
--- a/src/test/tests_stub_async.c
+++ b/src/test/tests_stub_async.c
@@ -44,6 +44,8 @@
#define TRANSPORT_UDP "udp"
#define TRANSPORT_TCP "tcp"
#define TRANSPORT_PIPELINE "pipeline"
+#define TRANSPORT_TLS_KEEPOPEN "tls"
+#define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls"
#define RESOLUTION_STUB "stub"
#define RESOLUTION_REC "rec"
@@ -98,6 +100,10 @@ main(int argc, char** argv)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY);
else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
+ else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0)
+ getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
+ else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0)
+ getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_UDP, 3) != 0) {
fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport);
exit(EXIT_FAILURE);
diff --git a/src/test/tests_stub_sync.c b/src/test/tests_stub_sync.c
index 4b04d5fb..496fb7ab 100644
--- a/src/test/tests_stub_sync.c
+++ b/src/test/tests_stub_sync.c
@@ -41,6 +41,8 @@
#define TRANSPORT_UDP "udp"
#define TRANSPORT_TCP "tcp"
#define TRANSPORT_PIPELINE "pipeline"
+#define TRANSPORT_TLS_KEEPOPEN "tls"
+#define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls"
#define RESOLUTION_STUB "stub"
#define RESOLUTION_REC "rec"
@@ -82,6 +84,10 @@ main(int argc, char** argv)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY);
else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
+ else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0)
+ getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
+ else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0)
+ getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_UDP, 3) != 0) {
fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport);
exit(EXIT_FAILURE);
diff --git a/src/types-internal.h b/src/types-internal.h
index 81141bcc..b961729e 100644
--- a/src/types-internal.h
+++ b/src/types-internal.h
@@ -37,6 +37,7 @@
#define TYPES_INTERNAL_H_
#include
+#include
#include "getdns/getdns.h"
#include "getdns/getdns_extra.h"
#include "util/rbtree.h"
@@ -211,6 +212,7 @@ typedef struct getdns_network_req
uint8_t *opt; /* offset of OPT RR in query */
size_t response_len;
uint8_t *response;
+ SSL* tls_obj;
size_t wire_data_sz;
uint8_t wire_data[];
From 99c1973faeb2df7f770d341e67e2221ad0f8deef Mon Sep 17 00:00:00 2001
From: Sara Dickinson
Date: Thu, 16 Apr 2015 18:01:17 +0100
Subject: [PATCH 02/10] Cleanup of TLS code
---
src/context.c | 27 +++++++++------------
src/request-internal.c | 1 -
src/stub.c | 54 +++++++-----------------------------------
src/types-internal.h | 1 -
4 files changed, 20 insertions(+), 63 deletions(-)
diff --git a/src/context.c b/src/context.c
index 07c09c75..961ea8f9 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1145,15 +1145,15 @@ set_ub_dns_transport(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:
/* 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.*/
+ * 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.*/
set_ub_string_opt(context, "do-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes");
- //set_ub_string_opt(context, "ssl-upstream:", "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...*/
+ * 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;
@@ -1171,10 +1171,10 @@ getdns_context_set_dns_transport(struct getdns_context *context,
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
/* Note that the call below does not have any effect in unbound after the
- ctx is finalised. So will not apply for recursive mode or stub + dnssec.
- However the method returns success as otherwise the transport could not
- be reset for stub mode..... */
- /* Also, not all transport options supported in libunbound yet*/
+ * ctx is finalised. So will not apply for recursive mode or stub + dnssec.
+ * However the method returns success as otherwise the transport could not
+ * be reset for stub mode.....
+ * Also, not all transport options supported in libunbound yet */
if (set_ub_dns_transport(context, value) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
@@ -1799,9 +1799,7 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
return GETDNS_RETURN_BAD_CONTEXT;
}
- /* Transport can in theory be set per query in stub mode so deal with it
- here */
- printf("[TLS] preparing for resolution, checking transport type\n");
+ /* Transport can in theory be set per query in stub mode */
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
switch (context->dns_transport) {
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
@@ -1809,13 +1807,10 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
if (context->tls_ctx == NULL) {
/* Init the SSL library */
SSL_library_init();
- /* Load error messages */
- SSL_load_error_strings();
/* Create client context, use TLS v1.2 only for now */
SSL_CTX* tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
if(!tls_ctx) {
- ERR_print_errors_fp(stderr);
return GETDNS_RETURN_BAD_CONTEXT;
}
context->tls_ctx = tls_ctx;
diff --git a/src/request-internal.c b/src/request-internal.c
index 6709fde9..99e5c7d6 100644
--- a/src/request-internal.c
+++ b/src/request-internal.c
@@ -98,7 +98,6 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
net_req->write_queue_tail = NULL;
net_req->query_len = 0;
net_req->response_len = 0;
- net_req->tls_obj = NULL;
net_req->wire_data_sz = wire_data_sz;
if (max_query_sz) {
diff --git a/src/stub.c b/src/stub.c
index 2de8d028..0d8610c4 100755
--- a/src/stub.c
+++ b/src/stub.c
@@ -320,8 +320,8 @@ upstream_erred(getdns_upstream *upstream)
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
- // TODO[TLS]: When we get an error (which is probably a timeout) and are
- // using to keep connections open should we leave the connection up here?
+ /* TODO[TLS]: When we get an error (which is probably a timeout) and are
+ * using to keep connections open should we leave the connection up here? */
if (upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
@@ -507,8 +507,6 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
uint8_t *buf;
size_t buf_size;
- fprintf(stderr, "[TLS] method: stub_tcp_read\n");
-
if (!tcp->read_buf) {
/* First time tcp read, create a buffer for reading */
if (!(tcp->read_buf = GETDNS_XMALLOC(*mf, uint8_t, 4096)))
@@ -529,7 +527,6 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
/* TODO: Try to reconnect */
return STUB_TCP_ERROR;
}
- fprintf(stderr, "[TLS] method: read %d TCP bytes \n", (int)read);
tcp->to_read -= read;
tcp->read_pos += read;
@@ -575,16 +572,13 @@ stub_tcp_read_cb(void *userarg)
&dnsreq->context->mf))) {
case STUB_TCP_AGAIN:
- fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> tcp again\n");
return;
case STUB_TCP_ERROR:
- fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> tcp error\n");
stub_erred(netreq);
return;
default:
- fprintf(stderr, "[TLS] method: stub_tcp_read_cb -> All done. close fd %d\n", netreq->fd);
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
if (q != netreq->query_id)
return;
@@ -618,7 +612,8 @@ sock_wait(int sockfd)
fd_set fds;
FD_ZERO(&fds);
FD_SET(FD_SET_T sockfd, &fds);
- struct timeval timeout = {2, 0 };
+ /*TODO[TLS]: Pick up this timeout from the context*/
+ struct timeval timeout = {5, 0 };
ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
if(ret == 0)
/* timeout expired */
@@ -632,7 +627,6 @@ sock_wait(int sockfd)
static int
sock_connected(int sockfd)
{
- fprintf(stderr, "[TLS] connect in progress \n");
/* wait(write) until connected or error */
while(1) {
int error = 0;
@@ -667,10 +661,8 @@ do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
{
/*Lets make sure the connection is up before we try a handshake*/
if (errno == EINPROGRESS && sock_connected(upstream->fd) == -1) {
- fprintf(stderr, "[TLS] connect failed \n");
return NULL;
}
- fprintf(stderr, "[TLS] connect done \n");
/* Create SSL instance */
SSL* ssl = SSL_new(dnsreq->context->tls_ctx);
@@ -694,29 +686,24 @@ do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
while ((r = SSL_do_handshake(ssl)) != 1)
{
want = SSL_get_error(ssl, r);
- fprintf(stderr, "[TLS] in handshake loop %d, want is %d \n", r, want);
switch (want) {
case SSL_ERROR_WANT_READ:
if (select(upstream->fd + 1, &fds, NULL, NULL, &timeout) == 0) {
- fprintf(stderr, "[TLS] ssl handshake timeout %d\n", want);
SSL_free(ssl);
return NULL;
}
break;
case SSL_ERROR_WANT_WRITE:
if (select(upstream->fd + 1, NULL, &fds, NULL, &timeout) == 0) {
- fprintf(stderr, "[TLS] ssl handshake timeout %d\n", want);
SSL_free(ssl);
return NULL;
}
break;
default:
- fprintf(stderr, "[TLS] got ssl error code %d\n", want);
SSL_free(ssl);
return NULL;
}
}
- fprintf(stderr, "[TLS] got TLS connection\n");
return ssl;
}
@@ -727,8 +714,6 @@ stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
uint8_t *buf;
size_t buf_size;
- fprintf(stderr, "[TLS] method: stub_tls_read\n");
-
if (!tcp->read_buf) {
/* First time tls read, create a buffer for reading */
if (!(tcp->read_buf = GETDNS_XMALLOC(*mf, uint8_t, 4096)))
@@ -750,7 +735,6 @@ stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
} else
return STUB_TCP_ERROR;
}
- fprintf(stderr, "[TLS] method: read %d TLS bytes \n", (int)read);
tcp->to_read -= read;
tcp->read_pos += read;
@@ -761,7 +745,6 @@ stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
if (read == 2) {
/* Read the packet size short */
tcp->to_read = gldns_read_uint16(tcp->read_buf);
- fprintf(stderr, "[TLS] method: %d TLS bytes to read \n", (int)tcp->to_read);
if (tcp->to_read < GLDNS_HEADER_SIZE)
return STUB_TCP_ERROR;
@@ -781,7 +764,6 @@ stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
}
/* Ready to start reading the packet */
- fprintf(stderr, "[TLS] method: resetting read_pos \n");
tcp->read_pos = tcp->read_buf;
read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read);
if (read <= 0) {
@@ -803,7 +785,6 @@ stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
static void netreq_upstream_read_cb(void *userarg);
static void netreq_upstream_write_cb(void *userarg);
-static void upstream_write_cb(void *userarg);
static void
upstream_read_cb(void *userarg)
{
@@ -814,8 +795,6 @@ upstream_read_cb(void *userarg)
uint16_t query_id;
intptr_t query_id_intptr;
- fprintf(stderr, "[TLS] method: upstream_read_cb\n");
-
if (upstream->tls_obj)
q = stub_tls_read(upstream->tls_obj, &upstream->tcp,
&upstream->upstreams->mf);
@@ -825,7 +804,6 @@ upstream_read_cb(void *userarg)
switch (q) {
case STUB_TCP_AGAIN:
- fprintf(stderr, "[TLS] method: upstream_read_cb -> STUB_TCP_AGAIN\n");
return;
case STUB_TCP_ERROR:
@@ -833,7 +811,6 @@ upstream_read_cb(void *userarg)
return;
default:
- fprintf(stderr, "[TLS] method: upstream_read_cb -> processing reponse\n");
/* Lookup netreq */
query_id = (uint16_t) q;
@@ -851,7 +828,6 @@ upstream_read_cb(void *userarg)
netreq->response = upstream->tcp.read_buf;
netreq->response_len =
upstream->tcp.read_pos - upstream->tcp.read_buf;
- netreq->tls_obj = upstream->tls_obj;
upstream->tcp.read_buf = NULL;
upstream->upstreams->current = 0;
@@ -906,7 +882,6 @@ static int
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
{
getdns_dns_req *dnsreq = netreq->owner;
- fprintf(stderr, "[TLS] method: stub_tcp_write\n");
size_t pkt_len = netreq->response - netreq->query;
ssize_t written;
@@ -1045,8 +1020,6 @@ stub_tcp_write_cb(void *userarg)
static int
stub_tls_write(SSL* tls_obj, getdns_tcp_state *tcp, getdns_network_req *netreq)
{
- fprintf(stderr, "[TLS] method: stub_tls_write\n");
-
size_t pkt_len = netreq->response - netreq->query;
ssize_t written;
uint16_t query_id;
@@ -1100,8 +1073,6 @@ upstream_write_cb(void *userarg)
getdns_dns_req *dnsreq = netreq->owner;
int q;
- fprintf(stderr, "[TLS] method: upstream_write_cb for %s with class %d\n", dnsreq->name, (int)netreq->request_class);
-
if (upstream->tls_obj)
q = stub_tls_write(upstream->tls_obj, &upstream->tcp, netreq);
else
@@ -1243,7 +1214,6 @@ tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
connect_addr = upstream->addr;
addr = &connect_addr;
set_port(addr, TLS_PORT);
- fprintf(stderr, "[TLS] Forcing switch to port %d for TLS\n", TLS_PORT);
}
if ((fd = socket(addr->ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
@@ -1271,8 +1241,6 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
getdns_dns_req *dnsreq = netreq->owner;
getdns_upstream *upstream = pick_upstream(dnsreq);
- fprintf(stderr, "[TLS] method: priv_getdns_submit_stub_request\n");
-
if (!upstream)
return GETDNS_RETURN_GENERIC_ERROR;
@@ -1325,19 +1293,16 @@ 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) {
- //TODO: Hum, a reset doesn't make the connect fail...
if (fb_transport == NONE)
return GETDNS_RETURN_GENERIC_ERROR;
- fprintf(stderr, "[TLS] Connect failed on fd... %d\n", upstream->fd);
if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
fallback = 1;
}
/* Now do a handshake for TLS. Note waiting for this to succeed or
- timeout blocks the scheduling of any messages for this upstream*/
+ * timeout blocks the scheduling of any messages for this upstream*/
if (transport == TLS && (fallback == 0)) {
- fprintf(stderr, "[TLS] Doing SSL handshake... %d\n", upstream->fd);
upstream->tls_obj = do_tls_handshake(dnsreq, upstream);
if (!upstream->tls_obj) {
if (fb_transport == NONE)
@@ -1347,6 +1312,10 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
return GETDNS_RETURN_GENERIC_ERROR;
}
}
+ /* Attach to the global event loop
+ * so it can do it's own scheduling
+ */
+ upstream->loop = dnsreq->context->extension;
} else {
/* Cater for the case of the user downgrading and existing TLS
connection to TCP for some reason...*/
@@ -1358,11 +1327,6 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
}
netreq->upstream = upstream;
- /* Attach to the global event loop
- * so it can do it's own scheduling
- */
- upstream->loop = dnsreq->context->extension;
-
/* We have a context wide socket.
* Now schedule the write request.
*/
diff --git a/src/types-internal.h b/src/types-internal.h
index b961729e..6e4001e6 100644
--- a/src/types-internal.h
+++ b/src/types-internal.h
@@ -212,7 +212,6 @@ typedef struct getdns_network_req
uint8_t *opt; /* offset of OPT RR in query */
size_t response_len;
uint8_t *response;
- SSL* tls_obj;
size_t wire_data_sz;
uint8_t wire_data[];
From ab4fb8d9e9bf42f6feafaccf271c4a36b2d5efed Mon Sep 17 00:00:00 2001
From: Sara Dickinson
Date: Fri, 17 Apr 2015 15:50:08 +0100
Subject: [PATCH 03/10] 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.
---
src/context.c | 68 ++++++++++++++++++++++++++++++++++++------------
src/context.h | 11 ++++++++
src/stub.c | 71 +++++++++++++--------------------------------------
3 files changed, 80 insertions(+), 70 deletions(-)
diff --git a/src/context.c b/src/context.c
index 961ea8f9..77fe07df 100644
--- a/src/context.c
+++ b/src/context.c
@@ -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) {
diff --git a/src/context.h b/src/context.h
index 816c068b..a9b23317 100644
--- a/src/context.h
+++ b/src/context.h
@@ -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_ */
diff --git a/src/stub.c b/src/stub.c
index 0d8610c4..72c00faf 100755
--- a/src/stub.c
+++ b/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;
From 6c7ffc4e4ecbffbe148fea6e1b7d2cdf75d49104 Mon Sep 17 00:00:00 2001
From: Sara Dickinson
Date: Fri, 17 Apr 2015 18:38:13 +0100
Subject: [PATCH 04/10] 1) Fix enum mapping error.
2) Also add detection of TLS 1.2 in openssl during configure and warn that it if not available then TLS will not be available. Using TLS_ONLY in stub mode will then error with BAD_CONTEXT. TLS/TCP will fallback to TCP.
3) Explicitly disallow use of TLS_ONLY in RECURSIVE mode since it isn't supported yet. TLS/TCP will fallback to TCP.
4) Fix for MAC OS X build where openssl not linked correctly
---
m4/acx_openssl.m4 | 6 ++++--
src/context.c | 17 ++++++++++++-----
src/context.h | 2 +-
src/stub.c | 6 ++++--
4 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/m4/acx_openssl.m4 b/m4/acx_openssl.m4
index 68e40f38..87507dce 100644
--- a/m4/acx_openssl.m4
+++ b/m4/acx_openssl.m4
@@ -48,8 +48,8 @@ AC_DEFUN([ACX_SSL_CHECKS], [
fi
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
- LIBS="$LIBS -lcrypto"
- LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
+ LIBS="$LIBS -lcrypto -lssl"
+ LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl"
AC_TRY_LINK(, [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
@@ -105,6 +105,8 @@ AC_DEFUN([ACX_SSL_CHECKS], [
AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
+AC_CHECK_LIB(ssl, TLSv1_2_client_method,AC_DEFINE([HAVE_LIBTLS1_2], [1],
+ [Define if you have libssl with tls 1.2]),[AC_MSG_WARN([Cannot find TLSv1_2_client_method in libssl library. TLS will not be available.])])
])dnl End of ACX_SSL_CHECKS
dnl Check for SSL, where SSL is mandatory
diff --git a/src/context.c b/src/context.c
index 77fe07df..1c6caddd 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1134,8 +1134,8 @@ 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) {
+getdns_base_transport_t
+priv_get_base_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:
@@ -1837,23 +1837,30 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
}
/* Transport can in theory be set per query in stub mode */
+ /* TODO: move this transport logic to a separate functions*/
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
switch (context->dns_transport) {
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) {
+#ifdef HAVE_LIBTLS1_2
/* Create client context, use TLS v1.2 only for now */
- SSL_CTX* tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
- if(!tls_ctx) {
+ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
+#endif
+ if(!context->tls_ctx && context->dns_transport ==
+ GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
return GETDNS_RETURN_BAD_CONTEXT;
}
- context->tls_ctx = tls_ctx;
}
break;
default:
break;
}
}
+ /* Block use of TLS ONLY in recursive mode as it won't work */
+ if (context->resolution_type == GETDNS_RESOLUTION_RECURSING
+ && context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
+ return GETDNS_RETURN_BAD_CONTEXT;
if (context->resolution_type_set == context->resolution_type)
/* already set and no config changes
diff --git a/src/context.h b/src/context.h
index a9b23317..569d42c5 100644
--- a/src/context.h
+++ b/src/context.h
@@ -231,6 +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);
+getdns_base_transport_t priv_get_base_transport(getdns_transport_t transport, int level);
#endif /* _GETDNS_CONTEXT_H_ */
diff --git a/src/stub.c b/src/stub.c
index 72c00faf..0914aa57 100755
--- a/src/stub.c
+++ b/src/stub.c
@@ -663,6 +663,8 @@ do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
}
/* Create SSL instance */
+ if (dnsreq->context->tls_ctx == NULL)
+ return NULL;
SSL* ssl = SSL_new(dnsreq->context->tls_ctx);
if(!ssl) {
return NULL;
@@ -1210,9 +1212,9 @@ 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 = priv_get_transport(
+ getdns_base_transport_t transport = priv_get_base_transport(
dnsreq->context->dns_transport,0);
- getdns_base_transport_t fb_transport = priv_get_transport(
+ getdns_base_transport_t fb_transport = priv_get_base_transport(
dnsreq->context->dns_transport,1);
switch(transport) {
case GETDNS_TRANSPORT_UDP:
From b26f09d1aac102c2334eb694be2776c91f8d2286 Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sat, 18 Apr 2015 09:35:46 +0200
Subject: [PATCH 05/10] autoreconf -if # For convenience...
---
configure | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
src/config.h.in | 3 +++
2 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index f404ad66..5c7c0b18 100755
--- a/configure
+++ b/configure
@@ -11333,8 +11333,8 @@ $as_echo "found in $ssldir" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for HMAC_CTX_init in -lcrypto" >&5
$as_echo_n "checking for HMAC_CTX_init in -lcrypto... " >&6; }
- LIBS="$LIBS -lcrypto"
- LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
+ LIBS="$LIBS -lcrypto -lssl"
+ LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -11543,6 +11543,51 @@ fi
done
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLSv1_2_client_method in -lssl" >&5
+$as_echo_n "checking for TLSv1_2_client_method in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_TLSv1_2_client_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TLSv1_2_client_method ();
+int
+main ()
+{
+return TLSv1_2_client_method ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ssl_TLSv1_2_client_method=yes
+else
+ ac_cv_lib_ssl_TLSv1_2_client_method=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_TLSv1_2_client_method" >&5
+$as_echo "$ac_cv_lib_ssl_TLSv1_2_client_method" >&6; }
+if test "x$ac_cv_lib_ssl_TLSv1_2_client_method" = xyes; then :
+
+$as_echo "#define HAVE_LIBTLS1_2 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find TLSv1_2_client_method in libssl library. TLS will not be available." >&5
+$as_echo "$as_me: WARNING: Cannot find TLSv1_2_client_method in libssl library. TLS will not be available." >&2;}
+fi
+
diff --git a/src/config.h.in b/src/config.h.in
index c6d368fd..1c458b61 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -84,6 +84,9 @@
/* Define to 1 if you have the `ldns' library (-lldns). */
#undef HAVE_LIBLDNS
+/* Define if you have libssl with tls 1.2 */
+#undef HAVE_LIBTLS1_2
+
/* Define to 1 if you have the `unbound' library (-lunbound). */
#undef HAVE_LIBUNBOUND
From 84c5b67ee0f3ee575f64091c325a97e2b6a76986 Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sat, 18 Apr 2015 09:53:50 +0200
Subject: [PATCH 06/10] Re-enable printing of json with getdns_query
---
src/test/getdns_query.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c
index 3fc27ffe..abe21529 100644
--- a/src/test/getdns_query.c
+++ b/src/test/getdns_query.c
@@ -125,7 +125,6 @@ print_usage(FILE *out, const char *progname)
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-q\tQuiet mode - don't print response\n");
- fprintf(out, "\t+sit[=cookie]\tSet edns cookie\n");
}
void callback(getdns_context *context, getdns_callback_type_t callback_type,
@@ -135,14 +134,12 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type,
if (callback_type == GETDNS_CALLBACK_COMPLETE) {
/* This is a callback with data */;
- if (!quiet) {
- if (json)
- response_str = getdns_print_json_dict(
- response, json == 1);
- else if ((response_str = getdns_pretty_print_dict(response))) {
- fprintf(stdout, "ASYNC response:\n%s\n", response_str);
- free(response_str);
- }
+ if (!quiet && (response_str = json ?
+ getdns_print_json_dict(response, json == 1)
+ : getdns_pretty_print_dict(response))) {
+
+ fprintf(stdout, "ASYNC response:\n%s\n", response_str);
+ free(response_str);
}
fprintf(stderr,
"The callback with ID %llu was successfull.\n",
@@ -156,6 +153,7 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type,
fprintf(stderr,
"The callback got a callback_type of %d. Exiting.\n",
callback_type);
+
getdns_dict_destroy(response);
response = NULL;
}
@@ -527,15 +525,17 @@ main(int argc, char **argv)
if (r)
goto done_destroy_extensions;
if (!quiet) {
- if (json)
- response_str = getdns_print_json_dict(
- response, json == 1);
- else if ((response_str = getdns_pretty_print_dict(response))) {
- fprintf(stdout, "SYNC response:\n%s\n", response_str);
+ if ((response_str = json ?
+ getdns_print_json_dict(response, json == 1)
+ : getdns_pretty_print_dict(response))) {
+
+ fprintf( stdout, "SYNC response:\n%s\n"
+ , response_str);
free(response_str);
} else {
r = GETDNS_RETURN_MEMORY_ERROR;
- fprintf(stderr, "Could not print response\n");
+ fprintf( stderr
+ , "Could not print response\n");
}
} else if (r == GETDNS_RETURN_GOOD)
fprintf(stdout, "Response code was: GOOD\n");
From 0ba6af352394fc6df8393ea7c9519ba148767311 Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sat, 18 Apr 2015 22:17:28 +0200
Subject: [PATCH 07/10] upstreams_cleanup from upstreams_dereference
---
src/context.c | 77 ++++++++++++++++++------------------------
src/context.h | 2 ++
src/request-internal.c | 3 +-
3 files changed, 36 insertions(+), 46 deletions(-)
diff --git a/src/context.c b/src/context.c
index 1c6caddd..45e4b472 100644
--- a/src/context.c
+++ b/src/context.c
@@ -470,29 +470,22 @@ upstreams_resize(getdns_upstreams *upstreams, size_t size)
return r;
}
-static void
-upstreams_cleanup(getdns_upstreams *upstreams)
+void
+priv_getdns_upstreams_dereference(getdns_upstreams *upstreams)
{
- if (!upstreams)
- return;
- for (int i = 0; i < (int)upstreams->count; i++) {
- if (upstreams->upstreams[i].tls_obj != NULL) {
- SSL_shutdown(upstreams->upstreams[i].tls_obj);
- SSL_free(upstreams->upstreams[i].tls_obj);
- upstreams->upstreams[i].tls_obj = NULL;
- }
- if (upstreams->upstreams[i].fd != -1) {
- close(upstreams->upstreams[i].fd);
- upstreams->upstreams[i].fd = -1;
- }
- }
-}
+ size_t i;
-static void
-upstreams_dereference(getdns_upstreams *upstreams)
-{
- if (upstreams && --upstreams->referenced == 0)
+ if (upstreams && --upstreams->referenced == 0) {
+ for (i = 0; i < upstreams->count; i++) {
+ if (upstreams->upstreams[i].tls_obj != NULL) {
+ SSL_shutdown(upstreams->upstreams[i].tls_obj);
+ SSL_free(upstreams->upstreams[i].tls_obj);
+ }
+ if (upstreams->upstreams[i].fd != -1)
+ close(upstreams->upstreams[i].fd);
+ }
GETDNS_FREE(upstreams->mf, upstreams);
+ }
}
static uint8_t*
@@ -537,11 +530,9 @@ upstream_ntop_buf(getdns_upstream *upstream, getdns_transport_t transport,
if (transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"@%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));
- }
+ 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
@@ -919,8 +910,7 @@ getdns_context_destroy(struct getdns_context *context)
getdns_traverse_postorder(&context->local_hosts,
destroy_local_host, context);
- upstreams_cleanup(context->upstreams);
- upstreams_dereference(context->upstreams);
+ priv_getdns_upstreams_dereference(context->upstreams);
GETDNS_FREE(context->my_mf, context);
} /* getdns_context_destroy */
@@ -1524,8 +1514,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
upstreams->count++;
freeaddrinfo(ai);
}
- upstreams_dereference(context->upstreams);
- /*Don't the existing upstreams need to be handled before overwritting here?*/
+ priv_getdns_upstreams_dereference(context->upstreams);
context->upstreams = upstreams;
dispatch_updated(context,
GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
@@ -1535,7 +1524,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
invalid_parameter:
r = GETDNS_RETURN_INVALID_PARAMETER;
error:
- upstreams_dereference(upstreams);
+ priv_getdns_upstreams_dereference(upstreams);
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
} /* getdns_context_set_upstream_recursive_servers */
@@ -1731,14 +1720,14 @@ getdns_cancel_callback(getdns_context *context,
} /* getdns_cancel_callback */
static getdns_return_t
-ub_setup_stub(struct ub_ctx *ctx, struct getdns_context *context)
+ub_setup_stub(struct ub_ctx *ctx, 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];
@@ -1840,21 +1829,21 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
/* TODO: move this transport logic to a separate functions*/
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
switch (context->dns_transport) {
- 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) {
+ 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) {
#ifdef HAVE_LIBTLS1_2
- /* Create client context, use TLS v1.2 only for now */
- context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
+ /* Create client context, use TLS v1.2 only for now */
+ context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
#endif
- if(!context->tls_ctx && context->dns_transport ==
- GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
- return GETDNS_RETURN_BAD_CONTEXT;
- }
+ if(!context->tls_ctx && context->dns_transport ==
+ GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
+ return GETDNS_RETURN_BAD_CONTEXT;
}
- break;
- default:
- break;
+ }
+ break;
+ default:
+ break;
}
}
/* Block use of TLS ONLY in recursive mode as it won't work */
diff --git a/src/context.h b/src/context.h
index 569d42c5..12a2c263 100644
--- a/src/context.h
+++ b/src/context.h
@@ -233,4 +233,6 @@ void priv_getdns_context_ub_read_cb(void *userarg);
getdns_base_transport_t priv_get_base_transport(getdns_transport_t transport, int level);
+void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams);
+
#endif /* _GETDNS_CONTEXT_H_ */
diff --git a/src/request-internal.c b/src/request-internal.c
index 99e5c7d6..0889b3fc 100644
--- a/src/request-internal.c
+++ b/src/request-internal.c
@@ -177,8 +177,7 @@ dns_req_free(getdns_dns_req * req)
return;
}
- if (req->upstreams && --req->upstreams->referenced == 0)
- GETDNS_FREE(req->upstreams->mf, req->upstreams);
+ priv_getdns_upstreams_dereference(req->upstreams);
/* cleanup network requests */
for (net_req = req->netreqs; *net_req; net_req++)
From 2a6fc74314afc361ea37a3755e23ec827a29e9e3 Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sat, 18 Apr 2015 22:30:56 +0200
Subject: [PATCH 08/10] netinet/in.h and openssl/ssl.h from config.h
---
configure.ac | 4 ++++
src/config.h.in | 4 ++++
src/types-internal.h | 2 --
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 141633c2..74d0f527 100755
--- a/configure.ac
+++ b/configure.ac
@@ -741,6 +741,10 @@ unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest);
#include
#endif
+#ifdef HAVE_OPENSSL_SSL_H
+#include
+#endif
+
#ifdef HAVE_ATTR_FORMAT
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
__attribute__ ((format (archetype, string_index, first_to_check)))
diff --git a/src/config.h.in b/src/config.h.in
index 1c458b61..c6e67fae 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -323,6 +323,10 @@ unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest);
#include
#endif
+#ifdef HAVE_OPENSSL_SSL_H
+#include
+#endif
+
#ifdef HAVE_ATTR_FORMAT
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
__attribute__ ((format (archetype, string_index, first_to_check)))
diff --git a/src/types-internal.h b/src/types-internal.h
index 6e4001e6..5220d599 100644
--- a/src/types-internal.h
+++ b/src/types-internal.h
@@ -36,8 +36,6 @@
#ifndef TYPES_INTERNAL_H_
#define TYPES_INTERNAL_H_
-#include
-#include
#include "getdns/getdns.h"
#include "getdns/getdns_extra.h"
#include "util/rbtree.h"
From 034150cb42ec671a91152ec42b13a58155ed0578 Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sun, 19 Apr 2015 21:36:24 +0200
Subject: [PATCH 09/10] Bump version & update ChangeLog for 0.1.8 release
---
ChangeLog | 5 +++++
configure | 23 ++++++++++++-----------
configure.ac | 5 +++--
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4b3802f1..53a43bb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+* 2015-04-19: Version 0.1.8
+ * The GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN and
+ GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN
+ DNS over TLS transport options.
+
* 2015-04-08: Version 0.1.7
* Individual getter functions for context settings
* Fix: --with-current-date function to make build deterministically
diff --git a/configure b/configure
index 5c7c0b18..acb71ec3 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for getdns 0.1.7.
+# Generated by GNU Autoconf 2.69 for getdns 0.1.8.
#
# Report bugs to .
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='getdns'
PACKAGE_TARNAME='getdns'
-PACKAGE_VERSION='0.1.7'
-PACKAGE_STRING='getdns 0.1.7'
+PACKAGE_VERSION='0.1.8'
+PACKAGE_STRING='getdns 0.1.8'
PACKAGE_BUGREPORT='stub-resolver@verisignlabs.com'
PACKAGE_URL='http://getdnsapi.net'
@@ -1323,7 +1323,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures getdns 0.1.7 to adapt to many kinds of systems.
+\`configure' configures getdns 0.1.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1388,7 +1388,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of getdns 0.1.7:";;
+ short | recursive ) echo "Configuration of getdns 0.1.8:";;
esac
cat <<\_ACEOF
@@ -1519,7 +1519,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-getdns configure 0.1.7
+getdns configure 0.1.8
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2008,7 +2008,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by getdns $as_me 0.1.7, which was
+It was created by getdns $as_me 0.1.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2367,7 +2367,7 @@ else
CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"
fi
-GETDNS_COMPILATION_COMMENT="getdns 0.1.7 configured on $CURRENT_DATE for the January 2015 version of the API"
+GETDNS_COMPILATION_COMMENT="getdns 0.1.8 configured on $CURRENT_DATE for the January 2015 version of the API"
# Library version
# ---------------
@@ -2388,8 +2388,9 @@ GETDNS_COMPILATION_COMMENT="getdns 0.1.7 configured on $CURRENT_DATE for the Jan
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
# getdns-0.1.7 will have libversion 1:2:1
+# getdns-0.1.8 will have libversion 1:3:2
#
-GETDNS_LIBVERSION=1:2:1
+GETDNS_LIBVERSION=1:3:2
@@ -14322,7 +14323,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by getdns $as_me 0.1.7, which was
+This file was extended by getdns $as_me 0.1.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14389,7 +14390,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-getdns config.status 0.1.7
+getdns config.status 0.1.8
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 74d0f527..c7dcf349 100755
--- a/configure.ac
+++ b/configure.ac
@@ -31,7 +31,7 @@
AC_PREREQ([2.56])
-AC_INIT([getdns], [0.1.7], [stub-resolver@verisignlabs.com], [], [http://getdnsapi.net])
+AC_INIT([getdns], [0.1.8], [stub-resolver@verisignlabs.com], [], [http://getdnsapi.net])
AC_SUBST(RELEASE_CANDIDATE, [])
# Set current date from system if not set
@@ -61,8 +61,9 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_STRING configured on $CURRENT_DATE for th
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
# getdns-0.1.7 will have libversion 1:2:1
+# getdns-0.1.8 will have libversion 1:3:2
#
-GETDNS_LIBVERSION=1:2:1
+GETDNS_LIBVERSION=1:3:2
AC_SUBST(GETDNS_COMPILATION_COMMENT)
AC_SUBST(GETDNS_LIBVERSION)
From 6d4c0afdebd124925458136688a9c1244eafdc8a Mon Sep 17 00:00:00 2001
From: Willem Toorop
Date: Sun, 19 Apr 2015 22:07:11 +0200
Subject: [PATCH 10/10] Correct library version bump
Also the mistake in the last version
---
configure | 6 +++---
configure.ac | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/configure b/configure
index acb71ec3..490c4ac9 100755
--- a/configure
+++ b/configure
@@ -2387,10 +2387,10 @@ GETDNS_COMPILATION_COMMENT="getdns 0.1.8 configured on $CURRENT_DATE for the Jan
# getdns-0.1.4 had libversion 0:0:0
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
-# getdns-0.1.7 will have libversion 1:2:1
-# getdns-0.1.8 will have libversion 1:3:2
+# getdns-0.1.7 had libversion 1:2:1
+# getdns-0.1.8 will have libversion 1:3:0
#
-GETDNS_LIBVERSION=1:3:2
+GETDNS_LIBVERSION=1:3:0
diff --git a/configure.ac b/configure.ac
index c7dcf349..6e98e01f 100755
--- a/configure.ac
+++ b/configure.ac
@@ -60,10 +60,10 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_STRING configured on $CURRENT_DATE for th
# getdns-0.1.4 had libversion 0:0:0
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
-# getdns-0.1.7 will have libversion 1:2:1
-# getdns-0.1.8 will have libversion 1:3:2
+# getdns-0.1.7 had libversion 1:2:1
+# getdns-0.1.8 will have libversion 1:3:0
#
-GETDNS_LIBVERSION=1:3:2
+GETDNS_LIBVERSION=1:3:0
AC_SUBST(GETDNS_COMPILATION_COMMENT)
AC_SUBST(GETDNS_LIBVERSION)