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/dict.c b/src/dict.c index 16e0b3fb..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( @@ -994,6 +995,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/request-internal.c b/src/request-internal.c index 31a080b1..c08ba682 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -115,6 +115,11 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->response_len = 0; net_req->base_query_option_sz = opt_options_size; + /* 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->wire_data_sz = wire_data_sz; if (max_query_sz) { /* first two bytes will contain query length (for tcp) */ @@ -440,7 +445,9 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, 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; - + 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 c08e93e4..d211b486 100644 --- a/src/stub.c +++ b/src/stub.c @@ -1205,6 +1205,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 */ /**************************/ @@ -1266,6 +1279,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); } @@ -1280,6 +1294,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) { @@ -1345,7 +1360,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); @@ -1358,7 +1373,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; @@ -1451,7 +1466,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); @@ -1478,7 +1493,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)) @@ -1508,6 +1526,8 @@ upstream_write_cb(void *userarg) return; default: + /* 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 96b458f0..bb105ab5 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -226,6 +226,11 @@ 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; + /* 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. @@ -250,6 +255,8 @@ typedef struct getdns_network_req size_t wire_data_sz; uint8_t wire_data[]; + + } getdns_network_req; /** @@ -277,6 +284,7 @@ typedef struct getdns_dns_req { int edns_cookies; int edns_client_subnet_private; uint16_t tls_query_padding_blocksize; + 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..ece41d3c 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -671,6 +671,69 @@ success: return result; } +getdns_dict * +_getdns_create_call_debugging_dict( + getdns_context *context, getdns_network_req *netreq) +{ + getdns_bindata qname; + getdns_dict *netreq_debug; + getdns_dict *address_debug = NULL; + + assert(netreq); + + /* It is the responsibility of the caller to free this */ + if (!(netreq_debug = getdns_dict_create_with_context(context))) + return NULL; + + 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))) { + + getdns_dict_destroy(netreq_debug); + return NULL; + + } 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); + getdns_dict_destroy(netreq_debug); + return NULL; + } + getdns_dict_destroy(address_debug); + + if (netreq->upstream->transport != GETDNS_TRANSPORT_TLS) + return netreq_debug; + + /* Only include the auth status if TLS was used */ + 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) { @@ -678,12 +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 = 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; @@ -713,6 +778,10 @@ _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 && + !(call_debugging = getdns_list_create_with_context(context))) + goto error_free_replies_full; + for ( netreq_p = completed_request->netreqs ; (netreq = *netreq_p) ; netreq_p++) { @@ -769,6 +838,21 @@ _getdns_create_getdns_response(getdns_dns_req *completed_request) getdns_dict_destroy(reply); goto error; } + + 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_dict_destroy(netreq_debug); + } + getdns_dict_destroy(reply); /* buffer */ @@ -781,6 +865,10 @@ _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); @@ -804,6 +892,8 @@ _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_result: