From ab60211020e6640735023493d5e7e4bd0c0369a8 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Tue, 11 Aug 2015 18:34:32 +0100 Subject: [PATCH] Fix fallback failures. Add manual regression test script. --- build/src/test/tests_transports.sh | 120 +++++++++++++++++++++++++++++ src/stub.c | 18 +++-- src/test/getdns_query.c | 6 +- 3 files changed, 136 insertions(+), 8 deletions(-) create mode 100755 build/src/test/tests_transports.sh diff --git a/build/src/test/tests_transports.sh b/build/src/test/tests_transports.sh new file mode 100755 index 00000000..4ed780bd --- /dev/null +++ b/build/src/test/tests_transports.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash + +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +SERVER_IP="8.8.8.8" +TLS_SERVER_IP="185.49.141.38" +GOOD_RESULT_SYNC="Status was: At least one response was returned" +GOOD_RESULT_ASYNC="successfull" +BAD_RESULT_SYNC="1 'Generic error'" +BAD_RESULT_ASYNC="callback_type of 703" +GOOD_COUNT=0 +FAIL_COUNT=0 + +check_good () { + result=`echo $1 | grep "Response code was: GOOD." | tail -1 | sed 's/ All done.'// | sed 's/Response code was: GOOD. '//` + async_success=`echo $result | grep -c "$GOOD_RESULT_ASYNC"` + if [[ $result =~ $GOOD_RESULT_SYNC ]] || [[ $async_success =~ 1 ]]; then + (( GOOD_COUNT++ )) + echo -n "PASS: " + else + (( FAIL_COUNT++ )) + echo "FAIL (RESULT): " $1 + echo -n "FAIL: " + fi +} + +check_bad () { + result=`echo $1 | grep "An error occurred:" | tail -1 | sed 's/ All done.'//` + error=` echo $result | sed 's/An error occurred: //'` + if [[ ! -z $result ]]; then + if [[ $error =~ $BAD_RESULT_SYNC ]] || [[ $error =~ $BAD_RESULT_ASYNC ]]; then + (( GOOD_COUNT++ )) + echo -n "PASS:" + else + (( FAIL_COUNT++ )) + echo "FAIL (RESULT): " $error + echo -n "FAIL: " + fi + else + (( FAIL_COUNT++ )) + echo "FAIL (RESULT): " $1 + echo -n "FAIL: " + fi +} + +usage () { + echo "This is a basic and temporary testing script for the transport list" + echo "functionality that utilises getdns_query to perform multiple queries." + echo "It will be replaced by an automated test harness in future, but" + echo "it can be used to check the basic functionality for now. It is recommended that" + echo "local or known test servers are used, but it should work with the default servers:" + echo " - Google Open DNS for TCP and UDP only " + echo "- the getdnsapi.net test server Open Resolver for TLS, STARTTLS, TCP and UDP" + echo + echo "usage: test_transport.sh" + echo " -s server configured for only TCP and UDP" + echo " -t server configured for TLS, STARTTLS, TCP and UDP" +} + +while getopts ":s:t:dh" opt; do + case $opt in + d ) set -x ;; + s ) SERVER_IP=$OPTARG ; echo "Setting server to $OPTARG" ;; + t ) TLS_SERVER_IP=$OPTARG ; echo "Setting TLS server to $OPTARG" ;; + h ) usage ; exit ;; + esac +done + +GOOD_QUERIES=( +"-s -A -q getdnsapi.net -l U @${SERVER_IP} " +"-s -A -q getdnsapi.net -l T @${SERVER_IP} " +"-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP}" +"-s -A -q getdnsapi.net -l S @${TLS_SERVER_IP}") + +GOOD_FALLBACK_QUERIES=( +"-s -A -q getdnsapi.net -l LT @${SERVER_IP}" +"-s -A -q getdnsapi.net -l LU @${SERVER_IP}" +"-s -A -q getdnsapi.net -l L @${SERVER_IP} @${TLS_SERVER_IP}" +"-s -G -q DNSKEY getdnsapi.net -l UT @${SERVER_IP} -b 512 -D") + +NOT_AVAILABLE_QUERIES=( +"-s -A -q getdnsapi.net -l L @${SERVER_IP} " +"-s -A -q getdnsapi.net -l S @${SERVER_IP} " +"-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") + +echo "Starting transport test" +echo +for (( i = 0; i < 2; i+=1 )); do + if [[ i -eq 0 ]]; then + echo "**SYNC Mode**" + else + echo + echo "**ASYNC Mode**" + SYNC_MODE=" -a " + fi + + echo "*Success cases:" + for (( j = 0; j < ${#GOOD_QUERIES[@]}; j+=1 )); do + check_good "`$DIR/getdns_query $SYNC_MODE ${GOOD_QUERIES[${j}]} 2>/dev/null`" + echo "getdns_query $SYNC_MODE ${GOOD_QUERIES[${j}]}" + (( COUNT++ )) + done + + echo "*Success fallback cases:" + for (( j = 0; j < ${#GOOD_FALLBACK_QUERIES[@]}; j+=1 )); do + check_good "`$DIR/getdns_query $SYNC_MODE ${GOOD_FALLBACK_QUERIES[${j}]} 2>/dev/null`" + echo "getdns_query $SYNC_MODE ${GOOD_FALLBACK_QUERIES[${j}]}" + (( COUNT++ )) + done + + echo "*Transport not available cases:" + for (( j = 0; j < ${#NOT_AVAILABLE_QUERIES[@]}; j+=1 )); do + check_bad "`$DIR/getdns_query $SYNC_MODE ${NOT_AVAILABLE_QUERIES[${j}]} 2>&1`" + echo "getdns_query $SYNC_MODE ${NOT_AVAILABLE_QUERIES[${j}]}" + (( COUNT++ )) + done +done + +echo +echo "Finished transport test: did $COUNT queries, $GOOD_COUNT passes, $FAIL_COUNT failures" +echo \ No newline at end of file diff --git a/src/stub.c b/src/stub.c index f3896fec..f9d28379 100644 --- a/src/stub.c +++ b/src/stub.c @@ -370,6 +370,7 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) static int tcp_connected(getdns_upstream *upstream) { /* Already tried and failed, so let the fallback code take care of things */ + /* TODO: We _should_ use a timeout on the TCP handshake*/ if (upstream->fd == -1 || upstream->tcp.write_error != 0) return STUB_TCP_ERROR; @@ -448,7 +449,8 @@ static int tls_cleanup(getdns_upstream *upstream) { DEBUG_STUB("*** %s\n", __FUNCTION__); - SSL_free(upstream->tls_obj); + if (upstream->tls_obj != NULL) + SSL_free(upstream->tls_obj); upstream->tls_obj = NULL; upstream->tls_hs_state = GETDNS_HS_FAILED; /* Reset timeout on failure*/ @@ -1376,10 +1378,10 @@ upstream_write_cb(void *userarg) /* Unqueue the netreq from the write_queue */ if (!(upstream->write_queue = netreq->write_queue_tail)) { upstream->write_queue_last = NULL; - GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.write_cb = NULL; /* Reschedule (if already reading) to clear writable */ if (upstream->event.read_cb) { + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, &upstream->event); @@ -1645,7 +1647,6 @@ upstream_reschedule_events(getdns_upstream *upstream, size_t idle_timeout) { DEBUG_STUB("# %s: %p %d\n", __FUNCTION__, upstream, upstream->fd); int reschedule = 0; - GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); if (!upstream->write_queue && upstream->event.write_cb) { upstream->event.write_cb = NULL; reschedule = 1; @@ -1663,6 +1664,7 @@ upstream_reschedule_events(getdns_upstream *upstream, size_t idle_timeout) { reschedule = 1; } if (reschedule) { + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); if (upstream->event.read_cb || upstream->event.write_cb) GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, &upstream->event); @@ -1775,12 +1777,18 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq) case GETDNS_TRANSPORT_TCP: upstream_schedule_netreq(netreq->upstream, netreq); /* TODO[TLS]: Change scheduling for sync calls. */ + /* For TLS, set a short timeout to catch setup problems. This is reset + when the connection is successful.*/ GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); GETDNS_SCHEDULE_EVENT( - dnsreq->loop, netreq->upstream->fd, dnsreq->context->timeout, + dnsreq->loop, netreq->upstream->fd, /*dnsreq->context->timeout,*/ + (transport == GETDNS_TRANSPORT_TLS ? + dnsreq->context->timeout / 2 : dnsreq->context->timeout), getdns_eventloop_event_init(&netreq->event, netreq, NULL, ( dnsreq->loop != netreq->upstream->loop /* Synchronous lookup? */ - ? netreq_upstream_write_cb : NULL), stub_timeout_cb)); + ? netreq_upstream_write_cb : NULL), + ( transport == GETDNS_TRANSPORT_TLS ? + stub_tls_timeout_cb : stub_timeout_cb))); return GETDNS_RETURN_GOOD; default: diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 88a8852d..31877010 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -272,16 +272,16 @@ void callback(getdns_context *context, getdns_callback_type_t callback_type, free(response_str); } fprintf(stdout, - "Result: The callback with ID %llu was successfull.\n", + "Response code was: GOOD. Status was: Callback with ID %llu was successfull.\n", (unsigned long long)trans_id); } else if (callback_type == GETDNS_CALLBACK_CANCEL) fprintf(stderr, - "Result: The callback with ID %llu was cancelled. Exiting.\n", + "An error occurred: The callback with ID %llu was cancelled. Exiting.\n", (unsigned long long)trans_id); else { fprintf(stderr, - "Result: The callback got a callback_type of %d. Exiting.\n", + "An error occurred: The callback got a callback_type of %d. Exiting.\n", callback_type); fprintf(stderr, "Error : '%s'\n",