mirror of https://github.com/getdnsapi/getdns.git
First pass at TLS implementation - needs work!
This commit is contained in:
parent
793423b325
commit
99aa79b48f
|
@ -2193,8 +2193,10 @@ getdns_context_set_dns_transport(
|
|||
The value is <span class=default>
|
||||
<code>GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP</code></span>,
|
||||
<code>GETDNS_TRANSPORT_UDP_ONLY</code>,
|
||||
<code>GETDNS_TRANSPORT_TCP_ONLY</code>, or
|
||||
<code>GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN</code>.</p>
|
||||
<code>GETDNS_TRANSPORT_TCP_ONLY</code>,
|
||||
<code>GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN></code>,
|
||||
<code>GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN></code>, or
|
||||
<code>GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN></code>
|
||||
|
||||
<div class=forh>
|
||||
getdns_return_t
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()"
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -29,9 +29,23 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <getdns/getdns.h>
|
||||
#include <getdns/getdns_extra.h>
|
||||
|
||||
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 <bufsize>\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 <filename>\tread the queries from the specified file\n");
|
||||
fprintf(out, "\t-G\tgeneral lookup\n");
|
||||
fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> 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 <timeout>\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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define TYPES_INTERNAL_H_
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <openssl/ssl.h>
|
||||
#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[];
|
||||
|
||||
|
|
Loading…
Reference in New Issue