Description: add module stubby
 .
 getdns (1.2.0-1) unstable; urgency=medium
 .
   * New upstream version
Author: Stefan Meinecke <meinecke@greensec.de>

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- /dev/null
+++ getdns-1.2.0/stubby/COPYING
@@ -0,0 +1,30 @@
+Copyright (c) 2016, NLnet Labs. All rights reserved.
+
+This software is open source.
+
+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 name of the NLNET LABS 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 THE COPYRIGHT
+HOLDER OR CONTRIBUTORS 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.
--- /dev/null
+++ getdns-1.2.0/stubby/ChangeLog
@@ -0,0 +1,17 @@
+* 2017-09: Version 0.1.3
+* Change the default configuration file format to be YAML. A default file 
+  'stubby.yml' will be installed. The JSON dict format is still supported when
+   specifying a custom configuration file on the command line.
+* Add a -v flag to let users specify the logging level they want to see
+
+* 2017-08-24: Version 0.1.2
+  * revert logging to stderr until we have good separation of logging and error
+    within the code
+
+* 2017-08-23: Version 0.1.1
+  * systemd folder has moved here from the getdns repo
+  * logging can now be controlled at runtime using the '-l' flag
+  * minor fixes from a static analysis
+
+* 2017-07-12: Version 0.1.0
+  * Initial release of stubby after break-out from getdns repository
--- /dev/null
+++ getdns-1.2.0/stubby/Makefile.am
@@ -0,0 +1,18 @@
+stubbyconfdir = $(sysconfdir)/stubby
+dist_stubbyconf_DATA = stubby.yml.example
+if ON_MACOS
+dist_sbin_SCRIPTS = stubby-setdns-macos.sh
+endif
+if ON_WINDOWS
+CONFIG_FILE = stubby.yml.windows
+else
+CONFIG_FILE = ${srcdir}/stubby.yml.example
+endif
+SUBDIRS=src
+
+stubby.yml.windows: ${srcdir}/stubby.yml.example
+	awk "{sub(/$$/,\"\r\")}1" $< > $@
+
+install-data-hook: $(CONFIG_FILE)
+	test -f ${stubbyconfdir}/stubby.yml || \
+		${INSTALL_DATA} $(CONFIG_FILE) ${stubbyconfdir}/stubby.yml
--- /dev/null
+++ getdns-1.2.0/stubby/README
@@ -0,0 +1,3 @@
+autoreconf -vfi
+./configure CFLAGS="-g -I$HOME/local2/include" LDFLAGS="-L$HOME/local2/lib" --prefix="$HOME/local2"
+make
--- /dev/null
+++ getdns-1.2.0/stubby/README.md
@@ -0,0 +1,225 @@
+# About Stubby
+
+Stubby is an application that acts as a local **DNS Privacy stub resolver** (using DNS-over-TLS). Stubby encrypts DNS queries sent from a client machine (desktop or laptop) to a DNS Privacy resolver increasing end user privacy. Stubby is in the early stages of development but is suitable for technical/advanced users. A more generally user-friendly version is on the way!
+
+Stubby provides DNS Privacy by:
+
+* Running as a daemon
+* Listening on the loopback address to send all outgoing DNS queries received on that address out over TLS
+* Using a default configuration which provides Strict Privacy and uses a subset
+of the available [DNS Privacy servers](https://dnsprivacy.org/wiki/x/E4AT)
+
+Stubby is developed by the getdns team.
+
+# Documentation
+
+See [Stubby Homepage](https://dnsprivacy.org/wiki/x/JYAT) for more details
+
+# Dependancies
+
+Stubby uses [getdns](https://getdnsapi.net/) and requires the 1.2 release of getdns or later.
+
+# Installing Using a Package Manager
+
+Check to see if getdns and Stubby are available via a package manager.
+
+UPDATE: August 2017 - A Homebrew package for stubby is now available (`brew install stubby`) !
+
+If you need to install getdns from source, see the section [at the end of this document.](#building-getdns-from-source)
+
+# Build Stubby from source
+
+Get the code:
+```
+git clone https://github.com/getdnsapi/stubby.git
+```
+
+Build and install (the paths below assume that getdns is installed in a standard location e.g. by Homebrew in /usr/local/)
+```
+cd stubby
+autoreconf -vfi
+./configure CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"
+make
+sudo make install
+````
+
+# Configure Stubby
+
+_It is recommended to use the default configuration file provided which will use 'Strict' privacy mode and spread the DNS 
+queries among several of the current DNS Privacy test servers. Note that this file contains both IPv4 and IPv6 addresses. 
+This file is installed on *nix systems as /usr/local/etc/stubby/stubby.yml_
+
+The configuration file format is a YAML like format and the name of the file must have an extension of .yml. Essentially the 
+configuration options available are the same as the options that can be set on a getdns `context` - Doxygen documentation for 
+which is available [here](https://getdnsapi.net/doxygen/group__getdns__context.html). To aid with creating a custom configuration file, an example is given below.
+
+NOTE: As of the 0.1.3 release of Stubby the YAML format replaces the JSON like format used in earlier versions of the configuration file for getdns/stubby. The YAML format is 
+more human readable and supports comments allowing options to be easily enabled and disabled. The JSON format is that which is used internally in getdns
+(it is the same as the output returned by `stubby -i`) and is still available by directly specifying a file with the name 'stubby.conf' on the command line using the -C option.
+
+## Create Custom Configuration File
+
+Alternatively the configuration file location can be specified on the command line using the `-C` flag. Changes to the configuration file require a restart of Stubby.
+
+The config file below will configure Stubby in the following ways:
+
+*  `resolution_type`: Work in stub mode only (not recursive mode) - required for Stubby operation.
+*  `dns_transport_list`: Use TLS only as a transport (no fallback to UDP or TCP). 
+*  `tls_authentication`:  Use Strict Privacy i.e. require a TLS connection and authentication of the upstream
+  * If Opportunistic mode is desired, simply remove the `tls_authentication: GETDNS_AUTHENTICATION_REQUIRED` field. In Opportunistic mode authentication of the nameserver is not required and fallback to clear text transports is permitted if they are in the `dns_transport_list`.
+*  `tls_query_padding_blocksize`: Use the EDNS0 padding option to pad DNS queries to hide their size
+*  `edns_client_subnet_private`: Use EDNS0 Client Subnet privacy so the client subnet is not sent to authoritative servers
+* ` idle_timeout`:  Use an EDNS0 Keepalive idle timeout of 10s unless overridden by the server. This keeps idle TLS connections open to avoid the overhead of opening a new connection for every query.
+*  `listen_address`: have the Stubbby daemon listen on IPv4 and IPv6 on port 53 on the loopback address
+*   `round_robin_upstreams`: Round robin queries across all the configured upstream servers. Without this option Stubby will use each upstream server sequentially until it becomes unavailable and then move on to use the next. 
+*  `upstream_recursive_servers`: Use the NLnet labs test DNS Privacy Server for outgoing queries. In Strict Privacy mode, at least one of the following is required for each nameserver:
+  *  `tls_auth_name`: This is the authentication domain name that will be verified against the presented certificate. 
+  * `tls_pubkey_pinset`: The sha256 SPKI pinset for the server. This is also verified against the presented certificate. 
+
+```
+resolution_type: GETDNS_RESOLUTION_STUB
+dns_transport_list: 
+  - GETDNS_TRANSPORT_TLS
+tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
+tls_query_padding_blocksize: 256
+edns_client_subnet_private : 1
+idle_timeout: 10000
+listen_addresses:
+  - 127.0.0.1
+  -  0::1
+round_robin_upstreams: 1
+upstream_recursive_servers:
+  - address_data: 185.49.141.38
+    tls_auth_name: "getdnsapi.net"
+    tls_pubkey_pinset:
+      digest: "sha256"
+       value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=
+```
+
+Additional privacy servers can be specified by adding more entries to the `upstream_recursive_servers` list above (note a separate entry must be made for the IPv4 and IPv6 addresses of a given server. More DNS Privacy test servers are listed [here](https://dnsprivacy.org/wiki/x/E4AT).
+
+A custom port can be specified by adding the `tls_port:` attribute to the `upstream_recursive_server` in the config file. 
+
+More details can be found in the comments in the default configuration file and at https://dnsprivacy.org/wiki/display/DP/Configuring+Stubby
+
+# Run Stubby
+
+
+Simply invoke Stubby on the command line. By default it runs in the foreground, the `-g` flag runs it in the background. 
+
+```sh
+> sudo stubby
+```
+
+* Enable connection logging by using the `-l` flag. The logging is currently simplistic and simply writes to stdout. (We are working on making this better!)
+* The pid file is /var/run/stubby.pid
+
+# Test Stubby
+
+A quick test can be done by using dig (or your favourite DNS tool) on the loopback address
+
+```sh
+> dig @127.0.0.1 www.example.com
+```
+
+# Modify your upstream resolvers
+
+!!! <span class="glyphicon glyphicon-warning-sign"></span> Once this change is made your DNS queries will be re-directed to Stubby and sent over TLS! <br>
+(You may need to restart some applications to have them pick up the network settings). <p>You can monitor the traffic using Wireshark watching on port 853.</p>
+
+For Stubby to re-send outgoing DNS queries over TLS the system stub resolvers on your machine must be changed to send all the local queries to the loopback interface on which Stubby is listening. This depends on the operating system being run. It is useful to note your existing default nameservers before making this change!
+
+
+## Linux/Unix systems
+
+* Edit the /etc/resolv.conf file
+* Comment out the existing *nameserver* entries
+* Add the following (only add the IPv4 address if you don't have IPv6)
+  ```sh
+  nameserver 127.0.0.1
+  nameserver ::1
+  ```
+
+## OS X
+
+A script is provided with Stubby for easier configuration. From the command line you can do the following to switch all your queries to use Stubby
+
+```sh
+> sudo /usr/local/sbin/stubby-setdns-macos.sh
+```
+
+If you want to reset, just use:
+
+```sh
+> sudo /usr/local/sbin/stubby-setdns-macos.sh -r
+```
+
+which should pick up the default DHCP nameservers.
+
+You can add /usr/local/sbin to your path to avoid having to type it above by doing
+```
+export PATH=/usr/local/sbin:$PATH
+```
+
+Or via the GUI:
+
+* Open *System Preferences &rarr; Network &rarr; Advanced &rarr; DNS*
+* Use the '-' button to remove the existing nameservers
+* Use the '+' button to add `127.0.0.1` and `::1` (only add the IPv4 address if you don't have IPv6)
+* Hit 'OK' in the *DNS* pane and then 'Apply' on the *Network* pane
+
+
+## Notes:
+
+* If Stubby works for a while but you then see failures from Stubby such as "None of the configured upstreams could be used to send queries on the specified transports" try restarting Stubby.
+* If you are using a DNS Privacy server that does not support concurrent processing of TLS queries, you may experience some issues due to timeouts causing subsequent queries on the same connection to fail.
+
+# Building getdns from Source
+
+Note that from getdns 1.1.3 stubby is included in the getdns code as a git submodule. Therefore stubby and getdns can be built together by following the
+instructions below but adding the ``--with-stubby`` flag to the `configure` step.
+
+## Dependencies
+
+The most limited install of getdns that will work with Stubby requires only OpenSSL as a dependancy (version 1.0.2 or later is required for hostname authentication to be supported). If OpenSSL is installed in a non-standard location on your system use the `--with-ssl` option to `configure` below to specify where it is installed.
+
+### Linux
+
+It may be necessary to install [1.0.2 from source](https://openssl.org/source/openssl-1.0.2h.tar.gz) for most Linux distros.
+
+### OS X
+
+It is recommended to [install OpenSSL using homebrew](http://brewformulas.org/Openssl), in which case use the following in the `configure` line in the build step below:
+
+```sh
+--with-ssl=/usr/local/opt/openssl/
+```
+
+## Download the getdns source
+
+Either clone the code:
+
+```sh
+> git clone https://github.com/getdnsapi/getdns.git
+> cd getdns
+> git checkout develop
+```
+for the very latest version of getdns or grab a release tarball from this page: [Latest getdns releases](https://getdnsapi.net/releases/)
+
+## Build the code
+
+Note that on Mac OS X you will need the developer tools from Xcode to compile the code. And you may need to use brew to install libtool, autoconf, and automake.
+
+```sh
+> git submodule update --init
+> autoreconf -fi
+> mkdir build
+> cd build
+> ../configure --prefix=<install_location> --without-libidn --enable-stub-only
+> make
+> sudo make install
+```
+
+Logging/debugging
+
+> **`--enable-debug-stub`**   If you do want to see _very_ detailed debug information as messages are processed then add the `--enable-debug-stub` option to the `configure` line above (not recommended for use with Stubby)
--- /dev/null
+++ getdns-1.2.0/stubby/configure.ac
@@ -0,0 +1,246 @@
+AC_PREREQ([2.68])
+AC_INIT([Stubby], [0.1.3], [sara@sinodun.com])
+AM_INIT_AUTOMAKE
+AC_CONFIG_SRCDIR([src/stubby.c])
+AC_CONFIG_HEADERS([config.h])
+
+AC_PROG_CC([clang gcc])
+
+AC_CHECK_LIB([getdns], [getdns_context_set_trust_anchors_url],,
+    [AC_MSG_ERROR([Missing dependency: getdns >= 1.2.0 ])],)
+AC_CHECK_HEADERS([getdns/getdns_extra.h],,
+    [AC_MSG_ERROR([Missing dependency getdns development headers])],)
+AC_CHECK_FUNCS([getdns_yaml2dict],, [
+	AC_CHECK_LIB([yaml], [yaml_parser_parse],,
+	    [AC_MSG_ERROR([Missing dependency: libyaml])])
+])
+AM_CONDITIONAL([WITH_YAML], [test "x$ac_cv_func_getdns_yaml2dict" = xno])
+AC_CHECK_HEADERS([assert.h stdio.h stdarg.h])
+
+AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "format" attribute)
+AC_TRY_COMPILE([
+	#include <stdio.h>
+	void f (char *format, ...) __attribute__ ((format (printf, 1, 2)));
+	void (*pf) (char *format, ...) __attribute__ ((format (printf, 1, 2)));
+], [f ("%s", "str");], [
+	AC_MSG_RESULT(yes)
+	AC_DEFINE(HAVE_ATTR_FORMAT, 1,
+	    [Whether the C compiler accepts the "format" attribute])
+], [
+	AC_MSG_RESULT(no)
+])
+
+AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "unused" attribute)
+AC_TRY_COMPILE([
+	#include <stdio.h>
+	void f (char *u __attribute__((unused)));
+], [f ("x");], [
+	AC_MSG_RESULT(yes)
+	AC_DEFINE(HAVE_ATTR_UNUSED, 1,
+	    [Whether the C compiler accepts the "unused" attribute])
+], [
+	AC_MSG_RESULT(no)
+])
+
+build_on_windows = 0
+build_on_macos = 0
+build_on_unix = 0
+AC_CANONICAL_HOST
+case "${host_os}" in
+cygwin*|mingw*)
+	AC_DEFINE(STUBBY_ON_WINDOWS, 1, [Whether the build target is Windows])
+	build_on_windows = 1
+	;;
+darwin*)
+	build_on_macos = 1
+	;;
+*)
+	build_on_unix = 1
+	;;
+esac
+AM_CONDITIONAL([ON_WINDOWS], [test $build_on_windows -eq 1])
+AM_CONDITIONAL([ON_MACOS], [test $build_on_macos -eq 1])
+AM_CONDITIONAL([ON_UNIX], [test $build_on_unix -eq 1])
+
+AC_CONFIG_FILES([Makefile
+                 src/Makefile])
+
+AH_BOTTOM([
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifdef STUBBY_ON_WINDOWS
+# ifndef  _CUSTOM_VSNPRINTF
+#  define _CUSTOM_VSNPRINTF
+	static inline int _gldns_custom_vsnprintf(
+	    char *str, size_t size, const char *format, va_list ap)
+	{ int r = vsnprintf(str, size, format, ap)
+	; return r == -1 ? _vscprintf(format, ap) : r; }
+#  define vsnprintf _gldns_custom_vsnprintf
+# endif
+# define PRIsz "Iu"
+#else
+# define PRIsz "zu"
+#endif
+
+#ifdef HAVE_ATTR_FORMAT
+# define ATTR_FORMAT(archetype, string_index, first_to_check) \
+    __attribute__ ((format (archetype, string_index, first_to_check)))
+#else /* !HAVE_ATTR_FORMAT */
+# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
+#endif /* !HAVE_ATTR_FORMAT */
+
+#if defined(__cplusplus)
+#  define ATTR_UNUSED(x)
+#elif defined(HAVE_ATTR_UNUSED)
+#  define ATTR_UNUSED(x)  x __attribute__((unused))
+#else /* !HAVE_ATTR_UNUSED */
+#  define ATTR_UNUSED(x)  x
+#endif /* !HAVE_ATTR_UNUSED */
+
+#ifndef HAVE_GETDNS_YAML2DICT
+# define USE_YAML_CONFIG 1
+#endif
+
+#define yaml_string_to_json_string        stubby_yaml_string_to_json_string
+
+#define sldns_read_uint16                 stubby_ldns_read_uint16
+#define sldns_read_uint32                 stubby_ldns_read_uint32
+#define sldns_write_uint16                stubby_ldns_write_uint16
+#define sldns_write_uint32                stubby_ldns_write_uint32
+#define sldns_write_uint48                stubby_ldns_write_uint48
+#define sldns_buffer                      stubby_ldns_buffer
+#define sldns_buffer_invariant            stubby_ldns_buffer_invariant
+#define sldns_buffer_invariant            stubby_ldns_buffer_invariant
+#define sldns_buffer_new                  stubby_ldns_buffer_new
+#define sldns_buffer_new_frm_data         stubby_ldns_new_frm_data
+#define sldns_buffer_init_frm_data        stubby_ldns_buffer_init_frm_data
+#define sldns_buffer_init_vfixed_frm_data stubby_ldns_buffer_init_vfixed_frm_data
+#define sldns_buffer_clear                stubby_ldns_buffer_clear
+#define sldns_buffer_flip                 stubby_ldns_buffer_flip
+#define sldns_buffer_rewind               stubby_ldns_buffer_rewind
+#define sldns_buffer_position             stubby_ldns_buffer_position
+#define sldns_buffer_set_position         stubby_ldns_buffer_set_position
+#define sldns_buffer_skip                 stubby_ldns_buffer_skip
+#define sldns_buffer_limit                stubby_ldns_buffer_limit
+#define sldns_buffer_set_limit            stubby_ldns_buffer_set_limit
+#define sldns_buffer_capacity             stubby_ldns_buffer_capacity
+#define sldns_buffer_set_capacity         stubby_ldns_buffer_set_capacity
+#define sldns_buffer_reserve              stubby_ldns_buffer_reserve
+#define sldns_buffer_at                   stubby_ldns_buffer_at
+#define sldns_buffer_begin                stubby_ldns_buffer_begin
+#define sldns_buffer_end                  stubby_ldns_buffer_end
+#define sldns_buffer_current              stubby_ldns_buffer_current
+#define sldns_buffer_remaining_at         stubby_ldns_buffer_remaining_at
+#define sldns_buffer_remaining            stubby_ldns_buffer_remaining
+#define sldns_buffer_available_at         stubby_ldns_buffer_available_at
+#define sldns_buffer_available            stubby_ldns_buffer_available
+#define sldns_buffer_write_at             stubby_ldns_buffer_write_at
+#define sldns_buffer_set_at               stubby_ldns_buffer_set_at
+#define sldns_buffer_write                stubby_ldns_buffer_write
+#define sldns_buffer_write_string_at      stubby_ldns_buffer_write_string_at
+#define sldns_buffer_write_string         stubby_ldns_buffer_write_string
+#define sldns_buffer_write_u8_at          stubby_ldns_buffer_write_u8_at
+#define sldns_buffer_write_u8             stubby_ldns_buffer_write_u8
+#define sldns_buffer_write_u16_at         stubby_ldns_buffer_write_u16_at
+#define sldns_buffer_write_u16            stubby_ldns_buffer_write_u16
+#define sldns_buffer_write_u32_at         stubby_ldns_buffer_write_u32_at
+#define sldns_buffer_write_u48_at         stubby_ldns_buffer_write_u48_at
+#define sldns_buffer_write_u32            stubby_ldns_buffer_write_u32
+#define sldns_buffer_write_u48            stubby_ldns_buffer_write_u48
+#define sldns_buffer_read_at              stubby_ldns_buffer_read_at
+#define sldns_buffer_read                 stubby_ldns_buffer_read
+#define sldns_buffer_read_u8_at           stubby_ldns_buffer_read_u8_at
+#define sldns_buffer_read_u8              stubby_ldns_buffer_read_u8
+#define sldns_buffer_read_u16_at          stubby_ldns_buffer_read_u16_at
+#define sldns_buffer_read_u16             stubby_ldns_buffer_read_u16
+#define sldns_buffer_read_u32_at          stubby_ldns_buffer_read_u32_at
+#define sldns_buffer_read_u32             stubby_ldns_buffer_read_u32
+#define sldns_buffer_status               stubby_ldns_buffer_status
+#define sldns_buffer_status_ok            stubby_ldns_buffer_status_ok
+#define sldns_buffer_printf               stubby_ldns_buffer_printf
+#define sldns_buffer_free                 stubby_ldns_buffer_free
+#define sldns_buffer_export               stubby_ldns_buffer_export
+#define sldns_buffer_copy                 stubby_ldns_buffer_copy
+
+#define gldns_read_uint16                 stubby_ldns_read_uint16
+#define gldns_read_uint32                 stubby_ldns_read_uint32
+#define gldns_write_uint16                stubby_ldns_write_uint16
+#define gldns_write_uint32                stubby_ldns_write_uint32
+#define gldns_write_uint48                stubby_ldns_write_uint48
+#define gldns_buffer                      stubby_ldns_buffer
+#define gldns_buffer_invariant            stubby_ldns_buffer_invariant
+#define gldns_buffer_invariant            stubby_ldns_buffer_invariant
+#define gldns_buffer_new                  stubby_ldns_buffer_new
+#define gldns_buffer_new_frm_data         stubby_ldns_new_frm_data
+#define gldns_buffer_init_frm_data        stubby_ldns_buffer_init_frm_data
+#define gldns_buffer_init_vfixed_frm_data stubby_ldns_buffer_init_vfixed_frm_data
+#define gldns_buffer_clear                stubby_ldns_buffer_clear
+#define gldns_buffer_flip                 stubby_ldns_buffer_flip
+#define gldns_buffer_rewind               stubby_ldns_buffer_rewind
+#define gldns_buffer_position             stubby_ldns_buffer_position
+#define gldns_buffer_set_position         stubby_ldns_buffer_set_position
+#define gldns_buffer_skip                 stubby_ldns_buffer_skip
+#define gldns_buffer_limit                stubby_ldns_buffer_limit
+#define gldns_buffer_set_limit            stubby_ldns_buffer_set_limit
+#define gldns_buffer_capacity             stubby_ldns_buffer_capacity
+#define gldns_buffer_set_capacity         stubby_ldns_buffer_set_capacity
+#define gldns_buffer_reserve              stubby_ldns_buffer_reserve
+#define gldns_buffer_at                   stubby_ldns_buffer_at
+#define gldns_buffer_begin                stubby_ldns_buffer_begin
+#define gldns_buffer_end                  stubby_ldns_buffer_end
+#define gldns_buffer_current              stubby_ldns_buffer_current
+#define gldns_buffer_remaining_at         stubby_ldns_buffer_remaining_at
+#define gldns_buffer_remaining            stubby_ldns_buffer_remaining
+#define gldns_buffer_available_at         stubby_ldns_buffer_available_at
+#define gldns_buffer_available            stubby_ldns_buffer_available
+#define gldns_buffer_write_at             stubby_ldns_buffer_write_at
+#define gldns_buffer_set_at               stubby_ldns_buffer_set_at
+#define gldns_buffer_write                stubby_ldns_buffer_write
+#define gldns_buffer_write_string_at      stubby_ldns_buffer_write_string_at
+#define gldns_buffer_write_string         stubby_ldns_buffer_write_string
+#define gldns_buffer_write_u8_at          stubby_ldns_buffer_write_u8_at
+#define gldns_buffer_write_u8             stubby_ldns_buffer_write_u8
+#define gldns_buffer_write_u16_at         stubby_ldns_buffer_write_u16_at
+#define gldns_buffer_write_u16            stubby_ldns_buffer_write_u16
+#define gldns_buffer_write_u32_at         stubby_ldns_buffer_write_u32_at
+#define gldns_buffer_write_u48_at         stubby_ldns_buffer_write_u48_at
+#define gldns_buffer_write_u32            stubby_ldns_buffer_write_u32
+#define gldns_buffer_write_u48            stubby_ldns_buffer_write_u48
+#define gldns_buffer_read_at              stubby_ldns_buffer_read_at
+#define gldns_buffer_read                 stubby_ldns_buffer_read
+#define gldns_buffer_read_u8_at           stubby_ldns_buffer_read_u8_at
+#define gldns_buffer_read_u8              stubby_ldns_buffer_read_u8
+#define gldns_buffer_read_u16_at          stubby_ldns_buffer_read_u16_at
+#define gldns_buffer_read_u16             stubby_ldns_buffer_read_u16
+#define gldns_buffer_read_u32_at          stubby_ldns_buffer_read_u32_at
+#define gldns_buffer_read_u32             stubby_ldns_buffer_read_u32
+#define gldns_buffer_status               stubby_ldns_buffer_status
+#define gldns_buffer_status_ok            stubby_ldns_buffer_status_ok
+#define gldns_buffer_printf               stubby_ldns_buffer_printf
+#define gldns_buffer_free                 stubby_ldns_buffer_free
+#define gldns_buffer_export               stubby_ldns_buffer_export
+#define gldns_buffer_copy                 stubby_ldns_buffer_copy
+])
+AC_OUTPUT
--- /dev/null
+++ getdns-1.2.0/stubby/src/Makefile.am
@@ -0,0 +1,9 @@
+bin_PROGRAMS = stubby
+
+AUTOMAKE_OPTIONS = subdir-objects
+if WITH_YAML
+stubby_SOURCES = stubby.c yaml/convert_yaml_to_json.c sldns/sbuffer.c
+else
+stubby_SOURCES = stubby.c
+endif
+AM_CPPFLAGS = -DSTUBBYCONFDIR=\"$(sysconfdir)/stubby\" -DRUNSTATEDIR=\"$(runstatedir)\"
--- /dev/null
+++ getdns-1.2.0/stubby/src/sldns/sbuffer.c
@@ -0,0 +1,193 @@
+/*
+ * buffer.c -- generic memory buffer .
+ *
+ * Copyright (c) 2001-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+/**
+ * \file
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+#include "config.h"
+#include "sldns/sbuffer.h"
+#include <stdarg.h>
+
+sldns_buffer *
+sldns_buffer_new(size_t capacity)
+{
+	sldns_buffer *buffer = (sldns_buffer*)malloc(sizeof(sldns_buffer));
+
+	if (!buffer) {
+		return NULL;
+	}
+	
+	buffer->_data = (uint8_t *) malloc(capacity);
+	if (!buffer->_data) {
+		free(buffer);
+		return NULL;
+	}
+	
+	buffer->_position = 0;
+	buffer->_limit = buffer->_capacity = capacity;
+	buffer->_fixed = 0;
+	buffer->_vfixed = 0;
+	buffer->_status_err = 0;
+	
+	sldns_buffer_invariant(buffer);
+	
+	return buffer;
+}
+
+void
+sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+	assert(data != NULL);
+
+	buffer->_position = 0; 
+	buffer->_limit = buffer->_capacity = size;
+	buffer->_fixed = 0;
+	buffer->_vfixed = 0;
+	if (!buffer->_fixed && buffer->_data)
+		free(buffer->_data);
+	buffer->_data = malloc(size);
+	if(!buffer->_data) {
+		buffer->_status_err = 1;
+		return;
+	}
+	memcpy(buffer->_data, data, size);
+	buffer->_status_err = 0;
+	
+	sldns_buffer_invariant(buffer);
+}
+
+void
+sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+	memset(buffer, 0, sizeof(*buffer));
+	buffer->_data = data;
+	buffer->_capacity = buffer->_limit = size;
+	buffer->_fixed = 1;
+	buffer->_vfixed = 0;
+}
+
+void
+sldns_buffer_init_vfixed_frm_data(sldns_buffer *buffer, void *data, size_t size)
+{
+	memset(buffer, 0, sizeof(*buffer));
+	buffer->_data = data;
+	buffer->_capacity = buffer->_limit = size;
+	buffer->_fixed = 1;
+	buffer->_vfixed = 1;
+}
+
+int
+sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity)
+{
+	void *data;
+	
+	sldns_buffer_invariant(buffer);
+	assert(buffer->_position <= capacity && !buffer->_fixed);
+
+	data = (uint8_t *) realloc(buffer->_data, capacity);
+	if (!data) {
+		buffer->_status_err = 1;
+		return 0;
+	} else {
+		buffer->_data = data;
+		buffer->_limit = buffer->_capacity = capacity;
+		return 1;
+	}
+}
+
+int
+sldns_buffer_reserve(sldns_buffer *buffer, size_t amount)
+{
+	sldns_buffer_invariant(buffer);
+	assert(!buffer->_fixed);
+	if (buffer->_capacity < buffer->_position + amount) {
+		size_t new_capacity = buffer->_capacity * 3 / 2;
+
+		if (new_capacity < buffer->_position + amount) {
+			new_capacity = buffer->_position + amount;
+		}
+		if (!sldns_buffer_set_capacity(buffer, new_capacity)) {
+			buffer->_status_err = 1;
+			return 0;
+		}
+	}
+	buffer->_limit = buffer->_capacity;
+	return 1;
+}
+
+int
+sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+{
+	va_list args;
+	int written = 0;
+	size_t remaining;
+	
+	if (sldns_buffer_status_ok(buffer)) {
+		sldns_buffer_invariant(buffer);
+		assert(buffer->_limit == buffer->_capacity);
+
+		remaining = sldns_buffer_remaining(buffer);
+		va_start(args, format);
+		written = vsnprintf((char *) sldns_buffer_current(buffer), remaining,
+				    format, args);
+		va_end(args);
+		if (written == -1) {
+			buffer->_status_err = 1;
+			return -1;
+		} else if (!buffer->_vfixed && (size_t) written >= remaining) {
+			if (!sldns_buffer_reserve(buffer, (size_t) written + 1)) {
+				buffer->_status_err = 1;
+				return -1;
+			}
+			va_start(args, format);
+			written = vsnprintf((char *) sldns_buffer_current(buffer),
+			    sldns_buffer_remaining(buffer), format, args);
+			va_end(args);
+			if (written == -1) {
+				buffer->_status_err = 1;
+				return -1;
+			}
+		}
+		buffer->_position += written;
+	}
+	return written;
+}
+
+void
+sldns_buffer_free(sldns_buffer *buffer)
+{
+	if (!buffer) {
+		return;
+	}
+
+	if (!buffer->_fixed)
+		free(buffer->_data);
+
+	free(buffer);
+}
+
+void *
+sldns_buffer_export(sldns_buffer *buffer)
+{
+	buffer->_fixed = 1;
+	return buffer->_data;
+}
+
+void 
+sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from)
+{
+	size_t tocopy = sldns_buffer_limit(from);
+
+	if(tocopy > sldns_buffer_capacity(result))
+		tocopy = sldns_buffer_capacity(result);
+	sldns_buffer_clear(result);
+	sldns_buffer_write(result, sldns_buffer_begin(from), tocopy);
+	sldns_buffer_flip(result);
+}
--- /dev/null
+++ getdns-1.2.0/stubby/src/sldns/sbuffer.h
@@ -0,0 +1,804 @@
+/*
+ * buffer.h -- generic memory buffer.
+ *
+ * Copyright (c) 2005-2008, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ *
+ * The buffer module implements a generic buffer.  The API is based on
+ * the java.nio.Buffer interface.
+ */
+
+#ifndef LDNS_SBUFFER_H
+#define LDNS_SBUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef S_SPLINT_S
+#  define INLINE 
+#else
+#  ifdef SWIG
+#    define INLINE static
+#  else
+#    define INLINE static inline
+#  endif
+#endif
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE uint16_t
+sldns_read_uint16(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        return ntohs(*(const uint16_t *) src);
+#else
+        const uint8_t *p = (const uint8_t *) src;
+        return ((uint16_t) p[0] << 8) | (uint16_t) p[1];
+#endif
+}
+
+INLINE uint32_t
+sldns_read_uint32(const void *src)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        return ntohl(*(const uint32_t *) src);
+#else
+        const uint8_t *p = (const uint8_t *) src;
+        return (  ((uint32_t) p[0] << 24)
+                | ((uint32_t) p[1] << 16)
+                | ((uint32_t) p[2] << 8)
+                |  (uint32_t) p[3]);
+#endif
+}
+
+/*
+ * Copy data allowing for unaligned accesses in network byte order
+ * (big endian).
+ */
+INLINE void
+sldns_write_uint16(void *dst, uint16_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        * (uint16_t *) dst = htons(data);
+#else
+        uint8_t *p = (uint8_t *) dst;
+        p[0] = (uint8_t) ((data >> 8) & 0xff);
+        p[1] = (uint8_t) (data & 0xff);
+#endif
+}
+
+INLINE void
+sldns_write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+        * (uint32_t *) dst = htonl(data);
+#else
+        uint8_t *p = (uint8_t *) dst;
+        p[0] = (uint8_t) ((data >> 24) & 0xff);
+        p[1] = (uint8_t) ((data >> 16) & 0xff);
+        p[2] = (uint8_t) ((data >> 8) & 0xff);
+        p[3] = (uint8_t) (data & 0xff);
+#endif
+}
+
+
+INLINE void
+sldns_write_uint48(void *dst, uint64_t data)
+{
+        uint8_t *p = (uint8_t *) dst;
+        p[0] = (uint8_t) ((data >> 40) & 0xff);
+        p[1] = (uint8_t) ((data >> 32) & 0xff);
+        p[2] = (uint8_t) ((data >> 24) & 0xff);
+        p[3] = (uint8_t) ((data >> 16) & 0xff);
+        p[4] = (uint8_t) ((data >> 8) & 0xff);
+        p[5] = (uint8_t) (data & 0xff);
+}
+
+
+/**
+ * \file sbuffer.h
+ *
+ * This file contains the definition of sldns_buffer, and functions to manipulate those.
+ */
+
+/** 
+ * implementation of buffers to ease operations
+ *
+ * sldns_buffers can contain arbitrary information, per octet. You can write
+ * to the current end of a buffer, read from the current position, and
+ * access any data within it.
+ */
+struct sldns_buffer
+{
+	/** The current position used for reading/writing */ 
+	size_t   _position;
+
+	/** The read/write limit */
+	size_t   _limit;
+
+	/** The amount of data the buffer can contain */
+	size_t   _capacity;
+
+	/** The data contained in the buffer */
+	uint8_t *_data;
+
+	/** If the buffer is fixed it cannot be resized */
+	unsigned _fixed : 1;
+
+	/** If the buffer is vfixed, no more than capacity bytes willl be
+	 * written to _data, however the _position counter will be updated
+	 * with the amount that would have been written in consecutive
+	 * writes.  This allows for a modus operandi in which a sequence is
+	 * written on a fixed capacity buffer (perhaps with _data on stack).
+	 * When everything could be written, then the _data is immediately
+	 * usable, if not, then a buffer could be allocated sized precisely
+	 * to fit the data for a second attempt.
+	 */
+	unsigned _vfixed : 1;
+
+	/** The current state of the buffer. If writing to the buffer fails
+	 * for any reason, this value is changed. This way, you can perform
+	 * multiple writes in sequence and check for success afterwards. */
+	unsigned _status_err : 1;
+};
+typedef struct sldns_buffer sldns_buffer;
+
+#ifdef NDEBUG
+INLINE void
+sldns_buffer_invariant(sldns_buffer *ATTR_UNUSED(buffer))
+{
+}
+#else
+INLINE void
+sldns_buffer_invariant(sldns_buffer *buffer)
+{
+	assert(buffer != NULL);
+	assert(buffer->_position <= buffer->_limit || buffer->_vfixed);
+	assert(buffer->_limit <= buffer->_capacity);
+	assert(buffer->_data != NULL || (buffer->_vfixed && buffer->_capacity == 0));
+}
+#endif
+
+/**
+ * creates a new buffer with the specified capacity.
+ *
+ * \param[in] capacity the size (in bytes) to allocate for the buffer
+ * \return the created buffer
+ */
+sldns_buffer *sldns_buffer_new(size_t capacity);
+
+/**
+ * creates a buffer with the specified data.  The data IS copied
+ * and MEMORY allocations are done.  The buffer is not fixed and can
+ * be resized using buffer_reserve().
+ *
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_new_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * Setup a buffer with the data pointed to. No data copied, no memory allocs.
+ * The buffer is fixed.
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_init_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * Setup a buffer with the data pointed to. No data copied, no memory allocs.
+ * The buffer is "virtually" fixed.  Writes beyond size (the capacity) will
+ * only update position, but no data will be written beyond capacity.  This
+ * allows to determine how big the buffer should have been to contain all the
+ * written data, by looking at the position with sldns_buffer_position(),
+ * similarly to the return value of POSIX's snprintf.
+ * \param[in] buffer pointer to the buffer to put the data in
+ * \param[in] data the data to encapsulate in the buffer
+ * \param[in] size the size of the data
+ */
+void sldns_buffer_init_vfixed_frm_data(sldns_buffer *buffer, void *data, size_t size);
+
+/**
+ * clears the buffer and make it ready for writing.  The buffer's limit
+ * is set to the capacity and the position is set to 0.
+ * \param[in] buffer the buffer to clear
+ */
+INLINE void sldns_buffer_clear(sldns_buffer *buffer)
+{
+	sldns_buffer_invariant(buffer);
+
+	/* reset status here? */
+
+	buffer->_position = 0;
+	buffer->_limit = buffer->_capacity;
+}
+
+/**
+ * makes the buffer ready for reading the data that has been written to
+ * the buffer.  The buffer's limit is set to the current position and
+ * the position is set to 0.
+ *
+ * \param[in] buffer the buffer to flip
+ * \return void
+ */
+INLINE void sldns_buffer_flip(sldns_buffer *buffer)
+{
+	sldns_buffer_invariant(buffer);
+
+	buffer->_limit = buffer->_position;
+	buffer->_position = 0;
+}
+
+/**
+ * make the buffer ready for re-reading the data.  The buffer's
+ * position is reset to 0.
+ * \param[in] buffer the buffer to rewind
+ */
+INLINE void sldns_buffer_rewind(sldns_buffer *buffer)
+{
+	sldns_buffer_invariant(buffer);
+
+	buffer->_position = 0;
+}
+
+/**
+ * returns the current position in the buffer (as a number of bytes)
+ * \param[in] buffer the buffer
+ * \return the current position
+ */
+INLINE size_t
+sldns_buffer_position(sldns_buffer *buffer)
+{
+	return buffer->_position;
+}
+
+/**
+ * sets the buffer's position to MARK.  The position must be less than
+ * or equal to the buffer's limit.
+ * \param[in] buffer the buffer
+ * \param[in] mark the mark to use
+ */
+INLINE void
+sldns_buffer_set_position(sldns_buffer *buffer, size_t mark)
+{
+	assert(mark <= buffer->_limit || buffer->_vfixed);
+	buffer->_position = mark;
+}
+
+/**
+ * changes the buffer's position by COUNT bytes.  The position must not
+ * be moved behind the buffer's limit or before the beginning of the
+ * buffer.
+ * \param[in] buffer the buffer
+ * \param[in] count the count to use
+ */
+INLINE void
+sldns_buffer_skip(sldns_buffer *buffer, ssize_t count)
+{
+	assert(buffer->_position + count <= buffer->_limit || buffer->_vfixed);
+	buffer->_position += count;
+}
+
+/**
+ * returns the maximum size of the buffer
+ * \param[in] buffer
+ * \return the size
+ */
+INLINE size_t
+sldns_buffer_limit(sldns_buffer *buffer)
+{
+	return buffer->_limit;
+}
+
+/**
+ * changes the buffer's limit.  If the buffer's position is greater
+ * than the new limit the position is set to the limit.
+ * \param[in] buffer the buffer
+ * \param[in] limit the new limit
+ */
+INLINE void
+sldns_buffer_set_limit(sldns_buffer *buffer, size_t limit)
+{
+	assert(limit <= buffer->_capacity);
+	buffer->_limit = limit;
+	if (buffer->_position > buffer->_limit)
+		buffer->_position = buffer->_limit;
+}
+
+/**
+ * returns the number of bytes the buffer can hold.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_capacity(sldns_buffer *buffer)
+{
+	return buffer->_capacity;
+}
+
+/**
+ * changes the buffer's capacity.  The data is reallocated so any
+ * pointers to the data may become invalid.  The buffer's limit is set
+ * to the buffer's new capacity.
+ * \param[in] buffer the buffer
+ * \param[in] capacity the capacity to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_set_capacity(sldns_buffer *buffer, size_t capacity);
+
+/**
+ * ensures BUFFER can contain at least AMOUNT more bytes.  The buffer's
+ * capacity is increased if necessary using buffer_set_capacity().
+ *
+ * The buffer's limit is always set to the (possibly increased)
+ * capacity.
+ * \param[in] buffer the buffer
+ * \param[in] amount amount to use
+ * \return whether this failed or succeeded
+ */
+int sldns_buffer_reserve(sldns_buffer *buffer, size_t amount);
+
+/**
+ * returns a pointer to the data at the indicated position.
+ * \param[in] buffer the buffer
+ * \param[in] at position
+ * \return the pointer to the data
+ */
+INLINE uint8_t *
+sldns_buffer_at(const sldns_buffer *buffer, size_t at)
+{
+	assert(at <= buffer->_limit || buffer->_vfixed);
+	return buffer->_data + at;
+}
+
+/**
+ * returns a pointer to the beginning of the buffer (the data at
+ * position 0).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_begin(const sldns_buffer *buffer)
+{
+	return sldns_buffer_at(buffer, 0);
+}
+
+/**
+ * returns a pointer to the end of the buffer (the data at the buffer's
+ * limit).
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_end(sldns_buffer *buffer)
+{
+	return sldns_buffer_at(buffer, buffer->_limit);
+}
+
+/**
+ * returns a pointer to the data at the buffer's current position.
+ * \param[in] buffer the buffer
+ * \return the pointer
+ */
+INLINE uint8_t *
+sldns_buffer_current(sldns_buffer *buffer)
+{
+	return sldns_buffer_at(buffer, buffer->_position);
+}
+
+/**
+ * returns the number of bytes remaining between the indicated position and
+ * the limit.
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \return number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining_at(sldns_buffer *buffer, size_t at)
+{
+	sldns_buffer_invariant(buffer);
+	assert(at <= buffer->_limit || buffer->_vfixed);
+	return at < buffer->_limit ? buffer->_limit - at : 0;
+}
+
+/**
+ * returns the number of bytes remaining between the buffer's position and
+ * limit.
+ * \param[in] buffer the buffer
+ * \return the number of bytes
+ */
+INLINE size_t
+sldns_buffer_remaining(sldns_buffer *buffer)
+{
+	return sldns_buffer_remaining_at(buffer, buffer->_position);
+}
+
+/**
+ * checks if the buffer has at least COUNT more bytes available.
+ * Before reading or writing the caller needs to ensure enough space
+ * is available!
+ * \param[in] buffer the buffer
+ * \param[in] at indicated position
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available_at(sldns_buffer *buffer, size_t at, size_t count)
+{
+	return count <= sldns_buffer_remaining_at(buffer, at);
+}
+
+/**
+ * checks if the buffer has count bytes available at the current position
+ * \param[in] buffer the buffer
+ * \param[in] count how much is available
+ * \return true or false (as int?)
+ */
+INLINE int
+sldns_buffer_available(sldns_buffer *buffer, size_t count)
+{
+	return sldns_buffer_available_at(buffer, buffer->_position, count);
+}
+
+/**
+ * writes the given data to the buffer at the specified position
+ * \param[in] buffer the buffer
+ * \param[in] at the position (in number of bytes) to write the data at
+ * \param[in] data pointer to the data to write to the buffer
+ * \param[in] count the number of bytes of data to write
+ */
+INLINE void
+sldns_buffer_write_at(sldns_buffer *buffer, size_t at, const void *data, size_t count)
+{
+	if (!buffer->_vfixed)
+		assert(sldns_buffer_available_at(buffer, at, count));
+	else if (sldns_buffer_remaining_at(buffer, at) == 0)
+		return;
+	else if (count > sldns_buffer_remaining_at(buffer, at)) {
+		memcpy(buffer->_data + at, data,
+		    sldns_buffer_remaining_at(buffer, at));
+		return;
+	}
+	memcpy(buffer->_data + at, data, count);
+}
+
+/**
+ * set the given byte to the buffer at the specified position
+ * \param[in] buffer the buffer
+ * \param[in] at the position (in number of bytes) to write the data at
+ * \param[in] c the byte to set to the buffer
+ * \param[in] count the number of bytes of bytes to write
+ */
+
+INLINE void
+sldns_buffer_set_at(sldns_buffer *buffer, size_t at, int c, size_t count)
+{
+    if (!buffer->_vfixed)
+        assert(sldns_buffer_available_at(buffer, at, count));
+    else if (sldns_buffer_remaining_at(buffer, at) == 0)
+        return;
+    else if (count > sldns_buffer_remaining_at(buffer, at)) {
+        memset(buffer->_data + at, c,
+            sldns_buffer_remaining_at(buffer, at));
+        return;
+    }
+	memset(buffer->_data + at, c, count);
+}
+
+
+/**
+ * writes count bytes of data to the current position of the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the data to write
+ * \param[in] count the lenght of the data to write
+ */
+INLINE void
+sldns_buffer_write(sldns_buffer *buffer, const void *data, size_t count)
+{
+	sldns_buffer_write_at(buffer, buffer->_position, data, count);
+	buffer->_position += count;
+}
+
+/**
+ * copies the given (null-delimited) string to the specified position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string_at(sldns_buffer *buffer, size_t at, const char *str)
+{
+	sldns_buffer_write_at(buffer, at, str, strlen(str));
+}
+
+/**
+ * copies the given (null-delimited) string to the current position at the buffer
+ * \param[in] buffer the buffer
+ * \param[in] str the string to write
+ */
+INLINE void
+sldns_buffer_write_string(sldns_buffer *buffer, const char *str)
+{
+	sldns_buffer_write(buffer, str, strlen(str));
+}
+
+/**
+ * writes the given byte of data at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8_at(sldns_buffer *buffer, size_t at, uint8_t data)
+{
+	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
+	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+	buffer->_data[at] = data;
+}
+
+/**
+ * writes the given byte of data at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 8 bits to write
+ */
+INLINE void
+sldns_buffer_write_u8(sldns_buffer *buffer, uint8_t data)
+{
+	sldns_buffer_write_u8_at(buffer, buffer->_position, data);
+	buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 2 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16_at(sldns_buffer *buffer, size_t at, uint16_t data)
+{
+	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
+	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+	sldns_write_uint16(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 2 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 16 bits to write
+ */
+INLINE void
+sldns_buffer_write_u16(sldns_buffer *buffer, uint16_t data)
+{
+	sldns_buffer_write_u16_at(buffer, buffer->_position, data);
+	buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 4 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32_at(sldns_buffer *buffer, size_t at, uint32_t data)
+{
+	if (buffer->_vfixed && at + sizeof(data) > buffer->_limit) return;
+	assert(sldns_buffer_available_at(buffer, at, sizeof(data)));
+	sldns_write_uint32(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 6 byte integer at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \param[in] data the (lower) 48 bits to write
+ */
+INLINE void
+sldns_buffer_write_u48_at(sldns_buffer *buffer, size_t at, uint64_t data)
+{
+	if (buffer->_vfixed && at + 6 > buffer->_limit) return;
+	assert(sldns_buffer_available_at(buffer, at, 6));
+	sldns_write_uint48(buffer->_data + at, data);
+}
+
+/**
+ * writes the given 4 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 32 bits to write
+ */
+INLINE void
+sldns_buffer_write_u32(sldns_buffer *buffer, uint32_t data)
+{
+	sldns_buffer_write_u32_at(buffer, buffer->_position, data);
+	buffer->_position += sizeof(data);
+}
+
+/**
+ * writes the given 6 byte integer at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] data the 48 bits to write
+ */
+INLINE void
+sldns_buffer_write_u48(sldns_buffer *buffer, uint64_t data)
+{
+	sldns_buffer_write_u48_at(buffer, buffer->_position, data);
+	buffer->_position += 6;
+}
+
+/**
+ * copies count bytes of data at the given position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer to start
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read_at(sldns_buffer *buffer, size_t at, void *data, size_t count)
+{
+	assert(sldns_buffer_available_at(buffer, at, count));
+	memcpy(data, buffer->_data + at, count);
+}
+
+/**
+ * copies count bytes of data at the current position to the given data-array
+ * \param[in] buffer the buffer
+ * \param[out] data buffer to copy to
+ * \param[in] count the length of the data to copy
+ */
+INLINE void
+sldns_buffer_read(sldns_buffer *buffer, void *data, size_t count)
+{
+	sldns_buffer_read_at(buffer, buffer->_position, data, count);
+	buffer->_position += count;
+}
+
+/**
+ * returns the byte value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at the position in the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8_at(sldns_buffer *buffer, size_t at)
+{
+	assert(sldns_buffer_available_at(buffer, at, sizeof(uint8_t)));
+	return buffer->_data[at];
+}
+
+/**
+ * returns the byte value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 1 byte integer
+ */
+INLINE uint8_t
+sldns_buffer_read_u8(sldns_buffer *buffer)
+{
+	uint8_t result = sldns_buffer_read_u8_at(buffer, buffer->_position);
+	buffer->_position += sizeof(uint8_t);
+	return result;
+}
+
+/**
+ * returns the 2-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16_at(sldns_buffer *buffer, size_t at)
+{
+	assert(sldns_buffer_available_at(buffer, at, sizeof(uint16_t)));
+	return sldns_read_uint16(buffer->_data + at);
+}
+
+/**
+ * returns the 2-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 2 byte integer
+ */
+INLINE uint16_t
+sldns_buffer_read_u16(sldns_buffer *buffer)
+{
+	uint16_t result = sldns_buffer_read_u16_at(buffer, buffer->_position);
+	buffer->_position += sizeof(uint16_t);
+	return result;
+}
+
+/**
+ * returns the 4-byte integer value at the given position in the buffer
+ * \param[in] buffer the buffer
+ * \param[in] at position in the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32_at(sldns_buffer *buffer, size_t at)
+{
+	assert(sldns_buffer_available_at(buffer, at, sizeof(uint32_t)));
+	return sldns_read_uint32(buffer->_data + at);
+}
+
+/**
+ * returns the 4-byte integer value at the current position in the buffer
+ * \param[in] buffer the buffer
+ * \return 4 byte integer
+ */
+INLINE uint32_t
+sldns_buffer_read_u32(sldns_buffer *buffer)
+{
+	uint32_t result = sldns_buffer_read_u32_at(buffer, buffer->_position);
+	buffer->_position += sizeof(uint32_t);
+	return result;
+}
+
+/**
+ * returns the status of the buffer
+ * \param[in] buffer
+ * \return the status
+ */
+INLINE int
+sldns_buffer_status(sldns_buffer *buffer)
+{
+	return (int)buffer->_status_err;
+}
+
+/**
+ * returns true if the status of the buffer is LDNS_STATUS_OK, false otherwise
+ * \param[in] buffer the buffer
+ * \return true or false
+ */
+INLINE int
+sldns_buffer_status_ok(sldns_buffer *buffer)
+{
+	if (buffer) {
+		return sldns_buffer_status(buffer) == 0;
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * prints to the buffer, increasing the capacity if required using
+ * buffer_reserve(). The buffer's position is set to the terminating '\\0'
+ * Returns the number of characters written (not including the
+ * terminating '\\0') or -1 on failure.
+ */
+int sldns_buffer_printf(sldns_buffer *buffer, const char *format, ...)
+	ATTR_FORMAT(printf, 2, 3);
+
+/**
+ * frees the buffer.
+ * \param[in] *buffer the buffer to be freed
+ * \return void
+ */
+void sldns_buffer_free(sldns_buffer *buffer);
+
+/**
+ * Makes the buffer fixed and returns a pointer to the data.  The
+ * caller is responsible for free'ing the result.
+ * \param[in] *buffer the buffer to be exported
+ * \return void
+ */
+void *sldns_buffer_export(sldns_buffer *buffer);
+
+/**
+ * Copy contents of the from buffer to the result buffer and then flips 
+ * the result buffer. Data will be silently truncated if the result buffer is
+ * too small.
+ * \param[out] *result resulting buffer which is copied to.
+ * \param[in] *from what to copy to result.
+ */
+void sldns_buffer_copy(sldns_buffer* result, sldns_buffer* from);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDNS_SBUFFER_H */
--- /dev/null
+++ getdns-1.2.0/stubby/src/stubby.c
@@ -0,0 +1,838 @@
+/*
+ * 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 "config.h"
+#include <getdns/getdns.h>
+#include <getdns/getdns_extra.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#if !defined(STUBBY_ON_WINDOWS) && !defined(GETDNS_ON_WINDOWS)
+#include <unistd.h>
+#endif
+#include <signal.h>
+#include <limits.h>
+
+#ifdef HAVE_GETDNS_YAML2DICT
+getdns_return_t getdns_yaml2dict(const char *str, getdns_dict **dict);
+#else
+# include "yaml/convert_yaml_to_json.h"
+# define getdns_yaml2dict stubby_yaml2dict
+getdns_return_t
+getdns_yaml2dict(const char *str, getdns_dict **dict)
+{
+	char *jsonstr;
+	
+	if (!str || !dict)
+		return GETDNS_RETURN_INVALID_PARAMETER;
+
+	jsonstr = yaml_string_to_json_string(str);
+	if (jsonstr) {
+		getdns_return_t res = getdns_str2dict(jsonstr, dict);
+		free(jsonstr);
+		return res;
+	} else {
+		return GETDNS_RETURN_GENERIC_ERROR;
+	}       
+}
+#endif
+
+#define STUBBYPIDFILE RUNSTATEDIR"/stubby.pid"
+
+#if defined(STUBBY_ON_WINDOWS) || defined(GETDNS_ON_WINDOWS)
+#define DEBUG_ON(...) do { \
+	                struct timeval tv_dEbUgSyM; \
+	                struct tm tm_dEbUgSyM; \
+	                char buf_dEbUgSyM[10]; \
+	                time_t tsec_dEbUgSyM; \
+	                \
+	                gettimeofday(&tv_dEbUgSyM, NULL); \
+	                tsec_dEbUgSyM = (time_t) tv_dEbUgSyM.tv_sec; \
+	                gmtime_s(&tm_dEbUgSyM, (const time_t *) &tsec_dEbUgSyM); \
+	                strftime(buf_dEbUgSyM, 10, "%H:%M:%S", &tm_dEbUgSyM); \
+	                fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
+	                fprintf(stderr, __VA_ARGS__); \
+	        } while (0)
+#else
+#define DEBUG_ON(...) do { \
+	                struct timeval tv_dEbUgSyM; \
+	                struct tm tm_dEbUgSyM; \
+	                char buf_dEbUgSyM[10]; \
+	                \
+	                gettimeofday(&tv_dEbUgSyM, NULL); \
+	                gmtime_r(&tv_dEbUgSyM.tv_sec, &tm_dEbUgSyM); \
+	                strftime(buf_dEbUgSyM, 10, "%H:%M:%S", &tm_dEbUgSyM); \
+	                fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
+	                fprintf(stderr, __VA_ARGS__); \
+	        } while (0)
+#endif
+#define DEBUG_OFF(...) do {} while (0)
+
+#if defined(SERVER_DEBUG) && SERVER_DEBUG
+#include <time.h>
+#define DEBUG_SERVER(...) DEBUG_ON(__VA_ARGS__)
+#else
+#define DEBUG_SERVER(...) DEBUG_OFF(__VA_ARGS__)
+#endif
+
+static const char *default_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"
+", round_robin_upstreams: 1"
+"}";
+
+static getdns_context  *context = NULL;
+static getdns_dict *listen_dict = NULL;
+static getdns_list *listen_list = NULL;
+static size_t listen_count = 0;
+static int run_in_foreground = 1;
+
+static void stubby_local_log(void *userarg, uint64_t system,
+	getdns_loglevel_type level, const char *fmt, ...);
+
+
+void
+print_usage(FILE *out, const char *progname)
+{
+	fprintf(out, "usage: %s [<option> ...] \\\n", progname);
+	fprintf(out, "\t-C\t<filename>\n");
+	fprintf(out, "\t\tRead settings from config file <filename>\n");
+	fprintf(out, "\t\tThe getdns context will be configured with these settings\n");
+	fprintf(out, "\t\tThe file should be in YAML format with an extension of .yml.\n");
+	fprintf(out, "\t\t(The old JSON dict format (.conf) is also still supported when\n");
+	fprintf(out, "\t\tspecified on the command line.)\n");
+	fprintf(out, "\t\tBy default, the configuration file location is obtained\n");
+	fprintf(out, "\t\tby looking for YAML files in the following order:\n");
+	fprintf(out, "\t\t\t\"%s/.stubby.yml\"\n", getenv("HOME"));
+	fprintf(out, "\t\t\t\"%s/stubby.yml\"\n", STUBBYCONFDIR);
+	fprintf(out, "\t\tAn default file (Using Strict mode) is installed as\n");
+	fprintf(out, "\t\t\t\"%s/stubby.yml\"\n", STUBBYCONFDIR);
+#if !defined(STUBBY_ON_WINDOWS) && !defined(GETDNS_ON_WINDOWS)
+	fprintf(out, "\t-g\tRun stubby in background (default is foreground)\n");
+#endif
+	fprintf(out, "\t-h\tPrint this help\n");
+	fprintf(out, "\t-i\tValidate and print the configuration only. Useful to validate config file contents.\n");
+	fprintf(out, "\t-l\tEnable logging of all logs (same as -v 7)\n");
+	fprintf(out, "\t-v\tSpecify logging level (overrides -l option). Values are\n");
+	fprintf(out, "\t\t\t0: EMERG  - %s\n", GETDNS_LOG_EMERG_TEXT);
+	fprintf(out, "\t\t\t1: ALERT  - %s\n", GETDNS_LOG_ALERT_TEXT);
+	fprintf(out, "\t\t\t2: CRIT   - %s\n", GETDNS_LOG_CRIT_TEXT);
+	fprintf(out, "\t\t\t3: ERROR  - %s\n", GETDNS_LOG_ERR_TEXT);
+	fprintf(out, "\t\t\t4: WARN   - %s\n", GETDNS_LOG_WARNING_TEXT);
+	fprintf(out, "\t\t\t5: NOTICE - %s\n", GETDNS_LOG_NOTICE_TEXT);
+	fprintf(out, "\t\t\t6: INFO   - %s\n", GETDNS_LOG_INFO_TEXT);
+	fprintf(out, "\t\t\t7: DEBUG  - %s\n", GETDNS_LOG_DEBUG_TEXT);
+}
+
+#define GETDNS_RETURN_IO_ERROR ((getdns_return_t) 3000)
+
+static const char *_getdns_strerror(getdns_return_t r)
+{
+	return r == GETDNS_RETURN_IO_ERROR ? strerror(errno)
+	                                   : getdns_get_errorstr_by_id(r);
+}
+
+static getdns_return_t parse_config(const char *config_str, int yaml_config)
+{
+	getdns_dict *config_dict;
+	getdns_list *list;
+	getdns_return_t r;
+
+	if (yaml_config) {
+		r = getdns_yaml2dict(config_str, &config_dict);
+		if (r == GETDNS_RETURN_NOT_IMPLEMENTED) {
+			/* If this fails then YAML is really not supported. Check this at 
+			   runtime because it could change under us..... */
+			r = getdns_yaml2dict(config_str, NULL);
+			if (r == GETDNS_RETURN_NOT_IMPLEMENTED) {
+				fprintf(stderr, "Support for YAML configuration files not available because\n");
+				fprintf(stderr, "the version of getdns used was not compiled with YAML support.\n");
+				return GETDNS_RETURN_NOT_IMPLEMENTED;
+			}
+		}
+	} else {
+		r = getdns_str2dict(config_str, &config_dict);
+	}
+	if (r) {
+		fprintf(stderr, "Could not parse config file %s, \"%s\"\n",
+		    config_str, _getdns_strerror(r));
+		return r;
+	}
+	if (!(r = getdns_dict_get_list(
+	    config_dict, "listen_addresses", &list))) {
+		if (listen_list && !listen_dict) {
+			getdns_list_destroy(listen_list);
+			listen_list = NULL;
+		}
+		/* Strange construction to copy the list.
+		 * Needs to be done, because config dict
+		 * will get destroyed.
+		 */
+		if (!listen_dict &&
+		    !(listen_dict = getdns_dict_create())) {
+			fprintf(stderr, "Could not create "
+					"listen_dict");
+			r = GETDNS_RETURN_MEMORY_ERROR;
+
+		} else if ((r = getdns_dict_set_list(
+		    listen_dict, "listen_list", list)))
+			fprintf(stderr, "Could not set listen_list");
+
+		else if ((r = getdns_dict_get_list(
+		    listen_dict, "listen_list", &listen_list)))
+			fprintf(stderr, "Could not get listen_list");
+
+		else if ((r = getdns_list_get_length(
+		    listen_list, &listen_count)))
+			fprintf(stderr, "Could not get listen_count");
+
+		(void) getdns_dict_remove_name(
+		    config_dict, "listen_addresses");
+	}
+	if (!r && (r = getdns_context_config(context, config_dict))) {
+		fprintf(stderr, "Could not configure context with "
+		    "config dict: %s\n", _getdns_strerror(r));
+	}
+	getdns_dict_destroy(config_dict);
+	return r;
+}
+
+static getdns_return_t parse_config_file(const char *fn)
+{
+	FILE *fh;
+	char *config_file = NULL;
+	long config_file_sz;
+	size_t read_sz;
+	getdns_return_t r;
+
+	if (!(fh = fopen(fn, "r")))
+		return GETDNS_RETURN_IO_ERROR;
+
+	if (fseek(fh, 0,SEEK_END) == -1) {
+		perror("fseek");
+		fclose(fh);
+		return GETDNS_RETURN_IO_ERROR;
+	}
+	config_file_sz = ftell(fh);
+	if (config_file_sz <= 0) {
+		/* Empty config is no config */
+		fclose(fh);
+		return GETDNS_RETURN_IO_ERROR;
+	}
+	if (!(config_file = malloc(config_file_sz + 1))){
+		fclose(fh);
+		fprintf(stderr, "Could not allocate memory for \"%s\"\n", fn);
+		return GETDNS_RETURN_MEMORY_ERROR;
+	}
+	rewind(fh);
+	read_sz = fread(config_file, 1, config_file_sz + 1, fh);
+	if (read_sz > (size_t)config_file_sz || ferror(fh) || !feof(fh)) {
+		fprintf( stderr, "An error occurred while reading \"%s\": %s\n"
+		       , fn, strerror(errno));
+		fclose(fh);
+		free(config_file);
+		return GETDNS_RETURN_IO_ERROR;
+	}
+	config_file[read_sz] = 0;
+	fclose(fh);
+	r = parse_config(config_file, strstr(fn, ".yml") != NULL);
+	free(config_file);
+	if (r == GETDNS_RETURN_GOOD)
+		stubby_local_log(NULL,GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
+			       "Read config from file %s\n", fn);
+	return r;
+}
+
+typedef struct dns_msg {
+	getdns_transaction_t  request_id;
+	getdns_dict          *request;
+	uint32_t              rt;
+	uint32_t              ad_bit;
+	uint32_t              do_bit;
+	uint32_t              cd_bit;
+	int                   has_edns0;
+} dns_msg;
+
+#if defined(SERVER_DEBUG) && SERVER_DEBUG
+#define SERVFAIL(error,r,msg,resp_p) do { \
+	if (r)	DEBUG_SERVER("%s: %s\n", error, _getdns_strerror(r)); \
+	else	DEBUG_SERVER("%s\n", error); \
+	servfail(msg, resp_p); \
+	} while (0)
+#else
+#define SERVFAIL(error,r,msg,resp_p) servfail(msg, resp_p)
+#endif
+
+void servfail(dns_msg *msg, getdns_dict **resp_p)
+{
+	getdns_dict *dict;
+
+	if (*resp_p)
+		getdns_dict_destroy(*resp_p);
+	if (!(*resp_p = getdns_dict_create()))
+		return;
+	if (msg) {
+		if (!getdns_dict_get_dict(msg->request, "header", &dict))
+			getdns_dict_set_dict(*resp_p, "header", dict);
+		if (!getdns_dict_get_dict(msg->request, "question", &dict))
+			getdns_dict_set_dict(*resp_p, "question", dict);
+		(void) getdns_dict_set_int(*resp_p, "/header/ra",
+		    msg->rt == GETDNS_RESOLUTION_RECURSING ? 1 : 0);
+	}
+	(void) getdns_dict_set_int(
+	    *resp_p, "/header/rcode", GETDNS_RCODE_SERVFAIL);
+	(void) getdns_dict_set_int(*resp_p, "/header/qr", 1);
+	(void) getdns_dict_set_int(*resp_p, "/header/ad", 0);
+}
+
+static getdns_return_t _handle_edns0(
+    getdns_dict *response, int has_edns0)
+{
+	getdns_return_t r;
+	getdns_list *additional;
+	size_t len, i;
+	getdns_dict *rr;
+	uint32_t rr_type;
+	char remove_str[100] = "/replies_tree/0/additional/";
+
+	if ((r = getdns_dict_set_int(
+	    response, "/replies_tree/0/header/do", 0)))
+		return r;
+	if ((r = getdns_dict_get_list(response, "/replies_tree/0/additional",
+	    &additional)))
+		return r;
+	if ((r = getdns_list_get_length(additional, &len)))
+		return r;
+	for (i = 0; i < len; i++) {
+		if ((r = getdns_list_get_dict(additional, i, &rr)))
+			return r;
+		if ((r = getdns_dict_get_int(rr, "type", &rr_type)))
+			return r;
+		if (rr_type != GETDNS_RRTYPE_OPT)
+			continue;
+		if (has_edns0) {
+			(void) getdns_dict_set_int(rr, "do", 0);
+			break;
+		}
+		(void) snprintf(remove_str + 27, 60, "%d", (int)i);
+		if ((r = getdns_dict_remove_name(response, remove_str)))
+			return r;
+		break;
+	}
+	return GETDNS_RETURN_GOOD;
+}
+
+static void request_cb(
+    getdns_context *context, getdns_callback_type_t callback_type,
+    getdns_dict *response, void *userarg, getdns_transaction_t transaction_id)
+{
+	dns_msg *msg = (dns_msg *)userarg;
+	uint32_t qid;
+	getdns_return_t r = GETDNS_RETURN_GOOD;
+	uint32_t n, rcode, dnssec_status;
+
+#if defined(SERVER_DEBUG) && SERVER_DEBUG
+	getdns_bindata *qname;
+	char *qname_str, *unknown_qname = "<unknown_qname>";
+
+	if (getdns_dict_get_bindata(msg->request, "/question/qname", &qname)
+	||  getdns_convert_dns_name_to_fqdn(qname, &qname_str))
+		qname_str = unknown_qname;
+
+	DEBUG_SERVER("reply for: %p %"PRIu64" %d (edns0: %d, do: %d, ad: %d,"
+	    " cd: %d, qname: %s)\n", (void *)msg, transaction_id, (int)callback_type,
+	    msg->has_edns0, msg->do_bit, msg->ad_bit, msg->cd_bit, qname_str);
+
+	if (qname_str != unknown_qname)
+		free(qname_str);
+#else
+	(void)transaction_id;
+#endif
+	assert(msg);
+
+	if (callback_type != GETDNS_CALLBACK_COMPLETE)
+		SERVFAIL("Callback type not complete",
+		    callback_type, msg, &response);
+
+	else if (!response)
+		SERVFAIL("Missing response", 0, msg, &response);
+
+	else if ((r = getdns_dict_get_int(msg->request, "/header/id", &qid)) ||
+	    (r=getdns_dict_set_int(response,"/replies_tree/0/header/id",qid)))
+		SERVFAIL("Could not copy QID", r, msg, &response);
+
+	else if (getdns_dict_get_int(
+	    response, "/replies_tree/0/header/rcode", &rcode))
+		SERVFAIL("No reply in replies tree", 0, msg, &response);
+
+	/* ansers when CD or not BOGUS */
+	else if (!msg->cd_bit && !getdns_dict_get_int(
+	    response, "/replies_tree/0/dnssec_status", &dnssec_status)
+	    && dnssec_status == GETDNS_DNSSEC_BOGUS)
+		SERVFAIL("DNSSEC status was bogus", 0, msg, &response);
+
+	else if (rcode == GETDNS_RCODE_SERVFAIL)
+		servfail(msg, &response);
+
+	/* RRsigs when DO and (CD or not BOGUS) 
+	 * Implemented in conversion to wireformat function by checking for DO
+	 * bit.  In recursing resolution mode we have to copy the do bit from
+	 * the request, because libunbound has it in the answer always.
+	 */
+	else if (msg->rt == GETDNS_RESOLUTION_RECURSING && !msg->do_bit &&
+	    (r = _handle_edns0(response, msg->has_edns0)))
+		SERVFAIL("Could not handle EDNS0", r, msg, &response);
+
+	/* AD when (DO or AD) and SECURE */
+	else if ((r = getdns_dict_set_int(response,"/replies_tree/0/header/ad",
+	    ((msg->do_bit || msg->ad_bit)
+	    && (  (!msg->cd_bit && dnssec_status == GETDNS_DNSSEC_SECURE)
+	       || ( msg->cd_bit && !getdns_dict_get_int(response,
+	            "/replies_tree/0/dnssec_status", &dnssec_status)
+	          && dnssec_status == GETDNS_DNSSEC_SECURE ))) ? 1 : 0)))
+		SERVFAIL("Could not set AD bit", r, msg, &response);
+
+	else if (msg->rt == GETDNS_RESOLUTION_STUB)
+		; /* following checks are for RESOLUTION_RECURSING only */
+	
+	else if ((r =  getdns_dict_set_int(
+	    response, "/replies_tree/0/header/cd", msg->cd_bit)))
+		SERVFAIL("Could not copy CD bit", r, msg, &response);
+
+	else if ((r = getdns_dict_get_int(
+	    response, "/replies_tree/0/header/ra", &n)))
+		SERVFAIL("Could not get RA bit from reply", r, msg, &response);
+
+	else if (n == 0)
+		SERVFAIL("Recursion not available", 0, msg, &response);
+
+	if ((r = getdns_reply(context, response, msg->request_id))) {
+		fprintf(stderr, "Could not reply: %s\n", _getdns_strerror(r));
+		/* Cancel reply */
+		(void) getdns_reply(context, NULL, msg->request_id);
+	}
+	if (msg) {
+		getdns_dict_destroy(msg->request);
+		free(msg);
+	}
+	if (response)
+		getdns_dict_destroy(response);
+}	
+
+static void incoming_request_handler(getdns_context *context,
+    getdns_callback_type_t callback_type, getdns_dict *request,
+    void *userarg, getdns_transaction_t request_id)
+{
+	getdns_bindata *qname;
+	char *qname_str = NULL;
+	uint32_t qtype;
+	uint32_t qclass;
+	getdns_return_t r;
+	getdns_dict *header;
+	uint32_t n;
+	getdns_list *list;
+	getdns_transaction_t transaction_id = 0;
+	getdns_dict *qext = NULL;
+	dns_msg *msg = NULL;
+	getdns_dict *response = NULL;
+	size_t i, len;
+	getdns_list *additional;
+	getdns_dict *rr;
+	uint32_t rr_type;
+
+	(void)callback_type;
+	(void)userarg;
+
+	if (!(qext = getdns_dict_create_with_context(context)) ||
+	    !(msg = malloc(sizeof(dns_msg))))
+		goto error;
+
+	/* pass through the header and the OPT record */
+	n = 0;
+	msg->request_id = request_id;
+	msg->request = request;
+	msg->ad_bit = msg->do_bit = msg->cd_bit = 0;
+	msg->has_edns0 = 0;
+	msg->rt = GETDNS_RESOLUTION_RECURSING;
+	(void) getdns_dict_get_int(request, "/header/ad", &msg->ad_bit);
+	(void) getdns_dict_get_int(request, "/header/cd", &msg->cd_bit);
+	if (!getdns_dict_get_list(request, "additional", &additional)) {
+		if (getdns_list_get_length(additional, &len))
+			len = 0;
+		for (i = 0; i < len; i++) {
+			if (getdns_list_get_dict(additional, i, &rr))
+				break;
+			if (getdns_dict_get_int(rr, "type", &rr_type))
+				break;
+			if (rr_type != GETDNS_RRTYPE_OPT)
+				continue;
+			msg->has_edns0 = 1;
+			(void) getdns_dict_get_int(rr, "do", &msg->do_bit);
+			break;
+		}
+	}
+	if ((r = getdns_context_get_resolution_type(context, &msg->rt)))
+		fprintf(stderr, "Could get resolution type from context: %s\n",
+		    _getdns_strerror(r));
+
+	if (msg->rt == GETDNS_RESOLUTION_STUB) {
+		(void)getdns_dict_set_int(
+		    qext , "/add_opt_parameters/do_bit", msg->do_bit);
+		if (!getdns_dict_get_dict(request, "header", &header))
+			(void)getdns_dict_set_dict(qext, "header", header);
+
+	}
+	if (msg->cd_bit)
+		getdns_dict_set_int(qext, "dnssec_return_all_statuses",
+		    GETDNS_EXTENSION_TRUE);
+
+	if (!getdns_dict_get_int(request, "/additional/0/extended_rcode",&n))
+		(void)getdns_dict_set_int(
+		    qext, "/add_opt_parameters/extended_rcode", n);
+
+	if (!getdns_dict_get_int(request, "/additional/0/version", &n))
+		(void)getdns_dict_set_int(
+		    qext, "/add_opt_parameters/version", n);
+
+	if (!getdns_dict_get_int(
+	    request, "/additional/0/udp_payload_size", &n))
+		(void)getdns_dict_set_int(qext,
+		    "/add_opt_parameters/maximum_udp_payload_size", n);
+
+	if (!getdns_dict_get_list(
+	    request, "/additional/0/rdata/options", &list))
+		(void)getdns_dict_set_list(qext,
+		    "/add_opt_parameters/options", list);
+
+	if ((r = getdns_dict_get_bindata(request,"/question/qname",&qname)))
+		fprintf(stderr, "Could not get qname from query: %s\n",
+		    _getdns_strerror(r));
+
+	else if ((r = getdns_convert_dns_name_to_fqdn(qname, &qname_str)))
+		fprintf(stderr, "Could not convert qname: %s\n",
+		    _getdns_strerror(r));
+
+	else if ((r=getdns_dict_get_int(request,"/question/qtype",&qtype)))
+		fprintf(stderr, "Could get qtype from query: %s\n",
+		    _getdns_strerror(r));
+
+	else if ((r=getdns_dict_get_int(request,"/question/qclass",&qclass)))
+		fprintf(stderr, "Could get qclass from query: %s\n",
+		    _getdns_strerror(r));
+
+	else if ((r = getdns_dict_set_int(qext, "specify_class", qclass)))
+		fprintf(stderr, "Could set class from query: %s\n",
+		    _getdns_strerror(r));
+
+	else if ((r = getdns_general(context, qname_str, qtype,
+	    qext, msg, &transaction_id, request_cb)))
+		fprintf(stderr, "Could not schedule query: %s\n",
+		    _getdns_strerror(r));
+	else {
+		DEBUG_SERVER("scheduled: %p %"PRIu64" for %s %d\n",
+		    (void *)msg, transaction_id, qname_str, (int)qtype);
+		getdns_dict_destroy(qext);
+		free(qname_str);
+		return;
+	}
+error:
+	if (qname_str)
+		free(qname_str);
+	if (qext)
+		getdns_dict_destroy(qext);
+	servfail(msg, &response);
+#if defined(SERVER_DEBUG) && SERVER_DEBUG
+	do {
+		char *request_str = getdns_pretty_print_dict(request);
+		char *response_str = getdns_pretty_print_dict(response);
+		DEBUG_SERVER("request error, request: %s\n, response: %s\n"
+		            , request_str, response_str);
+		free(response_str);
+		free(request_str);
+	} while(0);
+#endif
+	if ((r = getdns_reply(context, response, request_id))) {
+		fprintf(stderr, "Could not reply: %s\n",
+		    _getdns_strerror(r));
+		/* Cancel reply */
+		getdns_reply(context, NULL, request_id);
+	}
+	if (msg) {
+		if (msg->request)
+			getdns_dict_destroy(msg->request);
+		free(msg);
+	}
+	if (response)
+		getdns_dict_destroy(response);
+}
+
+static void stubby_log(void *userarg, uint64_t system,
+    getdns_loglevel_type level, const char *fmt, va_list ap)
+{
+	struct timeval tv;
+	struct tm tm;
+	char buf[10];
+#if defined(STUBBY_ON_WINDOWS) || defined(GETDNS_ON_WINDOWS)
+	time_t tsec;
+
+	gettimeofday(&tv, NULL);
+	tsec = (time_t) tv.tv_sec;
+	gmtime_s(&tm, (const time_t *) &tsec);
+#else
+	gettimeofday(&tv, NULL);
+	gmtime_r(&tv.tv_sec, &tm);
+#endif
+	strftime(buf, 10, "%H:%M:%S", &tm);
+	(void)userarg; (void)system; (void)level;
+	(void) fprintf(stderr, "[%s.%.6d] STUBBY: ", buf, (int)tv.tv_usec);
+	(void) vfprintf(stderr, fmt, ap);
+}
+
+void stubby_local_log(void *userarg, uint64_t system,
+    getdns_loglevel_type level, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	stubby_log(userarg, system, level, fmt, args);
+	va_end(args);
+}
+
+int
+main(int argc, char **argv)
+{
+	char home_stubby_conf_fn_spc[1024], *home_stubby_conf_fn = NULL;
+	const char *custom_config_fn = NULL;
+	int fn_sz;
+	int print_api_info = 0;
+	int log_connections = 0;
+	getdns_return_t r;
+	int opt;
+	long log_level = 7; 
+	char *ep;
+
+#ifndef USE_WINSOCK
+	char *prg_name = strrchr(argv[0], '/');
+#else
+	char *prg_name = strrchr(argv[0], '\\');
+#endif
+	prg_name = prg_name ? prg_name + 1 : argv[0];
+
+	while ((opt = getopt(argc, argv, "C:ighlv:")) != -1) {
+		switch (opt) {
+		case 'C':
+			custom_config_fn = optarg;
+			break;
+		case 'g':
+			run_in_foreground = 0;
+			break;
+		case 'h':
+			print_usage(stdout, prg_name);
+			exit(EXIT_SUCCESS);
+		case 'i':
+			print_api_info = 1;
+			break;
+		case 'l':
+			log_connections = 1;
+			break;
+		case 'v':
+			log_connections = 1;
+			errno = 0;
+			log_level = strtol(optarg, &ep, 10);
+			if (log_level < 0 ||  log_level > 7 || *ep != '\0' || 
+			    (errno == ERANGE &&
+			    (log_level == LONG_MAX || log_level == LONG_MIN)) ) {
+				fprintf(stderr, "Log level '%s' is invalid or out of range (0-7)\n", optarg);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		default:
+			print_usage(stderr, prg_name);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if ((r = getdns_context_create(&context, 1))) {
+		fprintf(stderr, "Create context failed: %s\n",
+		        _getdns_strerror(r));
+		return r;
+	}
+	if (log_connections) {
+		(void) getdns_context_set_logfunc(context, NULL,
+	    	GETDNS_LOG_UPSTREAM_STATS, (int)log_level, stubby_log);
+	}
+
+	(void) parse_config(default_config, 0);
+	if (custom_config_fn) {
+		if ((r = parse_config_file(custom_config_fn))) {
+			fprintf(stderr, "Could not parse config file "
+			        "\"%s\": %s\n", custom_config_fn,
+			        _getdns_strerror(r));
+			return r;
+		}
+	} else {
+		fn_sz = snprintf( home_stubby_conf_fn_spc
+				, sizeof(home_stubby_conf_fn_spc)
+				, "%s/.stubby.yml"
+				, getenv("HOME")
+				);
+
+		if (fn_sz > 0 && fn_sz < (int)sizeof(home_stubby_conf_fn_spc))
+			home_stubby_conf_fn = home_stubby_conf_fn_spc;
+
+		else if (fn_sz > 0) {
+			if (!(home_stubby_conf_fn = malloc(fn_sz + 1)) ||
+			    snprintf( home_stubby_conf_fn, fn_sz
+				    , "%s/.stubby.yml", getenv("HOME")) != fn_sz) {
+				if (home_stubby_conf_fn) {
+					free(home_stubby_conf_fn);
+					home_stubby_conf_fn = NULL;
+				}
+			}
+		}
+		if (home_stubby_conf_fn &&
+		    (r = parse_config_file(home_stubby_conf_fn))) {
+			if (r != GETDNS_RETURN_IO_ERROR)
+				fprintf( stderr, "Error parsing config file "
+				         "\"%s\": %s\n", home_stubby_conf_fn
+				       , _getdns_strerror(r));
+			if (home_stubby_conf_fn != home_stubby_conf_fn_spc)
+				free(home_stubby_conf_fn);
+			home_stubby_conf_fn = NULL;
+		}
+		if (!home_stubby_conf_fn &&
+		    (r = parse_config_file(STUBBYCONFDIR"/stubby.yml"))) {
+			if (r != GETDNS_RETURN_IO_ERROR) {
+				fprintf( stderr, "Error parsing config file \"%s\": %s\n"
+			            , STUBBYCONFDIR"/stubby.yml"
+			            , _getdns_strerror(r));
+			}
+			fprintf(stderr, "WARNING: No Stubby config file found... using minimal default config (Opportunistic Usage)\n");
+		}
+		if (home_stubby_conf_fn &&
+		    home_stubby_conf_fn != home_stubby_conf_fn_spc) {
+			free(home_stubby_conf_fn);
+		}
+	}
+	if ((r = getdns_context_set_resolution_type(context, GETDNS_RESOLUTION_STUB))) {
+		fprintf( stderr, "Error while trying to configure stubby for "
+		                 "stub resolution only: %s\n", _getdns_strerror(r));
+		exit(EXIT_FAILURE);
+	}
+	if (listen_count && (r = getdns_context_set_listen_addresses(
+	    context, listen_list, NULL, incoming_request_handler)))
+		perror("error: Could not bind on given addresses");
+	else if (print_api_info) {
+		getdns_dict *api_information = 
+		    getdns_context_get_api_information(context);
+		char *api_information_str;
+	       
+		if (listen_dict && !getdns_dict_get_list(
+		    listen_dict, "listen_list", &listen_list)) {
+
+			(void) getdns_dict_set_list(api_information,
+			    "listen_addresses", listen_list);
+		} else if (listen_list) {
+			(void) getdns_dict_set_list(api_information,
+			    "listen_addresses", listen_list);
+
+		} else if ((listen_list = getdns_list_create())) {
+			(void) getdns_dict_set_list(api_information,
+			    "listen_addresses", listen_list);
+			getdns_list_destroy(listen_list);
+			listen_list = NULL;
+		}
+		api_information_str =
+		    getdns_pretty_print_dict(api_information);
+		fprintf(stdout, "%s\n", api_information_str);
+		free(api_information_str);
+		getdns_dict_destroy(api_information);
+	}
+	else
+#if !defined(STUBBY_ON_WINDOWS) && !defined(GETDNS_ON_WINDOWS)
+	     if (!run_in_foreground) {
+		pid_t pid;
+		char pid_str[1024], *endptr;
+		FILE *fh = fopen(STUBBYPIDFILE, "r");
+		do {
+			pid_t running;
+
+			if (!fh || !fgets(pid_str, sizeof(pid_str), fh))
+				break;
+
+			running = strtol(pid_str, &endptr, 10);
+			if (endptr == pid_str)
+				break;
+
+			if (kill(running, 0) < 0 && errno == ESRCH)
+				break;
+
+			fprintf( stderr, "Not starting because a running "
+			        "stubby was found on pid: %d\n", running);
+			exit(EXIT_FAILURE);
+		} while(0);
+		if (fh)
+			(void) fclose(fh);
+
+		pid = fork();
+		if (pid == -1) {
+			perror("Could not fork of stubby daemon\n");
+			r = GETDNS_RETURN_GENERIC_ERROR;
+
+		} else if (pid) {
+			fh = fopen(STUBBYPIDFILE, "w");
+			if (fh) {
+				fprintf(fh, "%d", (int)pid);
+				fclose(fh);
+			} else {
+				fprintf(stderr, "Could not write pid to "
+				        "\"%s\": %s\n", STUBBYPIDFILE,
+				        strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+		} else
+			getdns_context_run(context);
+	} else
+#endif
+	{
+		stubby_local_log(NULL,GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
+			       "Starting DAEMON....\n");
+		getdns_context_run(context);
+	}
+
+	getdns_context_destroy(context);
+
+	if (listen_list)
+		getdns_list_destroy(listen_list);
+
+	return r;
+}
--- /dev/null
+++ getdns-1.2.0/stubby/src/yaml/convert_yaml_to_json.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2017, 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 <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "config.h"
+
+#include <yaml.h>
+
+#ifndef yaml_string_to_json_string
+#include "gldns/gbuffer.h"
+#else
+#include "sldns/sbuffer.h"
+#endif
+#include "convert_yaml_to_json.h"
+
+static int process_yaml_stream(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
+
+static int process_yaml_document(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
+
+static int process_yaml_mapping(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
+
+static int process_yaml_sequence(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
+
+static int process_yaml_value(yaml_parser_t *, yaml_event_t *, gldns_buffer *);
+
+static int output_scalar(yaml_event_t *, gldns_buffer *);
+
+static void report_parser_error(yaml_parser_t *);
+
+static char* event_type_string(yaml_event_type_t);
+
+/* public functions */
+
+char *
+yaml_string_to_json_string(const char *instr)
+{
+	assert(instr);
+
+	gldns_buffer *buf;
+	char* json = NULL;
+
+	buf = gldns_buffer_new(8192);
+	if (!buf) {
+		fprintf(stderr, "Could not assign buffer for json output");
+		return NULL;
+	}
+	
+	yaml_parser_t parser;
+	yaml_event_t event;
+
+	memset(&parser, 0, sizeof(parser));
+	memset(&event, 0, sizeof(event));
+
+	if (!yaml_parser_initialize(&parser)) {
+		fprintf(stderr, "Could not initialize the parser object\n");
+		goto return_error;
+	}
+
+	/* Set the parser parameters. */
+	yaml_parser_set_input_string(&parser, (const unsigned char *) instr, strlen(instr));
+
+	/* Get the first event. */
+	if (!yaml_parser_parse(&parser, &event)) {
+		report_parser_error(&parser);
+		goto return_error;
+	}
+
+	/* First event should be stream start. */
+	if (event.type != YAML_STREAM_START_EVENT) {
+		fprintf(stderr, "Event error: wrong type of event: %d\n", event.type);
+		goto return_error;
+	}
+
+	if (process_yaml_stream(&parser, &event, buf) != 0) {
+		goto return_error;
+	}
+
+	yaml_event_delete(&event);
+	yaml_parser_delete(&parser);
+	
+	/*
+	 * gldns_buffer_export() returns a pointer to the data and
+	 * sets a flag to prevent it from being deleted by
+	 * gldns_buffer_free()
+	 */
+	json = (char *) gldns_buffer_export(buf);
+	gldns_buffer_free(buf);
+
+	return json;
+
+return_error:
+
+	yaml_event_delete(&event);
+	yaml_parser_delete(&parser);
+	gldns_buffer_free(buf);
+
+	return NULL;
+}
+
+/* local functions */
+
+int
+process_yaml_stream(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
+{
+	assert(parser);
+	assert(event);
+	assert(buf);
+
+	int done = 0;
+
+	while (!done)
+	{
+		/* Delete the event that brought us here */
+		yaml_event_delete(event);
+
+		/* Get the next event. */
+		if (!yaml_parser_parse(parser, event)) {
+			report_parser_error(parser);
+			return -1;
+		}
+
+		switch (event->type) {
+		case YAML_STREAM_END_EVENT:
+
+			done = 1;
+			break;
+
+		case YAML_DOCUMENT_START_EVENT:
+
+			if (process_yaml_document(parser, event, buf) != 0) {
+				return -1;   
+			}
+			break;
+
+		case YAML_STREAM_START_EVENT:
+		case YAML_DOCUMENT_END_EVENT:
+		case YAML_ALIAS_EVENT:
+		case YAML_SCALAR_EVENT:
+		case YAML_SEQUENCE_START_EVENT:
+		case YAML_SEQUENCE_END_EVENT:
+		case YAML_MAPPING_START_EVENT:
+		case YAML_MAPPING_END_EVENT:
+
+			fprintf(stderr,
+				"Event error: %s. Expected YAML_DOCUMENT_START_EVENT or YAML_STREAM_END_EVENT.\n",
+				event_type_string(event->type));
+			return -1;
+
+		default:
+			/* NOTREACHED */
+			break;
+		}
+	}
+	return 0;
+}
+
+int
+process_yaml_document(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
+{
+	assert(parser);
+	assert(event);
+	assert(buf);
+
+	int done = 0;
+
+	while (!done)
+	{
+		/* Delete the event that brought us here */
+		yaml_event_delete(event);
+
+		/* Get the next event. */
+		if (!yaml_parser_parse(parser, event)) {
+			report_parser_error(parser);
+			return -1;
+		}
+
+		switch (event->type) {
+		case YAML_DOCUMENT_END_EVENT:
+
+			done = 1;
+			break;
+
+		case YAML_MAPPING_START_EVENT:
+			
+			if (process_yaml_mapping(parser, event, buf) != 0) {
+				return -1;
+			}
+			break;
+
+		case YAML_SEQUENCE_START_EVENT:
+			
+			if (process_yaml_sequence(parser, event, buf) != 0) {
+				return -1;   
+			}
+			break;
+
+		case YAML_SCALAR_EVENT:
+			
+			if (output_scalar(event, buf) != 0) {
+				fprintf(stderr, "Value error: Error outputting scalar\n");
+				return -1;
+			}
+			break;
+
+		case YAML_STREAM_START_EVENT:
+		case YAML_STREAM_END_EVENT:
+		case YAML_DOCUMENT_START_EVENT:
+		case YAML_ALIAS_EVENT:
+		case YAML_SEQUENCE_END_EVENT:
+		case YAML_MAPPING_END_EVENT:
+
+			fprintf(stderr,
+				"Event error: %s. Expected YAML_MAPPING_START_EVENT or YAML_DOCUMENT_END_EVENT.\n",
+				event_type_string(event->type));
+			return -1;
+
+		default:
+			/* NOTREACHED */
+			break;
+		}
+	}
+	return 0;
+}
+
+int
+process_yaml_mapping(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
+{
+	assert(parser);
+	assert(event);
+	assert(buf);
+	
+	int done = 0;
+	int members = 0;
+
+	if ( gldns_buffer_printf(buf, "{ ") == -1 )
+		return -1;
+	
+	while (!done)
+	{
+		/* Delete the event that brought us here */
+		yaml_event_delete(event);
+		
+		/* Get the next event. */
+		if (!yaml_parser_parse(parser, event)) {
+			report_parser_error(parser);
+			return -1;
+		}
+
+		if (event->type == YAML_SCALAR_EVENT) {
+			if (members)
+				if (gldns_buffer_printf(buf, ", ") == -1)
+					return -1;
+			
+			if (output_scalar(event, buf) != 0) {
+				fprintf(stderr, "Mapping error: Error outputting key\n");
+				return -1;
+			}
+			if (gldns_buffer_printf(buf, ": ") == -1)
+				return -1;
+			
+			members = 1;
+		} else if (event->type == YAML_MAPPING_END_EVENT) {
+			if (gldns_buffer_printf(buf, " }") == -1)
+				return -1;
+			done = 1;
+			continue;
+		} else {
+			fprintf(stderr,
+				"Event error: %s. Expected YAML_SCALAR_EVENT or YAML_MAPPING_END_EVENT.\n",
+				event_type_string(event->type));
+			return -1;
+		}
+		
+		/* Delete the event that brought us here */
+		yaml_event_delete(event);
+
+		/* Get the next event. */
+		if (!yaml_parser_parse(parser, event)) {
+			report_parser_error(parser);
+			return -1;
+		}
+
+		switch (event->type) {
+		case YAML_SCALAR_EVENT:
+		case YAML_SEQUENCE_START_EVENT:
+		case YAML_MAPPING_START_EVENT:
+			if (process_yaml_value(parser, event, buf) != 0) {
+				return -1;   
+			}
+			break;
+
+		case YAML_STREAM_START_EVENT:
+		case YAML_STREAM_END_EVENT:
+		case YAML_DOCUMENT_START_EVENT:
+		case YAML_DOCUMENT_END_EVENT:
+		case YAML_ALIAS_EVENT:
+		case YAML_SEQUENCE_END_EVENT:
+		case YAML_MAPPING_END_EVENT:
+			fprintf(stderr,
+				"Event error: %s. Expected YAML_MAPPING_START_EVENT, YAML_SEQUENCE_START_EVENT or YAML_SCALAR_EVENT.\n",
+				event_type_string(event->type));
+			return -1;
+
+		default:
+			/* NOTREACHED */
+			break;
+		}
+	}
+	return 0;
+}
+
+int
+process_yaml_sequence(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
+{	
+	assert(parser);
+	assert(event);
+	assert(buf);
+	
+	int done = 0;
+	int elements = 0;
+
+	if ( gldns_buffer_printf(buf, "[ ") == -1 )
+		return -1;
+   
+	while (!done)
+	{
+		/* Delete the event that brought us here */
+		yaml_event_delete(event);
+		
+		/* Get the next event. */
+		if (!yaml_parser_parse(parser, event)) {
+			report_parser_error(parser);
+			return -1;
+		}
+
+		switch (event->type) {
+		case YAML_SCALAR_EVENT:
+		case YAML_SEQUENCE_START_EVENT:
+		case YAML_MAPPING_START_EVENT:
+
+			if (elements)
+				if (gldns_buffer_printf(buf, ", ") == -1)
+					return -1;
+
+			if (process_yaml_value(parser, event, buf) != 0)
+				return -1;   
+
+			elements = 1;
+			break;
+
+		case YAML_SEQUENCE_END_EVENT:
+			if (gldns_buffer_printf(buf, " ]") == -1)
+				return -1;
+			done = 1;
+			break;
+
+		case YAML_STREAM_START_EVENT:
+		case YAML_STREAM_END_EVENT:
+		case YAML_DOCUMENT_START_EVENT:
+		case YAML_DOCUMENT_END_EVENT:
+		case YAML_ALIAS_EVENT:
+		case YAML_MAPPING_END_EVENT:
+			fprintf(stderr,
+				"Event error: %s. Expected YAML_MAPPING_START_EVENT, YAML_SEQUENCE_START_EVENT, YAML_SCALAR_EVENT or YAML_SEQUENCE_END_EVENT.\n",
+				event_type_string(event->type));
+			return -1;
+
+		default:
+			/* NOTREACHED */
+			break;
+		}
+	}
+	return 0;
+}
+
+int
+process_yaml_value(yaml_parser_t *parser, yaml_event_t *event, gldns_buffer *buf)
+{	
+	assert(parser);
+	assert(event);
+	assert(buf);
+	
+	switch (event->type) {
+	case YAML_SCALAR_EVENT:
+		if (output_scalar(event, buf) != 0) {
+			fprintf(stderr, "Value error: Error outputting scalar\n");
+			return -1;
+		}
+		break;
+
+	case YAML_SEQUENCE_START_EVENT:
+		if (process_yaml_sequence(parser, event, buf) != 0) {
+			return -1;   
+		}
+		break;
+
+	case YAML_MAPPING_START_EVENT:
+		if (process_yaml_mapping(parser, event, buf) != 0) {
+			return -1;   
+		}
+		break;
+		
+	default:
+		fprintf(stderr, "Bug: calling process_yaml_value() in the wrong context");
+		return -1;
+	}
+	return 0;
+}
+
+int
+output_scalar(yaml_event_t *event, gldns_buffer *buf)
+{
+	const char *fmt = "%s";
+	
+	assert(event);
+	assert(buf);
+	assert(event->data.scalar.length > 0);
+	
+	if (event->data.scalar.style != YAML_PLAIN_SCALAR_STYLE)
+		fmt = "\"%s\"";
+
+	if ( gldns_buffer_printf(buf, fmt, event->data.scalar.value) == -1 )
+		return -1;
+	return 0;
+}
+
+void report_parser_error(yaml_parser_t *parser)
+{
+	assert(parser);
+
+	/* Display a parser error message. */
+	switch (parser->error) {
+	case YAML_MEMORY_ERROR:
+		fprintf(stderr, "Memory error: Not enough memory for parsing\n");
+		break;
+
+	case YAML_READER_ERROR:
+		if (parser->problem_value != -1) {
+			fprintf(stderr, "Reader error: %s: #%X at %zu\n", parser->problem,
+					parser->problem_value, parser->problem_offset);
+		} else {
+			fprintf(stderr, "Reader error: %s at %zu\n", parser->problem,
+					parser->problem_offset);
+		}
+		break;
+
+	case YAML_SCANNER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Scanner error: %s at line %"PRIsz", column %"PRIsz"\n"
+					"%s at line %"PRIsz", column %"PRIsz"\n", parser->context,
+					parser->context_mark.line+1, parser->context_mark.column+1,
+					parser->problem, parser->problem_mark.line+1,
+					parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Scanner error: %s at line %"PRIsz", column %"PRIsz"\n",
+					parser->problem, parser->problem_mark.line+1,
+					parser->problem_mark.column+1);
+		}
+		break;
+
+	case YAML_PARSER_ERROR:
+		if (parser->context) {
+			fprintf(stderr, "Parser error: %s at line %"PRIsz", column %"PRIsz"\n"
+					"%s at line %"PRIsz", column %"PRIsz"\n", parser->context,
+					parser->context_mark.line+1, parser->context_mark.column+1,
+					parser->problem, parser->problem_mark.line+1,
+					parser->problem_mark.column+1);
+		} else {
+			fprintf(stderr, "Parser error: %s at line %"PRIsz", column %"PRIsz"\n",
+					parser->problem, parser->problem_mark.line+1,
+					parser->problem_mark.column+1);
+		}
+		break;
+
+	default:
+		/* Couldn't happen. */
+		fprintf(stderr, "Internal error\n");
+		break;
+	}
+	return;
+}
+
+/* TODO - improve this */
+char*
+event_type_string(yaml_event_type_t type)
+{	
+	switch (type) {
+	case YAML_STREAM_START_EVENT:
+		return "YAML_STREAM_START_EVENT";
+		
+	case YAML_STREAM_END_EVENT:
+		return "YAML_STREAM_END_EVENT";
+		
+	case YAML_DOCUMENT_START_EVENT:
+		return "YAML_DOCUMENT_START_EVENT";
+
+	case YAML_DOCUMENT_END_EVENT:
+		return "YAML_DOCUMENT_END_EVENT";
+
+	case YAML_ALIAS_EVENT:
+		return "YAML_ALIAS_EVENT";
+
+	case YAML_SCALAR_EVENT:
+		return "YAML_SCALAR_EVENT";
+
+	case YAML_SEQUENCE_START_EVENT:
+		return "YAML_SEQUENCE_START_EVENT";
+
+	case YAML_SEQUENCE_END_EVENT:
+		return "YAML_SEQUENCE_END_EVENT";
+
+	case YAML_MAPPING_START_EVENT:
+		return "YAML_MAPPING_START_EVENT";
+
+	case YAML_MAPPING_END_EVENT:
+		return "YAML_MAPPING_END_EVENT";
+
+	default:
+		/* NOTREACHED */
+		return NULL;
+	}
+	return NULL;
+}
--- /dev/null
+++ getdns-1.2.0/stubby/src/yaml/convert_yaml_to_json.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, 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 _CONVERT_YAML_TO_JSON_H
+#define _CONVERT_YAML_TO_JSON_H
+
+/**
+ * read yaml-syntax data from the string and convert to json-syntax
+ * yaml syntax resitrictions imposed for getdns:
+ *    the outer-most data structure must be a yaml mapping
+ *    mapping keys must be yaml scalars
+ *    plain scalars are output to the json string unchanged
+ *    non-plain scalars (quoted, double-quoted, wrapped) are output double-quoted
+ * TODO Test on yaml data containing yaml tags (these are ignored at present)
+ *      The code has only been tested on yaml data using indentation style, so it
+ *        should be tested on other styles as well.
+ * @param instr the string carrying data in yaml syntax
+ * @return a string of data in json syntax on success
+ * @return NULL if there is a yaml syntax violation
+ *                 the outer-most structure in not a mapping
+ *                 a mapping key is complex (a mapping or sequence)
+ */
+char * yaml_string_to_json_string(const char *instr);
+
+#endif //_CONVERT_YAML_TO_JSON_H
--- /dev/null
+++ getdns-1.2.0/stubby/stubby-setdns-macos.sh
@@ -0,0 +1,96 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, 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.
+
+
+# Stubby helper file to set DNS servers on macOS.
+# Note - this script doesn't detect or handle network events, simply changes the 
+# current resolvers
+# Must run as root.
+
+usage () {
+    echo
+    echo "Update the system DNS resolvers so that Stubby is used for all DNS"
+    echo "queries on macOS. (Stubby must already be running)"
+    echo "This must be run as root."
+    echo
+    echo "Usage: $0 options"
+    echo
+    echo "Supported options:"
+    echo "  -r Reset DNS resolvers to the default ones (e.g. from DHCP)"
+    echo "  -l List the current DNS settings for all interfaces"
+    echo "  -h Show this help."
+}
+
+RESET=0
+LIST=0
+SERVERS="127.0.0.1 ::1"
+OS_X=`uname -a | grep -c 'Darwin'`
+
+while getopts ":rlh" opt; do
+    case $opt in
+        r  ) RESET=1 ;;
+        l  ) LIST=1 ;;
+        h  ) usage
+             exit 1 ;;
+        \? ) usage
+             exit 1 ;;
+    esac
+done
+
+
+if [[ $OS_X -eq 0 ]]; then
+    echo "Sorry - This script only works on macOS and you are on a different OS."
+    exit 1
+fi
+
+if [[ $LIST -eq 1 ]]; then
+    echo "** Current DNS settings **"
+    networksetup -listallnetworkservices 2>/dev/null | grep -v '*' | while read x ; do
+        RESULT=`networksetup -getdnsservers "$x"`
+        RESULT=`echo $RESULT`
+        printf '%-30s %s\n' "$x:" "$RESULT"
+    done
+    exit 1
+fi
+
+if [ "$USER" != "root" ]; then
+    echo "Must be root to update system resolvers. Retry using 'sudo stubby-setdns'"
+    exit 1
+fi
+
+if [[ $RESET -eq 1 ]]; then
+    SERVERS="empty"
+    echo "Setting DNS servers to '"$SERVERS"' - the system will use default DNS service."
+else
+    echo "Setting DNS servers to '"$SERVERS"' - the system will use Stubby if it is running."
+fi
+
+### Set the DNS settings via networksetup ###
+networksetup -listallnetworkservices 2>/dev/null | grep -v '*' | while read x ; do
+    networksetup -setdnsservers "$x" $SERVERS
+done
+
--- /dev/null
+++ getdns-1.2.0/stubby/stubby.yml.example
@@ -0,0 +1,150 @@
+#
+# This is a yaml version of the stubby configuration file (it replaces the 
+# json based stubby.conf file used in earlier versions of getdns/stubby).
+#
+# For more information see
+# https://dnsprivacy.org/wiki/display/DP/Configuring+Stubby
+#
+# This format does not fully support all yaml features - the restrictions are:
+#   - the outer-most data structure must be a yaml mapping
+#   - mapping keys must be yaml scalars
+#   - plain scalars will be converted to json unchanged
+#   - non-plain scalars (quoted, double-quoted, wrapped) will be interpreted
+#     as json strings, i.e. double quoted
+#   - yaml tags are not supported
+#
+
+# Logging is currently configured at runtime using command line arguments. See
+# > stubby -h
+# for details.
+
+# Specifies whether to run as a recursive or stub resolver 
+# For stubby this MUST be set to GETDNS_RESOLUTION_STUB
+resolution_type: GETDNS_RESOLUTION_STUB
+
+# Ordered list composed of one or more transport protocols: 
+# GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP or GETDNS_TRANSPORT_TLS
+# If only one transport value is specified it will be the only transport used. 
+# Should it not be available basic resolution will fail.
+# Fallback transport options are specified by including multiple values in the
+# list.  Strict mode (see below) should use only GETDNS_TRANSPORT_TLS.
+dns_transport_list:
+  - GETDNS_TRANSPORT_TLS
+
+# Selects Strict or Opportunistic Usage profile as described in
+# https://datatracker.ietf.org/doc/draft-ietf-dprive-dtls-and-tls-profiles/
+# Strict mode requires that authentication information for the upstreams is
+# specified below. Opportunistic may fallback to clear text DNS if UDP or TCP
+# is included in the transport list above.
+# For Strict use        GETDNS_AUTHENTICATION_REQUIRED
+# For Opportunistic use GETDNS_AUTHENTICATION_NONE
+tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
+
+# EDNS0 option to pad the size of the DNS query to the given blocksize
+# 256 is currently recommended by 
+# https://tools.ietf.org/html/draft-ietf-dprive-padding-policy-01
+tls_query_padding_blocksize: 256
+
+# EDNS0 option for ECS client privacy as described in Section 7.1.2 of
+# https://tools.ietf.org/html/rfc7871
+edns_client_subnet_private : 1
+
+# EDNS0 option for keepalive idle timeout in ms as specified in
+# https://tools.ietf.org/html/rfc7828
+# This keeps idle TLS connections open to avoid the overhead of opening a new 
+# connection for every query.
+idle_timeout: 10000
+
+# Set the listen addresses for the stubby DAEMON. This specifies localhost IPv4
+# and IPv6. It will listen on port 53 by default.
+listen_addresses:
+  - 127.0.0.1
+  -  0::1
+
+# Instructs stubby to distribute queries across all available name servers. 
+# Set to 0 to treat the upstreams below as an ordered list and use a single
+# upstream until it becomes unavailable, then use the next one.
+round_robin_upstreams: 1
+
+# Specify the list of upstream recursive name servers to send queries to
+# In Strict mode upstreams need either a tls_auth_name or a tls_pubkey_pinset
+# so the upstream can be authenticated.
+# The list below includes some of the available test servers. If you don't
+# have IPv6 then comment then out.
+# In Opportunistic mode they only require an IP address in address_data.
+# The information for an upstream can include the following:
+# - address_data: IPv4 or IPv6 address of the upstream
+#   port: Port for UDP/TCP (default is 53)
+#   tls_auth_name: Authentication domain name checked against the server
+#                  certificate
+#   tls_pubkey_pinset: An SPKI pinset verified against the keys in the server
+#                      certificate
+#     - digest: Only "sha256" is currently supported
+#       value: Base64 encoded value of the sha256 fingerprint of the public
+#              key
+#   tls_port: Port for TLS (default is 853)
+upstream_recursive_servers:
+# IPv4 addresses
+# The Surfnet/Sinodun servers
+  - address_data: 145.100.185.15
+    tls_auth_name: "dnsovertls.sinodun.com"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: 62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=
+  - address_data: 145.100.185.16
+    tls_auth_name: "dnsovertls1.sinodun.com"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: cE2ecALeE5B+urJhDrJlVFmf38cJLAvqekONvjvpqUA=
+# The getdnsapi.net server
+  - address_data: 185.49.141.37
+    tls_auth_name: "getdnsapi.net"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=
+# The uncensored DNS servers (no SPKI available)
+  - address_data: 184.105.193.78
+    tls_auth_name: "unicast.censurfridns.dk"
+# IPv6 addresses
+# The Surfnet/Sinodun servers
+  - address_data: 2001:610:1:40ba:145:100:185:15
+    tls_auth_name: "dnsovertls.sinodun.com"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: 62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=
+  - address_data: 2001:610:1:40ba:145:100:185:16
+    tls_auth_name: "dnsovertls1.sinodun.com"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: cE2ecALeE5B+urJhDrJlVFmf38cJLAvqekONvjvpqUA=
+# The getdnsapi.net server
+  - address_data: 2a04:b900:0:100::38
+    tls_auth_name: "getdnsapi.net"
+    tls_pubkey_pinset:
+      - digest: "sha256"
+        value: foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9Q=
+# The uncensored DNS server (no SPKI available)
+  - address_data: 2620:ff:c000:0:1::64:25
+    tls_auth_name: "unicast.censurfridns.dk"
+
+# Require DNSSEC validation. For releases earlier than 1.2 a trust anchor must
+# be configured configured manually. This can be done with unbound-anchor.
+# dnssec_return_status: GETDNS_EXTENSION_TRUE
+
+#Specify the location of the installed trust anchor file
+# dnssec_trust_anchors: "/etc/unbound/getdns-root.key"
+
+# Control the maximum number of connection failures that will be permitted
+# before Stubby backs-off from using an individual upstream (default 2)
+# tls_connection_retries: 5
+
+# Control the maximum time in seconds Stubby will back-off from using an
+# individual upstream after failures under normal circumstances (default 3600)
+# tls_backoff_time: 300
+
+# Limit the total number of outstanding queries permitted
+# limit_outstanding_queries: 100
+
+# Specify the timeout on getting a response to an individual request
+# (default 5s)
+# timeout: 1
--- /dev/null
+++ getdns-1.2.0/stubby/systemd/README.md
@@ -0,0 +1,16 @@
+Stubby integration with systemd
+===============================
+
+For GNU/Linux operating systems which use systemd as a process
+manager, you might want to run stubby as a system service.
+
+This directory provides recommended systemd unit files.
+
+This setup assumes that there is a system-level user named "stubby"
+which is in group "stubby", and try to limit the privileges of the
+running daemon to that user as closely as possible.
+
+Normally, a downstream distributor will install them as:
+
+    /usr/lib/tmpfiles.d/stubby.yml
+    /lib/systemd/system/stubby.service
--- /dev/null
+++ getdns-1.2.0/stubby/systemd/stubby.conf
@@ -0,0 +1,2 @@
+# tmpfiles.d (5) for use with stubby.service
+d /run/stubby 0750 root stubby - -
--- /dev/null
+++ getdns-1.2.0/stubby/systemd/stubby.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=stubby DNS resolver
+
+[Service]
+WorkingDirectory=/run/stubby
+ExecStart=/usr/bin/stubby
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+User=stubby
+
+[Install]
+WantedBy=multi-user.target
