Merge branch 'develop'

This commit is contained in:
Willem Toorop 2018-02-22 10:24:43 +01:00
commit 21155d5aa9
41 changed files with 3362 additions and 365 deletions

3
.gitmodules vendored
View File

@ -9,3 +9,6 @@
path = stubby
url = https://github.com/getdnsapi/stubby.git
branch = develop
[submodule "src/ssl_dane"]
path = src/ssl_dane
url = https://github.com/getdnsapi/ssl_dane

View File

@ -1,3 +1,32 @@
* 2018-02-21: Version 1.4.0
* .so revision bump to please fedora packaging system.
Thanks Paul Wouters
* Specify the supported curves with getdns_context_set_tls_curves_list()
An upstream specific list of supported curves may also be given
with the tls_curves_list setting in the upstream dict with
getdns_context_set_upstream_recursive_servers()
* New tool getdns_server_mon for checking upstream recursive
resolver's capabilities.
* Improved handling of opportunistic back-off. If other transports
are working, dont forcibly promote failed upstreams just wait for
the re-try timer.
* Hostname authentication with libressl
Thanks Norbert Copones
* Security bugfix in response to CVE-2017-15105. Although getdns was
not vulnerable for this specific issue, as a precaution code has been
adapted so that signatures of DNSKEYs, DSs, NSECs and NSEC3s can not
be wildcard expansions when used with DNSSEC proofs. Only direct
queries for those types are allowed to be wildcard expansions.
* Bugfix PR#379: Miscelleneous double free or corruption, and corrupted
memory double linked list detected issue, whith serving functionality.
Thanks maddie and Bruno Pagani
* Security Bugfix PR#293: Check sha256 pinset's
with OpenSSL native DANE functions for OpenSSL >= 1.1.0
with Viktor Dukhovni's danessl library for OpenSSL >= 1.0.0
don't allow for authentication exceptions (like self-signed
certificates) otherwise. Thanks Viktor Dukhovni
* libidn2 support. Thanks Paul Wouters
* 2017-12-21: Version 1.3.0
* Bugfix #300: Detect dnsmasq and skip unit test that fails with it.
Thanks Tim Rühsen and Konomi Kitten

View File

