1
0
Fork 0

Adding upstream version 2.7.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 08:58:37 +01:00
parent dd7b5026ba
commit 462f4c9882
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
27 changed files with 1877 additions and 102 deletions

43
CHANGES
View file

@ -1,3 +1,46 @@
2021-08-09 Jerry Lundström
Release 2.7.0
This release adds DNS-over-HTTPS support!
DNS-over-HTTPS can be used by specifying transport mode `doh` and you
should also look at the dnsperf(1) man-page (or `-H`) for the extended
options `doh-uri` and `doh-method`, which controls aspects of DoH/HTTP/2
that you might want to set.
Other fixes:
- Add check when constructing DNS packet so that total length of labels
does not exceed 255 bytes
- Fix connection/reconnection state handling for DoT transport
- Fix event handling by initializing them directly when opening the
sockets, otherwise events could have been missed which would give
incorrect statistics
61b5eac Tests with dumdumd
d71071c Tests with dumdumd
b42f92e DoH sending
2fa40bb Net stats
f7f8692 DoH fixes
ea62b49 DoH concurrent streams
91929f1 DoH reconnect
17660e6 DoH fixes
5276aa6 resperf buckets
585860e Packages
3ffc601 Fixes
1570609 Man-page
6bcadc7 README
f81adf1 Fixes
1acd71f Code structure
6c47876 Fixes
2d379f4 Fixes
4d5384b Fixes
cee93b3 Initial DNS-over-HTTPS support implementation
4ff3ebc Events
8b24bbf DoT state
6a5b5ef Fix too long name
71fa09f long opts
2021-05-31 Jerry Lundström
Release 2.6.0

View file

@ -365,6 +365,8 @@ libdir = @libdir@
libexecdir = @libexecdir@
libldns_CFLAGS = @libldns_CFLAGS@
libldns_LIBS = @libldns_LIBS@
libnghttp2_CFLAGS = @libnghttp2_CFLAGS@
libnghttp2_LIBS = @libnghttp2_LIBS@
libssl_CFLAGS = @libssl_CFLAGS@
libssl_LIBS = @libssl_LIBS@
localedir = @localedir@

View file

@ -46,25 +46,26 @@ environment with autoconf, automake, libtool and pkgconfig.
- [OpenSSL](https://www.openssl.org/) - for TSIG support
- [Concurrency Kit](http://concurrencykit.org/) - for atomic operations
- [LDNS](https://nlnetlabs.nl/projects/ldns/about/) - optional for dynamic update support
- [nghttp2](https://nghttp2.org) - for DNS-over-HTTPS support using HTTP/2
To install the dependencies under Debian/Ubuntu:
```
apt-get install -y libssl-dev libldns-dev libck-dev
apt-get install -y libssl-dev libldns-dev libck-dev libnghttp2-dev
```
To install the dependencies under CentOS (with EPEL enabled):
```
yum install -y openssl-devel ldns-devel ck-devel
yum install -y openssl-devel ldns-devel ck-devel libnghttp2-devel
```
To install the dependencies under FreeBSD 12+ using `pkg`:
```
pkg install -y openssl ldns concurrencykit
pkg install -y openssl ldns concurrencykit libnghttp2
```
To install the dependencies under OpenBSD 6+ using `pkg_add`:
```
pkg_add libldns
pkg_add libldns nghttp2
```
## Building from source tarball

230
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for dnsperf 2.6.0.
# Generated by GNU Autoconf 2.69 for dnsperf 2.7.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.6.0'
PACKAGE_STRING='dnsperf 2.6.0'
PACKAGE_VERSION='2.7.0'
PACKAGE_STRING='dnsperf 2.7.0'
PACKAGE_BUGREPORT='admin@dns-oarc.net'
PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues'
@ -636,6 +636,8 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
libnghttp2_LIBS
libnghttp2_CFLAGS
libldns_LIBS
libldns_CFLAGS
ck_LIBS
@ -805,7 +807,9 @@ libcrypto_LIBS
ck_CFLAGS
ck_LIBS
libldns_CFLAGS
libldns_LIBS'
libldns_LIBS
libnghttp2_CFLAGS
libnghttp2_LIBS'
# Initialize some variables set by options.
@ -1356,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.6.0 to adapt to many kinds of systems.
\`configure' configures dnsperf 2.7.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1427,7 +1431,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of dnsperf 2.6.0:";;
short | recursive ) echo "Configuration of dnsperf 2.7.0:";;
esac
cat <<\_ACEOF
@ -1494,6 +1498,10 @@ Some influential environment variables:
C compiler flags for libldns, overriding pkg-config
libldns_LIBS
linker flags for libldns, overriding pkg-config
libnghttp2_CFLAGS
C compiler flags for libnghttp2, overriding pkg-config
libnghttp2_LIBS
linker flags for libnghttp2, overriding pkg-config
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@ -1562,7 +1570,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
dnsperf configure 2.6.0
dnsperf configure 2.7.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1931,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.6.0, which was
It was created by dnsperf $as_me 2.7.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2794,7 +2802,7 @@ fi
# Define the identity of the package.
PACKAGE='dnsperf'
VERSION='2.6.0'
VERSION='2.7.0'
cat >>confdefs.h <<_ACEOF
@ -13665,6 +13673,206 @@ $as_echo "#define HAVE_LDNS 1" >>confdefs.h
fi
# Check for nghttp2
pkg_failed=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnghttp2" >&5
$as_echo_n "checking for libnghttp2... " >&6; }
if test -n "$libnghttp2_CFLAGS"; then
pkg_cv_libnghttp2_CFLAGS="$libnghttp2_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2 >= 0\""; } >&5
($PKG_CONFIG --exists --print-errors "libnghttp2 >= 0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libnghttp2_CFLAGS=`$PKG_CONFIG --cflags "libnghttp2 >= 0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test -n "$libnghttp2_LIBS"; then
pkg_cv_libnghttp2_LIBS="$libnghttp2_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
{ { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnghttp2 >= 0\""; } >&5
($PKG_CONFIG --exists --print-errors "libnghttp2 >= 0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
pkg_cv_libnghttp2_LIBS=`$PKG_CONFIG --libs "libnghttp2 >= 0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
fi
else
pkg_failed=untried
fi
if test $pkg_failed = yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
libnghttp2_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnghttp2 >= 0" 2>&1`
else
libnghttp2_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnghttp2 >= 0" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$libnghttp2_PKG_ERRORS" >&5
for ac_header in nghttp2.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "nghttp2.h" "ac_cv_header_nghttp2_h" "$ac_includes_default"
if test "x$ac_cv_header_nghttp2_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_NGHTTP2_H 1
_ACEOF
else
as_fn_error $? "nghttp2 headers not found" "$LINENO" 5
fi
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nghttp2_session in -lnghttp2" >&5
$as_echo_n "checking for nghttp2_session in -lnghttp2... " >&6; }
if ${ac_cv_lib_nghttp2_nghttp2_session+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lnghttp2 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char nghttp2_session ();
int
main ()
{
return nghttp2_session ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_nghttp2_nghttp2_session=yes
else
ac_cv_lib_nghttp2_nghttp2_session=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_session" >&5
$as_echo "$ac_cv_lib_nghttp2_nghttp2_session" >&6; }
if test "x$ac_cv_lib_nghttp2_nghttp2_session" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBNGHTTP2 1
_ACEOF
LIBS="-lnghttp2 $LIBS"
else
as_fn_error $? "nghttp2 not found" "$LINENO" 5
fi
elif test $pkg_failed = untried; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
for ac_header in nghttp2.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "nghttp2.h" "ac_cv_header_nghttp2_h" "$ac_includes_default"
if test "x$ac_cv_header_nghttp2_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_NGHTTP2_H 1
_ACEOF
else
as_fn_error $? "nghttp2 headers not found" "$LINENO" 5
fi
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nghttp2_session in -lnghttp2" >&5
$as_echo_n "checking for nghttp2_session in -lnghttp2... " >&6; }
if ${ac_cv_lib_nghttp2_nghttp2_session+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lnghttp2 $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char nghttp2_session ();
int
main ()
{
return nghttp2_session ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_nghttp2_nghttp2_session=yes
else
ac_cv_lib_nghttp2_nghttp2_session=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nghttp2_nghttp2_session" >&5
$as_echo "$ac_cv_lib_nghttp2_nghttp2_session" >&6; }
if test "x$ac_cv_lib_nghttp2_nghttp2_session" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_LIBNGHTTP2 1
_ACEOF
LIBS="-lnghttp2 $LIBS"
else
as_fn_error $? "nghttp2 not found" "$LINENO" 5
fi
else
libnghttp2_CFLAGS=$pkg_cv_libnghttp2_CFLAGS
libnghttp2_LIBS=$pkg_cv_libnghttp2_LIBS
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
as_fn_append CFLAGS " $nghttp2_CFLAGS"
as_fn_append LIBS " $nghttp2_LIBS"
fi
# Output Makefiles
ac_config_files="$ac_config_files Makefile src/Makefile src/test/Makefile"
@ -14202,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.6.0, which was
This file was extended by dnsperf $as_me 2.7.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -14269,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.6.0
dnsperf config.status 2.7.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View file

@ -16,7 +16,7 @@
# limitations under the License.
AC_PREREQ(2.64)
AC_INIT([dnsperf], [2.6.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues])
AC_INIT([dnsperf], [2.7.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])
@ -77,6 +77,15 @@ PKG_CHECK_MODULES([libldns], [libldns >= 1.7.0], [AC_DEFINE([HAVE_LDNS], [1], [D
])
])
# Check for nghttp2
PKG_CHECK_MODULES([libnghttp2], [libnghttp2 >= 0], [
AS_VAR_APPEND([CFLAGS], [" $nghttp2_CFLAGS"])
AS_VAR_APPEND([LIBS], [" $nghttp2_LIBS"])
], [
AC_CHECK_HEADERS([nghttp2.h],, [AC_MSG_ERROR([nghttp2 headers not found])])
AC_CHECK_LIB([nghttp2], [nghttp2_session],, [AC_MSG_ERROR([nghttp2 not found])])
])
# Output Makefiles
AC_CONFIG_FILES([
Makefile

View file

@ -30,19 +30,19 @@ bin_PROGRAMS = dnsperf resperf
dist_bin_SCRIPTS = resperf-report
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \
edns.c tsig.c net_udp.c net_tcp.c net_dot.c
edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \
list.h result.h buffer.h qtype.h edns.h tsig.h
list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
dist_dnsperf_SOURCES = $(_libperf_headers)
dnsperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
$(libldns_LIBS)
$(libldns_LIBS) $(libnghttp2_LIBS)
resperf_SOURCES = $(_libperf_sources) resperf.c
dist_resperf_SOURCES = $(_libperf_headers)
resperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
$(libldns_LIBS)
$(libldns_LIBS) $(libnghttp2_LIBS)
man1_MANS = dnsperf.1 resperf.1

View file

@ -130,14 +130,16 @@ PROGRAMS = $(bin_PROGRAMS)
am__objects_1 = datafile.$(OBJEXT) dns.$(OBJEXT) log.$(OBJEXT) \
net.$(OBJEXT) opt.$(OBJEXT) os.$(OBJEXT) strerror.$(OBJEXT) \
qtype.$(OBJEXT) edns.$(OBJEXT) tsig.$(OBJEXT) \
net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT)
net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT) \
net_doh.$(OBJEXT) parse_uri.$(OBJEXT)
am_dnsperf_OBJECTS = $(am__objects_1) dnsperf.$(OBJEXT)
am__objects_2 =
dist_dnsperf_OBJECTS = $(am__objects_2)
dnsperf_OBJECTS = $(am_dnsperf_OBJECTS) $(dist_dnsperf_OBJECTS)
am__DEPENDENCIES_1 =
dnsperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
@ -146,7 +148,8 @@ am_resperf_OBJECTS = $(am__objects_1) resperf.$(OBJEXT)
dist_resperf_OBJECTS = $(am__objects_2)
resperf_OBJECTS = $(am_resperf_OBJECTS) $(dist_resperf_OBJECTS)
resperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@ -192,9 +195,10 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/datafile.Po ./$(DEPDIR)/dns.Po \
./$(DEPDIR)/dnsperf.Po ./$(DEPDIR)/edns.Po ./$(DEPDIR)/log.Po \
./$(DEPDIR)/net.Po ./$(DEPDIR)/net_dot.Po \
./$(DEPDIR)/net_tcp.Po ./$(DEPDIR)/net_udp.Po \
./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po ./$(DEPDIR)/qtype.Po \
./$(DEPDIR)/net.Po ./$(DEPDIR)/net_doh.Po \
./$(DEPDIR)/net_dot.Po ./$(DEPDIR)/net_tcp.Po \
./$(DEPDIR)/net_udp.Po ./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po \
./$(DEPDIR)/parse_uri.Po ./$(DEPDIR)/qtype.Po \
./$(DEPDIR)/resperf.Po ./$(DEPDIR)/strerror.Po \
./$(DEPDIR)/tsig.Po
am__mv = mv -f
@ -405,6 +409,8 @@ libdir = @libdir@
libexecdir = @libexecdir@
libldns_CFLAGS = @libldns_CFLAGS@
libldns_LIBS = @libldns_LIBS@
libnghttp2_CFLAGS = @libnghttp2_CFLAGS@
libnghttp2_LIBS = @libnghttp2_LIBS@
libssl_CFLAGS = @libssl_CFLAGS@
libssl_LIBS = @libssl_LIBS@
localedir = @localedir@
@ -435,20 +441,20 @@ AM_CFLAGS = -I$(srcdir) \
EXTRA_DIST = dnsperf.1.in resperf-report resperf.1.in
dist_bin_SCRIPTS = resperf-report
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \
edns.c tsig.c net_udp.c net_tcp.c net_dot.c
edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \
list.h result.h buffer.h qtype.h edns.h tsig.h
list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
dist_dnsperf_SOURCES = $(_libperf_headers)
dnsperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
$(libldns_LIBS)
$(libldns_LIBS) $(libnghttp2_LIBS)
resperf_SOURCES = $(_libperf_sources) resperf.c
dist_resperf_SOURCES = $(_libperf_headers)
resperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
$(libldns_LIBS)
$(libldns_LIBS) $(libnghttp2_LIBS)
man1_MANS = dnsperf.1 resperf.1
all: config.h
@ -605,11 +611,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edns.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_doh.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_dot.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_tcp.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_udp.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse_uri.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resperf.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strerror.Po@am__quote@ # am--include-marker
@ -902,11 +910,13 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/edns.Po
-rm -f ./$(DEPDIR)/log.Po
-rm -f ./$(DEPDIR)/net.Po
-rm -f ./$(DEPDIR)/net_doh.Po
-rm -f ./$(DEPDIR)/net_dot.Po
-rm -f ./$(DEPDIR)/net_tcp.Po
-rm -f ./$(DEPDIR)/net_udp.Po
-rm -f ./$(DEPDIR)/opt.Po
-rm -f ./$(DEPDIR)/os.Po
-rm -f ./$(DEPDIR)/parse_uri.Po
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/resperf.Po
-rm -f ./$(DEPDIR)/strerror.Po
@ -966,11 +976,13 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/edns.Po
-rm -f ./$(DEPDIR)/log.Po
-rm -f ./$(DEPDIR)/net.Po
-rm -f ./$(DEPDIR)/net_doh.Po
-rm -f ./$(DEPDIR)/net_dot.Po
-rm -f ./$(DEPDIR)/net_tcp.Po
-rm -f ./$(DEPDIR)/net_udp.Po
-rm -f ./$(DEPDIR)/opt.Po
-rm -f ./$(DEPDIR)/os.Po
-rm -f ./$(DEPDIR)/parse_uri.Po
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/resperf.Po
-rm -f ./$(DEPDIR)/strerror.Po

View file

@ -21,9 +21,15 @@
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the `nghttp2' library (-lnghttp2). */
#undef HAVE_LIBNGHTTP2
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <nghttp2.h> header file. */
#undef HAVE_NGHTTP2_H
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD

View file

@ -53,6 +53,7 @@ const char* perf_dns_rcode_strings[] = {
perf_result_t perf_dname_fromstring(const char* str, size_t len, perf_buffer_t* target)
{
size_t label_len, at;
ssize_t max = 255;
const char* orig_str = str;
bool is_quoted;
@ -101,6 +102,10 @@ perf_result_t perf_dname_fromstring(const char* str, size_t len, perf_buffer_t*
if (label_len > 63) {
return PERF_R_FAILURE;
}
max -= label_len + 1;
if (max < 0) {
return PERF_R_FAILURE;
}
perf_buffer_putuint8(target, label_len);
if (is_quoted) {
for (at = 0; at < len; at++) {

View file

@ -44,6 +44,7 @@ dnsperf \- test the performance of a DNS server
[\fB\-W\fR]
[\fB\-x\ \fIlocal_port\fR]
[\fB\-y\ \fI[alg:]name:secret\fR]
[\fB\-O\ \fIoption=value\fR]
.ad
.hy
.SH DESCRIPTION
@ -170,6 +171,11 @@ test over a local Ethernet connection, it should be zero.
If one or more packets has been dropped, there may be a problem with the
network connection.
In that case, the results should be considered suspect and the test repeated.
.SS "Using DNS-over-HTTPS"
When using DNS-over-HTTPS you must set the \fB-O doh\-uri=...\fR to something
that works with the server you're sending to.
Also note that the value for maximum outstanding queries will be used to
control the maximum concurrent streams within the HTTP/2 connection.
.SH OPTIONS
\fB-a \fIlocal_addr\fR
@ -259,7 +265,7 @@ times; if a time limit is set, the file may be read fewer times.
.br
.RS
Sets the port on which the DNS packets are sent.
If not specified, the standard DNS port (udp/tcp 53, DoT 853) is used.
If not specified, the standard DNS port (udp/tcp 53, DoT 853, DoH 443) is used.
.RE
\fB-q \fInum_queries\fR
@ -281,7 +287,7 @@ There is no default limit.
\fB-m \fImode\fR
.br
.RS
Specifies the transport mode to use, "udp", "tcp" or "dot".
Specifies the transport mode to use, "udp", "tcp", "dot" or "doh".
Default is "udp".
.RE
@ -368,6 +374,29 @@ the secret is expressed as a base-64 encoded string.
Available algorithms are: hmac-md5, hmac-sha1, hmac-sha224, hmac-sha256,
hmac-sha384 and hmac-sha512.
.RE
\fB-O \fIoption=value\fR
.br
.RS
Set an extended long option for various things to control different aspects
of testing or protocol modules, see EXTENDED OPTIONS for list of available
options.
.RE
.SH "EXTENDED OPTIONS"
\fBdoh-uri=\fIURI\fR
.br
.RS
The URI to use for DNS-over-HTTPS, default value is
"https://localhost/dns-query".
.RE
\fBdoh-method=\fIHTTP_METHOD\fR
.br
.RS
The HTTP method to use when querying with DNS-over-HTTPS, default is GET.
Available methods are: GET, POST.
.RE
.SH "SEE ALSO"
\fBresperf\fR(1)
.SH AUTHOR

View file

@ -52,7 +52,8 @@
#define DEFAULT_SERVER_NAME "127.0.0.1"
#define DEFAULT_SERVER_PORT 53
#define DEFAULT_SERVER_DOT_PORT 853
#define DEFAULT_SERVER_PORTS "udp/tcp 53 or DoT 853"
#define DEFAULT_SERVER_DOH_PORT 443
#define DEFAULT_SERVER_PORTS "udp/tcp 53, DoT 853 or DoH 443"
#define DEFAULT_LOCAL_PORT 0
#define DEFAULT_MAX_OUTSTANDING 100
#define DEFAULT_TIMEOUT 5
@ -407,6 +408,8 @@ setup(int argc, char** argv, config_t* config)
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;
memset(config, 0, sizeof(*config));
config->argc = argc;
@ -422,7 +425,7 @@ setup(int argc, char** argv, config_t* config)
perf_opt_add('f', perf_opt_string, "family",
"address family of DNS transport, inet or inet6", "any",
&family);
perf_opt_add('m', perf_opt_string, "mode", "set transport mode: udp, tcp or dot", "udp", &mode);
perf_opt_add('m', perf_opt_string, "mode", "set transport mode: udp, tcp, dot or doh", "udp", &mode);
perf_opt_add('s', perf_opt_string, "server_addr",
"the server to query", DEFAULT_SERVER_NAME, &server_name);
perf_opt_add('p', perf_opt_port, "port",
@ -480,6 +483,11 @@ setup(int argc, char** argv, config_t* config)
perf_opt_add('v', perf_opt_boolean, NULL,
"verbose: report each query and additional information to stdout",
NULL, &config->verbose);
perf_long_opt_add("doh-uri", perf_opt_string, "doh_uri",
"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);
bool log_stdout = false;
perf_opt_add('W', perf_opt_boolean, NULL, "log warnings and errors to stdout instead of stderr", NULL, &log_stdout);
@ -493,8 +501,26 @@ setup(int argc, char** argv, config_t* config)
config->mode = perf_net_parsemode(mode);
if (!server_port) {
server_port = config->mode == sock_dot ? DEFAULT_SERVER_DOT_PORT : DEFAULT_SERVER_PORT;
switch (config->mode) {
case sock_doh:
server_port = DEFAULT_SERVER_DOH_PORT;
break;
case sock_dot:
server_port = DEFAULT_SERVER_DOT_PORT;
break;
default:
server_port = DEFAULT_SERVER_PORT;
break;
}
}
if (doh_uri) {
perf_net_doh_parse_uri(doh_uri);
}
if (doh_method) {
perf_net_doh_parse_method(doh_method);
}
perf_net_doh_set_max_concurrent_streams(config->max_outstanding);
if (family != NULL)
config->family = perf_net_parsefamily(family);
@ -1181,13 +1207,11 @@ threadinfo_init(threadinfo_t* tinfo, const config_t* config,
tinfo->socks[i] = perf_net_opensocket(config->mode, &config->server_addr,
&config->local_addr,
socket_offset++,
config->bufsize);
config->bufsize,
tinfo, perf__net_sent, perf__net_event);
if (!tinfo->socks[i]) {
perf_log_fatal("perf_net_opensocket(): no socket returned, out of memory?");
}
tinfo->socks[i]->data = tinfo;
tinfo->socks[i]->sent = perf__net_sent;
tinfo->socks[i]->event = perf__net_event;
}
tinfo->current_sock = 0;
@ -1204,14 +1228,16 @@ threadinfo_stop(threadinfo_t* tinfo)
}
static void
threadinfo_cleanup(threadinfo_t* tinfo, times_t* times)
threadinfo_cleanup(config_t* config, threadinfo_t* tinfo, times_t* times)
{
unsigned int i;
if (interrupted)
cancel_queries(tinfo);
for (i = 0; i < tinfo->nsocks; i++)
for (i = 0; i < tinfo->nsocks; i++) {
perf_net_stats_compile(config->mode, tinfo->socks[i]);
perf_net_close(tinfo->socks[i]);
}
if (tinfo->last_recv > times->end_time)
times->end_time = tinfo->last_recv;
}
@ -1246,6 +1272,7 @@ int main(int argc, char** argv)
switch (config.mode) {
case sock_tcp:
case sock_dot:
case sock_doh:
// block SIGPIPE for TCP/DOT mode, if connection is closed it will generate a signal
perf_os_blocksignal(SIGPIPE, true);
break;
@ -1296,13 +1323,16 @@ int main(int argc, char** argv)
if (config.stats_interval > 0)
PERF_JOIN(stats_thread.sender, NULL);
perf_net_stats_init(config.mode);
for (i = 0; i < config.threads; i++)
threadinfo_cleanup(&threads[i], &times);
threadinfo_cleanup(&config, &threads[i], &times);
print_final_status(&config);
sum_stats(&config, &total_stats);
print_statistics(&config, &times, &total_stats);
perf_net_stats_print(config.mode);
cleanup(&config);
#if OPENSSL_VERSION_NUMBER < 0x10100000L

View file

@ -39,6 +39,8 @@ enum perf_net_mode perf_net_parsemode(const char* mode)
return sock_tcp;
} else if (!strcmp(mode, "tls") || !strcmp(mode, "dot")) {
return sock_dot;
} else if (!strcmp(mode, "doh")) {
return sock_doh;
}
perf_log_warning("invalid socket mode");
@ -189,7 +191,7 @@ void perf_net_parselocal(int family, const char* name, unsigned int port,
exit(1);
}
struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, size_t bufsize)
struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, size_t bufsize, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event)
{
int port;
perf_sockaddr_t tmp;
@ -209,14 +211,46 @@ struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_
switch (mode) {
case sock_udp:
return perf_net_udp_opensocket(server, &tmp, bufsize);
return perf_net_udp_opensocket(server, &tmp, bufsize, data, sent, event);
case sock_tcp:
return perf_net_tcp_opensocket(server, &tmp, bufsize);
return perf_net_tcp_opensocket(server, &tmp, bufsize, data, sent, event);
case sock_dot:
return perf_net_dot_opensocket(server, &tmp, bufsize);
return perf_net_dot_opensocket(server, &tmp, bufsize, data, sent, event);
case sock_doh:
return perf_net_doh_opensocket(server, &tmp, bufsize, data, sent, event);
default:
perf_log_fatal("perf_net_opensocket(): invalid mode");
}
return 0;
}
void perf_net_stats_init(enum perf_net_mode mode)
{
switch (mode) {
case sock_doh:
perf_net_doh_stats_init();
default:
break;
}
}
void perf_net_stats_compile(enum perf_net_mode mode, struct perf_net_socket* sock)
{
switch (mode) {
case sock_doh:
perf_net_doh_stats_compile(sock);
default:
break;
}
}
void perf_net_stats_print(enum perf_net_mode mode)
{
switch (mode) {
case sock_doh:
perf_net_doh_stats_print();
default:
break;
}
}

View file

@ -47,7 +47,8 @@ enum perf_net_mode {
sock_pipe,
sock_udp,
sock_tcp,
sock_dot
sock_dot,
sock_doh
};
struct perf_net_socket;
@ -158,10 +159,25 @@ static inline int perf_sockaddr_isinet6(const perf_sockaddr_t* sockaddr)
return sockaddr->sa.sa.sa_family == AF_INET6;
}
struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, size_t bufsize);
struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, size_t bufsize, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event);
struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t);
struct perf_net_socket* perf_net_tcp_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t);
struct perf_net_socket* perf_net_dot_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t);
struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event);
struct perf_net_socket* perf_net_tcp_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event);
struct perf_net_socket* perf_net_dot_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event);
struct perf_net_socket* perf_net_doh_opensocket(const perf_sockaddr_t*, const perf_sockaddr_t*, size_t, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event);
#define DEFAULT_DOH_URI "https://localhost/dns-query"
#define DEFAULT_DOH_METHOD "GET"
void perf_net_doh_parse_uri(const char*);
void perf_net_doh_parse_method(const char*);
void perf_net_doh_set_max_concurrent_streams(size_t);
void perf_net_stats_init(enum perf_net_mode);
void perf_net_stats_compile(enum perf_net_mode, struct perf_net_socket*);
void perf_net_stats_print(enum perf_net_mode);
void perf_net_doh_stats_init();
void perf_net_doh_stats_compile(struct perf_net_socket*);
void perf_net_doh_stats_print();
#endif

1017
src/net_doh.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -61,8 +61,6 @@ static void perf__dot_connect(struct perf_net_socket* sock)
{
int ret;
self->is_ready = true;
int fd = socket(self->server.sa.sa.sa_family, SOCK_STREAM, 0);
if (fd == -1) {
char __s[256];
@ -119,12 +117,14 @@ static void perf__dot_connect(struct perf_net_socket* sock)
}
if (connect(sock->fd, &self->server.sa.sa, self->server.length)) {
if (errno == EINPROGRESS) {
self->is_ready = false;
return;
} else {
char __s[256];
perf_log_fatal("connect() failed: %s", perf_strerror_r(errno, __s, sizeof(__s)));
}
}
self->is_conn_ready = true;
}
static void perf__dot_reconnect(struct perf_net_socket* sock)
@ -136,6 +136,7 @@ static void perf__dot_reconnect(struct perf_net_socket* sock)
self->sending = 0;
self->is_sending = false;
}
self->is_ready = false;
self->is_conn_ready = false;
perf__dot_connect(sock);
}
@ -416,7 +417,7 @@ static bool perf__dot_have_more(struct perf_net_socket* sock)
return self->have_more;
}
struct perf_net_socket* perf_net_dot_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize)
struct perf_net_socket* perf_net_dot_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event)
{
struct perf__dot_socket* tmp = calloc(1, sizeof(struct perf__dot_socket)); // clang scan-build
struct perf_net_socket* sock = (struct perf_net_socket*)tmp;
@ -433,6 +434,10 @@ struct perf_net_socket* perf_net_dot_opensocket(const perf_sockaddr_t* server, c
sock->sockready = perf__dot_sockready;
sock->have_more = perf__dot_have_more;
sock->data = data;
sock->sent = sent;
sock->event = event;
self->server = *server;
self->local = *local;
self->bufsize = bufsize;

View file

@ -367,7 +367,7 @@ static bool perf__tcp_have_more(struct perf_net_socket* sock)
return self->have_more;
}
struct perf_net_socket* perf_net_tcp_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize)
struct perf_net_socket* perf_net_tcp_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event)
{
struct perf__tcp_socket* tmp = calloc(1, sizeof(struct perf__tcp_socket)); // clang scan-build
struct perf_net_socket* sock = (struct perf_net_socket*)tmp;
@ -384,6 +384,10 @@ struct perf_net_socket* perf_net_tcp_opensocket(const perf_sockaddr_t* server, c
sock->sockready = perf__tcp_sockready;
sock->have_more = perf__tcp_have_more;
sock->data = data;
sock->sent = sent;
sock->event = event;
self->server = *server;
self->local = *local;
self->bufsize = bufsize;

View file

@ -61,7 +61,7 @@ static int perf__udp_sockready(struct perf_net_socket* sock, int pipe_fd, int64_
return 1;
}
struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize)
struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t* server, const perf_sockaddr_t* local, size_t bufsize, void* data, perf_net_sent_cb_t sent, perf_net_event_cb_t event)
{
struct perf__udp_socket* tmp = calloc(1, sizeof(struct perf__udp_socket)); // clang scan-build
struct perf_net_socket* sock = (struct perf_net_socket*)tmp;
@ -79,6 +79,10 @@ struct perf_net_socket* perf_net_udp_opensocket(const perf_sockaddr_t* server, c
sock->sockeq = perf__udp_sockeq;
sock->sockready = perf__udp_sockready;
sock->data = data;
sock->sent = sent;
sock->event = event;
sock->fd = socket(server->sa.sa.sa_family, SOCK_DGRAM, 0);
if (sock->fd == -1) {
char __s[256];

138
src/opt.c
View file

@ -44,7 +44,7 @@ typedef struct {
const char* desc;
const char* help;
const char* defval;
char defvalbuf[32];
char defvalbuf[512];
union {
void* valp;
char** stringp;
@ -56,7 +56,28 @@ typedef struct {
} u;
} opt_t;
typedef struct long_opt long_opt_t;
struct long_opt {
long_opt_t* next;
const char* name;
perf_opttype_t type;
const char* desc;
const char* help;
const char* defval;
char defvalbuf[512];
union {
void* valp;
char** stringp;
bool* boolp;
unsigned int* uintp;
uint64_t* uint64p;
double* doublep;
in_port_t* portp;
} u;
};
static opt_t opts[MAX_OPTS];
static long_opt_t* longopts = 0;
static unsigned int nopts;
static char optstr[MAX_OPTS * 2 + 2 + 1] = { 0 };
extern const char* progname;
@ -76,12 +97,12 @@ void perf_opt_add(char c, perf_opttype_t type, const char* desc, const char* hel
opt->desc = desc;
opt->help = help;
if (defval != NULL) {
opt->defvalbuf[sizeof(opt->defvalbuf) - 1] = 0;
strncpy(opt->defvalbuf, defval, sizeof(opt->defvalbuf));
if (opt->defvalbuf[sizeof(opt->defvalbuf) - 1]) {
if (strlen(defval) > sizeof(opt->defvalbuf) - 1) {
perf_log_fatal("perf_opt_add(): defval too large");
return;
}
strncpy(opt->defvalbuf, defval, sizeof(opt->defvalbuf));
opt->defvalbuf[sizeof(opt->defvalbuf) - 1] = 0;
opt->defval = opt->defvalbuf;
} else {
opt->defval = NULL;
@ -94,6 +115,37 @@ void perf_opt_add(char c, perf_opttype_t type, const char* desc, const char* hel
optstr[sizeof(optstr) - 1] = 0;
}
void perf_long_opt_add(const char* name, perf_opttype_t type, const char* desc, const char* help, const char* defval, void* valp)
{
long_opt_t* opt = calloc(1, sizeof(long_opt_t));
if (!opt) {
perf_log_fatal("perf_long_opt_add(): out of memory");
return;
}
opt->name = name;
opt->type = type;
opt->desc = desc;
opt->help = help;
if (defval != NULL) {
if (strlen(defval) > sizeof(opt->defvalbuf) - 1) {
perf_log_fatal("perf_opt_add(): defval too large");
free(opt); // fix clang scan-build
return;
}
strncpy(opt->defvalbuf, defval, sizeof(opt->defvalbuf));
opt->defvalbuf[sizeof(opt->defvalbuf) - 1] = 0;
opt->defval = opt->defvalbuf;
} else {
opt->defval = NULL;
}
opt->u.valp = valp;
opt->next = longopts;
longopts = opt;
}
void perf_opt_usage(void)
{
unsigned int prefix_len, position, arg_len, i, j;
@ -181,6 +233,70 @@ parse_timeval(const char* desc, const char* str)
return MILLION * parse_double(desc, str);
}
static int perf_opt_long_parse(char* optarg)
{
ssize_t optlen;
char* arg;
// TODO: Allow boolean not to have =/value
if (!(arg = strchr(optarg, '='))) {
return -1;
}
optlen = arg - optarg;
if (optlen < 1) {
return -1;
}
arg++;
long_opt_t* opt = longopts;
while (opt) {
if (!strncmp(optarg, opt->name, optlen)) {
switch (opt->type) {
case perf_opt_string:
*opt->u.stringp = arg;
break;
case perf_opt_boolean:
*opt->u.boolp = true;
break;
case perf_opt_uint:
*opt->u.uintp = parse_uint(opt->desc, arg, 1, 0xFFFFFFFF);
break;
case perf_opt_zpint:
*opt->u.uintp = parse_uint(opt->desc, arg, 0, 0xFFFFFFFF);
break;
case perf_opt_timeval:
*opt->u.uint64p = parse_timeval(opt->desc, arg);
break;
case perf_opt_double:
*opt->u.doublep = parse_double(opt->desc, arg);
break;
case perf_opt_port:
*opt->u.portp = parse_uint(opt->desc, arg, 0, 0xFFFF);
break;
}
return 0;
}
opt = opt->next;
}
return -1;
}
void perf_long_opt_usage(void)
{
fprintf(stderr, "Usage: %s ... -O <name>=<value> ...\n\nAvailable long options:\n", progname);
long_opt_t* opt = longopts;
while (opt) {
fprintf(stderr, " %s: %s", opt->name, opt->help);
if (opt->defval) {
fprintf(stderr, " (default: %s)", opt->defval);
}
fprintf(stderr, "\n");
opt = opt->next;
}
}
void perf_opt_parse(int argc, char** argv)
{
int c;
@ -188,6 +304,8 @@ void perf_opt_parse(int argc, char** argv)
unsigned int i;
perf_opt_add('h', perf_opt_boolean, NULL, "print this help", NULL, NULL);
perf_opt_add('H', perf_opt_boolean, NULL, "print long options help", NULL, NULL);
perf_opt_add('O', perf_opt_string, NULL, "set long options: <name>=<value>", NULL, NULL);
while ((c = getopt(argc, argv, optstr)) != -1) {
for (i = 0; i < nopts; i++) {
@ -202,6 +320,18 @@ void perf_opt_parse(int argc, char** argv)
perf_opt_usage();
exit(0);
}
if (c == 'H') {
perf_long_opt_usage();
exit(0);
}
if (c == 'O') {
if (perf_opt_long_parse(optarg)) {
fprintf(stderr, "invalid long option: %s\n", optarg);
perf_opt_usage();
exit(1);
}
continue;
}
opt = &opts[i];
switch (opt->type) {
case perf_opt_string:

View file

@ -30,10 +30,11 @@ typedef enum {
perf_opt_port,
} perf_opttype_t;
void perf_opt_add(char c, perf_opttype_t type, const char* desc, const char* help,
const char* defval, void* valp);
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);
void perf_opt_usage(void);
void perf_long_opt_usage(void);
void perf_opt_parse(int argc, char** argv);

112
src/parse_uri.c Normal file
View file

@ -0,0 +1,112 @@
#include "parse_uri.h"
#include <string.h>
// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
int parse_uri(struct URI* res, const char* uri)
{
/* We only interested in https */
size_t len, i, offset;
int ipv6addr = 0;
memset(res, 0, sizeof(struct URI));
len = strlen(uri);
if (len < 9 || memcmp("https://", uri, 8) != 0) {
return -1;
}
offset = 8;
res->host = res->hostport = &uri[offset];
res->hostlen = 0;
if (uri[offset] == '[') {
/* IPv6 literal address */
++offset;
++res->host;
ipv6addr = 1;
for (i = offset; i < len; ++i) {
if (uri[i] == ']') {
res->hostlen = i - offset;
offset = i + 1;
break;
}
}
} else {
const char delims[] = ":/?#";
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
}
res->hostlen = i - offset;
offset = i;
}
if (res->hostlen == 0) {
return -1;
}
/* Assuming https */
res->port = 443;
if (offset < len) {
if (uri[offset] == ':') {
/* port */
const char delims[] = "/?#";
int port = 0;
++offset;
for (i = offset; i < len; ++i) {
if (strchr(delims, uri[i]) != NULL) {
break;
}
if ('0' <= uri[i] && uri[i] <= '9') {
port *= 10;
port += uri[i] - '0';
if (port > 65535) {
return -1;
}
} else {
return -1;
}
}
if (port == 0) {
return -1;
}
offset = i;
res->port = (uint16_t)port;
}
}
res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host);
for (i = offset; i < len; ++i) {
if (uri[i] == '#') {
break;
}
}
if (i - offset == 0) {
res->path = "/";
res->pathlen = 1;
} else {
res->path = &uri[offset];
res->pathlen = i - offset;
}
return 0;
}

41
src/parse_uri.h Normal file
View file

@ -0,0 +1,41 @@
// From: https://github.com/nghttp2/nghttp2/blob/master/examples/client.c
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <inttypes.h>
#include <stdlib.h>
struct URI {
const char* host;
/* In this program, path contains query component as well. */
const char* path;
size_t pathlen;
const char* hostport;
size_t hostlen;
size_t hostportlen;
uint16_t port;
};
int parse_uri(struct URI* res, const char* uri);

View file

@ -44,6 +44,7 @@ resperf \- test the resolution performance of a caching DNS server
[\fB\-F\ \fIfall_behind\fR]
[\fB\-v\fR]
[\fB\-W\fR]
[\fB\-O\ \fIoption=value\fR]
.ad
.hy
.hy 0
@ -74,6 +75,7 @@ resperf \- test the resolution performance of a caching DNS server
[\fB\-F\ \fIfall_behind\fR]
[\fB\-v\fR]
[\fB\-W\fR]
[\fB\-O\ \fIoption=value\fR]
.ad
.hy
.SH DESCRIPTION
@ -413,6 +415,11 @@ itself and the server under test can sustain.
Otherwise, the test is likely to be cut short as a result of either running
out of query IDs (because of large numbers of dropped queries) or of
\fBresperf\fR falling behind its transmission schedule.
.SS "Using DNS-over-HTTPS"
When using DNS-over-HTTPS you must set the \fB-O doh\-uri=...\fR to something
that works with the server you're sending to.
Also note that the value for maximum outstanding queries will be used to
control the maximum concurrent streams within the HTTP/2 connection.
.SH OPTIONS
Because the \fBresperf\-report\fR script passes its command line options
directly to the \fBresperf\fR programs, they both accept the same set of
@ -437,7 +444,7 @@ This allows for long running tests on very small and simple query datafile.
\fB-M \fImode\fR
.br
.RS
Specifies the transport mode to use, "udp", "tcp" or "dot".
Specifies the transport mode to use, "udp", "tcp", "dot" or "doh".
Default is "udp".
.RE
@ -452,7 +459,7 @@ The default is the loopback address, 127.0.0.1.
.br
.RS
Sets the port on which the DNS packets are sent.
If not specified, the standard DNS port (udp/tcp 53, DoT 853) is used.
If not specified, the standard DNS port (udp/tcp 53, DoT 853, DoH 443) is used.
.RE
\fB-a \fIlocal_addr\fR
@ -634,6 +641,14 @@ Enables verbose mode to report about network readiness and congestion.
Log warnings and errors to standard output instead of standard error making
it easier for script, test and automation to capture all output.
.RE
\fB-O \fIoption=value\fR
.br
.RS
Set an extended long option for various things to control different aspects
of testing or protocol modules, see EXTENDED OPTIONS in \fBdnsperf\fR(1) for
list of available options.
.RE
.SH "THE PLOT DATA FILE"
The plot data file is written by the \fBresperf\fR program and contains the
data to be plotted using \fBgnuplot\fR.

View file

@ -53,7 +53,8 @@
#define DEFAULT_SERVER_NAME "127.0.0.1"
#define DEFAULT_SERVER_PORT 53
#define DEFAULT_SERVER_DOT_PORT 853
#define DEFAULT_SERVER_PORTS "udp/tcp 53 or DoT 853"
#define DEFAULT_SERVER_DOH_PORT 443
#define DEFAULT_SERVER_PORTS "udp/tcp 53, DoT 853 or DoH 443"
#define DEFAULT_LOCAL_PORT 0
#define DEFAULT_SOCKET_BUFFER 32
#define DEFAULT_TIMEOUT 45
@ -218,8 +219,23 @@ stringify(double value, int precision)
static void perf__net_event(struct perf_net_socket* sock, perf_socket_event_t event, uint64_t elapsed_time);
static void perf__net_sent(struct perf_net_socket* sock, uint16_t qid);
static void
setup(int argc, char** argv)
static ramp_bucket* init_buckets(int n)
{
ramp_bucket* p;
int i;
if (!(p = calloc(n, sizeof(*p)))) {
perf_log_fatal("out of memory");
return 0; // fix clang scan-build
}
for (i = 0; i < n; i++) {
p[i].queries = p[i].responses = p[i].failures = 0;
p[i].latency_sum = 0.0;
}
return p;
}
static void setup(int argc, char** argv)
{
const char* family = NULL;
const char* server_name = DEFAULT_SERVER_NAME;
@ -233,6 +249,8 @@ setup(int argc, char** argv)
unsigned int i;
const char* _mode = 0;
const char* edns_option_str = NULL;
const char* doh_uri = DEFAULT_DOH_URI;
const char* doh_method = DEFAULT_DOH_METHOD;
sock_family = AF_UNSPEC;
server_port = 0;
@ -251,7 +269,7 @@ setup(int argc, char** argv)
perf_opt_add('f', perf_opt_string, "family",
"address family of DNS transport, inet or inet6", "any",
&family);
perf_opt_add('M', perf_opt_string, "mode", "set transport mode: udp, tcp or dot", "udp", &_mode);
perf_opt_add('M', perf_opt_string, "mode", "set transport mode: udp, tcp, dot or doh", "udp", &_mode);
perf_opt_add('s', perf_opt_string, "server_addr",
"the server to query", DEFAULT_SERVER_NAME, &server_name);
perf_opt_add('p', perf_opt_port, "port",
@ -310,6 +328,10 @@ setup(int argc, char** argv)
perf_opt_add('R', perf_opt_boolean, NULL, "reopen datafile on end, allow for infinit use of it", NULL, &reopen_datafile);
perf_opt_add('F', perf_opt_zpint, "fall_behind", "the maximum number of queries that is allowed to fall behind, zero to disable",
stringify(DEFAULT_MAX_FALL_BEHIND, 0), &max_fall_behind);
perf_long_opt_add("doh-uri", perf_opt_string, "doh_uri",
"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_opt_parse(argc, argv);
@ -321,8 +343,26 @@ setup(int argc, char** argv)
mode = perf_net_parsemode(_mode);
if (!server_port) {
server_port = mode == sock_dot ? DEFAULT_SERVER_DOT_PORT : DEFAULT_SERVER_PORT;
switch (mode) {
case sock_doh:
server_port = DEFAULT_SERVER_DOH_PORT;
break;
case sock_dot:
server_port = DEFAULT_SERVER_DOT_PORT;
break;
default:
server_port = DEFAULT_SERVER_PORT;
break;
}
}
if (doh_uri) {
perf_net_doh_parse_uri(doh_uri);
}
if (doh_method) {
perf_net_doh_parse_method(doh_method);
}
perf_net_doh_set_max_concurrent_streams(max_outstanding);
if (max_outstanding > nsocks * DEFAULT_MAX_OUTSTANDING)
perf_log_fatal("number of outstanding packets (%u) must not "
@ -364,17 +404,23 @@ setup(int argc, char** argv)
if (edns_option_str != NULL)
edns_option = perf_edns_parseoption(edns_option_str);
traffic_time = ramp_time + sustain_time;
end_time = traffic_time + wait_time;
n_buckets = (traffic_time + bucket_interval - 1) / bucket_interval;
buckets = init_buckets(n_buckets);
time_now = perf_get_time();
time_of_program_start = time_now;
if (!(socks = calloc(nsocks, sizeof(*socks)))) {
perf_log_fatal("out of memory");
}
for (i = 0; i < nsocks; i++) {
socks[i] = perf_net_opensocket(mode, &server_addr, &local_addr, i, bufsize);
socks[i] = perf_net_opensocket(mode, &server_addr, &local_addr, i, bufsize, (void*)(intptr_t)i, perf__net_sent, perf__net_event);
if (!socks[i]) {
perf_log_fatal("perf_net_opensocket(): no socket returned, out of memory?");
}
socks[i]->data = (void*)(intptr_t)i;
socks[i]->sent = perf__net_sent;
socks[i]->event = perf__net_event;
}
}
@ -384,8 +430,10 @@ cleanup(void)
unsigned int i;
perf_datafile_close(&input);
for (i = 0; i < nsocks; i++)
for (i = 0; i < nsocks; i++) {
perf_net_stats_compile(mode, socks[i]);
(void)perf_net_close(socks[i]);
}
close(dummypipe[0]);
close(dummypipe[1]);
@ -499,23 +547,7 @@ print_statistics(void)
}
printf(" Maximum throughput: %.6lf qps\n", max_throughput);
printf(" Lost at that point: %.2f%%\n", loss_at_max_throughput);
}
static ramp_bucket*
init_buckets(int n)
{
ramp_bucket* p;
int i;
if (!(p = calloc(n, sizeof(*p)))) {
perf_log_fatal("out of memory");
return 0; // fix clang scan-build
}
for (i = 0; i < n; i++) {
p[i].queries = p[i].responses = p[i].failures = 0;
p[i].latency_sum = 0.0;
}
return p;
printf("\n");
}
/*
@ -776,6 +808,7 @@ int main(int argc, char** argv)
switch (mode) {
case sock_tcp:
case sock_dot:
case sock_doh:
// block SIGPIPE for TCP/DOT mode, if connection is closed it will generate a signal
perf_os_blocksignal(SIGPIPE, true);
break;
@ -788,15 +821,6 @@ int main(int argc, char** argv)
max_packet_size = edns ? MAX_EDNS_PACKET : MAX_UDP_PACKET;
perf_buffer_init(&msg, outpacket_buffer, max_packet_size);
traffic_time = ramp_time + sustain_time;
end_time = traffic_time + wait_time;
n_buckets = (traffic_time + bucket_interval - 1) / bucket_interval;
buckets = init_buckets(n_buckets);
time_now = perf_get_time();
time_of_program_start = time_now;
printf("[Status] Command line: %s", progname);
for (i = 1; i < argc; i++) {
printf(" %s", argv[i]);
@ -896,7 +920,9 @@ end_loop:
fclose(plotf);
print_statistics();
perf_net_stats_init(mode);
cleanup();
perf_net_stats_print(mode);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_free_strings();
#endif

View file

@ -441,6 +441,8 @@ libdir = @libdir@
libexecdir = @libexecdir@
libldns_CFLAGS = @libldns_CFLAGS@
libldns_LIBS = @libldns_LIBS@
libnghttp2_CFLAGS = @libnghttp2_CFLAGS@
libnghttp2_LIBS = @libnghttp2_LIBS@
libssl_CFLAGS = @libssl_CFLAGS@
libssl_LIBS = @libssl_LIBS@
localedir = @localedir@

View file

@ -100,6 +100,9 @@ echo " A" | ../dnsperf -W -s 1.1.1.1 \
echo "toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolongname" \
| ../dnsperf -W -s 1.1.1.1 -u \
| grep "Unable to parse domain name"
echo "tooooooooooooooooooooooooooooo.oooooooooooooooooooooooo.ooooooooooooooooooooooooooooo.ooooooooooooooooooooooooooooooo.oooooooooooooooooooooooooooooooooooooo.oooooooooooooooooooooooooooo.ooooooooooooooooooooooooo.ooooooooooooooooooooooooooooooooo.oooooooooooooooooooooooooooo.oooooooooooooooooooooooooooooooo.ooooooooooooooooooo.longname" \
| ../dnsperf -W -s 1.1.1.1 -u \
| grep "Unable to parse domain name"
echo -e "test\ndelete toooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooolongname" \
| ../dnsperf -W -s 1.1.1.1 -u \
| grep "invalid update command, domain name too large"

View file

@ -5,13 +5,17 @@ test "$TEST_DNSPERF_WITH_NETWORK" = "1" || exit 0
dumdumd=`which dumdumd`
if [ -n "$dumdumd" ]; then
pkill -9 dumdumd || true
$dumdumd 127.0.0.1 5353 -r -D 100 &
pid="$!"
sleep 2
../dnsperf -s 127.0.0.1 -p 5353 -d "$srcdir/datafile" -t 2 -l 2 -Q 10 -m tcp
kill "$pid"
$dumdumd 127.0.0.1 5353 -r -D 10 &
pid="$!"
sleep 2
../dnsperf -s 127.0.0.1 -p 5353 -d "$srcdir/datafile" -t 2 -l 10 -Q 100 -m tcp
kill "$pid"
@ -20,11 +24,13 @@ if [ -n "$dumdumd" ]; then
$dumdumd 127.0.0.1 5353 -r -T -D 100 &
pid="$!"
sleep 2
../dnsperf -s 127.0.0.1 -p 5353 -d "$srcdir/datafile" -t 2 -l 2 -Q 10 -m dot
kill "$pid"
$dumdumd 127.0.0.1 5353 -r -T -D 10 &
pid="$!"
sleep 2
../dnsperf -s 127.0.0.1 -p 5353 -d "$srcdir/datafile" -t 2 -l 10 -Q 100 -m dot
kill "$pid"

View file

@ -28,6 +28,7 @@
#include <stdbool.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>
#define MILLION ((uint64_t)1000000)
@ -76,6 +77,19 @@
} \
} while (0)
static inline int PERF_TRYLOCK(pthread_mutex_t* mutex)
{
int __n = pthread_mutex_trylock(mutex);
if (__n == EBUSY) {
return 1;
}
if (__n != 0) {
char __s[256];
perf_log_fatal("pthread_mutex_lock failed: %s", perf_strerror_r(__n, __s, sizeof(__s)));
}
return 0;
}
#define PERF_UNLOCK(mutex) \
do { \
int __n = pthread_mutex_unlock((mutex)); \