summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES24
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--src/dnsperf.1.in17
-rw-r--r--src/dnsperf.c54
-rw-r--r--src/net_doh.c81
-rw-r--r--src/opt.c35
-rw-r--r--src/opt.h11
-rw-r--r--src/resperf.c23
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=<message,...>` 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 <admin@dns-oarc.net>.
#
@@ -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 <stdbool.h>
+
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)));
}