release v0.1.8

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVNB2sAAoJEOX4+CEvd6SYQVkP/1AgRoUw+5BM6gm+z5J4heXg
 W9EpICfKn2BTC8JVwVOzA3LHJZ95tosNv+fy0faK0n7jByvT4ySl4V/k2W9JSd/S
 bhDR5A1zyfYJdLTDONdkwXki9H90MW69lRGfh+zb0VHzFwi/10xQqYlUatF0IxY3
 Vg4L0PBaUC4UsQevjJNxDJQkr4Q5hJph9jLyij7Zfty/rqjDIZoQpZgMeoZIr9xI
 v51lnlG0ss6lnSRUkM1Nta3mFsXhTDNAhe8/pPUP+lWXceXqCWK63vJGf6Lp3LN4
 gw/COsGnQdiUIbfRGWWGXuqG4c52SAK+ZE9D01bOeLJHw2S8IuA8oFvXdwfGcvYQ
 /gax26lguWk4IrgWIHTRalZJbn+mTNG/DXqrpOuw+BWp3prdoJmyvtOc0rLX1OB2
 ueDDphPg/kSiSknnMmrUgHC2elWewsZCFhx5Umy149ONQK85AQ08DAtJP5dHsXzi
 Om/wuvbuzhoHtPV9YZZYcTa6uSVWaMLHLVJ5K9ifTJEvIKk4pVwbsFS5XIZAVEig
 yGmSsngTQP4w3LdFZSCk3FRu0D+y60sG++Gs1X2X+TsLP/6ZoOL0lYEkPwGfHsvL
 dhgG+iNUgSKmLwrpyI7c1DD1ZlpZluomjQQ5evfogHOmZC22AJvuNQI6hJY1pvXQ
 AU+pzxUfo8947+nEJxMR
 =qFXQ
 -----END PGP SIGNATURE-----

Merge tag 'v0.1.8'

release v0.1.8
This commit is contained in:
Willem Toorop 2015-04-19 23:28:49 +02:00
commit 29b378ab16
16 changed files with 691 additions and 112 deletions

View File

@ -1,3 +1,8 @@
* 2015-04-19: Version 0.1.8
* The GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN and
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN
DNS over TLS transport options.
* 2015-04-08: Version 0.1.7
* Individual getter functions for context settings
* Fix: --with-current-date function to make build deterministically

74
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for getdns 0.1.7.
# Generated by GNU Autoconf 2.69 for getdns 0.1.8.
#
# Report bugs to <stub-resolver@verisignlabs.com>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='getdns'
PACKAGE_TARNAME='getdns'
PACKAGE_VERSION='0.1.7'
PACKAGE_STRING='getdns 0.1.7'
PACKAGE_VERSION='0.1.8'
PACKAGE_STRING='getdns 0.1.8'
PACKAGE_BUGREPORT='stub-resolver@verisignlabs.com'
PACKAGE_URL='http://getdnsapi.net'
@ -1323,7 +1323,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures getdns 0.1.7 to adapt to many kinds of systems.
\`configure' configures getdns 0.1.8 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1388,7 +1388,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of getdns 0.1.7:";;
short | recursive ) echo "Configuration of getdns 0.1.8:";;
esac
cat <<\_ACEOF
@ -1519,7 +1519,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
getdns configure 0.1.7
getdns configure 0.1.8
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2008,7 +2008,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by getdns $as_me 0.1.7, which was
It was created by getdns $as_me 0.1.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2367,7 +2367,7 @@ else
CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"
fi
GETDNS_COMPILATION_COMMENT="getdns 0.1.7 configured on $CURRENT_DATE for the January 2015 version of the API"
GETDNS_COMPILATION_COMMENT="getdns 0.1.8 configured on $CURRENT_DATE for the January 2015 version of the API"
# Library version
# ---------------
@ -2387,9 +2387,10 @@ GETDNS_COMPILATION_COMMENT="getdns 0.1.7 configured on $CURRENT_DATE for the Jan
# getdns-0.1.4 had libversion 0:0:0
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
# getdns-0.1.7 will have libversion 1:2:1
# getdns-0.1.7 had libversion 1:2:1
# getdns-0.1.8 will have libversion 1:3:0
#
GETDNS_LIBVERSION=1:2:1
GETDNS_LIBVERSION=1:3:0
@ -11333,8 +11334,8 @@ $as_echo "found in $ssldir" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for HMAC_CTX_init in -lcrypto" >&5
$as_echo_n "checking for HMAC_CTX_init in -lcrypto... " >&6; }
LIBS="$LIBS -lcrypto"
LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
LIBS="$LIBS -lcrypto -lssl"
LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@ -11543,6 +11544,51 @@ fi
done
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TLSv1_2_client_method in -lssl" >&5
$as_echo_n "checking for TLSv1_2_client_method in -lssl... " >&6; }
if ${ac_cv_lib_ssl_TLSv1_2_client_method+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-lssl $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char TLSv1_2_client_method ();
int
main ()
{
return TLSv1_2_client_method ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_lib_ssl_TLSv1_2_client_method=yes
else
ac_cv_lib_ssl_TLSv1_2_client_method=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_TLSv1_2_client_method" >&5
$as_echo "$ac_cv_lib_ssl_TLSv1_2_client_method" >&6; }
if test "x$ac_cv_lib_ssl_TLSv1_2_client_method" = xyes; then :
$as_echo "#define HAVE_LIBTLS1_2 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find TLSv1_2_client_method in libssl library. TLS will not be available." >&5
$as_echo "$as_me: WARNING: Cannot find TLSv1_2_client_method in libssl library. TLS will not be available." >&2;}
fi
@ -14277,7 +14323,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by getdns $as_me 0.1.7, which was
This file was extended by getdns $as_me 0.1.8, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -14344,7 +14390,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
getdns config.status 0.1.7
getdns config.status 0.1.8
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -31,7 +31,7 @@
AC_PREREQ([2.56])
AC_INIT([getdns], [0.1.7], [stub-resolver@verisignlabs.com], [], [http://getdnsapi.net])
AC_INIT([getdns], [0.1.8], [stub-resolver@verisignlabs.com], [], [http://getdnsapi.net])
AC_SUBST(RELEASE_CANDIDATE, [])
# Set current date from system if not set
@ -60,9 +60,10 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_STRING configured on $CURRENT_DATE for th
# getdns-0.1.4 had libversion 0:0:0
# getdns-0.1.5 had libversion 1:0:0
# getdns-0.1.6 had libversion 1:1:0
# getdns-0.1.7 will have libversion 1:2:1
# getdns-0.1.7 had libversion 1:2:1
# getdns-0.1.8 will have libversion 1:3:0
#
GETDNS_LIBVERSION=1:2:1
GETDNS_LIBVERSION=1:3:0
AC_SUBST(GETDNS_COMPILATION_COMMENT)
AC_SUBST(GETDNS_LIBVERSION)
@ -741,6 +742,10 @@ unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest);
#include <arpa/inet.h>
#endif
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
#ifdef HAVE_ATTR_FORMAT
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
__attribute__ ((format (archetype, string_index, first_to_check)))

View File

@ -48,8 +48,8 @@ AC_DEFUN([ACX_SSL_CHECKS], [
fi
AC_MSG_CHECKING([for HMAC_CTX_init in -lcrypto])
LIBS="$LIBS -lcrypto"
LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto"
LIBS="$LIBS -lcrypto -lssl"
LIBSSL_LIBS="$LIBSSL_LIBS -lcrypto -lssl"
AC_TRY_LINK(, [
int HMAC_CTX_init(void);
(void)HMAC_CTX_init();
@ -105,6 +105,8 @@ AC_DEFUN([ACX_SSL_CHECKS], [
AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_LIB(ssl, TLSv1_2_client_method,AC_DEFINE([HAVE_LIBTLS1_2], [1],
[Define if you have libssl with tls 1.2]),[AC_MSG_WARN([Cannot find TLSv1_2_client_method in libssl library. TLS will not be available.])])
])dnl End of ACX_SSL_CHECKS
dnl Check for SSL, where SSL is mandatory

6
spec/index.html Normal file → Executable file
View File

@ -2193,8 +2193,10 @@ getdns_context_set_dns_transport(
The value is <span class=default>
<code>GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP</code></span>,
<code>GETDNS_TRANSPORT_UDP_ONLY</code>,
<code>GETDNS_TRANSPORT_TCP_ONLY</code>, or
<code>GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN</code>.</p>
<code>GETDNS_TRANSPORT_TCP_ONLY</code>,
<code>GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN></code>,
<code>GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN></code>, or
<code>GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN></code>
<div class=forh>
getdns_return_t

View File

@ -84,6 +84,9 @@
/* Define to 1 if you have the `ldns' library (-lldns). */
#undef HAVE_LIBLDNS
/* Define if you have libssl with tls 1.2 */
#undef HAVE_LIBTLS1_2
/* Define to 1 if you have the `unbound' library (-lunbound). */
#undef HAVE_LIBUNBOUND
@ -320,6 +323,10 @@ unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest);
#include <arpa/inet.h>
#endif
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#endif
#ifdef HAVE_ATTR_FORMAT
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
__attribute__ ((format (archetype, string_index, first_to_check)))

2
src/const-info.c Normal file → Executable file
View File

