diff --git a/.gitignore b/.gitignore index fce9d682..7bbbdebd 100644 --- a/.gitignore +++ b/.gitignore @@ -36,9 +36,10 @@ src/test/check_getdns src/test/check_getdns_event src/test/check_getdns_uv src/test/check_getdns_ev -src/test/getdns_query src/test/scratchpad src/test/scratchpad.c +src/tools/getdns_query +src/tools/stubby doc/*.3 src/getdns/getdns.h *.log diff --git a/.gitmodules b/.gitmodules index 06b16b93..a79d3846 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "src/test/jsmn"] - path = src/test/jsmn + path = src/jsmn url = https://github.com/getdnsapi/jsmn.git branch = getdns diff --git a/ChangeLog b/ChangeLog index e154f85e..16a6428f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +* 2017-01-13: Version 1.0.0 + * edns0_cookies extension enabled by default (per RFC7873) + * dnssec_roadblock_avoidance enabled by default (per RFC8027) + * bugfix: DSA support with OpenSSL 1.1.0 + * Initialize OpenSSL just once in a thread safe way + * Thread safety with arc4random function + * Improvements that came from Visual Studio static analysis + Thanks Christian Huitema + * Conventional RFC3986 IPv6 [address]:port parsing from getdns_query + * bugfix: OpenSSL 1.1.0 style crypto locking + Thanks volkommenheit + * configure tells *which* dependency is missing + * bugfix: Exclude terminating '\0' from bindata's returned by + getdns_get_suffix(). Thanks Jim Hague + * Better README.md. Thanks Andrew Sullivan + +* 2016-10-19: Version 1.1.0-a2 + * Improved TLS connection management + * OpenSSL 1.1 support + * Stubby, Server version of getdns_query that by default listens + on 127.0.0.1 and ::1 and reads config from /etc/stubby.conf + and $HOME/.stubby.conf + +* 2016-07-14: Version 1.1.0a1 + * Conversion functions from text strings to getdns native types: + getdns_str2dict(), getdns_str2list(), getdns_str2bindata() and + getdns_str2int() + * A getdns_context_config() function that configures a context + with settings given in a getdns_dict + * A a getdns_context_set_listen_addresses() function and companion + getdns_reply() function to construct simple name servers. + * Relocate getdns_query to src/tools and build by default + * Enhancements to the logic used to select connection based upstream + transports (TCP, TLS) to improve robustness and re-use of + connections/upstreams. + * 2016-07-14: Version 1.0.0b2 * Collect coverage information from the unit tests Thanks Shane Kerr diff --git a/Makefile.in b/Makefile.in index 3f727468..a98b0654 100644 --- a/Makefile.in +++ b/Makefile.in @@ -44,7 +44,7 @@ libdir = @libdir@ srcdir = @srcdir@ INSTALL = @INSTALL@ -all : default @GETDNS_QUERY@ +all : default @GETDNS_QUERY@ @STUBBY@ everything: default cd src/test && $(MAKE) @@ -52,7 +52,7 @@ everything: default default: cd src && $(MAKE) $@ -install: all getdns.pc getdns_ext_event.pc @INSTALL_GETDNS_QUERY@ +install: all getdns.pc getdns_ext_event.pc @INSTALL_GETDNS_QUERY@ @INSTALL_STUBBY@ $(INSTALL) -m 755 -d $(DESTDIR)$(docdir) $(INSTALL) -m 644 $(srcdir)/AUTHORS $(DESTDIR)$(docdir) $(INSTALL) -m 644 $(srcdir)/ChangeLog $(DESTDIR)$(docdir) @@ -87,7 +87,7 @@ install: all getdns.pc getdns_ext_event.pc @INSTALL_GETDNS_QUERY@ @echo "*** at package installation time from the post-install script." @echo "***" -uninstall: @UNINSTALL_GETDNS_QUERY@ +uninstall: @UNINSTALL_GETDNS_QUERY@ @UNINSTALL_STUBBY@ rm -rf $(DESTDIR)$(docdir) cd doc && $(MAKE) $@ cd src && $(MAKE) $@ @@ -104,6 +104,9 @@ test: getdns_query: cd src && $(MAKE) $@ +stubby: + cd src && $(MAKE) $@ + scratchpad: cd src && $(MAKE) $@ @@ -111,10 +114,16 @@ pad: scratchpad src/test/scratchpad || ./libtool exec gdb src/test/scratchpad install-getdns_query: - cd src/test && $(MAKE) install + cd src/tools && $(MAKE) $@ uninstall-getdns_query: - cd src/test && $(MAKE) uninstall + cd src/tools && $(MAKE) $@ + +install-stubby: + cd src/tools && $(MAKE) $@ + +uninstall-stubby: + cd src/tools && $(MAKE) $@ clean: cd src && $(MAKE) $@ @@ -141,18 +150,22 @@ distclean: rm -f m4/ltoptions.m4 rm -f m4/ltsugar.m4 rm -f m4/ltversion.m4 - rm -f $(distdir).tar.gz $(distdir).tar.gz.sha1 + rm -f $(distdir).tar.gz $(distdir).tar.gz.sha256 rm -f $(distdir).tar.gz.md5 $(distdir).tar.gz.asc megaclean: - cd $(srcdir) && rm -fr * .dir-locals.el .gitignore .indent.pro .travis.yml && git reset --hard + cd $(srcdir) && rm -fr * .dir-locals.el .gitignore .indent.pro .travis.yml && git reset --hard && git submodule update --init + +autoclean: megaclean + libtoolize -ci + autoreconf -fi dist: $(distdir).tar.gz -pub: $(distdir).tar.gz.sha1 $(distdir).tar.gz.md5 $(distdir).tar.gz.asc +pub: $(distdir).tar.gz.sha256 $(distdir).tar.gz.md5 $(distdir).tar.gz.asc -$(distdir).tar.gz.sha1: $(distdir).tar.gz - openssl sha1 $(distdir).tar.gz >$@ +$(distdir).tar.gz.sha256: $(distdir).tar.gz + openssl sha256 $(distdir).tar.gz >$@ $(distdir).tar.gz.md5: $(distdir).tar.gz openssl md5 $(distdir).tar.gz >$@ @@ -183,6 +196,8 @@ $(distdir): mkdir -p $(distdir)/src/compat mkdir -p $(distdir)/src/util mkdir -p $(distdir)/src/gldns + mkdir -p $(distdir)/src/tools + mkdir -p $(distdir)/src/jsmn mkdir -p $(distdir)/doc mkdir -p $(distdir)/spec mkdir -p $(distdir)/spec/example @@ -225,9 +240,11 @@ $(distdir): cp $(srcdir)/spec/*.tgz $(distdir)/spec || true cp $(srcdir)/spec/example/Makefile.in $(distdir)/spec/example cp $(srcdir)/spec/example/*.[ch] $(distdir)/spec/example - cp $(srcdir)/src/test/jsmn/*.[ch] $(distdir)/src/test/jsmn - cp $(srcdir)/src/test/jsmn/LICENSE $(distdir)/src/test/jsmn - cp $(srcdir)/src/test/jsmn/README.md $(distdir)/src/test/jsmn + cp $(srcdir)/src/tools/Makefile.in $(distdir)/src/tools + cp $(srcdir)/src/tools/*.[ch] $(distdir)/src/tools + 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 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 diff --git a/README.md b/README.md index 1b5a4807..4f802fca 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ Traditional access to DNS data from applications has several limitations: * Sophisticated uses of the DNS (things like IDNA and DNSSEC validation) require considerable application work, possibly by application developers with little experience with the vagaries of DNS. +getdns also provides a experimental DNS Privacy enabled client called 'stubby' - see below for more details. + ## Motivation for providing the API The developers are of the opinion that DNSSEC offers a unique global infrastructure for establishing and enhancing cryptographic trust relations. With the development of this API we intend to offer application developers a modern and flexible interface that enables end-to-end trust in the DNS architecture, and which will inspire application developers to implement innovative security solutions in their applications. @@ -73,9 +75,13 @@ If you want to make use of the configuration files that utilise a JSON-like form before building. -If you want to use the getdns_query command line wrapper script for testing or to enable getdns as a daemon then you must build it using +As well as building the getdns library 2 other tools are installed by default by the above process: + +* getdns_query: a command line test script wrapper for getdns +* stubby: a experimental DNS Privacy enabled client + +Note: If you only want to build stubby, then use the `--enable-stub-only` and `--without-libidn` options when running 'configure'. - # make getdns_query ## Minimizing dependencies @@ -83,7 +89,7 @@ If you want to use the getdns_query command line wrapper script for testing or t * 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. -## Extensions / Event loop dependencies +## Extensions and Event loop dependencies The implementation works with a variety of event loops, each built as a separate shared library. See [the wiki](https://github.com/getdnsapi/getdns/wiki/Asynchronous-Support#wiki-included-event-loop-integrations) for more details. @@ -91,6 +97,18 @@ The implementation works with a variety of event loops, each built as a separate * [libuv](https://github.com/joyent/libuv) * [libev](http://software.schmorp.de/pkg/libev.html) +## Stubby + +* Stubby is an experimental implementation of a DNS Privacy enabled stub resolver. It is currently suitable for advanced/technical users - all feedback is welcome! Also see [dnsprivacy.org](https://dnsprivacy.org) for more information on DNS Privacy and stubby. +* By default stubby will attempt to use 'Opportunistic' Privacy for DNS queries. +* A sample configuration file is available in the source code (src/tools/stubby.conf) which uses 'Strict' Privacy and some of the available test DNS Privacy servers to resolve queries. Note these servers are test servers that offer no service guarantees. The location of a configuration file can be specified with the '-C' flag +* RECOMMENDED: Minimal logging output from Stubby is available (e.g. which servers are used and connection level statistics) by also using the '--enable-debug-daemon' flag when running 'configure'. + +To use stubby +* Start stubby from the command line +* Test it by doing, for example, 'dig @127.0.0.1 www.example.com' +* Alter the default DNS resolvers on your system to point at localhost (127.0.0.1, ::1) + ## Regression Tests A suite of regression tests are included with the library, if you make changes or just @@ -124,7 +142,7 @@ We have a [getdns users list](https://getdnsapi.net/mailman/listinfo/users) for The [getdns-api mailing list](https://getdnsapi.net/mailman/listinfo/spec) is a good place to engage in discussions regarding the design of the API. -# Tickets/Bug Reports +# Tickets and Bug Reports Tickets and bug reports should be reported via the [GitHub issues list](https://github.com/getdnsapi/getdns/issues). @@ -179,7 +197,18 @@ Stub mode does not support: # Known Issues -* None +* The synchronous lookup functions will not work when new file descriptors + needed for the lookup will be larger than `FD_SETSIZE`. This is because + the synchronous functions use a "default" event loop under the hood + which is based on `select()` and thus inherits the limits that `select()` has. + + If you need only slightly more file descriptors, it is possible to enlarge + the `FD_SETSIZE` with the `--with-fd-setsize=`*`size`* flag to `configure`. + + To resolve, use the asynchronous functions with an event loop extension for + libevent, libev or libuv. Note that the asynchronous functions will have + the same problem when used in combination with `getdns_context_run()`, which + also uses the default event loop. # Supported Platforms @@ -203,7 +232,7 @@ If you're using [FreeBSD](https://www.freebsd.org/), you may install getdns via If you are using FreeBSD 10 getdns can be intalled via 'pkg install getdns'. -### CentOS/RHEL 6.5 +### CentOS and RHEL 6.5 We rely on the most excellent package manager fpm to build the linux packages, which means that the packaging platform requires ruby 2.1.0. There are other ways to @@ -261,7 +290,7 @@ The build has been tested using the following: 32 bit only Mingw: [Mingw(3.21.0) and Msys 1.0](http://www.mingw.org/) on Windows 8.1 32 bit build on a 64 bit Mingw [Download latest from: http://mingw-w64.org/doku.php/download/mingw-builds and http://msys2.github.io/]. IMPORTANT: Install tested ONLY on the "x86_64" for 64-bit installer of msys2. -#### Dependencies: +#### Dependencies The following dependencies are * openssl-1.0.2j * libidn diff --git a/configure.ac b/configure.ac index f68aaf36..f3b35c98 100644 --- a/configure.ac +++ b/configure.ac @@ -36,8 +36,8 @@ sinclude(./m4/acx_getaddrinfo.m4) sinclude(./m4/ax_check_compile_flag.m4) sinclude(./m4/pkg.m4) -AC_INIT([getdns], [1.0.0], [users@getdnsapi.net], [], [https://getdnsapi.net]) -AC_SUBST(RELEASE_CANDIDATE, [b2]) +AC_INIT([getdns], [1.1.0], [users@getdnsapi.net], [], [https://getdnsapi.net]) +AC_SUBST(RELEASE_CANDIDATE, [-alpha3]) # Set current date from system if not set AC_ARG_WITH([current-date], @@ -47,7 +47,7 @@ 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, [0x00100200]) +AC_SUBST(GETDNS_NUMERIC_VERSION, [0x0100A300]) 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" @@ -78,8 +78,9 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRE # getdns-0.5.1 had libversion 4:1:3 (but should have been getdns-0.6.0) # getdns-0.9.0 had libversion 5:0:4 # getdns-1.0.0 will have libversion 5:1:4 +# getdns-1.1.0 will have libversion 6:0:0 # -GETDNS_LIBVERSION=5:1:4 +GETDNS_LIBVERSION=6:0:0 AC_SUBST(GETDNS_COMPILATION_COMMENT) AC_SUBST(GETDNS_LIBVERSION) @@ -150,6 +151,7 @@ ACX_ARG_RPATH AC_ARG_ENABLE(debug-sched, AC_HELP_STRING([--enable-debug-sched], [Enable scheduling debugging messages])) AC_ARG_ENABLE(debug-stub, AC_HELP_STRING([--enable-debug-stub], [Enable stub debugging messages])) +AC_ARG_ENABLE(debug-daemon, AC_HELP_STRING([--enable-debug-daemon], [Enable daemon debugging messages])) AC_ARG_ENABLE(debug-sec, AC_HELP_STRING([--enable-debug-sec], [Enable dnssec debugging messages])) AC_ARG_ENABLE(debug-server, AC_HELP_STRING([--enable-debug-server], [Enable server debugging messages])) AC_ARG_ENABLE(all-debugging, AC_HELP_STRING([--enable-all-debugging], [Enable scheduling, stub and dnssec debugging])) @@ -157,6 +159,7 @@ case "$enable_all_debugging" in yes) enable_debug_sched=yes enable_debug_stub=yes + enable_debug_daemon=yes enable_debug_sec=yes enable_debug_server=yes ;; @@ -177,6 +180,13 @@ case "$enable_debug_stub" in no|*) ;; esac +case "$enable_debug_daemon" in + yes) + AC_DEFINE_UNQUOTED([DAEMON_DEBUG], [1], [Define this to enable printing of daemon debugging messages.]) + ;; + no|*) + ;; +esac case "$enable_debug_sec" in yes) AC_DEFINE_UNQUOTED([SEC_DEBUG], [1], [Define this to enable printing of dnssec debugging messages.]) @@ -253,7 +263,7 @@ 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]) +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]) AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H @@ -440,39 +450,38 @@ case "$enable_dsa" in ;; *) dnl default # detect if DSA is supported, and turn it off if not. - AC_CHECK_FUNC(EVP_dss1, [ + AC_CHECK_FUNC(DSA_SIG_new, [ AC_DEFINE_UNQUOTED([USE_DSA], [1], [Define this to enable DSA support.]) ], [if test "x$enable_dsa" = "xyes"; then AC_MSG_ERROR([OpenSSL does not support DSA and you used --enable-dsa.]) fi ]) ;; esac -AC_ARG_ENABLE(draft-dnssec-roadblock-avoidance, AC_HELP_STRING([--enable-draft-dnssec-roadblock-avoidance], [Enable experimental dnssec roadblock avoidance])) -AC_ARG_ENABLE(draft-edns-cookies, AC_HELP_STRING([--enable-draft-edns-cookies], [Enable experimental edns cookies])) -AC_ARG_ENABLE(all-drafts, AC_HELP_STRING([--enable-all-drafts], [Enable cookies and roadblock avoidance])) +AC_ARG_ENABLE(all-drafts, AC_HELP_STRING([--enable-all-drafts], [No drafts in this release])) case "$enable_all_drafts" in yes) - enable_draft_dnssec_roadblock_avoidance=yes - enable_draft_edns_cookies=yes ;; no|*) ;; esac -case "$enable_draft_dnssec_roadblock_avoidance" in - yes) - AC_DEFINE_UNQUOTED([DNSSEC_ROADBLOCK_AVOIDANCE], [1], [Define this to enable the experimental draft dnssec roadblock avoidance.]) +AC_ARG_ENABLE(dnssec-roadblock-avoidance, AC_HELP_STRING([--disable-dnssec-roadblock-avoidance], [Disable dnssec roadblock avoidance])) +case "$enable_dnssec_roadblock_avoidance" in + no) ;; - no|*) + yes|*) + AC_DEFINE_UNQUOTED([DNSSEC_ROADBLOCK_AVOIDANCE], [1], [Define this to enable the experimental dnssec roadblock avoidance.]) ;; esac -case "$enable_draft_edns_cookies" in - yes) + +AC_ARG_ENABLE(edns-cookies, AC_HELP_STRING([--disable-edns-cookies], [Disable edns cookies])) +case "$enable_edns_cookies" in + no) + ;; + yes|*) if test "x_$HAVE_SSL" != "x_yes"; then - AC_MSG_ERROR([edns cookies need openssl libcrypto which is not available, please rerun without --enable-draft-edns-cookies]) + AC_MSG_ERROR([edns cookies need openssl libcrypto which is not available, please rerun with --disable-edns-cookies]) fi - AC_DEFINE_UNQUOTED([EDNS_COOKIES], [1], [Define this to enable the experimental draft edns cookies.]) - ;; - no|*) + AC_DEFINE_UNQUOTED([EDNS_COOKIES], [1], [Define this to enable the experimental edns cookies.]) ;; esac AC_DEFINE_UNQUOTED([EDNS_COOKIE_OPCODE], [10], [The edns cookie option code.]) @@ -908,9 +917,9 @@ AC_DEFINE_UNQUOTED([TRUST_ANCHOR_FILE], ["$TRUST_ANCHOR_FILE"], [Default trust a AC_SUBST(TRUST_ANCHOR_FILE) AC_MSG_NOTICE([Default trust anchor: $TRUST_ANCHOR_FILE]) -AC_ARG_WITH(getdns_query, AS_HELP_STRING([--with-getdns_query], - [Also compile and install the getdns_query tool]), - [], [withval="no"]) +AC_ARG_WITH(getdns_query, AS_HELP_STRING([--without-getdns_query], + [Do not compile and install the getdns_query tool]), + [], [withval="yes"]) if test x_$withval = x_no; then GETDNS_QUERY="" INSTALL_GETDNS_QUERY="" @@ -920,6 +929,26 @@ else INSTALL_GETDNS_QUERY="install-getdns_query" UNINSTALL_GETDNS_QUERY="uninstall-getdns_query" fi +AC_SUBST(GETDNS_QUERY) +AC_SUBST(INSTALL_GETDNS_QUERY) +AC_SUBST(UNINSTALL_GETDNS_QUERY) + +AC_ARG_WITH(stubby, AS_HELP_STRING([--without-stubby], + [Do not compile and install stubby, the (stub) resolver daemon]), + [], [withval="yes"]) +if test x_$withval = x_no; then + STUBBY="" + INSTALL_STUBBY="" + UNINSTALL_STUBBY="" +else + STUBBY="stubby" + INSTALL_STUBBY="install-stubby" + UNINSTALL_STUBBY="uninstall-stubby" +fi +AC_SUBST(STUBBY) +AC_SUBST(INSTALL_STUBBY) +AC_SUBST(UNINSTALL_STUBBY) + AC_ARG_WITH(fd-setsize, AS_HELP_STRING([--with-fd-setsize=size], [Set maximum file descriptor number that can be used by select]), [], [withval="no"]) @@ -932,11 +961,7 @@ case "$withval" in ;; esac -AC_SUBST(GETDNS_QUERY) -AC_SUBST(INSTALL_GETDNS_QUERY) -AC_SUBST(UNINSTALL_GETDNS_QUERY) - -AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile doc/Makefile getdns.pc getdns_ext_event.pc]) +AC_CONFIG_FILES([Makefile src/Makefile src/version.c src/getdns/getdns.h src/getdns/getdns_extra.h spec/example/Makefile src/test/Makefile src/tools/Makefile doc/Makefile getdns.pc getdns_ext_event.pc]) if [ test -n "$DOXYGEN" ] then AC_CONFIG_FILES([src/Doxyfile]) fi @@ -945,6 +970,14 @@ fi #---- check for pthreads library AC_SEARCH_LIBS([pthread_mutex_init],[pthread],[AC_DEFINE([HAVE_PTHREADS], [1], [Have pthreads library])], [AC_MSG_WARN([pthreads not available])]) +AC_MSG_CHECKING([whether the C compiler (${CC-cc}) supports the __func__ variable]) +AC_LANG_PUSH(C) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[char*s=__func__;]],[[]])], + [AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE___FUNC__, [1], [Whether the C compiler support the __func__ variable])], + [AC_MSG_RESULT([no])]) +AC_LANG_POP(C) dnl ----- dnl ----- Start of "Things needed for gldns" section @@ -1061,6 +1094,12 @@ AC_DEFINE_UNQUOTED([MAX_CNAME_REFERRALS], [100], [The maximum number of cname re AH_BOTTOM([ +#ifdef HAVE___FUNC__ +#define __FUNC__ __func__ +#else +#define __FUNC__ __FUNCTION__ +#endif + #ifdef GETDNS_ON_WINDOWS /* On windows it is allowed to increase the FD_SETSIZE * (and nescessary to make our custom eventloop work) diff --git a/src/Makefile.in b/src/Makefile.in index f095d6a6..bcd858e2 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -67,7 +67,7 @@ C99COMPATFLAGS=@C99COMPATFLAGS@ GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \ list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \ - rr-iter.lo stub.lo sync.lo ub_loop.lo util-internal.lo \ + rr-iter.lo server.lo stub.lo sync.lo ub_loop.lo util-internal.lo \ mdns.lo GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \ @@ -79,6 +79,8 @@ COMPAT_OBJ=$(LIBOBJS:.o=.lo) UTIL_OBJ=rbtree.lo val_secalgo.lo +JSMN_OBJ=jsmn.lo + EXTENSION_OBJ=default_eventloop.lo libevent.lo libev.lo NON_C99_OBJS=context.lo libuv.lo @@ -107,6 +109,9 @@ $(COMPAT_OBJ): $(UTIL_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WNOERRORFLAG) -c $(srcdir)/util/$(@:.lo=.c) -o $@ +$(JSMN_OBJ): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -DJSMN_GETDNS -c $(srcdir)/jsmn/$(@:.lo=.c) -o $@ + $(EXTENSION_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -c $(srcdir)/extension/$(@:.lo=.c) -o $@ @@ -147,15 +152,17 @@ libgetdns_ext_ev.la: libgetdns.la libev.lo $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ libev.lo libgetdns.la $(LDFLAGS) $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/extension/libev.symbols -libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) - $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols - +libgetdns.la: $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) + $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ $(GETDNS_OBJ) version.lo context.lo default_eventloop.lo $(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) $(JSMN_OBJ) $(LDFLAGS) -rpath $(libdir) -version-info $(libversion) -no-undefined -export-symbols $(srcdir)/libgetdns.symbols test: all cd test && $(MAKE) $@ getdns_query: all - cd test && $(MAKE) $@ + cd tools && $(MAKE) $@ + +stubby: all + cd tools && $(MAKE) $@ scratchpad: all cd test && $(MAKE) $@ @@ -163,11 +170,13 @@ scratchpad: all pad: scratchpad clean: + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ rm -f *.o *.lo extension/*.lo extension/*.o $(PROGRAMS) libgetdns.la libgetdns_ext_*.la rm -rf .libs extension/.libs distclean : clean + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ rmdir test 2>/dev/null || true rm -f Makefile config.status config.log Doxyfile config.h version.c getdns/Makefile getdns/getdns.h getdns/getdns_extra.h @@ -175,42 +184,17 @@ distclean : clean rmdir extension 2>/dev/null || true rm -Rf autom4te.cache -$(distdir): FORCE - mkdir -p $(distdir)/src - cp configure.ac $(distdir) - cp configure $(distdir) - cp Makefile.in $(distdir) - cp src/Makefile.in $(distdir)/src - -distcheck: $(distdir).tar.gz - gzip -cd $(distdir).tar.gz | tar xvf - - cd $(distdir) && ./configure - cd $(distdir) && $(MAKE) all - cd $(distdir) && $(MAKE) check - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst install - cd $(distdir) && $(MAKE) DESTDIR=$${PWD}/_inst uninstall - @remaining="`find $${PWD}/$(distdir)/_inst -type f | wc -l`"; \ - if test "$${remaining}" -ne 0; then - echo "@@@ $${remaining} file(s) remaining in stage directory!"; \ - exit 1; \ - fi - cd $(distdir) && $(MAKE) clean - rm -rf $(distdir) - @echo "*** Package $(distdir).tar.gz is ready for distribution" - Makefile: $(srcdir)/Makefile.in ../config.status cd .. && ./config.status src/Makefile -configure.status: configure - cd .. && ./config.status --recheck - 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" *.c gldns/*.c compat/*.c util/*.c extension/*.c| \ + (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" *.c gldns/*.c compat/*.c util/*.c jsmn/*.c extension/*.c| \ sed -e "s? $$blddir/? ?g" \ -e 's?gldns/?$$(srcdir)/gldns/?g' \ -e 's?compat/?$$(srcdir)/compat/?g' \ -e 's?util/?$$(srcdir)/util/?g' \ + -e 's?jsmn/?$$(srcdir)/jsmn/?g' \ -e 's?extension/?$$(srcdir)/extension/?g' \ -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ -e 's? \$$(srcdir)/config\.h? config.h?g' \ @@ -222,6 +206,7 @@ depend: -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ || mv Makefile.in.new Makefile.in ) + cd tools && $(MAKE) $@ cd test && $(MAKE) $@ .PHONY: clean test @@ -234,76 +219,84 @@ context.lo context.o: $(srcdir)/context.c config.h $(srcdir)/debug.h $(srcdir)/g $(srcdir)/gldns/wire2str.h $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h \ + $(srcdir)/pubkey-pinning.h convert.lo convert.o: $(srcdir)/convert.c config.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/convert.h + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.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 $(srcdir)/convert.h dict.lo dict.o: $(srcdir)/dict.c config.h $(srcdir)/types-internal.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h \ $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h \ - $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h + $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h $(srcdir)/list.h $(srcdir)/const-info.h $(srcdir)/gldns/wire2str.h dnssec.lo dnssec.o: $(srcdir)/dnssec.c config.h $(srcdir)/debug.h getdns/getdns.h $(srcdir)/context.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ - $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \ - $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h $(srcdir)/list.h \ - $(srcdir)/util/val_secalgo.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ + $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/parseutil.h $(srcdir)/general.h $(srcdir)/dict.h \ + $(srcdir)/list.h $(srcdir)/util/val_secalgo.h general.lo general.o: $(srcdir)/general.c config.h $(srcdir)/general.h getdns/getdns.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/ub_loop.h $(srcdir)/debug.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/dict.h \ $(srcdir)/mdns.h list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/util-internal.h config.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/list.h $(srcdir)/dict.h + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h \ + $(srcdir)/list.h $(srcdir)/dict.h +mdns.lo mdns.o: $(srcdir)/mdns.c config.h $(srcdir)/debug.h $(srcdir)/context.h getdns/getdns.h \ + getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ + $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ + $(srcdir)/server.h $(srcdir)/general.h $(srcdir)/gldns/pkthdr.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + $(srcdir)/gldns/gbuffer.h $(srcdir)/mdns.h pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c config.h $(srcdir)/debug.h getdns/getdns.h \ $(srcdir)/context.h getdns/getdns.h getdns/getdns_extra.h $(srcdir)/types-internal.h \ $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ - $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h \ + $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h request-internal.lo request-internal.o: $(srcdir)/request-internal.c config.h $(srcdir)/types-internal.h \ getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h \ $(srcdir)/gldns/rrdef.h $(srcdir)/dict.h $(srcdir)/convert.h rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h config.h getdns/getdns.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/util-internal.h $(srcdir)/context.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/dict.h rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h config.h getdns/getdns.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h +server.lo server.o: $(srcdir)/server.c config.h getdns/getdns_extra.h getdns/getdns.h \ + $(srcdir)/context.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ + $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ + $(srcdir)/debug.h $(srcdir)/server.h stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/debug.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h -mdns.lo mdns.o: $(srcdir)/mdns.c config.h $(srcdir)/debug.h $(srcdir)/mdns.h getdns/getdns.h $(srcdir)/types-internal.h \ - getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h \ - $(srcdir)/gldns/wire2str.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/context.h \ - $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h + $(srcdir)/server.h $(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h sync.lo sync.o: $(srcdir)/sync.c getdns/getdns.h config.h $(srcdir)/context.h getdns/getdns_extra.h \ getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/extension/default_eventloop.h config.h getdns/getdns_extra.h $(srcdir)/ub_loop.h \ - $(srcdir)/debug.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/gldns/wire2str.h + $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h \ + $(srcdir)/gldns/wire2str.h ub_loop.lo ub_loop.o: $(srcdir)/ub_loop.c $(srcdir)/ub_loop.h config.h getdns/getdns.h \ getdns/getdns_extra.h getdns/getdns.h $(srcdir)/types-internal.h $(srcdir)/util/rbtree.h \ $(srcdir)/debug.h util-internal.lo util-internal.o: $(srcdir)/util-internal.c config.h getdns/getdns.h $(srcdir)/dict.h \ $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/list.h $(srcdir)/util-internal.h $(srcdir)/context.h $(srcdir)/extension/default_eventloop.h config.h \ - getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ + getdns/getdns_extra.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/gbuffer.h $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/dnssec.h \ $(srcdir)/gldns/rrdef.h version.lo version.o: version.c @@ -335,6 +328,7 @@ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcd $(srcdir)/util/fptr_wlist.h $(srcdir)/util/rbtree.h val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c config.h $(srcdir)/util/val_secalgo.h $(srcdir)/util/log.h \ $(srcdir)/debug.h config.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/gbuffer.h +jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h default_eventloop.lo default_eventloop.o: $(srcdir)/extension/default_eventloop.c config.h \ $(srcdir)/extension/default_eventloop.h getdns/getdns.h getdns/getdns_extra.h \ $(srcdir)/debug.h config.h $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h \ diff --git a/src/const-info.c b/src/const-info.c index 200100c2..a71f928a 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -123,3 +123,213 @@ getdns_get_errorstr_by_id(uint16_t err) else return NULL; } + +static struct const_name_info consts_name_info[] = { + { "GETDNS_APPEND_NAME_ALWAYS", 550 }, + { "GETDNS_APPEND_NAME_NEVER", 553 }, + { "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", 552 }, + { "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", 551 }, + { "GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST", 554 }, + { "GETDNS_AUTHENTICATION_NONE", 1300 }, + { "GETDNS_AUTHENTICATION_REQUIRED", 1301 }, + { "GETDNS_BAD_DNS_ALL_NUMERIC_LABEL", 1101 }, + { "GETDNS_BAD_DNS_CNAME_IN_TARGET", 1100 }, + { "GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", 1102 }, + { "GETDNS_CALLBACK_CANCEL", 701 }, + { "GETDNS_CALLBACK_COMPLETE", 700 }, + { "GETDNS_CALLBACK_ERROR", 703 }, + { "GETDNS_CALLBACK_TIMEOUT", 702 }, + { "GETDNS_CONTEXT_CODE_APPEND_NAME", 607 }, + { "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", 614 }, + { "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", 609 }, + { "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", 604 }, + { "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", 605 }, + { "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", 619 }, + { "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", 613 }, + { "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", 611 }, + { "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", 610 }, + { "GETDNS_CONTEXT_CODE_EDNS_VERSION", 612 }, + { "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", 602 }, + { "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", 617 }, + { "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", 606 }, + { "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", 615 }, + { "GETDNS_CONTEXT_CODE_NAMESPACES", 600 }, + { "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", 621 }, + { "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", 601 }, + { "GETDNS_CONTEXT_CODE_SUFFIX", 608 }, + { "GETDNS_CONTEXT_CODE_TIMEOUT", 616 }, + { "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618 }, + { "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 }, + { "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603 }, + { "GETDNS_DNSSEC_BOGUS", 401 }, + { "GETDNS_DNSSEC_INDETERMINATE", 402 }, + { "GETDNS_DNSSEC_INSECURE", 403 }, + { "GETDNS_DNSSEC_NOT_PERFORMED", 404 }, + { "GETDNS_DNSSEC_SECURE", 400 }, + { "GETDNS_EXTENSION_FALSE", 1001 }, + { "GETDNS_EXTENSION_TRUE", 1000 }, + { "GETDNS_NAMESPACE_DNS", 500 }, + { "GETDNS_NAMESPACE_LOCALNAMES", 501 }, + { "GETDNS_NAMESPACE_MDNS", 503 }, + { "GETDNS_NAMESPACE_NETBIOS", 502 }, + { "GETDNS_NAMESPACE_NIS", 504 }, + { "GETDNS_NAMETYPE_DNS", 800 }, + { "GETDNS_NAMETYPE_WINS", 801 }, + { "GETDNS_OPCODE_IQUERY", 1 }, + { "GETDNS_OPCODE_NOTIFY", 4 }, + { "GETDNS_OPCODE_QUERY", 0 }, + { "GETDNS_OPCODE_STATUS", 2 }, + { "GETDNS_OPCODE_UPDATE", 5 }, + { "GETDNS_RCODE_BADALG", 21 }, + { "GETDNS_RCODE_BADKEY", 17 }, + { "GETDNS_RCODE_BADMODE", 19 }, + { "GETDNS_RCODE_BADNAME", 20 }, + { "GETDNS_RCODE_BADSIG", 16 }, + { "GETDNS_RCODE_BADTIME", 18 }, + { "GETDNS_RCODE_BADTRUNC", 22 }, + { "GETDNS_RCODE_BADVERS", 16 }, + { "GETDNS_RCODE_COOKIE", 23 }, + { "GETDNS_RCODE_FORMERR", 1 }, + { "GETDNS_RCODE_NOERROR", 0 }, + { "GETDNS_RCODE_NOTAUTH", 9 }, + { "GETDNS_RCODE_NOTIMP", 4 }, + { "GETDNS_RCODE_NOTZONE", 10 }, + { "GETDNS_RCODE_NXDOMAIN", 3 }, + { "GETDNS_RCODE_NXRRSET", 8 }, + { "GETDNS_RCODE_REFUSED", 5 }, + { "GETDNS_RCODE_SERVFAIL", 2 }, + { "GETDNS_RCODE_YXDOMAIN", 6 }, + { "GETDNS_RCODE_YXRRSET", 7 }, + { "GETDNS_REDIRECTS_DO_NOT_FOLLOW", 531 }, + { "GETDNS_REDIRECTS_FOLLOW", 530 }, + { "GETDNS_RESOLUTION_RECURSING", 521 }, + { "GETDNS_RESOLUTION_STUB", 520 }, + { "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", 904 }, + { "GETDNS_RESPSTATUS_ALL_TIMEOUT", 902 }, + { "GETDNS_RESPSTATUS_GOOD", 900 }, + { "GETDNS_RESPSTATUS_NO_NAME", 901 }, + { "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", 903 }, + { "GETDNS_RETURN_BAD_CONTEXT", 301 }, + { "GETDNS_RETURN_BAD_DOMAIN_NAME", 300 }, + { "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", 302 }, + { "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", 309 }, + { "GETDNS_RETURN_EXTENSION_MISFORMAT", 308 }, + { "GETDNS_RETURN_GENERIC_ERROR", 1 }, + { "GETDNS_RETURN_GOOD", 0 }, + { "GETDNS_RETURN_INVALID_PARAMETER", 311 }, + { "GETDNS_RETURN_MEMORY_ERROR", 310 }, + { "GETDNS_RETURN_NEED_MORE_SPACE", 399 }, + { "GETDNS_RETURN_NOT_IMPLEMENTED", 312 }, + { "GETDNS_RETURN_NO_SUCH_DICT_NAME", 305 }, + { "GETDNS_RETURN_NO_SUCH_EXTENSION", 307 }, + { "GETDNS_RETURN_NO_SUCH_LIST_ITEM", 304 }, + { "GETDNS_RETURN_UNKNOWN_TRANSACTION", 303 }, + { "GETDNS_RETURN_WRONG_TYPE_REQUESTED", 306 }, + { "GETDNS_RRCLASS_ANY", 255 }, + { "GETDNS_RRCLASS_CH", 3 }, + { "GETDNS_RRCLASS_HS", 4 }, + { "GETDNS_RRCLASS_IN", 1 }, + { "GETDNS_RRCLASS_NONE", 254 }, + { "GETDNS_RRTYPE_A", 1 }, + { "GETDNS_RRTYPE_AAAA", 28 }, + { "GETDNS_RRTYPE_AFSDB", 18 }, + { "GETDNS_RRTYPE_ANY", 255 }, + { "GETDNS_RRTYPE_APL", 42 }, + { "GETDNS_RRTYPE_ATMA", 34 }, + { "GETDNS_RRTYPE_AXFR", 252 }, + { "GETDNS_RRTYPE_CAA", 257 }, + { "GETDNS_RRTYPE_CDNSKEY", 60 }, + { "GETDNS_RRTYPE_CDS", 59 }, + { "GETDNS_RRTYPE_CERT", 37 }, + { "GETDNS_RRTYPE_CNAME", 5 }, + { "GETDNS_RRTYPE_CSYNC", 62 }, + { "GETDNS_RRTYPE_DHCID", 49 }, + { "GETDNS_RRTYPE_DLV", 32769 }, + { "GETDNS_RRTYPE_DNAME", 39 }, + { "GETDNS_RRTYPE_DNSKEY", 48 }, + { "GETDNS_RRTYPE_DS", 43 }, + { "GETDNS_RRTYPE_EID", 31 }, + { "GETDNS_RRTYPE_GID", 102 }, + { "GETDNS_RRTYPE_GPOS", 27 }, + { "GETDNS_RRTYPE_HINFO", 13 }, + { "GETDNS_RRTYPE_HIP", 55 }, + { "GETDNS_RRTYPE_IPSECKEY", 45 }, + { "GETDNS_RRTYPE_ISDN", 20 }, + { "GETDNS_RRTYPE_IXFR", 251 }, + { "GETDNS_RRTYPE_KEY", 25 }, + { "GETDNS_RRTYPE_KX", 36 }, + { "GETDNS_RRTYPE_LOC", 29 }, + { "GETDNS_RRTYPE_LP", 107 }, + { "GETDNS_RRTYPE_MAILA", 254 }, + { "GETDNS_RRTYPE_MAILB", 253 }, + { "GETDNS_RRTYPE_MB", 7 }, + { "GETDNS_RRTYPE_MD", 3 }, + { "GETDNS_RRTYPE_MF", 4 }, + { "GETDNS_RRTYPE_MG", 8 }, + { "GETDNS_RRTYPE_MINFO", 14 }, + { "GETDNS_RRTYPE_MR", 9 }, + { "GETDNS_RRTYPE_MX", 15 }, + { "GETDNS_RRTYPE_NAPTR", 35 }, + { "GETDNS_RRTYPE_NID", 104 }, + { "GETDNS_RRTYPE_NIMLOC", 32 }, + { "GETDNS_RRTYPE_NINFO", 56 }, + { "GETDNS_RRTYPE_NS", 2 }, + { "GETDNS_RRTYPE_NSAP", 22 }, + { "GETDNS_RRTYPE_NSEC", 47 }, + { "GETDNS_RRTYPE_NULL", 10 }, + { "GETDNS_RRTYPE_NXT", 30 }, + { "GETDNS_RRTYPE_OPENPGPKEY", 61 }, + { "GETDNS_RRTYPE_OPT", 41 }, + { "GETDNS_RRTYPE_PTR", 12 }, + { "GETDNS_RRTYPE_PX", 26 }, + { "GETDNS_RRTYPE_RKEY", 57 }, + { "GETDNS_RRTYPE_RP", 17 }, + { "GETDNS_RRTYPE_RRSIG", 46 }, + { "GETDNS_RRTYPE_RT", 21 }, + { "GETDNS_RRTYPE_SIG", 24 }, + { "GETDNS_RRTYPE_SINK", 40 }, + { "GETDNS_RRTYPE_SOA", 6 }, + { "GETDNS_RRTYPE_SPF", 99 }, + { "GETDNS_RRTYPE_SRV", 33 }, + { "GETDNS_RRTYPE_SSHFP", 44 }, + { "GETDNS_RRTYPE_TA", 32768 }, + { "GETDNS_RRTYPE_TALINK", 58 }, + { "GETDNS_RRTYPE_TKEY", 249 }, + { "GETDNS_RRTYPE_TLSA", 52 }, + { "GETDNS_RRTYPE_TSIG", 250 }, + { "GETDNS_RRTYPE_TXT", 16 }, + { "GETDNS_RRTYPE_UID", 101 }, + { "GETDNS_RRTYPE_UINFO", 100 }, + { "GETDNS_RRTYPE_UNSPEC", 103 }, + { "GETDNS_RRTYPE_URI", 256 }, + { "GETDNS_RRTYPE_WKS", 11 }, + { "GETDNS_TRANSPORT_TCP", 1201 }, + { "GETDNS_TRANSPORT_TCP_ONLY", 542 }, + { "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", 543 }, + { "GETDNS_TRANSPORT_TLS", 1202 }, + { "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", 545 }, + { "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", 544 }, + { "GETDNS_TRANSPORT_UDP", 1200 }, + { "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", 540 }, + { "GETDNS_TRANSPORT_UDP_ONLY", 541 }, +}; + +static int const_name_info_cmp(const void *a, const void *b) +{ + return strcmp( ((struct const_name_info *) a)->name + , ((struct const_name_info *) b)->name ); +} + +int +_getdns_get_const_name_info(const char *name, uint32_t *code) +{ + struct const_name_info key = { name, 0 }; + struct const_name_info *i = bsearch(&key, consts_name_info, + sizeof(consts_name_info) / sizeof(struct const_name_info), + sizeof(struct const_name_info), const_name_info_cmp); + if (!i) + return 0; + if (code) + *code = i->code; + return 1; +} diff --git a/src/const-info.h b/src/const-info.h index 39d7c98e..379e2512 100644 --- a/src/const-info.h +++ b/src/const-info.h @@ -47,6 +47,13 @@ struct const_info { struct const_info *_getdns_get_const_info(int value); +struct const_name_info { + const char *name; + uint32_t code; +}; + +int _getdns_get_const_name_info(const char *name, uint32_t *code); + #endif /* const-info.h */ diff --git a/src/context.c b/src/context.c index 34432780..c4f5d0f7 100644 --- a/src/context.c +++ b/src/context.c @@ -62,6 +62,11 @@ typedef unsigned short in_port_t; #include #include +#ifdef HAVE_PTHREADS +#include +#endif +#include + #include "config.h" #ifdef HAVE_LIBUNBOUND #include @@ -84,6 +89,14 @@ typedef unsigned short in_port_t; #define GETDNS_STR_PORT_ZERO "0" #define GETDNS_STR_PORT_DNS "53" #define GETDNS_STR_PORT_DNS_OVER_TLS "853" +/* How long to wait in seconds before re-trying a connection based backed-off + upstream. Using 1 hour for all transports - based on RFC7858 value for for TLS.*/ +#define BACKOFF_RETRY 3600 + +#ifdef HAVE_PTHREADS +static pthread_mutex_t ssl_init_lock = PTHREAD_MUTEX_INITIALIZER; +#endif +static bool ssl_init=false; void *plain_mem_funcs_user_arg = MF_PLAIN; @@ -152,7 +165,7 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) HCERTSTORE hSystemStore; PCCERT_CONTEXT pTargetCert = NULL; - DEBUG_STUB("%s %-35s: %s\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, + DEBUG_STUB("%s %-35s: %s\n", STUB_DEBUG_SETUP_TLS, __FUNC__, "Adding Windows certificates to CA store"); /* load just once per context lifetime for this version of getdns @@ -181,7 +194,7 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) /* failure if the CA store is empty or the call fails */ if ((pTargetCert = CertEnumCertificatesInStore( hSystemStore, pTargetCert)) == 0) { - DEBUG_STUB("%s %-35s: %s\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, + DEBUG_STUB("%s %-35s: %s\n", STUB_DEBUG_SETUP_TLS, __FUNC__, "CA certificate store for Windows is empty."); return 0; } @@ -193,7 +206,7 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) pTargetCert->cbCertEncoded); if (!cert1) { /* return error if a cert fails */ - DEBUG_STUB("%s %-35s: %s %d:%s\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, + DEBUG_STUB("%s %-35s: %s %d:%s\n", STUB_DEBUG_SETUP_TLS, __FUNC__, "Unable to parse certificate in memory", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL)); return 0; @@ -201,7 +214,7 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) else { /* return error if a cert add to store fails */ if (X509_STORE_add_cert(store, cert1) == 0) { - DEBUG_STUB("%s %-35s: %s %d:%s\n", STUB_DEBUG_SETUP_TLS, __FUNCTION__, + DEBUG_STUB("%s %-35s: %s %d:%s\n", STUB_DEBUG_SETUP_TLS, __FUNC__, "Error adding certificate", ERR_get_error(), ERR_error_string(ERR_get_error(), NULL)); return 0; @@ -224,6 +237,25 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx) } #endif +#if !defined(STUB_NATIVE_DNSSEC) || (defined(DAEMON_DEBUG) && DAEMON_DEBUG) +static uint8_t* +upstream_addr(getdns_upstream *upstream) +{ + return upstream->addr.ss_family == AF_INET + ? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr + : (void *)&((struct sockaddr_in6*)&upstream->addr)->sin6_addr; +} +#endif + + +static in_port_t +upstream_port(getdns_upstream *upstream) +{ + return ntohs(upstream->addr.ss_family == AF_INET + ? ((struct sockaddr_in *)&upstream->addr)->sin_port + : ((struct sockaddr_in6*)&upstream->addr)->sin6_port); +} + static void destroy_local_host(_getdns_rbnode_t * node, void *arg) { getdns_context *context = (getdns_context *)arg; @@ -264,7 +296,6 @@ create_default_dns_transports(struct getdns_context *context) context->dns_transports[0] = GETDNS_TRANSPORT_UDP; context->dns_transports[1] = GETDNS_TRANSPORT_TCP; context->dns_transport_count = 2; - context->dns_transport_current = 0; return GETDNS_RETURN_GOOD; } @@ -616,7 +647,7 @@ upstreams_create(getdns_context *context, size_t size) r->mf = context->mf; r->referenced = 1; r->count = 0; - r->current = 0; + r->current_udp = 0; return r; } @@ -678,48 +709,89 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) GETDNS_FREE(upstreams->mf, upstreams); } -#if defined(DAEMON_DEBUG) && DAEMON_DEBUG -static char* -getdns_auth_str_array[] = { - GETDNS_STR_AUTH_NONE, - GETDNS_STR_AUTH_FAILED, - GETDNS_STR_AUTH_OK -}; -#endif - void _getdns_upstream_shutdown(getdns_upstream *upstream) { - /*There is a race condition with a new request being scheduled - while this happens so take ownership of the fd asap*/ - int fd = upstream->fd; - upstream->fd = -1; - /* If the connection had a problem, but had worked this time, - * then allow re-use in the future*/ - if (upstream->tcp.write_error == 1 && - upstream->responses_received > 0) - upstream->tcp.write_error = 0; - upstream->writes_done = 0; - upstream->responses_received = 0; - upstream->keepalive_timeout = 0; - if (upstream->tls_hs_state != GETDNS_HS_FAILED) { - upstream->tls_hs_state = GETDNS_HS_NONE; - upstream->tls_auth_failed = 0; + /*Set condition to tear down asap to stop any further scheduling*/ + upstream->conn_state = GETDNS_CONN_TEARDOWN; + /* Update total stats for the upstream.*/ + upstream->total_responses+=upstream->responses_received; + upstream->total_timeouts+=upstream->responses_timeouts; + /* Need the last auth state when using session resumption*/ + upstream->last_tls_auth_state = upstream->tls_auth_state; + /* Keep track of the best auth state this upstream has had*/ + if (upstream->tls_auth_state > upstream->best_tls_auth_state) + upstream->best_tls_auth_state = upstream->tls_auth_state; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : Conn closed : Transport=%s - Resp=%d,Timeouts=%d,Auth=%s,Keepalive(ms)=%d\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), + (int)upstream->responses_received, (int)upstream->responses_timeouts, + _getdns_auth_str(upstream->tls_auth_state), (int)upstream->keepalive_timeout); + DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Resp=%d,Timeouts=%d,Best_auth=%s\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), + (int)upstream->total_responses, (int)upstream->total_timeouts, + _getdns_auth_str(upstream->best_tls_auth_state)); + DEBUG_DAEMON("%s %s : Upstream stats: Transport=%s - Conns=%d,Conn_fails=%d,Conn_shutdowns=%d,Backoffs=%d\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"), + (int)upstream->conn_completed, (int)upstream->conn_setup_failed, + (int)upstream->conn_shutdowns, (int)upstream->conn_backoffs); +#endif + + /* Back off connections that never got up service at all (probably no + TCP service or incompatible TLS version/cipher). + Leave choice between working upstreams to the stub. + This back-off should be time based for TLS according to RFC7858. For now, + use the same basis if we simply can't get TCP service either.*/ + + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + if (upstream->conn_setup_failed >= GETDNS_CONN_ATTEMPTS || + (upstream->conn_shutdowns >= GETDNS_CONN_ATTEMPTS*GETDNS_TRANSPORT_FAIL_MULT + && upstream->total_responses == 0) || + (upstream->conn_completed >= GETDNS_CONN_ATTEMPTS && + upstream->total_responses == 0 && + upstream->total_timeouts > GETDNS_TRANSPORT_FAIL_MULT)) { + upstream->conn_state = GETDNS_CONN_BACKOFF; + upstream->conn_retry_time = time(NULL) + BACKOFF_RETRY; + upstream->total_responses = 0; + upstream->total_timeouts = 0; + upstream->conn_completed = 0; + upstream->conn_setup_failed = 0; + upstream->conn_shutdowns = 0; + upstream->conn_backoffs++; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : !Backing off this upstream - Will retry as new upstream at %s", + STUB_DEBUG_DAEMON, upstream->addr_str, + asctime(gmtime(&upstream->conn_retry_time))); +#endif } + // Reset per connection counters + upstream->queries_sent = 0; + upstream->responses_received = 0; + upstream->responses_timeouts = 0; + upstream->keepalive_timeout = 0; + upstream->keepalive_shutdown = 0; + /* Now TLS stuff*/ + upstream->tls_auth_state = GETDNS_AUTH_NONE; if (upstream->tls_obj != NULL) { SSL_shutdown(upstream->tls_obj); SSL_free(upstream->tls_obj); upstream->tls_obj = NULL; } - if (fd != -1) - { + if (upstream->fd != -1) { #ifdef USE_WINSOCK - closesocket(fd); + closesocket(upstream->fd); #else - close(fd); + close(upstream->fd); #endif + upstream->fd = -1; } + /* Set connection ready for use again*/ + if (upstream->conn_state != GETDNS_CONN_BACKOFF) + upstream->conn_state = GETDNS_CONN_CLOSED; } static int @@ -825,13 +897,30 @@ upstream_init(getdns_upstream *upstream, upstream->addr_len = ai->ai_addrlen; (void) memcpy(&upstream->addr, ai->ai_addr, ai->ai_addrlen); +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + inet_ntop(upstream->addr.ss_family, upstream_addr(upstream), + upstream->addr_str, INET6_ADDRSTRLEN); +#endif - /* How is this upstream doing? */ - upstream->writes_done = 0; + /* How is this upstream doing on connections? */ + upstream->conn_completed = 0; + upstream->conn_shutdowns = 0; + upstream->conn_setup_failed = 0; + upstream->conn_retry_time = 0; + upstream->conn_backoffs = 0; + upstream->total_responses = 0; + upstream->total_timeouts = 0; + upstream->conn_state = GETDNS_CONN_CLOSED; + upstream->queries_sent = 0; upstream->responses_received = 0; + upstream->responses_timeouts = 0; + upstream->keepalive_shutdown = 0; upstream->keepalive_timeout = 0; + /* How is this upstream doing on UDP? */ upstream->to_retry = 2; upstream->back_off = 1; + upstream->udp_responses = 0; + upstream->udp_timeouts = 0; /* For sharing a socket to this upstream with TCP */ upstream->fd = -1; @@ -839,10 +928,11 @@ upstream_init(getdns_upstream *upstream, upstream->tls_session = NULL; upstream->transport = GETDNS_TRANSPORT_TCP; upstream->tls_hs_state = GETDNS_HS_NONE; - upstream->tls_auth_failed = 0; upstream->tls_auth_name[0] = '\0'; + upstream->tls_auth_state = GETDNS_AUTH_NONE; + upstream->last_tls_auth_state = GETDNS_AUTH_NONE; + upstream->best_tls_auth_state = GETDNS_AUTH_NONE; upstream->tls_pubkey_pinset = NULL; - upstream->tcp.write_error = 0; upstream->loop = NULL; (void) getdns_eventloop_event_init( &upstream->event, upstream, NULL, NULL, NULL); @@ -1243,6 +1333,8 @@ getdns_context_create_with_extended_memory_functions( _getdns_rbtree_init(&result->outbound_requests, transaction_id_cmp); _getdns_rbtree_init(&result->local_hosts, local_host_cmp); + result->server = NULL; + #ifdef HAVE_LIBUNBOUND result->resolution_type = GETDNS_RESOLUTION_RECURSING; #else @@ -1299,6 +1391,27 @@ getdns_context_create_with_extended_memory_functions( _getdns_default_eventloop_init(&result->default_eventloop); _getdns_default_eventloop_init(&result->sync_eventloop); + /* request extension defaults + */ + result->header = NULL; + result->add_opt_parameters = NULL; + result->add_warning_for_bad_dns = 0; + result->dnssec_return_all_statuses = 0; + result->dnssec_return_full_validation_chain = 0; + result->dnssec_return_only_secure = 0; + result->dnssec_return_status = 0; + result->dnssec_return_validation_chain = 0; +#ifdef DNSSEC_ROADBLOCK_AVOIDANCE + result->dnssec_roadblock_avoidance = 0; +#endif + result->edns_cookies = 0; + result->return_api_information = 0; + result->return_both_v4_and_v6 = 0; + result->return_call_reporting = 0; + result->specify_class = GETDNS_RRCLASS_IN; + + /* state data used to detect changes to the system config files + */ result->fchg_resolvconf = NULL; result->fchg_hosts = NULL; @@ -1318,14 +1431,26 @@ getdns_context_create_with_extended_memory_functions( result->tls_auth = GETDNS_AUTHENTICATION_NONE; result->tls_auth_min = GETDNS_AUTHENTICATION_NONE; result->limit_outstanding_queries = 0; - result->return_dnssec_status = GETDNS_EXTENSION_FALSE; /* unbound context is initialized here */ /* Unbound needs SSL to be init'ed this early when TLS is used. However we * don't know that till later so we will have to do this every time. */ - if ((set_from_os & 2) == 0) +#ifdef HAVE_PTHREADS + pthread_mutex_lock(&ssl_init_lock); +#else + /* XXX implement Windows-style lock here */ +#endif + /* Only initialise SSL once and ideally in a thread-safe manner */ + if (ssl_init == false) { SSL_library_init(); + ssl_init = true; + } +#ifdef HAVE_PTHREADS + pthread_mutex_unlock(&ssl_init_lock); +#else + /* XXX implement Windows-style unlock here */ +#endif #ifdef HAVE_LIBUNBOUND result->unbound_ctx = NULL; @@ -1398,6 +1523,9 @@ getdns_context_destroy(struct getdns_context *context) /* cancel all outstanding requests */ cancel_outstanding_requests(context, 1); + /* Destroy listening addresses */ + (void) getdns_context_set_listen_addresses(context, NULL, NULL, NULL); + /* This needs to be done before cleaning the extension, because there * might be an idle_timeout schedules, which will not get unscheduled * with cancel_outstanding_requests. @@ -1430,8 +1558,7 @@ getdns_context_destroy(struct getdns_context *context) if (context->tls_ctx) SSL_CTX_free(context->tls_ctx); - if (context->dns_root_servers) - getdns_list_destroy(context->dns_root_servers); + getdns_list_destroy(context->dns_root_servers); #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB) if (context->root_servers_fn[0]) @@ -1448,6 +1575,10 @@ getdns_context_destroy(struct getdns_context *context) _getdns_traverse_postorder(&context->local_hosts, destroy_local_host, context); + + getdns_dict_destroy(context->header); + getdns_dict_destroy(context->add_opt_parameters); + #ifdef USE_WINSOCK WSACleanup(); #endif @@ -1525,7 +1656,7 @@ getdns_context_request_count_changed(getdns_context *context) if (context->outbound_requests.count && ! context->ub_event.ev){ DEBUG_SCHED("gc_request_count_changed " "-> ub schedule(el_ev = %p, el_ev->ev = %p)\n", - &context->ub_event, context->ub_event.ev); + (void *)&context->ub_event, (void *)context->ub_event.ev); #ifndef USE_WINSOCK #ifdef HAVE_UNBOUND_EVENT_API if (!_getdns_ub_loop_enabled(&context->ub_loop)) @@ -1539,7 +1670,7 @@ getdns_context_request_count_changed(getdns_context *context) context->ub_event.ev) { DEBUG_SCHED("gc_request_count_changed " "-> ub clear(el_ev = %p, el_ev->ev = %p)\n", - &context->ub_event, context->ub_event.ev); + (void *)&context->ub_event, (void *)context->ub_event.ev); #ifndef USE_WINSOCK #ifdef HAVE_UNBOUND_EVENT_API @@ -2815,22 +2946,8 @@ getdns_cancel_callback(getdns_context *context, return r; } /* getdns_cancel_callback */ -#ifndef STUB_NATIVE_DNSSEC -static uint8_t* -upstream_addr(getdns_upstream *upstream) -{ - return upstream->addr.ss_family == AF_INET - ? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr - : (void *)&((struct sockaddr_in6*)&upstream->addr)->sin6_addr; -} -static in_port_t -upstream_port(getdns_upstream *upstream) -{ - return ntohs(upstream->addr.ss_family == AF_INET - ? ((struct sockaddr_in *)&upstream->addr)->sin_port - : ((struct sockaddr_in6*)&upstream->addr)->sin6_port); -} +#ifndef STUB_NATIVE_DNSSEC static uint32_t * upstream_scope_id(getdns_upstream *upstream) @@ -3326,14 +3443,6 @@ getdns_context_get_eventloop(getdns_context *context, getdns_eventloop **loop) return GETDNS_RETURN_GOOD; } -static in_port_t -upstream_port(getdns_upstream *upstream) -{ - return ntohs(upstream->addr.ss_family == AF_INET - ? ((struct sockaddr_in *)&upstream->addr)->sin_port - : ((struct sockaddr_in6*)&upstream->addr)->sin6_port); -} - static getdns_dict* _get_context_settings(getdns_context* context) { @@ -3462,7 +3571,7 @@ getdns_context_set_return_dnssec_status(getdns_context* context, int enabled) { enabled != GETDNS_EXTENSION_FALSE) { return GETDNS_RETURN_INVALID_PARAMETER; } - context->return_dnssec_status = enabled; + context->dnssec_return_status = enabled == GETDNS_EXTENSION_TRUE; return GETDNS_RETURN_GOOD; } @@ -3936,4 +4045,209 @@ getdns_context_get_tls_query_padding_blocksize(getdns_context *context, uint16_t return GETDNS_RETURN_GOOD; } +static int _streq(const getdns_bindata *name, const char *str) +{ + if (strlen(str) != name->size) + return 0; + else return strncmp((const char *)name->data, str, name->size) == 0; +} + +static getdns_return_t _get_list_or_read_file(const getdns_dict *config_dict, + const char *setting, getdns_list **r_list, int *destroy_list) +{ + getdns_bindata *fn_bd; + char fn[FILENAME_MAX]; + FILE *fh; + getdns_return_t r; + + assert(r_list); + assert(destroy_list); + + *destroy_list = 0; + if (!(r = getdns_dict_get_list(config_dict, setting, r_list))) + return GETDNS_RETURN_GOOD; + + else if ((r = getdns_dict_get_bindata(config_dict, setting, &fn_bd))) + return r; + + else if (fn_bd->size >= FILENAME_MAX) + return GETDNS_RETURN_INVALID_PARAMETER; + + (void)memcpy(fn, fn_bd->data, fn_bd->size); + fn[fn_bd->size] = 0; + + if (!(fh = fopen(fn, "r"))) + return GETDNS_RETURN_GENERIC_ERROR; + + if (!(r = getdns_fp2rr_list(fh, r_list, NULL, 3600))) + *destroy_list = 1; + + fclose(fh); + return r; +} + +#define CONTEXT_SETTING_INT(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = getdns_dict_get_int(config_dict, #X , &n))) \ + r = getdns_context_set_ ## X (context, n); + +#define CONTEXT_SETTING_LIST(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = getdns_dict_get_list(config_dict, #X , &list))) \ + r = getdns_context_set_ ## X (context, list); + +#define CONTEXT_SETTING_LIST_OR_ZONEFILE(X) \ + } else if (_streq(setting, #X)) { \ + if (!(r = _get_list_or_read_file( \ + config_dict, #X , &list, &destroy_list))) \ + r = getdns_context_set_ ## X(context, list); \ + if (destroy_list) getdns_list_destroy(list); + +#define CONTEXT_SETTING_ARRAY(X, T) \ + } else if (_streq(setting, #X )) { \ + if (!(r = getdns_dict_get_list(config_dict, #X , &list)) && \ + !(r = getdns_list_get_length(list, &count))) { \ + for (i=0; iX = 1; \ + else if (n == GETDNS_EXTENSION_FALSE) context->X = 0; \ + else r = GETDNS_RETURN_INVALID_PARAMETER; \ + } + +static getdns_return_t +_getdns_context_config_setting(getdns_context *context, + const getdns_dict *config_dict, const getdns_bindata *setting) +{ + getdns_return_t r = GETDNS_RETURN_GOOD; + getdns_dict *dict; + getdns_list *list; + getdns_namespace_t namespaces[100]; + getdns_transport_list_t dns_transport_list[100]; + size_t count, i; + uint32_t n; + int destroy_list = 0; + + if (_streq(setting, "all_context")) { + if (!(r = getdns_dict_get_dict(config_dict, "all_context", &dict))) + r = getdns_context_config(context, dict); + + CONTEXT_SETTING_INT(resolution_type) + CONTEXT_SETTING_ARRAY(namespaces, namespace) + CONTEXT_SETTING_INT(dns_transport) + CONTEXT_SETTING_ARRAY(dns_transport_list, transport_list) + CONTEXT_SETTING_INT(idle_timeout) + CONTEXT_SETTING_INT(limit_outstanding_queries) + CONTEXT_SETTING_INT(timeout) + CONTEXT_SETTING_INT(follow_redirects) + CONTEXT_SETTING_LIST_OR_ZONEFILE(dns_root_servers) + CONTEXT_SETTING_INT(append_name) + CONTEXT_SETTING_LIST(suffix) + CONTEXT_SETTING_LIST_OR_ZONEFILE(dnssec_trust_anchors) + CONTEXT_SETTING_INT(dnssec_allowed_skew) + CONTEXT_SETTING_LIST(upstream_recursive_servers) + CONTEXT_SETTING_INT(edns_maximum_udp_payload_size) + CONTEXT_SETTING_INT(edns_extended_rcode) + CONTEXT_SETTING_INT(edns_version) + CONTEXT_SETTING_INT(edns_do_bit) + + /***************************************/ + /**** ****/ + /**** Unofficial context settings ****/ + /**** ****/ + /***************************************/ + + CONTEXT_SETTING_INT(edns_client_subnet_private) + CONTEXT_SETTING_INT(tls_authentication) + CONTEXT_SETTING_INT(tls_query_padding_blocksize) + + /**************************************/ + /**** ****/ + /**** Default extensions setting ****/ + /**** ****/ + /**************************************/ + EXTENSION_SETTING_BOOL(add_warning_for_bad_dns) + EXTENSION_SETTING_BOOL(dnssec_return_all_statuses) + EXTENSION_SETTING_BOOL(dnssec_return_full_validation_chain) + EXTENSION_SETTING_BOOL(dnssec_return_only_secure) + EXTENSION_SETTING_BOOL(dnssec_return_status) + EXTENSION_SETTING_BOOL(dnssec_return_validation_chain) +#if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND) + EXTENSION_SETTING_BOOL(dnssec_roadblock_avoidance) +#endif +#ifdef EDNS_COOKIES + EXTENSION_SETTING_BOOL(edns_cookies) +#endif + EXTENSION_SETTING_BOOL(return_api_information) + EXTENSION_SETTING_BOOL(return_both_v4_and_v6) + EXTENSION_SETTING_BOOL(return_call_reporting) + + } else if (_streq(setting, "add_opt_parameters")) { + if (!(r = getdns_dict_get_dict(config_dict, "add_opt_parameters" , &dict))) { + if (context->add_opt_parameters) + getdns_dict_destroy(context->add_opt_parameters); + context->add_opt_parameters = NULL; + r = _getdns_dict_copy(dict, &context->add_opt_parameters); + } + + } else if (_streq(setting, "header")) { + if (!(r = getdns_dict_get_dict(config_dict, "header" , &dict))) { + if (context->header) + getdns_dict_destroy(context->header); + if (!(context->header = + getdns_dict_create_with_context(context))) + r = GETDNS_RETURN_MEMORY_ERROR; + else r = getdns_dict_set_dict( + context->header, "header", dict); + } + + } else if (_streq(setting, "specify_class")) { + if (!(r = getdns_dict_get_int( + config_dict, "specify_class" , &n))) + context->specify_class = (uint16_t)n; + + + /************************************/ + /**** ****/ + /**** Ignored context settings ****/ + /**** ****/ + /************************************/ + } else if (!_streq(setting, "implementation_string") && + !_streq(setting, "version_string")) { + r = GETDNS_RETURN_NOT_IMPLEMENTED; + } + return r; +} + +getdns_return_t +getdns_context_config(getdns_context *context, const getdns_dict *config_dict) +{ + getdns_list *settings; + getdns_return_t r; + getdns_bindata *setting; + size_t i; + + if ((r = getdns_dict_get_names(config_dict, &settings))) + return r; + + for (i = 0; !(r = getdns_list_get_bindata(settings,i,&setting)); i++) { + if ((r = _getdns_context_config_setting( + context, config_dict, setting))) + break; + } + if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) + r = GETDNS_RETURN_GOOD; + + getdns_list_destroy(settings); + return r; +} + /* context.c */ diff --git a/src/context.h b/src/context.h index 86bfb817..b89a5876 100644 --- a/src/context.h +++ b/src/context.h @@ -44,6 +44,7 @@ #include "extension/default_eventloop.h" #include "util/rbtree.h" #include "ub_loop.h" +#include "server.h" struct getdns_dns_req; struct ub_ctx; @@ -80,6 +81,14 @@ typedef enum getdns_tls_hs_state { GETDNS_HS_FAILED } getdns_tls_hs_state_t; +typedef enum getdns_conn_state { + GETDNS_CONN_CLOSED, + GETDNS_CONN_SETUP, + GETDNS_CONN_OPEN, + GETDNS_CONN_TEARDOWN, + GETDNS_CONN_BACKOFF +} getdns_conn_state_t; + typedef enum getdns_tsig_algo { GETDNS_NO_TSIG = 0, /* Do not use tsig */ GETDNS_HMAC_MD5 = 1, /* 128 bits */ @@ -115,31 +124,55 @@ typedef struct getdns_upstream { socklen_t addr_len; struct sockaddr_storage addr; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + char addr_str[INET6_ADDRSTRLEN]; +#endif - /* How is this upstream doing? */ - size_t writes_done; - size_t responses_received; - uint64_t keepalive_timeout; + /* How is this upstream doing over UDP? */ int to_retry; int back_off; + size_t udp_responses; + size_t udp_timeouts; - /* For sharing a TCP socket to this upstream */ + /* For stateful upstreams, need to share the connection and track the + activity on the connection */ int fd; getdns_transport_list_t transport; - SSL* tls_obj; - SSL_SESSION* tls_session; - getdns_tls_hs_state_t tls_hs_state; getdns_eventloop_event event; getdns_eventloop *loop; getdns_tcp_state tcp; - char tls_auth_name[256]; - size_t tls_auth_failed; - sha256_pin_t *tls_pubkey_pinset; + /* These are running totals or historical info */ + size_t conn_completed; + size_t conn_shutdowns; + size_t conn_setup_failed; + time_t conn_retry_time; + size_t conn_backoffs; + size_t total_responses; + size_t total_timeouts; + getdns_auth_state_t best_tls_auth_state; + getdns_auth_state_t last_tls_auth_state; + /* These are per connection. */ + getdns_conn_state_t conn_state; + size_t queries_sent; + size_t responses_received; + size_t responses_timeouts; + size_t keepalive_shutdown; + uint64_t keepalive_timeout; - /* Pipelining of TCP network requests */ + /* Management of outstanding requests on stateful transports */ getdns_network_req *write_queue; getdns_network_req *write_queue_last; - _getdns_rbtree_t netreq_by_query_id; + _getdns_rbtree_t netreq_by_query_id; + + /* TLS specific connection handling*/ + SSL* tls_obj; + SSL_SESSION* tls_session; + getdns_tls_hs_state_t tls_hs_state; + getdns_auth_state_t tls_auth_state; + unsigned tls_fallback_ok : 1; + /* Auth credentials*/ + char tls_auth_name[256]; + sha256_pin_t *tls_pubkey_pinset; /* When requests have been scheduled asynchronously on an upstream * that is kept open, and a synchronous call is then done with the @@ -157,6 +190,7 @@ typedef struct getdns_upstream { */ getdns_dns_req *finished_dnsreqs; getdns_eventloop_event finished_event; + unsigned is_sync_loop : 1; /* EDNS cookies */ uint32_t secret; @@ -168,8 +202,6 @@ typedef struct getdns_upstream { unsigned has_prev_client_cookie : 1; unsigned has_server_cookie : 1; unsigned server_cookie_len : 5; - unsigned tls_fallback_ok : 1; - unsigned is_sync_loop : 1; /* TSIG */ uint8_t tsig_dname[256]; @@ -184,7 +216,7 @@ typedef struct getdns_upstreams { struct mem_funcs mf; size_t referenced; size_t count; - size_t current; + size_t current_udp; getdns_upstream upstreams[]; } getdns_upstreams; @@ -219,7 +251,6 @@ struct getdns_context { getdns_transport_list_t *dns_transports; size_t dns_transport_count; - size_t dns_transport_current; uint8_t edns_extended_rcode; uint8_t edns_version; @@ -250,8 +281,6 @@ struct getdns_context { /* A tree to hold local host information*/ _getdns_rbtree_t local_hosts; - int return_dnssec_status; - /* which resolution type the contexts are configured for * 0 means nothing set */ @@ -262,6 +291,8 @@ struct getdns_context { */ _getdns_rbtree_t outbound_requests; + struct listen_set *server; + /* Event loop extension. */ getdns_eventloop *extension; @@ -275,6 +306,24 @@ struct getdns_context { _getdns_default_eventloop default_eventloop; _getdns_default_eventloop sync_eventloop; + /* request extension defaults */ + getdns_dict *header; + getdns_dict *add_opt_parameters; + unsigned add_warning_for_bad_dns : 1; + unsigned dnssec_return_all_statuses : 1; + unsigned dnssec_return_full_validation_chain : 1; + unsigned dnssec_return_only_secure : 1; + unsigned dnssec_return_status : 1; + unsigned dnssec_return_validation_chain : 1; +#ifdef DNSSEC_ROADBLOCK_AVOIDANCE + unsigned dnssec_roadblock_avoidance : 1; +#endif + unsigned edns_cookies : 1; + unsigned return_api_information : 1; /* Not used */ + unsigned return_both_v4_and_v6 : 1; + unsigned return_call_reporting : 1; + uint16_t specify_class; + /* * state data used to detect changes to the system config files */ diff --git a/src/convert.c b/src/convert.c index 055abf96..5e2c2684 100644 --- a/src/convert.c +++ b/src/convert.c @@ -48,8 +48,12 @@ #include "util-internal.h" #include "gldns/wire2str.h" #include "gldns/str2wire.h" +#include "gldns/parseutil.h" +#include "const-info.h" +#include "types-internal.h" /* For getdns_item */ #include "dict.h" #include "list.h" +#include "jsmn/jsmn.h" #include "convert.h" #include "debug.h" @@ -156,6 +160,7 @@ getdns_convert_ulabel_to_alabel(const char *ulabel) free(prepped2); return buf; #else + (void)ulabel; return NULL; #endif } @@ -185,6 +190,7 @@ getdns_convert_alabel_to_ulabel(const char *alabel) } return buf; #else + (void)alabel; return NULL; #endif } @@ -832,7 +838,6 @@ _getdns_reply_dict2wire( } } remove_dnssec = !getdns_dict_get_int(reply, "/header/do", &n) && n == 0; - DEBUG_SERVER("remove_dnssec: %d\n", remove_dnssec); if (!getdns_dict_get_list(reply, "answer", §ion)) { for ( n = 0, i = 0 @@ -1067,5 +1072,673 @@ getdns_msg_dict2str_scan( return r; } +static getdns_dict * +_getdns_ipaddr_dict_mf(struct mem_funcs *mf, const char *ipstr) +{ + getdns_dict *r = _getdns_dict_create_with_mf(mf); + char *s = strchr(ipstr, '%'), *scope_id_str = ""; + char *p = strchr(ipstr, '@'), *portstr = ""; + char *t = strchr(ipstr, '#'), *tls_portstr = ""; + char *n = strchr(ipstr, '~'), *tls_namestr = ""; + /* ^[alg:]name:key */ + char *T = strchr(ipstr, '^'), *tsig_name_str = "" + , *tsig_secret_str = "" + , *tsig_algorithm_str = ""; + char *br, *c; + int tsig_secret_size; + uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */ + getdns_bindata tsig_secret; + uint8_t buf[sizeof(struct in6_addr)]; + getdns_bindata addr; + + addr.data = buf; + + if (!r) return NULL; + + if (*ipstr == '[') { + char *br = strchr(ipstr, ']'); + if (br) { + ipstr += 1; + *br = 0; + if ((c = strchr(br + 1, ':'))) { + p = c; + } + } + } else if ((br = strchr(ipstr, '.')) && (c = strchr(br + 1, ':')) + && (T == NULL || c < T)) + p = c; + + else if ((*ipstr == '*') && (c = strchr(ipstr+1, ':'))) + p = c; + + if (s) { + *s = 0; + scope_id_str = s + 1; + } + if (p) { + *p = 0; + portstr = p + 1; + } + if (t) { + *t = 0; + tls_portstr = t + 1; + } + if (n) { + *n = 0; + tls_namestr = n + 1; + } + if (T) { + *T = 0; + tsig_name_str = T + 1; + if ((T = strchr(tsig_name_str, ':'))) { + *T = 0; + tsig_secret_str = T + 1; + if ((T = strchr(tsig_secret_str, ':'))) { + *T = 0; + tsig_algorithm_str = tsig_name_str; + tsig_name_str = tsig_secret_str; + tsig_secret_str = T + 1; + } + } else { + tsig_name_str = ""; + } + } + if (*ipstr == '*') { + getdns_dict_util_set_string(r, "address_type", "IPv6"); + addr.size = 16; + (void) memset(buf, 0, 16); + } else if (strchr(ipstr, ':')) { + getdns_dict_util_set_string(r, "address_type", "IPv6"); + addr.size = 16; + if (inet_pton(AF_INET6, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } else { + getdns_dict_util_set_string(r, "address_type", "IPv4"); + addr.size = 4; + if (inet_pton(AF_INET, ipstr, buf) <= 0) { + getdns_dict_destroy(r); + return NULL; + } + } + getdns_dict_set_bindata(r, "address_data", &addr); + if (*portstr) + getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); + if (*tls_portstr) + getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); + if (*tls_namestr) { + getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); + } + if (*scope_id_str) + getdns_dict_util_set_string(r, "scope_id", scope_id_str); + if (*tsig_name_str) + getdns_dict_util_set_string(r, "tsig_name", tsig_name_str); + if (*tsig_algorithm_str) + getdns_dict_util_set_string(r, "tsig_algorithm", tsig_algorithm_str); + if (*tsig_secret_str) { + tsig_secret_size = gldns_b64_pton( + tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf)); + if (tsig_secret_size > 0) { + tsig_secret.size = tsig_secret_size; + tsig_secret.data = tsig_secret_buf; + getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret); + } + } + return r; +} + +static int _jsmn_get_ipdict(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_dict **value) +{ + char value_str[3072]; + int size = t->end - t->start; + + if (size <= 0 || size >= (int)sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + *value = _getdns_ipaddr_dict_mf(mf, value_str); + return *value != NULL; +} + +static int _jsmn_get_data(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + int i; + size_t j; + uint8_t h, l; + + if ((t->end - t->start) < 4 || (t->end - t->start) % 2 == 1 || + js[t->start] != '0' || js[t->start + 1] != 'x') + return 0; + + for (i = t->start + 2; i < t->end; i++) + if (!((js[i] >= '0' && js[i] <= '9') + ||(js[i] >= 'a' && js[i] <= 'f') + ||(js[i] >= 'A' && js[i] <= 'F'))) + return 0; + + if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + return 0; + + else if (!((*value)->data = GETDNS_XMALLOC( + *mf, uint8_t, (t->end - t->start) / 2 - 1))) { + GETDNS_FREE(*mf, *value); + return 0; + } + for (i = t->start + 2, j = 0; i < t->end; i++, j++) { + h = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' + : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' + : js[i] + 10 - 'a'; + h <<= 4; + i++; + l = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' + : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' + : js[i] + 10 - 'a'; + (*value)->data[j] = h | l; + } + (*value)->size = j; + return 1; +} + +static int _jsmn_get_dname(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[1025]; + int size = t->end - t->start; + (void)mf; /* TODO: Fix to use mf */ + + if (size <= 0 || size >= (int)sizeof(value_str) || js[t->end - 1] != '.') + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + return !getdns_convert_fqdn_to_dns_name(value_str, value); +} + +static int _jsmn_get_ipv4(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[16]; + int size = t->end - t->start; + uint8_t buf[4]; + + if (size <= 0 || size >= (int)sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + if (inet_pton(AF_INET, value_str, buf) <= 0) + ; /* pass */ + + else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + ; /* pass */ + + else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 4))) + GETDNS_FREE(*mf, *value); + + else { + (*value)->size = 4; + (void) memcpy((*value)->data, buf, 4); + return 1; + } + return 0; +} + +static int _jsmn_get_ipv6(struct mem_funcs *mf, const char *js, jsmntok_t *t, + getdns_bindata **value) +{ + char value_str[40]; + int size = t->end - t->start; + uint8_t buf[16]; + + if (size <= 0 || size >= (int)sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + if (inet_pton(AF_INET6, value_str, buf) <= 0) + ; /* pass */ + + else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) + ; /* pass */ + + else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 16))) + GETDNS_FREE(*mf, *value); + + else { + (*value)->size = 16; + (void) memcpy((*value)->data, buf, 16); + return 1; + } + return 0; +} + +static int _jsmn_get_int(const char *js, jsmntok_t *t, uint32_t *value) +{ + char value_str[11]; + int size = t->end - t->start; + char *endptr; + + if (size <= 0 || size >= (int)sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + *value = (uint32_t)strtoul(value_str, &endptr, 10); + return *value_str != '\0' && *endptr == '\0'; +} + +static int _jsmn_get_const(const char *js, jsmntok_t *t, uint32_t *value) +{ + char value_str[80]; + int size = t->end - t->start; + + if (size <= 0 || size >= (int)sizeof(value_str)) + return 0; + + (void) memcpy(value_str, js + t->start, size); + value_str[size] = '\0'; + + return _getdns_get_const_name_info(value_str, value); +} + +static void +_getdns_destroy_item_data(struct mem_funcs *mf, getdns_item *item) +{ + switch (item->dtype) { + case t_dict: + getdns_dict_destroy(item->data.dict); + break; + + case t_list: + getdns_list_destroy(item->data.list); + break; + + case t_bindata: + GETDNS_FREE(*mf, item->data.bindata->data); + GETDNS_FREE(*mf, item->data.bindata); + default: + break; + } +} +static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_item *item, getdns_return_t *r); + +static int _jsmn_get_dict(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_dict *dict, getdns_return_t *r) +{ + int i; + size_t j = 1; + char key_spc[1024], *key = NULL; + getdns_item child_item; + + if (t->size <= 0) + *r = GETDNS_RETURN_GOOD; + + else for (i = 0; i < t->size; i++) { + if (t[j].type != JSMN_STRING && + t[j].type != JSMN_PRIMITIVE) { + + /* Key must be string or primitive */ + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + } + if (t[j].end <= t[j].start) { + /* Key must be at least 1 character */ + *r = GETDNS_RETURN_GENERIC_ERROR; /* range error */ + break; + } + if (t[j].end - t[j].start < (int)sizeof(key_spc)) + key = key_spc; + + else if (!(key = GETDNS_XMALLOC( + *mf, char, t[j].end - t[j].start + 1))) { + + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + (void) memcpy(key, js + t[j].start, t[j].end - t[j].start); + key[t[j].end - t[j].start] = '\0'; + j += 1; + + j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); + if (*r) break; + + switch (child_item.dtype) { + case t_int: + *r = getdns_dict_set_int(dict, key, + child_item.data.n); + break; + case t_bindata: + *r = getdns_dict_set_bindata(dict, key, + child_item.data.bindata); + break; + case t_list: + *r = getdns_dict_set_list(dict, key, + child_item.data.list); + break; + case t_dict: + *r = getdns_dict_set_dict(dict, key, + child_item.data.dict); + break; + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + + } + _getdns_destroy_item_data(mf, &child_item); + if (*r) break; + if (key && key != key_spc) { + GETDNS_FREE(*mf, key); + key = NULL; + } + } + if (key && key != key_spc) + GETDNS_FREE(*mf, key); + + if (*r) { + getdns_dict_destroy(dict); + return 0; + } + return j; +} + +static int _jsmn_get_list(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_list *list, getdns_return_t *r) +{ + int i; + size_t j = 1, index = 0; + getdns_item child_item; + + if (t->size <= 0) + *r = GETDNS_RETURN_GOOD; + + else for (i = 0; i < t->size; i++) { + j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); + if (*r) break; + + switch (child_item.dtype) { + case t_int: + *r = getdns_list_set_int(list, index++, + child_item.data.n); + break; + case t_bindata: + *r = getdns_list_set_bindata(list, index++, + child_item.data.bindata); + break; + case t_list: + *r = getdns_list_set_list(list, index++, + child_item.data.list); + break; + case t_dict: + *r = getdns_list_set_dict(list, index++, + child_item.data.dict); + break; + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + + } + _getdns_destroy_item_data(mf, &child_item); + if (*r) break; + } + if (*r) { + getdns_list_destroy(list); + return 0; + } + return j; +} + +static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, + size_t count, getdns_item *item, getdns_return_t *r) +{ + assert(item); + + switch (t->type) { + case JSMN_STRING: + if (t->end < t->start) + *r = GETDNS_RETURN_GENERIC_ERROR; + + else if (!(item->data.bindata = + GETDNS_MALLOC(*mf, getdns_bindata))) + *r = GETDNS_RETURN_MEMORY_ERROR; + + else if (!(item->data.bindata->data = GETDNS_XMALLOC( + *mf, uint8_t, t->end - t->start + 1))) { + GETDNS_FREE(*mf, item->data.bindata); + *r = GETDNS_RETURN_MEMORY_ERROR; + } else { + item->dtype = t_bindata; + if (t->end - t->start) { + (void) memcpy(item->data.bindata->data, + js + t->start, t->end - t->start); + } + item->data.bindata->data[t->end - t->start] = '\0'; + item->data.bindata->size = t->end - t->start; + *r = GETDNS_RETURN_GOOD; + return 1; + } + break; + + case JSMN_PRIMITIVE: + /* There is no such thing as an empty primitive */ + if (t->end <= t->start) { + *r = GETDNS_RETURN_GENERIC_ERROR; + break; + + } else if (_jsmn_get_int(js, t, &item->data.n) + || _jsmn_get_const(js, t, &item->data.n)) { + + item->dtype = t_int; + } + else if (_jsmn_get_data(mf, js, t, &item->data.bindata) + || _jsmn_get_dname(mf, js, t, &item->data.bindata) + || _jsmn_get_ipv4(mf, js, t, &item->data.bindata) + || _jsmn_get_ipv6(mf, js, t, &item->data.bindata)) + + item->dtype = t_bindata; + + else if (_jsmn_get_ipdict(mf, js, t, &item->data.dict)) + + item->dtype = t_dict; + else { + *r = GETDNS_RETURN_GENERIC_ERROR; + break; + } + *r = GETDNS_RETURN_GOOD; + return 1; + + case JSMN_OBJECT: + if (!(item->data.dict = _getdns_dict_create_with_mf(mf))) { + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + item->dtype = t_dict; + return _jsmn_get_dict(mf, js, t, count, item->data.dict, r); + + case JSMN_ARRAY: + if (!(item->data.list = _getdns_list_create_with_mf(mf))) { + *r = GETDNS_RETURN_MEMORY_ERROR; + break; + } + item->dtype = t_list; + return _jsmn_get_list(mf, js, t, count, item->data.list, r); + + default: + *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + break; + } + return 0; +} + +static getdns_return_t +_getdns_str2item_mf(struct mem_funcs *mf, const char *str, getdns_item *item) +{ + jsmn_parser p; + jsmntok_t *tok = NULL, *new_tok; + size_t tokcount = 100; + int r; + getdns_return_t gr; + + jsmn_init(&p); + tok = GETDNS_XMALLOC(*mf, jsmntok_t, tokcount); + do { + r = jsmn_parse(&p, str, strlen(str), tok, tokcount); + if (r == JSMN_ERROR_NOMEM) { + tokcount *= 2; + if (!(new_tok = GETDNS_XREALLOC( + *mf, tok, jsmntok_t, tokcount))) { + GETDNS_FREE(*mf, tok); + return GETDNS_RETURN_MEMORY_ERROR; + } + tok = new_tok; + } + } while (r == JSMN_ERROR_NOMEM); + if (r < 0) + gr = GETDNS_RETURN_GENERIC_ERROR; + else + (void) _jsmn_get_item(mf, str, tok, p.toknext, item, &gr); + GETDNS_FREE(*mf, tok); + return gr; +} + +getdns_return_t +getdns_str2dict(const char *str, getdns_dict **dict) +{ + getdns_item item; + getdns_return_t r; + + if (!str || !dict) + return GETDNS_RETURN_INVALID_PARAMETER; + + while (*str && isspace(*str)) + str++; + + if (*str != '{') { + getdns_dict *dict_r = _getdns_ipaddr_dict_mf( + &_getdns_plain_mem_funcs, str); + + if (dict_r) { + *dict = dict_r; + return GETDNS_RETURN_GOOD; + } + } + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_dict) { + uint8_t buf[16]; + getdns_dict *dict_r; + + if (item.dtype != t_bindata) + r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + + else if (item.data.bindata->size == 4 && + inet_pton(AF_INET, str, buf) == 1) { + + if (!(dict_r = getdns_dict_create())) + r = GETDNS_RETURN_MEMORY_ERROR; + + else if ((r = getdns_dict_util_set_string( + dict_r, "address_type", "IPv4"))) + getdns_dict_destroy(dict_r); + + else if ((r = getdns_dict_set_bindata( + dict_r, "address_data", item.data.bindata))) + getdns_dict_destroy(dict_r); + else + *dict = dict_r; + + } else if (item.data.bindata->size == 16 && + inet_pton(AF_INET6, str, buf) == 1) { + + if (!(dict_r = getdns_dict_create())) + r = GETDNS_RETURN_MEMORY_ERROR; + + else if ((r = getdns_dict_util_set_string( + dict_r, "address_type", "IPv6"))) + getdns_dict_destroy(dict_r); + + else if ((r = getdns_dict_set_bindata( + dict_r, "address_data", item.data.bindata))) + getdns_dict_destroy(dict_r); + else + *dict = dict_r; + } else + r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; + + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return r; + } + *dict = item.data.dict; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2list(const char *str, getdns_list **list) +{ + getdns_item item; + getdns_return_t r; + + if (!str || !list) + return GETDNS_RETURN_INVALID_PARAMETER; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_list) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *list = item.data.list; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2bindata(const char *str, getdns_bindata **bindata) +{ + getdns_item item; + getdns_return_t r; + + if (!str || !bindata) + return GETDNS_RETURN_INVALID_PARAMETER; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_bindata) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *bindata = item.data.bindata; + return GETDNS_RETURN_GOOD; +} + +getdns_return_t +getdns_str2int(const char *str, uint32_t *value) +{ + getdns_item item; + getdns_return_t r; + + if (!str || !value) + return GETDNS_RETURN_INVALID_PARAMETER; + + if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) + return r; + + else if (item.dtype != t_int) { + _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); + return GETDNS_RETURN_WRONG_TYPE_REQUESTED; + } + *value = item.data.n; + return GETDNS_RETURN_GOOD; +} -/* convert.c */ diff --git a/src/debug.h b/src/debug.h index 5afbdea3..5087efb4 100644 --- a/src/debug.h +++ b/src/debug.h @@ -37,7 +37,7 @@ #include "config.h" -#define STUB_DEBUG_ENTRY "-> ENTRY: " +#define STUB_DEBUG_ENTRY "=> ENTRY: " #define STUB_DEBUG_SETUP "--- SETUP: " #define STUB_DEBUG_SETUP_TLS "--- SETUP(TLS): " #define STUB_DEBUG_TSIG "--- TSIG: " @@ -45,6 +45,7 @@ #define STUB_DEBUG_READ "------- READ: " #define STUB_DEBUG_WRITE "------- WRITE: " #define STUB_DEBUG_CLEANUP "--- CLEANUP: " +#define STUB_DEBUG_DAEMON "GETDNS_DAEMON: " #ifdef GETDNS_ON_WINDOWS #define DEBUG_ON(...) do { \ @@ -67,7 +68,7 @@ char buf[10]; \ \ gettimeofday(&tv, NULL); \ - gmtime_r(&tm, &tv.tv_sec); \ + gmtime_r(&tv.tv_sec, &tm); \ strftime(buf, 10, "%H:%M:%S", &tm); \ fprintf(stderr, "[%s.%.6d] ", buf, (int)tv.tv_usec); \ fprintf(stderr, __VA_ARGS__); \ @@ -104,6 +105,13 @@ #define DEBUG_STUB(...) DEBUG_OFF(__VA_ARGS__) #endif +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG +#include +#define DEBUG_DAEMON(...) DEBUG_ON(__VA_ARGS__) +#else +#define DEBUG_DAEMON(...) DEBUG_OFF(__VA_ARGS__) +#endif + #if defined(SEC_DEBUG) && SEC_DEBUG #include #define DEBUG_SEC(...) DEBUG_ON(__VA_ARGS__) diff --git a/src/dnssec.c b/src/dnssec.c index 87e2943b..0269fe3d 100644 --- a/src/dnssec.c +++ b/src/dnssec.c @@ -2696,6 +2696,7 @@ static int chain_head_validate(struct mem_funcs *mf, time_t now, uint32_t skew, * evaluated by processing each head in turn. The worst outcome per network request * is the dnssec status for that network request. */ +#ifdef STUB_NATIVE_DNSSEC static void chain_set_netreq_dnssec_status(chain_head *chain, _getdns_rrset_iter *tas) { chain_head *head; @@ -2732,6 +2733,7 @@ static void chain_set_netreq_dnssec_status(chain_head *chain, _getdns_rrset_iter } } } +#endif /* The DNSSEC status of all heads for a chain structure is evaluated by * processing each head in turn. The worst outcome is the dnssec status for diff --git a/src/extension/default_eventloop.c b/src/extension/default_eventloop.c index c27dacde..e9e74550 100644 --- a/src/extension/default_eventloop.c +++ b/src/extension/default_eventloop.c @@ -54,7 +54,7 @@ default_eventloop_schedule(getdns_eventloop *loop, size_t i; DEBUG_SCHED( "%s(loop: %p, fd: %d, timeout: %"PRIu64", event: %p, FD_SETSIZE: %d)\n" - , __FUNCTION__, loop, fd, timeout, event, FD_SETSIZE); + , __FUNC__, (void *)loop, fd, timeout, (void *)event, FD_SETSIZE); if (!loop || !event) return GETDNS_RETURN_INVALID_PARAMETER; @@ -75,11 +75,11 @@ default_eventloop_schedule(getdns_eventloop *loop, if (default_loop->fd_events[fd] == event) { DEBUG_SCHED("WARNING: Event %p not cleared " "before being rescheduled!\n" - , default_loop->fd_events[fd]); + , (void *)default_loop->fd_events[fd]); } else { DEBUG_SCHED("ERROR: A different event is " "already present at fd slot: %p!\n" - , default_loop->fd_events[fd]); + , (void *)default_loop->fd_events[fd]); } } #endif @@ -123,7 +123,7 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) if (!loop || !event) return GETDNS_RETURN_INVALID_PARAMETER; - DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNCTION__, loop, event); + DEBUG_SCHED( "%s(loop: %p, event: %p)\n", __FUNC__, (void *)loop, (void *)event); i = (intptr_t)event->ev - 1; if (i < 0 || i >= FD_SETSIZE) { @@ -134,7 +134,7 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) if (default_loop->timeout_events[i] != event) DEBUG_SCHED( "ERROR: Different/wrong event present at " "timeout slot: %p!\n" - , default_loop->timeout_events[i]); + , (void *)default_loop->timeout_events[i]); #endif default_loop->timeout_events[i] = NULL; } else { @@ -142,7 +142,7 @@ default_eventloop_clear(getdns_eventloop *loop, getdns_eventloop_event *event) if (default_loop->fd_events[i] != event) DEBUG_SCHED( "ERROR: Different/wrong event present at " "fd slot: %p!\n" - , default_loop->fd_events[i]); + , (void *)default_loop->fd_events[i]); #endif default_loop->fd_events[i] = NULL; } @@ -162,7 +162,7 @@ default_read_cb(int fd, getdns_eventloop_event *event) #if !defined(SCHED_DEBUG) || !SCHED_DEBUG (void)fd; #endif - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event); event->read_cb(event->userarg); } @@ -172,7 +172,7 @@ default_write_cb(int fd, getdns_eventloop_event *event) #if !defined(SCHED_DEBUG) || !SCHED_DEBUG (void)fd; #endif - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event); event->write_cb(event->userarg); } @@ -182,7 +182,7 @@ default_timeout_cb(int fd, getdns_eventloop_event *event) #if !defined(SCHED_DEBUG) || !SCHED_DEBUG (void)fd; #endif - DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNCTION__, fd, event); + DEBUG_SCHED( "%s(fd: %d, event: %p)\n", __FUNC__, fd, (void *)event); event->timeout_cb(event->userarg); } @@ -212,7 +212,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking) else if (default_loop->timeout_times[i] < timeout) timeout = default_loop->timeout_times[i]; } - for (fd = 0; fd < FD_SETSIZE; fd++) { + for (fd = 0; fd < (int)FD_SETSIZE; fd++) { if (!default_loop->fd_events[fd]) continue; if (default_loop->fd_events[fd]->read_cb) @@ -240,7 +240,7 @@ default_eventloop_run_once(getdns_eventloop *loop, int blocking) exit(EXIT_FAILURE); } now = get_now_plus(0); - for (fd = 0; fd < FD_SETSIZE; fd++) { + for (fd = 0; fd < (int)FD_SETSIZE; fd++) { if (default_loop->fd_events[fd] && default_loop->fd_events[fd]->read_cb && FD_ISSET(fd, &readfds)) diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index 2a8f7f2a..f7825361 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -485,6 +485,7 @@ typedef enum getdns_callback_type_t { #define GETDNS_RCODE_BADNAME 20 #define GETDNS_RCODE_BADALG 21 #define GETDNS_RCODE_BADTRUNC 22 +#define GETDNS_RCODE_COOKIE 23 /** @} */ diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index 7e2a16e3..5abf39e7 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -900,6 +900,196 @@ getdns_msg_dict2str_buf( getdns_return_t getdns_msg_dict2str_scan( const getdns_dict *msg_dict, char **str, int *str_len); + +/** + * Convert string text to a getdns_dict. + * + * @param str A textual representation of a getdns_dict. + * The format is similar, but not precisely JSON. + * - dict keys may be given without quotes. + * For example: `{ timeout: 2000 }` is the same as { "timeout": 2000 } + * - When str contains an IP or IPv6 address, it is converted + * to an getdns dict representation of that address. This may contain + * a port, tls_port, tsig spec or tls authentication name in the same + * way as may be given with the `getdns_query` tool. For example: + * `185.49.140.67:80#443` will result in the following getdns_dict: + * + * { address_type: "IPv4" + * , address_data: "185.49.140.67" + * , port: 80 + * , tls_port: 443 + * } + * + * @param dict The returned getdns_dict. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + */ +getdns_return_t +getdns_str2dict(const char *str, getdns_dict **dict); + +/** + * Convert string text to a getdns_list. + * + * @param str A textual representation of a getdns_list. + * The format is similar, but not precisely JSON. + * @param list The returned getdns_list. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + */ +getdns_return_t +getdns_str2list(const char *str, getdns_list **list); + +/** + * Convert string text to a getdns_bindata. + * + * @param str A textual representation of a getdns_bindata + * The format is similar, but not precisely JSON. + * - Strings between double-quotes will be converted to bindata + * containers, but *without the trailing null byte*. + * For example: `{ suffix: [ "nlnetlabs.nl.", "nlnet.nl." ] }` + * - bindata representation of IP or IPv6 addresses may be + * given in their presentation format. For example: + * `{ dns_root_servers: [ 2001:7fd::1, 193.0.14.129 ] }` + * - Arbitrary binary data may be given with a `0x` prefix. + * For example: + * + * { add_opt_parameters: + * { options: [ { option_code: 10 + * , option_data: 0xA9E4EC50C03F5D65 + * } ] + * } + * } + * + * - Wireformat domain name bindatas can be given with a trailing dot. + * For example: + * + * { upstream_recursive_servers: + * [ { address_data : 2a04:b900:0:100::37 + * , tsig_name : hmac-md5.tsigs.getdnsapi.net. + * , tsig_algorithm: hmac-md5.sig-alg.reg.int. + * , tsig_secret : 0xD7A1BAF4E4DE5D6EB149 + * } ] + * } + * + * @param bindata The returned getdns_bindata. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + */ +getdns_return_t +getdns_str2bindata(const char *str, getdns_bindata **bindata); + +/** + * Convert string text to a getdns 32 bits unsigned integer. + * + * @param str A textual representation of the integer. + * The format is similar, but not precisely JSON. + * - integer values may be given by the constant name. + * For example: `{ resolution_type: GETDNS_RESOLUTION_STUB }` + * or `{ specify_class: GETDNS_RRCLASS_CH }` + * @param value The returned integer. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + */ +getdns_return_t +getdns_str2int(const char *str, uint32_t *value); + +/** + * Configure a context with settings given in a getdns_dict. + * + * @param context The context to be configured. + * @param config_dict The getdns_dict containing the settings. + * The settings have the same name as returned by the + * getdns_context_get_api_information() function, or as + * used in the names of the getdns_context_get_*() and + * getdns_context_set_*() functions. + * - The dict returned by + * getdns_context_get_api_information() can be used + * as the config_dict directly, but context settings + * do *not* have to be below a `"all_context"` key. + * - It is possible to set default values for extensions + * that could otherwise only be given on a per query + * basis. For example: + * `{ dnssec_return_status: GETDNS_EXTENSION_TRUE }` is + * equivalent to using the + * getdns_context_set_return_dnssec_status() function + * with that value, but default values for the other + * extensions can be set by this method now too. + * For example + * `{ return_call_reporting: GETDNS_EXTENSION_TRUE}` + * - Trust anchor files and root hints content can also be + * given by file, for example: + * + * { dns_root_servers : "named.root" + * , dnssec_trust_anchors: "/etc/unbound/getdns-root.key" + * } + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + * **Beware** that context might be partially configured on error. For retry + * strategies it is advised to recreate a new config. + */ +getdns_return_t +getdns_context_config(getdns_context *context, const getdns_dict *config_dict); + + +/** + * The user defined request handler that will be called on incoming requests. + */ +typedef void (*getdns_request_handler_t)( + getdns_context *context, + getdns_callback_type_t callback_type, + getdns_dict *request, + void *userarg, + getdns_transaction_t request_id +); + +/** + * Create a name server by registering a list of addresses to listen on and + * a user defined function that will handle the requests. + * + * @param context The context managing the eventloop that needs to be run to + * start serving. + * @param listen_addresses A list of address dicts or bindatas that will be + * listened on for DNS requests. Both UDP and TCP + * transports will be used. + * @param userarg A user defined argument that will be passed to the handler + * untouched. + * @param handler The user defined request handler that will be called with the + * request received in reply dict format. To reply to this request + * the function has to construct a response (or modify the request) + * and call getdns_reply() with the response and the with the request + * associated request_id. The user is responsible of destroying + * both the replies and the response. **Beware** that if requests are + * not answered by the function, by not calling getdns_reply() this + * will cause a memory leak. The user most use getdns_reply() + * with NULL as the response to not answer/cancel a request. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + * On failure, the current set of listening addresses is left in place. + * Also, if there is overlap in listening_addresses between the active set + * and the newly given set, the ones in the active set will remain in their + * current condition and will not be closed and reopened, also all assoicated + * DNS transactions will remain. + */ +getdns_return_t +getdns_context_set_listen_addresses( + getdns_context *context, const getdns_list *listen_addresses, + void *userarg, getdns_request_handler_t handler); + +/** + * Answer the request associated with a request_id that is received by a + * request handler + * + * @param context The context managing the eventloop that needs to be run to + * listen for and answer requests. + * @param reply The answer in getdns reply dict or response dict format. + * When NULL is given as reply, the request is not answered + * but all associated state is deleted. + * @param request_id The identifier that links this response with the + * received request. + * @return GETDNS_RETURN_GOOD on success or an error code on failure. + * On fatal failure (no retry strategy possible) the user still needs to + * cancel the request by recalling getdns_reply() but with NULL as response, + * to clean up state. + */ +getdns_return_t +getdns_reply(getdns_context *context, + getdns_dict *reply, getdns_transaction_t request_id); + + /** @} */ @@ -918,7 +1108,6 @@ getdns_return_t getdns_strerror(getdns_return_t err, char *buf, size_t buflen); */ /** @} */ - /** @} */ diff --git a/src/test/jsmn b/src/jsmn similarity index 100% rename from src/test/jsmn rename to src/jsmn diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 2eb8e381..6e3cb128 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -1,6 +1,7 @@ getdns_address getdns_address_sync getdns_cancel_callback +getdns_context_config getdns_context_create getdns_context_create_with_extended_memory_functions getdns_context_create_with_memory_functions @@ -50,6 +51,7 @@ getdns_context_set_extended_memory_functions getdns_context_set_follow_redirects getdns_context_set_idle_timeout getdns_context_set_limit_outstanding_queries +getdns_context_set_listen_addresses getdns_context_set_memory_functions getdns_context_set_namespaces getdns_context_set_resolution_type @@ -123,6 +125,7 @@ getdns_print_json_dict getdns_print_json_list getdns_pubkey_pin_create_from_string getdns_pubkey_pinset_sanity_check +getdns_reply getdns_root_trust_anchor getdns_rr_dict2str getdns_rr_dict2str_buf @@ -134,6 +137,10 @@ getdns_service getdns_service_sync getdns_snprint_json_dict getdns_snprint_json_list +getdns_str2bindata +getdns_str2dict +getdns_str2int +getdns_str2list getdns_str2rr_dict getdns_strerror getdns_validate_dnssec diff --git a/src/mk-const-info.c.sh b/src/mk-const-info.c.sh index 9e8b2826..f9c54323 100755 --- a/src/mk-const-info.c.sh +++ b/src/mk-const-info.c.sh @@ -46,18 +46,20 @@ getdns_get_errorstr_by_id(uint16_t err) else return NULL; } -END_OF_TAIL -gawk 'BEGIN{p=1}{if(p)print}/^static struct const_name_info consts_name_info\[\] = {$/{p=0}' test/getdns_str2dict.c > test/new-getdns_str2dict.c -gawk '/^[ ]+GETDNS_[A-Z_]+[ ]+=[ ]+[0-9]+/{ key = sprintf("%d", $3); consts[$1] = key; }/^#define GETDNS_[A-Z_]+[ ]+[0-9]+/ && !/_TEXT/{ key = sprintf("%d", $3); consts[$2] = key; }/^#define GETDNS_[A-Z_]+[ ]+\(\(getdns_(return|append_name)_t) [0-9]+ \)/{ key = sprintf("%d", $4); consts[$2] = key; }END{ n = asorti(consts, const_vals); for ( i = 1; i <= n; i++) { val = const_vals[i]; name = consts[val]; print "\t{ \""val"\", "name" },"}}' getdns/getdns.h.in getdns/getdns_extra.h.in | sed 's/,,/,/g' >> test/new-getdns_str2dict.c -cat >> test/new-getdns_str2dict.c << END_OF_TAIL +static struct const_name_info consts_name_info[] = { +END_OF_TAIL +gawk '/^[ ]+GETDNS_[A-Z_]+[ ]+=[ ]+[0-9]+/{ key = sprintf("%d", $3); consts[$1] = key; }/^#define GETDNS_[A-Z_]+[ ]+[0-9]+/ && !/_TEXT/{ key = sprintf("%d", $3); consts[$2] = key; }/^#define GETDNS_[A-Z_]+[ ]+\(\(getdns_(return|append_name)_t) [0-9]+ \)/{ key = sprintf("%d", $4); consts[$2] = key; }END{ n = asorti(consts, const_vals); for ( i = 1; i <= n; i++) { val = const_vals[i]; name = consts[val]; print "\t{ \""val"\", "name" },"}}' getdns/getdns.h.in getdns/getdns_extra.h.in | sed 's/,,/,/g' >> const-info.c +cat >> const-info.c << END_OF_TAIL }; + static int const_name_info_cmp(const void *a, const void *b) { return strcmp( ((struct const_name_info *) a)->name , ((struct const_name_info *) b)->name ); } -static int + +int _getdns_get_const_name_info(const char *name, uint32_t *code) { struct const_name_info key = { name, 0 }; @@ -71,5 +73,4 @@ _getdns_get_const_name_info(const char *name, uint32_t *code) return 1; } END_OF_TAIL -mv test/new-getdns_str2dict.c test/getdns_str2dict.c diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index db60fbc8..89ba5d86 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -382,10 +382,10 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset, X509_STORE_CTX *store) { getdns_return_t ret = GETDNS_RETURN_GENERIC_ERROR; - X509 *x; + X509 *x, *prev; int i, len; unsigned char raw[4096]; - unsigned char *next = raw; + unsigned char *next; unsigned char buf[sizeof(pinset->pin)]; const sha256_pin_t *p; @@ -407,33 +407,45 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset, /* TODO: how do we handle raw public keys? */ - for (i = 0; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)); i++) { - if (i > 0) { - /* TODO: how do we ensure that the certificates in - * each stage appropriately sign the previous one? - * for now, to be safe, we only examine the end-entity - * cert: */ - return GETDNS_RETURN_GENERIC_ERROR; - } + for (i = 0; i < sk_X509_num(X509_STORE_CTX_get0_untrusted(store)); i++, prev = x) { x = sk_X509_value(X509_STORE_CTX_get0_untrusted(store), i); #if defined(STUB_DEBUG) && STUB_DEBUG DEBUG_STUB("%s %-35s: Name of cert: %d ", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, i); + STUB_DEBUG_SETUP_TLS, __FUNC__, i); X509_NAME_print_ex_fp(stderr, X509_get_subject_name(x), 1, XN_FLAG_ONELINE); fprintf(stderr, "\n"); #endif + if (i > 0) { + /* we ensure that "prev" is signed by "x" */ + EVP_PKEY *pkey = X509_get_pubkey(x); + int verified; + if (!pkey) { + DEBUG_STUB("%s %-35s: Could not get pubkey from cert %d (%p)\n", + STUB_DEBUG_SETUP_TLS, __FUNC__, i, (void*)x); + return GETDNS_RETURN_GENERIC_ERROR; + } + verified = X509_verify(prev, pkey); + EVP_PKEY_free(pkey); + if (!verified) { + DEBUG_STUB("%s %-35s: cert %d (%p) was not signed by cert %d\n", + STUB_DEBUG_SETUP_TLS, __FUNC__, i-1, (void*)prev, i); + return GETDNS_RETURN_GENERIC_ERROR; + } + } + /* digest the cert with sha256 */ len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL); if (len > (int)sizeof(raw)) { DEBUG_STUB("%s %-35s: Pubkey %d is larger than "PRIsz" octets\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, i, sizeof(raw)); + STUB_DEBUG_SETUP_TLS, __FUNC__, i, sizeof(raw)); continue; } + next = raw; i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &next); if (next - raw != len) { DEBUG_STUB("%s %-35s: Pubkey %d claimed it needed %d octets, really needed "PRIsz"\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, i, len, next - raw); + STUB_DEBUG_SETUP_TLS, __FUNC__, i, len, next - raw); continue; } SHA256(raw, len, buf); @@ -442,11 +454,11 @@ _getdns_verify_pinset_match(const sha256_pin_t *pinset, for (p = pinset; p; p = p->next) if (0 == memcmp(buf, p->pin, sizeof(p->pin))) { DEBUG_STUB("%s %-35s: Pubkey %d matched pin %p ("PRIsz")\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, i, p, sizeof(p->pin)); + STUB_DEBUG_SETUP_TLS, __FUNC__, i, (void*)p, sizeof(p->pin)); return GETDNS_RETURN_GOOD; } else DEBUG_STUB("%s %-35s: Pubkey %d did not match pin %p\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, i, p); + STUB_DEBUG_SETUP_TLS, __FUNC__, i, (void*)p); } return ret; diff --git a/src/request-internal.c b/src/request-internal.c index 4f2e7773..37ba93b4 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -85,20 +85,20 @@ getdns_dict *dnssec_ok_checking_disabled_avoid_roadblocks static int -is_extension_set(getdns_dict *extensions, const char *extension) +is_extension_set(getdns_dict *extensions, const char *name, int default_value) { getdns_return_t r; uint32_t value; - if (! extensions) - return 0; - else if (extensions == dnssec_ok_checking_disabled + if ( ! extensions + || extensions == dnssec_ok_checking_disabled || extensions == dnssec_ok_checking_disabled_roadblock_avoidance || extensions == dnssec_ok_checking_disabled_avoid_roadblocks) return 0; - r = getdns_dict_get_int(extensions, extension, &value); - return r == GETDNS_RETURN_GOOD && value == GETDNS_EXTENSION_TRUE; + r = getdns_dict_get_int(extensions, name, &value); + return r == GETDNS_RETURN_GOOD ? ( value == GETDNS_EXTENSION_TRUE ) + : default_value; } static void @@ -177,11 +177,10 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, net_req->fd = -1; net_req->transport_current = 0; memset(&net_req->event, 0, sizeof(net_req->event)); - memset(&net_req->tcp, 0, sizeof(net_req->tcp)); net_req->keepalive_sent = 0; net_req->write_queue_tail = NULL; /* Some fields to record info for return_call_reporting */ - net_req->debug_tls_auth_status = 0; + net_req->debug_tls_auth_status = GETDNS_AUTH_NONE; net_req->debug_udp = 0; if (max_query_sz == 0) { @@ -206,6 +205,9 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner, buf = netreq_reset(net_req); gldns_buffer_init_frm_data( &gbuf, net_req->query, net_req->wire_data_sz - 2); + if (owner->context->header) + _getdns_reply_dict2wire(owner->context->header, &gbuf, 1); + gldns_buffer_rewind(&gbuf); _getdns_reply_dict2wire(extensions, &gbuf, 1); if (dnssec_extension_set) /* We will do validation ourselves */ GLDNS_CD_SET(net_req->query); @@ -472,7 +474,7 @@ _getdns_network_validate_tsig(getdns_network_req *req) HMAC_CTX ctx_space; #endif - DEBUG_STUB("%s %-35s: Validate TSIG\n", STUB_DEBUG_TSIG, __FUNCTION__); + DEBUG_STUB("%s %-35s: Validate TSIG\n", STUB_DEBUG_TSIG, __FUNC__); for ( rr = _getdns_rr_iter_init(&rr_spc, req->query, (req->response - req->query)) ; rr @@ -489,7 +491,7 @@ _getdns_network_validate_tsig(getdns_network_req *req) if (request_mac_len != rdf->nxt - rdf->pos - 2) return; DEBUG_STUB("%s %-35s: Request MAC found length %d\n", - STUB_DEBUG_TSIG, __FUNCTION__, (int)(request_mac_len)); + STUB_DEBUG_TSIG, __FUNC__, (int)(request_mac_len)); request_mac = rdf->pos + 2; @@ -546,7 +548,7 @@ _getdns_network_validate_tsig(getdns_network_req *req) if (response_mac_len != rdf->nxt - rdf->pos - 2) return; DEBUG_STUB("%s %-35s: Response MAC found length: %d\n", - STUB_DEBUG_TSIG, __FUNCTION__, (int)(response_mac_len)); + STUB_DEBUG_TSIG, __FUNC__, (int)(response_mac_len)); response_mac = rdf->pos + 2; if (!(rdf = _getdns_rdf_iter_next(rdf)) || @@ -571,7 +573,7 @@ _getdns_network_validate_tsig(getdns_network_req *req) /* TSIG found */ DEBUG_STUB("%s %-35s: TSIG found, original ID: %d\n", - STUB_DEBUG_TSIG, __FUNCTION__, (int)original_id); + STUB_DEBUG_TSIG, __FUNC__, (int)original_id); gldns_write_uint16(req->response + 10, gldns_read_uint16(req->response + 10) - 1); @@ -612,7 +614,7 @@ _getdns_network_validate_tsig(getdns_network_req *req) HMAC_Final(ctx, result_mac, &result_mac_len); DEBUG_STUB("%s %-35s: Result MAC length: %d\n", - STUB_DEBUG_TSIG, __FUNCTION__, (int)(result_mac_len)); + STUB_DEBUG_TSIG, __FUNC__, (int)(result_mac_len)); if (result_mac_len == response_mac_len && memcmp(result_mac, response_mac, result_mac_len) == 0) req->tsig_status = GETDNS_DNSSEC_SECURE; @@ -658,28 +660,32 @@ getdns_dns_req * _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, const char *name, uint16_t request_type, getdns_dict *extensions) { - int dnssec_return_status - = context->return_dnssec_status == GETDNS_EXTENSION_TRUE - || is_extension_set(extensions, "dnssec_return_status"); - int dnssec_return_only_secure - = is_extension_set(extensions, "dnssec_return_only_secure"); - int dnssec_return_all_statuses - = is_extension_set(extensions, "dnssec_return_all_statuses"); - int dnssec_return_full_validation_chain - = is_extension_set(extensions, "dnssec_return_full_validation_chain"); - int dnssec_return_validation_chain - = is_extension_set(extensions, "dnssec_return_validation_chain"); - int edns_cookies - = is_extension_set(extensions, "edns_cookies"); + int dnssec_return_status = is_extension_set( + extensions, "dnssec_return_status", + context->dnssec_return_status); + int dnssec_return_only_secure = is_extension_set( + extensions, "dnssec_return_only_secure", + context->dnssec_return_only_secure); + int dnssec_return_all_statuses = is_extension_set( + extensions, "dnssec_return_all_statuses", + context->dnssec_return_all_statuses); + int dnssec_return_full_validation_chain = is_extension_set( + extensions, "dnssec_return_full_validation_chain", + context->dnssec_return_full_validation_chain); + int dnssec_return_validation_chain = is_extension_set( + extensions, "dnssec_return_validation_chain", + context->dnssec_return_validation_chain); + int edns_cookies = is_extension_set( + extensions, "edns_cookies", + context->edns_cookies); #ifdef DNSSEC_ROADBLOCK_AVOIDANCE int avoid_dnssec_roadblocks = (extensions == dnssec_ok_checking_disabled_avoid_roadblocks); - int dnssec_roadblock_avoidance - = is_extension_set(extensions, "dnssec_roadblock_avoidance") + int dnssec_roadblock_avoidance = avoid_dnssec_roadblocks || (extensions == dnssec_ok_checking_disabled_roadblock_avoidance) - || avoid_dnssec_roadblocks; + || is_extension_set(extensions, "dnssec_roadblock_avoidance", + context->dnssec_roadblock_avoidance); #endif - int dnssec_extension_set = dnssec_return_status || dnssec_return_only_secure || dnssec_return_all_statuses || dnssec_return_validation_chain @@ -713,9 +719,9 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, int with_opt; getdns_dns_req *result = NULL; - uint32_t klass = GLDNS_RR_CLASS_IN; - int a_aaaa_query = - is_extension_set(extensions, "return_both_v4_and_v6") && + uint32_t klass = context->specify_class; + int a_aaaa_query = is_extension_set(extensions, + "return_both_v4_and_v6", context->return_both_v4_and_v6) && ( request_type == GETDNS_RRTYPE_A || request_type == GETDNS_RRTYPE_AAAA ); /* Reserve for the buffer at least one more byte @@ -732,7 +738,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, have_add_opt_parameters = getdns_dict_get_dict(extensions, "add_opt_parameters", &add_opt_parameters) == GETDNS_RETURN_GOOD; - + if (!have_add_opt_parameters && context->add_opt_parameters) { + add_opt_parameters = context->add_opt_parameters; + have_add_opt_parameters = 1; + } if (dnssec_extension_set) { edns_maximum_udp_payload_size = -1; edns_extended_rcode = 0; @@ -746,17 +755,26 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, edns_do_bit = context->edns_do_bit; if (have_add_opt_parameters) { - if (!getdns_dict_get_int(add_opt_parameters, + if (getdns_dict_get_int(add_opt_parameters, "maximum_udp_payload_size", - &get_edns_maximum_udp_payload_size)) + &get_edns_maximum_udp_payload_size)) { + if (!getdns_dict_get_int( + add_opt_parameters, "udp_payload_size", + &get_edns_maximum_udp_payload_size)) + edns_maximum_udp_payload_size = + get_edns_maximum_udp_payload_size; + } else edns_maximum_udp_payload_size = get_edns_maximum_udp_payload_size; + (void) getdns_dict_get_int(add_opt_parameters, "extended_rcode", &edns_extended_rcode); (void) getdns_dict_get_int(add_opt_parameters, "version", &edns_version); - (void) getdns_dict_get_int(add_opt_parameters, - "do_bit", &edns_do_bit); + if (getdns_dict_get_int(add_opt_parameters, + "do_bit", &edns_do_bit)) + (void) getdns_dict_get_int( + add_opt_parameters, "do", &edns_do_bit); } } if (have_add_opt_parameters && getdns_dict_get_list( @@ -895,10 +913,10 @@ _getdns_dns_req_new(getdns_context *context, getdns_eventloop *loop, #endif result->edns_client_subnet_private = context->edns_client_subnet_private; result->tls_query_padding_blocksize = context->tls_query_padding_blocksize; - result->return_call_reporting = - is_extension_set(extensions, "return_call_reporting"); - result->add_warning_for_bad_dns = - is_extension_set(extensions, "add_warning_for_bad_dns"); + result->return_call_reporting = is_extension_set(extensions, + "return_call_reporting" , context->return_call_reporting); + result->add_warning_for_bad_dns = is_extension_set(extensions, + "add_warning_for_bad_dns", context->add_warning_for_bad_dns); /* will be set by caller */ result->user_pointer = NULL; diff --git a/src/rr-iter.h b/src/rr-iter.h index eae61012..d440d939 100644 --- a/src/rr-iter.h +++ b/src/rr-iter.h @@ -76,7 +76,7 @@ _getdns_rr_iter *_getdns_single_rr_iter_init(_getdns_rr_iter *i, const uint8_t *wire, const size_t wire_len); static inline _getdns_rr_iter *_getdns_rr_iter_rewind(_getdns_rr_iter *i) -{ return _getdns_rr_iter_init(i, i->pkt, i->pkt_end - i->pkt); } +{ return i ? _getdns_rr_iter_init(i, i->pkt, i->pkt_end - i->pkt) : NULL; } _getdns_rr_iter *_getdns_rr_iter_next(_getdns_rr_iter *i); @@ -181,7 +181,7 @@ static inline _getdns_rrset *_getdns_rrset_iter_value(_getdns_rrset_iter *i) { return i && i->rr_i.pos ? &i->rrset : NULL; } static inline _getdns_rrset_iter *_getdns_rrset_iter_rewind(_getdns_rrset_iter *i) -{ return _getdns_rrset_iter_init(i, i->rrset.pkt, i->rrset.pkt_len, i->rrset.sections); } +{ return i ? _getdns_rrset_iter_init(i, i->rrset.pkt, i->rrset.pkt_len, i->rrset.sections) : NULL; } typedef struct _getdns_rdf_iter { const uint8_t *pkt; diff --git a/src/test/getdns_context_set_listen_addresses.c b/src/server.c similarity index 81% rename from src/test/getdns_context_set_listen_addresses.c rename to src/server.c index 03ac6340..968564e8 100644 --- a/src/test/getdns_context_set_listen_addresses.c +++ b/src/server.c @@ -26,11 +26,20 @@ */ #include "config.h" -#include "getdns_context_set_listen_addresses.h" + +#ifndef USE_WINSOCK +#include +#else +#include +#include +#endif + #include "getdns/getdns_extra.h" +#include "context.h" #include "types-internal.h" #include "debug.h" -#include +#include "util/rbtree.h" +#include "server.h" #define DNS_REQUEST_SZ 4096 #define DOWNSTREAM_IDLE_TIMEOUT 5000 @@ -63,9 +72,10 @@ struct listener { */ struct listen_set { getdns_context *context; - listen_set *next; + void *userarg; getdns_request_handler_t handler; + _getdns_rbtree_t connections_set; size_t count; listener items[]; }; @@ -79,6 +89,9 @@ struct tcp_to_write { }; struct connection { + /* struct connection is a sub struct of _getdns_rbnode_t */ + _getdns_rbnode_t super; + listener *l; struct sockaddr_storage remote_in; socklen_t addrlen; @@ -88,14 +101,8 @@ struct connection { }; typedef struct tcp_connection { - /* A TCP connection is a connection */ - listener *l; - struct sockaddr_storage remote_in; - socklen_t addrlen; - - connection *next; - connection **prev_next; - /************************************/ + /* struct tcp_connection is a sub struct of connection */ + connection super; int fd; getdns_eventloop_event event; @@ -118,10 +125,10 @@ static void tcp_connection_destroy(tcp_connection *conn) tcp_to_write *cur, *next; - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + 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) @@ -139,10 +146,14 @@ static void tcp_connection_destroy(tcp_connection *conn) return; /* Unlink this connection */ - if ((*conn->prev_next = conn->next)) - conn->next->prev_next = conn->prev_next; + (void) _getdns_rbtree_delete( + &conn->super.l->set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)conn->super.l->set->connections_set.count); + if ((*conn->super.prev_next = conn->super.next)) + conn->super.next->prev_next = conn->super.prev_next; - free_listen_set_when_done(conn->l->set); + free_listen_set_when_done(conn->super.l->set); GETDNS_FREE(*mf, conn); } @@ -157,10 +168,10 @@ static void tcp_write_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + if (getdns_context_get_eventloop(conn->super.l->set->context, &loop)) return; /* Reset tcp_connection idle timeout */ @@ -195,28 +206,30 @@ static void tcp_write_cb(void *userarg) DOWNSTREAM_IDLE_TIMEOUT, &conn->event); } -void -_getdns_cancel_reply(getdns_context *context, getdns_transaction_t request_id) +static void +_getdns_cancel_reply(getdns_context *context, connection *conn) { - /* TODO: Check request_id at context->outbound_requests */ - connection *conn = (connection *)(intptr_t)request_id; struct mem_funcs *mf; if (!context || !conn) return; if (conn->l->transport == GETDNS_TRANSPORT_TCP) { - tcp_connection *conn = (tcp_connection *)(intptr_t)request_id; + tcp_connection *tcp_conn = (tcp_connection *)conn; - if (conn->to_answer > 0 && --conn->to_answer == 0 && - conn->fd == -1) - tcp_connection_destroy(conn); + if (tcp_conn->to_answer > 0 && --tcp_conn->to_answer == 0 && + tcp_conn->fd == -1) + tcp_connection_destroy(tcp_conn); } else if (conn->l->transport == GETDNS_TRANSPORT_UDP && - (mf = priv_getdns_context_mf(conn->l->set->context))) { + (mf = &conn->l->set->context->mf)) { listen_set *set = conn->l->set; /* Unlink this connection */ + (void) _getdns_rbtree_delete( + &set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; GETDNS_FREE(*mf, conn); @@ -226,7 +239,7 @@ _getdns_cancel_reply(getdns_context *context, getdns_transaction_t request_id) getdns_return_t getdns_reply( - getdns_context *context, getdns_transaction_t request_id, getdns_dict *reply) + getdns_context *context, getdns_dict *reply, getdns_transaction_t request_id) { /* TODO: Check request_id at context->outbound_requests */ connection *conn = (connection *)(intptr_t)request_id; @@ -236,10 +249,21 @@ getdns_reply( size_t len; getdns_return_t r; - if (!context || !reply || !conn) + if (!context || !conn) return GETDNS_RETURN_INVALID_PARAMETER; - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!context->server) + return GETDNS_RETURN_GENERIC_ERROR;; + + if (_getdns_rbtree_search(&context->server->connections_set, conn) + != &conn->super) + return GETDNS_RETURN_NO_SUCH_LIST_ITEM; + + if (!reply) { + _getdns_cancel_reply(context, conn); + return GETDNS_RETURN_GOOD; + } + if (!(mf = &conn->l->set->context->mf)) return GETDNS_RETURN_GENERIC_ERROR;; if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop))) @@ -252,7 +276,7 @@ getdns_reply( else if (conn->l->transport == GETDNS_TRANSPORT_UDP) { listener *l = conn->l; - if (conn->l->fd >= 0 && sendto(conn->l->fd, buf, len, 0, + if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0, (struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) { /* IO error, cleanup this listener */ loop->vmt->clear(loop, &conn->l->event); @@ -260,6 +284,10 @@ getdns_reply( conn->l->fd = -1; } /* Unlink this connection */ + (void) _getdns_rbtree_delete( + &l->set->connections_set, conn); + DEBUG_SERVER("[connection del] count: %d\n", + (int)l->set->connections_set.count); if ((*conn->prev_next = conn->next)) conn->next->prev_next = conn->prev_next; @@ -320,10 +348,10 @@ static void tcp_read_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(conn->l->set->context))) + if (!(mf = &conn->super.l->set->context->mf)) return; - if ((r = getdns_context_get_eventloop(conn->l->set->context, &loop))) + if ((r = getdns_context_get_eventloop(conn->super.l->set->context, &loop))) return; /* Reset tcp_connection idle timeout */ @@ -380,9 +408,14 @@ static void tcp_read_cb(void *userarg) else { conn->to_answer++; + /* TODO: wish list item: + * (void) getdns_dict_set_int64( + * request_dict, "request_id", intptr_t)conn); + */ /* Call request handler */ - conn->l->set->handler( - conn->l->set->context, request_dict, (intptr_t)conn); + conn->super.l->set->handler( + conn->super.l->set->context, GETDNS_CALLBACK_COMPLETE, + request_dict, conn->super.l->set->userarg, (intptr_t)conn); conn->read_pos = conn->read_buf; conn->to_read = 2; @@ -402,7 +435,8 @@ static void tcp_timeout_cb(void *userarg) if (conn->to_answer) { getdns_eventloop *loop; - if (getdns_context_get_eventloop(conn->l->set->context, &loop)) + if (getdns_context_get_eventloop( + conn->super.l->set->context, &loop)) return; loop->vmt->clear(loop, &conn->event); @@ -423,7 +457,7 @@ static void tcp_accept_cb(void *userarg) assert(userarg); - if (!(mf = priv_getdns_context_mf(l->set->context))) + if (!(mf = &l->set->context->mf)) return; if ((r = getdns_context_get_eventloop(l->set->context, &loop))) @@ -433,11 +467,10 @@ static void tcp_accept_cb(void *userarg) return; (void) memset(conn, 0, sizeof(tcp_connection)); - - conn->l = l; - conn->addrlen = sizeof(conn->remote_in); - if ((conn->fd = accept(l->fd, - (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { + conn->super.l = l; + conn->super.addrlen = sizeof(conn->super.remote_in); + if ((conn->fd = accept(l->fd, (struct sockaddr *) + &conn->super.remote_in, &conn->super.addrlen)) == -1) { /* IO error, cleanup this listener */ loop->vmt->clear(loop, &l->event); close(l->fd); @@ -458,10 +491,20 @@ static void tcp_accept_cb(void *userarg) conn->event.timeout_cb = tcp_timeout_cb; /* Insert connection */ - if ((conn->next = l->connections)) - conn->next->prev_next = &conn->next; - conn->prev_next = &l->connections; + conn->super.super.key = conn; + if (!_getdns_rbtree_insert( + &l->set->connections_set, &conn->super.super)) { + /* Memory error */ + GETDNS_FREE(*mf, conn); + return; + } + DEBUG_SERVER("[connection add] count: %d\n", + (int)l->set->connections_set.count); + if ((conn->super.next = l->connections)) + conn->super.next->prev_next = &conn->super.next; + conn->super.prev_next = &l->connections; l->connections = (connection *)conn; + (void) loop->vmt->schedule(loop, conn->fd, DOWNSTREAM_IDLE_TIMEOUT, &conn->event); @@ -485,7 +528,7 @@ static void udp_read_cb(void *userarg) if (l->fd == -1) return; - if (!(mf = priv_getdns_context_mf(l->set->context))) + if (!(mf = &l->set->context->mf)) return; if ((r = getdns_context_get_eventloop(l->set->context, &loop))) @@ -496,7 +539,7 @@ static void udp_read_cb(void *userarg) conn->l = l; conn->addrlen = sizeof(conn->remote_in); - if ((len = recvfrom(l->fd, buf, sizeof(buf), 0, + if ((len = recvfrom(l->fd, (void *)buf, sizeof(buf), 0, (struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) { /* IO error, cleanup this listener. */ loop->vmt->clear(loop, &l->event); @@ -574,37 +617,33 @@ static void udp_read_cb(void *userarg) else { /* Insert connection */ + conn->super.key = conn; + if (!_getdns_rbtree_insert( + &l->set->connections_set, &conn->super)) { + /* Memory error */ + GETDNS_FREE(*mf, conn); + return; + } + DEBUG_SERVER("[connection add] count: %d\n", + (int)l->set->connections_set.count); if ((conn->next = l->connections)) conn->next->prev_next = &conn->next; conn->prev_next = &l->connections; l->connections = conn; + /* TODO: wish list item: + * (void) getdns_dict_set_int64( + * request_dict, "request_id", (intptr_t)conn); + */ /* Call request handler */ - l->set->handler(l->set->context, request_dict, (intptr_t)conn); + l->set->handler(l->set->context, GETDNS_CALLBACK_COMPLETE, + request_dict, l->set->userarg, (intptr_t)conn); + return; } GETDNS_FREE(*mf, conn); } -static void rm_listen_set(listen_set **root, listen_set *set) -{ - assert(root); - - while (*root && *root != set) - root = &(*root)->next; - - *root = set->next; - set->next = NULL; -} - -static listen_set *lookup_listen_set(listen_set *root, getdns_context *key) -{ - while (root && root->context != key) - root = root->next; - - return root; -} - static void free_listen_set_when_done(listen_set *set) { struct mem_funcs *mf; @@ -613,10 +652,10 @@ static void free_listen_set_when_done(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return; - DEBUG_SERVER("To free listen set: %p\n", set); + DEBUG_SERVER("To free listen set: %p\n", (void *)set); for (i = 0; i < set->count; i++) { listener *l = &set->items[i]; @@ -627,7 +666,7 @@ static void free_listen_set_when_done(listen_set *set) return; } GETDNS_FREE(*mf, set); - DEBUG_SERVER("Listen set: %p freed\n", set); + DEBUG_SERVER("Listen set: %p freed\n", (void *)set); } static void remove_listeners(listen_set *set) @@ -639,7 +678,7 @@ static void remove_listeners(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return; if (getdns_context_get_eventloop(set->context, &loop)) @@ -663,7 +702,8 @@ static void remove_listeners(listen_set *set) while (*conn_p) { tcp_connection_destroy(*conn_p); if (*conn_p && (*conn_p)->to_answer > 0) - conn_p = (tcp_connection **)&(*conn_p)->next; + conn_p = (tcp_connection **) + &(*conn_p)->super.next; } } free_listen_set_when_done(set); @@ -671,7 +711,11 @@ static void remove_listeners(listen_set *set) static getdns_return_t add_listeners(listen_set *set) { +#ifdef USE_WINSOCK + static const char enable = 1; +#else static const int enable = 1; +#endif struct mem_funcs *mf; getdns_eventloop *loop; @@ -681,7 +725,7 @@ static getdns_return_t add_listeners(listen_set *set) assert(set); assert(set->context); - if (!(mf = priv_getdns_context_mf(set->context))) + if (!(mf = &set->context->mf)) return GETDNS_RETURN_GENERIC_ERROR; if ((r = getdns_context_get_eventloop(set->context, &loop))) @@ -738,17 +782,21 @@ static getdns_return_t add_listeners(listen_set *set) return GETDNS_RETURN_GOOD; } -getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, - getdns_request_handler_t request_handler, - const getdns_list *listen_addresses) +static int +ptr_cmp(const void *a, const void *b) +{ + return a == b ? 0 : (a < b ? -1 : 1); +} + +getdns_return_t getdns_context_set_listen_addresses( + getdns_context *context, const getdns_list *listen_addresses, + void *userarg, getdns_request_handler_t request_handler) { static const getdns_transport_list_t listen_transports[] = { GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP }; static const uint32_t transport_ports[] = { 53, 53 }; static const size_t n_transports = sizeof( listen_transports) / sizeof(*listen_transports); - static listen_set *root = NULL; - listen_set *current_set; listen_set *new_set; size_t new_set_count; @@ -761,9 +809,10 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, size_t i; struct addrinfo hints; - DEBUG_SERVER("getdns_context_set_listen_addresses(%p, %p, %p)\n", context, request_handler, - listen_addresses); - if (!(mf = priv_getdns_context_mf(context))) + DEBUG_SERVER("getdns_context_set_listen_addresses(%p, , %p)\n", + (void *)context, (void *)listen_addresses); + + if (!(mf = &context->mf)) return GETDNS_RETURN_GENERIC_ERROR; if ((r = getdns_context_get_eventloop(context, &loop))) @@ -775,7 +824,7 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, else if ((r = getdns_list_get_length(listen_addresses, &new_set_count))) return r; - if ((current_set = lookup_listen_set(root, context))) { + if ((current_set = context->server)) { for (i = 0; i < current_set->count; i++) current_set->items[i].action = to_remove; } @@ -783,7 +832,7 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, if (!current_set) return GETDNS_RETURN_GOOD; - rm_listen_set(&root, current_set); + context->server = NULL; /* action is already to_remove */ remove_listeners(current_set); return GETDNS_RETURN_GOOD; @@ -796,11 +845,14 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, sizeof(listener) * new_set_count * n_transports))) return GETDNS_RETURN_MEMORY_ERROR; - DEBUG_SERVER("New listen set: %p, current_set: %p\n", new_set, current_set); + _getdns_rbtree_init(&new_set->connections_set, ptr_cmp); + + DEBUG_SERVER("New listen set: %p, current_set: %p\n", + (void *)new_set, (void *)current_set); new_set->context = context; - new_set->next = root; new_set->handler = request_handler; + new_set->userarg = userarg; new_set->count = new_set_count * n_transports; (void) memset(new_set->items, 0, sizeof(listener) * new_set_count * n_transports); @@ -940,10 +992,10 @@ getdns_return_t getdns_context_set_listen_addresses(getdns_context *context, } } if (current_set) { - rm_listen_set(&root, current_set); + context->server = NULL; remove_listeners(current_set); /* Is already remove */ } - root = new_set; + context->server = new_set; return GETDNS_RETURN_GOOD; } diff --git a/src/test/getdns_context_config.h b/src/server.h similarity index 82% rename from src/test/getdns_context_config.h rename to src/server.h index 7252f367..f60f267e 100644 --- a/src/test/getdns_context_config.h +++ b/src/server.h @@ -1,3 +1,11 @@ +/** + * \file server.h + * @brief Functions for serving requests + * + * getdns_context_set_listen_addresses() and getdns_reply() are implemented + * here. + */ + /* * Copyright (c) 2013, NLNet Labs, Verisign, Inc. * All rights reserved. @@ -24,18 +32,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _GETDNS_SERVER_H_ +#define _GETDNS_SERVER_H_ -#include "getdns/getdns.h" - -#ifndef GETDNS_CONTEXT_CONFIG_H_ -#define GETDNS_CONTEXT_CONFIG_H_ - -/* -getdns_return_t getdns_context_config( - getdns_context *context, const getdns_dict *config_dict); - */ -getdns_return_t _getdns_context_config_(getdns_context *context, - getdns_dict *extensions, const getdns_dict *config_dict); - -#endif +struct listen_set; +#endif /* _GETDNS_SERVER_H_ */ diff --git a/src/stub.c b/src/stub.c index e047462e..9421f5d8 100644 --- a/src/stub.c +++ b/src/stub.c @@ -63,9 +63,11 @@ typedef u_short sa_family_t; * STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus * level triggered). See also lines containing WSA TODO below... */ +#define STUB_NO_AUTH -8 /* Existing TLS connection is not authenticated */ +#define STUB_CONN_GONE -7 /* Connection has failed, clear queue*/ #define STUB_TCP_WOULDBLOCK -6 #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ -#define STUB_TLS_SETUP_ERROR -4 +#define STUB_SETUP_ERROR -4 #define STUB_TCP_AGAIN -3 #define STUB_TCP_ERROR -2 @@ -85,6 +87,9 @@ static void upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq); static void upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout); +static int upstream_working_ok(getdns_upstream *upstream); +static int upstream_auth_status_ok(getdns_upstream *upstream, + getdns_network_req *netreq); static int upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_dns_req *dnsreq); @@ -246,8 +251,8 @@ match_edns_opt_rr(uint16_t code, uint8_t *response, size_t response_len, size_t data_len = rr_iter->nxt - rr_iter->pos; (void) gldns_wire2str_rr_scan( &data, &data_len, &str, &str_len, (uint8_t *)rr_iter->pkt, rr_iter->pkt_end - rr_iter->pkt); - DEBUG_STUB("%s %-35s: OPT RR: %s\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, str_spc); + DEBUG_STUB("%s %-35s: OPT RR: %s", + STUB_DEBUG_READ, __FUNC__, str_spc); #endif /* OPT found, now search for the specified option */ @@ -321,25 +326,36 @@ process_keepalive( int found = match_edns_opt_rr(GLDNS_EDNS_KEEPALIVE, response, response_len, &position, &option_len); if (found != 2 || option_len != 2) { - if (netreq->keepalive_sent == 1) - /* If no keepalive sent back, then we must use 0 idle timeout - as server does not support it.*/ -#if defined(KEEP_CONNECTIONS_OPEN_DEBUG) && KEEP_CONNECTIONS_OPEN_DEBUG - upstream->keepalive_timeout = netreq->owner->context->idle_timeout; -#else - upstream->keepalive_timeout = 0; + if (netreq->keepalive_sent == 1) { + /* For TCP if no keepalive sent back, then we must use 0 idle timeout + as server does not support it. TLS allows idle connections without + keepalive, according to RFC7858. */ +#if !defined(KEEP_CONNECTIONS_OPEN_DEBUG) || !KEEP_CONNECTIONS_OPEN_DEBUG + if (upstream->transport != GETDNS_TRANSPORT_TLS) + upstream->keepalive_timeout = 0; + else #endif + upstream->keepalive_timeout = netreq->owner->context->idle_timeout; + } return; } /* 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; + DEBUG_STUB("%s %-35s: FD: %d Server Keepalive recieved: %d ms\n", + STUB_DEBUG_READ, __FUNC__, upstream->fd, + (int)server_keepalive); if (netreq->owner->context->idle_timeout < server_keepalive) upstream->keepalive_timeout = netreq->owner->context->idle_timeout; else { + if (server_keepalive == 0) { + /* This means the server wants us to shut the connection (sending no + more queries). */ + upstream->keepalive_shutdown = 1; + } upstream->keepalive_timeout = server_keepalive; DEBUG_STUB("%s %-35s: FD: %d Server Keepalive used: %d ms\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd, + STUB_DEBUG_READ, __FUNC__, upstream->fd, (int)server_keepalive); } } @@ -368,12 +384,15 @@ static int tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) { int fd = -1; - DEBUG_STUB("%s %-35s: Creating TCP connection: %p\n", STUB_DEBUG_SETUP, - __FUNCTION__, upstream); + DEBUG_STUB("%s %-35s: Creating TCP connection: %p\n", STUB_DEBUG_SETUP, + __FUNC__, (void*)upstream); if ((fd = socket(upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) return -1; getdns_sock_nonblock(fd); + /* Note that error detection is different with TFO. Since the handshake + doesn't start till the sendto() lack of connection is often delayed until + then or even the subsequent event depending on the error and platform.*/ #ifdef USE_TCP_FASTOPEN /* Leave the connect to the later call to sendto() if using TCP*/ if (transport == GETDNS_TRANSPORT_TCP) @@ -414,29 +433,30 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport) static int tcp_connected(getdns_upstream *upstream) { - /* Already tried and failed, so let the fallback code take care of things */ - /* TODO: We _should_ use a timeout on the TCP handshake*/ - if (upstream->fd == -1 || upstream->tcp.write_error != 0) - return STUB_TCP_ERROR; - int error = 0; socklen_t len = (socklen_t)sizeof(error); getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len); #ifdef USE_WINSOCK if (error == WSAEINPROGRESS) - return STUB_TCP_WOULDBLOCK; + return STUB_TCP_AGAIN; else if (error == WSAEWOULDBLOCK) return STUB_TCP_WOULDBLOCK; else if (error != 0) - return STUB_TCP_ERROR; + return STUB_SETUP_ERROR; #else if (error == EINPROGRESS) - return STUB_TCP_WOULDBLOCK; + return STUB_TCP_AGAIN; else if (error == EWOULDBLOCK || error == EAGAIN) return STUB_TCP_WOULDBLOCK; - else if (error != 0) - return STUB_TCP_ERROR; + else if (error != 0) { + return STUB_SETUP_ERROR; + } #endif + if (upstream->transport == GETDNS_TRANSPORT_TCP && + upstream->queries_sent == 0) { + upstream->conn_state = GETDNS_CONN_OPEN; + upstream->conn_completed++; + } return 0; } @@ -452,19 +472,16 @@ stub_next_upstream(getdns_network_req *netreq) if (! --netreq->upstream->to_retry) netreq->upstream->to_retry = -(netreq->upstream->back_off *= 2); - /*[TLS]:TODO - This works because the next message won't try the exact - * same upstream (and the next message may not use the same transport), - * but the next message will find the next matching one thanks to logic in - * upstream_select, but this could be better */ - if (++dnsreq->upstreams->current >= dnsreq->upstreams->count) - dnsreq->upstreams->current = 0; + dnsreq->upstreams->current_udp+=GETDNS_UPSTREAM_TRANSPORTS; + if (dnsreq->upstreams->current_udp >= dnsreq->upstreams->count) + dnsreq->upstreams->current_udp = 0; } static void stub_cleanup(getdns_network_req *netreq) { DEBUG_STUB("%s %-35s: MSG: %p\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); + STUB_DEBUG_CLEANUP, __FUNC__, (void*)netreq); getdns_dns_req *dnsreq = netreq->owner; getdns_network_req *r, *prev_r; getdns_upstream *upstream; @@ -472,8 +489,6 @@ stub_cleanup(getdns_network_req *netreq) GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); - GETDNS_NULL_FREE(dnsreq->context->mf, netreq->tcp.read_buf); - /* Nothing globally scheduled? Then nothing queued */ if (!netreq->upstream || !(upstream = netreq->upstream)->event.ev) return; @@ -502,51 +517,52 @@ stub_cleanup(getdns_network_req *netreq) upstream_reschedule_events(upstream, upstream->keepalive_timeout); } -static int -tls_cleanup(getdns_upstream *upstream, int handshake_fail) -{ - DEBUG_STUB("%s %-35s: FD: %d\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); - if (upstream->tls_obj != NULL) - SSL_free(upstream->tls_obj); - upstream->tls_obj = NULL; - /* This will prevent the connection from being tried again for the cases - where we know it didn't work. Otherwise leave it to try again.*/ - if (handshake_fail) - upstream->tls_hs_state = GETDNS_HS_FAILED; - /* Reset timeout on failure*/ - GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); - GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, - getdns_eventloop_event_init(&upstream->event, upstream, - NULL, upstream_write_cb, NULL)); - return STUB_TLS_SETUP_ERROR; -} - static void -upstream_erred(getdns_upstream *upstream) +upstream_failed(getdns_upstream *upstream, int during_setup) { - DEBUG_STUB("%s %-35s: FD: %d\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); - getdns_network_req *netreq; - - while ((netreq = upstream->write_queue)) { - stub_cleanup(netreq); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); + DEBUG_STUB("%s %-35s: FD: %d During setup = %d\n", + STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd, during_setup); + /* Fallback code should take care of queue queries and then close conn + when idle.*/ + /* [TLS1]TODO: Work out how to re-open the connection and re-try + the queries if there is only one upstream.*/ + if (during_setup) { + /* Reset timeout on setup failure to trigger fallback handling.*/ + GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); + /* Need this check because if the setup failed because the interface is + not up we get -1 and then a seg fault. Found when using IPv6 address + but IPv6 interface not enabled.*/ + if (upstream->fd != -1) { + GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER, + getdns_eventloop_event_init(&upstream->event, upstream, + NULL, upstream_write_cb, NULL)); + } + /* 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++; + } else { + upstream->conn_shutdowns++; + /* [TLS1]TODO: Re-try these queries if possible.*/ + getdns_network_req *netreq; + while (upstream->netreq_by_query_id.count) { + netreq = (getdns_network_req *) + _getdns_rbtree_first(&upstream->netreq_by_query_id); + stub_cleanup(netreq); + netreq->state = NET_REQ_FINISHED; + _getdns_check_dns_req_complete(netreq->owner); + } } - while (upstream->netreq_by_query_id.count) { - netreq = (getdns_network_req *) - _getdns_rbtree_first(&upstream->netreq_by_query_id); - stub_cleanup(netreq); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); - } - _getdns_upstream_shutdown(upstream); + + upstream->conn_state = GETDNS_CONN_TEARDOWN; } void _getdns_cancel_stub_request(getdns_network_req *netreq) { + DEBUG_STUB("%s %-35s: MSG: %p\n", + STUB_DEBUG_CLEANUP, __FUNC__, (void*)netreq); stub_cleanup(netreq); if (netreq->fd >= 0) { #ifdef USE_WINSOCK @@ -557,47 +573,46 @@ _getdns_cancel_stub_request(getdns_network_req *netreq) } } -/* May be needed in future for better UDP error handling?*/ -/*static void -stub_erred(getdns_network_req *netreq) -{ - DEBUG_STUB("*** %s\n", __FUNCTION__); - stub_next_upstream(netreq); - stub_cleanup(netreq); - if (netreq->fd >= 0) close(netreq->fd); - netreq->state = NET_REQ_FINISHED; - _getdns_check_dns_req_complete(netreq->owner); -}*/ - static void stub_timeout_cb(void *userarg) { getdns_network_req *netreq = (getdns_network_req *)userarg; DEBUG_STUB("%s %-35s: MSG: %p\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); - stub_next_upstream(netreq); + STUB_DEBUG_CLEANUP, __FUNC__, (void*)netreq); stub_cleanup(netreq); - if (netreq->fd >= 0) + netreq->state = NET_REQ_TIMED_OUT; + /* Handle upstream*/ + if (netreq->fd >= 0) { #ifdef USE_WINSOCK closesocket(netreq->fd); #else close(netreq->fd); #endif - netreq->state = NET_REQ_TIMED_OUT; - if (netreq->owner->user_callback) { + netreq->upstream->udp_timeouts++; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + if (netreq->upstream->udp_timeouts % 100 == 0) + DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n", + STUB_DEBUG_DAEMON, netreq->upstream->addr_str, + (int)netreq->upstream->udp_responses, (int)netreq->upstream->udp_timeouts); +#endif + stub_next_upstream(netreq); + } else { + netreq->upstream->responses_timeouts++; + } + if (netreq->owner->user_callback) { netreq->debug_end_time = _getdns_get_time_as_uintt64(); + /* Note this calls cancel_request which calls stub_cleanup again....!*/ (void) _getdns_context_request_timed_out(netreq->owner); } else _getdns_check_dns_req_complete(netreq->owner); } - static void upstream_idle_timeout_cb(void *userarg) { getdns_upstream *upstream = (getdns_upstream *)userarg; DEBUG_STUB("%s %-35s: FD: %d Closing connection\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); + STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.timeout_cb = NULL; upstream->event.read_cb = NULL; @@ -606,13 +621,13 @@ upstream_idle_timeout_cb(void *userarg) } static void -upstream_tls_timeout_cb(void *userarg) +upstream_setup_timeout_cb(void *userarg) { getdns_upstream *upstream = (getdns_upstream *)userarg; DEBUG_STUB("%s %-35s: FD: %d\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, upstream->fd); + STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd); /* Clean up and trigger a write to let the fallback code to its job */ - tls_cleanup(upstream, 1); + upstream_failed(upstream, 1); /* Need to handle the case where the far end doesn't respond to a * TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853). @@ -627,38 +642,13 @@ upstream_tls_timeout_cb(void *userarg) tval.tv_usec = 0; ret = select(upstream->fd+1, NULL, &fds, NULL, &tval); if (ret == 0) { + DEBUG_STUB("%s %-35s: FD: %d Cleaning up dangling queue\n", + STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd); while (upstream->write_queue) upstream_write_cb(upstream); } } -static void -stub_tls_timeout_cb(void *userarg) -{ - getdns_network_req *netreq = (getdns_network_req *)userarg; - getdns_upstream *upstream = netreq->upstream; - DEBUG_STUB("%s %-35s: MSG: %p\n", - STUB_DEBUG_CLEANUP, __FUNCTION__, netreq); - /* Clean up and trigger a write to let the fallback code to its job */ - tls_cleanup(upstream, 0); - - /* Need to handle the case where the far end doesn't respond to a - * TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853). - * For that case the socket never becomes writable so doesn't trigger any - * callbacks. If so then clear out the queue in one go.*/ - int ret; - fd_set fds; - FD_ZERO(&fds); - FD_SET(FD_SET_T upstream->fd, &fds); - struct timeval tval; - tval.tv_sec = 0; - tval.tv_usec = 0; - ret = select(upstream->fd+1, NULL, &fds, NULL, &tval); - if (ret == 0) { - while (upstream->write_queue) - upstream_write_cb(upstream); - } -} /****************************/ /* TCP read/write functions */ @@ -769,11 +759,11 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq) if (netreq->owner->edns_client_subnet_private) if (attach_edns_client_subnet_private(netreq)) return STUB_OUT_OF_OPTIONS; - if (netreq->upstream->writes_done == 0 && + if (netreq->upstream->queries_sent == 0 && netreq->owner->context->idle_timeout != 0) { /* Add the keepalive option to the first query on this connection*/ DEBUG_STUB("%s %-35s: FD: %d Requesting keepalive \n", - STUB_DEBUG_WRITE, __FUNCTION__, fd); + STUB_DEBUG_WRITE, __FUNC__, fd); if (attach_edns_keepalive(netreq)) return STUB_OUT_OF_OPTIONS; netreq->keepalive_sent = 1; @@ -863,72 +853,71 @@ tls_requested(getdns_network_req *netreq) 1 : 0; } -static int -tls_should_write(getdns_upstream *upstream) -{ - /* Should messages be written on TLS upstream. */ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - upstream->tls_hs_state != GETDNS_HS_NONE) ? 1 : 0; -} - -static int -tls_should_read(getdns_upstream *upstream) -{ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - !(upstream->tls_hs_state == GETDNS_HS_FAILED || - upstream->tls_hs_state == GETDNS_HS_NONE)) ? 1 : 0; -} - -static int -tls_failed(getdns_upstream *upstream) -{ - /* No messages should be scheduled onto an upstream in this state */ - return ((upstream->transport == GETDNS_TRANSPORT_TLS) && - upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1 : 0; -} - -static int -tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { - return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED && - upstream->tls_auth_failed) ? 0 : 1; -} - int tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { getdns_upstream *upstream; getdns_return_t pinset_ret = GETDNS_RETURN_GOOD; upstream = _getdns_upstream_from_x509_store(ctx); + if (!upstream) + return 0; -#if defined(STUB_DEBUG) && STUB_DEBUG || defined(X509_V_ERR_HOSTNAME_MISMATCH) - int err = X509_STORE_CTX_get_error(ctx); - + int err = X509_STORE_CTX_get_error(ctx); +#if defined(STUB_DEBUG) && STUB_DEBUG DEBUG_STUB("%s %-35s: FD: %d Verify result: (%d) \"%s\"\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, err, + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err, X509_verify_cert_error_string(err)); #endif + /* First deal with the hostname authentication done by OpenSSL. */ #ifdef X509_V_ERR_HOSTNAME_MISMATCH /*Report if error is hostname mismatch*/ - if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_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, __FUNCTION__, upstream->fd); + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); +#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 - if (upstream && upstream->tls_pubkey_pinset) + + /* Now deal with the pinset validation*/ + if (upstream->tls_pubkey_pinset) pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); if (pinset_ret != GETDNS_RETURN_GOOD) { DEBUG_STUB("%s %-35s: FD: %d, WARNING: Pinset validation failure!\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); preverify_ok = 0; - upstream->tls_auth_failed = 1; + upstream->tls_auth_state = GETDNS_AUTH_FAILED; if (upstream->tls_fallback_ok) DEBUG_STUB("%s %-35s: FD: %d, WARNING: Proceeding even though pinset validation failed!\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); + } else { + /* If we _only_ had a pinset and it is good then force succesful + authentication when the cert self-signed */ + 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); + } } + + /* If nothing has failed yet and we had credentials, we have succesfully authenticated*/ + if (preverify_ok == 0) + upstream->tls_auth_state = GETDNS_AUTH_FAILED; + else if (upstream->tls_auth_state == GETDNS_AUTH_NONE && + (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0])) + upstream->tls_auth_state = GETDNS_AUTH_OK; /* If fallback is allowed, proceed regardless of what the auth error is (might not be hostname or pinset related) */ - return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; + return (upstream->tls_fallback_ok) ? 1 : preverify_ok; } static SSL* @@ -961,7 +950,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) if (upstream->tls_auth_name[0] != '\0') { /*Request certificate for the auth_name*/ DEBUG_STUB("%s %-35s: Hostname verification requested for: %s\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->tls_auth_name); + 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*/ @@ -971,11 +960,9 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); #else if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { - /* TODO: Trigger post-handshake custom validation*/ DEBUG_STUB("%s %-35s: ERROR: TLS Authentication functionality not available\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__); + STUB_DEBUG_SETUP_TLS, __FUNC__); upstream->tls_hs_state = GETDNS_HS_FAILED; - upstream->tls_auth_failed = 1; return NULL; } #endif @@ -988,33 +975,45 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { if (upstream->tls_pubkey_pinset) { DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning authentication\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__); + STUB_DEBUG_SETUP_TLS, __FUNC__); } else { DEBUG_STUB("%s %-35s: ERROR: No host name or pubkey pinset provided for TLS authentication\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__); + STUB_DEBUG_SETUP_TLS, __FUNC__); upstream->tls_hs_state = GETDNS_HS_FAILED; - upstream->tls_auth_failed = 1; return NULL; } } else { /* no hostname verification, so we will make opportunistic connections */ DEBUG_STUB("%s %-35s: Proceeding even though no hostname provided!\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__); - upstream->tls_auth_failed = 1; + STUB_DEBUG_SETUP_TLS, __FUNC__); upstream->tls_fallback_ok = 1; } } if (upstream->tls_fallback_ok) { SSL_set_cipher_list(ssl, "DEFAULT"); DEBUG_STUB("%s %-35s: WARNING: Using Oppotunistic TLS (fallback allowed)!\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__); + STUB_DEBUG_SETUP_TLS, __FUNC__); } else DEBUG_STUB("%s %-35s: Using Strict TLS \n", STUB_DEBUG_SETUP_TLS, - __FUNCTION__); + __FUNC__); SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); SSL_set_connect_state(ssl); (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + + /* Session resumption. There are trade-offs here. Want to do it when + possible only if we have the right type of connection. Note a change + to the upstream auth info creates a new upstream so never re-uses.*/ + if (upstream->tls_session != NULL) { + if ((upstream->tls_fallback_ok == 0 && + upstream->last_tls_auth_state == GETDNS_AUTH_OK) || + upstream->tls_fallback_ok == 1) { + SSL_set_session(ssl, upstream->tls_session); + DEBUG_STUB("%s %-35s: Attempting session re-use\n", STUB_DEBUG_SETUP_TLS, + __FUNC__); + } + } + return ssl; } @@ -1022,7 +1021,7 @@ static int tls_do_handshake(getdns_upstream *upstream) { DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SETUP_TLS, - __FUNCTION__, upstream->fd); + __FUNC__, upstream->fd); int r; int want; ERR_clear_error(); @@ -1048,26 +1047,20 @@ tls_do_handshake(getdns_upstream *upstream) return STUB_TCP_AGAIN; default: DEBUG_STUB("%s %-35s: FD: %d Handshake failed %d\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, + STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, want); - return tls_cleanup(upstream, 1); + return STUB_SETUP_ERROR; } } upstream->tls_hs_state = GETDNS_HS_DONE; - DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd); - r = SSL_get_verify_result(upstream->tls_obj); - if (upstream->tls_auth_name[0]) -#ifdef X509_V_ERR_HOSTNAME_MISMATCH - if (r == X509_V_ERR_HOSTNAME_MISMATCH) -#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. */ -#endif - upstream->tls_auth_failed = 1; - DEBUG_STUB("%s %-35s: FD: %d Session is %s\n", - STUB_DEBUG_SETUP_TLS, __FUNCTION__, upstream->fd, + 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; + 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"); if (upstream->tls_session != NULL) SSL_SESSION_free(upstream->tls_session); @@ -1086,21 +1079,17 @@ static int tls_connected(getdns_upstream* upstream) { /* Already have a TLS connection*/ - if (upstream->tls_hs_state == GETDNS_HS_DONE && - (upstream->tls_obj != NULL)) + if (upstream->tls_hs_state == GETDNS_HS_DONE) return 0; /* Already tried and failed, so let the fallback code take care of things */ if (upstream->tls_hs_state == GETDNS_HS_FAILED) - return STUB_TLS_SETUP_ERROR; + return STUB_SETUP_ERROR; - /* Lets make sure the connection is up before we try a handshake*/ + /* Lets make sure the TCP connection is up before we try a handshake*/ int q = tcp_connected(upstream); - if (q != 0) { - if (q == STUB_TCP_ERROR) - tls_cleanup(upstream, 0); + if (q != 0) return q; - } return tls_do_handshake(upstream); } @@ -1205,8 +1194,12 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, int q = tls_connected(upstream); if (q != 0) return q; - if (!tls_auth_status_ok(upstream, netreq)) - return STUB_TLS_SETUP_ERROR; + /* This is the case where the upstream is connected but it isn't an authenticated + connection, but the request needs an authenticated connection. For now, we + fail the write as a special case, since other oppotunistic requests can still use + this upstream. but this needs more thought: Should we open a second connection? */ + if (!upstream_auth_status_ok(upstream, netreq)) + return STUB_NO_AUTH; /* Do we have remaining data that we could not write before? */ if (! tcp->write_buf) { @@ -1237,12 +1230,12 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp, if (netreq->owner->edns_client_subnet_private) if (attach_edns_client_subnet_private(netreq)) return STUB_OUT_OF_OPTIONS; - if (netreq->upstream->writes_done % EDNS_KEEPALIVE_RESEND == 0 && + if (netreq->upstream->queries_sent % EDNS_KEEPALIVE_RESEND == 0 && netreq->owner->context->idle_timeout != 0) { /* Add the keepalive option to every nth query on this connection */ DEBUG_STUB("%s %-35s: FD: %d Requesting keepalive \n", - STUB_DEBUG_SETUP, __FUNCTION__, upstream->fd); + STUB_DEBUG_SETUP, __FUNC__, upstream->fd); if (attach_edns_keepalive(netreq)) return STUB_OUT_OF_OPTIONS; netreq->keepalive_sent = 1; @@ -1304,7 +1297,7 @@ stub_udp_read_cb(void *userarg) getdns_upstream *upstream = netreq->upstream; ssize_t read; DEBUG_STUB("%s %-35s: MSG: %p \n", STUB_DEBUG_READ, - __FUNCTION__, netreq); + __FUNC__, (void*)netreq); GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); @@ -1333,10 +1326,11 @@ stub_udp_read_cb(void *userarg) closesocket(netreq->fd); #else close(netreq->fd); + netreq->fd = -1; #endif while (GLDNS_TC_WIRE(netreq->response)) { DEBUG_STUB("%s %-35s: MSG: %p TC bit set in response \n", STUB_DEBUG_READ, - __FUNCTION__, netreq); + __FUNC__, (void*)netreq); if (!(netreq->transport_current < netreq->transport_count)) break; getdns_transport_list_t next_transport = @@ -1357,9 +1351,17 @@ stub_udp_read_cb(void *userarg) return; } netreq->response_len = read; - dnsreq->upstreams->current = 0; + dnsreq->upstreams->current_udp = 0; netreq->debug_end_time = _getdns_get_time_as_uintt64(); netreq->state = NET_REQ_FINISHED; + upstream->udp_responses++; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + if (upstream->udp_responses == 1 || + upstream->udp_responses % 100 == 0) + DEBUG_DAEMON("%s %s : Upstream stats: Transport=UDP - Resp=%d,Timeouts=%d\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (int)upstream->udp_responses, (int)upstream->udp_timeouts); +#endif _getdns_check_dns_req_complete(dnsreq); } @@ -1370,7 +1372,7 @@ stub_udp_write_cb(void *userarg) getdns_dns_req *dnsreq = netreq->owner; size_t pkt_len; DEBUG_STUB("%s %-35s: MSG: %p \n", STUB_DEBUG_WRITE, - __FUNCTION__, netreq); + __FUNC__, (void *)netreq); GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event); @@ -1436,7 +1438,7 @@ static void upstream_read_cb(void *userarg) { getdns_upstream *upstream = (getdns_upstream *)userarg; - DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_READ, __FUNCTION__, + DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_READ, __FUNC__, upstream->fd); getdns_network_req *netreq; int q; @@ -1444,7 +1446,7 @@ upstream_read_cb(void *userarg) intptr_t query_id_intptr; getdns_dns_req *dnsreq; - if (tls_should_read(upstream)) + if (upstream->transport == GETDNS_TRANSPORT_TLS) q = stub_tls_read(upstream, &upstream->tcp, &upstream->upstreams->mf); else @@ -1457,9 +1459,9 @@ upstream_read_cb(void *userarg) */ case STUB_TCP_WOULDBLOCK: return; - + case STUB_SETUP_ERROR: /* Can happen for TLS HS*/ case STUB_TCP_ERROR: - upstream_erred(upstream); + upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1) ); return; default: @@ -1477,22 +1479,19 @@ upstream_read_cb(void *userarg) } DEBUG_STUB("%s %-35s: MSG: %p (read)\n", - STUB_DEBUG_READ, __FUNCTION__, netreq); + STUB_DEBUG_READ, __FUNC__, (void*)netreq); netreq->state = NET_REQ_FINISHED; netreq->response = upstream->tcp.read_buf; netreq->response_len = upstream->tcp.read_pos - upstream->tcp.read_buf; upstream->tcp.read_buf = NULL; upstream->responses_received++; - /* TODO[TLS]: I don't think we should do this for TCP. We should stay - * on a working connection until we hit a problem.*/ - upstream->upstreams->current = 0; /* !THIS CODE NEEDS TESTING! */ if (netreq->owner->edns_cookies && match_and_process_server_cookie( - netreq->upstream, netreq->tcp.read_buf, - netreq->tcp.read_pos - netreq->tcp.read_buf)) + netreq->upstream, upstream->tcp.read_buf, + upstream->tcp.read_pos - upstream->tcp.read_buf)) return; /* Client cookie didn't match (or FORMERR) */ if (netreq->owner->context->idle_timeout != 0) @@ -1552,18 +1551,24 @@ upstream_write_cb(void *userarg) getdns_upstream *upstream = (getdns_upstream *)userarg; getdns_network_req *netreq = upstream->write_queue; int q; - + if (!netreq) { GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.write_cb = NULL; return; } - /* TODO: think about TCP AGAIN */ + netreq->debug_start_time = _getdns_get_time_as_uintt64(); DEBUG_STUB("%s %-35s: MSG: %p (writing)\n", STUB_DEBUG_WRITE, - __FUNCTION__, netreq); + __FUNC__, (void*)netreq); - if (tls_requested(netreq) && tls_should_write(upstream)) + /* Health checks on current connection */ + if (upstream->conn_state == GETDNS_CONN_TEARDOWN) + q = STUB_CONN_GONE; + else if (!upstream_working_ok(upstream)) + q = STUB_TCP_ERROR; + /* Seems ok, now try to write */ + else if (tls_requested(netreq)) q = stub_tls_write(upstream, &upstream->tcp, netreq); else q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq); @@ -1572,32 +1577,37 @@ upstream_write_cb(void *userarg) case STUB_TCP_AGAIN: /* WSA TODO: if callback is still upstream_write_cb, do it again */ - case STUB_TCP_WOULDBLOCK: return; - case STUB_TCP_ERROR: - /* Problem with the TCP connection itself. Need to fallback.*/ - DEBUG_STUB("%s %-35s: MSG: %p ERROR!\n", STUB_DEBUG_WRITE, - __FUNCTION__, ((getdns_network_req *)userarg)); - upstream->tcp.write_error = 1; - /* Use policy of trying next upstream in this case. Need more work on - * TCP connection re-use.*/ - stub_next_upstream(netreq); + /* New problem with the TCP connection itself. Need to fallback.*/ /* Fall through */ - case STUB_TLS_SETUP_ERROR: - /* Could not complete the TLS set up. Need to fallback.*/ + case STUB_SETUP_ERROR: + /* Could not complete the set up. Need to fallback.*/ + DEBUG_STUB("%s %-35s: Upstream: %p ERROR = %d\n", STUB_DEBUG_WRITE, + __FUNC__, (void*)userarg, q); + upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1)); + /* Fall through */ + case STUB_CONN_GONE: + case STUB_NO_AUTH: + /* Cleaning up after connection or auth check failure. Need to fallback. */ stub_cleanup(netreq); +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : Conn closed : Transport=%s - *Failure*\n", + STUB_DEBUG_DAEMON, upstream->addr_str, + (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP")); +#endif if (fallback_on_write(netreq) == STUB_TCP_ERROR) { + /* TODO: Need new state to report transport unavailable*/ netreq->state = NET_REQ_FINISHED; _getdns_check_dns_req_complete(netreq->owner); } return; default: - /* Need this because auth status is reset on connection clode */ - netreq->debug_tls_auth_status = netreq->upstream->tls_auth_failed; - upstream->writes_done++; + /* Need this because auth status is reset on connection close */ + netreq->debug_tls_auth_status = netreq->upstream->tls_auth_state; + upstream->queries_sent++; netreq->query_id = (uint16_t) q; /* Unqueue the netreq from the write_queue */ if (!(upstream->write_queue = netreq->write_queue_tail)) { @@ -1630,87 +1640,167 @@ upstream_write_cb(void *userarg) /*****************************/ static int -upstream_transport_valid(getdns_upstream *upstream, +upstream_working_ok(getdns_upstream *upstream) +{ + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + return (upstream->responses_timeouts > + upstream->responses_received*GETDNS_CONN_ATTEMPTS ? 0 : 1); +} + +static int +upstream_active(getdns_upstream *upstream) +{ + if ((upstream->conn_state == GETDNS_CONN_SETUP || + upstream->conn_state == GETDNS_CONN_OPEN) && + upstream->keepalive_shutdown == 0) + return 1; + return 0; +} + +static int +upstream_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { + if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) + return 1; + return (upstream->tls_auth_state == GETDNS_AUTH_OK ? 1 : 0); +} + +static int +upstream_stats(getdns_upstream *upstream) +{ + /* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/ + return (upstream->total_responses - upstream->total_timeouts + - upstream->conn_shutdowns*GETDNS_TRANSPORT_FAIL_MULT); +} + +static int +upstream_valid(getdns_upstream *upstream, + getdns_transport_list_t transport, + getdns_network_req *netreq) +{ + if (upstream->transport != transport || upstream->conn_state != GETDNS_CONN_CLOSED) + return 0; + if (transport == GETDNS_TRANSPORT_TCP) + return 1; + /* We need to check past authentication history to see if this is usable for TLS.*/ + if (netreq->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) + return 1; + return ((upstream->best_tls_auth_state == GETDNS_AUTH_OK || + upstream->best_tls_auth_state == GETDNS_AUTH_NONE) ? 1 : 0); +} + +static int +upstream_valid_and_open(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_network_req *netreq) { - /* Single shot UDP, uses same upstream as plain TCP. */ - if (transport == GETDNS_TRANSPORT_UDP) - return (upstream->transport == GETDNS_TRANSPORT_TCP ? 1:0); - /* If we got an error and have never managed to write to this TCP then - treat it as a hard failure */ - if (transport == GETDNS_TRANSPORT_TCP && - upstream->transport == GETDNS_TRANSPORT_TCP && - upstream->tcp.write_error != 0) { + if (!(upstream->transport == transport && upstream_active(upstream))) return 0; - } - /* Otherwise, transport must match, and not have failed */ - if (upstream->transport != transport) + if (transport == GETDNS_TRANSPORT_TCP) + return 1; + /* Connection is complete, we know the auth status so check*/ + if (upstream->conn_state == GETDNS_CONN_OPEN && + !upstream_auth_status_ok(upstream, netreq)) return 0; - if (tls_failed(upstream) || !tls_auth_status_ok(upstream, netreq)) - return 0; - return 1; + /* We must have a TLS connection still setting up so schedule and the + write code will check again once the connection is complete*/ + return 1; } static getdns_upstream * -upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport) +upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t transport) +{ + getdns_upstream *upstream = NULL; + getdns_upstreams *upstreams = netreq->owner->upstreams; + size_t i; + time_t now = time(NULL); + + if (!upstreams->count) + return NULL; + + /* A check to re-instate backed-off upstreams after X amount of time*/ + for (i = 0; i < upstreams->count; i++) { + if (upstreams->upstreams[i].conn_state == GETDNS_CONN_BACKOFF && + upstreams->upstreams[i].conn_retry_time < now) { + upstreams->upstreams[i].conn_state = GETDNS_CONN_CLOSED; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : Re-instating upstream\n", + STUB_DEBUG_DAEMON, upstreams->upstreams[i].addr_str); +#endif + } + } + + /* First find if an open upstream has the correct properties and use that*/ + for (i = 0; i < upstreams->count; i++) { + if (upstream_valid_and_open(&upstreams->upstreams[i], transport, netreq)) + return &upstreams->upstreams[i]; + } + + /* OK - we will have to open one. Choose the first one that has the best stats + and the right properties, but because we completely back off failed + upstreams we may have no valid upstream at all (in contrast to UDP). This + will be better communicated to the user when we have better error codes*/ + for (i = 0; i < upstreams->count; i++) { + DEBUG_STUB("%s %-35s: Testing upstreams %d %d\n", STUB_DEBUG_SETUP, + __FUNC__, (int)i, (int)upstreams->upstreams[i].conn_state); + if (upstream_valid(&upstreams->upstreams[i], transport, netreq)) { + upstream = &upstreams->upstreams[i]; + break; + } + } + if (!upstream) + return NULL; + for (i++; i < upstreams->count; i++) { + if (upstream_valid(&upstreams->upstreams[i], transport, netreq) && + upstream_stats(&upstreams->upstreams[i]) > upstream_stats(upstream)) + upstream = &upstreams->upstreams[i]; + } + return upstream; +} + +static getdns_upstream * +upstream_select(getdns_network_req *netreq) { getdns_upstream *upstream; getdns_upstreams *upstreams = netreq->owner->upstreams; size_t i; - + if (!upstreams->count) return NULL; - - - /* Only do this when a new message is scheduled?*/ - for (i = 0; i < upstreams->count; i++) + /* First UPD/TCP upstream is always at i=0 and then start of each upstream block*/ + /* TODO: Have direct access to sets of upstreams for different transports*/ + for (i = 0; i < upstreams->count; i+=GETDNS_UPSTREAM_TRANSPORTS) if (upstreams->upstreams[i].to_retry <= 0) upstreams->upstreams[i].to_retry++; - /* TODO[TLS]: Should we create a tmp array of upstreams with correct*/ - /* transport type and/or maintain separate current for transports?*/ - i = upstreams->current; - DEBUG_STUB("%s %-35s: Starting from upstream: %d of %d available \n", STUB_DEBUG_SETUP, - __FUNCTION__, (int)i, (int)upstreams->count); + i = upstreams->current_udp; do { - if (upstreams->upstreams[i].to_retry > 0 && - upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) { - upstreams->current = i; - DEBUG_STUB("%s %-35s: Selected upstream: %d %p transport: %d\n", - STUB_DEBUG_SETUP, __FUNCTION__, (int)i, - &upstreams->upstreams[i], transport); + if (upstreams->upstreams[i].to_retry > 0) { + upstreams->current_udp = i; return &upstreams->upstreams[i]; } - if (++i >= upstreams->count) + i+=GETDNS_UPSTREAM_TRANSPORTS; + if (i > upstreams->count) i = 0; - } while (i != upstreams->current); + } while (i != upstreams->current_udp); upstream = upstreams->upstreams; - for (i = 0; i < upstreams->count; i++) - if (upstreams->upstreams[i].back_off < upstream->back_off && - upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) + for (i = 0; i < upstreams->count; i+=GETDNS_UPSTREAM_TRANSPORTS) + if (upstreams->upstreams[i].back_off < + upstream->back_off) upstream = &upstreams->upstreams[i]; - /* Need to check again that the transport is valid */ - if (!upstream_transport_valid(upstream, transport, netreq)) { - DEBUG_STUB("%s %-35s: No valid upstream available for transport %d!\n", - STUB_DEBUG_SETUP, __FUNCTION__, transport); - return NULL; - } upstream->back_off++; upstream->to_retry = 1; - upstreams->current = upstream - upstreams->upstreams; + upstreams->current_udp = (upstream - upstreams->upstreams) / GETDNS_UPSTREAM_TRANSPORTS; return upstream; } - int upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, getdns_dns_req *dnsreq) { - DEBUG_STUB("%s %-35s: Checking upstream connection: %p\n", STUB_DEBUG_SETUP, - __FUNCTION__, upstream); + DEBUG_STUB("%s %-35s: Getting upstream connection: %p\n", STUB_DEBUG_SETUP, + __FUNC__, (void*)upstream); int fd = -1; switch(transport) { case GETDNS_TRANSPORT_UDP: @@ -1718,40 +1808,40 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) return -1; getdns_sock_nonblock(fd); - return fd; + break; case GETDNS_TRANSPORT_TCP: + case GETDNS_TRANSPORT_TLS: /* Use existing if available*/ if (upstream->fd != -1) return upstream->fd; fd = tcp_connect(upstream, transport); - upstream->loop = dnsreq->loop; - upstream->is_sync_loop = dnsreq->is_sync_request; - upstream->fd = fd; - break; - - case GETDNS_TRANSPORT_TLS: - /* Use existing if available*/ - if (upstream->fd != -1 && !tls_failed(upstream)) - return upstream->fd; - fd = tcp_connect(upstream, transport); - if (fd == -1) return -1; - upstream->tls_obj = tls_create_object(dnsreq, fd, upstream); - if (upstream->tls_obj == NULL) { -#ifdef USE_WINSOCK - closesocket(fd); -#else - close(fd); -#endif + if (fd == -1) { + upstream_failed(upstream, 1); return -1; } - - if (upstream->tls_session != NULL) - SSL_set_session(upstream->tls_obj, upstream->tls_session); - upstream->tls_hs_state = GETDNS_HS_WRITE; upstream->loop = dnsreq->loop; upstream->is_sync_loop = dnsreq->is_sync_request; upstream->fd = fd; + if (transport == GETDNS_TRANSPORT_TLS) { + upstream->tls_obj = tls_create_object(dnsreq, fd, upstream); + if (upstream->tls_obj == NULL) { + upstream_failed(upstream, 1); +#ifdef USE_WINSOCK + closesocket(fd); +#else + close(fd); +#endif + return -1; + } + upstream->tls_hs_state = GETDNS_HS_WRITE; + } + upstream->conn_state = GETDNS_CONN_SETUP; +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s %s : Conn init : Transport=%s - Profile=%s\n", STUB_DEBUG_DAEMON, + upstream->addr_str, transport == GETDNS_TRANSPORT_TLS ? "TLS":"TCP", + dnsreq->context->tls_auth_min == GETDNS_AUTHENTICATION_NONE ? "Opportunistic":"Strict"); +#endif break; default: return -1; @@ -1762,16 +1852,31 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport, static getdns_upstream* upstream_find_for_transport(getdns_network_req *netreq, - getdns_transport_list_t transport, - int *fd) + getdns_transport_list_t transport, + int *fd) { - // TODO[TLS]: Need to loop over upstreams here!! - getdns_upstream *upstream = upstream_select(netreq, transport); - if (!upstream) - return NULL; - *fd = upstream_connect(upstream, transport, netreq->owner); - DEBUG_STUB("%s %-35s: FD: %d Connected for upstream: %p\n", - STUB_DEBUG_SETUP, __FUNCTION__, *fd, upstream); + getdns_upstream *upstream = NULL; + + /* UDP always returns an upstream, the only reason this will fail is if + no socket is available, in which case that is an error.*/ + if (transport == GETDNS_TRANSPORT_UDP) { + upstream = upstream_select(netreq); + *fd = upstream_connect(upstream, transport, netreq->owner); + return upstream; + } + else { + /* For stateful transport we should keep trying until all our transports + are exhausted/backed-off (no upstream)*/ + do { + upstream = upstream_select_stateful(netreq, transport); + if (!upstream) + return NULL; + *fd = upstream_connect(upstream, transport, netreq->owner); + } while (*fd == -1); + DEBUG_STUB("%s %-35s: FD: %d Connecting to upstream: %p No: %d\n", + STUB_DEBUG_SETUP, __FUNC__, *fd, (void*)upstream, + (int)(upstream - netreq->owner->context->upstreams->upstreams)); + } return upstream; } @@ -1792,6 +1897,12 @@ upstream_find_for_netreq(getdns_network_req *netreq) netreq->keepalive_sent = 0; return fd; } + /* Handle better, will give generic error*/ + DEBUG_STUB("%s %-35s: MSG: %p No valid upstream! \n", STUB_DEBUG_SCHEDULE, __FUNC__, (void*)netreq); +#if defined(DAEMON_DEBUG) && DAEMON_DEBUG + DEBUG_DAEMON("%s *FAILURE* no valid transports or upstreams available!\n", + STUB_DEBUG_DAEMON); +#endif return -1; } @@ -1803,9 +1914,8 @@ static int fallback_on_write(getdns_network_req *netreq) { - /* Deal with UDP and change error code*/ - - DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); + /* Deal with UDP one day*/ + DEBUG_STUB("%s %-35s: MSG: %p FALLING BACK \n", STUB_DEBUG_SCHEDULE, __FUNC__, (void*)netreq); /* Try to find a fallback transport*/ getdns_return_t result = _getdns_submit_stub_request(netreq); @@ -1822,7 +1932,7 @@ static void upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout) { DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SCHEDULE, - __FUNCTION__, upstream->fd); + __FUNC__, upstream->fd); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); if (!upstream->write_queue && upstream->event.write_cb) { upstream->event.write_cb = NULL; @@ -1841,9 +1951,9 @@ upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout) { upstream->fd, TIMEOUT_FOREVER, &upstream->event); else { DEBUG_STUB("%s %-35s: FD: %d Connection idle - timeout is %d\n", - STUB_DEBUG_SCHEDULE, __FUNCTION__, upstream->fd, (int)idle_timeout); + STUB_DEBUG_SCHEDULE, __FUNC__, upstream->fd, (int)idle_timeout); upstream->event.timeout_cb = upstream_idle_timeout_cb; - if (upstream->tcp.write_error != 0) + if (upstream->conn_state != GETDNS_CONN_OPEN) idle_timeout = 0; GETDNS_SCHEDULE_EVENT(upstream->loop, -1, idle_timeout, &upstream->event); @@ -1853,7 +1963,7 @@ upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout) { static void upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) { - DEBUG_STUB("%s %-35s: MSG: %p (schedule event)\n", STUB_DEBUG_SCHEDULE, __FUNCTION__, netreq); + DEBUG_STUB("%s %-35s: MSG: %p (schedule event)\n", STUB_DEBUG_SCHEDULE, __FUNC__, (void*)netreq); /* We have a connected socket and a global event loop */ assert(upstream->fd >= 0); assert(upstream->loop); @@ -1869,11 +1979,9 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) } upstream->event.timeout_cb = NULL; upstream->event.write_cb = upstream_write_cb; - if (upstream->tls_hs_state == GETDNS_HS_WRITE) { + if (upstream->queries_sent == 0) { /* Set a timeout on the upstream so we can catch failed setup*/ - /* TODO[TLS]: When generic fallback supported, we should decide how - * to split the timeout between transports. */ - upstream->event.timeout_cb = upstream_tls_timeout_cb; + upstream->event.timeout_cb = upstream_setup_timeout_cb; GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, netreq->owner->context->timeout / 2, &upstream->event); @@ -1906,8 +2014,8 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq) getdns_return_t _getdns_submit_stub_request(getdns_network_req *netreq) { - DEBUG_STUB("%s %-35s: MSG: %p TYPE: %d\n", STUB_DEBUG_ENTRY, __FUNCTION__, - netreq, netreq->request_type); + DEBUG_STUB("%s %-35s: MSG: %p TYPE: %d\n", STUB_DEBUG_ENTRY, __FUNC__, + (void*)netreq, netreq->request_type); int fd = -1; getdns_dns_req *dnsreq = netreq->owner; @@ -1915,6 +2023,7 @@ _getdns_submit_stub_request(getdns_network_req *netreq) * All other set up is done async*/ fd = upstream_find_for_netreq(netreq); if (fd == -1) + /* Handle better, will give unhelpful error is some cases */ return GETDNS_RETURN_GENERIC_ERROR; getdns_transport_list_t transport = @@ -1998,14 +2107,10 @@ _getdns_submit_stub_request(getdns_network_req *netreq) */ GETDNS_SCHEDULE_EVENT( dnsreq->loop, -1, - dnsreq->context->timeout, - getdns_eventloop_event_init( &netreq->event, netreq, NULL, NULL, - - ( transport == GETDNS_TRANSPORT_TLS - ? stub_tls_timeout_cb : stub_timeout_cb))); + stub_timeout_cb)); return GETDNS_RETURN_GOOD; default: diff --git a/src/test/Makefile.in b/src/test/Makefile.in index afb807c5..c481fdab 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -67,20 +67,14 @@ CHECK_CFLAGS=@CHECK_CFLAGS@ CHECK_OBJS=check_getdns_common.lo check_getdns_context_set_timeout.lo \ check_getdns.lo check_getdns_transport.lo -DECOMPOSED_OBJS_WITHOUT_JSMN=getdns_str2dict.lo getdns_context_config.lo \ - getdns_context_set_listen_addresses.lo - -DECOMPOSED_OBJS=$(DECOMPOSED_OBJS_WITHOUT_JSMN) jsmn.lo - ALL_OBJS=$(CHECK_OBJS) check_getdns_libevent.lo check_getdns_libev.lo \ - check_getdns_selectloop.lo getdns_query.lo scratchpad.lo \ + check_getdns_selectloop.lo scratchpad.lo \ testmessages.lo tests_dict.lo tests_list.lo tests_namespaces.lo \ - tests_stub_async.lo tests_stub_sync.lo \ - $(DECOMPOSED_OBJS_WITHOUT_JSMN) + tests_stub_async.lo tests_stub_sync.lo NON_C99_OBJS=check_getdns_libuv.lo -PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync getdns_query $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) +PROGRAMS=tests_dict tests_list tests_namespaces tests_stub_async tests_stub_sync $(CHECK_GETDNS) $(CHECK_EV_PROG) $(CHECK_EVENT_PROG) $(CHECK_UV_PROG) .SUFFIXES: .c .o .a .lo .h @@ -95,9 +89,6 @@ default: all all: $(PROGRAMS) -jsmn.lo: - $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -DJSMN_GETDNS -c $(srcdir)/jsmn/jsmn.c -o $@ - $(ALL_OBJS): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WPEDANTICFLAG) -c $(srcdir)/$(@:.lo=.c) -o $@ @@ -134,9 +125,6 @@ check_getdns_uv: check_getdns.lo check_getdns_common.lo check_getdns_context_set check_getdns_ev: check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo ../libgetdns_ext_ev.la $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ check_getdns.lo check_getdns_common.lo check_getdns_context_set_timeout.lo check_getdns_transport.lo check_getdns_libev.lo $(LDFLAGS) $(LDLIBS) $(CHECK_LIBS) ../libgetdns_ext_ev.la $(EXTENSION_LIBEV_LDFLAGS) $(EXTENSION_LIBEV_EXT_LIBS) -getdns_query: getdns_query.lo $(DECOMPOSED_OBJS) - $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ getdns_query.lo $(DECOMPOSED_OBJS) $(LDFLAGS) $(LDLIBS) - scratchpad: scratchpad.lo $(LIBTOOL) --tag=CC --mode=link $(CC) -o $@ scratchpad.lo $(LDFLAGS) $(LDLIBS) @@ -145,12 +133,11 @@ scratchpad.lo: scratchpad.c $(srcdir)/scratchpad.c: scratchpad.template.c [ ! -f $(srcdir)/scratchpad.c ] && cp -p $(srcdir)/scratchpad.template.c $(srcdir)/scratchpad.c || true -install: getdns_query - $(INSTALL) -m 755 -d $(DESTDIR)$(bindir) - $(LIBTOOL) --mode=install cp getdns_query $(DESTDIR)$(bindir) +install: + echo nothing to install uninstall: - $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/getdns_query + echo nothing to uninstall nolibcheck: @echo "***" @@ -222,7 +209,6 @@ depend: -e 's? \$$(srcdir)/\.\./config\.h? ../config.h?g' \ -e 's? \$$(srcdir)/\.\./getdns/getdns\.h? ../getdns/getdns.h?g' \ -e 's? \$$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ - -e 's? jsmn/jsmn\.h? $$(srcdir)/jsmn/jsmn.h?g' \ -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ || mv Makefile.in.new Makefile.in ) @@ -274,20 +260,6 @@ check_getdns_selectloop.lo check_getdns_selectloop.o: $(srcdir)/check_getdns_sel check_getdns_transport.lo check_getdns_transport.o: $(srcdir)/check_getdns_transport.c \ $(srcdir)/check_getdns_transport.h $(srcdir)/check_getdns_common.h ../getdns/getdns.h \ ../getdns/getdns_extra.h -getdns_context_config.lo getdns_context_config.o: $(srcdir)/getdns_context_config.c $(srcdir)/getdns_context_config.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h -getdns_context_set_listen_addresses.lo getdns_context_set_listen_addresses.o: \ - $(srcdir)/getdns_context_set_listen_addresses.c ../config.h \ - $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h $(srcdir)/../types-internal.h ../getdns/getdns.h \ - ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../debug.h ../config.h -getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ - $(srcdir)/getdns_str2dict.h ../getdns/getdns.h $(srcdir)/getdns_context_config.h \ - $(srcdir)/getdns_context_set_listen_addresses.h ../getdns/getdns_extra.h -getdns_str2dict.lo getdns_str2dict.o: $(srcdir)/getdns_str2dict.c ../config.h $(srcdir)/../const-info.h \ - $(srcdir)/jsmn/jsmn.h $(srcdir)/getdns_str2dict.h ../getdns/getdns.h $(srcdir)/../types-internal.h \ - ../getdns/getdns.h ../getdns/getdns_extra.h $(srcdir)/../util/rbtree.h $(srcdir)/../list.h \ - $(srcdir)/../types-internal.h $(srcdir)/../dict.h scratchpad.template.lo scratchpad.template.o: scratchpad.template.c ../getdns/getdns.h \ ../getdns/getdns_extra.h testmessages.lo testmessages.o: $(srcdir)/testmessages.c $(srcdir)/testmessages.h diff --git a/src/test/check_getdns_address.h b/src/test/check_getdns_address.h index 2c59d992..f898bdd8 100644 --- a/src/test/check_getdns_address.h +++ b/src/test/check_getdns_address.h @@ -224,7 +224,7 @@ EVENT_BASE_CREATE; - ASSERT_RC(getdns_address(context, "hostnamedoesntexist", NULL, + ASSERT_RC(getdns_address(context, "hostnamedoesntexist.", NULL, &fn_ref, &transaction_id, callbackfn), GETDNS_RETURN_GOOD, "Return code from getdns_address()"); diff --git a/src/test/check_getdns_context_set_dns_transport.h b/src/test/check_getdns_context_set_dns_transport.h index 9b4aac23..fba6c195 100644 --- a/src/test/check_getdns_context_set_dns_transport.h +++ b/src/test/check_getdns_context_set_dns_transport.h @@ -300,6 +300,7 @@ } CONTEXT_DESTROY; + getdns_dict_destroy(extensions); getdns_list_destroy(root_servers); diff --git a/src/test/check_getdns_service_sync.h b/src/test/check_getdns_service_sync.h index 09c48f9c..17273e24 100644 --- a/src/test/check_getdns_service_sync.h +++ b/src/test/check_getdns_service_sync.h @@ -124,7 +124,7 @@ */ struct getdns_context *context = NULL; struct getdns_dict *response = NULL; - const char *name = "labelsizeofsixtythreecharacterscom"; + const char *name = "labelsizeofsixtythreecharacterscom."; CONTEXT_CREATE(TRUE); diff --git a/src/test/getdns_context_config.c b/src/test/getdns_context_config.c deleted file mode 100644 index 3cb7e272..00000000 --- a/src/test/getdns_context_config.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "getdns_context_config.h" -#include "getdns/getdns_extra.h" -#include -#include -#include - -static int _streq(const getdns_bindata *name, const char *str) -{ - if (strlen(str) != name->size) - return 0; - else return strncmp((const char *)name->data, str, name->size) == 0; -} - -static getdns_return_t _get_list_or_read_file(const getdns_dict *config_dict, - const char *setting, getdns_list **r_list, int *destroy_list) -{ - getdns_bindata *fn_bd; - char fn[FILENAME_MAX]; - FILE *fh; - getdns_return_t r; - - assert(r_list); - assert(destroy_list); - - *destroy_list = 0; - if (!(r = getdns_dict_get_list(config_dict, setting, r_list))) - return GETDNS_RETURN_GOOD; - - else if ((r = getdns_dict_get_bindata(config_dict, setting, &fn_bd))) - return r; - - else if (fn_bd->size >= FILENAME_MAX) - return GETDNS_RETURN_INVALID_PARAMETER; - - (void)memcpy(fn, fn_bd->data, fn_bd->size); - fn[fn_bd->size] = 0; - - if (!(fh = fopen(fn, "r"))) - return GETDNS_RETURN_GENERIC_ERROR; - - if (!(r = getdns_fp2rr_list(fh, r_list, NULL, 3600))) - *destroy_list = 1; - - fclose(fh); - return r; -} - -#define CONTEXT_SETTING_INT(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = getdns_dict_get_int(config_dict, #X , &n))) \ - r = getdns_context_set_ ## X (context, n); - -#define CONTEXT_SETTING_LIST(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = getdns_dict_get_list(config_dict, #X , &list))) \ - r = getdns_context_set_ ## X (context, list); - -#define CONTEXT_SETTING_LIST_OR_ZONEFILE(X) \ - } else if (_streq(setting, #X)) { \ - if (!(r = _get_list_or_read_file( \ - config_dict, #X , &list, &destroy_list))) \ - r = getdns_context_set_ ## X(context, list); \ - if (destroy_list) getdns_list_destroy(list); - -#define CONTEXT_SETTING_ARRAY(X, T) \ - } else if (_streq(setting, #X )) { \ - if (!(r = getdns_dict_get_list(config_dict, #X , &list)) && \ - !(r = getdns_list_get_length(list, &count))) { \ - for (i=0; i /* For bsearch */ -#include /* For isspace */ - -static struct mem_funcs _getdns_plain_mem_funcs = { - MF_PLAIN, .mf.pln = { malloc, realloc, free } -}; - -/* TODO: Replace with gldns_b64_pton - * once getdns_ipaddr_dict becomes part of the library - */ -static int _gldns_b64_pton(char const *src, uint8_t *target, size_t targsize) -{ - const uint8_t pad64 = 64; /* is 64th in the b64 array */ - const char* s = src; - uint8_t in[4]; - size_t o = 0, incount = 0; - - while(*s) { - /* skip any character that is not base64 */ - /* conceptually we do: - const char* b64 = pad'=' is appended to array - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - const char* d = strchr(b64, *s++); - and use d-b64; - */ - char d = *s++; - if(d <= 'Z' && d >= 'A') - d -= 'A'; - else if(d <= 'z' && d >= 'a') - d = d - 'a' + 26; - else if(d <= '9' && d >= '0') - d = d - '0' + 52; - else if(d == '+') - d = 62; - else if(d == '/') - d = 63; - else if(d == '=') - d = 64; - else continue; - in[incount++] = (uint8_t)d; - if(incount != 4) - continue; - /* process whole block of 4 characters into 3 output bytes */ - if(in[3] == pad64 && in[2] == pad64) { /* A B = = */ - if(o+1 > targsize) - return -1; - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - o += 1; - break; /* we are done */ - } else if(in[3] == pad64) { /* A B C = */ - if(o+2 > targsize) - return -1; - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); - o += 2; - break; /* we are done */ - } else { - if(o+3 > targsize) - return -1; - /* write xxxxxxyy yyyyzzzz zzwwwwww */ - target[o] = (in[0]<<2) | ((in[1]&0x30)>>4); - target[o+1]= ((in[1]&0x0f)<<4) | ((in[2]&0x3c)>>2); - target[o+2]= ((in[2]&0x03)<<6) | in[3]; - o += 3; - } - incount = 0; - } - return (int)o; -} - -static getdns_dict * -_getdns_ipaddr_dict_mf(struct mem_funcs *mf, const char *ipstr) -{ - getdns_dict *r = _getdns_dict_create_with_mf(mf); - char *s = strchr(ipstr, '%'), *scope_id_str = ""; - char *p = strchr(ipstr, '@'), *portstr = ""; - char *t = strchr(ipstr, '#'), *tls_portstr = ""; - char *n = strchr(ipstr, '~'), *tls_namestr = ""; - /* ^[alg:]name:key */ - char *T = strchr(ipstr, '^'), *tsig_name_str = "" - , *tsig_secret_str = "" - , *tsig_algorithm_str = ""; - char *br, *c; - int tsig_secret_size; - uint8_t tsig_secret_buf[256]; /* 4 times SHA512 */ - getdns_bindata tsig_secret; - uint8_t buf[sizeof(struct in6_addr)]; - getdns_bindata addr; - - addr.data = buf; - - if (!r) return NULL; - - if (*ipstr == '[') { - char *br = strchr(ipstr, ']'); - if (br) { - ipstr += 1; - *br = 0; - if ((c = strchr(br + 1, ':'))) { - p = c; - } - } - } else if ((br = strchr(ipstr, '.')) && (c = strchr(br + 1, ':')) - && (T == NULL || c < T)) - p = c; - - else if ((*ipstr == '*') && (c = strchr(ipstr+1, ':'))) - p = c; - - if (s) { - *s = 0; - scope_id_str = s + 1; - } - if (p) { - *p = 0; - portstr = p + 1; - } - if (t) { - *t = 0; - tls_portstr = t + 1; - } - if (n) { - *n = 0; - tls_namestr = n + 1; - } - if (T) { - *T = 0; - tsig_name_str = T + 1; - if ((T = strchr(tsig_name_str, ':'))) { - *T = 0; - tsig_secret_str = T + 1; - if ((T = strchr(tsig_secret_str, ':'))) { - *T = 0; - tsig_algorithm_str = tsig_name_str; - tsig_name_str = tsig_secret_str; - tsig_secret_str = T + 1; - } - } else { - tsig_name_str = ""; - } - } - if (*ipstr == '*') { - getdns_dict_util_set_string(r, "address_type", "IPv6"); - addr.size = 16; - (void) memset(buf, 0, 16); - } else if (strchr(ipstr, ':')) { - getdns_dict_util_set_string(r, "address_type", "IPv6"); - addr.size = 16; - if (inet_pton(AF_INET6, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } else { - getdns_dict_util_set_string(r, "address_type", "IPv4"); - addr.size = 4; - if (inet_pton(AF_INET, ipstr, buf) <= 0) { - getdns_dict_destroy(r); - return NULL; - } - } - getdns_dict_set_bindata(r, "address_data", &addr); - if (*portstr) - getdns_dict_set_int(r, "port", (int32_t)atoi(portstr)); - if (*tls_portstr) - getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr)); - if (*tls_namestr) { - getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr); - } - if (*scope_id_str) - getdns_dict_util_set_string(r, "scope_id", scope_id_str); - if (*tsig_name_str) - getdns_dict_util_set_string(r, "tsig_name", tsig_name_str); - if (*tsig_algorithm_str) - getdns_dict_util_set_string(r, "tsig_algorithm", tsig_algorithm_str); - if (*tsig_secret_str) { - tsig_secret_size = _gldns_b64_pton( - tsig_secret_str, tsig_secret_buf, sizeof(tsig_secret_buf)); - if (tsig_secret_size > 0) { - tsig_secret.size = tsig_secret_size; - tsig_secret.data = tsig_secret_buf; - getdns_dict_set_bindata(r, "tsig_secret", &tsig_secret); - } - } - return r; -} - -static int _jsmn_get_ipdict(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_dict **value) -{ - char value_str[3072]; - int size = t->end - t->start; - - if (size <= 0 || size >= (int)sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - *value = _getdns_ipaddr_dict_mf(mf, value_str); - return *value != NULL; -} - -static int _jsmn_get_data(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - int i; - size_t j; - uint8_t h, l; - - if ((t->end - t->start) < 4 || (t->end - t->start) % 2 == 1 || - js[t->start] != '0' || js[t->start + 1] != 'x') - return 0; - - for (i = t->start + 2; i < t->end; i++) - if (!((js[i] >= '0' && js[i] <= '9') - ||(js[i] >= 'a' && js[i] <= 'f') - ||(js[i] >= 'A' && js[i] <= 'F'))) - return 0; - - if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - return 0; - - else if (!((*value)->data = GETDNS_XMALLOC( - *mf, uint8_t, (t->end - t->start) / 2 - 1))) { - GETDNS_FREE(*mf, *value); - return 0; - } - for (i = t->start + 2, j = 0; i < t->end; i++, j++) { - h = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' - : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' - : js[i] + 10 - 'a'; - h <<= 4; - i++; - l = js[i] >= '0' && js[i] <= '9' ? js[i] - '0' - : js[i] >= 'A' && js[i] <= 'F' ? js[i] + 10 - 'A' - : js[i] + 10 - 'a'; - (*value)->data[j] = h | l; - } - (*value)->size = j; - return 1; -} - -static int _jsmn_get_dname(const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[1025]; - int size = t->end - t->start; - - if (size <= 0 || size >= (int)sizeof(value_str) || js[t->end - 1] != '.') - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - return !getdns_convert_fqdn_to_dns_name(value_str, value); -} - -static int _jsmn_get_ipv4(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[16]; - int size = t->end - t->start; - uint8_t buf[4]; - - if (size <= 0 || size >= (int)sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - if (inet_pton(AF_INET, value_str, buf) <= 0) - ; /* pass */ - - else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - ; /* pass */ - - else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 4))) - GETDNS_FREE(*mf, *value); - - else { - (*value)->size = 4; - (void) memcpy((*value)->data, buf, 4); - return 1; - } - return 0; -} - -static int _jsmn_get_ipv6(struct mem_funcs *mf, const char *js, jsmntok_t *t, - getdns_bindata **value) -{ - char value_str[40]; - int size = t->end - t->start; - uint8_t buf[16]; - - if (size <= 0 || size >= (int)sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - if (inet_pton(AF_INET6, value_str, buf) <= 0) - ; /* pass */ - - else if (!(*value = GETDNS_MALLOC(*mf, getdns_bindata))) - ; /* pass */ - - else if (!((*value)->data = GETDNS_XMALLOC(*mf, uint8_t, 16))) - GETDNS_FREE(*mf, *value); - - else { - (*value)->size = 16; - (void) memcpy((*value)->data, buf, 16); - return 1; - } - return 0; -} - -static int _jsmn_get_int(const char *js, jsmntok_t *t, uint32_t *value) -{ - char value_str[11]; - int size = t->end - t->start; - char *endptr; - - if (size <= 0 || size >= (int)sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - *value = (uint32_t)strtoul(value_str, &endptr, 10); - return *value_str != '\0' && *endptr == '\0'; -} - -static int _getdns_get_const_name_info(const char *name, uint32_t *code); - -static int _jsmn_get_const(const char *js, jsmntok_t *t, uint32_t *value) -{ - char value_str[80]; - int size = t->end - t->start; - - if (size <= 0 || size >= (int)sizeof(value_str)) - return 0; - - (void) memcpy(value_str, js + t->start, size); - value_str[size] = '\0'; - - return _getdns_get_const_name_info(value_str, value); -} - -static void -_getdns_destroy_item_data(struct mem_funcs *mf, getdns_item *item) -{ - switch (item->dtype) { - case t_dict: - getdns_dict_destroy(item->data.dict); - break; - - case t_list: - getdns_list_destroy(item->data.list); - break; - - case t_bindata: - GETDNS_FREE(*mf, item->data.bindata->data); - GETDNS_FREE(*mf, item->data.bindata); - default: - break; - } -} -static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_item *item, getdns_return_t *r); - -static int _jsmn_get_dict(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_dict *dict, getdns_return_t *r) -{ - int i; - size_t j = 1; - char key_spc[1024], *key = NULL; - getdns_item child_item; - - if (t->size <= 0) - *r = GETDNS_RETURN_GOOD; - - else for (i = 0; i < t->size; i++) { - if (t[j].type != JSMN_STRING && - t[j].type != JSMN_PRIMITIVE) { - - /* Key must be string or primitive */ - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - } - if (t[j].end <= t[j].start) { - /* Key must be at least 1 character */ - *r = GETDNS_RETURN_GENERIC_ERROR; /* range error */ - break; - } - if (t[j].end - t[j].start < (int)sizeof(key_spc)) - key = key_spc; - - else if (!(key = GETDNS_XMALLOC( - *mf, char, t[j].end - t[j].start + 1))) { - - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - (void) memcpy(key, js + t[j].start, t[j].end - t[j].start); - key[t[j].end - t[j].start] = '\0'; - j += 1; - - j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); - if (*r) break; - - switch (child_item.dtype) { - case t_int: - *r = getdns_dict_set_int(dict, key, - child_item.data.n); - break; - case t_bindata: - *r = getdns_dict_set_bindata(dict, key, - child_item.data.bindata); - break; - case t_list: - *r = getdns_dict_set_list(dict, key, - child_item.data.list); - break; - case t_dict: - *r = getdns_dict_set_dict(dict, key, - child_item.data.dict); - break; - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - - } - _getdns_destroy_item_data(mf, &child_item); - if (*r) break; - if (key && key != key_spc) { - GETDNS_FREE(*mf, key); - key = NULL; - } - } - if (key && key != key_spc) - GETDNS_FREE(*mf, key); - - if (*r) { - getdns_dict_destroy(dict); - return 0; - } - return j; -} - -static int _jsmn_get_list(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_list *list, getdns_return_t *r) -{ - int i; - size_t j = 1, index = 0; - getdns_item child_item; - - if (t->size <= 0) - *r = GETDNS_RETURN_GOOD; - - else for (i = 0; i < t->size; i++) { - j += _jsmn_get_item(mf, js, t + j, count - j, &child_item, r); - if (*r) break; - - switch (child_item.dtype) { - case t_int: - *r = getdns_list_set_int(list, index++, - child_item.data.n); - break; - case t_bindata: - *r = getdns_list_set_bindata(list, index++, - child_item.data.bindata); - break; - case t_list: - *r = getdns_list_set_list(list, index++, - child_item.data.list); - break; - case t_dict: - *r = getdns_list_set_dict(list, index++, - child_item.data.dict); - break; - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - - } - _getdns_destroy_item_data(mf, &child_item); - if (*r) break; - } - if (*r) { - getdns_list_destroy(list); - return 0; - } - return j; -} - -static int _jsmn_get_item(struct mem_funcs *mf, const char *js, jsmntok_t *t, - size_t count, getdns_item *item, getdns_return_t *r) -{ - assert(item); - - switch (t->type) { - case JSMN_STRING: - if (t->end < t->start) - *r = GETDNS_RETURN_GENERIC_ERROR; - - else if (!(item->data.bindata = - GETDNS_MALLOC(*mf, getdns_bindata))) - *r = GETDNS_RETURN_MEMORY_ERROR; - - else if (!(item->data.bindata->data = GETDNS_XMALLOC( - *mf, uint8_t, t->end - t->start + 1))) { - GETDNS_FREE(*mf, item->data.bindata); - *r = GETDNS_RETURN_MEMORY_ERROR; - } else { - item->dtype = t_bindata; - if (t->end - t->start) { - (void) memcpy(item->data.bindata->data, - js + t->start, t->end - t->start); - } - item->data.bindata->data[t->end - t->start] = '\0'; - item->data.bindata->size = t->end - t->start; - *r = GETDNS_RETURN_GOOD; - return 1; - } - break; - - case JSMN_PRIMITIVE: - /* There is no such thing as an empty primitive */ - if (t->end <= t->start) { - *r = GETDNS_RETURN_GENERIC_ERROR; - break; - - } else if (_jsmn_get_int(js, t, &item->data.n) - || _jsmn_get_const(js, t, &item->data.n)) { - - item->dtype = t_int; - } - else if (_jsmn_get_data(mf, js, t, &item->data.bindata) - || _jsmn_get_dname(js, t, &item->data.bindata) - || _jsmn_get_ipv4(mf, js, t, &item->data.bindata) - || _jsmn_get_ipv6(mf, js, t, &item->data.bindata)) - - item->dtype = t_bindata; - - else if (_jsmn_get_ipdict(mf, js, t, &item->data.dict)) - - item->dtype = t_dict; - else { - *r = GETDNS_RETURN_GENERIC_ERROR; - break; - } - *r = GETDNS_RETURN_GOOD; - return 1; - - case JSMN_OBJECT: - if (!(item->data.dict = _getdns_dict_create_with_mf(mf))) { - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - item->dtype = t_dict; - return _jsmn_get_dict(mf, js, t, count, item->data.dict, r); - - case JSMN_ARRAY: - if (!(item->data.list = _getdns_list_create_with_mf(mf))) { - *r = GETDNS_RETURN_MEMORY_ERROR; - break; - } - item->dtype = t_list; - return _jsmn_get_list(mf, js, t, count, item->data.list, r); - - default: - *r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - break; - } - return 0; -} - -static getdns_return_t -_getdns_str2item_mf(struct mem_funcs *mf, const char *str, getdns_item *item) -{ - jsmn_parser p; - jsmntok_t *tok = NULL, *new_tok; - size_t tokcount = 100; - int r; - getdns_return_t gr; - - jsmn_init(&p); - tok = GETDNS_XMALLOC(*mf, jsmntok_t, tokcount); - do { - r = jsmn_parse(&p, str, strlen(str), tok, tokcount); - if (r == JSMN_ERROR_NOMEM) { - tokcount *= 2; - if (!(new_tok = GETDNS_XREALLOC( - *mf, tok, jsmntok_t, tokcount))) { - GETDNS_FREE(*mf, tok); - return GETDNS_RETURN_MEMORY_ERROR; - } - tok = new_tok; - } - } while (r == JSMN_ERROR_NOMEM); - if (r < 0) - gr = GETDNS_RETURN_GENERIC_ERROR; - else - (void) _jsmn_get_item(mf, str, tok, p.toknext, item, &gr); - GETDNS_FREE(*mf, tok); - return gr; -} - -getdns_return_t -getdns_str2dict(const char *str, getdns_dict **dict) -{ - getdns_item item; - getdns_return_t r; - - while (*str && isspace(*str)) - str++; - - if (*str != '{') { - getdns_dict *dict_r = _getdns_ipaddr_dict_mf( - &_getdns_plain_mem_funcs, str); - if (dict_r) { - *dict = dict_r; - return GETDNS_RETURN_GOOD; - } - } - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_dict) { - uint8_t buf[16]; - getdns_dict *dict_r; - - if (item.dtype != t_bindata) - r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - - else if (item.data.bindata->size == 4 && - inet_pton(AF_INET, str, buf) == 1) { - - if (!(dict_r = getdns_dict_create())) - r = GETDNS_RETURN_MEMORY_ERROR; - - else if ((r = getdns_dict_util_set_string( - dict_r, "address_type", "IPv4"))) - getdns_dict_destroy(dict_r); - - else if ((r = getdns_dict_set_bindata( - dict_r, "address_data", item.data.bindata))) - getdns_dict_destroy(dict_r); - else - *dict = dict_r; - - } else if (item.data.bindata->size == 16 && - inet_pton(AF_INET6, str, buf) == 1) { - - if (!(dict_r = getdns_dict_create())) - r = GETDNS_RETURN_MEMORY_ERROR; - - else if ((r = getdns_dict_util_set_string( - dict_r, "address_type", "IPv6"))) - getdns_dict_destroy(dict_r); - - else if ((r = getdns_dict_set_bindata( - dict_r, "address_data", item.data.bindata))) - getdns_dict_destroy(dict_r); - else - *dict = dict_r; - } else - r = GETDNS_RETURN_WRONG_TYPE_REQUESTED; - - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return r; - } - *dict = item.data.dict; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2list(const char *str, getdns_list **list) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_list) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *list = item.data.list; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2bindata(const char *str, getdns_bindata **bindata) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_bindata) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *bindata = item.data.bindata; - return GETDNS_RETURN_GOOD; -} - -getdns_return_t -getdns_str2int(const char *str, uint32_t *value) -{ - getdns_item item; - getdns_return_t r; - - if ((r = _getdns_str2item_mf(&_getdns_plain_mem_funcs, str, &item))) - return r; - - else if (item.dtype != t_int) { - _getdns_destroy_item_data(&_getdns_plain_mem_funcs, &item); - return GETDNS_RETURN_WRONG_TYPE_REQUESTED; - } - *value = item.data.n; - return GETDNS_RETURN_GOOD; -} - - -struct const_name_info { const char *name; uint32_t code; }; -static struct const_name_info consts_name_info[] = { - { "GETDNS_APPEND_NAME_ALWAYS", 550 }, - { "GETDNS_APPEND_NAME_NEVER", 553 }, - { "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", 552 }, - { "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", 551 }, - { "GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST", 554 }, - { "GETDNS_AUTHENTICATION_NONE", 1300 }, - { "GETDNS_AUTHENTICATION_REQUIRED", 1301 }, - { "GETDNS_BAD_DNS_ALL_NUMERIC_LABEL", 1101 }, - { "GETDNS_BAD_DNS_CNAME_IN_TARGET", 1100 }, - { "GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE", 1102 }, - { "GETDNS_CALLBACK_CANCEL", 701 }, - { "GETDNS_CALLBACK_COMPLETE", 700 }, - { "GETDNS_CALLBACK_ERROR", 703 }, - { "GETDNS_CALLBACK_TIMEOUT", 702 }, - { "GETDNS_CONTEXT_CODE_APPEND_NAME", 607 }, - { "GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW", 614 }, - { "GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS", 609 }, - { "GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS", 604 }, - { "GETDNS_CONTEXT_CODE_DNS_TRANSPORT", 605 }, - { "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", 619 }, - { "GETDNS_CONTEXT_CODE_EDNS_DO_BIT", 613 }, - { "GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE", 611 }, - { "GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE", 610 }, - { "GETDNS_CONTEXT_CODE_EDNS_VERSION", 612 }, - { "GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS", 602 }, - { "GETDNS_CONTEXT_CODE_IDLE_TIMEOUT", 617 }, - { "GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES", 606 }, - { "GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS", 615 }, - { "GETDNS_CONTEXT_CODE_NAMESPACES", 600 }, - { "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", 621 }, - { "GETDNS_CONTEXT_CODE_RESOLUTION_TYPE", 601 }, - { "GETDNS_CONTEXT_CODE_SUFFIX", 608 }, - { "GETDNS_CONTEXT_CODE_TIMEOUT", 616 }, - { "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", 618 }, - { "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", 620 }, - { "GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS", 603 }, - { "GETDNS_DNSSEC_BOGUS", 401 }, - { "GETDNS_DNSSEC_INDETERMINATE", 402 }, - { "GETDNS_DNSSEC_INSECURE", 403 }, - { "GETDNS_DNSSEC_NOT_PERFORMED", 404 }, - { "GETDNS_DNSSEC_SECURE", 400 }, - { "GETDNS_EXTENSION_FALSE", 1001 }, - { "GETDNS_EXTENSION_TRUE", 1000 }, - { "GETDNS_NAMESPACE_DNS", 500 }, - { "GETDNS_NAMESPACE_LOCALNAMES", 501 }, - { "GETDNS_NAMESPACE_MDNS", 503 }, - { "GETDNS_NAMESPACE_NETBIOS", 502 }, - { "GETDNS_NAMESPACE_NIS", 504 }, - { "GETDNS_NAMETYPE_DNS", 800 }, - { "GETDNS_NAMETYPE_WINS", 801 }, - { "GETDNS_OPCODE_IQUERY", 1 }, - { "GETDNS_OPCODE_NOTIFY", 4 }, - { "GETDNS_OPCODE_QUERY", 0 }, - { "GETDNS_OPCODE_STATUS", 2 }, - { "GETDNS_OPCODE_UPDATE", 5 }, - { "GETDNS_RCODE_BADALG", 21 }, - { "GETDNS_RCODE_BADKEY", 17 }, - { "GETDNS_RCODE_BADMODE", 19 }, - { "GETDNS_RCODE_BADNAME", 20 }, - { "GETDNS_RCODE_BADSIG", 16 }, - { "GETDNS_RCODE_BADTIME", 18 }, - { "GETDNS_RCODE_BADTRUNC", 22 }, - { "GETDNS_RCODE_BADVERS", 16 }, - { "GETDNS_RCODE_FORMERR", 1 }, - { "GETDNS_RCODE_NOERROR", 0 }, - { "GETDNS_RCODE_NOTAUTH", 9 }, - { "GETDNS_RCODE_NOTIMP", 4 }, - { "GETDNS_RCODE_NOTZONE", 10 }, - { "GETDNS_RCODE_NXDOMAIN", 3 }, - { "GETDNS_RCODE_NXRRSET", 8 }, - { "GETDNS_RCODE_REFUSED", 5 }, - { "GETDNS_RCODE_SERVFAIL", 2 }, - { "GETDNS_RCODE_YXDOMAIN", 6 }, - { "GETDNS_RCODE_YXRRSET", 7 }, - { "GETDNS_REDIRECTS_DO_NOT_FOLLOW", 531 }, - { "GETDNS_REDIRECTS_FOLLOW", 530 }, - { "GETDNS_RESOLUTION_RECURSING", 521 }, - { "GETDNS_RESOLUTION_STUB", 520 }, - { "GETDNS_RESPSTATUS_ALL_BOGUS_ANSWERS", 904 }, - { "GETDNS_RESPSTATUS_ALL_TIMEOUT", 902 }, - { "GETDNS_RESPSTATUS_GOOD", 900 }, - { "GETDNS_RESPSTATUS_NO_NAME", 901 }, - { "GETDNS_RESPSTATUS_NO_SECURE_ANSWERS", 903 }, - { "GETDNS_RETURN_BAD_CONTEXT", 301 }, - { "GETDNS_RETURN_BAD_DOMAIN_NAME", 300 }, - { "GETDNS_RETURN_CONTEXT_UPDATE_FAIL", 302 }, - { "GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED", 309 }, - { "GETDNS_RETURN_EXTENSION_MISFORMAT", 308 }, - { "GETDNS_RETURN_GENERIC_ERROR", 1 }, - { "GETDNS_RETURN_GOOD", 0 }, - { "GETDNS_RETURN_INVALID_PARAMETER", 311 }, - { "GETDNS_RETURN_MEMORY_ERROR", 310 }, - { "GETDNS_RETURN_NEED_MORE_SPACE", 399 }, - { "GETDNS_RETURN_NOT_IMPLEMENTED", 312 }, - { "GETDNS_RETURN_NO_SUCH_DICT_NAME", 305 }, - { "GETDNS_RETURN_NO_SUCH_EXTENSION", 307 }, - { "GETDNS_RETURN_NO_SUCH_LIST_ITEM", 304 }, - { "GETDNS_RETURN_UNKNOWN_TRANSACTION", 303 }, - { "GETDNS_RETURN_WRONG_TYPE_REQUESTED", 306 }, - { "GETDNS_RRCLASS_ANY", 255 }, - { "GETDNS_RRCLASS_CH", 3 }, - { "GETDNS_RRCLASS_HS", 4 }, - { "GETDNS_RRCLASS_IN", 1 }, - { "GETDNS_RRCLASS_NONE", 254 }, - { "GETDNS_RRTYPE_A", 1 }, - { "GETDNS_RRTYPE_AAAA", 28 }, - { "GETDNS_RRTYPE_AFSDB", 18 }, - { "GETDNS_RRTYPE_ANY", 255 }, - { "GETDNS_RRTYPE_APL", 42 }, - { "GETDNS_RRTYPE_ATMA", 34 }, - { "GETDNS_RRTYPE_AXFR", 252 }, - { "GETDNS_RRTYPE_CAA", 257 }, - { "GETDNS_RRTYPE_CDNSKEY", 60 }, - { "GETDNS_RRTYPE_CDS", 59 }, - { "GETDNS_RRTYPE_CERT", 37 }, - { "GETDNS_RRTYPE_CNAME", 5 }, - { "GETDNS_RRTYPE_CSYNC", 62 }, - { "GETDNS_RRTYPE_DHCID", 49 }, - { "GETDNS_RRTYPE_DLV", 32769 }, - { "GETDNS_RRTYPE_DNAME", 39 }, - { "GETDNS_RRTYPE_DNSKEY", 48 }, - { "GETDNS_RRTYPE_DS", 43 }, - { "GETDNS_RRTYPE_EID", 31 }, - { "GETDNS_RRTYPE_GID", 102 }, - { "GETDNS_RRTYPE_GPOS", 27 }, - { "GETDNS_RRTYPE_HINFO", 13 }, - { "GETDNS_RRTYPE_HIP", 55 }, - { "GETDNS_RRTYPE_IPSECKEY", 45 }, - { "GETDNS_RRTYPE_ISDN", 20 }, - { "GETDNS_RRTYPE_IXFR", 251 }, - { "GETDNS_RRTYPE_KEY", 25 }, - { "GETDNS_RRTYPE_KX", 36 }, - { "GETDNS_RRTYPE_LOC", 29 }, - { "GETDNS_RRTYPE_LP", 107 }, - { "GETDNS_RRTYPE_MAILA", 254 }, - { "GETDNS_RRTYPE_MAILB", 253 }, - { "GETDNS_RRTYPE_MB", 7 }, - { "GETDNS_RRTYPE_MD", 3 }, - { "GETDNS_RRTYPE_MF", 4 }, - { "GETDNS_RRTYPE_MG", 8 }, - { "GETDNS_RRTYPE_MINFO", 14 }, - { "GETDNS_RRTYPE_MR", 9 }, - { "GETDNS_RRTYPE_MX", 15 }, - { "GETDNS_RRTYPE_NAPTR", 35 }, - { "GETDNS_RRTYPE_NID", 104 }, - { "GETDNS_RRTYPE_NIMLOC", 32 }, - { "GETDNS_RRTYPE_NINFO", 56 }, - { "GETDNS_RRTYPE_NS", 2 }, - { "GETDNS_RRTYPE_NSAP", 22 }, - { "GETDNS_RRTYPE_NSEC", 47 }, - { "GETDNS_RRTYPE_NULL", 10 }, - { "GETDNS_RRTYPE_NXT", 30 }, - { "GETDNS_RRTYPE_OPENPGPKEY", 61 }, - { "GETDNS_RRTYPE_OPT", 41 }, - { "GETDNS_RRTYPE_PTR", 12 }, - { "GETDNS_RRTYPE_PX", 26 }, - { "GETDNS_RRTYPE_RKEY", 57 }, - { "GETDNS_RRTYPE_RP", 17 }, - { "GETDNS_RRTYPE_RRSIG", 46 }, - { "GETDNS_RRTYPE_RT", 21 }, - { "GETDNS_RRTYPE_SIG", 24 }, - { "GETDNS_RRTYPE_SINK", 40 }, - { "GETDNS_RRTYPE_SOA", 6 }, - { "GETDNS_RRTYPE_SPF", 99 }, - { "GETDNS_RRTYPE_SRV", 33 }, - { "GETDNS_RRTYPE_SSHFP", 44 }, - { "GETDNS_RRTYPE_TA", 32768 }, - { "GETDNS_RRTYPE_TALINK", 58 }, - { "GETDNS_RRTYPE_TKEY", 249 }, - { "GETDNS_RRTYPE_TLSA", 52 }, - { "GETDNS_RRTYPE_TSIG", 250 }, - { "GETDNS_RRTYPE_TXT", 16 }, - { "GETDNS_RRTYPE_UID", 101 }, - { "GETDNS_RRTYPE_UINFO", 100 }, - { "GETDNS_RRTYPE_UNSPEC", 103 }, - { "GETDNS_RRTYPE_URI", 256 }, - { "GETDNS_RRTYPE_WKS", 11 }, - { "GETDNS_TRANSPORT_TCP", 1201 }, - { "GETDNS_TRANSPORT_TCP_ONLY", 542 }, - { "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", 543 }, - { "GETDNS_TRANSPORT_TLS", 1202 }, - { "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", 545 }, - { "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", 544 }, - { "GETDNS_TRANSPORT_UDP", 1200 }, - { "GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP", 540 }, - { "GETDNS_TRANSPORT_UDP_ONLY", 541 }, -}; -static int const_name_info_cmp(const void *a, const void *b) -{ - return strcmp( ((struct const_name_info *) a)->name - , ((struct const_name_info *) b)->name ); -} -static int -_getdns_get_const_name_info(const char *name, uint32_t *code) -{ - struct const_name_info key = { name, 0 }; - struct const_name_info *i = bsearch(&key, consts_name_info, - sizeof(consts_name_info) / sizeof(struct const_name_info), - sizeof(struct const_name_info), const_name_info_cmp); - if (!i) - return 0; - if (code) - *code = i->code; - return 1; -} diff --git a/src/test/getdns_str2dict.h b/src/test/getdns_str2dict.h deleted file mode 100644 index 71cb26c8..00000000 --- a/src/test/getdns_str2dict.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2013, NLNet Labs, Verisign, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the names of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GETDNS_STR2DICT_H_ -#define GETDNS_STR2DICT_H_ -#include "getdns/getdns.h" - -getdns_return_t getdns_str2dict(const char *str, getdns_dict **dict); -getdns_return_t getdns_str2list(const char *str, getdns_list **list); -getdns_return_t getdns_str2bindata(const char *str, getdns_bindata **bindata); -getdns_return_t getdns_str2int(const char *str, uint32_t *value); - -#endif diff --git a/src/test/tests_transports.sh b/src/test/tests_transports.sh index 13e5b6b6..0cb0947b 100755 --- a/src/test/tests_transports.sh +++ b/src/test/tests_transports.sh @@ -5,25 +5,72 @@ SERVER_IP="8.8.8.8" SERVER_IPv6="2001:4860:4860::8888" TLS_SERVER_IP="185.49.141.38~getdnsapi.net" TLS_SERVER_IPv6="2a04:b900:0:100::38~getdnsapi.net" +TLS_SERVER_SS_IP="184.105.193.78~tls-dns-u.odvr.dns-oarc.net" #Self signed cert TLS_SERVER_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9S=" +TLS_SERVER_SS_KEY="pOXrpUt9kgPgbWxBFFcBTbRH2heo2wHwXp1fd4AEVXI=" TLS_SERVER_WRONG_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc1S=" GOOD_RESULT_SYNC="Status was: At least one response was returned" GOOD_RESULT_ASYNC="successfull" BAD_RESULT_SYNC="1 'Generic error'" BAD_RESULT_ASYNC="callback_type of 703" +NUM_ARGS=3 GOOD_COUNT=0 FAIL_COUNT=0 + +check_auth () { + local my_auth_ok=0; + auth_result=`echo $1 | sed 's/.*tls_auth_status\": .*//'` + if [[ $2 == "-" ]] ; then + my_auth_ok=1; + fi + if [[ $2 == "N" ]] && [[ $auth_result == "None" ]]; then + my_auth_ok=1; + fi + if [[ $2 == "F" ]] && [[ $auth_result == "Failed" ]]; then + my_auth_ok=1; + fi + if [[ $2 == "S" ]] && [[ $auth_result == "Success" ]]; then + my_auth_ok=1; + fi + echo $my_auth_ok; +} + +check_trans () { + local my_trans_ok=0; + trans_result=`echo $1 | sed "s/.*\"transport\": GETDNS_TRANSPORT_//" | sed 's/ }.*//' | sed 's/,.*//'` + if [[ $2 == "U" ]] && [[ $trans_result == "UDP" ]]; then + my_trans_ok=1; + fi + if [[ $2 == "T" ]] && [[ $trans_result == "TCP" ]]; then + my_trans_ok=1; + fi + if [[ $2 == "L" ]] && [[ $trans_result == "TLS" ]]; then + my_trans_ok=1; + fi + echo $my_trans_ok; +} + check_good () { - result=`echo $1 | grep "Response code was: GOOD." | tail -1 | sed 's/ All done.'// | sed 's/Response code was: GOOD. '//` + auth_ok=0; + result_ok=0; + trans_ok=0; + result=`echo $1 | sed 's/ All done.'// | sed 's/.*Response code was: GOOD. '//` async_success=`echo $result | grep -c "$GOOD_RESULT_ASYNC"` if [[ $result =~ $GOOD_RESULT_SYNC ]] || [[ $async_success =~ 1 ]]; then - (( GOOD_COUNT++ )) - echo -n "PASS: " - else - (( FAIL_COUNT++ )) - echo "FAIL (RESULT): " $1 - echo -n "FAIL: " + result_ok=1; + fi + if [[ $result_ok == 1 ]] ; then + trans_ok=$(check_trans "$1" "$2") + auth_ok=$(check_auth "$1" "$3") + fi + if [[ $result_ok == 1 ]] && [[ $auth_ok == 1 ]] && [[ $trans_ok == 1 ]]; then + (( GOOD_COUNT++ )) + echo -n "PASS: " + else + (( FAIL_COUNT++ )) + echo "FAIL (RESULT): Result: $result Auth: $auth_ok Trans: $trans_ok" + echo -n "FAIL: " fi } @@ -80,30 +127,38 @@ while getopts ":p:s:t:k:idh" opt; do done TLS_SERVER_IP_NO_NAME=`echo ${TLS_SERVER_IP%~*}` +TLS_SERVER_SS_IP_NO_NAME=`echo ${TLS_SERVER_SS_IP%~*}` TLS_SERVER_IP_WRONG_NAME=`echo ${TLS_SERVER_IP::${#TLS_SERVER_IP}-1}` +NUM_GOOD_QUERIES=7 GOOD_QUERIES=( -"-s -A -q getdnsapi.net -l U @${SERVER_IP} " -"-s -A -q getdnsapi.net -l T @${SERVER_IP} " -"-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP_NO_NAME}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"" -"-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") +"-s -A getdnsapi.net -l U @${SERVER_IP}" "U" "-" +"-s -A getdnsapi.net -l T @${SERVER_IP}" "T" "-" +"-s -A getdnsapi.net -l L @${TLS_SERVER_IP_NO_NAME}" "L" "N" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP}" "L" "S" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" "L" "S" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"" "L" "S" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_SS_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_SS_KEY}\"" "L" "S" +"-s -G DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D" "U" "-") +NUM_GOOD_FB_QUERIES=6 GOOD_FALLBACK_QUERIES=( -"-s -A -q getdnsapi.net -l LT @${SERVER_IP}" -"-s -A -q getdnsapi.net -l LT @${SERVER_IP}" -"-s -A -q getdnsapi.net -l LT @${TLS_SERVER_IP_NO_NAME}" -"-s -A -q getdnsapi.net -l LT -m @${TLS_SERVER_IP_NO_NAME}" -"-s -A -q getdnsapi.net -l L @${SERVER_IP} @${TLS_SERVER_IP_NO_NAME}" -"-s -G -q DNSKEY getdnsapi.net -l UT @${SERVER_IP} -b 512 -D") +"-s -A getdnsapi.net -l LU @${SERVER_IP}" "U" "-" +"-s -A getdnsapi.net -l LT @${SERVER_IP}" "T" "-" +"-s -A getdnsapi.net -l LT @${TLS_SERVER_IP_NO_NAME}" "L" "N" +"-s -A getdnsapi.net -l LT -m @${TLS_SERVER_IP_NO_NAME}" "L" "N" +"-s -A getdnsapi.net -l L @${SERVER_IP} @${TLS_SERVER_IP_NO_NAME}" "L" "-" +"-s -G DNSKEY getdnsapi.net -l UT @${SERVER_IP} -b 512 -D" "T" "-") NOT_AVAILABLE_QUERIES=( -"-s -A -q getdnsapi.net -l L @${SERVER_IP}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_WRONG_KEY}\"") +"-s -A getdnsapi.net -l L @${SERVER_IP}" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME}" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME}" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_WRONG_KEY}\"" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_WRONG_KEY}\"" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME} -K pin-sha256=\"${TLS_SERVER_WRONG_KEY}\"" +"-s -A getdnsapi.net -l L -m @${TLS_SERVER_SS_IP} -K pin-sha256=\"${TLS_SERVER_SS_KEY}\"") echo "Starting transport test" @@ -118,19 +173,19 @@ for (( i = 0; i < 2; i+=1 )); do fi echo "*Success cases:" - for (( j = 0; j < ${#GOOD_QUERIES[@]}; j+=1 )); do - check_good "`$DIR/getdns_query $SYNC_MODE ${GOOD_QUERIES[${j}]} 2>/dev/null`" - echo "getdns_query $SYNC_MODE ${GOOD_QUERIES[${j}]}" - (( COUNT++ )) + for (( j = 0; j < $NUM_GOOD_QUERIES; j+=1 )); do + check_good "`$DIR/getdns_query +return_call_reporting $SYNC_MODE ${GOOD_QUERIES[$j*$NUM_ARGS]} 2>/dev/null`" ${GOOD_QUERIES[$((j*NUM_ARGS))+1]} ${GOOD_QUERIES[$((j*NUM_ARGS))+2]} + echo "getdns_query $SYNC_MODE ${GOOD_QUERIES[$j*$NUM_ARGS]}" + (( COUNT++ )) done echo "*Success fallback cases:" - for (( j = 0; j < ${#GOOD_FALLBACK_QUERIES[@]}; j+=1 )); do - check_good "`$DIR/getdns_query $SYNC_MODE ${GOOD_FALLBACK_QUERIES[${j}]} 2>/dev/null`" - echo "getdns_query $SYNC_MODE ${GOOD_FALLBACK_QUERIES[${j}]}" - (( COUNT++ )) + for (( j = 0; j < $NUM_GOOD_FB_QUERIES; j+=1 )); do + check_good "`$DIR/getdns_query +return_call_reporting $SYNC_MODE ${GOOD_FALLBACK_QUERIES[$j*$NUM_ARGS]} 2>/dev/null`" ${GOOD_FALLBACK_QUERIES[$((j*NUM_ARGS))+1]} ${GOOD_FALLBACK_QUERIES[$((j*NUM_ARGS))+2]} + echo "getdns_query $SYNC_MODE ${GOOD_FALLBACK_QUERIES[$j*$NUM_ARGS]} TESTS: ${GOOD_FALLBACK_QUERIES[$((j*NUM_ARGS))+1]} ${GOOD_FALLBACK_QUERIES[$((j*NUM_ARGS))+2]}" + (( COUNT++ )) done - + echo "*Transport not available cases:" for (( j = 0; j < ${#NOT_AVAILABLE_QUERIES[@]}; j+=1 )); do check_bad "`$DIR/getdns_query $SYNC_MODE ${NOT_AVAILABLE_QUERIES[${j}]} 2>&1`" diff --git a/src/test/tpkg/110-link.tpkg/110-link.test b/src/test/tpkg/110-link.tpkg/110-link.test index c0d77db0..424c9074 100644 --- a/src/test/tpkg/110-link.tpkg/110-link.test +++ b/src/test/tpkg/110-link.tpkg/110-link.test @@ -6,5 +6,5 @@ cd "${BUILDDIR}/build" make getdns_query \ - && echo "export GETDNS_QUERY=\"${BUILDDIR}/build/src/test/getdns_query\"" \ + && echo "export GETDNS_QUERY=\"${BUILDDIR}/build/src/tools/getdns_query\"" \ >> ../.tpkg.var.master diff --git a/src/test/tpkg/210-stub-only-link.tpkg/210-stub-only-link.test b/src/test/tpkg/210-stub-only-link.tpkg/210-stub-only-link.test index 33379762..94aaf626 100644 --- a/src/test/tpkg/210-stub-only-link.tpkg/210-stub-only-link.test +++ b/src/test/tpkg/210-stub-only-link.tpkg/210-stub-only-link.test @@ -6,5 +6,5 @@ cd "${BUILDDIR}/build-stub-only" make getdns_query \ - && echo "export GETDNS_STUB_QUERY=\"${BUILDDIR}/build-stub-only/src/test/getdns_query\"" \ + && echo "export GETDNS_STUB_QUERY=\"${BUILDDIR}/build-stub-only/src/tools/getdns_query\"" \ >> ../.tpkg.var.master diff --git a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.dsc b/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.dsc deleted file mode 100644 index 82cbdb8c..00000000 --- a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.dsc +++ /dev/null @@ -1,16 +0,0 @@ -BaseName: 315-event-loops-compile -Version: 1.0 -Description: Compile -CreationDate: do 8 dec 2016 23:38:18 CET -Maintainer: Willem Toorop -Category: -Component: -CmdDepends: -Depends: 300-event-loops-configure.tpkg -Help: -Pre: 315-event-loops-compile.pre -Post: 315-event-loops-compile.post -Test: 315-event-loops-compile.test -AuxFiles: -Passed: -Failure: diff --git a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.post b/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.post deleted file mode 100644 index 4d5f4293..00000000 --- a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.post +++ /dev/null @@ -1,20 +0,0 @@ -# #-- 315-event-loops-compile.post --# -# source the master var file when it's there -if [ -f ../.tpkg.var.master ] -then - source ../.tpkg.var.master -else - ( - cd .. - [ -f "${TPKG_SRCDIR}/setup-env.sh" ] \ - && sh "${TPKG_SRCDIR}/setup-env.sh" - ) && source ../.tpkg.var.master -fi -# use .tpkg.var.test for in test variable passing -[ -f .tpkg.var.test ] && source .tpkg.var.test - -for f in `cat restore-srcdir-configure-settings` -do - mv "${SRCROOT}/${f}.build-event-loops" "${SRCROOT}/${f}" -done - diff --git a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.pre b/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.pre deleted file mode 100644 index 4ec46299..00000000 --- a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.pre +++ /dev/null @@ -1,24 +0,0 @@ -# #-- 315-event-loops-compile.pre--# -# source the master var file when it's there -if [ -f ../.tpkg.var.master ] -then - source ../.tpkg.var.master -else - ( - cd .. - [ -f "${TPKG_SRCDIR}/setup-env.sh" ] \ - && sh "${TPKG_SRCDIR}/setup-env.sh" - ) && source ../.tpkg.var.master -fi -# use .tpkg.var.test for in test variable passing -[ -f .tpkg.var.test ] && source .tpkg.var.test - -echo "" > restore-srcdir-configure-settings -for f in `grep 'CONFIG_[FH][IE][LA][ED][SE]' "${SRCROOT}/configure.ac" | sed -e 's/^.*(\[//g' -e 's/\])//g'` -do - if [ -f "${SRCROOT}/$f" ] - then - mv "${SRCROOT}/${f}" "${SRCROOT}/${f}.build-event-loops" && \ - echo "$f" >> restore-srcdir-configure-settings - fi -done diff --git a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.test b/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.test deleted file mode 100644 index 7a420026..00000000 --- a/src/test/tpkg/315-event-loops-compile.tpkg/315-event-loops-compile.test +++ /dev/null @@ -1,8 +0,0 @@ -# #-- 315-event-loops-compile.test --# -# source the master var file when it's there -[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master -# use .tpkg.var.test for in test variable passing -[ -f .tpkg.var.test ] && source .tpkg.var.test - -cd "${BUILDDIR}/build-event-loops" -make XTRA_CFLAGS='-Werror' diff --git a/src/test/tpkg/320-event-loops-compile.tpkg/320-event-loops-compile.test b/src/test/tpkg/320-event-loops-compile.tpkg/320-event-loops-compile.test index aa19d023..1be03f3d 100644 --- a/src/test/tpkg/320-event-loops-compile.tpkg/320-event-loops-compile.test +++ b/src/test/tpkg/320-event-loops-compile.tpkg/320-event-loops-compile.test @@ -5,5 +5,4 @@ [ -f .tpkg.var.test ] && source .tpkg.var.test cd "${BUILDDIR}/build-event-loops" -make clean -make +make XTRA_CFLAGS=-Werror diff --git a/src/test/tpkg/run-all-lcov.sh b/src/test/tpkg/run-all-lcov.sh index 740ef828..37bf8cea 100755 --- a/src/test/tpkg/run-all-lcov.sh +++ b/src/test/tpkg/run-all-lcov.sh @@ -15,7 +15,7 @@ LCOV_MERGE="" for TEST_PKG in ${SRCDIR}/*.tpkg do # when we run our test, we need to compile with profiling - CFLAGS="-fprofile-arcs -ftest-coverage -O0" "${TPKG}" $* exe "${TEST_PKG}" + LDFLAGS="-lgcov --coverage" CFLAGS="-fprofile-arcs -ftest-coverage -O0" "${TPKG}" $* exe "${TEST_PKG}" # after the test is complete, we need to collect the coverage data INFO_FILE=`echo $TEST_PKG | sed 's/.tpkg$//'`.info geninfo $SRCDIR/.. -o $INFO_FILE diff --git a/src/tools/Makefile.in b/src/tools/Makefile.in new file mode 100644 index 00000000..d98cf437 --- /dev/null +++ b/src/tools/Makefile.in @@ -0,0 +1,117 @@ +# +# @configure_input@ +# +# Copyright (c) 2013, Verisign, Inc., NLNet Labs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the names of the copyright holders nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package = @PACKAGE_NAME@ +version = @PACKAGE_VERSION@ +tarname = @PACKAGE_TARNAME@ +distdir = $(tarname)-$(version) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +INSTALL = @INSTALL@ +LIBTOOL = ../../libtool + +srcdir = @srcdir@ + +CC=@CC@ +WPEDANTICFLAG=@WPEDANTICFLAG@ +CFLAGS=-I$(srcdir)/.. -I$(srcdir) -I.. $(cflags) @CFLAGS@ @CPPFLAGS@ $(WPEDANTICFLAG) $(XTRA_CFLAGS) +LDFLAGS=-L.. @LDFLAGS@ +LDLIBS=../libgetdns.la @LIBS@ + +ALL_OBJS=getdns_query.lo + +PROGRAMS=getdns_query + + +.SUFFIXES: .c .o .a .lo .h + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +.c.lo: + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@ + +default: all + +all: $(PROGRAMS) + +$(ALL_OBJS): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(srcdir)/$(@:.lo=.c) -o $@ + +getdns_query: getdns_query.lo + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) + +stubby: getdns_query.lo + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ getdns_query.lo $(LDFLAGS) $(LDLIBS) + +install-getdns_query: getdns_query + $(INSTALL) -m 755 -d $(DESTDIR)$(bindir) + $(LIBTOOL) --mode=install cp getdns_query $(DESTDIR)$(bindir) + +uninstall-getdns_query: + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/getdns_query + +install-stubby: getdns_query + $(INSTALL) -m 755 -d $(DESTDIR)$(bindir) + $(LIBTOOL) --mode=install cp getdns_query $(DESTDIR)$(bindir)/stubby + +uninstall-stubby: + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/stubby + +clean: + rm -f *.o *.lo $(PROGRAMS) + rm -rf .libs + +distclean : clean + rm -f Makefile + +Makefile: $(srcdir)/Makefile.in ../../config.status + cd ../.. && ./config.status src/test/Makefile + +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.. -I"$$blddir"/.. *.c | \ + sed -e "s? $$blddir/? ?g" \ + -e 's? \([a-z0-9_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ + -e 's? \.\./\([a-z0-9_-]*\)\.h? $$(srcdir)/../\1.h?g' \ + -e 's? \.\./\([a-z0-9_-]*\)/\([a-z0-9_-]*\)\.h? $$(srcdir)/../\1/\2.h?g' \ + -e 's? \$$(srcdir)/config\.h? ../config.h?g' \ + -e 's? \$$(srcdir)/\.\./config\.h? ../config.h?g' \ + -e 's? \$$(srcdir)/\.\./getdns/getdns\.h? ../getdns/getdns.h?g' \ + -e 's? \$$(srcdir)/\.\./getdns/getdns_extra\.h? ../getdns/getdns_extra.h?g' \ + -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new ) + (cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \ + || mv Makefile.in.new Makefile.in ) + +.PHONY: clean test + +# Dependencies for getdns_query +getdns_query.lo getdns_query.o: $(srcdir)/getdns_query.c ../config.h $(srcdir)/../debug.h ../config.h \ + ../getdns/getdns.h ../getdns/getdns_extra.h diff --git a/src/test/getdns_query.c b/src/tools/getdns_query.c similarity index 86% rename from src/test/getdns_query.c rename to src/tools/getdns_query.c index 8230b7ef..61825f1b 100644 --- a/src/test/getdns_query.c +++ b/src/tools/getdns_query.c @@ -27,9 +27,6 @@ #include "config.h" #include "debug.h" -#include "getdns_str2dict.h" -#include "getdns_context_config.h" -#include "getdns_context_set_listen_addresses.h" #include #include #include @@ -51,6 +48,19 @@ typedef unsigned short in_port_t; #define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" +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: 256" +", 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; @@ -154,13 +164,19 @@ print_usage(FILE *out, const char *progname) { fprintf(out, "usage: %s [