From 1d092509b65227239caf2ef24c5031bd4f431c6e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Nov 2021 14:41:35 +0100 Subject: Merging upstream version 2.8.0. Signed-off-by: Daniel Baumann --- CHANGES | 24 +++++++++++++++++ configure | 20 +++++++------- configure.ac | 2 +- src/dnsperf.1.in | 17 ++++++++++++ src/dnsperf.c | 54 ++++++++++++++++++++++--------------- src/net_doh.c | 81 ++++++++++++++++++++++++++++++++++---------------------- src/opt.c | 35 ++++++++++++++++++++++++ src/opt.h | 11 ++++++++ src/resperf.c | 23 ++++++++++------ 9 files changed, 194 insertions(+), 73 deletions(-) diff --git a/CHANGES b/CHANGES index 99ef14c..6a23639 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,27 @@ +2021-11-02 Jerry Lundström + + Release 2.8.0 + + This release fixes response handling for DNS-over-HTTPS when multiple + responses are received within the same receive cycle, and adds a new + option to suppress some of the normal and verbose output. + + The network model within dnsperf and resperf can not process more then + one response at a time from a protocol module, so a buffer has been added + to the DNS-over-HTTPS module to handle this situation (this already exists + in all other modules). + + The new option `-O suppress=` can selectively suppress parts + of the normal and verbose output. Some of these messages might be + excessively displayed due to the network model and depending on what + protocol you use which makes usage harder then necessary. For example + during TCP connection stage, if you end-point is slow to establish + connection you will get a lot of output saying that the socket isn't ready + yet. + + 6a452b0 DoH response handling + e2828e7 Suppress + 2021-09-17 Jerry Lundström Release 2.7.1 diff --git a/configure b/configure index aef8378..ea9874c 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for dnsperf 2.7.1. +# Generated by GNU Autoconf 2.69 for dnsperf 2.8.0. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='dnsperf' PACKAGE_TARNAME='dnsperf' -PACKAGE_VERSION='2.7.1' -PACKAGE_STRING='dnsperf 2.7.1' +PACKAGE_VERSION='2.8.0' +PACKAGE_STRING='dnsperf 2.8.0' PACKAGE_BUGREPORT='admin@dns-oarc.net' PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues' @@ -1360,7 +1360,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dnsperf 2.7.1 to adapt to many kinds of systems. +\`configure' configures dnsperf 2.8.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1431,7 +1431,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dnsperf 2.7.1:";; + short | recursive ) echo "Configuration of dnsperf 2.8.0:";; esac cat <<\_ACEOF @@ -1570,7 +1570,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dnsperf configure 2.7.1 +dnsperf configure 2.8.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1939,7 +1939,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dnsperf $as_me 2.7.1, which was +It was created by dnsperf $as_me 2.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2802,7 +2802,7 @@ fi # Define the identity of the package. PACKAGE='dnsperf' - VERSION='2.7.1' + VERSION='2.8.0' cat >>confdefs.h <<_ACEOF @@ -14410,7 +14410,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by dnsperf $as_me 2.7.1, which was +This file was extended by dnsperf $as_me 2.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14477,7 +14477,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -dnsperf config.status 2.7.1 +dnsperf config.status 2.8.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index a4e044b..b3436df 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # limitations under the License. AC_PREREQ(2.64) -AC_INIT([dnsperf], [2.7.1], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues]) +AC_INIT([dnsperf], [2.8.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AC_CONFIG_SRCDIR([src/dnsperf.c]) AC_CONFIG_HEADER([src/config.h]) diff --git a/src/dnsperf.1.in b/src/dnsperf.1.in index 55cbdf1..99c0785 100644 --- a/src/dnsperf.1.in +++ b/src/dnsperf.1.in @@ -397,6 +397,23 @@ The URI to use for DNS-over-HTTPS, default value is The HTTP method to use when querying with DNS-over-HTTPS, default is GET. Available methods are: GET, POST. .RE + +\fBsuppress=\fIMESSAGE[,MESSAGE,...]\fR +.br +.RS +Suppress various messages and warnings that may be shown excessively in some +situations, such as socket readiness when connecting to a slow service. +Can suppress multiple types by listing them as a comma separated list. +Following type are available. + +\fBtimeouts\fR: Suppress messages about queries being timed out +.br +\fBcongestion\fR: Suppress messages about network congestion +.br +\fBsendfailed\fR: Suppress messages about failure to send packets or if only parts of the packet were sent +.br +\fBsockready\fR: Suppress messages about socket readiness +.RE .SH "SEE ALSO" \fBresperf\fR(1) .SH AUTHOR diff --git a/src/dnsperf.c b/src/dnsperf.c index 0f312ce..c3ff297 100644 --- a/src/dnsperf.c +++ b/src/dnsperf.c @@ -88,6 +88,7 @@ typedef struct { bool updates; bool verbose; enum perf_net_mode mode; + perf_suppress_t suppress; } config_t; typedef struct { @@ -399,17 +400,18 @@ stringify(unsigned int value) static void setup(int argc, char** argv, config_t* config) { - const char* family = NULL; - const char* server_name = DEFAULT_SERVER_NAME; - in_port_t server_port = 0; - const char* local_name = NULL; - in_port_t local_port = DEFAULT_LOCAL_PORT; - const char* filename = NULL; - const char* edns_option = NULL; - const char* tsigkey = NULL; - const char* mode = 0; - const char* doh_uri = DEFAULT_DOH_URI; - const char* doh_method = DEFAULT_DOH_METHOD; + const char* family = NULL; + const char* server_name = DEFAULT_SERVER_NAME; + in_port_t server_port = 0; + const char* local_name = NULL; + in_port_t local_port = DEFAULT_LOCAL_PORT; + const char* filename = NULL; + const char* edns_option = NULL; + const char* tsigkey = NULL; + const char* mode = 0; + const char* doh_uri = DEFAULT_DOH_URI; + const char* doh_method = DEFAULT_DOH_METHOD; + const char* local_suppress = 0; memset(config, 0, sizeof(*config)); config->argc = argc; @@ -487,6 +489,8 @@ setup(int argc, char** argv, config_t* config) "the URI to use for DNS-over-HTTPS", DEFAULT_DOH_URI, &doh_uri); perf_long_opt_add("doh-method", perf_opt_string, "doh_method", "the HTTP method to use for DNS-over-HTTPS: GET or POST", DEFAULT_DOH_METHOD, &doh_method); + perf_long_opt_add("suppress", perf_opt_string, "message[,message,...]", + "suppress messages/warnings, see man-page for list of message types", NULL, &local_suppress); bool log_stdout = false; perf_opt_add('W', perf_opt_boolean, NULL, "log warnings and errors to stdout instead of stderr", NULL, &log_stdout); @@ -497,6 +501,8 @@ setup(int argc, char** argv, config_t* config) perf_log_tostdout(); } + config->suppress = perf_opt_parse_suppress(local_suppress); + if (mode != 0) config->mode = perf_net_parsemode(mode); @@ -695,14 +701,14 @@ do_send(void* arg) q->sock = tinfo->socks[tinfo->current_sock++ % tinfo->nsocks]; switch (perf_net_sockready(q->sock, threadpipe[0], TIMEOUT_CHECK_TIME)) { case 0: - if (config->verbose) { + if (config->verbose && !config->suppress.sockready) { perf_log_warning("socket %p not ready", q->sock); } q->sock = 0; all_fail = false; continue; case -1: - if (config->verbose) { + if (config->verbose && !config->suppress.sockready) { perf_log_warning("socket %p readiness check timed out", q->sock); } q->sock = 0; @@ -765,12 +771,12 @@ do_send(void* arg) config->server_addr.length); if (n < 0) { if (errno == EINPROGRESS) { - if (config->verbose) { + if (config->verbose && !config->suppress.congestion) { perf_log_warning("network congested, packet sending in progress"); } any_inprogress = 1; } else { - if (config->verbose) { + if (config->verbose && !config->suppress.sendfailed) { char __s[256]; perf_log_warning("failed to send packet: %s", perf_strerror_r(errno, __s, sizeof(__s))); } @@ -780,7 +786,9 @@ do_send(void* arg) continue; } } else if ((unsigned int)n != length) { - perf_log_warning("failed to send full packet: only sent %d of %u", n, length); + if (!config->suppress.sendfailed) { + perf_log_warning("failed to send full packet: only sent %d of %u", n, length); + } PERF_LOCK(&tinfo->lock); query_move(tinfo, q, prepend_unused); PERF_UNLOCK(&tinfo->lock); @@ -827,12 +835,14 @@ process_timeouts(threadinfo_t* tinfo, uint64_t now) tinfo->stats.num_timedout++; - if (q->desc != NULL) { - perf_log_printf("> T %s", q->desc); - } else { - perf_log_printf("[Timeout] %s timed out: msg id %u", - config->updates ? "Update" : "Query", - (unsigned int)(q - tinfo->queries)); + if (!config->suppress.timeouts) { + if (q->desc != NULL) { + perf_log_printf("> T %s", q->desc); + } else { + perf_log_printf("[Timeout] %s timed out: msg id %u", + config->updates ? "Update" : "Query", + (unsigned int)(q - tinfo->queries)); + } } q = perf_list_tail(tinfo->outstanding_queries); } while (q != NULL && q->timestamp < now && now - q->timestamp >= config->timeout); diff --git a/src/net_doh.c b/src/net_doh.c index 0689fc6..0920696 100644 --- a/src/net_doh.c +++ b/src/net_doh.c @@ -115,6 +115,9 @@ struct perf__doh_socket { bool http2_is_dns; struct _doh_stats stats; + + char recvbuf[TCP_RECV_BUF_SIZE]; + size_t recv_at; }; static pthread_mutex_t _nghttp2_lock = PTHREAD_MUTEX_INITIALIZER; @@ -291,50 +294,62 @@ static ssize_t perf__doh_recv(struct perf_net_socket* sock, void* buf, size_t le return -1; } - uint8_t recvbuf[TCP_RECV_BUF_SIZE]; - ssize_t n = SSL_read(self->ssl, recvbuf, TCP_RECV_BUF_SIZE); - if (!n) { - perf__doh_reconnect(sock); - PERF_UNLOCK(&self->lock); - errno = EAGAIN; - return -1; - } - if (n < 0) { - int err = SSL_get_error(self->ssl, n); - switch (err) { - case SSL_ERROR_WANT_READ: + if (self->recv_at < sizeof(self->recvbuf)) { + // try to recv more if we can + ssize_t n = SSL_read(self->ssl, self->recvbuf + self->recv_at, sizeof(self->recvbuf) - self->recv_at); + if (!n) { + perf__doh_reconnect(sock); + PERF_UNLOCK(&self->lock); errno = EAGAIN; - break; - case SSL_ERROR_SYSCALL: - switch (errno) { - case ECONNREFUSED: - case ECONNRESET: - case ENOTCONN: - perf__doh_reconnect(sock); + return -1; + } + if (n < 0) { + int err = SSL_get_error(self->ssl, n); + switch (err) { + case SSL_ERROR_WANT_READ: + if (self->recv_at) { + // did not recv but we got something in buffer + break; + } errno = EAGAIN; - break; + PERF_UNLOCK(&self->lock); + return -1; + case SSL_ERROR_SYSCALL: + switch (errno) { + case ECONNREFUSED: + case ECONNRESET: + case ENOTCONN: + perf__doh_reconnect(sock); + errno = EAGAIN; + break; + default: + break; + } + PERF_UNLOCK(&self->lock); + return -1; default: - break; + errno = EBADF; + PERF_UNLOCK(&self->lock); + return -1; } - break; - default: - errno = EBADF; - break; + } else { + self->recv_at += n; } - PERF_UNLOCK(&self->lock); - return -1; } // this will be processed by nghttp2 callbacks - int ret = nghttp2_session_mem_recv(self->http2.session, recvbuf, n); + ssize_t ret = nghttp2_session_mem_recv(self->http2.session, (uint8_t*)self->recvbuf, self->recv_at); if (ret < 0) { perf_log_warning("nghttp2_session_mem_recv failed: %s", nghttp2_strerror(ret)); PERF_UNLOCK(&self->lock); return -1; } - // TODO: handle partial mem_recv - if (ret != n) { - perf_log_fatal("perf__doh_recv() mem_recv did not take all"); + if (ret != self->recv_at) { + // only process one response per call + memmove(self->recvbuf, self->recvbuf + ret, self->recv_at - ret); + self->recv_at -= ret; + } else { + self->recv_at = 0; } // TODO: is this faster then mem_recv? @@ -850,7 +865,9 @@ static int _http2_data_chunk_recv_cb(nghttp2_session* session, } if (self->http2.dnsmsg_completed) { - perf_log_fatal("_http2_data_chunk_recv_cb: chunk received when already having a dns msg"); + // pause for now and don't process this chunk + // can only do one response at a time in perf__doh_recv() + return NGHTTP2_ERR_PAUSE; } // TODO: point of nghttp2_session_get_stream_user_data() code? diff --git a/src/opt.c b/src/opt.c index 4ea798d..01949e6 100644 --- a/src/opt.c +++ b/src/opt.c @@ -366,3 +366,38 @@ void perf_opt_parse(int argc, char** argv) exit(1); } } + +perf_suppress_t perf_opt_parse_suppress(const char* val) +{ + perf_suppress_t s = { false, false, false }; + + while (val && *val) { + const char* next = strchr(val, ','); + int len; + if (next) { + len = next - val; + next += 1; + } else { + len = strlen(val); + next = 0; + } + + if (!strncmp(val, "timeouts", len)) { + s.timeouts = true; + } else if (!strncmp(val, "congestion", len)) { + s.congestion = true; + } else if (!strncmp(val, "sendfailed", len)) { + s.sendfailed = true; + } else if (!strncmp(val, "sockready", len)) { + s.sockready = true; + } else { + fprintf(stderr, "unknown message type to suppress: %.*s\n", len, val); + perf_opt_usage(); + exit(1); + } + + val = next; + } + + return s; +} diff --git a/src/opt.h b/src/opt.h index 22a460b..7e8433f 100644 --- a/src/opt.h +++ b/src/opt.h @@ -20,6 +20,8 @@ #ifndef PERF_OPT_H #define PERF_OPT_H 1 +#include + typedef enum { perf_opt_string, perf_opt_boolean, @@ -30,6 +32,13 @@ typedef enum { perf_opt_port, } perf_opttype_t; +typedef struct { + bool timeouts; + bool congestion; + bool sendfailed; + bool sockready; +} perf_suppress_t; + void perf_opt_add(char c, perf_opttype_t type, const char* desc, const char* help, const char* defval, void* valp); void perf_long_opt_add(const char* name, perf_opttype_t type, const char* desc, const char* help, const char* defval, void* valp); @@ -38,4 +47,6 @@ void perf_long_opt_usage(void); void perf_opt_parse(int argc, char** argv); +perf_suppress_t perf_opt_parse_suppress(const char* val); + #endif diff --git a/src/resperf.c b/src/resperf.c index 2a93bf1..a62c819 100644 --- a/src/resperf.c +++ b/src/resperf.c @@ -205,6 +205,8 @@ static perf_tsigkey_t* tsigkey; static bool verbose; static unsigned int max_fall_behind; +static perf_suppress_t suppress; + const char* progname = "resperf"; static char* @@ -251,6 +253,7 @@ static void setup(int argc, char** argv) const char* edns_option_str = NULL; const char* doh_uri = DEFAULT_DOH_URI; const char* doh_method = DEFAULT_DOH_METHOD; + const char* local_suppress = 0; sock_family = AF_UNSPEC; server_port = 0; @@ -332,6 +335,8 @@ static void setup(int argc, char** argv) "the URI to use for DNS-over-HTTPS", DEFAULT_DOH_URI, &doh_uri); perf_long_opt_add("doh-method", perf_opt_string, "doh_method", "the HTTP method to use for DNS-over-HTTPS: GET or POST", DEFAULT_DOH_METHOD, &doh_method); + perf_long_opt_add("suppress", perf_opt_string, "message[,message,...]", + "suppress messages/warnings, see dnsperf(1) man-page for list of message types", NULL, &local_suppress); perf_opt_parse(argc, argv); @@ -339,6 +344,8 @@ static void setup(int argc, char** argv) perf_log_tostdout(); } + suppress = perf_opt_parse_suppress(local_suppress); + if (_mode != 0) mode = perf_net_parsemode(_mode); @@ -574,11 +581,11 @@ do_one_line(perf_buffer_t* lines, perf_buffer_t* msg) while (q->is_inprogress) { if (perf_net_sockready(socks[sock], dummypipe[0], TIMEOUT_CHECK_TIME) == -1) { if (errno == EINPROGRESS) { - if (verbose) { + if (verbose && !suppress.congestion) { perf_log_warning("network congested, packet sending in progress"); } } else { - if (verbose) { + if (verbose && !suppress.sockready) { char __s[256]; perf_log_warning("failed to check socket readiness: %s", perf_strerror_r(errno, __s, sizeof(__s))); } @@ -603,16 +610,16 @@ do_one_line(perf_buffer_t* lines, perf_buffer_t* msg) switch (perf_net_sockready(socks[sock], dummypipe[0], TIMEOUT_CHECK_TIME)) { case 0: - if (verbose) { + if (verbose && !suppress.sockready) { perf_log_warning("failed to send packet: socket %d not ready", sock); } return (PERF_R_FAILURE); case -1: if (errno == EINPROGRESS) { - if (verbose) { + if (verbose && !suppress.congestion) { perf_log_warning("network congested, packet sending in progress"); } - } else { + } else if (!suppress.sockready) { perf_log_warning("failed to send packet: socket %d not ready", sock); } return (PERF_R_FAILURE); @@ -642,12 +649,12 @@ do_one_line(perf_buffer_t* lines, perf_buffer_t* msg) &server_addr.sa.sa, server_addr.length) < 1) { if (errno == EINPROGRESS) { - if (verbose) { + if (verbose && !suppress.congestion) { perf_log_warning("network congested, packet sending in progress"); } q->is_inprogress = true; } else { - if (verbose) { + if (verbose && !suppress.sendfailed) { char __s[256]; perf_log_warning("failed to send packet: %s", perf_strerror_r(errno, __s, sizeof(__s))); } @@ -702,7 +709,7 @@ try_process_response(unsigned int sockindex) if (perf_net_sockready(socks[sockindex], dummypipe[0], TIMEOUT_CHECK_TIME) == -1) { if (errno != EINPROGRESS) { - if (verbose) { + if (verbose && !suppress.sockready) { char __s[256]; perf_log_warning("failed to check socket readiness: %s", perf_strerror_r(errno, __s, sizeof(__s))); } -- cgit v1.2.3