@ -44,7 +44,7 @@ libdir = @libdir@
srcdir = @srcdir@
INSTALL = @INSTALL@
all : default @GETDNS_QUERY@
all : default @GETDNS_QUERY@ @GETDNS_SERVER_MON@
everything: default
cd src/test && $(MAKE)
@ -55,7 +55,7 @@ default:
install-lib:
cd src && $(MAKE) install
install: getdns.pc getdns_ext_event.pc install-lib @INSTALL_GETDNS_QUERY@
install: getdns.pc getdns_ext_event.pc install-lib @INSTALL_GETDNS_QUERY@ @INSTALL_GETDNS_SERVER_MON@
$(INSTALL) -m 755 -d $(DESTDIR)$(docdir)
$(INSTALL) -m 644 $(srcdir)/AUTHORS $(DESTDIR)$(docdir)
$(INSTALL) -m 644 $(srcdir)/ChangeLog $(DESTDIR)$(docdir)
@ -93,7 +93,7 @@ install: getdns.pc getdns_ext_event.pc install-lib @INSTALL_GETDNS_QUERY@
@echo "*** trust anchor management keeping it up-to-date."
@echo "***"
uninstall: @UNINSTALL_GETDNS_QUERY@
uninstall: @UNINSTALL_GETDNS_QUERY@ @UNINSTALL_GETDNS_SERVER_MON@
rm -rf $(DESTDIR)$(docdir)
cd doc && $(MAKE) $@
cd src && $(MAKE) $@
@ -110,6 +110,9 @@ test: default
getdns_query: default
cd src/tools && $(MAKE) $@
getdns_server_mon: default
cd src/tools && $(MAKE) $@
stubby:
cd src && $(MAKE) $@
@ -125,6 +128,12 @@ install-getdns_query: install-lib
uninstall-getdns_query:
cd src/tools && $(MAKE) $@
install-getdns_server_mon: install-lib
cd src/tools && $(MAKE) $@
uninstall-getdns_server_mon:
cd src/tools && $(MAKE) $@
install-stubby:
cd src && $(MAKE) $@
@ -204,12 +213,14 @@ $(distdir):
mkdir -p $(distdir)/src/tools
mkdir -p $(distdir)/src/jsmn
mkdir -p $(distdir)/src/yxml
mkdir -p $(distdir)/src/ssl_dane
mkdir -p $(distdir)/doc
mkdir -p $(distdir)/spec
mkdir -p $(distdir)/spec/example
mkdir -p $(distdir)/stubby
mkdir -p $(distdir)/stubby/src
mkdir -p $(distdir)/stubby/src/yaml
mkdir -p $(distdir)/stubby/doc
cp $(srcdir)/configure.ac $(distdir)
cp $(srcdir)/configure $(distdir)
cp $(srcdir)/AUTHORS $(distdir)
@ -258,12 +269,15 @@ $(distdir):
cp $(srcdir)/stubby/src/yaml/*.[ch] $(distdir)/stubby/src/yaml
cp $(srcdir)/stubby/COPYING $(distdir)/stubby
cp $(srcdir)/stubby/README.md $(distdir)/stubby
cp $(srcdir)/stubby/doc/stubby.1.in $(distdir)/stubby/doc
cp $(srcdir)/src/jsmn/*.[ch] $(distdir)/src/jsmn
cp $(srcdir)/src/jsmn/LICENSE $(distdir)/src/jsmn
cp $(srcdir)/src/jsmn/README.md $(distdir)/src/jsmn
cp $(srcdir)/src/yxml/*.[ch] $(distdir)/src/yxml
cp $(srcdir)/src/yxml/COPYING $(distdir)/src/yxml
cp $(srcdir)/src/yxml/yxml.pod $(distdir)/src/yxml
cp $(srcdir)/src/ssl_dane/danessl.[ch] $(distdir)/src/ssl_dane
cp $(srcdir)/src/ssl_dane/README.md $(distdir)/src/ssl_dane
rm -f $(distdir)/Makefile $(distdir)/src/Makefile $(distdir)/src/getdns/getdns.h $(distdir)/spec/example/Makefile $(distdir)/src/test/Makefile $(distdir)/doc/Makefile $(distdir)/src/config.h
distcheck: $(distdir).tar.gz

View File

@ -70,13 +70,13 @@ If you are installing from packages, you have to install the library and also th
External dependencies are linked outside the getdns API build tree (we rely on configure to find them). We would like to keep the dependency tree short. Please refer to section for building on Windows for separate dependency and build instructions for that platform.
* [libunbound from NLnet Labs](https://unbound.net/) version 1.4.16 or later.
* [libidn from the FSF](https://www.gnu.org/software/libidn/) version 1. (Note that the libidn version means the conversions between A-labels and U-labels may permit conversion of formally invalid labels under IDNA2008.)
* [libidn from the FSF](https://www.gnu.org/software/libidn/) version 1 or 2. (Note that the libidn version means the conversions between A-labels and U-labels may permit conversion of formally invalid labels under IDNA2008.)
* [libssl and libcrypto from the OpenSSL Project](https://www.openssl.org/) version 0.9.7 or later. (Note: version 1.0.1 or later is required for TLS support, version 1.0.2 or later is required for TLS hostname authentication)
* Doxygen is used to generate documentation; while this is not technically necessary for the build it makes things a lot more pleasant.
For example, to build on a recent version of Ubuntu, you would need the following packages:
# apt install build-essential libunbound-dev libidn11-dev libssl-dev libtool m4 autoconf
# apt install build-essential libunbound-dev libidn2-dev libssl-dev libtool m4 autoconf
If you are building from git, you need to do the following before building:
@ -87,10 +87,11 @@ If you are building from git, you need to do the following before building:
# autoreconf -fi
As well as building the getdns library two other tools may be installed:
As well as building the getdns library three other tools may be installed:
* getdns_query: a command line test script wrapper for getdns
* stubby: an experimental DNS Privacy enabled client
* getdns_server_mon: test DNS server function and capabilities
Note: If you only want to build stubby, then use the `--with-stubby` option when running 'configure'.
@ -98,8 +99,8 @@ Note: If you only want to build stubby, then use the `--with-stubby` option when
## Minimizing dependencies
* getdns can be configured for stub resolution mode only with the `--enable-stub-only` option to configure. This removes the dependency on `libunbound`.
* Currently getdns only offers two helper functions to deal with IDN: `getdns_convert_ulabel_to_alabel` and `getdns_convert_alabel_to_ulabel`. If you do not need these functions, getdns can be configured to compile without them with the `--without-libidn` option to configure.
* When both `--enable-stub-only` and `--without-libidn` options are used, getdns has only one dependency left, which is OpenSSL.
* Currently getdns only offers two helper functions to deal with IDN: `getdns_convert_ulabel_to_alabel` and `getdns_convert_alabel_to_ulabel`. If you do not need these functions, getdns can be configured to compile without them with the `--without-libidn` and `--without-libidn2` options to configure.
* When `--enable-stub-only`, `--without-libidn` and `--without-libidn2` options are used, getdns has only one dependency left, which is OpenSSL.
## Extensions and Event loop dependencies

View File

@ -36,7 +36,7 @@ sinclude(./m4/acx_getaddrinfo.m4)
sinclude(./m4/ax_check_compile_flag.m4)
sinclude(./m4/pkg.m4)
AC_INIT([getdns], [1.3.0], [team@getdnsapi.net], [getdns], [https://getdnsapi.net])
AC_INIT([getdns], [1.4.0], [team@getdnsapi.net], [getdns], [https://getdnsapi.net])
# Autoconf 2.70 will have set up runstatedir. 2.69 is frequently (Debian)
# patched to do the same, but frequently (MacOS) not. So add a with option
@ -62,11 +62,13 @@ AC_ARG_WITH([current-date],
[CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"])
AC_SUBST(GETDNS_VERSION, ["AC_PACKAGE_VERSION$RELEASE_CANDIDATE"])
AC_SUBST(GETDNS_NUMERIC_VERSION, [0x01030000])
AC_SUBST(GETDNS_NUMERIC_VERSION, [0x01040000])
AC_SUBST(API_VERSION, ["December 2015"])
AC_SUBST(API_NUMERIC_VERSION, [0x07df0c00])
GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRENT_DATE for the $API_VERSION version of the API"
AC_DEFINE_UNQUOTED([STUBBY_PACKAGE], ["stubby"], [Stubby package])
AC_DEFINE_UNQUOTED([STUBBY_PACKAGE_STRING], ["0.2.2$RELEASE_CANDIDATE"], [Stubby package string])
# Library version
# ---------------
@ -99,9 +101,10 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRE
# getdns-1.1.3 had libversion 7:1:1
# getdns-1.2.0 had libversion 8:0:2
# getdns-1.2.1 had libversion 8:1:2
# getdns-1.3.0 has libversion 9:0:3
# getdns-1.3.0 had libversion 9:0:3
# getdns-1.4.0 has libversion 10:0:0
#
GETDNS_LIBVERSION=9:0:3
GETDNS_LIBVERSION=10:0:0
AC_SUBST(GETDNS_COMPILATION_COMMENT)
AC_SUBST(GETDNS_LIBVERSION)
@ -408,8 +411,8 @@ fi
AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/bn.h openssl/rsa.h openssl/dsa.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version])
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [
AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add X509_check_host])
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set1_curves_list,SSL_set1_curves_list], [], [], [
AC_INCLUDES_DEFAULT
#ifdef HAVE_OPENSSL_ERR_H
#include <openssl/err.h>
@ -431,6 +434,28 @@ AC_INCLUDES_DEFAULT
])
fi
AC_MSG_CHECKING([whether we need to compile/link DANE support])
DANESSL_XTRA_OBJS=""
AC_LANG_PUSH(C)
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
[#include <openssl/opensslv.h>]
[#if OPENSSL_VERSION_NUMBER < 0x1000000fL]
[#error "OpenSSL 1.0.0 or higher required for DANE library"]
[#elif defined(HAVE_SSL_DANE_ENABLE)]
[#error "OpenSSL has native DANE support"]
[#elif defined(LIBRESSL_VERSION_NUMBER)]
[#error "dane_ssl library does not work with LibreSSL"]
[#endif]
],[[]])],
[
AC_MSG_RESULT([yes])
AC_DEFINE([USE_DANESSL], [1], [Define this to use DANE functions from the ssl_dane/danessl library.])
DANESSL_XTRA_OBJS="danessl.lo"
],
[AC_MSG_RESULT([no])])
AC_LANG_POP(C)
AC_SUBST(DANESSL_XTRA_OBJS)
AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support]))
case "$enable_sha1" in
@ -763,6 +788,39 @@ else
fi
fi
my_with_libidn2=1
AC_ARG_WITH(libidn2, AS_HELP_STRING([--with-libidn2=pathname],
[path to libidn2 (default: search /usr/local ..)]),
[], [withval="yes"])
if test x_$withval = x_yes; then
for dir in /usr/local /opt/local /usr/pkg /usr/sfw; do
if test -f "$dir/include/idn2.h"; then
CFLAGS="$CFLAGS -I$dir/include"
LDFLAGS="$LDFLAGS -L$dir/lib"
AC_MSG_NOTICE([Found libidn2 in $dir])
break
fi
if test -f "$dir/include/idn2/idn2.h"; then
CFLAGS="$CFLAGS -I$dir/include/idn2"
LDFLAGS="$LDFLAGS -L$dir/lib"
AC_MSG_NOTICE([Found libidn2 in $dir])
break
fi
done
if test -f "/usr/include/idn2/idn2.h"; then
CFLAGS="$CFLAGS -I/usr/include/idn2"
#LDFLAGS="$LDFLAGS -L/usr/lib"
AC_MSG_NOTICE([Found libidn2 in /usr])
fi
else
if test x_$withval != x_no; then
CFLAGS="$CFLAGS -I$withval/include"
LDFLAGS="$LDFLAGS -L$withval/lib"
else
my_with_libidn2=0
fi
fi
if test $my_with_libunbound = 1
then
# find libunbound
@ -793,15 +851,37 @@ fi
found_all_libs=1
MISSING_DEPS=""
MISSING_SEP=""
if test $my_with_libidn = 1
working_libidn2=0
if test $my_with_libidn2 = 1
then
AC_MSG_NOTICE([Checking for dependency libidn])
AC_CHECK_LIB([idn], [idna_to_ascii_8z], [], [
MISSING_DEPS="${MISSING_DEPS}${MISSING_SEP}libidn"
AC_MSG_NOTICE([Checking for dependency libidn2])
AC_CHECK_LIB([idn2], [idn2_to_unicode_8z8z], [
working_libidn2=1
LIBS="-lidn2 $LIBS"
AC_DEFINE_UNQUOTED([HAVE_LIBIDN2], [1], [Define to 1 if you have the `idn2' library (-lidn).]) dnl `
], [
MISSING_DEPS="${MISSING_DEPS}${MISSING_SEP}libidn2"
MISSING_SEP=", "
found_all_libs=0
])
fi
if test $working_libidn2 = 0
then
if test $my_with_libidn = 1
then
AC_MSG_NOTICE([Checking for dependency libidn])
AC_CHECK_LIB([idn], [idna_to_ascii_8z], [], [
MISSING_DEPS="${MISSING_DEPS}${MISSING_SEP}libidn"
MISSING_SEP=", "
found_all_libs=0
])
else
if test $my_with_libidn2 = 1
then
found_all_libs=0
fi
fi
fi
AC_ARG_ENABLE(unbound-event-api, AC_HELP_STRING([--disable-unbound-event-api], [Disable usage of libunbounds event API]))
case "$enable_unbound_event_api" in
@ -1150,6 +1230,22 @@ AC_SUBST(GETDNS_QUERY)
AC_SUBST(INSTALL_GETDNS_QUERY)
AC_SUBST(UNINSTALL_GETDNS_QUERY)
AC_ARG_WITH(getdns_server_mon, AS_HELP_STRING([--without-getdns_server_mon],
[Do not compile and install the getdns_server_mon tool]),
[], [withval="yes"])
if test x_$withval = x_no; then
GETDNS_SERVER_MON=""
INSTALL_GETDNS_SERVER_MON=""
UNINSTALL_GETDNS_SERVER_MON=""
else
GETDNS_SERVER_MON="getdns_server_mon"
INSTALL_GETDNS_SERVER_MON="install-getdns_server_mon"
UNINSTALL_GETDNS_SERVER_MON="uninstall-getdns_server_mon"
fi
AC_SUBST(GETDNS_SERVER_MON)
AC_SUBST(INSTALL_GETDNS_SERVER_MON)
AC_SUBST(UNINSTALL_GETDNS_SERVER_MON)
stubby_with_yaml=0
AC_ARG_WITH(stubby, AS_HELP_STRING([--with-stubby],
[Compile and install stubby, the (stub) resolver daemon]),

View File

@ -47,6 +47,7 @@ have_libuv = @have_libuv@
have_libev = @have_libev@
# datarootdir is here to please some checkers
datarootdir=@datarootdir@
mandir=@mandir@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
@ -96,7 +97,9 @@ JSMN_OBJ=jsmn.lo
YXML_OBJ=yxml.lo
YAML_OBJ=convert_yaml_to_json.lo
GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@
DANESSL_OBJ=danessl.lo
GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@ @DANESSL_XTRA_OBJS@
STUBBY_XTRA_OBJS=@STUBBY_XTRA_OBJS@
EXTENSION_OBJ=$(DEFAULT_EVENTLOOP_OBJ) libevent.lo libev.lo
@ -133,6 +136,9 @@ $(JSMN_OBJ):
$(YAML_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(stubbysrcdir)/src/yaml/$(@:.lo=.c) -o $@
$(DANESSL_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WNOERRORFLAG) -c $(srcdir)/ssl_dane/$(@:.lo=.c) -o $@
$(YXML_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -I$(srcdir)/yxml -DYXML_GETDNS -Wno-unused-parameter -c $(srcdir)/yxml/$(@:.lo=.c) -o $@
@ -197,8 +203,14 @@ test: default
getdns_query: default
cd tools && $(MAKE) $@
getdns_server_mon: default
cd tools && $(MAKE) $@
stubby.1: $(stubbysrcdir)/doc/stubby.1.in
sed -e "s|@ETCDIR@|$(stubbyconfdir)|g" $(stubbysrcdir)/doc/stubby.1.in > $@
stubby.lo: $(stubbysrcdir)/src/stubby.c
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -DSTUBBYCONFDIR=\"$(sysconfdir)/stubby\" -DRUNSTATEDIR=\"$(runstatedir)\" -c $< -o $@
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -DSTUBBYCONFDIR=\"$(sysconfdir)/stubby\" -DRUNSTATEDIR=\"$(runstatedir)\" -c $(stubbysrcdir)/src/stubby.c -o $@
stubby: stubby.lo libgetdns.la $(STUBBY_XTRA_OBJS)
$(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ stubby.lo $(STUBBY_XTRA_OBJS) $(STUBBY_LDFLAGS) libgetdns.la
@ -220,14 +232,18 @@ install-stubby-files-windows: stubby.yml.windows
test -f $(DESTDIR)$(stubbyconfdir)/stubby.yml || \
$(INSTALL_DATA) stubby.yml.windows $(DESTDIR)$(stubbyconfdir)/stubby.yml
install-stubby: stubby install-stubby-files-@HOSTOS@
install-stubby: stubby stubby.1 install-stubby-files-@HOSTOS@
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
$(LIBTOOL) --mode=install cp stubby $(DESTDIR)$(bindir)
$(INSTALL) -m 755 -d $(DESTDIR)$(runstatedir)
$(INSTALL) -m 755 -d $(DESTDIR)$(mandir)
$(INSTALL) -m 755 -d $(DESTDIR)$(mandir)/man1
$(INSTALL) -m 644 stubby\.1 $(DESTDIR)$(mandir)/man1
uninstall-stubby:
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/stubby
rm -f $(DESTDIR)$(sbindir)/stubby-setdns-macos.sh
rm -f $(DESTDIR)$(mandir)/man1/stubby.1
scratchpad: default
cd test && $(MAKE) $@
@ -255,7 +271,7 @@ Makefile: $(srcdir)/Makefile.in ../config.status
depend:
(cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new )
(blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yxml/*.c extension/*.c ../stubby/src/*.c | \
(blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yxml/*.c ssl_dane/danessl.c extension/*.c ../stubby/src/*.c | \
sed -e "s? $$blddir/? ?g" \
-e 's? gldns/? $$(srcdir)/gldns/?g' \
-e 's? compat/? $$(srcdir)/compat/?g' \
@ -263,6 +279,7 @@ depend:
-e 's? util/? $$(srcdir)/util/?g' \
-e 's? jsmn/? $$(srcdir)/jsmn/?g' \
-e 's? yxml/? $$(srcdir)/yxml/?g' \
-e 's? ssl_dane/? $$(srcdir)/ssl_dane/?g' \
-e 's? extension/? $$(srcdir)/extension/?g' \
-e 's? \.\./stubby/? $$(stubbysrcdir)/?g' \
-e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \
@ -311,7 +328,7 @@ context.lo context.o: $(srcdir)/context.c \
$(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/dnssec.h \
$(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h
$(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h
convert.lo convert.o: $(srcdir)/convert.c \
config.h \
getdns/getdns.h \
@ -323,7 +340,7 @@ convert.lo convert.o: $(srcdir)/convert.c \
$(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h \
$(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/gldns/wire2str.h \
$(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/parseutil.h $(srcdir)/const-info.h $(srcdir)/dict.h \
$(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(stubbysrcdir)/src/yaml/convert_yaml_to_json.h $(srcdir)/convert.h
$(srcdir)/list.h $(srcdir)/jsmn/jsmn.h $(srcdir)/convert.h
dict.lo dict.o: $(srcdir)/dict.c \
config.h \
$(srcdir)/types-internal.h \
@ -450,7 +467,7 @@ stub.lo stub.o: $(srcdir)/stub.c \
$(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h \
$(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/anchor.h \
$(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
$(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h
sync.lo sync.o: $(srcdir)/sync.c \
getdns/getdns.h \
config.h \
@ -557,6 +574,7 @@ val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c \
$(srcdir)/util/auxiliary/sldns/sbuffer.h $(srcdir)/gldns/gbuffer.h
jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h
yxml.lo yxml.o: $(srcdir)/yxml/yxml.c $(srcdir)/yxml/yxml.h
danessl.lo danessl.o: $(srcdir)/ssl_dane/danessl.c $(srcdir)/ssl_dane/danessl.h
libev.lo libev.o: $(srcdir)/extension/libev.c \
config.h \
$(srcdir)/types-internal.h \

View File

@ -92,6 +92,7 @@ static struct const_info consts_info[] = {
{ 631, "GETDNS_CONTEXT_CODE_TLS_CA_PATH", GETDNS_CONTEXT_CODE_TLS_CA_PATH_TEXT },
{ 632, "GETDNS_CONTEXT_CODE_TLS_CA_FILE", GETDNS_CONTEXT_CODE_TLS_CA_FILE_TEXT },
{ 633, "GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST", GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST_TEXT },
{ 634, "GETDNS_CONTEXT_CODE_TLS_CURVES_LIST", GETDNS_CONTEXT_CODE_TLS_CURVES_LIST_TEXT },
{ 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT },
{ 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT },
{ 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT },
@ -189,6 +190,7 @@ static struct const_name_info consts_name_info[] = {
{ "GETDNS_CONTEXT_CODE_TLS_CA_PATH", 631 },
{ "GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST", 633 },
{ "GETDNS_CONTEXT_CODE_TLS_CONNECTION_RETRIES", 624 },
{ "GETDNS_CONTEXT_CODE_TLS_CURVES_LIST", 634 },
{ "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 },
{ "GETDNS_CONTEXT_CODE_TRUST_ANCHORS_URL", 625 },
{ "GETDNS_CONTEXT_CODE_TRUST_ANCHORS_VERIFY_CA", 626 },

View File

@ -59,6 +59,7 @@ typedef unsigned short in_port_t;
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <sys/stat.h>
#include <string.h>
@ -89,6 +90,9 @@ typedef unsigned short in_port_t;
#include "list.h"
#include "dict.h"
#include "pubkey-pinning.h"
#ifdef USE_DANESSL
# include "ssl_dane/danessl.h"
#endif
#define GETDNS_PORT_ZERO 0
#define GETDNS_PORT_DNS 53
@ -681,6 +685,27 @@ upstreams_create(getdns_context *context, size_t size)
return r;
}
#if defined(USE_DANESSL) && defined(STUB_DEBUG) && STUB_DEBUG
static void _stub_debug_print_openssl_errors(void)
{
unsigned long err;
char buffer[1024];
const char *file;
const char *data;
int line;
int flags;
while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
ERR_error_string_n(err, buffer, sizeof(buffer));
if (flags & ERR_TXT_STRING)
DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d:%s\n", buffer, file, line, data);
else
DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d\n", buffer, file, line);
}
}
#endif
void
_getdns_upstreams_dereference(getdns_upstreams *upstreams)
{
@ -722,6 +747,12 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj);
#ifdef USE_DANESSL
# if defined(STUB_DEBUG) && STUB_DEBUG
_stub_debug_print_openssl_errors();
# endif
DANESSL_cleanup(upstream->tls_obj);
#endif
SSL_free(upstream->tls_obj);
}
if (upstream->fd != -1)
@ -738,6 +769,8 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
upstream->tls_pubkey_pinset = NULL;
if (upstream->tls_cipher_list)
GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list);
if (upstream->tls_curves_list)
GETDNS_FREE(upstreams->mf, upstream->tls_curves_list);
}
GETDNS_FREE(upstreams->mf, upstreams);
}
@ -779,8 +812,9 @@ upstream_backoff(getdns_upstream *upstream) {
upstream->conn_shutdowns = 0;
upstream->conn_backoffs++;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : !Backing off this upstream - Will retry again in %ds at %s",
"%-40s : Upstream : !Backing off %s on this upstream - Will retry again in %ds at %s",
upstream->addr_str,
upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP",
upstream->conn_backoff_interval,
asctime(gmtime(&upstream->conn_retry_time)));
}
@ -832,6 +866,12 @@ _getdns_upstream_reset(getdns_upstream *upstream)
}
if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj);
#ifdef USE_DANESSL
# if defined(STUB_DEBUG) && STUB_DEBUG
_stub_debug_print_openssl_errors();
# endif
DANESSL_cleanup(upstream->tls_obj);
#endif
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
@ -1011,6 +1051,7 @@ upstream_init(getdns_upstream *upstream,
upstream->responses_timeouts = 0;
upstream->keepalive_shutdown = 0;
upstream->keepalive_timeout = 0;
upstream->server_keepalive_received = 0;
/* How is this upstream doing on UDP? */
upstream->to_retry = 1;
upstream->back_off = 1;
@ -1022,6 +1063,7 @@ upstream_init(getdns_upstream *upstream,
upstream->tls_obj = NULL;
upstream->tls_session = NULL;
upstream->tls_cipher_list = NULL;
upstream->tls_curves_list = NULL;
upstream->transport = GETDNS_TRANSPORT_TCP;
upstream->tls_hs_state = GETDNS_HS_NONE;
upstream->tls_auth_name[0] = '\0';
@ -1535,6 +1577,7 @@ getdns_context_create_with_extended_memory_functions(
result->tls_ca_path = NULL;
result->tls_ca_file = NULL;
result->tls_cipher_list = NULL;
result->tls_curves_list = NULL;
(void) memset(&result->root_ksk, 0, sizeof(result->root_ksk));
@ -1636,6 +1679,9 @@ getdns_context_create_with_extended_memory_functions(
#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
OpenSSL_add_all_algorithms();
SSL_library_init();
# ifdef USE_DANESSL
(void) DANESSL_library_init();
# endif
#else
OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
@ -1805,6 +1851,8 @@ getdns_context_destroy(struct getdns_context *context)
GETDNS_FREE(context->mf, context->tls_ca_file);
if (context->tls_cipher_list)
GETDNS_FREE(context->mf, context->tls_cipher_list);
if (context->tls_curves_list)
GETDNS_FREE(context->mf, context->tls_curves_list);
#ifdef USE_WINSOCK
WSACleanup();
@ -2996,6 +3044,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
getdns_list *pubkey_pinset = NULL;
getdns_bindata *tls_cipher_list = NULL;
getdns_bindata *tls_curves_list = NULL;
if ((r = getdns_dict_get_bindata(
dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) {
@ -3007,6 +3056,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
* into account, should not
* be larger than 1024 bytes.
*/
freeaddrinfo(ai);
goto invalid_parameter;
}
memcpy(upstream->tls_auth_name,
@ -3022,8 +3072,10 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
r = _getdns_get_pubkey_pinset_from_list(pubkey_pinset,
&(upstreams->mf),
&(upstream->tls_pubkey_pinset));
if (r != GETDNS_RETURN_GOOD)
if (r != GETDNS_RETURN_GOOD) {
freeaddrinfo(ai);
goto invalid_parameter;
}
}
(void) getdns_dict_get_bindata(
dict, "tls_cipher_list", &tls_cipher_list);
@ -3031,6 +3083,19 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
? _getdns_strdup2(&upstreams->mf
, tls_cipher_list)
: NULL;
(void) getdns_dict_get_bindata(
dict, "tls_curves_list", &tls_curves_list);
if (tls_curves_list) {
#if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST
upstream->tls_curves_list =
_getdns_strdup2(&upstreams->mf
, tls_curves_list);
#else
freeaddrinfo(ai);
goto not_implemented;
#endif
} else
upstream->tls_curves_list = NULL;
}
if ((upstream->tsig_alg = tsig_alg)) {
if (tsig_name) {
@ -3068,6 +3133,11 @@ invalid_parameter:
error:
_getdns_upstreams_dereference(upstreams);
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
#if !defined(HAVE_DECL_SSL_SET1_CURVES_LIST) || !HAVE_DECL_SSL_SET1_CURVES_LIST
not_implemented:
_getdns_upstreams_dereference(upstreams);
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif
} /* getdns_context_set_upstream_recursive_servers */
@ -3608,6 +3678,12 @@ _getdns_context_prepare_for_resolution(getdns_context *context)
context->tls_cipher_list ? context->tls_cipher_list
: _getdns_default_tls_cipher_list))
return GETDNS_RETURN_BAD_CONTEXT;
# if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST
if (context->tls_curves_list &&
!SSL_CTX_set1_curves_list(context->tls_ctx, context->tls_curves_list))
return GETDNS_RETURN_BAD_CONTEXT;
# endif
/* For strict authentication, we must have local root certs available
Set up is done only when the tls_ctx is created (per getdns_context)*/
if ((context->tls_ca_file || context->tls_ca_path) &&
@ -3622,6 +3698,25 @@ _getdns_context_prepare_for_resolution(getdns_context *context)
if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED)
return GETDNS_RETURN_BAD_CONTEXT;
}
# if defined(HAVE_SSL_CTX_DANE_ENABLE)
# if defined(STUB_DEBUG) && STUB_DEBUG
int osr =
# else
(void)
# endif
SSL_CTX_dane_enable(context->tls_ctx);
DEBUG_STUB("%s %-35s: DEBUG: SSL_CTX_dane_enable() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
# elif defined(USE_DANESSL)
# if defined(STUB_DEBUG) && STUB_DEBUG
int osr =
# else
(void)
# endif
DANESSL_CTX_init(context->tls_ctx);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_CTX_init() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
# endif
#else /* HAVE_TLS_v1_2 */
if (tls_only_is_in_transports_list(context) == 1)
return GETDNS_RETURN_BAD_CONTEXT;
@ -3924,6 +4019,8 @@ _get_context_settings(getdns_context* context)
(void) getdns_dict_util_set_string(result, "tls_ca_file", str_value);
if (!getdns_context_get_tls_cipher_list(context, &str_value) && str_value)
(void) getdns_dict_util_set_string(result, "tls_cipher_list", str_value);
if (!getdns_context_get_tls_curves_list(context, &str_value) && str_value)
(void) getdns_dict_util_set_string(result, "tls_curves_list", str_value);
/* Default settings for extensions */
(void)getdns_dict_set_int(
@ -4513,6 +4610,11 @@ getdns_context_get_upstream_recursive_servers(getdns_context *context,
d, "tls_cipher_list",
upstream->tls_cipher_list);
}
if (upstream->tls_curves_list) {
(void) getdns_dict_util_set_string(
d, "tls_curves_list",
upstream->tls_curves_list);
}
}
}
if (!r)
@ -4722,6 +4824,7 @@ _getdns_context_config_setting(getdns_context *context,
CONTEXT_SETTING_STRING(tls_ca_path)
CONTEXT_SETTING_STRING(tls_ca_file)
CONTEXT_SETTING_STRING(tls_cipher_list)
CONTEXT_SETTING_STRING(tls_curves_list)
/**************************************/
/**** ****/
@ -5301,5 +5404,35 @@ getdns_context_get_tls_cipher_list(
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_set_tls_curves_list(
getdns_context *context, const char *tls_curves_list)
{
if (!context)
return GETDNS_RETURN_INVALID_PARAMETER;
#if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST
if (context->tls_curves_list)
GETDNS_FREE(context->mf, context->tls_curves_list);
context->tls_curves_list = tls_curves_list
? _getdns_strdup(&context->mf, tls_curves_list)
: NULL;
dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST);
return GETDNS_RETURN_GOOD;
#else
(void)tls_curves_list;
return GETDNS_RETURN_NOT_IMPLEMENTED;
#endif
}
getdns_return_t
getdns_context_get_tls_curves_list(
getdns_context *context, const char **tls_curves_list)
{
if (!context || !tls_curves_list)
return GETDNS_RETURN_INVALID_PARAMETER;
*tls_curves_list = context->tls_curves_list;
return GETDNS_RETURN_GOOD;
}
/* context.c */

View File

@ -193,6 +193,7 @@ typedef struct getdns_upstream {
size_t responses_timeouts;
size_t keepalive_shutdown;
uint64_t keepalive_timeout;
int server_keepalive_received;
/* Management of outstanding requests on stateful transports */
getdns_network_req *write_queue;
@ -206,6 +207,7 @@ typedef struct getdns_upstream {
getdns_auth_state_t tls_auth_state;
unsigned tls_fallback_ok : 1;
char *tls_cipher_list;
char *tls_curves_list;
/* Auth credentials*/
char tls_auth_name[256];
sha256_pin_t *tls_pubkey_pinset;
@ -347,6 +349,7 @@ struct getdns_context {
char *tls_ca_path;
char *tls_ca_file;
char *tls_cipher_list;
char *tls_curves_list;
getdns_upstreams *upstreams;
uint16_t limit_outstanding_queries;

View File

@ -39,7 +39,9 @@
#ifndef USE_WINSOCK
#include <arpa/inet.h>
#endif
#ifdef HAVE_LIBIDN
#if defined(HAVE_LIBIDN2)
#include <idn2.h>
#elif defined(HAVE_LIBIDN)
#include <stringprep.h>
#include <idna.h>
#endif
@ -54,7 +56,9 @@
#include "dict.h"
#include "list.h"
#include "jsmn/jsmn.h"
#ifdef USE_YAML_CONFIG
#include "yaml/convert_yaml_to_json.h"
#endif
#include "convert.h"
#include "debug.h"
@ -113,48 +117,43 @@ getdns_convert_fqdn_to_dns_name(
char *
getdns_convert_ulabel_to_alabel(const char *ulabel)
{
#ifdef HAVE_LIBIDN
int ret;
char *buf;
char *prepped;
char *prepped2;
#if defined(HAVE_LIBIDN2)
uint8_t *alabel;
if (ulabel == NULL)
return 0;
prepped2 = malloc(BUFSIZ);
if(!prepped2)
return 0;
setlocale(LC_ALL, "");
if ((prepped = stringprep_locale_to_utf8(ulabel)) == 0) {
/* convert to utf8 fails, which it can, but continue anyway */
if(strlen(ulabel)+1 > BUFSIZ) {
free(prepped2);
return 0;
}
memcpy(prepped2, ulabel, strlen(ulabel)+1);
} else {
if(strlen(prepped)+1 > BUFSIZ) {
free(prepped);
free(prepped2);
return 0;
}
memcpy(prepped2, prepped, strlen(prepped)+1);
free(prepped);
}
if ((ret = stringprep(prepped2, BUFSIZ, 0, stringprep_nameprep)) != STRINGPREP_OK) {
free(prepped2);
return 0;
}
if ((ret = idna_to_ascii_8z(prepped2, &buf, 0)) != IDNA_SUCCESS) {
free(prepped2);
return 0;
}
free(prepped2);
return buf;
if (!ulabel) return NULL;
if (idn2_lookup_u8((uint8_t *)ulabel, &alabel, IDN2_TRANSITIONAL) == IDN2_OK)
return (char *)alabel;
#elif defined(HAVE_LIBIDN)
char *alabel;
char *prepped;
char prepped2[BUFSIZ];
if (!ulabel) return NULL;
setlocale(LC_ALL, "");
if ((prepped = stringprep_locale_to_utf8(ulabel))) {
if(strlen(prepped)+1 > BUFSIZ) {
free(prepped);
return NULL;
}
memcpy(prepped2, prepped, strlen(prepped)+1);
free(prepped);
/* convert to utf8 fails, which it can, but continue anyway */
} else if (strlen(ulabel)+1 > BUFSIZ)
return NULL;
else
memcpy(prepped2, ulabel, strlen(ulabel)+1);
if (stringprep(prepped2, BUFSIZ, 0, stringprep_nameprep) == STRINGPREP_OK
&& idna_to_ascii_8z(prepped2, &alabel, 0) == IDNA_SUCCESS)
return alabel;
#else
(void)ulabel;
return NULL;
(void)ulabel;
#endif
return NULL;
}
/*---------------------------------------- getdns_convert_alabel_to_ulabel */
@ -171,20 +170,21 @@ getdns_convert_ulabel_to_alabel(const char *ulabel)
char *
getdns_convert_alabel_to_ulabel(const char *alabel)
{
#ifdef HAVE_LIBIDN
int ret; /* just in case we might want to use it someday */
char *buf;
#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
char *ulabel;
if (alabel == NULL)
return 0;
if ((ret = idna_to_unicode_8z8z(alabel, &buf, 0)) != IDNA_SUCCESS) {
return NULL;
}
return buf;
if (!alabel) return NULL;
# if defined(HAVE_LIBIDN2)
if (idn2_to_unicode_8z8z(alabel, &ulabel, 0) == IDN2_OK)
# else
if (idna_to_unicode_8z8z(alabel, &ulabel, 0) == IDNA_SUCCESS)
# endif
return ulabel;
#else
(void)alabel;
return NULL;
(void)alabel;
#endif
return NULL;
}

View File

@ -1755,6 +1755,26 @@ static int dnskey_signed_rrset(struct mem_funcs *mf, time_t now, uint32_t skew,
return 0;
}
/* Returns whether a dnskey for keyset signed a non wildcard rrset. */
static int a_key_signed_rrset_no_wc(struct mem_funcs *mf, time_t now,
uint32_t skew, _getdns_rrset *keyset, _getdns_rrset *rrset)
{
_getdns_rrtype_iter dnskey_spc, *dnskey;
const uint8_t *nc_name;
int keytag;
assert(keyset->rr_type == GETDNS_RRTYPE_DNSKEY);
for ( dnskey = _getdns_rrtype_iter_init(&dnskey_spc, keyset)
; dnskey ; dnskey = _getdns_rrtype_iter_next(dnskey) ) {
if ((keytag = dnskey_signed_rrset(mf, now, skew,
dnskey, rrset, &nc_name)) && !nc_name)
return keytag;
}
return 0;
}
static int find_nsec_covering_name(
struct mem_funcs *mf, time_t now, uint32_t skew, _getdns_rrset *dnskey,
_getdns_rrset *rrset, const uint8_t *name, int *opt_out);
@ -2110,7 +2130,8 @@ static int find_nsec_covering_name(
&& (bitmap = _getdns_rdf_iter_init_at(
&bitmap_spc, &nsec_rr->rr_i, 5))
&& (keytag = a_key_signed_rrset(mf, now, skew, dnskey, n))
&& (keytag = a_key_signed_rrset_no_wc(
mf, now, skew, dnskey, n))
&& ( keytag & NSEC3_ITERATION_COUNT_HIGH
|| ( nsec3_covers_name(n, name, opt_out)
@ -2174,7 +2195,8 @@ static int find_nsec_covering_name(
)
)
&& (keytag = a_key_signed_rrset(mf,now,skew, dnskey, n))) {
&& (keytag = a_key_signed_rrset_no_wc(
mf, now, skew, dnskey, n))) {
debug_sec_print_rrset("NSEC: ", n);
debug_sec_print_dname("covered: ", name);
@ -2297,7 +2319,8 @@ static int key_proves_nonexistance(
|| bitmap_has_type(bitmap, GETDNS_RRTYPE_SOA))
/* And a valid signature please */
&& (keytag = a_key_signed_rrset(mf,now,skew,keyset,&nsec_rrset))) {
&& (keytag = a_key_signed_rrset_no_wc(
mf, now, skew, keyset, &nsec_rrset))) {
debug_sec_print_rrset("NSEC NODATA proof for: ", rrset);
return keytag;
@ -2353,7 +2376,7 @@ static int key_proves_nonexistance(
)
/* And a valid signature please (as always) */
|| !(keytag = a_key_signed_rrset(
|| !(keytag = a_key_signed_rrset_no_wc(
mf, now, skew, keyset, cover)))
continue;
@ -2437,7 +2460,8 @@ static int key_proves_nonexistance(
|| bitmap_has_type(bitmap, GETDNS_RRTYPE_SOA))
/* It must have a valid signature */
&& (keytag = a_key_signed_rrset(mf, now, skew, keyset, ce))
&& (keytag = a_key_signed_rrset_no_wc(
mf, now, skew, keyset, ce))
/* The qname must match the NSEC3 */
&& ( keytag & NSEC3_ITERATION_COUNT_HIGH
@ -2493,7 +2517,7 @@ static int key_proves_nonexistance(
&& !bitmap_has_type(bitmap, GETDNS_RRTYPE_SOA)
)
|| !(keytag = a_key_signed_rrset(
|| !(keytag = a_key_signed_rrset_no_wc(
mf, now, skew, keyset, ce))
|| ( !(keytag & NSEC3_ITERATION_COUNT_HIGH)
&& !nsec3_matches_name(ce, ce_name)))
@ -2545,7 +2569,7 @@ static int chain_node_get_trusted_keys(
} else if (ta->rr_type == GETDNS_RRTYPE_DNSKEY) {
/* ta is KSK */
if ((keytag = a_key_signed_rrset(
if ((keytag = a_key_signed_rrset_no_wc(
mf, now, skew, ta, &node->dnskey))) {
*keys = &node->dnskey;
node->dnskey_signer = keytag;
@ -2563,7 +2587,8 @@ static int chain_node_get_trusted_keys(
return GETDNS_DNSSEC_INSECURE;
}
if ((keytag = a_key_signed_rrset(mf,now,skew,ta,&node->ds))) {
if ((keytag = a_key_signed_rrset_no_wc(
mf, now, skew, ta, &node->ds))) {
node->ds_signer = keytag;
if ((keytag = ds_authenticates_keys(
mf, now, skew, &node->ds, &node->dnskey))) {
@ -2597,7 +2622,7 @@ static int chain_node_get_trusted_keys(
}
if (key_matches_signer(ta, &node->ds)) {
if ((node->ds_signer = a_key_signed_rrset(
if ((node->ds_signer = a_key_signed_rrset_no_wc(
mf, now, skew, ta, &node->ds))
&& (keytag = ds_authenticates_keys(
mf, now, skew, &node->ds, &node->dnskey))){

View File

@ -697,6 +697,8 @@ getdns_general_ns(getdns_context *context, getdns_eventloop *loop,
/* clean up the request */
_getdns_context_clear_outbound_request(req);
_getdns_dns_req_free(req);
if (return_netreq_p)
*return_netreq_p = NULL;
return r;
}
return GETDNS_RETURN_GOOD;

View File

@ -100,6 +100,8 @@ extern "C" {
#define GETDNS_CONTEXT_CODE_TLS_CA_FILE_TEXT "Change related to getdns_context_set_tls_ca_file"
#define GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST 633
#define GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST_TEXT "Change related to getdns_context_set_tls_cipher_list"
#define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST 634
#define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST_TEXT "Change related to getdns_context_set_tls_curves_list"
/** @}
*/
@ -753,6 +755,20 @@ getdns_return_t
getdns_context_set_tls_cipher_list(
getdns_context *context, const char *cipher_list);
/**
* Sets the supported curves TLS upstreams.
* @see getdns_context_get_tls_curves_list
* @param[in] context The context to configure
* @param[in] curves_list The string is a colon separated list of curve
* NIDs or names, for example "P-521:P-384:P-256".
* @return GETDNS_RETURN_GOOD when successful
* @return GETDNS_RETURN_INVALID_PARAMETER when context was NULL.
*/
getdns_return_t
getdns_context_set_tls_curves_list(
getdns_context *context, const char *curves_list);
/**
* Get the current resolution type setting from this context.
* @see getdns_context_set_resolution_type
@ -1272,6 +1288,21 @@ getdns_return_t
getdns_context_get_tls_cipher_list(
getdns_context *context, const char **cipher_list);
/**
* Get the supported curves list if one has been set earlier.
* @see getdns_context_set_tls_curves_list
* @param[in] context The configured context
* @param[out] curves_list The string is a colon separated list of curve
* NIDs or names, for example "P-521:P-384:P-256",
* when one has been configured on the context,
* or NULL when none has been set before.
* @return GETDNS_RETURN_GOOD when successful
* @return GETDNS_RETURN_INVALID_PARAMETER when context was NULL.
*/
getdns_return_t
getdns_context_get_tls_curves_list(
getdns_context *context, const char **curves_list);
/** @}
*/

View File

@ -497,7 +497,7 @@ gldns_buffer_set_at(gldns_buffer *buffer, size_t at, int c, size_t count)
* writes count bytes of data to the current position of the buffer
* \param[in] buffer the buffer
* \param[in] data the data to write
* \param[in] count the lenght of the data to write
* \param[in] count the length of the data to write
*/
INLINE void
gldns_buffer_write(gldns_buffer *buffer, const void *data, size_t count)

View File

@ -33,14 +33,14 @@ ssize_t
gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
{
int c, prev_c;
int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
int p; /* 0 -> no parentheses seen, >0 nr of ( seen */
int com, quoted;
char *t;
size_t i;
const char *d;
const char *del;
/* standard delimeters */
/* standard delimiters */
if (!delim) {
/* from isspace(3) */
del = GLDNS_PARSE_NORMAL;
@ -244,7 +244,7 @@ gldns_bget_token_par(gldns_buffer *b, char *token, const char *delim,
size_t limit, int* par, const char* skipw)
{
int c, lc;
int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
int p; /* 0 -> no parentheses seen, >0 nr of ( seen */
int com, quoted;
char *t;
size_t i;

View File

@ -103,9 +103,9 @@ ssize_t gldns_bget_token(struct gldns_buffer *b, char *token, const char *delim,
* after the keyword + k_del until we hit d_del
* \param[in] f file pointer to read from
* \param[in] keyword keyword to look for
* \param[in] k_del keyword delimeter
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimeter
* \param[in] d_del the data delimiter
* \param[in] data_limit maximum size the the data buffer
* \return the number of character read
*/
@ -116,9 +116,9 @@ ssize_t gldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del,
* after the keyword + k_del until we hit d_del
* \param[in] f file pointer to read from
* \param[in] keyword keyword to look for
* \param[in] k_del keyword delimeter
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimeter
* \param[in] d_del the data delimiter
* \param[in] data_limit maximum size the the data buffer
* \param[in] line_nr pointer to an integer containing the current line number (for
debugging purposes)
@ -131,9 +131,9 @@ ssize_t gldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_de
* after the keyword + k_del until we hit d_del
* \param[in] b buffer pointer to read from
* \param[in] keyword keyword to look for
* \param[in] k_del keyword delimeter
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimeter
* \param[in] d_del the data delimiter
* \param[in] data_limit maximum size the the data buffer
* \return the number of character read
*/

View File

@ -165,20 +165,20 @@ gldns_gmtime64_r(int64_t clock, struct tm *result)
#endif /* SIZEOF_TIME_T <= 4 */
static int64_t
gldns_serial_arithmitics_time(int32_t time, time_t now)
gldns_serial_arithmetics_time(int32_t time, time_t now)
{
int32_t offset = time - (int32_t) now;
return (int64_t) now + offset;
}
struct tm *
gldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result)
gldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result)
{
#if SIZEOF_TIME_T <= 4
int64_t secs_since_epoch = gldns_serial_arithmitics_time(time, now);
int64_t secs_since_epoch = gldns_serial_arithmetics_time(time, now);
return gldns_gmtime64_r(secs_since_epoch, result);
#else
time_t secs_since_epoch = gldns_serial_arithmitics_time(time, now);
time_t secs_since_epoch = gldns_serial_arithmetics_time(time, now);
return gmtime_r(&secs_since_epoch, result);
#endif
}

View File

@ -62,13 +62,13 @@ time_t gldns_mktime_from_utc(const struct tm *tm);
* fields of RRSIG records.
*
* \param[in] time number of seconds since epoch (midnight, January 1st, 1970)
* to be intepreted as a serial arithmetics number relative to now.
* to be interpreted as a serial arithmetics number relative to now.
* \param[in] now number of seconds since epoch (midnight, January 1st, 1970)
* to which the time value is compared to determine the final value.
* \param[out] result the struct with the broken-out time information
* \return result on success or NULL on error
*/
struct tm * gldns_serial_arithmitics_gmtime_r(int32_t time, time_t now, struct tm *result);
struct tm * gldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct tm *result);
/**
* converts a ttl value (like 5d2h) to a long.

View File

@ -836,7 +836,7 @@ const char* gldns_get_errorstr_parse(int e)
}
/* Strip whitespace from the start and the end of <line>. */
static char *
char *
gldns_strip_ws(char *line)
{
char *s = line, *e;
@ -906,7 +906,7 @@ int gldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
*dname_len = 0;
return GLDNS_WIREPARSE_ERR_INCLUDE;
} else {
return gldns_str2wire_rr_buf(line, rr, len, dname_len,
int r = gldns_str2wire_rr_buf(line, rr, len, dname_len,
parse_state?parse_state->default_ttl:0,
(parse_state&&parse_state->origin_len)?
parse_state->origin:NULL,
@ -914,6 +914,13 @@ int gldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len,
(parse_state&&parse_state->prev_rr_len)?
parse_state->prev_rr:NULL,
parse_state?parse_state->prev_rr_len:0);
if(r == GLDNS_WIREPARSE_ERR_OK && (*dname_len) != 0 &&
parse_state &&
(*dname_len) <= sizeof(parse_state->prev_rr)) {
memmove(parse_state->prev_rr, rr, *dname_len);
parse_state->prev_rr_len = (*dname_len);
}
return r;
}
return GLDNS_WIREPARSE_ERR_OK;
}
@ -1541,7 +1548,7 @@ int gldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
s = strtod(my_str, &my_str);
}
/* skip blanks before norterness */
/* skip blanks before northerness */
while (isblank((unsigned char) *my_str)) {
my_str++;
}
@ -1693,12 +1700,15 @@ int gldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len)
struct protoent *p = getprotobyname(token);
have_proto = 1;
if(p) rd[0] = (uint8_t)p->p_proto;
else if(strcasecmp(token, "tcp")==0) rd[0]=6;
else if(strcasecmp(token, "udp")==0) rd[0]=17;
else rd[0] = (uint8_t)atoi(token);
(void)strlcpy(proto_str, token, sizeof(proto_str));
} else {
int serv_port;
struct servent *serv = getservbyname(token, proto_str);
if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port);
else if(strcasecmp(token, "domain")==0) serv_port=53;
else {
serv_port = atoi(token);
if(serv_port == 0 && strcmp(token, "0") != 0) {

View File

@ -554,6 +554,12 @@ int gldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len);
*/
int gldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len);
/**
* Strip whitespace from the start and the end of line.
* @param line: modified with 0 to shorten it.
* @return new start with spaces skipped.
*/
char * gldns_strip_ws(char *line);
#ifdef __cplusplus
}
#endif

View File

@ -255,6 +255,12 @@ int gldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
return gldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0);
}
int gldns_wire2str_rrquestion_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
{
/* use arguments as temporary variables */
return gldns_wire2str_rrquestion_scan(&d, &dlen, &s, &slen, NULL, 0);
}
int gldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
size_t str_len, uint16_t rrtype)
{
@ -1331,7 +1337,7 @@ int gldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
if(*dl < 4) return -1;
t = gldns_read_uint32(*d);
date_buf[15]=0;
if(gldns_serial_arithmitics_gmtime_r(t, time(NULL), &tm) &&
if(gldns_serial_arithmetics_gmtime_r(t, time(NULL), &tm) &&
strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) {
(*d) += 4;
(*dl) -= 4;
@ -1467,6 +1473,10 @@ int gldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
if(protocol && (protocol->p_name != NULL)) {
w += gldns_str_print(s, sl, "%s", protocol->p_name);
proto_name = protocol->p_name;
} else if(protocol_nr == 6) {
w += gldns_str_print(s, sl, "tcp");
} else if(protocol_nr == 17) {
w += gldns_str_print(s, sl, "udp");
} else {
w += gldns_str_print(s, sl, "%u", (unsigned)protocol_nr);
}

View File

@ -358,6 +358,22 @@ int gldns_wire2str_edns_option_code_print(char** str, size_t* str_len,
int gldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str,
size_t str_len);
/**
* Convert question RR to string presentation format, on one line. User buffer.
* @param rr: wireformat RR data
* @param rr_len: length of the rr wire data.
* @param str: the string buffer to write to.
* If you pass NULL as the str, the return value of the function is
* the str_len you need for the entire packet. It does not include
* the 0 byte at the end.
* @param str_len: the size of the string buffer. If more is needed, it'll
* silently truncate the output to fit in the buffer.
* @return the number of characters for this element, excluding zerobyte.
* Is larger or equal than str_len if output was truncated.
*/
int gldns_wire2str_rrquestion_buf(uint8_t* rr, size_t rr_len, char* str,
size_t str_len);
/**
* 3597 printout of an RR in unknown rr format.
* There are more format and comment options available for printout

View File

@ -37,6 +37,7 @@ getdns_context_get_tls_ca_file
getdns_context_get_tls_ca_path
getdns_context_get_tls_cipher_list
getdns_context_get_tls_connection_retries
getdns_context_get_tls_curves_list
getdns_context_get_tls_query_padding_blocksize
getdns_context_get_trust_anchors_url
getdns_context_get_trust_anchors_verify_CA
@ -80,6 +81,7 @@ getdns_context_set_tls_ca_file
getdns_context_set_tls_ca_path
getdns_context_set_tls_cipher_list
getdns_context_set_tls_connection_retries
getdns_context_set_tls_curves_list
getdns_context_set_tls_query_padding_blocksize
getdns_context_set_trust_anchors_url
getdns_context_set_trust_anchors_verify_CA

View File

@ -211,6 +211,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
net_req->debug_tls_auth_status = GETDNS_AUTH_NONE;
net_req->debug_tls_peer_cert.size = 0;
net_req->debug_tls_peer_cert.data = NULL;
net_req->debug_tls_version = NULL;
net_req->debug_udp = 0;
/* Scheduling, touch only via _getdns_netreq_change_state!

View File

@ -34,6 +34,10 @@
#include <iphlpapi.h>
#endif
#if defined(HAVE_FCNTL)
#include <fcntl.h>
#endif
#include "getdns/getdns_extra.h"
#include "context.h"
#include "types-internal.h"
@ -118,6 +122,25 @@ typedef struct tcp_connection {
size_t to_answer;
} tcp_connection;
/** best effort to set nonblocking */
static void
getdns_sock_nonblock(int sockfd)
{
#if defined(HAVE_FCNTL)
int flag;
if((flag = fcntl(sockfd, F_GETFL)) != -1) {
flag |= O_NONBLOCK;
if(fcntl(sockfd, F_SETFL, flag) == -1) {
/* ignore error, continue blockingly */
}
}
#elif defined(HAVE_IOCTLSOCKET)
unsigned long on = 1;
if(ioctlsocket(sockfd, FIONBIO, &on) != 0) {
/* ignore error, continue blockingly */
}
#endif
}
static void free_listen_set_when_done(listen_set *set);
static void tcp_connection_destroy(tcp_connection *conn)
@ -127,22 +150,33 @@ static void tcp_connection_destroy(tcp_connection *conn)
tcp_to_write *cur, *next;
if (!(mf = &conn->super.l->set->context->mf))
return;
mf = &conn->super.l->set->context->mf;
if (getdns_context_get_eventloop(conn->super.l->set->context, &loop))
return;
if (conn->event.read_cb||conn->event.write_cb||conn->event.timeout_cb)
if (conn->event.ev)
loop->vmt->clear(loop, &conn->event);
if (conn->fd >= 0)
if (conn->event.read_cb||conn->event.write_cb||conn->event.timeout_cb) {
conn->event.read_cb = conn->event.write_cb =
conn->event.timeout_cb = NULL;
}
if (conn->fd >= 0) {
(void) _getdns_closesocket(conn->fd);
GETDNS_FREE(*mf, conn->read_buf);
for (cur = conn->to_write; cur; cur = next) {
next = cur->next;
GETDNS_FREE(*mf, cur);
conn->fd = -1;
}
if (conn->read_buf) {
GETDNS_FREE(*mf, conn->read_buf);
conn->read_buf = conn->read_pos = NULL;
conn->to_read = 0;
}
if ((cur = conn->to_write)) {
while (cur) {
next = cur->next;
GETDNS_FREE(*mf, cur);
cur = next;
}
conn->to_write = NULL;
}
if (conn->to_answer > 0)
return;
@ -191,15 +225,16 @@ static void tcp_write_cb(void *userarg)
(const void *)&to_write->write_buf[to_write->written],
to_write->write_buf_len - to_write->written, 0)) == -1) {
if (_getdns_socketerror_wants_retry())
return;
DEBUG_SERVER("I/O error from send(): %s\n",
_getdns_errnostr());
if (conn->fd != -1) {
if (_getdns_socketerror_wants_retry()) {
(void) loop->vmt->schedule(loop, conn->fd,
DOWNSTREAM_IDLE_TIMEOUT, &conn->event);
return;
}
DEBUG_SERVER("I/O error from send(): %s\n",
_getdns_errnostr());
}
/* IO error, close connection */
conn->event.read_cb = conn->event.write_cb =
conn->event.timeout_cb = NULL;
tcp_connection_destroy(conn);
return;
}
@ -317,8 +352,10 @@ getdns_reply(
return GETDNS_RETURN_GOOD;
}
if (!(to_write = (tcp_to_write *)GETDNS_XMALLOC(
*mf, uint8_t, sizeof(tcp_to_write) + len + 2)))
*mf, uint8_t, sizeof(tcp_to_write) + len + 2))) {
tcp_connection_destroy(conn);
return GETDNS_RETURN_MEMORY_ERROR;
}
to_write->write_buf_len = len + 2;
to_write->write_buf[0] = (len >> 8) & 0xFF;
@ -327,20 +364,27 @@ getdns_reply(
to_write->next = NULL;
(void) memcpy(to_write->write_buf + 2, buf, len);
/* Appen to_write to conn->to_write list */
/* Append to_write to conn->to_write list */
for ( to_write_p = &conn->to_write
; *to_write_p
; to_write_p = &(*to_write_p)->next)
; /* pass */
*to_write_p = to_write;
loop->vmt->clear(loop, &conn->event);
conn->event.write_cb = tcp_write_cb;
if (conn->to_answer > 0)
conn->to_answer--;
(void) loop->vmt->schedule(loop,
conn->fd, DOWNSTREAM_IDLE_TIMEOUT,
&conn->event);
/* When event is scheduled, and doesn't have tcp_write_cb:
* reschedule.
*/
if (conn->event.write_cb == NULL) {
if (conn->event.ev)
loop->vmt->clear(loop, &conn->event);
conn->event.write_cb = tcp_write_cb;
(void) loop->vmt->schedule(loop,
conn->fd, DOWNSTREAM_IDLE_TIMEOUT,
&conn->event);
}
}
/* TODO: other transport types */
@ -366,18 +410,19 @@ static void tcp_read_cb(void *userarg)
/* Reset tcp_connection idle timeout */
loop->vmt->clear(loop, &conn->event);
(void) loop->vmt->schedule(loop, conn->fd,
DOWNSTREAM_IDLE_TIMEOUT, &conn->event);
if ((bytes_read = recv(conn->fd,
if (conn->fd == -1 ||
(bytes_read = recv(conn->fd,
(void *)conn->read_pos, conn->to_read, 0)) < 0) {
if (_getdns_socketerror_wants_retry())
return; /* Come back to do the read later */
/* IO error, close connection */
DEBUG_SERVER("I/O error from recv(): %s\n",
_getdns_errnostr());
if (conn->fd != -1) {
if (_getdns_socketerror_wants_retry()) {
(void) loop->vmt->schedule(loop, conn->fd,
DOWNSTREAM_IDLE_TIMEOUT, &conn->event);
return; /* Come back to do the read later */
}
/* IO error, close connection */
DEBUG_SERVER("I/O error from recv(): %s\n",
_getdns_errnostr());
}
tcp_connection_destroy(conn);
return;
}
@ -391,9 +436,9 @@ static void tcp_read_cb(void *userarg)
conn->to_read -= bytes_read;
conn->read_pos += bytes_read;
if (conn->to_read)
return; /* More to read */
; /* Schedule for more reading */
if (conn->read_pos - conn->read_buf == 2) {
else if (conn->read_pos - conn->read_buf == 2) {
/* read length of dns msg to read */
conn->to_read = (conn->read_buf[0] << 8) | conn->read_buf[1];
if (conn->to_read > conn->read_buf_len) {
@ -413,47 +458,60 @@ static void tcp_read_cb(void *userarg)
return;
}
conn->read_pos = conn->read_buf;
return; /* Read DNS message */
}
if ((r = getdns_wire2msg_dict(conn->read_buf,
(conn->read_pos - conn->read_buf), &request_dict)))
; /* FROMERR on input, ignore */
; /* Schedule for more reading */
else {
conn->to_answer++;
} else {
/* Ready for reading a new packet */
/* TODO: wish list item:
* (void) getdns_dict_set_int64(
* request_dict, "request_id", intptr_t)conn);
*/
/* Call request handler */
conn->super.l->set->handler(
conn->super.l->set->context, GETDNS_CALLBACK_COMPLETE,
request_dict, conn->super.l->set->userarg, (intptr_t)conn);
if (!(r = getdns_wire2msg_dict(conn->read_buf,
(conn->read_pos - conn->read_buf), &request_dict))) {
conn->to_answer++;
/* TODO: wish list item:
* (void) getdns_dict_set_int64(
* request_dict, "request_id", intptr_t)conn);
*/
/* Call request handler */
conn->to_answer += 1; /* conn removal protection */
conn->super.l->set->handler(
conn->super.l->set->context,
GETDNS_CALLBACK_COMPLETE, request_dict,
conn->super.l->set->userarg, (intptr_t)conn);
conn->to_answer -= 1; /* conn removal protection */
if (conn->fd == -1) {
tcp_connection_destroy(conn);
return;
}
}
conn->read_pos = conn->read_buf;
conn->to_read = 2;
return; /* Read more requests */
; /* Schedule for more reading */
}
conn->read_pos = conn->read_buf;
conn->to_read = 2;
/* Read more requests */
if (!conn->event.ev) { /* event not scheduled */
conn->event.write_cb = conn->to_write ? tcp_write_cb : NULL;
(void) loop->vmt->schedule(loop, conn->fd,
DOWNSTREAM_IDLE_TIMEOUT, &conn->event);
}
}
static void tcp_timeout_cb(void *userarg)
{
tcp_connection *conn = (tcp_connection *)userarg;
getdns_eventloop *loop;
assert(userarg);
if (conn->to_answer) {
getdns_eventloop *loop;
if (getdns_context_get_eventloop(
conn->super.l->set->context, &loop))
return;
if (getdns_context_get_eventloop(
conn->super.l->set->context, &loop))
return;
loop->vmt->clear(loop, &conn->event);
loop->vmt->clear(loop, &conn->event);
if (conn->to_answer && conn->fd >= 0) {
(void) loop->vmt->schedule(loop,
conn->fd, DOWNSTREAM_IDLE_TIMEOUT,
&conn->event);
@ -501,8 +559,10 @@ static void tcp_accept_cb(void *userarg)
GETDNS_FREE(*mf, conn);
return;
}
getdns_sock_nonblock(conn->fd);
if (!(conn->read_buf = malloc(DNS_REQUEST_SZ))) {
/* Memory error */
(void) _getdns_closesocket(conn->fd);
GETDNS_FREE(*mf, conn);
return;
}
@ -518,6 +578,7 @@ static void tcp_accept_cb(void *userarg)
if (!_getdns_rbtree_insert(
&l->set->connections_set, &conn->super.super)) {
/* Memory error */
(void) _getdns_closesocket(conn->fd);
GETDNS_FREE(*mf, conn);
return;
}
@ -730,8 +791,17 @@ static void remove_listeners(listen_set *set)
conn_p = (tcp_connection **)&l->connections;
while (*conn_p) {
tcp_connection *prev_conn_p = *conn_p;
loop->vmt->clear(loop, &(*conn_p)->event);
tcp_connection_destroy(*conn_p);
if (*conn_p && (*conn_p)->to_answer > 0)
/* tcp_connection_destroy() updates the pointer to the
* connection. For the first connection this is
* l->connections. When the connection is not actually
* destroyed, the value of *conn_p thus remains the
* same. When it is destroyed it is updated.
*/
if (*conn_p == prev_conn_p)
conn_p = (tcp_connection **)
&(*conn_p)->super.next;
}

1
src/ssl_dane Submodule

@ -0,0 +1 @@
Subproject commit dd093e585a237e0321d303ec35e84c393ef739f4

View File

@ -55,6 +55,9 @@
#include "platform.h"
#include "general.h"
#include "pubkey-pinning.h"
#ifdef USE_DANESSL
# include "ssl_dane/danessl.h"
#endif
/* WSA TODO:
* STUB_TCP_RETRY added to deal with edge triggered event loops (versus
@ -341,6 +344,7 @@ process_keepalive(
}
return;
}
upstream->server_keepalive_received = 1;
/* Use server sent value unless the client specified a shorter one.
Convert to ms first (wire value has units of 100ms) */
uint64_t server_keepalive = ((uint64_t)gldns_read_uint16(position))*100;
@ -529,11 +533,7 @@ upstream_failed(getdns_upstream *upstream, int during_setup)
the queries if there is only one upstream.*/
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (during_setup) {
/* Special case if failure was due to authentication issues since this
upstream could be used oppotunistically with no problem.*/
if (!(upstream->transport == GETDNS_TRANSPORT_TLS &&
upstream->tls_auth_state == GETDNS_AUTH_FAILED))
upstream->conn_setup_failed++;
upstream->conn_setup_failed++;
} else {
upstream->conn_shutdowns++;
/* [TLS1]TODO: Re-try these queries if possible.*/
@ -580,7 +580,7 @@ stub_timeout_cb(void *userarg)
netreq->upstream->udp_timeouts++;
if (netreq->upstream->udp_timeouts % 100 == 0)
_getdns_upstream_log(netreq->upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_INFO,
"%-40s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n",
"%-40s : Upstream : UDP - Resps=%6d, Timeouts =%6d (logged every 100 responses)\n",
netreq->upstream->addr_str,
(int)netreq->upstream->udp_responses, (int)netreq->upstream->udp_timeouts);
stub_next_upstream(netreq);
@ -827,7 +827,37 @@ tls_requested(getdns_network_req *netreq)
1 : 0;
}
int
#if defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL)
static int
_getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx)
{
# if defined(STUB_DEBUG) && STUB_DEBUG
char buf[8192];
X509 *cert;
int err;
int depth;
cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
if (cert)
X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
else
strcpy(buf, "<unknown>");
DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err));
# else /* defined(STUB_DEBUG) && STUB_DEBUG */
(void)ok;
(void)ctx;
# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */
return 1;
}
#else /* defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */
static int
tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
getdns_upstream *upstream;
@ -837,36 +867,22 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
return 0;
int err = X509_STORE_CTX_get_error(ctx);
#if defined(STUB_DEBUG) && STUB_DEBUG
# if defined(STUB_DEBUG) && STUB_DEBUG
DEBUG_STUB("%s %-35s: FD: %d Verify result: (%d) \"%s\"\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err,
X509_verify_cert_error_string(err));
#endif
# endif
if (!preverify_ok && !upstream->tls_fallback_ok)
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR,
"%-40s : Verify failed : Transport=TLS - *Failure* - (%d) \"%s\"\n",
"%-40s : Verify failed: TLS - *Failure* - (%d) \"%s\"\n",
upstream->addr_str, err,
X509_verify_cert_error_string(err));
/* First deal with the hostname authentication done by OpenSSL. */
#ifdef X509_V_ERR_HOSTNAME_MISMATCH
# if defined(STUB_DEBUG) && STUB_DEBUG
/*Report if error is hostname mismatch*/
if (err == X509_V_ERR_HOSTNAME_MISMATCH && upstream->tls_fallback_ok)
DEBUG_STUB("%s %-35s: FD: %d WARNING: Proceeding even though hostname validation failed!\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd);
# endif
#else
/* if we weren't built against OpenSSL with hostname matching we
* could not have matched the hostname, so this would be an automatic
* tls_auth_fail if there is a hostname provided*/
if (upstream->tls_auth_name[0]) {
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
preverify_ok = 0;
}
#endif
/* No need to deal with hostname authentication, since this will be
* dealt with in the DANE preprocessor paths.
*/
/* Now deal with the pinset validation*/
/* Deal with the pinset validation */
if (upstream->tls_pubkey_pinset)
pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx);
@ -880,24 +896,9 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd);
else
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR,
"%-40s : Conn failed : Transport=TLS - *Failure* - Pinset validation failure\n",
"%-40s : Conn failed: TLS - *Failure* - Pinset validation failure\n",
upstream->addr_str);
} else {
/* If we _only_ had a pinset and it is good then force succesful
authentication when the cert self-signed
TODO: We need to check for other error cases here, not blindly accept the cert!! */
if ((upstream->tls_pubkey_pinset && upstream->tls_auth_name[0] == '\0') &&
(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
preverify_ok = 1;
DEBUG_STUB("%s %-35s: FD: %d, Allowing self-signed (%d) cert since pins match\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err);
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
"%-40s : Verify passed : Transport=TLS - Allowing self-signed cert since pins match\n",
upstream->addr_str);
}
}
/* If nothing has failed yet and we had credentials, we have succesfully authenticated*/
if (preverify_ok == 0)
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
@ -910,6 +911,8 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
return (upstream->tls_fallback_ok) ? 1 : preverify_ok;
}
#endif /* #else defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */
static SSL*
tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
{
@ -925,6 +928,10 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
SSL_free(ssl);
return NULL;
}
#if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST
if (upstream->tls_curves_list)
(void) SSL_set1_curves_list(ssl, upstream->tls_curves_list);
#endif
/* make sure we'll be able to find the context again when we need it */
if (_getdns_associate_upstream_with_SSL(ssl, upstream) != GETDNS_RETURN_GOOD) {
SSL_free(ssl);
@ -942,13 +949,16 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
DEBUG_STUB("%s %-35s: Hostname verification requested for: %s\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name);
SSL_set_tlsext_host_name(ssl, upstream->tls_auth_name);
#ifdef HAVE_SSL_HN_AUTH
/* Set up native OpenSSL hostname verification*/
#if defined(HAVE_SSL_HN_AUTH)
/* Set up native OpenSSL hostname verification
* ( doesn't work with USE_DANESSL, but we verify the
* name afterwards in such cases )
*/
X509_VERIFY_PARAM *param;
param = SSL_get0_param(ssl);
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0);
#else
#elif !defined(HAVE_X509_CHECK_HOST)
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
DEBUG_STUB("%s %-35s: ERROR: Hostname Authentication not available from TLS library (check library version)\n",
STUB_DEBUG_SETUP_TLS, __FUNC__);
@ -956,6 +966,8 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
"%-40s : ERROR: Hostname Authentication not available from TLS library (check library version)\n",
upstream->addr_str);
upstream->tls_hs_state = GETDNS_HS_FAILED;
SSL_free(ssl);
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
return NULL;
}
#endif
@ -970,9 +982,14 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning authentication\n",
STUB_DEBUG_SETUP_TLS, __FUNC__);
} else {
DEBUG_STUB("%s %-35s: ERROR: No host name or pubkey pinset provided for TLS authentication\n",
DEBUG_STUB("%s %-35s: ERROR:No auth name or pinset provided for this upstream for Strict TLS authentication\n",
STUB_DEBUG_SETUP_TLS, __FUNC__);
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR,
"%-40s : Verify fail: *CONFIG ERROR* - No auth name or pinset provided for this upstream for Strict TLS authentication\n",
upstream->addr_str);
upstream->tls_hs_state = GETDNS_HS_FAILED;
SSL_free(ssl);
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
return NULL;
}
} else {
@ -992,7 +1009,71 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
DEBUG_STUB("%s %-35s: Using Strict TLS \n", STUB_DEBUG_SETUP_TLS,
__FUNC__);
}
#if defined(HAVE_SSL_DANE_ENABLE)
int osr;
# if defined(STUB_DEBUG) && STUB_DEBUG
osr =
# else
(void)
# endif
SSL_dane_enable(ssl, *upstream->tls_auth_name ? upstream->tls_auth_name : NULL);
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr);
SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
sha256_pin_t *pin_p;
size_t n_pins = 0;
for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) {
osr = SSL_dane_tlsa_add(ssl, 2, 1, 1,
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
osr = SSL_dane_tlsa_add(ssl, 3, 1, 1,
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
}
#elif defined(USE_DANESSL)
if (upstream->tls_pubkey_pinset) {
const char *auth_names[2] = { upstream->tls_auth_name, NULL };
int osr;
# if defined(STUB_DEBUG) && STUB_DEBUG
osr =
# else
(void)
# endif
DANESSL_init(ssl,
*upstream->tls_auth_name ? upstream->tls_auth_name : NULL,
*upstream->tls_auth_name ? auth_names : NULL
);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr);
SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
sha256_pin_t *pin_p;
size_t n_pins = 0;
for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) {
osr = DANESSL_add_tlsa(ssl, 3, 1, "sha256",
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
osr = DANESSL_add_tlsa(ssl, 2, 1, "sha256",
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
}
} else {
SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
}
#else
SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback);
#endif
SSL_set_connect_state(ssl);
(void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
@ -1009,7 +1090,6 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
__FUNC__);
}
}
return ssl;
}
@ -1048,16 +1128,120 @@ tls_do_handshake(getdns_upstream *upstream)
return STUB_SETUP_ERROR;
}
}
upstream->tls_hs_state = GETDNS_HS_DONE;
upstream->conn_state = GETDNS_CONN_OPEN;
upstream->conn_completed++;
/* A re-used session is not verified so need to fix up state in that case */
if (SSL_session_reused(upstream->tls_obj))
upstream->tls_auth_state = upstream->last_tls_auth_state;
else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) {
X509 *peer_cert = SSL_get_peer_certificate(upstream->tls_obj);
long verify_result = SSL_get_verify_result(upstream->tls_obj);
/* In case of DANESSL use, and a tls_auth_name was given alongside a pinset,
* we need to verify auth_name explicitely (otherwise it will not be checked,
* because this is not required with DANE with an EE match).
* This is not needed with native OpenSSL DANE, because EE name checks have
* to be disabled explicitely.
*/
#if defined(HAVE_X509_CHECK_HOST) && (defined(USE_DANESSL) || !defined(HAVE_SSL_HN_AUTH))
int xch;
if (peer_cert && verify_result == X509_V_OK
&& upstream->tls_auth_name[0]
&& (xch = X509_check_host(peer_cert,
upstream->tls_auth_name,
strlen(upstream->tls_auth_name),
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS,
NULL)) <= 0)
verify_result = X509_V_ERR_HOSTNAME_MISMATCH;
#endif
upstream->tls_auth_state = peer_cert && verify_result == X509_V_OK
? GETDNS_AUTH_OK : GETDNS_AUTH_FAILED;
if (!peer_cert)
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
( upstream->tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
"%-40s : Verify failed : TLS - %s - "
"Remote did not offer certificate\n",
upstream->addr_str,
( upstream->tls_fallback_ok
? "Tolerated because of Opportunistic profile"
: "*Failure*" ));
/* Since we don't have DANE validation yet, DANE validation
* failures are always pinset validation failures
*/
#if defined(HAVE_SSL_DANE_ENABLE)
else if (verify_result == X509_V_ERR_DANE_NO_MATCH)
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
( upstream->tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
"%-40s : Verify failed : TLS - %s - "
"Pinset validation failure\n", upstream->addr_str,
( upstream->tls_fallback_ok
? "Tolerated because of Opportunistic profile"
: "*Failure*" ));
#elif defined(USE_DANESSL)
else if (verify_result == X509_V_ERR_CERT_UNTRUSTED
&& upstream->tls_pubkey_pinset
&& !DANESSL_get_match_cert(
upstream->tls_obj, NULL, NULL, NULL))
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
( upstream->tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
"%-40s : Verify failed : TLS - %s - "
"Pinset validation failure\n", upstream->addr_str,
( upstream->tls_fallback_ok
? "Tolerated because of Opportunistic profile"
: "*Failure*" ));
#endif
else if (verify_result != X509_V_OK)
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
( upstream->tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
"%-40s : Verify failed : TLS - %s - "
"(%d) \"%s\"\n", upstream->addr_str,
( upstream->tls_fallback_ok
? "Tolerated because of Opportunistic profile"
: "*Failure*" ), verify_result,
X509_verify_cert_error_string(verify_result));
#if !defined(HAVE_SSL_HN_AUTH) && !defined(HAVE_X509_CHECK_HOST)
else if (*upstream->tls_auth_name) {
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
( upstream->tls_fallback_ok
? GETDNS_LOG_INFO : GETDNS_LOG_ERR),
"%-40s : Verify failed : TLS - %s - "
"Hostname Authentication not available from TLS "
"library (check library version)\n",
upstream->addr_str,
( upstream->tls_fallback_ok
? "Tolerated because of Opportunistic profile"
: "*Failure*" ));
upstream->tls_auth_state = GETDNS_AUTH_FAILED;
}
#endif
else
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
"%-40s : Verify passed : TLS\n",
upstream->addr_str);
X509_free(peer_cert);
if (upstream->tls_auth_state == GETDNS_AUTH_FAILED
&& !upstream->tls_fallback_ok)
return STUB_SETUP_ERROR;
}
DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s.\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd,
_getdns_auth_str(upstream->tls_auth_state),
SSL_session_reused(upstream->tls_obj) ?"re-used":"new");
upstream->tls_hs_state = GETDNS_HS_DONE;
upstream->conn_state = GETDNS_CONN_OPEN;
upstream->conn_completed++;
if (upstream->tls_session != NULL)
SSL_SESSION_free(upstream->tls_session);
upstream->tls_session = SSL_get1_session(upstream->tls_obj);
@ -1409,7 +1593,7 @@ stub_udp_read_cb(void *userarg)
if (upstream->udp_responses == 1 ||
upstream->udp_responses % 100 == 0)
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_INFO,
"%-40s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n",
"%-40s : Upstream : UDP - Resps=%6d, Timeouts =%6d (logged every 100 responses)\n",
upstream->addr_str,
(int)upstream->udp_responses, (int)upstream->udp_timeouts);
_getdns_check_dns_req_complete(dnsreq);
@ -1671,7 +1855,7 @@ upstream_write_cb(void *userarg)
/* Cleaning up after connection or auth check failure. Need to fallback. */
stub_cleanup(netreq);
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
"%-40s : Conn closed : Transport=%s - *Failure*\n",
"%-40s : Conn closed: %s - *Failure*\n",
upstream->addr_str,
(upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"));
if (fallback_on_write(netreq) == STUB_TCP_ERROR) {
@ -1686,12 +1870,14 @@ upstream_write_cb(void *userarg)
remove_from_write_queue(upstream, netreq);
if (netreq->owner->return_call_reporting &&
netreq->upstream->tls_obj &&
netreq->debug_tls_peer_cert.data == NULL &&
(cert = SSL_get_peer_certificate(netreq->upstream->tls_obj))) {
netreq->debug_tls_peer_cert.size = i2d_X509(
cert, &netreq->debug_tls_peer_cert.data);
X509_free(cert);
netreq->upstream->tls_obj) {
if (netreq->debug_tls_peer_cert.data == NULL &&
(cert = SSL_get_peer_certificate(netreq->upstream->tls_obj))) {
netreq->debug_tls_peer_cert.size = i2d_X509(
cert, &netreq->debug_tls_peer_cert.data);
X509_free(cert);
}
netreq->debug_tls_version = SSL_get_version(netreq->upstream->tls_obj);
}
/* Need this because auth status is reset on connection close */
netreq->debug_tls_auth_status = netreq->upstream->tls_auth_state;
@ -1826,6 +2012,34 @@ upstream_valid_and_open(getdns_upstream *upstream,
return 1;
}
static int
other_transports_working(getdns_network_req *netreq,
getdns_upstreams *upstreams,
getdns_transport_list_t transport)
{
size_t i,j;
for (i = 0; i< netreq->transport_count;i++) {
if (netreq->transports[i] == transport)
continue;
if (netreq->transports[i] == GETDNS_TRANSPORT_UDP) {
for (j = 0; j < upstreams->count; j+=GETDNS_UPSTREAM_TRANSPORTS) {
if (upstreams->upstreams[j].back_off == 1)
return 1;
}
}
else if (netreq->transports[i] == GETDNS_TRANSPORT_TCP ||
netreq->transports[i] == GETDNS_TRANSPORT_TLS) {
for (j = 0; j < upstreams->count; j++) {
if (netreq->transports[i] == upstreams->upstreams[j].transport &&
upstream_valid(&upstreams->upstreams[j], netreq->transports[i],
netreq, 0))
return 1;
}
}
}
return 0;
}
static getdns_upstream *
upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t transport)
{
@ -1843,8 +2057,9 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
upstreams->upstreams[i].conn_retry_time < now) {
upstreams->upstreams[i].conn_state = GETDNS_CONN_CLOSED;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : Re-instating upstream\n",
upstreams->upstreams[i].addr_str);
"%-40s : Upstream : Re-instating %s for this upstream\n",
upstreams->upstreams[i].addr_str,
upstreams->upstreams[i].transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP");
}
}
@ -1857,12 +2072,13 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
}
/* OK - Find the next one to use. First check we have at least one valid
upstream (not backed-off) because we completely back off failed
upstream (not backed-off). Because we completely back off failed
upstreams we may have no valid upstream at all (in contrast to UDP).*/
i = upstreams->current_stateful;
do {
DEBUG_STUB("%s %-35s: Testing upstreams %d %d\n", STUB_DEBUG_SETUP,
__FUNC__, (int)i, (int)upstreams->upstreams[i].conn_state);
DEBUG_STUB("%s %-35s: Testing upstreams %d %d for transport %d \n",
STUB_DEBUG_SETUP, __FUNC__, (int)i,
(int)upstreams->upstreams[i].conn_state, transport);
if (upstream_valid(&upstreams->upstreams[i], transport, netreq, 0)) {
upstream = &upstreams->upstreams[i];
break;
@ -1872,7 +2088,15 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
i = 0;
} while (i != upstreams->current_stateful);
if (!upstream) {
/* Oh, oh. We have no valid upstreams. Try to find one that might work so
/* Oh, oh. We have no valid upstreams for this transport. */
/* If there are other fallback transports that are working, we should
use them before forcibly promoting failed upstreams for re-try, since
waiting for the the re-try timer to re-instate them is the right thing
in this case. */
if (other_transports_working(netreq, upstreams, transport))
return NULL;
/* Try to find one that might work so
allow backed off upstreams to be considered valid.
Don't worry about the policy, just use the one with the least bad
stats that still fits the bill (right transport, right authentication)
@ -1902,8 +2126,9 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
upstream->conn_state = GETDNS_CONN_CLOSED;
upstream->conn_backoff_interval = 1;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : No valid upstreams... promoting this backed-off upstream for re-try...\n",
upstream->addr_str);
"%-40s : Upstream : No valid upstreams for %s... promoting this backed-off upstream for re-try...\n",
upstream->addr_str,
upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP");
return upstream;
}
@ -2081,7 +2306,7 @@ upstream_find_for_netreq(getdns_network_req *netreq)
/* Handle better, will give generic error*/
DEBUG_STUB("%s %-35s: MSG: %p No valid upstream! \n", STUB_DEBUG_SCHEDULE, __FUNC__, (void*)netreq);
_getdns_context_log(netreq->owner->context, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR,
"*FAILURE* no valid transports or upstreams available!\n");
" *FAILURE* no valid transports or upstreams available!\n");
return -1;
}