@ -39,6 +39,8 @@ static struct const_info consts_info[] = {
{ 541, "GETDNS_TRANSPORT_UDP_ONLY", GETDNS_TRANSPORT_UDP_ONLY_TEXT },
{ 542, "GETDNS_TRANSPORT_TCP_ONLY", GETDNS_TRANSPORT_TCP_ONLY_TEXT },
{ 543, "GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
{ 544, "GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT },
{ 545, "GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN", GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT },
{ 550, "GETDNS_APPEND_NAME_ALWAYS", GETDNS_APPEND_NAME_ALWAYS_TEXT },
{ 551, "GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE_TEXT },
{ 552, "GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE", GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE_TEXT },

View File

@ -470,11 +470,22 @@ upstreams_resize(getdns_upstreams *upstreams, size_t size)
return r;
}
static void
upstreams_dereference(getdns_upstreams *upstreams)
void
priv_getdns_upstreams_dereference(getdns_upstreams *upstreams)
{
if (upstreams && --upstreams->referenced == 0)
size_t i;
if (upstreams && --upstreams->referenced == 0) {
for (i = 0; i < upstreams->count; i++) {
if (upstreams->upstreams[i].tls_obj != NULL) {
SSL_shutdown(upstreams->upstreams[i].tls_obj);
SSL_free(upstreams->upstreams[i].tls_obj);
}
if (upstreams->upstreams[i].fd != -1)
close(upstreams->upstreams[i].fd);
}
GETDNS_FREE(upstreams->mf, upstreams);
}
}
static uint8_t*
@ -503,7 +514,8 @@ upstream_scope_id(getdns_upstream *upstream)
}
static void
upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
upstream_ntop_buf(getdns_upstream *upstream, getdns_transport_t transport,
char *buf, size_t len)
{
/* Also possible but prints scope_id by name (nor parsed by unbound)
*
@ -515,7 +527,10 @@ upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
if (upstream_scope_id(upstream))
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"%%%d", (int)*upstream_scope_id(upstream));
if (upstream_port(upstream) != 53 && upstream_port(upstream) != 0)
if (transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"@%d", GETDNS_TLS_PORT);
else if (upstream_port(upstream) != 53 && upstream_port(upstream) != 0)
(void) snprintf(buf + strlen(buf), len - strlen(buf),
"@%d", (int)upstream_port(upstream));
}
@ -541,6 +556,7 @@ upstream_init(getdns_upstream *upstream,
/* For sharing a socket to this upstream with TCP */
upstream->fd = -1;
upstream->tls_obj = NULL;
upstream->loop = NULL;
(void) getdns_eventloop_event_init(
&upstream->event, upstream, NULL, NULL, NULL);
@ -770,6 +786,7 @@ getdns_context_create_with_extended_memory_functions(
result->edns_extended_rcode = 0;
result->edns_version = 0;
result->edns_do_bit = 0;
result-> tls_ctx = NULL;
result->extension = &result->mini_event.loop;
if ((r = getdns_mini_event_init(result, &result->mini_event)))
@ -789,6 +806,9 @@ getdns_context_create_with_extended_memory_functions(
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
/* unbound context is initialized here */
/* Unbound needs SSL to be init'ed this early when TLS is used. However we
* don't know that till later so we will have to do this every time. */
SSL_library_init();
result->unbound_ctx = NULL;
if ((r = rebuild_ub_ctx(result)))
goto error;
@ -876,6 +896,9 @@ getdns_context_destroy(struct getdns_context *context)
GETDNS_FREE(context->my_mf, context->fchg_hosts->prevstat);
GETDNS_FREE(context->my_mf, context->fchg_hosts);
}
if (context->tls_ctx) {
SSL_CTX_free(context->tls_ctx);
}
getdns_list_destroy(context->dns_root_servers);
getdns_list_destroy(context->suffix);
@ -887,7 +910,7 @@ getdns_context_destroy(struct getdns_context *context)
getdns_traverse_postorder(&context->local_hosts,
destroy_local_host, context);
upstreams_dereference(context->upstreams);
priv_getdns_upstreams_dereference(context->upstreams);
GETDNS_FREE(context->my_mf, context);
} /* getdns_context_destroy */
@ -1101,6 +1124,33 @@ getdns_context_set_namespaces(struct getdns_context *context,
return GETDNS_RETURN_GOOD;
} /* getdns_context_set_namespaces */
getdns_base_transport_t
priv_get_base_transport(getdns_transport_t transport, int level) {
if (!(level == 0 || level == 1)) return GETDNS_TRANSPORT_NONE;
switch (transport) {
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
if (level == 0) return GETDNS_TRANSPORT_UDP;
if (level == 1) return GETDNS_TRANSPORT_TCP;
case GETDNS_TRANSPORT_UDP_ONLY:
if (level == 0) return GETDNS_TRANSPORT_UDP;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TCP_ONLY:
if (level == 0) return GETDNS_TRANSPORT_TCP_SINGLE;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TCP;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TLS;
if (level == 1) return GETDNS_TRANSPORT_NONE;
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
if (level == 0) return GETDNS_TRANSPORT_TLS;
if (level == 1) return GETDNS_TRANSPORT_TCP;
default:
return GETDNS_TRANSPORT_NONE;
}
}
static getdns_return_t
set_ub_dns_transport(struct getdns_context* context,
getdns_transport_t value) {
@ -1114,13 +1164,25 @@ set_ub_dns_transport(struct getdns_context* context,
set_ub_string_opt(context, "do-tcp:", "no");
break;
case GETDNS_TRANSPORT_TCP_ONLY:
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
/* Note: no pipelining available directly in unbound.*/
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
set_ub_string_opt(context, "do-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes");
break;
default:
/* TODO GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN */
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
/* Hum. If used in recursive mode this will try TLS on port 53...
* So we need to fix or document that or delay setting it until
* resolution.*/
set_ub_string_opt(context, "ssl-upstream:", "yes");
/* Fall through*/
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
/* Note: no fallback to TCP available directly in unbound, so we just
* use TCP for now to make sure the messages are sent. */
set_ub_string_opt(context, "do-udp:", "no");
set_ub_string_opt(context, "do-tcp:", "yes");
break;
default:
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
return GETDNS_RETURN_GOOD;
}
@ -1134,6 +1196,11 @@ getdns_context_set_dns_transport(struct getdns_context *context,
getdns_transport_t value)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
/* Note that the call below does not have any effect in unbound after the
* ctx is finalised. So will not apply for recursive mode or stub + dnssec.
* However the method returns success as otherwise the transport could not
* be reset for stub mode.....
* Also, not all transport options supported in libunbound yet */
if (set_ub_dns_transport(context, value) != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
}
@ -1447,7 +1514,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
upstreams->count++;
freeaddrinfo(ai);
}
upstreams_dereference(context->upstreams);
priv_getdns_upstreams_dereference(context->upstreams);
context->upstreams = upstreams;
dispatch_updated(context,
GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
@ -1457,7 +1524,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
invalid_parameter:
r = GETDNS_RETURN_INVALID_PARAMETER;
error:
upstreams_dereference(upstreams);
priv_getdns_upstreams_dereference(upstreams);
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
} /* getdns_context_set_upstream_recursive_servers */
@ -1653,17 +1720,18 @@ getdns_cancel_callback(getdns_context *context,
} /* getdns_cancel_callback */
static getdns_return_t
ub_setup_stub(struct ub_ctx *ctx, getdns_upstreams *upstreams)
ub_setup_stub(struct ub_ctx *ctx, getdns_context *context)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
size_t i;
getdns_upstream *upstream;
char addr[1024];
getdns_upstreams *upstreams = context->upstreams;
(void) ub_ctx_set_fwd(ctx, NULL);
for (i = 0; i < upstreams->count; i++) {
upstream = &upstreams->upstreams[i];
upstream_ntop_buf(upstream, addr, 1024);
upstream_ntop_buf(upstream, context->dns_transport, addr, 1024);
ub_ctx_set_fwd(ctx, addr);
}
@ -1735,7 +1803,7 @@ priv_getdns_ns_dns_setup(struct getdns_context *context)
case GETDNS_RESOLUTION_STUB:
if (!context->upstreams || !context->upstreams->count)
return GETDNS_RETURN_GENERIC_ERROR;
return ub_setup_stub(context->unbound_ctx, context->upstreams);
return ub_setup_stub(context->unbound_ctx, context);
case GETDNS_RESOLUTION_RECURSING:
/* TODO: use the root servers via root hints file */
@ -1756,6 +1824,33 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
if (context->destroying) {
return GETDNS_RETURN_BAD_CONTEXT;
}
/* Transport can in theory be set per query in stub mode */
/* TODO: move this transport logic to a separate functions*/
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
switch (context->dns_transport) {
case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
if (context->tls_ctx == NULL) {
#ifdef HAVE_LIBTLS1_2
/* Create client context, use TLS v1.2 only for now */
context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
#endif
if(!context->tls_ctx && context->dns_transport ==
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN) {
return GETDNS_RETURN_BAD_CONTEXT;
}
}
break;
default:
break;
}
}
/* Block use of TLS ONLY in recursive mode as it won't work */
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING
&& context->dns_transport == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
return GETDNS_RETURN_BAD_CONTEXT;
if (context->resolution_type_set == context->resolution_type)
/* already set and no config changes
* have caused this to be bad.

View File

@ -49,6 +49,7 @@ struct ub_ctx;
#define GETDNS_FN_RESOLVCONF "/etc/resolv.conf"
#define GETDNS_FN_HOSTS "/etc/hosts"
#define GETDNS_TLS_PORT 1021
enum filechgs { GETDNS_FCHG_ERRORS = -1
, GETDNS_FCHG_NOERROR = 0
@ -71,6 +72,14 @@ struct filechg {
struct stat *prevstat;
};
typedef enum getdns_base_transport {
GETDNS_TRANSPORT_NONE,
GETDNS_TRANSPORT_UDP,
GETDNS_TRANSPORT_TCP_SINGLE,
GETDNS_TRANSPORT_TCP,
GETDNS_TRANSPORT_TLS
} getdns_base_transport_t;
typedef struct getdns_upstream {
struct getdns_upstreams *upstreams;
@ -83,6 +92,7 @@ typedef struct getdns_upstream {
/* For sharing a TCP socket to this upstream */
int fd;
SSL* tls_obj;
getdns_eventloop_event event;
getdns_eventloop *loop;
getdns_tcp_state tcp;
@ -133,6 +143,7 @@ struct getdns_context {
uint8_t edns_version;
uint8_t edns_do_bit;
int edns_maximum_udp_payload_size; /* -1 is unset */
SSL_CTX* tls_ctx;
getdns_update_callback update_callback;
getdns_update_callback2 update_callback2;
@ -220,4 +231,8 @@ int filechg_check(struct getdns_context *context, struct filechg *fchg);
void priv_getdns_context_ub_read_cb(void *userarg);
getdns_base_transport_t priv_get_base_transport(getdns_transport_t transport, int level);
void priv_getdns_upstreams_dereference(getdns_upstreams *upstreams);
#endif /* _GETDNS_CONTEXT_H_ */

6
src/getdns/getdns.h.in Normal file → Executable file
View File

@ -163,7 +163,9 @@ typedef enum getdns_transport_t {
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP = 540,
GETDNS_TRANSPORT_UDP_ONLY = 541,
GETDNS_TRANSPORT_TCP_ONLY = 542,
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN = 543
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN = 543,
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN = 544,
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN = 545
} getdns_transport_t;
/**
@ -174,6 +176,8 @@ typedef enum getdns_transport_t {
#define GETDNS_TRANSPORT_UDP_ONLY_TEXT "See getdns_context_set_dns_transport()"
#define GETDNS_TRANSPORT_TCP_ONLY_TEXT "See getdns_context_set_dns_transport()"
#define GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
#define GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
#define GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN_TEXT "See getdns_context_set_dns_transport()"
/** @}
*/

View File

@ -177,8 +177,7 @@ dns_req_free(getdns_dns_req * req)
return;
}
if (req->upstreams && --req->upstreams->referenced == 0)
GETDNS_FREE(req->upstreams->mf, req->upstreams);
priv_getdns_upstreams_dereference(req->upstreams);
/* cleanup network requests */
for (net_req = req->netreqs; *net_req; net_req++)

392
src/stub.c Normal file → Executable file
View File

@ -318,6 +318,13 @@ upstream_erred(getdns_upstream *upstream)
netreq->state = NET_REQ_FINISHED;
priv_getdns_check_dns_req_complete(netreq->owner);
}
/* TODO[TLS]: When we get an error (which is probably a timeout) and are
* using to keep connections open should we leave the connection up here? */
if (upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
close(upstream->fd);
upstream->fd = -1;
}
@ -521,7 +528,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
tcp->to_read -= read;
tcp->read_pos += read;
if (tcp->to_read > 0)
if ((int)tcp->to_read > 0)
return STUB_TCP_AGAIN;
read = tcp->read_pos - tcp->read_buf;
@ -595,6 +602,187 @@ stub_tcp_read_cb(void *userarg)
}
}
/** wait for a socket to become ready */
static int
sock_wait(int sockfd)
{
int ret;
fd_set fds;
FD_ZERO(&fds);
FD_SET(FD_SET_T sockfd, &fds);
/*TODO[TLS]: Pick up this timeout from the context*/
struct timeval timeout = {5, 0 };
ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
if(ret == 0)
/* timeout expired */
return 0;
else if(ret == -1)
/* error */
return 0;
return 1;
}
static int
sock_connected(int sockfd)
{
/* wait(write) until connected or error */
while(1) {
int error = 0;
socklen_t len = (socklen_t)sizeof(error);
if(!sock_wait(sockfd)) {
close(sockfd);
return -1;
}
/* check if there is a pending error for nonblocking connect */
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)&error, &len) < 0) {
error = errno; /* on solaris errno is error */
}
if (error == EINPROGRESS || error == EWOULDBLOCK)
continue; /* try again */
else if (error != 0) {
close(sockfd);
return -1;
}
/* connected */
break;
}
return sockfd;
}
/* The connection testing and handshake should be handled by integrating this
* with the event loop framework, but for now just implement a standalone
* handshake method.*/
static SSL*
do_tls_handshake(getdns_dns_req *dnsreq, getdns_upstream *upstream)
{
/*Lets make sure the connection is up before we try a handshake*/
if (errno == EINPROGRESS && sock_connected(upstream->fd) == -1) {
return NULL;
}
/* Create SSL instance */
if (dnsreq->context->tls_ctx == NULL)
return NULL;
SSL* ssl = SSL_new(dnsreq->context->tls_ctx);
if(!ssl) {
return NULL;
}
/* Connect the SSL object with a file descriptor */
if(!SSL_set_fd(ssl, upstream->fd)) {
SSL_free(ssl);
return NULL;
}
SSL_set_connect_state(ssl);
(void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
int r;
int want;
fd_set fds;
FD_ZERO(&fds);
FD_SET(upstream->fd, &fds);
struct timeval timeout = {dnsreq->context->timeout/1000, 0 };
while ((r = SSL_do_handshake(ssl)) != 1)
{
want = SSL_get_error(ssl, r);
switch (want) {
case SSL_ERROR_WANT_READ:
if (select(upstream->fd + 1, &fds, NULL, NULL, &timeout) == 0) {
SSL_free(ssl);
return NULL;
}
break;
case SSL_ERROR_WANT_WRITE:
if (select(upstream->fd + 1, NULL, &fds, NULL, &timeout) == 0) {
SSL_free(ssl);
return NULL;
}
break;
default:
SSL_free(ssl);
return NULL;
}
}
return ssl;
}
static int
stub_tls_read(SSL* tls_obj, getdns_tcp_state *tcp, struct mem_funcs *mf)
{
ssize_t read;
uint8_t *buf;
size_t buf_size;
if (!tcp->read_buf) {
/* First time tls read, create a buffer for reading */
if (!(tcp->read_buf = GETDNS_XMALLOC(*mf, uint8_t, 4096)))
return STUB_TCP_ERROR;
tcp->read_buf_len = 4096;
tcp->read_pos = tcp->read_buf;
tcp->to_read = 2; /* Packet size */
}
ERR_clear_error();
read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read);
if (read <= 0) {
/* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
renegotiation. Need to keep handshake state to do that.*/
int want = SSL_get_error(tls_obj, read);
if (want == SSL_ERROR_WANT_READ) {
return STUB_TCP_AGAIN; /* read more later */
} else
return STUB_TCP_ERROR;
}
tcp->to_read -= read;
tcp->read_pos += read;
if ((int)tcp->to_read > 0)
return STUB_TCP_AGAIN;
read = tcp->read_pos - tcp->read_buf;
if (read == 2) {
/* Read the packet size short */
tcp->to_read = gldns_read_uint16(tcp->read_buf);
if (tcp->to_read < GLDNS_HEADER_SIZE)
return STUB_TCP_ERROR;
/* Resize our buffer if needed */
if (tcp->to_read > tcp->read_buf_len) {
buf_size = tcp->read_buf_len;
while (tcp->to_read > buf_size)
buf_size *= 2;
if (!(buf = GETDNS_XREALLOC(*mf,
tcp->read_buf, uint8_t, buf_size)))
return STUB_TCP_ERROR;
tcp->read_buf = buf;
tcp->read_buf_len = buf_size;
}
/* Ready to start reading the packet */
tcp->read_pos = tcp->read_buf;
read = SSL_read(tls_obj, tcp->read_pos, tcp->to_read);
if (read <= 0) {
/* TODO[TLS]: Handle SSL_ERROR_WANT_WRITE which means handshake
renegotiation. Need to keep handshake state to do that.*/
int want = SSL_get_error(tls_obj, read);
if (want == SSL_ERROR_WANT_READ) {
return STUB_TCP_AGAIN; /* read more later */
} else
return STUB_TCP_ERROR;
}
tcp->to_read -= read;
tcp->read_pos += read;
if ((int)tcp->to_read > 0)
return STUB_TCP_AGAIN;
}
return GLDNS_ID_WIRE(tcp->read_buf);
}
static void netreq_upstream_read_cb(void *userarg);
static void netreq_upstream_write_cb(void *userarg);
static void
@ -607,8 +795,14 @@ upstream_read_cb(void *userarg)
uint16_t query_id;
intptr_t query_id_intptr;
switch ((q = stub_tcp_read(upstream->fd, &upstream->tcp,
&upstream->upstreams->mf))) {
if (upstream->tls_obj)
q = stub_tls_read(upstream->tls_obj, &upstream->tcp,
&upstream->upstreams->mf);
else
q = stub_tcp_read(upstream->fd, &upstream->tcp,
&upstream->upstreams->mf);
switch (q) {
case STUB_TCP_AGAIN:
return;
@ -617,6 +811,7 @@ upstream_read_cb(void *userarg)
return;
default:
/* Lookup netreq */
query_id = (uint16_t) q;
query_id_intptr = (intptr_t) query_id;
@ -705,9 +900,9 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
* the write_queue) for that upstream. Register this netreq
* by query_id in the process.
*/
if (dnsreq->context->dns_transport !=
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN)
if ((dnsreq->context->dns_transport == GETDNS_TRANSPORT_TCP_ONLY) ||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_ONLY) ||
(dnsreq->context->dns_transport == GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP))
query_id = arc4random();
else do {
query_id = arc4random();
@ -822,6 +1017,54 @@ stub_tcp_write_cb(void *userarg)
}
}
static int
stub_tls_write(SSL* tls_obj, getdns_tcp_state *tcp, getdns_network_req *netreq)
{
size_t pkt_len = netreq->response - netreq->query;
ssize_t written;
uint16_t query_id;
intptr_t query_id_intptr;
/* Do we have remaining data that we could not write before? */
if (! tcp->write_buf) {
/* No, this is an initial write. Try to send
*/
/* Find a unique query_id not already written (or in
* the write_queue) for that upstream. Register this netreq
* by query_id in the process.
*/
do {
query_id = ldns_get_random();
query_id_intptr = (intptr_t)query_id;
netreq->node.key = (void *)query_id_intptr;
} while (!getdns_rbtree_insert(
&netreq->upstream->netreq_by_query_id, &netreq->node));
GLDNS_ID_SET(netreq->query, query_id);
if (netreq->opt)
/* no limits on the max udp payload size with tcp */
gldns_write_uint16(netreq->opt + 3, 65535);
/* We have an initialized packet buffer.
* Lets see how much of it we can write */
// TODO[TLS]: Handle error cases, partial writes, renegotiation etc.
ERR_clear_error();
written = SSL_write(tls_obj, netreq->query - 2, pkt_len + 2);
if (written <= 0)
return STUB_TCP_ERROR;
/* We were able to write everything! Start reading. */
return (int) query_id;
}
return STUB_TCP_ERROR;
}
static void
upstream_write_cb(void *userarg)
{
@ -830,7 +1073,12 @@ upstream_write_cb(void *userarg)
getdns_dns_req *dnsreq = netreq->owner;
int q;
switch ((q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq))) {
if (upstream->tls_obj)
q = stub_tls_write(upstream->tls_obj, &upstream->tcp, netreq);
else
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
switch (q) {
case STUB_TCP_AGAIN:
return;
@ -902,6 +1150,58 @@ upstream_schedule_netreq(getdns_upstream *upstream, getdns_network_req *netreq)
}
}
static in_port_t
get_port(struct sockaddr_storage* addr)
{
return ntohs(addr->ss_family == AF_INET
? ((struct sockaddr_in *)addr)->sin_port
: ((struct sockaddr_in6*)addr)->sin6_port);
}
static void
set_port(struct sockaddr_storage* addr, in_port_t port)
{
addr->ss_family == AF_INET
? (((struct sockaddr_in *)addr)->sin_port = htons(port))
: (((struct sockaddr_in6*)addr)->sin6_port = htons(port));
}
static int
tcp_connect (getdns_upstream *upstream, getdns_base_transport_t transport) {
int fd =-1;
struct sockaddr_storage connect_addr;
struct sockaddr_storage* addr = &upstream->addr;
socklen_t addr_len = upstream->addr_len;
/* TODO[TLS]: For now, override the port to a hardcoded value*/
if (transport == GETDNS_TRANSPORT_TLS &&
(int)get_port(addr) != GETDNS_TLS_PORT) {
connect_addr = upstream->addr;
addr = &connect_addr;
set_port(addr, GETDNS_TLS_PORT);
}
if ((fd = socket(addr->ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
return -1;
getdns_sock_nonblock(fd);
#ifdef USE_TCP_FASTOPEN
/* Leave the connect to the later call to sendto() if using TCP*/
if (transport == GETDNS_TRANSPORT_TCP ||
transport == GETDNS_TRANSPORT_TCP_SINGLE)
return fd;
#endif
if (connect(fd, (struct sockaddr *)addr,
addr_len) == -1) {
if (errno != EINPROGRESS) {
close(fd);
return -1;
}
}
return fd;
}
getdns_return_t
priv_getdns_submit_stub_request(getdns_network_req *netreq)
{
@ -911,9 +1211,13 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
if (!upstream)
return GETDNS_RETURN_GENERIC_ERROR;
switch(dnsreq->context->dns_transport) {
case GETDNS_TRANSPORT_UDP_ONLY:
case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
// Work out the primary and fallback transport options
getdns_base_transport_t transport = priv_get_base_transport(
dnsreq->context->dns_transport,0);
getdns_base_transport_t fb_transport = priv_get_base_transport(
dnsreq->context->dns_transport,1);
switch(transport) {
case GETDNS_TRANSPORT_UDP:
if ((netreq->fd = socket(
upstream->addr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1)
@ -929,23 +1233,10 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
return GETDNS_RETURN_GOOD;
case GETDNS_TRANSPORT_TCP_ONLY:
case GETDNS_TRANSPORT_TCP_SINGLE:
if ((netreq->fd = socket(
upstream->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
if ((netreq->fd = tcp_connect(upstream, transport)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
getdns_sock_nonblock(netreq->fd);
#ifdef USE_TCP_FASTOPEN
/* Leave the connect to the later call to sendto() */
#else
if (connect(netreq->fd, (struct sockaddr *)&upstream->addr,
upstream->addr_len) == -1 && errno != EINPROGRESS) {
close(netreq->fd);
return GETDNS_RETURN_GENERIC_ERROR;
}
#endif
netreq->upstream = upstream;
GETDNS_SCHEDULE_EVENT(
@ -955,34 +1246,51 @@ priv_getdns_submit_stub_request(getdns_network_req *netreq)
return GETDNS_RETURN_GOOD;
case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
case GETDNS_TRANSPORT_TCP:
case GETDNS_TRANSPORT_TLS:
/* In coming comments, "global" means "context wide" */
/* Are we the first? (Is global socket initialized?) */
if (upstream->fd == -1) {
/* We are the first. Make global socket and connect. */
if ((upstream->fd = socket(upstream->addr.ss_family,
SOCK_STREAM, IPPROTO_TCP)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
getdns_sock_nonblock(upstream->fd);
#ifdef USE_TCP_FASTOPEN
/* Leave the connect to the later call to sendto() */
#else
if (connect(upstream->fd,
(struct sockaddr *)&upstream->addr,
upstream->addr_len) == -1 && errno != EINPROGRESS){
/* TODO[TLS]: We should remember on the context if we had to fallback
* for this upstream so when re-connecting from a dropped TCP
* connection we don't retry TLS. */
int fallback = 0;
close(upstream->fd);
upstream->fd = -1;
return GETDNS_RETURN_GENERIC_ERROR;
/* We are the first. Make global socket and connect. */
if ((upstream->fd = tcp_connect(upstream, transport)) == -1) {
if (fb_transport == GETDNS_TRANSPORT_NONE)
return GETDNS_RETURN_GENERIC_ERROR;
if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
fallback = 1;
}
/* Now do a handshake for TLS. Note waiting for this to succeed or
* timeout blocks the scheduling of any messages for this upstream*/
if (transport == GETDNS_TRANSPORT_TLS && (fallback == 0)) {
upstream->tls_obj = do_tls_handshake(dnsreq, upstream);
if (!upstream->tls_obj) {
if (fb_transport == GETDNS_TRANSPORT_NONE)
return GETDNS_RETURN_GENERIC_ERROR;
close(upstream->fd);
if ((upstream->fd = tcp_connect(upstream, fb_transport)) == -1)
return GETDNS_RETURN_GENERIC_ERROR;
}
}
#endif
/* Attach to the global event loop
* so it can do it's own scheduling
*/
upstream->loop = dnsreq->context->extension;
} else {
/* Cater for the case of the user downgrading and existing TLS
connection to TCP for some reason...*/
if (transport == GETDNS_TRANSPORT_TCP && upstream->tls_obj) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
}
netreq->upstream = upstream;

View File

@ -29,9 +29,23 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <getdns/getdns.h>
#include <getdns/getdns_extra.h>
static int quiet = 0;
static int batch_mode = 0;
static char *query_file = NULL;
static int json = 0;
static char *the_root = ".";
static char *name;
static getdns_context *context;
static getdns_dict *extensions;
static uint16_t request_type = GETDNS_RRTYPE_NS;
static int timeout, edns0_size;
static int async = 0, interactive = 0;
static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
int get_rrtype(const char *t);
getdns_dict *
@ -90,6 +104,7 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-b <bufsize>\tSet edns0 max_udp_payload size\n");
fprintf(out, "\t-D\tSet edns0 do bit\n");
fprintf(out, "\t-d\tclear edns0 do bit\n");
fprintf(out, "\t-F <filename>\tread the queries from the specified file\n");
fprintf(out, "\t-G\tgeneral lookup\n");
fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> is ignored)\n");
fprintf(out, "\t-h\tPrint this help\n");
@ -104,29 +119,45 @@ print_usage(FILE *out, const char *progname)
fprintf(out, "\t-t <timeout>\tSet timeout in miliseconds\n");
fprintf(out, "\t-T\tSet transport to TCP only\n");
fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n");
fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n");
fprintf(out, "\t-E\tSet transport to TLS with TCP fallback only keep connections open\n");
fprintf(out, "\t-u\tSet transport to UDP with TCP fallback\n");
fprintf(out, "\t-U\tSet transport to UDP only\n");
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
}
void callback(getdns_context *context, getdns_callback_type_t callback_type,
getdns_dict *response, void *userarg, getdns_transaction_t trans_id)
{
getdns_dict **response_ptr = (getdns_dict **)userarg;
char *response_str;
if (response)
*response_ptr = response;
if (callback_type == GETDNS_CALLBACK_COMPLETE) {
/* This is a callback with data */;
if (!quiet && (response_str = json ?
getdns_print_json_dict(response, json == 1)
: getdns_pretty_print_dict(response))) {
fprintf(stdout, "ASYNC response:\n%s\n", response_str);
free(response_str);
}
fprintf(stderr,
"The callback with ID %llu was successfull.\n",
(unsigned long long)trans_id);
} else if (callback_type == GETDNS_CALLBACK_CANCEL)
fprintf(stderr,
"The callback with ID %llu was cancelled. Exiting.\n",
(unsigned long long)trans_id);
else
fprintf(stderr,
"The callback got a callback_type of %d. Exiting.\n",
callback_type);
getdns_dict_destroy(response);
response = NULL;
}
static char *the_root = ".";
static char *name;
static getdns_context *context;
static getdns_dict *extensions;
static uint16_t request_type = GETDNS_RRTYPE_NS;
static int timeout, edns0_size;
static int async = 0, interactive = 0;
static enum { GENERAL, ADDRESS, HOSTNAME, SERVICE } calltype = GENERAL;
static int json = 0;
#define CONTINUE ((getdns_return_t)-2)
static getdns_return_t set_cookie(getdns_dict *exts, char *cookie)
@ -259,6 +290,15 @@ getdns_return_t parse_args(int argc, char **argv)
case 'd':
(void) getdns_context_set_edns_do_bit(context, 0);
break;
case 'F':
if (c[1] != 0 || ++i >= argc || !*argv[i]) {
fprintf(stderr, "file name expected "
"after -F\n");
return GETDNS_RETURN_GENERIC_ERROR;
}
query_file = argv[i];
interactive = 1;
break;
case 'G':
calltype = GENERAL;
break;
@ -282,6 +322,8 @@ getdns_return_t parse_args(int argc, char **argv)
break;
case 'p':
json = 0;
case 'q':
quiet = 1;
break;
case 'r':
getdns_context_set_resolution_type(
@ -319,6 +361,14 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
break;
case 'L':
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
break;
case 'E':
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
break;
case 'u':
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP);
@ -327,6 +377,9 @@ getdns_return_t parse_args(int argc, char **argv)
getdns_context_set_dns_transport(context,
GETDNS_TRANSPORT_UDP_ONLY);
break;
case 'B':
batch_mode = 1;
break;
default:
@ -361,6 +414,7 @@ main(int argc, char **argv)
char *response_str;
getdns_return_t r;
getdns_dict *address = NULL;
FILE *fp = NULL;
name = the_root;
if ((r = getdns_context_create(&context, 1))) {
@ -376,14 +430,28 @@ main(int argc, char **argv)
if ((r = parse_args(argc, argv)))
goto done_destroy_context;
if (query_file) {
fp = fopen(query_file, "rt");
if (fp == NULL) {
fprintf(stderr, "Could not open query file: %s\n", query_file);
goto done_destroy_context;
}
}
/* Make the call */
do {
char line[1024], *token, *linev[256];
int linec;
if (interactive) {
fprintf(stdout, "> ");
if (!fgets(line, 1024, stdin) || !*line)
break;
if (!query_file) {
fprintf(stdout, "> ");
if (!fgets(line, 1024, stdin) || !*line)
break;
} else {
if (!fgets(line, 1024, fp) || !*line)
break;
fprintf(stdout,"Found query: %s", line);
}
linev[0] = argv[0];
linec = 1;
@ -430,8 +498,8 @@ main(int argc, char **argv)
}
if (r)
goto done_destroy_extensions;
getdns_context_run(context);
if (!batch_mode)
getdns_context_run(context);
} else {
switch (calltype) {
case GENERAL:
@ -456,22 +524,29 @@ main(int argc, char **argv)
}
if (r)
goto done_destroy_extensions;
}
if (json)
response_str = getdns_print_json_dict(
response, json == 1);
else
response_str = getdns_pretty_print_dict(response);
if (!quiet) {
if ((response_str = json ?
getdns_print_json_dict(response, json == 1)
: getdns_pretty_print_dict(response))) {
if (response_str) {
fprintf(stdout, "%s\n", response_str);
free(response_str);
} else {
r = GETDNS_RETURN_MEMORY_ERROR;
fprintf(stderr, "Could not print response\n");
fprintf( stdout, "SYNC response:\n%s\n"
, response_str);
free(response_str);
} else {
r = GETDNS_RETURN_MEMORY_ERROR;
fprintf( stderr
, "Could not print response\n");
}
} else if (r == GETDNS_RETURN_GOOD)
fprintf(stdout, "Response code was: GOOD\n");
else if (interactive)
fprintf(stderr, "An error occurred: %d\n", r);
}
} while (interactive);
if (batch_mode)
getdns_context_run(context);
/* Clean up */
done_destroy_extensions:
getdns_dict_destroy(extensions);
@ -479,6 +554,9 @@ done_destroy_context:
if (response) getdns_dict_destroy(response);
getdns_context_destroy(context);
if (fp)
fclose(fp);
if (r == CONTINUE)
return 0;
if (r)

View File

@ -44,6 +44,8 @@
#define TRANSPORT_UDP "udp"
#define TRANSPORT_TCP "tcp"
#define TRANSPORT_PIPELINE "pipeline"
#define TRANSPORT_TLS_KEEPOPEN "tls"
#define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls"
#define RESOLUTION_STUB "stub"
#define RESOLUTION_REC "rec"
@ -98,6 +100,10 @@ main(int argc, char** argv)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY);
else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_UDP, 3) != 0) {
fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport);
exit(EXIT_FAILURE);

View File

@ -41,6 +41,8 @@
#define TRANSPORT_UDP "udp"
#define TRANSPORT_TCP "tcp"
#define TRANSPORT_PIPELINE "pipeline"
#define TRANSPORT_TLS_KEEPOPEN "tls"
#define TRANSPORT_TLS_TCP_KEEPOPEN "dns-over-tls"
#define RESOLUTION_STUB "stub"
#define RESOLUTION_REC "rec"
@ -82,6 +84,10 @@ main(int argc, char** argv)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY);
else if (strncmp(transport, TRANSPORT_PIPELINE, 8) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_KEEPOPEN, 3) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_TLS_TCP_KEEPOPEN, 12) == 0)
getdns_context_set_dns_transport(this_context, GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN);
else if (strncmp(transport, TRANSPORT_UDP, 3) != 0) {
fprintf(stderr, "Invalid transport %s, must be one of udp, tcp or pipeline\n", transport);
exit(EXIT_FAILURE);

View File

@ -36,7 +36,6 @@
#ifndef TYPES_INTERNAL_H_
#define TYPES_INTERNAL_H_
#include <netinet/in.h>
#include "getdns/getdns.h"
#include "getdns/getdns_extra.h"
#include "util/rbtree.h"