From a85b17c8856aabe118b8a43992d859bc3984bc85 Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 10:24:02 +0900 Subject: [PATCH 01/18] working prototype 1 --- src/Makefile.in | 2 +- src/request-internal.c | 10 +++++++- src/stub.c | 6 +++++ src/types-internal.h | 9 ++++++++ src/util-internal.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 381ab6bd..d6d90054 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -117,7 +117,7 @@ install: libgetdns.la $(INSTALL) -m 755 -d $(DESTDIR)$(includedir) $(INSTALL) -m 755 -d $(DESTDIR)$(includedir)/getdns $(INSTALL) -m 644 getdns/getdns.h $(DESTDIR)$(includedir)/getdns/getdns.h - $(INSTALL) -m 644 $(srcdir)/getdns/getdns_extra.h $(DESTDIR)$(includedir)/getdns/getdns_extra.h + $(INSTALL) -m 644 getdns/getdns_extra.h $(DESTDIR)$(includedir)/getdns/getdns_extra.h $(INSTALL) -m 755 -d $(DESTDIR)$(libdir) $(LIBTOOL) --mode=install cp libgetdns.la $(DESTDIR)$(libdir) if test $(have_libevent) = 1 ; then $(INSTALL) -m 644 $(srcdir)/getdns/getdns_ext_libevent.h $(DESTDIR)$(includedir)/getdns/ ; $(LIBTOOL) --mode=install cp $(EXTENSION_LIBEVENT_LIB) $(DESTDIR)$(libdir) ; fi diff --git a/src/request-internal.c b/src/request-internal.c index 30156724..3e87195d 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -114,6 +114,12 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->write_queue_tail = NULL; net_req->response_len = 0; + /* Some fields to record info for return_call_debugging */ + net_req->debug_start_time = 0; + net_req->debug_end_time = 0; + net_req->debug_tls_auth_status = 0; + net_req->debug_upstream = NULL; + net_req->wire_data_sz = wire_data_sz; if (max_query_sz) { /* first two bytes will contain query length (for tcp) */ @@ -372,7 +378,9 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->dnssec_return_only_secure = dnssec_return_only_secure; result->dnssec_return_validation_chain = dnssec_return_validation_chain; result->edns_cookies = edns_cookies; - + result->return_call_debugging + = is_extension_set(extensions, "return_call_debugging"); + /* will be set by caller */ result->user_pointer = NULL; result->user_callback = NULL; diff --git a/src/stub.c b/src/stub.c index 7bc30c2d..cafd1f85 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1276,6 +1276,8 @@ stub_udp_write_cb(void *userarg) dnsreq->loop, netreq->fd, dnsreq->context->timeout, getdns_eventloop_event_init(&netreq->event, netreq, stub_udp_read_cb, NULL, stub_timeout_cb)); + + netreq->debug_upstream = netreq->upstream; } /**************************/ @@ -1343,6 +1345,7 @@ stub_tcp_write_cb(void *userarg) dnsreq->loop, netreq->fd, dnsreq->context->timeout, getdns_eventloop_event_init(&netreq->event, netreq, stub_tcp_read_cb, NULL, stub_timeout_cb)); + netreq->debug_upstream = netreq->upstream; return; } } @@ -1477,6 +1480,9 @@ upstream_write_cb(void *userarg) return; default: + netreq->debug_upstream = netreq->upstream; + /* Need this because auth status is reset on connection clode */ + netreq->debug_tls_auth_status = netreq->upstream->tls_auth_failed; upstream->writes_done++; netreq->query_id = (uint16_t) q; /* Unqueue the netreq from the write_queue */ diff --git a/src/types-internal.h b/src/types-internal.h index 93b97973..0dbe7028 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -226,6 +226,12 @@ typedef struct getdns_network_req /* Network requests scheduled to write after me */ struct getdns_network_req *write_queue_tail; + /* Some fields to record info for return_call_debugging */ + uint64_t debug_start_time; + uint64_t debug_end_time; + size_t debug_tls_auth_status; + struct getdns_upstream *debug_upstream; + /* When more space is needed for the wire_data response than is * available in wire_data[], it will be allocated seperately. * response will then not point to wire_data anymore. @@ -237,6 +243,8 @@ typedef struct getdns_network_req size_t wire_data_sz; uint8_t wire_data[]; + + } getdns_network_req; /** @@ -262,6 +270,7 @@ typedef struct getdns_dns_req { int dnssec_return_only_secure; int dnssec_return_validation_chain; int edns_cookies; + int return_call_debugging; /* Internally used by return_validation_chain */ int dnssec_ok_checking_disabled; diff --git a/src/util-internal.c b/src/util-internal.c index d6e9299e..67a8c982 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -671,6 +671,33 @@ success: return result; } +getdns_dict * +_getdns_create_call_debugging_dict(getdns_context *context, + getdns_network_req *netreq, + getdns_dict *reply) { + getdns_dict *netreq_debug = getdns_dict_create_with_context(context); + getdns_bindata *qname = NULL; + uint32_t qtype; + getdns_dict *question = NULL; + getdns_dict_get_dict(reply, "question", &question); + getdns_dict_get_bindata(question, "qname", &qname); + getdns_dict_set_bindata(netreq_debug, "qname", qname); + getdns_dict_get_int(question, "qtype", &qtype); + getdns_dict_set_int(netreq_debug, "qtype", qtype); + getdns_dict *address_debug = getdns_dict_create_with_context(context); + _getdns_sockaddr_to_dict(context, &netreq->upstream->addr, &address_debug); + getdns_dict_set_dict(netreq_debug, "upstream", address_debug); + getdns_dict_set_int(netreq_debug, "transport", netreq->upstream->transport); + /* Only include the auth status if TLS was used */ + if (netreq->upstream->transport == GETDNS_TRANSPORT_TLS) { + getdns_dict_util_set_string(netreq_debug, "tls_auth", + netreq->debug_tls_auth_status == 0 ? "OK" : "FAILED"); + } + return netreq_debug; + +} + + getdns_dict * _getdns_create_getdns_response(getdns_dns_req *completed_request) { @@ -678,6 +705,7 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) getdns_list *just_addrs = NULL; getdns_list *replies_full; getdns_list *replies_tree; + getdns_list *call_debugging; getdns_network_req *netreq, **netreq_p; int rrsigs_in_answer = 0; getdns_dict *reply; @@ -713,6 +741,11 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) if (!(replies_tree = getdns_list_create_with_context(context))) goto error_free_replies_full; + if (completed_request->return_call_debugging) { + if (!(call_debugging = getdns_list_create_with_context(context))) + goto error_free_result; + } + for ( netreq_p = completed_request->netreqs ; (netreq = *netreq_p) ; netreq_p++) { @@ -769,6 +802,17 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) getdns_dict_destroy(reply); goto error; } + + if (completed_request->return_call_debugging) { + getdns_dict *netreq_debug; + if (!(netreq_debug = _getdns_create_call_debugging_dict(context, + netreq, reply))) { + goto error; + } + _getdns_list_append_dict(call_debugging, netreq_debug); + getdns_dict_destroy(netreq_debug); + } + getdns_dict_destroy(reply); /* buffer */ @@ -785,6 +829,11 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) goto error_free_replies_full; getdns_list_destroy(replies_full); + if (completed_request->return_call_debugging) { + if (getdns_dict_set_list(result, "return_call_debugging", call_debugging)) + goto error_free_call_debugging; + } + if (just_addrs && getdns_dict_set_list( result, GETDNS_STR_KEY_JUST_ADDRS, just_addrs)) goto error_free_result; @@ -806,6 +855,9 @@ error: getdns_list_destroy(replies_tree); error_free_replies_full: getdns_list_destroy(replies_full); +error_free_call_debugging: + if (completed_request->return_call_debugging) + getdns_list_destroy(call_debugging); error_free_result: getdns_list_destroy(just_addrs); getdns_dict_destroy(result); From 80864655d7e2865230489d897ca724231470709f Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 10:51:00 +0900 Subject: [PATCH 02/18] Working prototype 2 --- src/util-internal.c | 60 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/util-internal.c b/src/util-internal.c index 67a8c982..4b420ca7 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -675,24 +675,64 @@ getdns_dict * _getdns_create_call_debugging_dict(getdns_context *context, getdns_network_req *netreq, getdns_dict *reply) { - getdns_dict *netreq_debug = getdns_dict_create_with_context(context); + getdns_bindata *qname = NULL; uint32_t qtype; getdns_dict *question = NULL; - getdns_dict_get_dict(reply, "question", &question); - getdns_dict_get_bindata(question, "qname", &qname); - getdns_dict_set_bindata(netreq_debug, "qname", qname); - getdns_dict_get_int(question, "qtype", &qtype); - getdns_dict_set_int(netreq_debug, "qtype", qtype); + if (getdns_dict_get_dict(reply, "question", &question)) { + return NULL; + } + if (getdns_dict_get_bindata(question, "qname", &qname)) { + return NULL; + } + if (getdns_dict_get_int(question, "qtype", &qtype)) { + return NULL; + } + + /* It is the responsibility of the caller to free this */ + getdns_dict *netreq_debug = getdns_dict_create_with_context(context); + if (netreq_debug == NULL) { + return NULL; + } + getdns_dict *address_debug = getdns_dict_create_with_context(context); + if (address_debug == NULL){ + getdns_dict_destroy(netreq_debug); + return NULL; + } _getdns_sockaddr_to_dict(context, &netreq->upstream->addr, &address_debug); - getdns_dict_set_dict(netreq_debug, "upstream", address_debug); - getdns_dict_set_int(netreq_debug, "transport", netreq->upstream->transport); + + if (getdns_dict_set_bindata(netreq_debug, "qname", qname)) { + getdns_dict_destroy(netreq_debug); + getdns_dict_destroy(address_debug); + return NULL; + } + if (getdns_dict_set_int(netreq_debug, "qtype", qtype)) { + getdns_dict_destroy(netreq_debug); + getdns_dict_destroy(address_debug); + return NULL; + } + if (getdns_dict_set_dict(netreq_debug, "upstream", address_debug)) { + getdns_dict_destroy(netreq_debug); + getdns_dict_destroy(address_debug); + return NULL; + } + getdns_dict_destroy(address_debug); + + if (getdns_dict_set_int(netreq_debug, "transport", + netreq->upstream->transport)) { + getdns_dict_destroy(netreq_debug); + return NULL; + } /* Only include the auth status if TLS was used */ if (netreq->upstream->transport == GETDNS_TRANSPORT_TLS) { - getdns_dict_util_set_string(netreq_debug, "tls_auth", - netreq->debug_tls_auth_status == 0 ? "OK" : "FAILED"); + if (getdns_dict_util_set_string(netreq_debug, "tls_auth", + netreq->debug_tls_auth_status == 0 ? "OK" : "FAILED")) { + getdns_dict_destroy(netreq_debug); + return NULL; + } } + return netreq_debug; } From 25f7f2182be70527d452c5d06c2b6373104fc0d4 Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 11:04:03 +0900 Subject: [PATCH 03/18] working prototype 3 --- src/dict.c | 1 + src/util-internal.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/dict.c b/src/dict.c index 16e0b3fb..19e55e0a 100644 --- a/src/dict.c +++ b/src/dict.c @@ -994,6 +994,7 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent, strcmp(item->node.key, "status") == 0 || strcmp(item->node.key, "append_name") == 0 || strcmp(item->node.key, "follow_redirects") == 0 || + strcmp(item->node.key, "transport") == 0 || strcmp(item->node.key, "resolution_type") == 0) && (strval = _getdns_get_const_info(item->i.data.n)->name)) { diff --git a/src/util-internal.c b/src/util-internal.c index 4b420ca7..fb1d664d 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -727,9 +727,11 @@ _getdns_create_call_debugging_dict(getdns_context *context, /* Only include the auth status if TLS was used */ if (netreq->upstream->transport == GETDNS_TRANSPORT_TLS) { if (getdns_dict_util_set_string(netreq_debug, "tls_auth", - netreq->debug_tls_auth_status == 0 ? "OK" : "FAILED")) { - getdns_dict_destroy(netreq_debug); - return NULL; + netreq->debug_tls_auth_status == 0 ? + "OK: Hostname matched valid cert." : + "FAILED: Server not validated.")) { + getdns_dict_destroy(netreq_debug); + return NULL; } } From 2d20e18b8ab758d2231c1d470c8efcbb101d26d2 Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 11:14:45 +0900 Subject: [PATCH 04/18] working prototype 4 --- src/request-internal.c | 1 - src/stub.c | 4 ---- src/types-internal.h | 1 - 3 files changed, 6 deletions(-) diff --git a/src/request-internal.c b/src/request-internal.c index 3e87195d..2bef85ae 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -118,7 +118,6 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->debug_start_time = 0; net_req->debug_end_time = 0; net_req->debug_tls_auth_status = 0; - net_req->debug_upstream = NULL; net_req->wire_data_sz = wire_data_sz; if (max_query_sz) { diff --git a/src/stub.c b/src/stub.c index cafd1f85..e6974378 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1276,8 +1276,6 @@ stub_udp_write_cb(void *userarg) dnsreq->loop, netreq->fd, dnsreq->context->timeout, getdns_eventloop_event_init(&netreq->event, netreq, stub_udp_read_cb, NULL, stub_timeout_cb)); - - netreq->debug_upstream = netreq->upstream; } /**************************/ @@ -1345,7 +1343,6 @@ stub_tcp_write_cb(void *userarg) dnsreq->loop, netreq->fd, dnsreq->context->timeout, getdns_eventloop_event_init(&netreq->event, netreq, stub_tcp_read_cb, NULL, stub_timeout_cb)); - netreq->debug_upstream = netreq->upstream; return; } } @@ -1480,7 +1477,6 @@ upstream_write_cb(void *userarg) return; default: - netreq->debug_upstream = netreq->upstream; /* Need this because auth status is reset on connection clode */ netreq->debug_tls_auth_status = netreq->upstream->tls_auth_failed; upstream->writes_done++; diff --git a/src/types-internal.h b/src/types-internal.h index 0dbe7028..c6376de6 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -230,7 +230,6 @@ typedef struct getdns_network_req uint64_t debug_start_time; uint64_t debug_end_time; size_t debug_tls_auth_status; - struct getdns_upstream *debug_upstream; /* When more space is needed for the wire_data response than is * available in wire_data[], it will be allocated seperately. From f5662bbf32b3dbf1abff412cc04dd0e5b20b49ab Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 11:43:12 +0900 Subject: [PATCH 05/18] working prototype 5 --- src/util-internal.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/util-internal.c b/src/util-internal.c index fb1d664d..27932bbc 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -702,17 +702,17 @@ _getdns_create_call_debugging_dict(getdns_context *context, } _getdns_sockaddr_to_dict(context, &netreq->upstream->addr, &address_debug); - if (getdns_dict_set_bindata(netreq_debug, "qname", qname)) { + if (getdns_dict_set_bindata(netreq_debug, "query_name", qname)) { getdns_dict_destroy(netreq_debug); getdns_dict_destroy(address_debug); return NULL; } - if (getdns_dict_set_int(netreq_debug, "qtype", qtype)) { + if (getdns_dict_set_int(netreq_debug, "query_type", qtype)) { getdns_dict_destroy(netreq_debug); getdns_dict_destroy(address_debug); return NULL; } - if (getdns_dict_set_dict(netreq_debug, "upstream", address_debug)) { + if (getdns_dict_set_dict(netreq_debug, "query_to", address_debug)) { getdns_dict_destroy(netreq_debug); getdns_dict_destroy(address_debug); return NULL; @@ -724,9 +724,19 @@ _getdns_create_call_debugging_dict(getdns_context *context, getdns_dict_destroy(netreq_debug); return NULL; } + if (getdns_dict_set_int(netreq_debug, "start_time", + netreq->debug_start_time)) { + getdns_dict_destroy(netreq_debug); + return NULL; + } + if (getdns_dict_set_int(netreq_debug, "end_time", + netreq->debug_end_time)) { + getdns_dict_destroy(netreq_debug); + return NULL; + } /* Only include the auth status if TLS was used */ if (netreq->upstream->transport == GETDNS_TRANSPORT_TLS) { - if (getdns_dict_util_set_string(netreq_debug, "tls_auth", + if (getdns_dict_util_set_string(netreq_debug, "tls_auth_status", netreq->debug_tls_auth_status == 0 ? "OK: Hostname matched valid cert." : "FAILED: Server not validated.")) { From 51eb2fdf5590efda9a4dafef5971e5bef26245b9 Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 12:47:49 +0900 Subject: [PATCH 06/18] working prototype 6 --- src/dict.c | 1 + src/stub.c | 26 ++++++++++++++++++++++---- src/util-internal.c | 11 ++++------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/dict.c b/src/dict.c index 19e55e0a..dd59d346 100644 --- a/src/dict.c +++ b/src/dict.c @@ -981,6 +981,7 @@ getdns_pp_dict(gldns_buffer * buf, size_t indent, if (!json && (strcmp(item->node.key, "type") == 0 || strcmp(item->node.key, "type_covered") == 0 || + strcmp(item->node.key, "query_type") == 0 || strcmp(item->node.key, "qtype") == 0) && (strval = _getdns_rr_type_name(item->i.data.n))) { if (gldns_buffer_printf( diff --git a/src/stub.c b/src/stub.c index e6974378..b6c6d11d 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1176,6 +1176,19 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, return STUB_TCP_ERROR; } +static uint64_t +_getdns_get_time_as_uintt64() { + + struct timeval tv; + uint64_t now; + + if (gettimeofday(&tv, NULL)) { + return 0; + } + now = tv.tv_sec * 1000000 + tv.tv_usec; + return now; +} + /**************************/ /* UDP callback functions */ /**************************/ @@ -1237,6 +1250,7 @@ stub_udp_read_cb(void *userarg) netreq->response_len = read; dnsreq->upstreams->current = 0; done: + netreq->debug_end_time = _getdns_get_time_as_uintt64(); netreq->state = NET_REQ_FINISHED; _getdns_check_dns_req_complete(dnsreq); } @@ -1251,6 +1265,7 @@ stub_udp_write_cb(void *userarg) GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); + netreq->debug_start_time = _getdns_get_time_as_uintt64(); netreq->query_id = arc4random(); GLDNS_ID_SET(netreq->query, netreq->query_id); if (netreq->opt) { @@ -1314,7 +1329,7 @@ stub_tcp_read_cb(void *userarg) netreq->tcp.read_pos - netreq->tcp.read_buf; netreq->tcp.read_buf = NULL; dnsreq->upstreams->current = 0; - + netreq->debug_end_time = _getdns_get_time_as_uintt64(); stub_cleanup(netreq); close(netreq->fd); _getdns_check_dns_req_complete(dnsreq); @@ -1327,7 +1342,7 @@ stub_tcp_write_cb(void *userarg) getdns_network_req *netreq = (getdns_network_req *)userarg; getdns_dns_req *dnsreq = netreq->owner; int q; - + netreq->debug_start_time = _getdns_get_time_as_uintt64(); switch ((q = stub_tcp_write(netreq->fd, &netreq->tcp, netreq))) { case STUB_TCP_AGAIN: return; @@ -1420,7 +1435,7 @@ upstream_read_cb(void *userarg) getdns_eventloop_event_init(&upstream->event, upstream, NULL, upstream_write_cb, NULL)); } - + netreq->debug_end_time = _getdns_get_time_as_uintt64(); /* This also reschedules events for the upstream*/ stub_cleanup(netreq); @@ -1447,7 +1462,10 @@ upstream_write_cb(void *userarg) getdns_network_req *netreq = upstream->write_queue; getdns_dns_req *dnsreq = netreq->owner; int q; - + + /* TODO: think about TCP AGAIN */ + netreq->debug_start_time = _getdns_get_time_as_uintt64(); + DEBUG_STUB("--- WRITE: %s: %p TYPE: %d\n", __FUNCTION__, netreq, netreq->request_type); if (tls_requested(netreq) && tls_should_write(upstream)) diff --git a/src/util-internal.c b/src/util-internal.c index 27932bbc..377395a3 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -724,13 +724,10 @@ _getdns_create_call_debugging_dict(getdns_context *context, getdns_dict_destroy(netreq_debug); return NULL; } - if (getdns_dict_set_int(netreq_debug, "start_time", - netreq->debug_start_time)) { - getdns_dict_destroy(netreq_debug); - return NULL; - } - if (getdns_dict_set_int(netreq_debug, "end_time", - netreq->debug_end_time)) { + + /* TODO: This is not safe */ + uint32_t run_time = (uint32_t)(netreq->debug_end_time - netreq->debug_start_time); + if (getdns_dict_set_int(netreq_debug, "run_time/ms", run_time/1000)) { getdns_dict_destroy(netreq_debug); return NULL; } From 30043d2ba5db279797f123f635f23c86840965ae Mon Sep 17 00:00:00 2001 From: jad Date: Sun, 1 Nov 2015 13:09:18 +0900 Subject: [PATCH 07/18] corrected name --- src/util-internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util-internal.c b/src/util-internal.c index 377395a3..6ff02bb2 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -879,7 +879,7 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) getdns_list_destroy(replies_full); if (completed_request->return_call_debugging) { - if (getdns_dict_set_list(result, "return_call_debugging", call_debugging)) + if (getdns_dict_set_list(result, "call_debugging", call_debugging)) goto error_free_call_debugging; } From 3e90795680e3a3934d84fb0943b076aee630529b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 30 Oct 2015 16:17:18 +0900 Subject: [PATCH 08/18] enable talking to servers with ECDSA certs There is no clear reason to reject servers that don't have RSA certs. We should accept ECDSA certs as well. (also, clean up comments about opportunistic TLS) --- src/context.c | 4 ++-- src/stub.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/context.c b/src/context.c index 95dc5b6e..79dde85b 100644 --- a/src/context.c +++ b/src/context.c @@ -2200,8 +2200,8 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, if(context->tls_ctx == NULL) return GETDNS_RETURN_BAD_CONTEXT; /* Be strict and only use the cipher suites recommended in RFC7525 - Unless we later fallback to oppotunistic. */ - const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EDH+aRSA+AESGCM"; + Unless we later fallback to opportunistic. */ + const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EECDH+aECDSA+AESGCM:EDH+aRSA+AESGCM"; if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS)) return GETDNS_RETURN_BAD_CONTEXT; if (!SSL_CTX_set_default_verify_paths(context->tls_ctx)) diff --git a/src/stub.c b/src/stub.c index 0fcaefe4..5c9b6b5a 100644 --- a/src/stub.c +++ b/src/stub.c @@ -908,7 +908,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) return NULL; } #endif - /* Allow fallback to oppotunisitc if settings permit it*/ + /* Allow fallback to opportunistic if settings permit it*/ if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); else { @@ -923,6 +923,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) upstream->tls_auth_failed = 1; return NULL; } else { + /* no hostname verification, so we will make opportunistic connections */ DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); upstream->tls_auth_failed = 1; SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback); From 0b388872ea5701d90c8490aefad8c54103822d70 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sat, 31 Oct 2015 19:04:56 +0900 Subject: [PATCH 09/18] clarify per-query options vs. per-upstream options Sending DNS cookies was overwriting any existing options (DNS OPT) in the outbound query. Also, DNS cookies may not be the only option that gets set per-upstream (instead of per-query). This changeset establishes a set of per-query options (established at the time of the query), and a buffer of additional space for adding options based on the upstream is in use. The size of this buffer is defined at configure time (defaults to 3000 octets). Just before a query is sent out, we add the per-upstream options to the query. Note: we're also standardizing the query in tls too, even though we're not sending any upstream options in that case at the moment (edns_cookies are much weaker than TLS itself) --- configure.ac | 2 + src/request-internal.c | 77 ++++++++++++++++++++++++++++++++++++--- src/stub.c | 83 ++++++++++++++++++++---------------------- src/types-internal.h | 18 +++++++++ 4 files changed, 130 insertions(+), 50 deletions(-) diff --git a/configure.ac b/configure.ac index b4409fa3..613eec79 100644 --- a/configure.ac +++ b/configure.ac @@ -408,6 +408,8 @@ esac AC_DEFINE_UNQUOTED([EDNS_COOKIE_OPCODE], [10], [The edns cookie option code.]) AC_DEFINE_UNQUOTED([EDNS_COOKIE_ROLLOVER_TIME], [(24 * 60 * 60)], [How often the edns client cookie is refreshed.]) +AC_DEFINE_UNQUOTED([MAXIMUM_UPSTREAM_OPTION_SPACE], [3000], [limit for dynamically-generated DNS options]) + my_with_libunbound=1 AC_ARG_ENABLE(stub-only, AC_HELP_STRING([--enable-stub-only], [Restricts resolution modes to STUB (which will be the default mode). Removes the libunbound dependency.])) case "$enable_stub_only" in diff --git a/src/request-internal.c b/src/request-internal.c index 30156724..42c296ec 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -113,6 +113,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, ? edns_maximum_udp_payload_size : 1432; net_req->write_queue_tail = NULL; net_req->response_len = 0; + net_req->base_query_option_sz = opt_options_size; net_req->wire_data_sz = wire_data_sz; if (max_query_sz) { @@ -184,6 +185,75 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, return r; } +/* req->opt + 9 is the length; req->opt + 11 is the start of the + options. + + clear_upstream_options() goes back to the per-query options. + */ + +void +_getdns_network_req_clear_upstream_options(getdns_network_req * req) +{ + size_t pktlen; + if (req->opt) { + gldns_write_uint16(req->opt + 9, req->base_query_option_sz); + req->response = req->opt + 11 + req->base_query_option_sz; + pktlen = req->response - req->query; + gldns_write_uint16(req->query - 2, pktlen); + } +} + +/* add_upstream_option appends an option that is derived at send time. + (you can send data as NULL and it will fill with all zeros) */ +getdns_return_t +_getdns_network_req_add_upstream_option(getdns_network_req * req, uint16_t code, uint16_t sz, const void* data) +{ + uint16_t oldlen; + uint32_t newlen; + uint32_t pktlen; + size_t cur_upstream_option_sz; + + /* if no options are set, we can't add upstream options */ + if (!req->opt) + return GETDNS_RETURN_GENERIC_ERROR; + + /* if TCP, no overflow allowed for length field + https://tools.ietf.org/html/rfc1035#section-4.2.2 */ + pktlen = req->response - req->query; + pktlen += 4 + sz; + if (pktlen > UINT16_MAX) + return GETDNS_RETURN_GENERIC_ERROR; + + /* no overflow allowed for OPT size either (maybe this is overkill + given the above check?) */ + oldlen = gldns_read_uint16(req->opt + 9); + newlen = oldlen + 4 + sz; + if (newlen > UINT16_MAX) + return GETDNS_RETURN_GENERIC_ERROR; + + /* avoid overflowing MAXIMUM_UPSTREAM_OPTION_SPACE */ + cur_upstream_option_sz = (size_t)oldlen - req->base_query_option_sz; + if (cur_upstream_option_sz + 4 + sz > MAXIMUM_UPSTREAM_OPTION_SPACE) + return GETDNS_RETURN_GENERIC_ERROR; + + /* actually add the option: */ + gldns_write_uint16(req->opt + 11 + oldlen, code); + gldns_write_uint16(req->opt + 11 + oldlen + 2, sz); + if (data != NULL) + memcpy(req->opt + 11 + oldlen + 4, data, sz); + else + memset(req->opt + 11 + oldlen + 4, 0, sz); + gldns_write_uint16(req->opt + 9, newlen); + + /* the response should start right after the options end: */ + req->response = req->opt + 11 + newlen; + + /* for TCP, adjust the size of the wire format itself: */ + gldns_write_uint16(req->query - 2, pktlen); + + return GETDNS_RETURN_GOOD; +} + void _getdns_dns_req_free(getdns_dns_req * req) { @@ -323,12 +393,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, max_query_sz = ( GLDNS_HEADER_SIZE + strlen(name) + 1 + 4 /* dname always smaller then strlen(name) + 1 */ + 12 + opt_options_size /* space needed for OPT (if needed) */ - + ( !edns_cookies ? 0 - : 2 /* EDNS0 Option Code */ - + 2 /* Option length = 8 + 16 = 24 */ - + 8 /* client cookie */ - + 16 /* server cookie */ - ) + + MAXIMUM_UPSTREAM_OPTION_SPACE /* TODO: TSIG */ + 7) / 8 * 8; } diff --git a/src/stub.c b/src/stub.c index 5c9b6b5a..582c02c5 100644 --- a/src/stub.c +++ b/src/stub.c @@ -46,6 +46,7 @@ #include "util-internal.h" #include "general.h" +#define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ #define STUB_TLS_SETUP_ERROR -4 #define STUB_TCP_AGAIN -3 #define STUB_TCP_ERROR -2 @@ -129,9 +130,13 @@ calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie) cookie[i % 8] ^= md_value[i]; } -static uint8_t * -attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt) +static getdns_return_t +attach_edns_cookie(getdns_network_req *req) { + getdns_upstream *upstream = req->upstream; + uint16_t sz; + void* val; + uint8_t buf[8 + 32]; /* server cookies can be no larger than 32 bytes */ rollover_secret(); if (!upstream->has_client_cookie) { @@ -139,12 +144,8 @@ attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt) upstream->secret = secret; upstream->has_client_cookie = 1; - gldns_write_uint16(opt + 9, 12); /* rdata len */ - gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE); - gldns_write_uint16(opt + 13, 8); /* opt len */ - memcpy(opt + 15, upstream->client_cookie, 8); - return opt + 23; - + sz = 8; + val = upstream->client_cookie; } else if (upstream->secret != secret) { memcpy( upstream->prev_client_cookie , upstream->client_cookie, 8); @@ -152,29 +153,19 @@ attach_edns_cookie(getdns_upstream *upstream, uint8_t *opt) calc_new_cookie(upstream, upstream->client_cookie); upstream->secret = secret; - gldns_write_uint16(opt + 9, 12); /* rdata len */ - gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE); - gldns_write_uint16(opt + 13, 8); /* opt len */ - memcpy(opt + 15, upstream->client_cookie, 8); - return opt + 23; - + sz = 8; + val = upstream->client_cookie; } else if (!upstream->has_server_cookie) { - gldns_write_uint16(opt + 9, 12); /* rdata len */ - gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE); - gldns_write_uint16(opt + 13, 8); /* opt len */ - memcpy(opt + 15, upstream->client_cookie, 8); - return opt + 23; + sz = 8; + val = upstream->client_cookie; } else { - gldns_write_uint16( opt + 9, 12 /* rdata len */ - + upstream->server_cookie_len); - gldns_write_uint16(opt + 11, EDNS_COOKIE_OPCODE); - gldns_write_uint16(opt + 13, 8 /* opt len */ - + upstream->server_cookie_len); - memcpy(opt + 15, upstream->client_cookie, 8); - memcpy(opt + 23, upstream->server_cookie - , upstream->server_cookie_len); - return opt + 23+ upstream->server_cookie_len; + sz = 8 + upstream->server_cookie_len; + memcpy(buf, upstream->client_cookie, 8); + memcpy(buf+8, upstream->server_cookie, upstream->server_cookie_len); + val = buf; } + return _getdns_network_req_add_upstream_option(req, EDNS_COOKIE_OPCODE, sz, val); + } static int @@ -681,7 +672,7 @@ static int stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) { - size_t pkt_len = netreq->response - netreq->query; + size_t pkt_len; ssize_t written; uint16_t query_id; intptr_t query_id_intptr; @@ -704,16 +695,15 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) GLDNS_ID_SET(netreq->query, query_id); if (netreq->opt) { + _getdns_network_req_clear_upstream_options(netreq); /* no limits on the max udp payload size with tcp */ gldns_write_uint16(netreq->opt + 3, 65535); - if (netreq->owner->edns_cookies) { - netreq->response = attach_edns_cookie( - netreq->upstream, netreq->opt); - pkt_len = netreq->response - netreq->query; - gldns_write_uint16(netreq->query - 2, pkt_len); - } + if (netreq->owner->edns_cookies) + if (attach_edns_cookie(netreq)) + return STUB_OUT_OF_OPTIONS; } + pkt_len = netreq->response - netreq->query; /* We have an initialized packet buffer. * Lets see how much of it we can write */ @@ -1126,7 +1116,7 @@ static int stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, getdns_network_req *netreq) { - size_t pkt_len = netreq->response - netreq->query; + size_t pkt_len; ssize_t written; uint16_t query_id; intptr_t query_id_intptr; @@ -1156,10 +1146,16 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, &netreq->upstream->netreq_by_query_id, &netreq->node)); GLDNS_ID_SET(netreq->query, query_id); - if (netreq->opt) + if (netreq->opt) { + _getdns_network_req_clear_upstream_options(netreq); /* no limits on the max udp payload size with tcp */ gldns_write_uint16(netreq->opt + 3, 65535); + /* we do not edns_cookie over TLS, since TLS + * provides stronger guarantees than cookies + * already */ + } + pkt_len = netreq->response - netreq->query; /* We have an initialized packet buffer. * Lets see how much of it we can write */ @@ -1248,25 +1244,24 @@ stub_udp_write_cb(void *userarg) DEBUG_STUB("%s\n", __FUNCTION__); getdns_network_req *netreq = (getdns_network_req *)userarg; getdns_dns_req *dnsreq = netreq->owner; - size_t pkt_len = netreq->response - netreq->query; + size_t pkt_len; GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); netreq->query_id = arc4random(); GLDNS_ID_SET(netreq->query, netreq->query_id); if (netreq->opt) { + _getdns_network_req_clear_upstream_options(netreq); if (netreq->edns_maximum_udp_payload_size == -1) gldns_write_uint16(netreq->opt + 3, ( netreq->max_udp_payload_size = netreq->upstream->addr.ss_family == AF_INET6 ? 1232 : 1432)); - if (netreq->owner->edns_cookies) { - netreq->response = attach_edns_cookie( - netreq->upstream, netreq->opt); - pkt_len = netreq->response - netreq->query; - } + if (netreq->owner->edns_cookies) + if (attach_edns_cookie(netreq)) + return; /* too many upstream options */ } - + pkt_len = netreq->response - netreq->query; if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0, (struct sockaddr *)&netreq->upstream->addr, netreq->upstream->addr_len)) { diff --git a/src/types-internal.h b/src/types-internal.h index 93b97973..202fbc61 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -232,6 +232,19 @@ typedef struct getdns_network_req */ uint8_t *query; uint8_t *opt; /* offset of OPT RR in query */ + + /* each network_req has a set of base options that are + * specific to the query, which are static and included when + * the network_req is created. When the query is sent out to + * a given upstream, some additional options are added that + * are specific to the upstream. There can be at most + * GETDNS_MAXIMUM_UPSTREAM_OPTION_SPACE bytes of + * upstream-specific options. + + * use _getdns_network_req_clear_upstream_options() and + * _getdns_network_req_add_upstream_option() to fiddle with the + */ + size_t base_query_option_sz; size_t response_len; uint8_t *response; size_t wire_data_sz; @@ -344,5 +357,10 @@ getdns_dns_req *_getdns_dns_req_new(getdns_context *context, getdns_eventloop *l void _getdns_dns_req_free(getdns_dns_req * req); +/* network request utils */ +getdns_return_t _getdns_network_req_add_upstream_option(getdns_network_req * req, + uint16_t code, uint16_t sz, const void* data); +void _getdns_network_req_clear_upstream_options(getdns_network_req * req); + #endif /* types-internal.h */ From df3725e635bdc0dccc1207fd93b8f3b235fa24cc Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 12:20:12 +0900 Subject: [PATCH 10/18] added edns_client_subnet_private to getdns_context https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet-04 Using the above spec, an intermediate resolver may forward a chunk of the client's IP address to the authoritative resolver. Setting edns_client_subnet_private to a getdns_context in stub mode will indicate to the next-hop recursive resolver that the client wishes to keep their address information private. --- src/context.c | 29 +++++++++++++++++++++++++++++ src/context.h | 1 + src/getdns/getdns_extra.h.in | 7 +++++++ src/libgetdns.symbols | 2 ++ src/request-internal.c | 3 ++- src/stub.c | 23 +++++++++++++++++++++++ src/types-internal.h | 1 + 7 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/context.c b/src/context.c index 79dde85b..549c604b 100644 --- a/src/context.c +++ b/src/context.c @@ -881,6 +881,7 @@ getdns_context_create_with_extended_memory_functions( result->edns_extended_rcode = 0; result->edns_version = 0; result->edns_do_bit = 0; + result->edns_client_subnet_private = 0; result-> tls_ctx = NULL; result->extension = &result->mini_event.loop; @@ -1897,6 +1898,26 @@ getdns_context_set_edns_do_bit(struct getdns_context *context, uint8_t value) return GETDNS_RETURN_GOOD; } /* getdns_context_set_edns_do_bit */ +/* + * getdns_context_set_edns_client_subnet_private + * + */ +getdns_return_t +getdns_context_set_edns_client_subnet_private(struct getdns_context *context, uint8_t value) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + /* only allow 1 */ + if (value != 0 && value != 1) { + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } + + context->edns_client_subnet_private = value; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE); + + return GETDNS_RETURN_GOOD; +} /* getdns_context_set_edns_client_subnet_private */ + /* * getdns_context_set_extended_memory_functions * @@ -2966,4 +2987,12 @@ getdns_context_get_edns_do_bit(getdns_context *context, uint8_t* value) { return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* value) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); + *value = context->edns_client_subnet_private; + return GETDNS_RETURN_GOOD; +} + /* context.c */ diff --git a/src/context.h b/src/context.h index 8a205e4e..5b6620e5 100644 --- a/src/context.h +++ b/src/context.h @@ -157,6 +157,7 @@ struct getdns_context { uint8_t edns_version; uint8_t edns_do_bit; int edns_maximum_udp_payload_size; /* -1 is unset */ + uint8_t edns_client_subnet_private; SSL_CTX* tls_ctx; getdns_update_callback update_callback; diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index bd46a4c2..141dcc58 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -194,6 +194,11 @@ getdns_context_get_edns_version(getdns_context *context, uint8_t* value); getdns_return_t getdns_context_get_edns_do_bit(getdns_context *context, uint8_t* value); +getdns_return_t +getdns_context_set_edns_client_subnet_private(getdns_context *context, uint8_t value); +getdns_return_t +getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* value); + /** * Pretty print the getdns_dict in a given buffer snprintf style. @@ -366,6 +371,8 @@ typedef enum getdns_tls_authentication_t { #define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION 618 #define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT "Change related to getdns_context_set_tls_authentication" +#define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE 619 +#define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private" getdns_return_t getdns_context_set_tls_authentication( diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index c0241c31..9991f010 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -13,6 +13,7 @@ getdns_context_get_dnssec_allowed_skew getdns_context_get_dnssec_trust_anchors getdns_context_get_dns_transport getdns_context_get_dns_transport_list +getdns_context_get_edns_client_subnet_private getdns_context_get_edns_do_bit getdns_context_get_edns_extended_rcode getdns_context_get_edns_maximum_udp_payload_size @@ -36,6 +37,7 @@ getdns_context_set_dnssec_allowed_skew getdns_context_set_dnssec_trust_anchors getdns_context_set_dns_transport getdns_context_set_dns_transport_list +getdns_context_set_edns_client_subnet_private getdns_context_set_edns_do_bit getdns_context_set_edns_extended_rcode getdns_context_set_edns_maximum_udp_payload_size diff --git a/src/request-internal.c b/src/request-internal.c index 42c296ec..ddad29ec 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -367,7 +367,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != 512 || edns_extended_rcode != 0 || edns_version != 0 || noptions || - edns_cookies; + edns_cookies || context->edns_client_subnet_private; edns_maximum_udp_payload_size = with_opt && ( edns_maximum_udp_payload_size == -1 || @@ -437,6 +437,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->dnssec_return_only_secure = dnssec_return_only_secure; result->dnssec_return_validation_chain = dnssec_return_validation_chain; result->edns_cookies = edns_cookies; + result->edns_client_subnet_private = context->edns_client_subnet_private; /* will be set by caller */ result->user_pointer = NULL; diff --git a/src/stub.c b/src/stub.c index 582c02c5..0698e0eb 100644 --- a/src/stub.c +++ b/src/stub.c @@ -130,6 +130,20 @@ calc_new_cookie(getdns_upstream *upstream, uint8_t *cookie) cookie[i % 8] ^= md_value[i]; } +static getdns_return_t +attach_edns_client_subnet_private(getdns_network_req *req) +{ + /* see + * https://tools.ietf.org/html/draft-ietf-dnsop-edns-client-subnet-04#section-6 */ + /* all-zeros is a request to not leak the data further: */ + /* "\x00\x00" FAMILY: 0 (because no address) */ + /* "\x00" SOURCE PREFIX-LENGTH: 0 */ + /* "\x00"; SCOPE PREFIX-LENGTH: 0 */ + return _getdns_network_req_add_upstream_option(req, + GLDNS_EDNS_CLIENT_SUBNET, + 4, NULL); +} + static getdns_return_t attach_edns_cookie(getdns_network_req *req) { @@ -702,6 +716,9 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) if (netreq->owner->edns_cookies) if (attach_edns_cookie(netreq)) return STUB_OUT_OF_OPTIONS; + if (netreq->owner->edns_client_subnet_private) + if (attach_edns_client_subnet_private(netreq)) + return STUB_OUT_OF_OPTIONS; } pkt_len = netreq->response - netreq->query; /* We have an initialized packet buffer. @@ -1153,6 +1170,9 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, /* we do not edns_cookie over TLS, since TLS * provides stronger guarantees than cookies * already */ + if (netreq->owner->edns_client_subnet_private) + if (attach_edns_client_subnet_private(netreq)) + return STUB_OUT_OF_OPTIONS; } pkt_len = netreq->response - netreq->query; @@ -1260,6 +1280,9 @@ stub_udp_write_cb(void *userarg) if (netreq->owner->edns_cookies) if (attach_edns_cookie(netreq)) return; /* too many upstream options */ + if (netreq->owner->edns_client_subnet_private) + if (attach_edns_client_subnet_private(netreq)) + return; /* too many upstream options */ } pkt_len = netreq->response - netreq->query; if ((ssize_t)pkt_len != sendto(netreq->fd, netreq->query, pkt_len, 0, diff --git a/src/types-internal.h b/src/types-internal.h index 202fbc61..7c05e2b9 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -275,6 +275,7 @@ typedef struct getdns_dns_req { int dnssec_return_only_secure; int dnssec_return_validation_chain; int edns_cookies; + int edns_client_subnet_private; /* Internally used by return_validation_chain */ int dnssec_ok_checking_disabled; From 05585281eb08a7c7d9bd0ee9983f744b9d90032b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 12:37:42 +0900 Subject: [PATCH 11/18] add test for context update callback for edns_client_subnet_private --- ...tdns_context_set_context_update_callback.h | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/check_getdns_context_set_context_update_callback.h b/src/test/check_getdns_context_set_context_update_callback.h index 67bfc928..6cfef0df 100644 --- a/src/test/check_getdns_context_set_context_update_callback.h +++ b/src/test/check_getdns_context_set_context_update_callback.h @@ -365,6 +365,30 @@ } END_TEST + START_TEST (getdns_context_set_context_update_callback_20) + { + /* + * Create a context by calling getdns_context_create() + * Define a callback routine for context changes and call getdns_context_set_context_update_callback() so that it gets called when there are context changes + * Call getdns_context_set_edns_client_subnet_private() setting to 1 + * expect: GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE + */ + struct getdns_context *context = NULL; + CONTEXT_CREATE(TRUE); + + ASSERT_RC(getdns_context_set_context_update_callback(context, update_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_context_set_context_update_callback()"); + + expected_changed_item = GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE; + + ASSERT_RC(getdns_context_set_edns_client_subnet_private(context, 1), + GETDNS_RETURN_GOOD, "Return code from getdns_context_set_edns_client_subnet_private()"); + + CONTEXT_DESTROY; + + } + END_TEST + Suite * @@ -391,6 +415,7 @@ tcase_add_test(tc_pos, getdns_context_set_context_update_callback_17); tcase_add_test(tc_pos, getdns_context_set_context_update_callback_18); tcase_add_test(tc_pos, getdns_context_set_context_update_callback_19); + tcase_add_test(tc_pos, getdns_context_set_context_update_callback_20); suite_add_tcase(s, tc_pos); return s; From 8291cdb45547104ebe05752321ebd7185e804699 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 12:38:10 +0900 Subject: [PATCH 12/18] add -c flag for EDNS Client Subnet privacy to getdns_query --- src/test/getdns_query.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 6c1421a6..d47a8284 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -368,6 +368,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-A\taddress lookup ( is ignored)\n"); fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n"); fprintf(out, "\t-b \tSet edns0 max_udp_payload size\n"); + fprintf(out, "\t-c\tSend Client Subnet privacy request\n"); fprintf(out, "\t-D\tSet edns0 do bit\n"); fprintf(out, "\t-d\tclear edns0 do bit\n"); fprintf(out, "\t-e \tSet idle timeout in miliseconds\n"); @@ -655,6 +656,9 @@ getdns_return_t parse_args(int argc, char **argv) getdns_context_set_edns_maximum_udp_payload_size( context, (uint16_t) edns0_size); goto next; + case 'c': + getdns_context_set_edns_client_subnet_private(context, 1); + break; case 'D': (void) getdns_context_set_edns_do_bit(context, 1); break; From b3128652f469e7ca8b95436711c4ef911882e89b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 13:51:46 +0900 Subject: [PATCH 13/18] add tls_query_padding_blocksize property for getdns_context This is a parameter to the getdns_context that tells the context how much to pad queries that go out over TLS. It is not yet functional in this commit, but the idea is to pad each outbound query over TLS to a multiple of the requested blocksize. Because we only have a set amount of pre-allocated space for dynamic options (MAXIMUM_UPSTREAM_OPTION_SPACE), we limit the maximum padding blocksize. This is a simplistic padding policy. Suggestions for improved padding policies are welcome! --- src/context.c | 29 +++++++++++++++++++ src/context.h | 1 + src/getdns/getdns_extra.h.in | 7 +++++ src/libgetdns.symbols | 2 ++ ...tdns_context_set_context_update_callback.h | 25 ++++++++++++++++ 5 files changed, 64 insertions(+) diff --git a/src/context.c b/src/context.c index 549c604b..9dd7661e 100644 --- a/src/context.c +++ b/src/context.c @@ -882,6 +882,7 @@ getdns_context_create_with_extended_memory_functions( result->edns_version = 0; result->edns_do_bit = 0; result->edns_client_subnet_private = 0; + result->tls_query_padding_blocksize = 1; /* default is to not try to pad */ result-> tls_ctx = NULL; result->extension = &result->mini_event.loop; @@ -1918,6 +1919,26 @@ getdns_context_set_edns_client_subnet_private(struct getdns_context *context, ui return GETDNS_RETURN_GOOD; } /* getdns_context_set_edns_client_subnet_private */ +/* + * getdns_context_set_tls_query_padding_blocksize + * + */ +getdns_return_t +getdns_context_set_tls_query_padding_blocksize(struct getdns_context *context, uint16_t value) +{ + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + /* only allow values between 0 and MAXIMUM_UPSTREAM_OPTION_SPACE - 4 + (4 is for the overhead of the option itself) */ + if (value > MAXIMUM_UPSTREAM_OPTION_SPACE - 4) { + return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; + } + + context->tls_query_padding_blocksize = value; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE); + + return GETDNS_RETURN_GOOD; +} /* getdns_context_set_tls_query_padding_blocksize */ /* * getdns_context_set_extended_memory_functions * @@ -2995,4 +3016,12 @@ getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t* value) { + RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); + RETURN_IF_NULL(value, GETDNS_RETURN_INVALID_PARAMETER); + *value = context->tls_query_padding_blocksize; + return GETDNS_RETURN_GOOD; +} + /* context.c */ diff --git a/src/context.h b/src/context.h index 5b6620e5..1e489d2d 100644 --- a/src/context.h +++ b/src/context.h @@ -158,6 +158,7 @@ struct getdns_context { uint8_t edns_do_bit; int edns_maximum_udp_payload_size; /* -1 is unset */ uint8_t edns_client_subnet_private; + uint16_t tls_query_padding_blocksize; SSL_CTX* tls_ctx; getdns_update_callback update_callback; diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index 141dcc58..919d6b05 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -199,6 +199,11 @@ getdns_context_set_edns_client_subnet_private(getdns_context *context, uint8_t v getdns_return_t getdns_context_get_edns_client_subnet_private(getdns_context *context, uint8_t* value); +getdns_return_t +getdns_context_set_tls_query_padding_blocksize(getdns_context *context, uint16_t value); +getdns_return_t +getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t* value); + /** * Pretty print the getdns_dict in a given buffer snprintf style. @@ -373,6 +378,8 @@ typedef enum getdns_tls_authentication_t { #define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT "Change related to getdns_context_set_tls_authentication" #define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE 619 #define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private" +#define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE 620 +#define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize" getdns_return_t getdns_context_set_tls_authentication( diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 9991f010..39226295 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -26,6 +26,7 @@ getdns_context_get_num_pending_requests getdns_context_get_resolution_type getdns_context_get_suffix getdns_context_get_timeout +getdns_context_get_tls_query_padding_blocksize getdns_context_get_update_callback getdns_context_get_upstream_recursive_servers getdns_context_process_async @@ -54,6 +55,7 @@ getdns_context_set_return_dnssec_status getdns_context_set_suffix getdns_context_set_timeout getdns_context_set_tls_authentication +getdns_context_set_tls_query_padding_blocksize getdns_context_set_update_callback getdns_context_set_upstream_recursive_servers getdns_context_set_use_threads diff --git a/src/test/check_getdns_context_set_context_update_callback.h b/src/test/check_getdns_context_set_context_update_callback.h index 6cfef0df..2b5e6674 100644 --- a/src/test/check_getdns_context_set_context_update_callback.h +++ b/src/test/check_getdns_context_set_context_update_callback.h @@ -389,6 +389,30 @@ } END_TEST + START_TEST (getdns_context_set_context_update_callback_21) + { + /* + * Create a context by calling getdns_context_create() + * Define a callback routine for context changes and call getdns_context_set_context_update_callback() so that it gets called when there are context changes + * Call getdns_context_set_edns_client_subnet_private() setting to 1 + * expect: GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE + */ + struct getdns_context *context = NULL; + CONTEXT_CREATE(TRUE); + + ASSERT_RC(getdns_context_set_context_update_callback(context, update_callbackfn), + GETDNS_RETURN_GOOD, "Return code from getdns_context_set_context_update_callback()"); + + expected_changed_item = GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE; + + ASSERT_RC(getdns_context_set_tls_query_padding_blocksize(context, 1400), + GETDNS_RETURN_GOOD, "Return code from getdns_context_set_tls_query_padding_blocksize()"); + + CONTEXT_DESTROY; + + } + END_TEST + Suite * @@ -416,6 +440,7 @@ tcase_add_test(tc_pos, getdns_context_set_context_update_callback_18); tcase_add_test(tc_pos, getdns_context_set_context_update_callback_19); tcase_add_test(tc_pos, getdns_context_set_context_update_callback_20); + tcase_add_test(tc_pos, getdns_context_set_context_update_callback_21); suite_add_tcase(s, tc_pos); return s; From 1457c1a2b568ff1afc7f854aa9f91a3d160e5f3e Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 14:05:40 +0900 Subject: [PATCH 14/18] stash tls_query_padding_blocksize in the dns_req from the context --- src/request-internal.c | 4 +++- src/types-internal.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/request-internal.c b/src/request-internal.c index ddad29ec..31a080b1 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -367,7 +367,8 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, with_opt = edns_do_bit != 0 || edns_maximum_udp_payload_size != 512 || edns_extended_rcode != 0 || edns_version != 0 || noptions || - edns_cookies || context->edns_client_subnet_private; + edns_cookies || context->edns_client_subnet_private || + context->tls_query_padding_blocksize > 1; edns_maximum_udp_payload_size = with_opt && ( edns_maximum_udp_payload_size == -1 || @@ -438,6 +439,7 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, result->dnssec_return_validation_chain = dnssec_return_validation_chain; result->edns_cookies = edns_cookies; result->edns_client_subnet_private = context->edns_client_subnet_private; + result->tls_query_padding_blocksize = context->tls_query_padding_blocksize; /* will be set by caller */ result->user_pointer = NULL; diff --git a/src/types-internal.h b/src/types-internal.h index 7c05e2b9..96b458f0 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -276,6 +276,7 @@ typedef struct getdns_dns_req { int dnssec_return_validation_chain; int edns_cookies; int edns_client_subnet_private; + uint16_t tls_query_padding_blocksize; /* Internally used by return_validation_chain */ int dnssec_ok_checking_disabled; From 83bf5ab08b157463bc9c12a7a2c7ba191f33694c Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 14:58:12 +0900 Subject: [PATCH 15/18] actually implement tls_query_padding_blocksize since no DNS OPT value has been allocated, i chose a random value in the experimental/local range. --- configure.ac | 1 + src/stub.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/configure.ac b/configure.ac index 613eec79..253158ae 100644 --- a/configure.ac +++ b/configure.ac @@ -409,6 +409,7 @@ AC_DEFINE_UNQUOTED([EDNS_COOKIE_OPCODE], [10], [The edns cookie option code.]) AC_DEFINE_UNQUOTED([EDNS_COOKIE_ROLLOVER_TIME], [(24 * 60 * 60)], [How often the edns client cookie is refreshed.]) AC_DEFINE_UNQUOTED([MAXIMUM_UPSTREAM_OPTION_SPACE], [3000], [limit for dynamically-generated DNS options]) +AC_DEFINE_UNQUOTED([EDNS_PADDING_OPCODE], [65461], [The experimental edns padding option code.]) my_with_libunbound=1 AC_ARG_ENABLE(stub-only, AC_HELP_STRING([--enable-stub-only], [Restricts resolution modes to STUB (which will be the default mode). Removes the libunbound dependency.])) diff --git a/src/stub.c b/src/stub.c index 0698e0eb..c08e93e4 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1138,6 +1138,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, uint16_t query_id; intptr_t query_id_intptr; SSL* tls_obj = upstream->tls_obj; + uint16_t padding_sz; int q = tls_connected(upstream); if (q != 0) @@ -1173,6 +1174,17 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, if (netreq->owner->edns_client_subnet_private) if (attach_edns_client_subnet_private(netreq)) return STUB_OUT_OF_OPTIONS; + if (netreq->owner->tls_query_padding_blocksize > 1) { + pkt_len = netreq->response - netreq->query; + pkt_len += 4; /* this accounts for the OPTION-CODE and OPTION-LENGTH of the padding */ + padding_sz = pkt_len % netreq->owner->tls_query_padding_blocksize; + if (padding_sz) + padding_sz = netreq->owner->tls_query_padding_blocksize - padding_sz; + if (_getdns_network_req_add_upstream_option(netreq, + EDNS_PADDING_OPCODE, + padding_sz, NULL)) + return STUB_OUT_OF_OPTIONS; + } } pkt_len = netreq->response - netreq->query; From c322a8a330a1edeea3784e4d5cdec8438d2f08f9 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 1 Nov 2015 15:43:19 +0900 Subject: [PATCH 16/18] add -P flag to getdns_query for EDNS padding policy --- src/test/getdns_query.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index d47a8284..b2319ad8 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -261,7 +261,7 @@ 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 timeout, edns0_size, padding_blocksize; static int async = 0, interactive = 0; static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL; @@ -384,6 +384,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n"); fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n"); fprintf(out, "\t-p\tPretty print response dict\n"); + fprintf(out, "\t-P \tPad TLS queries to a multiple of blocksize\n"); fprintf(out, "\t-r\tSet recursing resolution type\n"); fprintf(out, "\t-q\tQuiet mode - don't print response\n"); fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n"); @@ -657,7 +658,8 @@ getdns_return_t parse_args(int argc, char **argv) context, (uint16_t) edns0_size); goto next; case 'c': - getdns_context_set_edns_client_subnet_private(context, 1); + if (getdns_context_set_edns_client_subnet_private(context, 1)) + return GETDNS_RETURN_GENERIC_ERROR; break; case 'D': (void) getdns_context_set_edns_do_bit(context, 1); @@ -706,6 +708,23 @@ getdns_return_t parse_args(int argc, char **argv) getdns_context_set_tls_authentication(context, GETDNS_AUTHENTICATION_HOSTNAME); break; + case 'P': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "tls_query_padding_blocksize " + "expected after -P\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + padding_blocksize = strtol(argv[i], &endptr, 10); + if (*endptr || padding_blocksize < 0) { + fprintf(stderr, "non-negative " + "numeric padding blocksize expected " + "after -P\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + if (getdns_context_set_tls_query_padding_blocksize( + context, padding_blocksize)) + return GETDNS_RETURN_GENERIC_ERROR; + goto next; case 'p': json = 0; case 'q': From 1bccd562447a7e1c3bf6ff51cf62bd672fc61fb7 Mon Sep 17 00:00:00 2001 From: Gowri Date: Mon, 2 Nov 2015 02:58:24 +0100 Subject: [PATCH 17/18] Name change on test server certificate --- src/test/tests_transports.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/tests_transports.sh b/src/test/tests_transports.sh index 15d31341..75efe2ca 100755 --- a/src/test/tests_transports.sh +++ b/src/test/tests_transports.sh @@ -2,7 +2,7 @@ DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) SERVER_IP="8.8.8.8" -TLS_SERVER_IP="185.49.141.38~www.dnssec-name-and-shame.com" +TLS_SERVER_IP="185.49.141.38~getdnsapi.net" GOOD_RESULT_SYNC="Status was: At least one response was returned" GOOD_RESULT_ASYNC="successfull" BAD_RESULT_SYNC="1 'Generic error'" @@ -58,7 +58,7 @@ usage () { echo " -p path to getdns_query binary" echo " -s server configured for only TCP and UDP" echo " -t server configured for TLS, STARTTLS, TCP and UDP" - echo " (This must include the hostname e.g. 185.49.141.38~www.dnssec-name-and-shame.com)" + echo " (This must include the hostname e.g. 185.49.141.38~getdnsapi.net)" } while getopts ":p:s:t:dh" opt; do @@ -130,4 +130,4 @@ done echo echo "Finished transport test: did $COUNT queries, $GOOD_COUNT passes, $FAIL_COUNT failures" -echo \ No newline at end of file +echo From 3a1905041315cf15f1a4441053de8ecf314de932 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Wed, 4 Nov 2015 16:17:53 +0900 Subject: [PATCH 18/18] Code review changes Commented inline on github --- src/util-internal.c | 137 ++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 74 deletions(-) diff --git a/src/util-internal.c b/src/util-internal.c index 6ff02bb2..ece41d3c 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -672,81 +672,68 @@ success: } getdns_dict * -_getdns_create_call_debugging_dict(getdns_context *context, - getdns_network_req *netreq, - getdns_dict *reply) { +_getdns_create_call_debugging_dict( + getdns_context *context, getdns_network_req *netreq) +{ + getdns_bindata qname; + getdns_dict *netreq_debug; + getdns_dict *address_debug = NULL; - getdns_bindata *qname = NULL; - uint32_t qtype; - getdns_dict *question = NULL; - if (getdns_dict_get_dict(reply, "question", &question)) { - return NULL; - } - if (getdns_dict_get_bindata(question, "qname", &qname)) { - return NULL; - } - if (getdns_dict_get_int(question, "qtype", &qtype)) { - return NULL; - } + assert(netreq); /* It is the responsibility of the caller to free this */ - getdns_dict *netreq_debug = getdns_dict_create_with_context(context); - if (netreq_debug == NULL) { + if (!(netreq_debug = getdns_dict_create_with_context(context))) return NULL; - } - getdns_dict *address_debug = getdns_dict_create_with_context(context); - if (address_debug == NULL){ - getdns_dict_destroy(netreq_debug); - return NULL; - } - _getdns_sockaddr_to_dict(context, &netreq->upstream->addr, &address_debug); + qname.data = netreq->owner->name; + qname.size = netreq->owner->name_len; + + if (getdns_dict_set_bindata(netreq_debug, "query_name", &qname) || + getdns_dict_set_int( netreq_debug, "query_type" + , netreq->request_type ) || + + /* Safe, because uint32_t facilitates RRT's of almost 50 days*/ + getdns_dict_set_int(netreq_debug, "run_time/ms", + (uint32_t)(( netreq->debug_end_time + - netreq->debug_start_time)/1000))) { - if (getdns_dict_set_bindata(netreq_debug, "query_name", qname)) { getdns_dict_destroy(netreq_debug); - getdns_dict_destroy(address_debug); return NULL; - } - if (getdns_dict_set_int(netreq_debug, "query_type", qtype)) { - getdns_dict_destroy(netreq_debug); + + } else if (!netreq->upstream) + + /* Nothing more for full recursion */ + return netreq_debug; + + + /* Stub resolver debug data */ + _getdns_sockaddr_to_dict( + context, &netreq->upstream->addr, &address_debug); + + if (getdns_dict_set_dict(netreq_debug, "query_to", address_debug) || + getdns_dict_set_int( netreq_debug, "transport" + , netreq->upstream->transport)) { + getdns_dict_destroy(address_debug); - return NULL; - } - if (getdns_dict_set_dict(netreq_debug, "query_to", address_debug)) { getdns_dict_destroy(netreq_debug); - getdns_dict_destroy(address_debug); return NULL; } getdns_dict_destroy(address_debug); + + if (netreq->upstream->transport != GETDNS_TRANSPORT_TLS) + return netreq_debug; - if (getdns_dict_set_int(netreq_debug, "transport", - netreq->upstream->transport)) { - getdns_dict_destroy(netreq_debug); - return NULL; - } - - /* TODO: This is not safe */ - uint32_t run_time = (uint32_t)(netreq->debug_end_time - netreq->debug_start_time); - if (getdns_dict_set_int(netreq_debug, "run_time/ms", run_time/1000)) { - getdns_dict_destroy(netreq_debug); - return NULL; - } /* Only include the auth status if TLS was used */ - if (netreq->upstream->transport == GETDNS_TRANSPORT_TLS) { - if (getdns_dict_util_set_string(netreq_debug, "tls_auth_status", - netreq->debug_tls_auth_status == 0 ? - "OK: Hostname matched valid cert." : - "FAILED: Server not validated.")) { - getdns_dict_destroy(netreq_debug); - return NULL; - } + if (getdns_dict_util_set_string(netreq_debug, "tls_auth_status", + netreq->debug_tls_auth_status == 0 ? + "OK: Hostname matched valid cert":"FAILED: Server not validated")){ + + getdns_dict_destroy(netreq_debug); + return NULL; } - return netreq_debug; - } - getdns_dict * _getdns_create_getdns_response(getdns_dns_req *completed_request) { @@ -754,13 +741,14 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) getdns_list *just_addrs = NULL; getdns_list *replies_full; getdns_list *replies_tree; - getdns_list *call_debugging; + getdns_list *call_debugging = NULL; getdns_network_req *netreq, **netreq_p; int rrsigs_in_answer = 0; getdns_dict *reply; getdns_bindata *canonical_name = NULL; int nreplies = 0, nanswers = 0, nsecure = 0, ninsecure = 0, nbogus = 0; getdns_bindata full_data; + getdns_dict *netreq_debug; /* info (bools) about dns_req */ int dnssec_return_status; @@ -790,10 +778,9 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) if (!(replies_tree = getdns_list_create_with_context(context))) goto error_free_replies_full; - if (completed_request->return_call_debugging) { - if (!(call_debugging = getdns_list_create_with_context(context))) - goto error_free_result; - } + if (completed_request->return_call_debugging && + !(call_debugging = getdns_list_create_with_context(context))) + goto error_free_replies_full; for ( netreq_p = completed_request->netreqs ; (netreq = *netreq_p) ; netreq_p++) { @@ -852,13 +839,17 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) goto error; } - if (completed_request->return_call_debugging) { - getdns_dict *netreq_debug; - if (!(netreq_debug = _getdns_create_call_debugging_dict(context, - netreq, reply))) { + if (call_debugging) { + if (!(netreq_debug = + _getdns_create_call_debugging_dict(context,netreq))) + goto error; + + if (_getdns_list_append_dict( + call_debugging, netreq_debug)) { + + getdns_dict_destroy(netreq_debug); goto error; } - _getdns_list_append_dict(call_debugging, netreq_debug); getdns_dict_destroy(netreq_debug); } @@ -874,15 +865,14 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) goto error; getdns_list_destroy(replies_tree); + if (call_debugging && + getdns_dict_set_list(result, "call_debugging", call_debugging)) + goto error_free_call_debugging; + if (getdns_dict_set_list(result, "replies_full", replies_full)) goto error_free_replies_full; getdns_list_destroy(replies_full); - if (completed_request->return_call_debugging) { - if (getdns_dict_set_list(result, "call_debugging", call_debugging)) - goto error_free_call_debugging; - } - if (just_addrs && getdns_dict_set_list( result, GETDNS_STR_KEY_JUST_ADDRS, just_addrs)) goto error_free_result; @@ -902,11 +892,10 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) error: /* cleanup */ getdns_list_destroy(replies_tree); +error_free_call_debugging: + getdns_list_destroy(call_debugging); error_free_replies_full: getdns_list_destroy(replies_full); -error_free_call_debugging: - if (completed_request->return_call_debugging) - getdns_list_destroy(call_debugging); error_free_result: getdns_list_destroy(just_addrs); getdns_dict_destroy(result);