View File

@ -83,7 +83,7 @@ void handler(getdns_context *context, getdns_callback_type_t callback_type,
exit(EXIT_FAILURE);
}
int main()
int main(int argc, char **argv)
{
getdns_context *context = NULL;
getdns_list *listeners = NULL;
@ -92,9 +92,20 @@ int main()
uint32_t port1 = 18000;
uint32_t port2 = 18000;
getdns_return_t r;
char listenliststr[1024];
char listendictstr[1024];
if ((r = getdns_str2list("[ 127.0.0.1:18000 ]", &listeners)) ||
(r = getdns_str2dict("127.0.0.1:18000", &address2)) ||
if (argc != 2) {
fprintf(stderr, "usage: %s <localhost ipv4>\n", argv[0]);
return 1;
}
(void) snprintf(listenliststr, sizeof(listenliststr),
"[ %s:18000 ]", argv[1]);
(void) snprintf(listendictstr, sizeof(listendictstr),
"%s:18000", argv[1]);
if ((r = getdns_str2list(listenliststr, &listeners)) ||
(r = getdns_str2dict(listendictstr, &address2)) ||
(r = getdns_list_get_dict(listeners, 0, &address)) ||
(r = getdns_context_create(&context, 0)))
fprintf(stderr, "Error initializing: ");

View File

@ -4,18 +4,22 @@
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
LOCALHOST=`${GETDNS_STUB_QUERY} '{namespaces:[GETDNS_NAMESPACE_LOCALNAMES]}' -A localhost. -J \
| awk -F: '/\"address_data\".*\"127/{print $2}' \
| sed -e 's/^[^"]*"//g' -e 's/"[^"]*$//g'`
echo "localhost: $LOCALHOST"
make && "${BUILDDIR}/build-stub-only/libtool" exec valgrind -v --log-file=valgrind.log --leak-check=full --error-exitcode=1 --track-origins=yes "./${TPKG_NAME}" | (
make && "${BUILDDIR}/build-stub-only/libtool" exec valgrind -v --log-file=valgrind.log --leak-check=full --error-exitcode=1 --track-origins=yes "./${TPKG_NAME}" ${LOCALHOST} | (
read PORT
read PORT2
${GETDNS_STUB_QUERY} -s -t 1000 @127.0.0.1:$PORT TXT cancel. +return_call_reporting 2>&1 > time_out
${GETDNS_STUB_QUERY} -s -t 1000 @${LOCALHOST}:$PORT TXT cancel. +return_call_reporting 2>&1 > time_out
${GETDNS_STUB_QUERY} -s @127.0.0.1:$PORT TXT test +return_call_reporting 2>&1 > tcp_out
${GETDNS_STUB_QUERY} -s @${LOCALHOST}:$PORT TXT test +return_call_reporting 2>&1 > tcp_out
${GETDNS_STUB_QUERY} -s -U @127.0.0.1:$PORT2 TXT test +return_call_reporting 2>&1 > udp_out
${GETDNS_STUB_QUERY} -s -U @${LOCALHOST}:$PORT2 TXT test +return_call_reporting 2>&1 > udp_out
${GETDNS_STUB_QUERY} -s -q @127.0.0.1:$PORT TXT quit.
${GETDNS_STUB_QUERY} -s -q @${LOCALHOST}:$PORT TXT quit.
)
if grep -q 'definitely lost: [^0]' valgrind.log
then

View File

@ -107,15 +107,23 @@ void handler(getdns_context *context, getdns_callback_type_t callback_type,
exit(EXIT_FAILURE);
}
int main()
int main(int argc, char **argv)
{
getdns_context *context = NULL;
getdns_list *listeners = NULL;
getdns_dict *address = NULL;
uint32_t port = 18000;
getdns_return_t r;
char listenliststr[1024];
if ((r = getdns_str2list("[ 127.0.0.1:18000 ]", &listeners)) ||
if (argc != 2) {
fprintf(stderr, "usage: %s <localhost ipv4>\n", argv[0]);
return 1;
}
(void) snprintf(listenliststr, sizeof(listenliststr),
"[ %s:18000 ]", argv[1]);
if ((r = getdns_str2list(listenliststr, &listeners)) ||
(r = getdns_list_get_dict(listeners, 0, &address)) ||
(r = getdns_context_create(&context, 0)))
fprintf(stderr, "Error initializing: ");

View File

@ -5,21 +5,27 @@
[ -f .tpkg.var.test ] && source .tpkg.var.test
LOCALHOST=`${GETDNS_STUB_QUERY} '{namespaces:[GETDNS_NAMESPACE_LOCALNAMES]}' -A localhost. -J \
| awk -F: '/\"address_data\".*\"127/{print $2}' \
| sed -e 's/^[^"]*"//g' -e 's/"[^"]*$//g'`
echo "localhost: $LOCALHOST"
QLIMIT=64
NQUERIES=`wc "./${TPKG_NAME}.queries"|sed 's/ .*$//g'`
NQUERIES=`wc "./${TPKG_NAME}.queries"|sed -e 's/^ *//g' -e 's/ .*$//g'`
echo "# queries: $NQUERIES"
# Test will take NQUERIES / QLIMIT * answer delay
# For current parameters this is 1000 / 64 * 0.3 = 4.6875
# which is smaller than 5 seconds default query timeout value,
# so the test should succeed.
make && "./${TPKG_NAME}" | (
make && "./${TPKG_NAME}" ${LOCALHOST} | (
read PORT
${GETDNS_STUB_QUERY} @127.0.0.1:$PORT TXT \
${GETDNS_STUB_QUERY} @${LOCALHOST}:$PORT TXT \
-a -F "./${TPKG_NAME}.queries" \
"{limit_outstanding_queries:$QLIMIT}" 2>&1 > out
${GETDNS_STUB_QUERY} -q @127.0.0.1:$PORT TXT quit.
${GETDNS_STUB_QUERY} -q @${LOCALHOST}:$PORT TXT quit.
) && grep '"n_requests: [0-9][0-9]*"' out | sed -e 's/^.*n_requests: //g' -e 's/".*$//g' \
| awk -vQLIMIT=$QLIMIT -vNQUERIES=$NQUERIES '

View File

@ -112,15 +112,23 @@ void handler(getdns_context *context, getdns_callback_type_t callback_type,
exit(EXIT_FAILURE);
}
int main()
int main(int argc, char **argv)
{
getdns_context *context = NULL;
getdns_list *listeners = NULL;
getdns_dict *address = NULL;
uint32_t port = 18000;
getdns_return_t r;
char listenliststr[1024];
if ((r = getdns_str2list("[ 127.0.0.1:18000 ]", &listeners)) ||
if (argc != 2) {
fprintf(stderr, "usage: %s <localhost ipv4>\n", argv[0]);
return 1;
}
(void) snprintf(listenliststr, sizeof(listenliststr),
"[ %s:18000 ]", argv[1]);
if ((r = getdns_str2list(listenliststr, &listeners)) ||
(r = getdns_list_get_dict(listeners, 0, &address)) ||
(r = getdns_context_create(&context, 0)))
fprintf(stderr, "Error initializing: ");

View File

@ -5,8 +5,14 @@
[ -f .tpkg.var.test ] && source .tpkg.var.test
LOCALHOST=`${GETDNS_STUB_QUERY} '{namespaces:[GETDNS_NAMESPACE_LOCALNAMES]}' -A localhost. -J \
| awk -F: '/\"address_data\".*\"127/{print $2}' \
| sed -e 's/^[^"]*"//g' -e 's/"[^"]*$//g'`
echo "localhost: $LOCALHOST"
QLIMIT=79
NQUERIES=`wc "./${TPKG_NAME}.queries"|sed 's/ .*$//g'`
NQUERIES=`wc "./${TPKG_NAME}.queries"|sed -e 's/^ *//g' -e 's/ .*$//g'`
echo "# queries: $NQUERIES"
# This time the query limit is set by setting the maximum open
# filedescriptors. We seem to be needing a higher QLIMIT, than
@ -21,13 +27,13 @@ NQUERIES=`wc "./${TPKG_NAME}.queries"|sed 's/ .*$//g'`
# which is smaller than 5 seconds default query timeout value,
# so the test should succeed.
make && "./${TPKG_NAME}" | (
make && "./${TPKG_NAME}" ${LOCALHOST}| (
read PORT
ulimit -n $QLIMIT
${GETDNS_STUB_QUERY} @127.0.0.1:$PORT TXT \
${GETDNS_STUB_QUERY} @${LOCALHOST}:$PORT TXT \
-a -F "./${TPKG_NAME}.queries" 2>&1 > out
${GETDNS_STUB_QUERY} -q @127.0.0.1:$PORT TXT quit.
${GETDNS_STUB_QUERY} -q @${LOCALHOST}:$PORT TXT quit.
) && grep '"n_requests: [0-9][0-9]*"' out | sed -e 's/^.*n_requests: //g' -e 's/".*$//g' \
| awk -vQLIMIT=$QLIMIT -vNQUERIES=$NQUERIES '

View File

@ -45,9 +45,9 @@ CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ @CPPFLAGS@ $(WPEDANTIC
LDFLAGS=-L.. @LDFLAGS@
LDLIBS=../libgetdns.la @LIBS@
ALL_OBJS=getdns_query.lo
ALL_OBJS=getdns_query.lo getdns_server_mon.lo
PROGRAMS=getdns_query
PROGRAMS=getdns_query getdns_server_mon
.SUFFIXES: .c .o .a .lo .h
@ -68,6 +68,9 @@ $(ALL_OBJS):
getdns_query: getdns_query.lo
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS)
getdns_server_mon: getdns_server_mon.lo
$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_server_mon.lo $(LDFLAGS) $(LDLIBS)
stubby:
cd .. && $(MAKE) $@
@ -78,6 +81,13 @@ install-getdns_query: getdns_query
uninstall-getdns_query:
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/getdns_query
install-getdns_server_mon: getdns_server_mon
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
$(LIBTOOL) --mode=install cp getdns_server_mon $(DESTDIR)$(bindir)
uninstall-getdns_server_mon:
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/getdns_server_mon
install-stubby:
cd .. && $(MAKE) $@
@ -117,3 +127,10 @@ getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c \
$(srcdir)/../debug.h \
../getdns/getdns.h \
../getdns/getdns_extra.h
# Dependencies for getdns_server_mon
getdns_server_mon.lo getdns_server_mon.o: $(srcdir)/getdns_server_mon.c \
../config.h \
$(srcdir)/../debug.h \
../getdns/getdns.h \
../getdns/getdns_extra.h

263
src/tools/README.adoc Normal file
View File

@ -0,0 +1,263 @@
= getdns tools
This directory contains some tools based on `getdns`.
* `getdns_query` - a command line wrapper for `getdns`.
* `getdns_server_mon` - test DNS server function and capabilities.
== `getdns_query`
`getdns_query` is a command line wrapper for `getdns` exposing the
features of this implementation (both in the official API and the
additional API functions).
=== Usage
----
usage: getdns_query [<option> ...] \
[@<upstream> ...] [+<extension> ...] ['{ <settings> }'] [<name>] [<type>]
default mode: recursive, synchronous resolution of NS record
using UDP with TCP fallback
upstreams: @<ip>[%<scope_id>][@<port>][#<tls port>][~<tls name>][^<tsig spec>]
<ip>@<port> may be given as <IPv4>:<port>
or '['<IPv6>[%<scope_id>]']':<port> too
tsig spec: [<algorithm>:]<name>:<secret in Base64>
extensions:
+add_warning_for_bad_dns
+dnssec_return_status
+dnssec_return_only_secure
+dnssec_return_all_statuses
+dnssec_return_validation_chain
+dnssec_return_full_validation_chain
+dnssec_roadblock_avoidance
+edns_cookies
+return_both_v4_and_v6
+return_call_reporting
+sit=<cookie> Send along cookie OPT with value <cookie>
+specify_class=<class>
+0 Clear all extensions
settings in json dict format (like outputted by -i option).
options:
-a Perform asynchronous resolution (default = synchronous)
-A address lookup (<type> is ignored)
-B Batch mode. Schedule all messages before processing responses.
-b <bufsize> Set edns0 max_udp_payload size
-c Send Client Subnet privacy request
-C <filename>
Read settings from config file <filename>
The getdns context will be configured with these settings
The file must be in YAML format (with extension of '.yml')
or JSON dict format (with extension '.conf')
-D Set edns0 do bit
-d clear edns0 do bit
-e <idle_timeout> Set idle timeout in milliseconds
-F <filename> read the queries from the specified file
-f <filename> Read DNSSEC trust anchors from <filename>
-G general lookup
-H hostname lookup. (<name> must be an IP address; <type> is ignored)
-h Print this help
-i Print api information
-I Interactive mode (> 1 queries on same context)
-j Output json response dict
-J Pretty print json response dict
-k Print root trust anchors
-K <pin> Pin a public key for TLS connections (can repeat)
(should look like 'pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="')
-m Set TLS authentication mode to REQUIRED
-n Set TLS authentication mode to NONE (default)
-o <filename> Set resolver configuration file path
(default = /etc/resolv.conf)
-p Pretty print response dict (default)
-P <blocksize> Pad TLS queries to a multiple of blocksize
(special values: 0: no padding, 1: sensible default policy)
-q Quiet mode - don't print response
-r Set recursing resolution type
-R <filename> Read root hints from <filename>
-s Set stub resolution type(default = recursing)
-S service lookup (<type> is ignored)
-t <timeout> Set timeout in milliseconds
-v Print getdns release version
-V Increase verbosity (may be used more than once)
-x Do not follow redirects
-X Follow redirects (default)
-0 Append suffix to single label first (default)
-W Append suffix always
-1 Append suffix only to single label after failure
-M Append suffix only to multi label name after failure
-N Never append a suffix
-Z <suffixes> Set suffixes with the given comma separated list
-T Set transport to TCP only
-O Set transport to TCP only keep connections open
-L Set transport to TLS only keep connections open
-E Set transport to TLS with TCP fallback only keep connections open
-u Set transport to UDP with TCP fallback (default)
-U Set transport to UDP only
-l <transports> Set transport list. List can contain 1 of each of the characters
U T L for UDP, TCP or TLS e.g 'UT' or 'LTU'
-z <listen address>
Listen for DNS requests on the given IP address
<listen address> is in the same format as upstreams.
This option can be given more than once.
----
== `getdns_server_mon`
`getdns_server_mon` is a collection of DNS server tests. The tests examine
both server function and server capability.
`get_server_mon` can optionally be run in Monitoring mode. In this mode,
the tool output is modified to enable it to function as a plugin for
popular monitoring systems such as https://www.icinga.org[Icinga],
http://naemon.github.io/[Naemon], http://www.nagios.org[Nagios],
http://www.shinken-monitoring.org/[Shinken], http://sensuapp.org/[Sensu]
and others.
=== Usage
----
Usage: getdns_server_mon [-M] [-E] [(-u|-t|-T)] [-S] [-K <spki-pin>]
[-v [-v [-v]]] [-V] @upstream testname [<test args>]
-M|--monitoring Make output suitable for monitoring tools
-E|--fail-on-dns-errors Fail on DNS error (NXDOMAIN, SERVFAIL)
-u|--udp Use UDP transport
-t|--tcp Use TCP transport
-T|--tls Use TLS transport
-S|--strict-usage-profile Use strict profile (require authentication)
-K|--spki-pin <spki-pin> SPKI pin for TLS connections (can repeat)
-v|--verbose Increase output verbosity
-D|--debug Enable debugging output
-V|--version Report GetDNS version
spki-pin: Should look like 'pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="'
upstream: @<ip>[%<scope_id][@<port>][#<tls_port>][~tls name>][^<tsig spec>]
<ip>@<port> may be given as <IPv4>:<port> or
'['<IPv6>[%<scope_id>]']':<port>
tsig spec: [<algorithm>:]<name>:<secret in Base64>
Tests:
lookup [<name> [<type>]] Check lookup on server
keepalive <timeout-ms> [<name> [<type>]]
Check server support for EDNS0 keepalive in
TCP or TLS connections
Timeout of 0 is off.
OOOR Check whether server delivers responses out of
query order on a TCP or TLS connection
qname-min Check whether server supports QNAME minimisation
rtt [warn-ms,crit-ms] [<name> [<type>]]
Check if server round trip time exceeds
thresholds (default 250,500)
dnssec-validate Check whether server does DNSSEC validation
tls-auth [<name> [<type>]] Check authentication of TLS server
If both a SPKI pin and authentication name are
provided, both must authenticate for this test
to pass.
tls-cert-valid [warn-days,crit-days] [<name> [type]]
Check server certificate validity, report
warning or critical if days to expiry at
or below thresholds (default 14,7).
tls-padding <blocksize> [<name> [<type>]]
Check server support for EDNS0 padding in TLS
Special blocksize values are 0 = off,
1 = sensible default.
tls-1.3 Check whether server supports TLS 1.3
Enabling monitoring mode ensures output messages and exit statuses conform
to the requirements of monitoring plugins (www.monitoring-plugins.org).
----
Note that the server must currently be specified with an IPv4 or an IPv6 address.
=== The tests
Several tests take optional name and RR type parameters. If these are not supplied,
default values of `getdnsapi.net` and `AAAA` are used. If the lookup returns no
answering records, `getdns_server_mon` reports a status of WARNING.
[cols="1,3a,1" options="header"]
|===
| Test name | Test description | Default connection type
| `lookup`
| Check a name lookup succeeds.
| UDP with TCP fallback
| `keepalive`
| See if the server supports EDNS0 keepalive in TCP or TLS
connections. Specify a non-zero timeout to set the keepalive timeout
in milliseconds, or 0 to disable it.
| TCP
| `OOOR`
| Out Of Order Responses. See if the server will send responses to
multiple queries in a single TCP or TLS connection in a different
order to the order of queries.
This test is currently experimental, and may give false negative results.
| TCP
| `qname-min`
| Does the server support QNAME minimisation?
| UDP with TCP fallback
|`rtt`
| Check a lookup round trip time exceeds warning and critical levels in milliseconds.
If thresholds are not specified, defaults of 500ms (critical) and 250ms (warning) are used.
| UDP with TCP fallback
|`dnssec-validate`
| See if the server is doing DNSSEC validation.
| UDP with TCP fallback
|`tls-auth`
| Check if a TLS lookup authenticates successfully. You must specify
either a SPKI pin, an authentication name, or both. If you supply
both, both must authenticate for the test to succeed.
| TLS
|`tls-cert-valid`
| Check the server certificate against warning and critical days to
expiry. If thresholds are not specified, defaults of 7 days
(critical) and 14 days (warning) are used.
| TLS
|`tls-padding`
| Does the server support EDNS0 padding? Specify a non-zero blocksize to set
the padding. A padding size of 1 specifies padding of a sensible default size.
| TLS
|`tls-1.3`
| Does the server support TLS 1.3? To enable this test,
`getdns_server_mon` must be compiled with OpenSSL v1.1.1 or later.
This test is currently experimental, and may give false negative results.
| TLS
|===
=== Exit status
[cols="^1,^1,3a" options="header"]
|===
| Numeric value | Service Status | Status Description
| 0
| OK
| The service was functioning properly
| 1
| WARNING
| The service fell below a warning threshold
|2
| CRITICAL
| The service was not working or fell below a critical threshold
|3
| UNKNOWN | Invalid arguments or an internal low-level failure
|===

View File

@ -57,19 +57,7 @@ getdns_return_t getdns_yaml2dict(const char *, getdns_dict **dict);
#define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""
static int verbosity = 0;
static int i_am_stubby = 0;
static const char *default_stubby_config =
"{ resolution_type: GETDNS_RESOLUTION_STUB"
", dns_transport_list: [ GETDNS_TRANSPORT_TLS, GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP ]"
", idle_timeout: 10000"
", listen_addresses: [ 127.0.0.1@53, 0::1@53 ]"
", tls_query_padding_blocksize: 1"
", edns_client_subnet_private : 1"
"}";
static int clear_listen_list_on_arg = 0;
#ifndef GETDNS_ON_WINDOWS
static int run_in_foreground = 1;
#endif
static int quiet = 0;
static int batch_mode = 0;
static char *query_file = NULL;
@ -95,6 +83,8 @@ static int check_dnssec = 0;
static char *resolvconf = NULL;
#endif
static int print_api_info = 0, print_trust_anchors = 0;
static int log_level = 0;
static uint64_t log_systems = 0xFFFFFFFFFFFFFFFF;
static int get_rrtype(const char *t)
{
@ -179,19 +169,14 @@ print_usage(FILE *out, const char *progname)
{
fprintf(out, "usage: %s [<option> ...] \\\n"
"\t[@<upstream> ...] [+<extension> ...] [\'{ <settings> }\'] [<name>] [<type>]\n", progname);
if (!i_am_stubby) {
fprintf(out, "\ndefault mode: "
#ifdef HAVE_LIBUNBOUND
"recursive"
# define DEFAULT_RESOLUTION_TYPE "recursive"
#else
"stub"
# define DEFAULT_RESOLUTION_TYPE "stub"
#endif
", synchronous resolution of NS record\n\t\tusing UDP with TCP fallback\n");
}
else {
fprintf(out, "\ndefault mode: "
"stub, asynchronous resolution \n\t\tusing TLS with UDP then TCP fallback\n");
}
fprintf(out, "\ndefault mode: " DEFAULT_RESOLUTION_TYPE
", synchronous resolution of NS record\n\t\tusing UDP with TCP fallback\n");
fprintf(out, "\nupstreams: @<ip>[%%<scope_id>][@<port>][#<tls port>][~<tls name>][^<tsig spec>]");
fprintf(out, "\n <ip>@<port> may be given as <IPv4>:<port>");
fprintf(out, "\n or \'[\'<IPv6>[%%<scope_id>]\']\':<port> too\n");
@ -216,12 +201,9 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t+0\t\t\tClear all extensions\n");
fprintf(out, "\nsettings in json dict format (like outputted by -i option).\n");
fprintf(out, "\noptions:\n");
if (!i_am_stubby) {
fprintf(out, "\t-a\tPerform asynchronous resolution "
"(default = synchronous)\n");
fprintf(out, "\t-A\taddress lookup (<type> is ignored)\n");
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
}
fprintf(out, "\t-a\tPerform asynchronous resolution (default = synchronous)\n");
fprintf(out, "\t-A\taddress lookup (<type> is ignored)\n");
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
fprintf(out, "\t-b <bufsize>\tSet edns0 max_udp_payload size\n");
fprintf(out, "\t-c\tSend Client Subnet privacy request\n");
fprintf(out, "\t-C\t<filename>\n");
@ -229,28 +211,16 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t\tThe getdns context will be configured with these settings\n");
fprintf(out, "\t\tThe file must be in YAML format (with extension of '.yml')\n");
fprintf(out, "\t\tor JSON dict format (with extension '.conf')\n");
if (i_am_stubby) {
fprintf(out, "\t\tBy default, configuration is first read from");
fprintf(out, "\n\t\t\"/etc/stubby.conf\" and then from \"$HOME/.stubby.conf\"\n");
}
fprintf(out, "\t-D\tSet edns0 do bit\n");
fprintf(out, "\t-d\tclear edns0 do bit\n");
fprintf(out, "\t-e <idle_timeout>\tSet idle timeout in milliseconds\n");
if (!i_am_stubby)
fprintf(out, "\t-F <filename>\tread the queries from the specified file\n");
fprintf(out, "\t-F <filename>\tread the queries from the specified file\n");
fprintf(out, "\t-f <filename>\tRead DNSSEC trust anchors from <filename>\n");
#ifndef GETDNS_ON_WINDOWS
if (i_am_stubby)
fprintf(out, "\t-g\tRun stubby in background (default is foreground)\n");
#endif
if (!i_am_stubby) {
fprintf(out, "\t-G\tgeneral lookup\n");
fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> is ignored)\n");
}
fprintf(out, "\t-G\tgeneral lookup\n");
fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> is ignored)\n");
fprintf(out, "\t-h\tPrint this help\n");
fprintf(out, "\t-i\tPrint api information\n");
if (!i_am_stubby)
fprintf(out, "\t-I\tInteractive mode (> 1 queries on same context)\n");
fprintf(out, "\t-I\tInteractive mode (> 1 queries on same context)\n");
fprintf(out, "\t-j\tOutput json response dict\n");
fprintf(out, "\t-J\tPretty print json response dict\n");
fprintf(out, "\t-k\tPrint root trust anchors\n");
@ -266,19 +236,21 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-P <blocksize>\tPad TLS queries to a multiple of blocksize\n"
"\t\t(special values: 0: no padding, 1: sensible default policy)\n");
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
fprintf( out, "\t-r\tSet recursing resolution type%s\n"
, i_am_stubby ? "(default = stub)" : "");
fprintf( out, "\t-r\tSet recursing resolution type (default = "
DEFAULT_RESOLUTION_TYPE ")\n");
fprintf(out, "\t-R <filename>\tRead root hints from <filename>\n");
fprintf(out, "\t-s\tSet stub resolution type%s\n"
, i_am_stubby ? "" : "(default = recursing)" );
if (!i_am_stubby)
fprintf(out, "\t-S\tservice lookup (<type> is ignored)\n");
fprintf(out, "\t-s\tSet stub resolution type (default = "
DEFAULT_RESOLUTION_TYPE ")\n");
fprintf(out, "\t-S\tservice lookup (<type> is ignored)\n");
fprintf(out, "\t-t <timeout>\tSet timeout in milliseconds\n");
fprintf(out, "\t-v\tPrint getdns release version\n");
fprintf(out, "\t-V\tIncrease verbosity (may be used more than once)\n");
fprintf(out, "\t-x\tDo not follow redirects\n");
fprintf(out, "\t-X\tFollow redirects (default)\n");
fprintf(out, "\t-y <log level>\tPrint log messages with"
"severity <= <log level> (default = 0)\n");
fprintf(out, "\t-Y <log systems>\tBitwise or'ed set of systems for "
" which to print log messages (default == -1 (= all))\n");
fprintf(out, "\t-0\tAppend suffix to single label first (default)\n");
fprintf(out, "\t-W\tAppend suffix always\n");
fprintf(out, "\t-1\tAppend suffix only to single label after failure\n");
@ -298,8 +270,6 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t\tListen for DNS requests on the given IP address\n");
fprintf(out, "\t\t<listen address> is in the same format as upstreams.\n");
fprintf(out, "\t\tThis option can be given more than once.\n");
if (i_am_stubby)
fprintf(out, "\t\t(default is to listen on 127.0.0.1:53)\n");
}
static getdns_return_t validate_chain(getdns_dict *response)
@ -609,6 +579,7 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_bindata bindata;
size_t upstream_count = 0;
FILE *fh;
int int_value;
for (i = 1; i < argc; i++) {
arg = argv[i];
@ -927,17 +898,49 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_follow_redirects(
context, GETDNS_REDIRECTS_FOLLOW);
break;
case 'y':
if (c[1] != 0 || ++i >= argc || !*argv[i]) {
fprintf(stderr, "log level expected "
"after -y\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
int_value = strtol(argv[i], &endptr, 10);
if (*endptr || int_value < 0) {
fprintf(stderr, "positive "
"numeric log level expected "
"after -y\n");
return GETDNS_RETURN_GENERIC_ERROR;
} else
log_level = int_value;
goto next;
case 'Y':
if (c[1] != 0 || ++i >= argc || !*argv[i]) {
fprintf(stderr, "log systems expected "
"after -y\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
int_value = strtol(argv[i], &endptr, 10);
if (*endptr || int_value < 0) {
fprintf(stderr, "positive "
"numeric log systems expected "
"after -Y\n");
return GETDNS_RETURN_GENERIC_ERROR;
} else
log_systems = (uint64_t)int_value;
goto next;
case 'e':
if (c[1] != 0 || ++i >= argc || !*argv[i]) {
fprintf(stderr, "idle timeout expected "
"after -t\n");
"after -e\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
timeout = strtol(argv[i], &endptr, 10);
if (*endptr || timeout < 0) {
fprintf(stderr, "positive "
"numeric idle timeout expected "
"after -t\n");
"after -e\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
getdns_context_set_idle_timeout(
@ -1081,12 +1084,6 @@ getdns_return_t parse_args(int argc, char **argv)
}
break;
default:
#ifndef GETDNS_ON_WINDOWS
if (i_am_stubby && *c == 'g') {
run_in_foreground = 0;
break;
}
#endif
fprintf(stderr, "Unknown option "
"\"%c\"\n", *c);
for (i = 0; i < argc; i++)
@ -1616,7 +1613,43 @@ static void incoming_request_handler(getdns_context *context,
fprintf(stderr, "Could set class from query: %s\n",
getdns_get_errorstr_by_id(r));
else if ((r = getdns_general(context, qname_str, qtype,
else if (qtype == GETDNS_RRTYPE_TXT && qclass == GETDNS_RRCLASS_CH &&
strcasecmp(qname_str, "version.bind.") == 0) {
const char *getdns_query_version = "getdns_query " GETDNS_VERSION;
char getdns_version[100] = "getdns ";
char getdns_api_version[100] = "getdns API ";
response = request;
(void) getdns_dict_set_bindata(response, "/answer/0/name", qname);
(void) getdns_dict_set_int(response, "/answer/0/type", qtype);
(void) getdns_dict_set_int(response, "/answer/0/class", qclass);
(void) getdns_dict_set_int(response, "/answer/0/ttl", 0);
(void) getdns_dict_util_set_string(response,
"/answer/0/rdata/txt_strings/0", getdns_query_version);
(void) getdns_dict_set_bindata(response, "/answer/1/name", qname);
(void) getdns_dict_set_int(response, "/answer/1/type", qtype);
(void) getdns_dict_set_int(response, "/answer/1/class", qclass);
(void) getdns_dict_set_int(response, "/answer/1/ttl", 0);
(void) strncat(getdns_version + 7,
getdns_get_version(), sizeof(getdns_version) - 8);
(void) getdns_dict_util_set_string(response,
"/answer/1/rdata/txt_strings/0",getdns_version);
(void) getdns_dict_set_bindata(response, "/answer/2/name", qname);
(void) getdns_dict_set_int(response, "/answer/2/type", qtype);
(void) getdns_dict_set_int(response, "/answer/2/class", qclass);
(void) getdns_dict_set_int(response, "/answer/2/ttl", 0);
(void) strncat(getdns_api_version + 11,
getdns_get_api_version(), sizeof(getdns_api_version) - 12);
(void) getdns_dict_util_set_string(response,
"/answer/2/rdata/txt_strings/0",getdns_api_version);
(void) getdns_dict_set_int(response, "/header/ancount", 3);
goto answer_request;
} else if ((r = getdns_general(context, qname_str, qtype,
qext, msg, &transaction_id, request_cb)))
fprintf(stderr, "Could not schedule query: %s\n",
getdns_get_errorstr_by_id(r));
@ -1627,9 +1660,8 @@ static void incoming_request_handler(getdns_context *context,
return;
}
error:
if (qname_str)
free(qname_str);
servfail(msg, &response);
answer_request:
#if defined(SERVER_DEBUG) && SERVER_DEBUG
do {
char *request_str = getdns_pretty_print_dict(request);
@ -1646,16 +1678,20 @@ error:
/* Cancel reply */
getdns_reply(context, NULL, request_id);
}
if (response && response != request)
getdns_dict_destroy(response);
if (qname_str)
free(qname_str);
if (msg) {
if (msg->request)
getdns_dict_destroy(msg->request);
free(msg);
}
if (response)
getdns_dict_destroy(response);
}
static void stubby_log(void *userarg, uint64_t system,
static void _getdns_query_log(void *userarg, uint64_t system,
getdns_loglevel_type level, const char *fmt, va_list ap)
{
struct timeval tv;
@ -1664,16 +1700,10 @@ static void stubby_log(void *userarg, uint64_t system,
#ifdef GETDNS_ON_WINDOWS
time_t tsec;
if (!verbosity)
return;
gettimeofday(&tv, NULL);
tsec = (time_t) tv.tv_sec;
gmtime_s(&tm, (const time_t *) &tsec);
#else
if (!verbosity)
return;
gettimeofday(&tv, NULL);
gmtime_r(&tv.tv_sec, &tm);
#endif
@ -1695,18 +1725,7 @@ static void stubby_log(void *userarg, uint64_t system,
int
main(int argc, char **argv)
{
char home_stubby_conf_fn[1024];
getdns_return_t r;
#ifndef USE_WINSOCK
char *prg_name = strrchr(argv[0], '/');
#else
char *prg_name = strrchr(argv[0], '\\');
#endif
prg_name = prg_name ? prg_name + 1 : argv[0];
i_am_stubby = strcasecmp(prg_name, "stubby") == 0
|| strcasecmp(prg_name, "lt-stubby") == 0
|| strcasecmp(prg_name, "stubby.exe") == 0;
name = the_root;
if ((r = getdns_context_create(&context, 1))) {
@ -1721,22 +1740,6 @@ main(int argc, char **argv)
r = GETDNS_RETURN_MEMORY_ERROR;
goto done_destroy_context;
}
if (i_am_stubby) {
int n_chars = snprintf( home_stubby_conf_fn
, sizeof(home_stubby_conf_fn)
, "%s/.stubby.conf"
, getenv("HOME")
);
(void) parse_config(default_stubby_config, 0);
(void) parse_config_file("/etc/stubby.conf", 0);
if (n_chars > 0 && n_chars < (int)sizeof(home_stubby_conf_fn)){
(void) parse_config_file(home_stubby_conf_fn, 0);
}
clear_listen_list_on_arg = 1;
}
(void) getdns_context_set_logfunc(context, NULL,
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, stubby_log);
if ((r = parse_args(argc, argv)) && r != CONTINUE)
goto done_destroy_context;
#ifndef USE_WINSOCK
@ -1749,6 +1752,9 @@ main(int argc, char **argv)
goto done_destroy_context;
}
#endif
(void) getdns_context_set_logfunc(context, NULL,
log_systems, log_level, _getdns_query_log);
if (print_api_info) {
getdns_dict *api_information =
getdns_context_get_api_information(context);
@ -1863,7 +1869,7 @@ done_destroy_context:
else if (r == CONTINUE_ERROR)
return 1;
if (!i_am_stubby && verbosity)
if (verbosity)
fprintf(stdout, "\nAll done.\n");
return r ? r

File diff suppressed because it is too large Load Diff

View File

@ -242,6 +242,7 @@ typedef struct getdns_network_req
uint64_t debug_end_time;
getdns_auth_state_t debug_tls_auth_status;
getdns_bindata debug_tls_peer_cert;
const char *debug_tls_version;
size_t debug_udp;
/* When more space is needed for the wire_data response than is

View File

@ -880,6 +880,10 @@ _getdns_create_call_reporting_dict(
return NULL;
}
}
if (getdns_dict_set_int( netreq_debug, "server_keepalive_received", netreq->upstream->server_keepalive_received)) {
getdns_dict_destroy(netreq_debug);
return NULL;
}
/* The running totals are only updated when a connection is closed.
Since it is open as we have just used it, calcualte the value on the fly */
if (getdns_dict_set_int( netreq_debug, "responses_on_this_connection",
@ -916,6 +920,12 @@ _getdns_create_call_reporting_dict(
getdns_dict_destroy(netreq_debug);
return NULL;
}
if (getdns_dict_util_set_string(netreq_debug, "tls_version",
netreq->debug_tls_version)){
getdns_dict_destroy(netreq_debug);
return NULL;
}
if (getdns_dict_set_bindata(netreq_debug, "tls_peer_cert",
&netreq->debug_tls_peer_cert)) {

View File

@ -322,7 +322,7 @@ static int
setup_ecdsa_sig(unsigned char** sig, unsigned int* len)
{
/* convert from two BIGNUMs in the rdata buffer, to ASN notation.
* ASN preable: 30440220 <R 32bytefor256> 0220 <S 32bytefor256>
* ASN preamble: 30440220 <R 32bytefor256> 0220 <S 32bytefor256>
* the '20' is the length of that field (=bnsize).
i * the '44' is the total remaining length.
* if negative, start with leading zero.

2
stubby

@ -1 +1 @@
Subproject commit f0b330454b95a07106af33b1869b7cd18cfaebf2
Subproject commit 1a6acd642c7dc9a04cf092e1a3837c5636d4b465