Merge branch 'develop'

This commit is contained in:
Willem Toorop 2017-11-11 10:24:55 +08:00
commit 3098ed6fca
29 changed files with 866 additions and 513 deletions

View File

@ -1,3 +1,21 @@
* 2017-11-11: Version 1.2.1
* Handle more I/O error cases. Also, when an I/O error does occur,
never stop listening (with servers), and
never exit (when running the built-in event loop).
* Bugfix: Tolerate unsigned and unused RRsets in the authority section.
Fixes DNSSEC with BIND upstream.
* Bugfix: DNSSEC validation without support records
* Bugfix: Validation of full recursive DNSKEY lookups
* Bugfix: Retry to validate full recursion BOGUS replies with zero
configuration DNSSEC only when DNSSEC was actually requested
* Bugfix #348: Fix a linking issue in stubby when libbsd is present
Thanks Remi Gacogne
* More robust scheduling; Eliminating a segfault with long running
applications.
* Miscellaneous Windows portability fixes from Jim Hague.
* Fix Makefile dependencies for parallel install.
Thanks ilovezfs
* 2017-09-29: Version 1.2.0
* Bugfix of rc1: authentication of first query with TLS
Thanks Travis Burtrum

View File

@ -36,7 +36,18 @@ sinclude(./m4/acx_getaddrinfo.m4)
sinclude(./m4/ax_check_compile_flag.m4)
sinclude(./m4/pkg.m4)
AC_INIT([getdns], [1.2.0], [users@getdnsapi.net], [], [https://getdnsapi.net])
AC_INIT([getdns], [1.2.1], [team@getdnsapi.net], [getdns], [https://getdnsapi.net])
# Autoconf 2.70 will have set up runstatedir. 2.69 is frequently (Debian)
# patched to do the same, but frequently (MacOS) not. So add a with option
# for pid file location, and default it to runstatedir if present.
default_piddir=${runstatedir:-"${localstatedir}/run"}
AC_ARG_WITH([piddir],
[AS_HELP_STRING([--with-piddir=DIR],
[directory for pid files @<:@default=RUNSTATEDIR or LOCALSTATEDIR/run@:>@])],
[],
[with_piddir=${default_piddir}])
AC_SUBST([runstatedir], [$with_piddir])
# Dont forget to put a dash in front of the release candidate!!!
# That is how it is done with semantic versioning!
@ -51,7 +62,7 @@ AC_ARG_WITH([current-date],
[CURRENT_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`"])
AC_SUBST(GETDNS_VERSION, ["AC_PACKAGE_VERSION$RELEASE_CANDIDATE"])
AC_SUBST(GETDNS_NUMERIC_VERSION, [0x01020000])
AC_SUBST(GETDNS_NUMERIC_VERSION, [0x01020100])
AC_SUBST(API_VERSION, ["December 2015"])
AC_SUBST(API_NUMERIC_VERSION, [0x07df0c00])
GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRENT_DATE for the $API_VERSION version of the API"
@ -86,9 +97,10 @@ GETDNS_COMPILATION_COMMENT="AC_PACKAGE_NAME $GETDNS_VERSION configured on $CURRE
# getdns-1.1.1 had libversion 6:1:0
# getdns-1.1.2 had libversion 7:0:1
# getdns-1.1.3 had libversion 7:1:1
# getdns-1.2.0 has libversion 8:0:2
# getdns-1.2.0 had libversion 8:0:2
# getdns-1.2.1 has libversion 8:1:2
#
GETDNS_LIBVERSION=8:0:2
GETDNS_LIBVERSION=8:1:2
AC_SUBST(GETDNS_COMPILATION_COMMENT)
AC_SUBST(GETDNS_LIBVERSION)
@ -253,7 +265,7 @@ esac
DEFAULT_EVENTLOOP=select_eventloop
AC_CHECK_HEADERS([sys/poll.h poll.h sys/resource.h sys/types.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([signal.h sys/poll.h poll.h sys/resource.h sys/types.h],,, [AC_INCLUDES_DEFAULT])
AC_ARG_ENABLE(poll-eventloop, AC_HELP_STRING([--disable-poll-eventloop], [Disable default eventloop based on poll (default=enabled if available)]))
case "$enable_poll_eventloop" in
no)
@ -588,7 +600,7 @@ case "$enable_ed25519" in
no)
;;
*)
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
if test "$USE_NSS" = "no" -a "$USE_NETTLE" = "no"; then
AC_CHECK_DECLS([NID_ED25519], [
AC_DEFINE_UNQUOTED([USE_ED25519], [1], [Define this to enable ED25519 support.])
use_ed25519="yes"
@ -676,28 +688,30 @@ if test "$USE_WINSOCK" = 1; then
LIBS="$LIBS -lgdi32 -liphlpapi"
fi
dnl Check if -D_POSIX is needed for sigset_t
AC_CHECK_TYPE([sigset_t], [
AC_MSG_NOTICE(-D_POSIX is NOT needed for the sigset_t type)
], [
BACKCFLAGS="$CFLAGS"
CFLAGS="-D_POSIX $CFLAGS"
AC_CHECK_TYPE([sigset_t], [
AC_MSG_NOTICE(-D_POSIX is needed for the sigset_t type)
], [
AC_MSG_NOTICE(Unclear whether -D_POSIX is needed for the sigset_t type)
BACKCFLAGS="$CFLAGS"
], [AC_INCLUDES_DEFAULT
dnl sigset_t or _sigset_t? MinGW is latter by default.
AC_CHECK_TYPES([sigset_t],
[],
[AC_CHECK_TYPES([_sigset_t],
[],
[AC_MSG_ERROR([Can't find type `sigset_t' or type `_sigset_t'])],
[AC_INCLUDES_DEFAULT
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
])
], [AC_INCLUDES_DEFAULT
])
],
[AC_INCLUDES_DEFAULT
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
])
AC_CHECK_FUNCS(sigemptyset sigfillset sigaddset)
my_with_libidn=1
AC_ARG_WITH(libidn, AS_HELP_STRING([--with-libidn=pathname],
@ -1144,8 +1158,8 @@ AC_SUBST(INSTALL_STUBBY)
AC_SUBST(UNINSTALL_STUBBY)
AC_SUBST(STUBBY_XTRA_OBJS)
STUBBY_LDFLAGS=""
STUBBY_LIBS=""
STUBBY_LDFLAGS=""
if test $my_with_yaml = 1
then
@ -1153,8 +1167,8 @@ then
then
getdns_LIBS="$LIBS"
getdns_LDFLAGS="$LDFLAGS"
LIBS=""
LDFLAGS=""
LIBS="$initial_LIBS"
LDFLAGS="$initial_LDFLAGS"
fi
AC_ARG_WITH(libyaml, AS_HELP_STRING([--with-libyaml=pathname],
[path to libyaml (default: search /usr/local ..)]),
@ -1267,11 +1281,12 @@ fi
# system implementation.
PKG_CHECK_MODULES([LIBBSD],[libbsd-overlay],[
LIBS="$LIBS $LIBBSD_LIBS"
STUBBY_LIBS="$STUBBY_LIBS $LIBBSD_LIBS"
CFLAGS="$CFLAGS $LIBBSD_CFLAGS"
],[
AC_MSG_WARN([libbsd not found or usable; using embedded code instead])
])
AC_CHECK_DECLS([strlcpy,arc4random,arc4random_uniform])
AC_CHECK_DECLS([inet_pton,inet_ntop,strlcpy,arc4random,arc4random_uniform])
AC_REPLACE_FUNCS(inet_pton)
AC_REPLACE_FUNCS(inet_ntop)
AC_REPLACE_FUNCS(strlcpy)
@ -1347,7 +1362,38 @@ AH_BOTTOM([
# ifndef FD_SETSIZE
# define FD_SETSIZE 1024
# endif
# define PRIsz "Iu"
/* the version of the windows API enabled */
# ifndef WINVER
# define WINVER 0x0600 // 0x0502
# endif
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0600 // 0x0502
# endif
# ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
# endif
# ifdef _MSC_VER
# if _MSC_VER >= 1800
# define PRIsz "zu"
# else
# define PRIsz "Iu"
# endif
# else
# define PRIsz "Iu"
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
# ifdef HAVE_WINSOCK2_H
# define FD_SET_T (u_int)
# else
# define FD_SET_T
# endif
/* Windows wants us to use _strdup instead of strdup */
# ifndef strdup
@ -1363,34 +1409,6 @@ AH_BOTTOM([
#include <assert.h>
#include <string.h>
/* the version of the windows API enabled */
#ifndef WINVER
#define WINVER 0x0600 // 0x0502
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // 0x0502
#endif
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#ifndef USE_WINSOCK
#define ARG_LL "%ll"
#else
#define ARG_LL "%I64"
#endif
/* detect if we need to cast to unsigned int for FD_SET to avoid warnings */
#ifdef HAVE_WINSOCK2_H
#define FD_SET_T (u_int)
#else
#define FD_SET_T
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -1437,11 +1455,11 @@ void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*);
unsigned char *SHA512(void* data, unsigned int data_len, unsigned char *digest);
#endif /* COMPAT_SHA512 */
#ifndef HAVE_INET_PTON
#ifndef HAVE_DECL_INET_PTON
int inet_pton(int af, const char* src, void* dst);
#endif /* HAVE_INET_PTON */
#ifndef HAVE_INET_NTOP
#ifndef HAVE_DECL_INET_NTOP
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
@ -1544,12 +1562,29 @@ static inline int _gldns_custom_vsnprintf(char *str, size_t size, const char *fo
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(HAVE_STRPTIME) || !defined(STRPTIME_WORKS)
#define strptime unbound_strptime
struct tm;
char *strptime(const char *s, const char *format, struct tm *tm);
#endif
#if !defined(HAVE_SIGSET_T) && defined(HAVE__SIGSET_T)
typedef _sigset_t sigset_t;
#endif
#if !defined(HAVE_SIGEMPTYSET)
# define sigemptyset(pset) (*(pset) = 0)
#endif
#if !defined(HAVE_SIGFILLSET)
# define sigfillset(pset) (*(pset) = (sigset_t)-1)
#endif
#if !defined(HAVE_SIGADDSET)
# define sigaddset(pset, num) (*(pset) |= (1L<<(num)))
#endif
#ifdef HAVE_LIBUNBOUND
# include <unbound.h>
# ifdef HAVE_UNBOUND_EVENT_H
@ -1567,6 +1602,10 @@ int ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
# endif
# endif
#endif
#ifdef __cplusplus
}
#endif
])
dnl ---------------------------------------------------------------------------

View File

@ -77,7 +77,7 @@ C99COMPATFLAGS=@C99COMPATFLAGS@
DEFAULT_EVENTLOOP_OBJ=@DEFAULT_EVENTLOOP@.lo
GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \
list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \
list.lo request-internal.lo platform.lo pubkey-pinning.lo rr-dict.lo \
rr-iter.lo server.lo stub.lo sync.lo ub_loop.lo util-internal.lo \
mdns.lo
@ -160,7 +160,7 @@ install-headers: getdns/getdns.h getdns/getdns_extra.h
uninstall-headers:
rm -rf $(DESTDIR)$(includedir)/getdns
install-libs: libgetdns.la
install-libs: libgetdns.la $(EXTENSION_LIBEVENT_LIB) $(EXTENSION_LIBUV_LIB) $(EXTENSION_LIBEV_LIB)
$(INSTALL) -m 755 -d $(DESTDIR)$(libdir)
$(LIBTOOL) --mode=install cp libgetdns.la $(DESTDIR)$(libdir)
if test $(have_libevent) = 1 ; then $(LIBTOOL) --mode=install cp $(EXTENSION_LIBEVENT_LIB) $(DESTDIR)$(libdir) ; fi
@ -223,6 +223,7 @@ install-stubby-files-windows: stubby.yml.windows
install-stubby: stubby install-stubby-files-@HOSTOS@
$(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
$(LIBTOOL) --mode=install cp stubby $(DESTDIR)$(bindir)
$(INSTALL) -m 755 -d $(DESTDIR)$(runstatedir)
uninstall-stubby:
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(bindir)/stubby
@ -293,7 +294,7 @@ anchor.lo anchor.o: $(srcdir)/anchor.c \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/yxml/yxml.h \
$(srcdir)/gldns/parseutil.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/wire2str.h \
$(srcdir)/gldns/keyraw.h $(srcdir)/general.h $(srcdir)/util-internal.h
$(srcdir)/gldns/keyraw.h $(srcdir)/general.h $(srcdir)/util-internal.h $(srcdir)/platform.h
const-info.lo const-info.o: $(srcdir)/const-info.c \
getdns/getdns.h \
getdns/getdns_extra.h \
@ -309,8 +310,8 @@ context.lo context.o: $(srcdir)/context.c \
$(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \
$(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h \
$(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/dnssec.h \
$(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h
convert.lo convert.o: $(srcdir)/convert.c \
config.h \
getdns/getdns.h \
@ -362,7 +363,7 @@ general.lo general.o: $(srcdir)/general.c \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h $(srcdir)/dnssec.h $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h \
$(srcdir)/dict.h $(srcdir)/mdns.h
$(srcdir)/dict.h $(srcdir)/mdns.h $(srcdir)/platform.h
list.lo list.o: $(srcdir)/list.c $(srcdir)/types-internal.h \
getdns/getdns.h \
getdns/getdns_extra.h \
@ -383,9 +384,11 @@ mdns.lo mdns.o: $(srcdir)/mdns.c \
$(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/general.h $(srcdir)/gldns/rrdef.h $(srcdir)/util-internal.h $(srcdir)/mdns.h \
$(srcdir)/util/auxiliary/util/fptr_wlist.h $(srcdir)/util/lookup3.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/general.h $(srcdir)/gldns/rrdef.h $(srcdir)/util-internal.h \
$(srcdir)/platform.h $(srcdir)/mdns.h $(srcdir)/util/auxiliary/util/fptr_wlist.h $(srcdir)/util/lookup3.h \
$(srcdir)/util/orig-headers/lookup3.h
platform.lo platform.o: $(srcdir)/platform.c $(srcdir)/platform.h \
config.h
pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c \
config.h \
$(srcdir)/debug.h \
@ -434,7 +437,7 @@ server.lo server.o: $(srcdir)/server.c \
$(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/util-internal.h $(srcdir)/platform.h
stub.lo stub.o: $(srcdir)/stub.c \
config.h \
$(srcdir)/debug.h $(srcdir)/stub.h \
@ -447,7 +450,7 @@ stub.lo stub.o: $(srcdir)/stub.c \
$(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h \
$(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/anchor.h \
$(srcdir)/util-internal.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
$(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h
sync.lo sync.o: $(srcdir)/sync.c \
getdns/getdns.h \
config.h \
@ -574,16 +577,22 @@ libuv.lo libuv.o: $(srcdir)/extension/libuv.c \
$(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/getdns/getdns_ext_libuv.h
poll_eventloop.lo poll_eventloop.o: $(srcdir)/extension/poll_eventloop.c \
config.h \
$(srcdir)/extension/poll_eventloop.h \
$(srcdir)/util-internal.h $(srcdir)/context.h \
getdns/getdns.h \
getdns/getdns_extra.h \
$(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/debug.h
$(srcdir)/types-internal.h $(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h \
$(srcdir)/extension/default_eventloop.h $(srcdir)/extension/poll_eventloop.h \
$(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/debug.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \
$(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \
$(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/rr-iter.h $(srcdir)/rr-dict.h $(srcdir)/gldns/gbuffer.h \
$(srcdir)/gldns/pkthdr.h $(srcdir)/anchor.h $(srcdir)/platform.h
select_eventloop.lo select_eventloop.o: $(srcdir)/extension/select_eventloop.c \
config.h \
$(srcdir)/debug.h $(srcdir)/types-internal.h \
getdns/getdns.h \
getdns/getdns_extra.h \
$(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/extension/select_eventloop.h
$(srcdir)/util/rbtree.h $(srcdir)/util/orig-headers/rbtree.h $(srcdir)/platform.h \
$(srcdir)/extension/select_eventloop.h
stubby.lo stubby.o: $(stubbysrcdir)/src/stubby.c \
config.h \
getdns/getdns.h \

View File

@ -50,6 +50,7 @@
#include "gldns/keyraw.h"
#include "general.h"
#include "util-internal.h"
#include "platform.h"
/* get key usage out of its extension, returns 0 if no key_usage extension */
static unsigned long
@ -1198,10 +1199,10 @@ static void tas_read_cb(void *userarg)
return;
}
}
} else if (_getdns_EWOULDBLOCK)
} else if (_getdns_socketerror_wants_retry())
return;
DEBUG_ANCHOR("Read error: %d %s\n", (int)n, strerror(errno));
DEBUG_ANCHOR("Read error: %d %s\n", (int)n, _getdns_errnostr());
GETDNS_CLEAR_EVENT(a->loop, &a->event);
tas_next(context, a);
}
@ -1248,10 +1249,10 @@ static void tas_write_cb(void *userarg)
tas_read_cb, NULL, tas_timeout_cb));
return;
} else if (_getdns_EWOULDBLOCK || _getdns_EINPROGRESS)
} else if (_getdns_socketerror_wants_retry())
return;
DEBUG_ANCHOR("Write error: %s\n", strerror(errno));
DEBUG_ANCHOR("Write error: %s\n", _getdns_errnostr());
GETDNS_CLEAR_EVENT(a->loop, &a->event);
tas_next(context, a);
}
@ -1315,7 +1316,8 @@ static void tas_connect(getdns_context *context, tas_connection *a)
if ((a->fd = socket(( a->req->request_type == GETDNS_RRTYPE_A
? AF_INET : AF_INET6), SOCK_STREAM, IPPROTO_TCP)) == -1) {
DEBUG_ANCHOR("Error creating socket: %s\n", strerror(errno));
DEBUG_ANCHOR("Error creating socket: %s\n",
_getdns_errnostr());
tas_next(context, a);
return;
}
@ -1348,8 +1350,8 @@ static void tas_connect(getdns_context *context, tas_connection *a)
addr.sin6_scope_id = 0;
r = connect(a->fd, (struct sockaddr *)&addr, sizeof(addr));
}
if (r == 0 || (r == -1 && (_getdns_EINPROGRESS ||
_getdns_EWOULDBLOCK))) {
if (r == 0 || (r == -1 && (_getdns_socketerror() == _getdns_EINPROGRESS ||
_getdns_socketerror() == _getdns_EWOULDBLOCK))) {
char tas_hostname[256];
const char *path = "", *fmt;
getdns_return_t R;
@ -1425,7 +1427,7 @@ static void tas_connect(getdns_context *context, tas_connection *a)
DEBUG_ANCHOR("Scheduled write with event\n");
return;
} else
DEBUG_ANCHOR("Connect error: %s\n", strerror(errno));
DEBUG_ANCHOR("Connect error: %s\n", _getdns_errnostr());
error:
tas_next(context, a);

View File

@ -80,6 +80,7 @@ typedef unsigned short in_port_t;
#include "context.h"
#include "types-internal.h"
#include "util-internal.h"
#include "platform.h"
#include "dnssec.h"
#include "stub.h"
#include "list.h"
@ -704,11 +705,7 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
}
if (upstream->fd != -1)
{
#ifdef USE_WINSOCK
closesocket(upstream->fd);
#else
close(upstream->fd);
#endif
_getdns_closesocket(upstream->fd);
}
while (pin) {
sha256_pin_t *nextpin = pin->next;
@ -736,7 +733,7 @@ void _getdns_upstream_log(getdns_upstream *upstream, uint64_t system,
va_end(args);
}
void
static void
upstream_backoff(getdns_upstream *upstream) {
upstream->conn_state = GETDNS_CONN_BACKOFF;
/* Increase the backoff interval incrementally up to the tls_backoff_time*/
@ -757,12 +754,13 @@ upstream_backoff(getdns_upstream *upstream) {
upstream->conn_shutdowns = 0;
upstream->conn_backoffs++;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : !Backing off this upstream - Will retry again at %s",
"%-40s : !Backing off this upstream - Will retry again in %ds at %s",
upstream->addr_str,
upstream->conn_backoff_interval,
asctime(gmtime(&upstream->conn_retry_time)));
}
void
static void
_getdns_upstream_reset(getdns_upstream *upstream)
{
/* Back off connections that never got up service at all (probably no
@ -803,17 +801,17 @@ _getdns_upstream_reset(getdns_upstream *upstream)
/* Now TLS stuff*/
upstream->tls_auth_state = GETDNS_AUTH_NONE;
if (upstream->event.ev && upstream->loop) {
upstream->loop->vmt->clear(
upstream->loop, &upstream->event);
}
if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj);
SSL_free(upstream->tls_obj);
upstream->tls_obj = NULL;
}
if (upstream->fd != -1) {
#ifdef USE_WINSOCK
closesocket(upstream->fd);
#else
close(upstream->fd);
#endif
_getdns_closesocket(upstream->fd);
upstream->fd = -1;
}
/* Set connection ready for use again*/
@ -2776,11 +2774,14 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
struct addrinfo hints;
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(upstream_list, GETDNS_RETURN_INVALID_PARAMETER);
r = getdns_list_get_length(upstream_list, &count);
if (count == 0 || r != GETDNS_RETURN_GOOD) {
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
if ( !upstream_list
|| (r = getdns_list_get_length(upstream_list, &count))
|| count == 0) {
_getdns_upstreams_dereference(context->upstreams);
context->upstreams = NULL;
dispatch_updated(context,
GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
@ -3902,7 +3903,7 @@ getdns_context_get_api_information(getdns_context* context)
result, "compilation_comment", GETDNS_COMPILATION_COMMENT)
&& ! getdns_dict_util_set_string(
result, "trust_anchor_file", TRUST_ANCHOR_FILE)
result, "default_trust_anchor_location", TRUST_ANCHOR_FILE)
&& ! getdns_dict_set_int(
result, "resolution_type", context->resolution_type)
@ -4622,6 +4623,7 @@ _getdns_context_config_setting(getdns_context *context,
&& !_streq(setting, "api_version_string")
&& !_streq(setting, "api_version_number")
&& !_streq(setting, "trust_anchor_file")
&& !_streq(setting, "default_trust_anchor_location")
&& !_streq(setting, "compilation_comment")
) {
r = GETDNS_RETURN_NOT_IMPLEMENTED;

View File

@ -557,6 +557,4 @@ int _getdns_context_write_priv_file(getdns_context *context,
int _getdns_context_can_write_appdata(getdns_context *context);
void _getdns_upstream_reset(getdns_upstream *upstream);
#endif /* _GETDNS_CONTEXT_H_ */

View File

@ -32,10 +32,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include "config.h"
#ifndef USE_WINSOCK
#include <arpa/inet.h>
#endif

View File

@ -59,6 +59,20 @@
fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#define DEBUG_NL(...) 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; \
@ -71,9 +85,8 @@
fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
fprintf(stderr, __VA_ARGS__); \
} while (0)
#endif
#define DEBUG_NL(...) do { \
#define DEBUG_NL(...) do { \
struct timeval tv_dEbUgSyM; \
struct tm tm_dEbUgSyM; \
char buf_dEbUgSyM[10]; \
@ -85,7 +98,7 @@
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} while (0)
#endif
#define DEBUG_OFF(...) do {} while (0)

View File

@ -34,8 +34,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ctype.h>
#include "config.h"
#include <ctype.h>
#ifndef USE_WINSOCK
#include <sys/types.h>
#include <sys/socket.h>

View File

@ -802,11 +802,14 @@ static void add_pkt2val_chain(struct mem_funcs *mf,
if (is_synthesized_cname(rrset))
continue;
if (!(rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset))
&& _getdns_rr_iter_section(&i->rr_i) != SECTION_ANSWER)
continue; /* No sigs in authority section is okayish */
if (!(head = add_rrset2val_chain(mf, chain_p, rrset, netreq)))
continue;
for ( rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset), n_rrsigs = 0
; rrsig
for ( n_rrsigs = 0; rrsig
; rrsig = _getdns_rrsig_iter_next(rrsig), n_rrsigs++) {
/* Signature, so lookup DS/DNSKEY at signer's name */
@ -934,6 +937,17 @@ static void val_chain_sched_soa(chain_head *head, const uint8_t *dname)
val_chain_sched_soa_node(node);
}
static chain_head *_dnskey_query(const chain_node *node)
{
chain_head *head;
for (head = node->chains; head; head = head->next)
if (head->rrset.rr_type == GETDNS_RRTYPE_DNSKEY &&
head->parent == node)
return head;
return NULL;
}
static void val_chain_node_cb(getdns_dns_req *dnsreq);
static void val_chain_sched_node(chain_node *node)
{
@ -951,13 +965,27 @@ static void val_chain_sched_node(chain_node *node)
DEBUG_SEC("schedule DS & DNSKEY lookup for %s\n", name);
node->lock++;
if (! node->dnskey_req /* not scheduled */ &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DNSKEY,
CD_extension(node->chains->netreq->owner),
node, &node->dnskey_req, NULL, val_chain_node_cb))
if (! node->dnskey_req) {
chain_head *head;
node->dnskey_req = NULL;
/* Reuse the DNSKEY query if this node is scheduled in the
* context of validating a DNSKEY query, because libunbound
* does not callback from a callback for the same query.
*/
if ((head = _dnskey_query(node))) {
DEBUG_SEC("Found DNSKEY head: %p\n", (void *)head);
node->dnskey_req = head->netreq;
node->dnskey.pkt = head->netreq->response;
node->dnskey.pkt_len = head->netreq->response_len;
} else if (_getdns_general_loop(
context, loop, name, GETDNS_RRTYPE_DNSKEY,
CD_extension(node->chains->netreq->owner),
node, &node->dnskey_req, NULL, val_chain_node_cb))
node->dnskey_req = NULL;
}
if (! node->ds_req && node->parent /* not root */ &&
_getdns_general_loop(context, loop, name, GETDNS_RRTYPE_DS,
CD_extension(node->chains->netreq->owner),
@ -2523,6 +2551,11 @@ static int chain_node_get_trusted_keys(
node->dnskey_signer = keytag;
return GETDNS_DNSSEC_SECURE;
}
/* ta is the DNSKEY for this name? */
if (_dname_equal(ta->name, node->dnskey.name)) {
*keys = ta;
return GETDNS_DNSSEC_SECURE;
}
/* ta is parent's ZSK */
if ((keytag = key_proves_nonexistance(
mf, now, skew, ta, &node->ds, NULL))) {
@ -2938,6 +2971,26 @@ static void append_rrset2val_chain_list(
_getdns_list_append_this_dict(val_chain_list, rr_dict))
getdns_dict_destroy(rr_dict);
/* Append the other RRSIGs, which were not used for validation too,
* because other validators might not have the same algorithm support.
*/
for ( rrsig = _getdns_rrsig_iter_init(&rrsig_spc, rrset)
; rrsig
; rrsig = _getdns_rrsig_iter_next(rrsig)) {
if (rrsig->rr_i.nxt < rrsig->rr_i.rr_type + 28)
continue;
if (gldns_read_uint16(rrsig->rr_i.rr_type + 26)
== (signer & 0xFFFF))
continue;
orig_ttl = gldns_read_uint32(rrsig->rr_i.rr_type + 14);
if ((rr_dict = _getdns_rr_iter2rr_dict_canonical(
&val_chain_list->mf, &rrsig->rr_i, &orig_ttl)) &&
_getdns_list_append_this_dict(val_chain_list, rr_dict))
getdns_dict_destroy(rr_dict);
}
if (val_rrset != val_rrset_spc)
GETDNS_FREE(val_chain_list->mf, val_rrset);
}
@ -3341,7 +3394,7 @@ void _getdns_validation_chain_timeout(getdns_dns_req *dnsreq)
void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
{
chain_head *head = dnsreq->chain, *next;
chain_head *head = dnsreq->chain, *next, *dnskey_head;
chain_node *node;
size_t node_count;
@ -3353,7 +3406,10 @@ void _getdns_cancel_validation_chain(getdns_dns_req *dnsreq)
; node_count
; node_count--, node = node->parent ) {
if (node->dnskey_req)
if (node->dnskey_req &&
!( (dnskey_head = _dnskey_query(node))
&& dnskey_head->netreq == node->dnskey_req))
_getdns_context_cancel_request(
node->dnskey_req->owner);
@ -3537,13 +3593,17 @@ getdns_validate_dnssec2(getdns_list *records_to_validate,
fflush(stdout);
#endif
if (!records_to_validate || !support_records || !trust_anchors)
if (!records_to_validate || !trust_anchors)
return GETDNS_RETURN_INVALID_PARAMETER;
mf = &records_to_validate->mf;
/* First convert everything to wire format
*/
if (!(support = _getdns_list2wire(support_records,
if (!support_records)
(void) memset((support = support_buf), 0, GLDNS_HEADER_SIZE);
else if (!(support = _getdns_list2wire(support_records,
support_buf, &support_len, mf)))
return GETDNS_RETURN_MEMORY_ERROR;

View File

@ -27,13 +27,8 @@
#include "config.h"
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#else
#ifndef USE_WINSOCK
#include <poll.h>
#endif
#endif
#include "util-internal.h"
#include "platform.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
@ -148,7 +143,7 @@ static uint64_t get_now_plus(uint64_t amount)
uint64_t now;
if (gettimeofday(&tv, NULL)) {
perror("gettimeofday() failed");
_getdns_perror("gettimeofday() failed");
exit(EXIT_FAILURE);
}
now = tv.tv_sec * 1000000 + tv.tv_usec;
@ -411,12 +406,14 @@ poll_eventloop_run_once(getdns_eventloop *loop, int blocking)
{
Sleep(poll_timeout);
} else
if (WSAPoll(poll_loop->pfds, poll_loop->fd_events_free, poll_timeout) < 0) {
#else
if (poll(poll_loop->pfds, poll_loop->fd_events_free, poll_timeout) < 0) {
#endif
perror("poll() failed");
exit(EXIT_FAILURE);
if (_getdns_poll(poll_loop->pfds, poll_loop->fd_events_free, poll_timeout) < 0) {
if (_getdns_socketerror() == _getdns_EAGAIN ||
_getdns_socketerror() == _getdns_EINTR )
return;
DEBUG_SCHED("I/O error with poll(): %s\n", _getdns_errnostr());
return;
}
now = get_now_plus(0);

View File

@ -29,6 +29,7 @@
#include "debug.h"
#include "types-internal.h"
#include "platform.h"
#include "extension/select_eventloop.h"
static uint64_t get_now_plus(uint64_t amount)
@ -37,7 +38,7 @@ static uint64_t get_now_plus(uint64_t amount)
uint64_t now;
if (gettimeofday(&tv, NULL)) {
perror("gettimeofday() failed");
_getdns_perror("gettimeofday() failed");
exit(EXIT_FAILURE);
}
now = tv.tv_sec * 1000000 + tv.tv_usec;
@ -244,8 +245,11 @@ select_eventloop_run_once(getdns_eventloop *loop, int blocking)
#endif
if (select(max_fd + 1, &readfds, &writefds, NULL,
(timeout == TIMEOUT_FOREVER ? NULL : &tv)) < 0) {
perror("select() failed");
exit(EXIT_FAILURE);
if (_getdns_socketerror_wants_retry())
return;
DEBUG_SCHED("I/O error with select(): %s\n", _getdns_errnostr());
return;
}
#ifdef USE_WINSOCK
}

View File

@ -221,7 +221,10 @@ _getdns_check_dns_req_complete(getdns_dns_req *dns_req)
dns_req->dnssec_return_all_statuses
))
#endif
|| ( dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING
|| ( dns_req->context->resolution_type == GETDNS_RESOLUTION_RECURSING
&& (dns_req->dnssec_return_status ||
dns_req->dnssec_return_only_secure ||
dns_req->dnssec_return_all_statuses)
&& _getdns_bogus(dns_req))
)) {
/* Reschedule timeout for this DNS request
@ -446,14 +449,12 @@ _getdns_submit_netreq(getdns_network_req *netreq, uint64_t *now_ms)
if (_getdns_ub_loop_enabled(&context->ub_loop))
ub_resolve_r = ub_resolve_event(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_event_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
netreq, ub_resolve_event_callback, &(netreq->unbound_id));
else
#endif
ub_resolve_r = ub_resolve_async(context->unbound_ctx,
name, netreq->request_type, dns_req->request_class,
netreq, ub_resolve_callback, &(netreq->unbound_id)) ?
GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
netreq, ub_resolve_callback, &(netreq->unbound_id));
if (dnsreq_freed)
return DNS_REQ_FINISHED;
dns_req->freed = NULL;

View File

@ -1059,11 +1059,7 @@ int gldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
d4 = (*d)[4];
d5 = (*d)[5];
tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5;
#ifndef USE_WINSOCK
w = gldns_str_print(s, sl, "%llu", (long long)tsigtime);
#else
w = gldns_str_print(s, sl, "%I64u", (long long)tsigtime);
#endif
w = gldns_str_print(s, sl, "%"PRIu64, (uint64_t)tsigtime);
(*d)+=6;
(*dl)-=6;
return w;
@ -1746,13 +1742,8 @@ int gldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data,
if(error_code < llq_errors_num)
w += gldns_str_print(s, sl, " %s", llq_errors[error_code]);
else w += gldns_str_print(s, sl, " error %d", (int)error_code);
#ifndef USE_WINSOCK
w += gldns_str_print(s, sl, " id %llx lease-life %lu",
(unsigned long long)llq_id, (unsigned long)lease_life);
#else
w += gldns_str_print(s, sl, " id %I64x lease-life %lu",
(unsigned long long)llq_id, (unsigned long)lease_life);
#endif
w += gldns_str_print(s, sl, " id %"PRIx64" lease-life %lu",
(uint64_t)llq_id, (unsigned long)lease_life);
return w;
}

View File

@ -26,28 +26,11 @@
#include "gldns/pkthdr.h"
#include "gldns/rrdef.h"
#include "util-internal.h"
#include "platform.h"
#include "mdns.h"
#ifdef HAVE_MDNS_SUPPORT
#ifdef USE_WINSOCK
typedef u_short sa_family_t;
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
WSAGetLastError() == WSAEWOULDBLOCK)
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
#else
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
#define SOCKADDR struct sockaddr
#define SOCKADDR_IN struct sockaddr_in
#define SOCKADDR_IN6 struct sockaddr_in6
#define SOCKET int
#define IP_MREQ struct ip_mreq
#define IPV6_MREQ struct ipv6_mreq
#define BOOL int
#define TRUE 1
#endif
/* Define IPV6_ADD_MEMBERSHIP for FreeBSD and Mac OS X */
#ifndef IPV6_ADD_MEMBERSHIP
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@ -1148,7 +1131,8 @@ mdns_udp_multicast_read_cb(void *userarg)
sizeof(cnx->response), 0, NULL, NULL);
if (read == -1 && _getdns_EWOULDBLOCK)
if (read == -1 && (_getdns_socketerror() == _getdns_EWOULDBLOCK ||
_getdns_socketerror() == _getdns_ECONNRESET))
return; /* TODO: this will stop the receive loop! */
if (read >= GLDNS_HEADER_SIZE)
@ -1353,11 +1337,7 @@ static int mdns_open_ipv4_multicast(SOCKADDR_STORAGE* mcast_dest, int* mcast_des
if (ret != 0 && fd4 != -1)
{
#ifdef USE_WINSOCK
closesocket(fd4);
#else
close(fd4);
#endif
_getdns_closesocket(fd4);
fd4 = -1;
}
@ -1428,11 +1408,7 @@ static int mdns_open_ipv6_multicast(SOCKADDR_STORAGE* mcast_dest, int* mcast_des
if (ret != 0 && fd6 != -1)
{
#ifdef USE_WINSOCK
closesocket(fd6);
#else
close(fd6);
#endif
_getdns_closesocket(fd6);
fd6 = -1;
}
@ -1514,11 +1490,7 @@ static getdns_return_t mdns_delayed_network_init(struct getdns_context *context)
GETDNS_CLEAR_EVENT(context->extension
, &context->mdns_connection[i].event);
#ifdef USE_WINSOCK
closesocket(context->mdns_connection[i].fd);
#else
close(context->mdns_connection[i].fd);
#endif
_getdns_closesocket(context->mdns_connection[i].fd);
}
}
@ -1657,11 +1629,7 @@ void _getdns_mdns_context_destroy(struct getdns_context *context)
/* suppress the receive event */
GETDNS_CLEAR_EVENT(context->extension, &context->mdns_connection[i].event);
/* close the socket */
#ifdef USE_WINSOCK
closesocket(context->mdns_connection[i].fd);
#else
close(context->mdns_connection[i].fd);
#endif
_getdns_closesocket(context->mdns_connection[i].fd);
}
GETDNS_FREE(context->mf, context->mdns_connection);
@ -1686,11 +1654,7 @@ _getdns_cancel_mdns_request(getdns_network_req *netreq)
{
mdns_cleanup(netreq);
if (netreq->fd >= 0) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
}
}
@ -1706,11 +1670,7 @@ mdns_timeout_cb(void *userarg)
/* Check the required cleanup */
mdns_cleanup(netreq);
if (netreq->fd >= 0)
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
_getdns_netreq_change_state(netreq, NET_REQ_TIMED_OUT);
if (netreq->owner->user_callback) {
netreq->debug_end_time = _getdns_get_time_as_uintt64();
@ -1745,7 +1705,8 @@ mdns_udp_read_cb(void *userarg)
* i.e. overflow
*/
0, NULL, NULL);
if (read == -1 && _getdns_EWOULDBLOCK)
if (read == -1 && (_getdns_socketerror() == _getdns_EWOULDBLOCK ||
_getdns_socketerror() == _getdns_ECONNRESET))
return;
if (read < GLDNS_HEADER_SIZE)
@ -1759,11 +1720,7 @@ mdns_udp_read_cb(void *userarg)
// TODO: check that the source address originates from the local network.
// TODO: check TTL = 255
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
/*
* TODO: how to handle an MDNS response with TC bit set?
* Ignore it for now, as we do not support any kind of TCP fallback
@ -1814,11 +1771,7 @@ mdns_udp_write_cb(void *userarg)
netreq->fd, (const void *)netreq->query, pkt_len, 0,
(struct sockaddr *)&mdns_mcast_v4,
sizeof(mdns_mcast_v4))) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
return;
}
GETDNS_SCHEDULE_EVENT(

View File

@ -24,13 +24,11 @@
#ifdef HAVE_MDNS_SUPPORT
#include "getdns/getdns.h"
#include "types-internal.h"
#include "util-internal.h"
#include "platform.h"
#include "util/lruhash.h"
#include "config.h"
#ifndef USE_WINSOCK
#define SOCKADDR_STORAGE struct sockaddr_storage
#endif
getdns_return_t
_getdns_submit_mdns_request(getdns_network_req *netreq);

180
src/platform.c Normal file
View File

@ -0,0 +1,180 @@
/**
*
* \file platform.c
* @brief general functions with platform-dependent implementations
*
*/
/*
* Copyright (c) 2017, NLnet Labs, Sinodun
* 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 "platform.h"
#include <stdio.h>
#ifdef USE_WINSOCK
void _getdns_perror(const char *str)
{
char msg[256];
int errid = WSAGetLastError();
*msg = '\0';
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errid,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msg,
sizeof(msg),
NULL);
if (*msg == '\0')
sprintf(msg, "Unknown error: %d", errid);
if (str && *str != '\0')
fprintf(stderr, "%s: ", str);
fputs(msg, stderr);
}
const char *_getdns_strerror(DWORD errnum)
{
static char unknown[32];
switch(errnum) {
case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
case WSA_IO_PENDING: return "Overlapped operations will complete later.";
case WSAEINTR: return "Interrupted function call.";
case WSAEBADF: return "File handle is not valid.";
case WSAEACCES: return "Permission denied.";
case WSAEFAULT: return "Bad address.";
case WSAEINVAL: return "Invalid argument.";
case WSAEMFILE: return "Too many open files.";
case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
case WSAEINPROGRESS: return "Operation now in progress.";
case WSAEALREADY: return "Operation already in progress.";
case WSAENOTSOCK: return "Socket operation on nonsocket.";
case WSAEDESTADDRREQ: return "Destination address required.";
case WSAEMSGSIZE: return "Message too long.";
case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
case WSAENOPROTOOPT: return "Bad protocol option.";
case WSAEPROTONOSUPPORT: return "Protocol not supported.";
case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
case WSAEOPNOTSUPP: return "Operation not supported.";
case WSAEPFNOSUPPORT: return "Protocol family not supported.";
case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
case WSAEADDRINUSE: return "Address already in use.";
case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
case WSAENETDOWN: return "Network is down.";
case WSAENETUNREACH: return "Network is unreachable.";
case WSAENETRESET: return "Network dropped connection on reset.";
case WSAECONNABORTED: return "Software caused connection abort.";
case WSAECONNRESET: return "Connection reset by peer.";
case WSAENOBUFS: return "No buffer space available.";
case WSAEISCONN: return "Socket is already connected.";
case WSAENOTCONN: return "Socket is not connected.";
case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
case WSAETOOMANYREFS: return "Too many references.";
case WSAETIMEDOUT: return "Connection timed out.";
case WSAECONNREFUSED: return "Connection refused.";
case WSAELOOP: return "Cannot translate name.";
case WSAENAMETOOLONG: return "Name too long.";
case WSAEHOSTDOWN: return "Host is down.";
case WSAEHOSTUNREACH: return "No route to host.";
case WSAENOTEMPTY: return "Directory not empty.";
case WSAEPROCLIM: return "Too many processes.";
case WSAEUSERS: return "User quota exceeded.";
case WSAEDQUOT: return "Disk quota exceeded.";
case WSAESTALE: return "Stale file handle reference.";
case WSAEREMOTE: return "Item is remote.";
case WSASYSNOTREADY: return "Network subsystem is unavailable.";
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
case WSAEDISCON: return "Graceful shutdown in progress.";
case WSAENOMORE: return "No more results.";
case WSAECANCELLED: return "Call has been canceled.";
case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid.";
case WSAEINVALIDPROVIDER: return "Service provider is invalid.";
case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize.";
case WSASYSCALLFAILURE: return "System call failure.";
case WSASERVICE_NOT_FOUND: return "Service not found.";
case WSATYPE_NOT_FOUND: return "Class type not found.";
case WSA_E_NO_MORE: return "No more results.";
case WSA_E_CANCELLED: return "Call was canceled.";
case WSAEREFUSED: return "Database query was refused.";
case WSAHOST_NOT_FOUND: return "Host not found.";
case WSATRY_AGAIN: return "Nonauthoritative host not found.";
case WSANO_RECOVERY: return "This is a nonrecoverable error.";
case WSANO_DATA: return "Valid name, no data record of requested type.";
case WSA_QOS_RECEIVERS: return "QOS receivers.";
case WSA_QOS_SENDERS: return "QOS senders.";
case WSA_QOS_NO_SENDERS: return "No QOS senders.";
case WSA_QOS_NO_RECEIVERS: return "QOS no receivers.";
case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed.";
case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error.";
case WSA_QOS_POLICY_FAILURE: return "QOS policy failure.";
case WSA_QOS_BAD_STYLE: return "QOS bad style.";
case WSA_QOS_BAD_OBJECT: return "QOS bad object.";
case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error.";
case WSA_QOS_GENERIC_ERROR: return "QOS generic error.";
case WSA_QOS_ESERVICETYPE: return "QOS service type error.";
case WSA_QOS_EFLOWSPEC: return "QOS flowspec error.";
case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer.";
case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style.";
case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type.";
case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count.";
case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length.";
case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count.";
/*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/
case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object.";
case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor.";
case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec.";
case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec.";
case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object.";
case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object.";
case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type.";
default:
snprintf(unknown, sizeof(unknown),
"unknown WSA error code %d", (int)errnum);
return unknown;
}
}
#else
void _getdns_perror(const char *str)
{
perror(str);
}
const char *_getdns_strerror(int errnum)
{
return strerror(errnum);
}
#endif

151
src/platform.h Normal file
View File

@ -0,0 +1,151 @@
/**
*
* \file platform.h
* @brief general functions with platform-dependent implementations
*
*/
/*
* Copyright (c) 2017, NLnet Labs, Sinodun
* 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 PLATFORM_H
#define PLATFORM_H
#include "config.h"
#ifdef USE_WINSOCK
typedef u_short sa_family_t;
#define _getdns_EINTR (WSAEINTR)
#define _getdns_EAGAIN (WSATRY_AGAIN)
#define _getdns_EWOULDBLOCK (WSAEWOULDBLOCK)
#define _getdns_EINPROGRESS (WSAEINPROGRESS)
#define _getdns_ENOBUFS (WSAENOBUFS)
#define _getdns_EPROTO (0)
#define _getdns_EMFILE (WSAEMFILE)
#ifdef WSAENFILE
# define _getdns_ENFILE (WSAENFILE)
#else
# define _getdns_ENFILE (0)
#endif
#define _getdns_ECONNRESET (WSAECONNRESET)
#define _getdns_ECONNABORTED (0)
#define _getdns_EISCONN (WSAEISCONN)
#define _getdns_closesocket(fd) closesocket(fd)
#define _getdns_poll(fdarray, nsockets, timer) WSAPoll(fdarray, nsockets, timer)
#define _getdns_socketerror() (WSAGetLastError())
const char *_getdns_strerror(DWORD errnum);
#else /* USE_WINSOCK */
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#else
# include <poll.h>
#endif
#define _getdns_EINTR (EINTR)
#define _getdns_EAGAIN (EAGAIN)
#ifdef EWOULDBLOCK
#define _getdns_EWOULDBLOCK (EWOULDBLOCK)
#else
#define _getdns_EWOULDBLOCK (0)
#endif
#ifdef EINPROGRESS
# define _getdns_EINPROGRESS (EINPROGRESS)
#else
# define _getdns_EINPROGRESS (0)
#endif
#ifdef ENOBUFS
# define _getdns_ENOBUFS (ENOBUFS)
#else
# define _getdns_ENOBUFS (0)
#endif
#ifdef EPROTO
# define _getdns_EPROTO (EPROTO)
#else
# define _getdns_EPROTO (0)
#endif
#ifdef EMFILE
# define _getdns_EMFILE (EMFILE)
#else
# define _getdns_EMFILE (0)
#endif
#ifdef ENFILE
# define _getdns_ENFILE (ENFILE)
#else
# define _getdns_ENFILE (0)
#endif
#ifdef ECONNRESET
# define _getdns_ECONNRESET (ECONNRESET)
#else
# define _getdns_ECONNRESET (0)
#endif
#ifdef ECONNABORTED
# define _getdns_ECONNABORTED (ECONNABORTED)
#else
# define _getdns_ECONNABORTED (0)
#endif
#ifdef EISCONN
# define _getdns_EISCONN (EISCONN)
#else
# define _getdns_EISCONN (0)
#endif
#define SOCKADDR struct sockaddr
#define SOCKADDR_IN struct sockaddr_in
#define SOCKADDR_IN6 struct sockaddr_in6
#define SOCKADDR_STORAGE struct sockaddr_storage
#define SOCKET int
#define IP_MREQ struct ip_mreq
#define IPV6_MREQ struct ipv6_mreq
#define BOOL int
#define TRUE 1
#define _getdns_closesocket(fd) close(fd)
#define _getdns_poll(fdarray, nsockets, timer) poll(fdarray, nsockets, timer)
#define _getdns_socketerror() (errno)
const char *_getdns_strerror(int errnum);
#endif
void _getdns_perror(const char *str);
#define _getdns_errnostr() (_getdns_strerror(_getdns_socketerror()))
#define _getdns_error_wants_retry(X) ( (X) != 0 \
&& ( (X) == _getdns_EINTR \
|| (X) == _getdns_EAGAIN \
|| (X) == _getdns_EWOULDBLOCK \
|| (X) == _getdns_EINPROGRESS \
|| (X) == _getdns_ENOBUFS ))
#define _getdns_socketerror_wants_retry() (_getdns_error_wants_retry(_getdns_socketerror()))
#define _getdns_resource_depletion() ( _getdns_socketerror() != 0 \
&& ( _getdns_socketerror() == _getdns_ENFILE \
|| _getdns_socketerror() == _getdns_EMFILE ))
#endif

View File

@ -107,6 +107,12 @@ network_req_cleanup(getdns_network_req *net_req)
{
assert(net_req);
if (net_req->query_id_registered) {
(void) _getdns_rbtree_delete(
net_req->query_id_registered, net_req->node.key);
net_req->query_id_registered = NULL;
net_req->node.key = NULL;
}
if (net_req->response && (net_req->response < net_req->wire_data ||
net_req->response > net_req->wire_data+ net_req->wire_data_sz))
GETDNS_FREE(net_req->owner->my_mf, net_req->response);
@ -123,6 +129,12 @@ netreq_reset(getdns_network_req *net_req)
*/
net_req->unbound_id = -1;
_getdns_netreq_change_state(net_req, NET_REQ_NOT_SENT);
if (net_req->query_id_registered) {
(void) _getdns_rbtree_delete(net_req->query_id_registered,
(void *)(intptr_t)GLDNS_ID_WIRE(net_req->query));
net_req->query_id_registered = NULL;
net_req->node.key = NULL;
}
net_req->dnssec_status = GETDNS_DNSSEC_INDETERMINATE;
net_req->tsig_status = GETDNS_DNSSEC_INDETERMINATE;
net_req->response_len = 0;
@ -196,6 +208,11 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
/* Scheduling, touch only via _getdns_netreq_change_state!
*/
net_req->state = NET_REQ_NOT_SENT;
/* A registered netreq (on a statefull transport)
* Deregister on reset and cleanup.
*/
net_req->query_id_registered = NULL;
net_req->node.key = NULL;
if (max_query_sz == 0) {
net_req->query = NULL;

View File

@ -39,6 +39,8 @@
#include "types-internal.h"
#include "debug.h"
#include "util/rbtree.h"
#include "util-internal.h"
#include "platform.h"
#include "server.h"
#define DNS_REQUEST_SZ 4096
@ -135,11 +137,7 @@ static void tcp_connection_destroy(tcp_connection *conn)
loop->vmt->clear(loop, &conn->event);
if (conn->fd >= 0)
#ifdef USE_WINSOCK
(void) closesocket(conn->fd);
#else
(void) close(conn->fd);
#endif
(void) _getdns_closesocket(conn->fd);
GETDNS_FREE(*mf, conn->read_buf);
for (cur = conn->to_write; cur; cur = next) {
@ -193,6 +191,12 @@ static void tcp_write_cb(void *userarg)
(const void *)&to_write->write_buf[to_write->written],
to_write->write_buf_len - to_write->written, 0)) == -1) {
if (_getdns_socketerror_wants_retry())
return;
DEBUG_SERVER("I/O error from send(): %s\n",
_getdns_errnostr());
/* IO error, close connection */
conn->event.read_cb = conn->event.write_cb =
conn->event.timeout_cb = NULL;
@ -283,14 +287,11 @@ getdns_reply(
if (conn->l->fd >= 0 && sendto(conn->l->fd, (void *)buf, len, 0,
(struct sockaddr *)&conn->remote_in, conn->addrlen) == -1) {
/* IO error, cleanup this listener */
loop->vmt->clear(loop, &conn->l->event);
#ifdef USE_WINSOCK
closesocket(conn->l->fd);
#else
close(conn->l->fd);
#endif
conn->l->fd = -1;
/* TODO: handle _getdns_socketerror_wants_retry() */
/* IO error, never cleanup a listener because of I/O error */
DEBUG_SERVER("I/O error from sendto(): %s\n",
_getdns_errnostr());
}
/* Unlink this connection */
(void) _getdns_rbtree_delete(
@ -370,10 +371,13 @@ static void tcp_read_cb(void *userarg)
if ((bytes_read = recv(conn->fd,
(void *)conn->read_pos, conn->to_read, 0)) < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
if (_getdns_socketerror_wants_retry())
return; /* Come back to do the read later */
/* IO error, close connection */
DEBUG_SERVER("I/O error from recv(): %s\n",
_getdns_errnostr());
tcp_connection_destroy(conn);
return;
}
@ -481,14 +485,19 @@ static void tcp_accept_cb(void *userarg)
conn->super.addrlen = sizeof(conn->super.remote_in);
if ((conn->fd = accept(l->fd, (struct sockaddr *)
&conn->super.remote_in, &conn->super.addrlen)) == -1) {
/* IO error, cleanup this listener */
loop->vmt->clear(loop, &l->event);
#ifdef USE_WINSOCK
closesocket(l->fd);
#else
close(l->fd);
#endif
l->fd = -1;
if (_getdns_socketerror_wants_retry() ||
_getdns_socketerror() == _getdns_ECONNRESET)
; /* pass */
else if (_getdns_resource_depletion())
; /* TODO: Stop listening for a little while? */
else
DEBUG_SERVER("I/O error during accept: %s\n",
_getdns_errnostr());
/* Never cleanup a listener because of I/O errors! */
GETDNS_FREE(*mf, conn);
return;
}
@ -555,14 +564,17 @@ static void udp_read_cb(void *userarg)
conn->addrlen = sizeof(conn->remote_in);
if ((len = recvfrom(l->fd, (void *)buf, sizeof(buf), 0,
(struct sockaddr *)&conn->remote_in, &conn->addrlen)) == -1) {
/* IO error, cleanup this listener. */
loop->vmt->clear(loop, &l->event);
#ifdef USE_WINSOCK
closesocket(l->fd);
#else
close(l->fd);
#endif
l->fd = -1;
if ( _getdns_socketerror_wants_retry() &&
_getdns_socketerror() != _getdns_ECONNRESET) {
/*
* WINSOCK gives ECONNRESET on ICMP Port Unreachable
* being received. Ignore it.
*/
DEBUG_SERVER("I/O error from recvfrom: %s\n",
_getdns_errnostr());
}
/* Never cleanup a listener because of an I/O error! */
#if 0 && defined(SERVER_DEBUG) && SERVER_DEBUG
} else {
@ -710,11 +722,7 @@ static void remove_listeners(listen_set *set)
continue;
loop->vmt->clear(loop, &l->event);
#ifdef USE_WINSOCK
closesocket(l->fd);
#else
close(l->fd);
#endif
_getdns_closesocket(l->fd);
l->fd = -1;
if (l->transport != GETDNS_TRANSPORT_TCP)

View File

@ -38,17 +38,6 @@
*/
#define INTERCEPT_COM_DS 0
#ifdef USE_POLL_DEFAULT_EVENTLOOP
# ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
# else
#ifdef USE_WINSOCK
#define poll(fdarray, nbsockets, timer) WSAPoll(fdarray, nbsockets, timer)
#else
# include <poll.h>
#endif
# endif
#endif
#include "debug.h"
#include <openssl/err.h>
#include <openssl/conf.h>
@ -63,20 +52,22 @@
#include "rr-iter.h"
#include "context.h"
#include "util-internal.h"
#include "platform.h"
#include "general.h"
#include "pubkey-pinning.h"
/* WSA TODO:
* STUB_TCP_WOULDBLOCK added to deal with edge triggered event loops (versus
* STUB_TCP_RETRY added to deal with edge triggered event loops (versus
* level triggered). See also lines containing WSA TODO below...
*/
#define STUB_TRY_AGAIN_LATER -24 /* EMFILE, i.e. Out of OS resources */
#define STUB_NO_AUTH -8 /* Existing TLS connection is not authenticated */
#define STUB_CONN_GONE -7 /* Connection has failed, clear queue*/
#define STUB_TCP_WOULDBLOCK -6
#define STUB_TCP_RETRY -6
#define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */
#define STUB_SETUP_ERROR -4
#define STUB_TCP_AGAIN -3
#define STUB_TCP_MORE_TO_READ -3
#define STUB_TCP_MORE_TO_WRITE -3
#define STUB_TCP_ERROR -2
/* Don't currently have access to the context whilst doing handshake */
@ -93,8 +84,7 @@ static void upstream_write_cb(void *userarg);
static void upstream_idle_timeout_cb(void *userarg);
static void upstream_schedule_netreq(getdns_upstream *upstream,
getdns_network_req *netreq);
static void upstream_reschedule_events(getdns_upstream *upstream,
uint64_t idle_timeout);
static void upstream_reschedule_events(getdns_upstream *upstream);
static int upstream_working_ok(getdns_upstream *upstream);
static int upstream_auth_status_ok(getdns_upstream *upstream,
getdns_network_req *netreq);
@ -418,21 +408,18 @@ tcp_connect(getdns_upstream *upstream, getdns_transport_list_t transport)
NULL, 0, NULL, NULL) == 0) {
return fd;
}
if (errno == EINPROGRESS) {
if (_getdns_socketerror() == _getdns_EINPROGRESS ||
_getdns_socketerror() == _getdns_EWOULDBLOCK)
return fd;
}
#else
(void)transport;
#endif
if (connect(fd, (struct sockaddr *)&upstream->addr,
upstream->addr_len) == -1) {
if (_getdns_EINPROGRESS || _getdns_EWOULDBLOCK)
if (_getdns_socketerror() == _getdns_EINPROGRESS ||
_getdns_socketerror() == _getdns_EWOULDBLOCK)
return fd;
#ifdef USE_WINSOCK
closesocket(fd);
#else
close(fd);
#endif
_getdns_closesocket(fd);
return -1;
}
return fd;
@ -443,22 +430,11 @@ tcp_connected(getdns_upstream *upstream) {
int error = 0;
socklen_t len = (socklen_t)sizeof(error);
getsockopt(upstream->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
#ifdef USE_WINSOCK
if (error == WSAEINPROGRESS)
return STUB_TCP_AGAIN;
else if (error == WSAEWOULDBLOCK)
return STUB_TCP_WOULDBLOCK;
else if (error != 0)
return STUB_SETUP_ERROR;
#else
if (error == EINPROGRESS)
return STUB_TCP_AGAIN;
else if (error == EWOULDBLOCK || error == EAGAIN)
return STUB_TCP_WOULDBLOCK;
if (_getdns_error_wants_retry(error))
return STUB_TCP_RETRY;
else if (error != 0) {
return STUB_SETUP_ERROR;
}
#endif
if (upstream->transport == GETDNS_TRANSPORT_TCP &&
upstream->queries_sent == 0) {
upstream->conn_state = GETDNS_CONN_OPEN;
@ -484,42 +460,56 @@ stub_next_upstream(getdns_network_req *netreq)
dnsreq->upstreams->current_udp = 0;
}
static void
remove_from_write_queue(getdns_upstream *upstream, getdns_network_req * netreq)
{
getdns_network_req *r, *prev_r;
for ( r = upstream->write_queue, prev_r = NULL
; r
; prev_r = r, r = r->write_queue_tail) {
if (r != netreq)
continue;
if (prev_r)
prev_r->write_queue_tail = r->write_queue_tail;
else
upstream->write_queue = r->write_queue_tail;
if (r == upstream->write_queue_last) {
/* If r was the last netreq,
* its write_queue tail MUST be NULL
*/
assert(r->write_queue_tail == NULL);
upstream->write_queue_last = prev_r ? prev_r : NULL;
}
netreq->write_queue_tail = NULL;
break; /* netreq found and removed */
}
}
static void
stub_cleanup(getdns_network_req *netreq)
{
DEBUG_STUB("%s %-35s: MSG: %p\n",
STUB_DEBUG_CLEANUP, __FUNC__, (void*)netreq);
getdns_dns_req *dnsreq = netreq->owner;
getdns_network_req *r, *prev_r;
getdns_upstream *upstream;
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
/* Nothing globally scheduled? Then nothing queued */
if (!netreq->upstream || !(upstream = netreq->upstream)->event.ev)
return;
/* Delete from upstream->netreq_by_query_id (if present) */
(void) _getdns_rbtree_delete(&upstream->netreq_by_query_id,
(void *)(intptr_t)GLDNS_ID_WIRE(netreq->query));
/* Delete from upstream->write_queue (if present) */
for (prev_r = NULL, r = upstream->write_queue; r;
prev_r = r, r = r->write_queue_tail)
if (r == netreq) {
if (prev_r)
prev_r->write_queue_tail = r->write_queue_tail;
else
upstream->write_queue = r->write_queue_tail;
if (r == upstream->write_queue_last)
upstream->write_queue_last =
prev_r ? prev_r : NULL;
netreq->write_queue_tail = NULL;
break;
}
upstream_reschedule_events(upstream, upstream->keepalive_timeout);
if (netreq->query_id_registered) {
(void) _getdns_rbtree_delete(
netreq->query_id_registered, netreq->node.key);
netreq->query_id_registered = NULL;
netreq->node.key = NULL;
}
if (netreq->upstream) {
remove_from_write_queue(netreq->upstream, netreq);
if (netreq->upstream->event.ev)
upstream_reschedule_events(netreq->upstream);
}
}
static void
@ -533,17 +523,8 @@ upstream_failed(getdns_upstream *upstream, int during_setup)
when idle.*/
/* [TLS1]TODO: Work out how to re-open the connection and re-try
the queries if there is only one upstream.*/
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (during_setup) {
/* Reset timeout on setup failure to trigger fallback handling.*/
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
/* Need this check because if the setup failed because the interface is
not up we get -1 and then a seg fault. Found when using IPv6 address
but IPv6 interface not enabled.*/
if (upstream->fd != -1) {
GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd, TIMEOUT_FOREVER,
getdns_eventloop_event_init(&upstream->event, upstream,
NULL, upstream_write_cb, NULL));
}
/* Special case if failure was due to authentication issues since this
upstream could be used oppotunistically with no problem.*/
if (!(upstream->transport == GETDNS_TRANSPORT_TLS &&
@ -553,6 +534,11 @@ upstream_failed(getdns_upstream *upstream, int during_setup)
upstream->conn_shutdowns++;
/* [TLS1]TODO: Re-try these queries if possible.*/
}
upstream->conn_state = GETDNS_CONN_TEARDOWN;
while (upstream->write_queue)
upstream_write_cb(upstream);
while (upstream->netreq_by_query_id.count) {
netreq = (getdns_network_req *)
_getdns_rbtree_first(&upstream->netreq_by_query_id);
@ -560,7 +546,7 @@ upstream_failed(getdns_upstream *upstream, int during_setup)
_getdns_netreq_change_state(netreq, NET_REQ_ERRORED);
_getdns_check_dns_req_complete(netreq->owner);
}
upstream->conn_state = GETDNS_CONN_TEARDOWN;
_getdns_upstream_shutdown(upstream);
}
void
@ -570,11 +556,7 @@ _getdns_cancel_stub_request(getdns_network_req *netreq)
STUB_DEBUG_CLEANUP, __FUNC__, (void*)netreq);
stub_cleanup(netreq);
if (netreq->fd >= 0) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
netreq->fd = -1;
}
}
@ -589,11 +571,7 @@ stub_timeout_cb(void *userarg)
_getdns_netreq_change_state(netreq, NET_REQ_TIMED_OUT);
/* Handle upstream*/
if (netreq->fd >= 0) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
netreq->fd = -1;
netreq->upstream->udp_timeouts++;
if (netreq->upstream->udp_timeouts % 100 == 0)
@ -629,42 +607,12 @@ upstream_idle_timeout_cb(void *userarg)
static void
upstream_setup_timeout_cb(void *userarg)
{
int ret;
getdns_upstream *upstream = (getdns_upstream *)userarg;
#ifdef USE_POLL_DEFAULT_EVENTLOOP
struct pollfd fds;
#else
fd_set fds;
struct timeval tval;
#endif
DEBUG_STUB("%s %-35s: FD: %d\n",
STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd);
/* Clean up and trigger a write to let the fallback code to its job */
upstream_failed(upstream, 1);
/* Need to handle the case where the far end doesn't respond to a
* TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853).
* For that case the socket never becomes writable so doesn't trigger any
* callbacks. If so then clear out the queue in one go.*/
#ifdef USE_POLL_DEFAULT_EVENTLOOP
fds.fd = upstream->fd;
fds.events = POLLOUT;
ret = poll(&fds, 1, 0);
#else
FD_ZERO(&fds);
FD_SET((int)(upstream->fd), &fds);
tval.tv_sec = 0;
tval.tv_usec = 0;
ret = select(upstream->fd+1, NULL, &fds, NULL, &tval);
#endif
if (ret == 0) {
DEBUG_STUB("%s %-35s: FD: %d Cleaning up dangling queue\n",
STUB_DEBUG_CLEANUP, __FUNC__, upstream->fd);
while (upstream->write_queue)
upstream_write_cb(upstream);
}
_getdns_upstream_reset(upstream);
upstream_failed(upstream, 1);
}
@ -690,8 +638,8 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
}
read = recv(fd, (void *)tcp->read_pos, tcp->to_read, 0);
if (read < 0) {
if (_getdns_EWOULDBLOCK)
return STUB_TCP_WOULDBLOCK;
if (_getdns_socketerror_wants_retry())
return STUB_TCP_RETRY;
else
return STUB_TCP_ERROR;
} else if (read == 0) {
@ -705,7 +653,7 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
tcp->read_pos += read;
if (tcp->to_read > 0)
return STUB_TCP_AGAIN;
return STUB_TCP_MORE_TO_READ;
read = tcp->read_pos - tcp->read_buf;
if (read == 2) {
@ -730,14 +678,14 @@ stub_tcp_read(int fd, getdns_tcp_state *tcp, struct mem_funcs *mf)
}
/* Ready to start reading the packet */
tcp->read_pos = tcp->read_buf;
return STUB_TCP_AGAIN;
return STUB_TCP_MORE_TO_READ;
}
return GLDNS_ID_WIRE(tcp->read_buf);
}
/* stub_tcp_write(fd, tcp, netreq)
* will return STUB_TCP_AGAIN when we need to come back again,
* STUB_TCP_ERROR on error and a query_id on successful sent.
* will return STUB_TCP_RETRY or STUB_TCP_MORE_TO_WRITE when we need to come
* back again, STUB_TCP_ERROR on error and a query_id on successful sent.
*/
static int
stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
@ -764,6 +712,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
} while (!_getdns_rbtree_insert(
&netreq->upstream->netreq_by_query_id, &netreq->node));
netreq->query_id_registered = &netreq->upstream->netreq_by_query_id;
GLDNS_ID_SET(netreq->query, query_id);
@ -799,7 +748,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
netreq->upstream->addr_len);
/* If pipelining we will find that the connection is already up so
just fall back to a 'normal' write. */
if (written == -1 && errno == EISCONN)
if (written == -1 && _getdns_socketerror() == _getdns_EISCONN)
written = write(fd, netreq->query - 2, pkt_len + 2);
#else
written = sendto(fd, (const char *)(netreq->query - 2),
@ -807,27 +756,24 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
(struct sockaddr *)&(netreq->upstream->addr),
netreq->upstream->addr_len);
#endif
if ((written < 0 && (_getdns_EWOULDBLOCK ||
/* Add the error case where the connection is in progress which is when
a cookie is not available (e.g. when doing the first request to an
upstream). We must let the handshake complete since non-blocking. */
_getdns_EINPROGRESS)) ||
(size_t)written < pkt_len + 2) {
if ((written == -1 && _getdns_socketerror_wants_retry()) ||
(size_t)written < pkt_len + 2) {
/* We couldn't write the whole packet.
* We have to return with STUB_TCP_AGAIN.
* Setup tcp to track the state.
*/
tcp->write_buf = netreq->query - 2;
tcp->write_buf_len = pkt_len + 2;
tcp->written = written >= 0 ? written : 0;
return STUB_TCP_WOULDBLOCK;
return written == -1
? STUB_TCP_RETRY
: STUB_TCP_MORE_TO_WRITE;
} else if (written == -1) {
DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:"
" %s\n", STUB_DEBUG_WRITE, __FUNC__, (void*)netreq
, strerror(errno));
, _getdns_errnostr());
return STUB_TCP_ERROR;
}
@ -839,20 +785,15 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
/* Coming back from an earlier unfinished write or handshake.
* Try to send remaining data */
#ifdef USE_WINSOCK
written = send(fd, (void *)(tcp->write_buf + tcp->written),
tcp->write_buf_len - tcp->written, 0);
#else
written = write(fd, tcp->write_buf + tcp->written,
tcp->write_buf_len - tcp->written);
#endif
if (written == -1) {
if (_getdns_EWOULDBLOCK)
return STUB_TCP_WOULDBLOCK;
if (_getdns_socketerror_wants_retry())
return STUB_TCP_RETRY;
else {
DEBUG_STUB("%s %-35s: MSG: %p error while writing to TCP socket:"
" %s\n", STUB_DEBUG_WRITE, __FUNC__, (void*)netreq
, strerror(errno));
, _getdns_errnostr());
return STUB_TCP_ERROR;
}
@ -860,7 +801,7 @@ stub_tcp_write(int fd, getdns_tcp_state *tcp, getdns_network_req *netreq)
tcp->written += written;
if (tcp->written < tcp->write_buf_len)
/* Still more to send */
return STUB_TCP_AGAIN;
return STUB_TCP_MORE_TO_WRITE;
query_id = (int)GLDNS_ID_WIRE(tcp->write_buf + 2);
/* Done. Start reading */
@ -1005,8 +946,11 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0);
#else
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
DEBUG_STUB("%s %-35s: ERROR: TLS Authentication functionality not available\n",
DEBUG_STUB("%s %-35s: ERROR: Hostname Authentication not available from TLS library (check library version)\n",
STUB_DEBUG_SETUP_TLS, __FUNC__);
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR,
"%-40s : ERROR: Hostname Authentication not available from TLS library (check library version)\n",
upstream->addr_str);
upstream->tls_hs_state = GETDNS_HS_FAILED;
return NULL;
}
@ -1081,7 +1025,7 @@ tls_do_handshake(getdns_upstream *upstream)
GETDNS_SCHEDULE_EVENT(upstream->loop,
upstream->fd, TIMEOUT_TLS, &upstream->event);
upstream->tls_hs_state = GETDNS_HS_READ;
return STUB_TCP_AGAIN;
return STUB_TCP_RETRY;
case SSL_ERROR_WANT_WRITE:
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.read_cb = NULL;
@ -1089,7 +1033,7 @@ tls_do_handshake(getdns_upstream *upstream)
GETDNS_SCHEDULE_EVENT(upstream->loop,
upstream->fd, TIMEOUT_TLS, &upstream->event);
upstream->tls_hs_state = GETDNS_HS_WRITE;
return STUB_TCP_AGAIN;
return STUB_TCP_RETRY;
default:
DEBUG_STUB("%s %-35s: FD: %d Handshake failed %d\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd,
@ -1173,7 +1117,7 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp,
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 */
return STUB_TCP_RETRY; /* Come back later */
} else
return STUB_TCP_ERROR;
}
@ -1181,7 +1125,7 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp,
tcp->read_pos += read;
if ((int)tcp->to_read > 0)
return STUB_TCP_AGAIN;
return STUB_TCP_MORE_TO_READ;
read = tcp->read_pos - tcp->read_buf;
if (read == 2) {
@ -1213,14 +1157,14 @@ stub_tls_read(getdns_upstream *upstream, getdns_tcp_state *tcp,
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 */
return STUB_TCP_RETRY; /* 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 STUB_TCP_MORE_TO_READ;
}
return GLDNS_ID_WIRE(tcp->read_buf);
}
@ -1262,6 +1206,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
} while (!_getdns_rbtree_insert(
&netreq->upstream->netreq_by_query_id, &netreq->node));
netreq->query_id_registered = &netreq->upstream->netreq_by_query_id;
GLDNS_ID_SET(netreq->query, query_id);
@ -1336,7 +1281,7 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
switch (SSL_get_error(tls_obj, written)) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
return STUB_TCP_AGAIN;
return STUB_TCP_RETRY;
default:
return STUB_TCP_ERROR;
}
@ -1386,23 +1331,20 @@ stub_udp_read_cb(void *userarg)
* i.e. overflow
*/
0, NULL, NULL);
if (read == -1 && _getdns_EWOULDBLOCK)
if (read == -1 && (_getdns_socketerror_wants_retry() ||
_getdns_socketerror() == _getdns_ECONNRESET))
return; /* Try again later */
if (read == -1) {
DEBUG_STUB("%s %-35s: MSG: %p error while reading from socket:"
" %s\n", STUB_DEBUG_READ, __FUNC__, (void*)netreq
, strerror(errno));
, _getdns_errnostr());
stub_cleanup(netreq);
_getdns_netreq_change_state(netreq, NET_REQ_ERRORED);
/* Handle upstream*/
if (netreq->fd >= 0) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
netreq->fd = -1;
stub_next_upstream(netreq);
}
@ -1422,11 +1364,7 @@ stub_udp_read_cb(void *userarg)
GETDNS_CLEAR_EVENT(dnsreq->loop, &netreq->event);
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
netreq->fd = -1;
while (GLDNS_TC_WIRE(netreq->response)) {
DEBUG_STUB("%s %-35s: MSG: %p TC bit set in response \n", STUB_DEBUG_READ,
@ -1509,7 +1447,7 @@ stub_udp_write_cb(void *userarg)
if (written == -1)
DEBUG_STUB( "%s %-35s: MSG: %p error: %s\n"
, STUB_DEBUG_WRITE, __FUNC__, (void *)netreq
, strerror(errno));
, _getdns_errnostr());
else
DEBUG_STUB( "%s %-35s: MSG: %p returned: %d, expeced: %d\n"
, STUB_DEBUG_WRITE, __FUNC__, (void *)netreq
@ -1519,11 +1457,7 @@ stub_udp_write_cb(void *userarg)
_getdns_netreq_change_state(netreq, NET_REQ_ERRORED);
/* Handle upstream*/
if (netreq->fd >= 0) {
#ifdef USE_WINSOCK
closesocket(netreq->fd);
#else
close(netreq->fd);
#endif
_getdns_closesocket(netreq->fd);
netreq->fd = -1;
stub_next_upstream(netreq);
}
@ -1579,20 +1513,17 @@ upstream_read_cb(void *userarg)
&upstream->upstreams->mf);
switch (q) {
case STUB_TCP_AGAIN:
case STUB_TCP_MORE_TO_READ:
/* WSA TODO: if callback is still upstream_read_cb, do it again
*/
case STUB_TCP_WOULDBLOCK:
case STUB_TCP_RETRY:
return;
case STUB_SETUP_ERROR: /* Can happen for TLS HS*/
case STUB_TCP_ERROR:
upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1) );
if (!upstream->write_queue)
_getdns_upstream_shutdown(upstream);
return;
default:
/* Lookup netreq */
query_id = (uint16_t) q;
query_id_intptr = (intptr_t) query_id;
@ -1604,7 +1535,16 @@ upstream_read_cb(void *userarg)
upstream->tcp.to_read = 2;
return;
}
if (netreq->query_id_registered == &upstream->netreq_by_query_id) {
netreq->query_id_registered = NULL;
netreq->node.key = NULL;
} else if (netreq->query_id_registered) {
(void) _getdns_rbtree_delete(
netreq->query_id_registered, netreq->node.key);
netreq->query_id_registered = NULL;
netreq->node.key = NULL;
}
DEBUG_STUB("%s %-35s: MSG: %p (read)\n",
STUB_DEBUG_READ, __FUNC__, (void*)netreq);
_getdns_netreq_change_state(netreq, NET_REQ_FINISHED);
@ -1704,10 +1644,10 @@ upstream_write_cb(void *userarg)
q = stub_tcp_write(upstream->fd, &upstream->tcp, netreq);
switch (q) {
case STUB_TCP_AGAIN:
case STUB_TCP_MORE_TO_WRITE:
/* WSA TODO: if callback is still upstream_write_cb, do it again
*/
case STUB_TCP_WOULDBLOCK:
case STUB_TCP_RETRY:
return;
case STUB_OUT_OF_OPTIONS:
case STUB_TCP_ERROR:
@ -1717,10 +1657,8 @@ upstream_write_cb(void *userarg)
/* Could not complete the set up. Need to fallback.*/
DEBUG_STUB("%s %-35s: Upstream: %p ERROR = %d\n", STUB_DEBUG_WRITE,
__FUNC__, (void*)userarg, q);
(void) _getdns_rbtree_delete(&upstream->netreq_by_query_id,
(void *)(intptr_t)GLDNS_ID_WIRE(netreq->query));
upstream_failed(upstream, (q == STUB_TCP_ERROR ? 0:1));
/* Fall through */
return;
case STUB_CONN_GONE:
case STUB_NO_AUTH:
/* Cleaning up after connection or auth check failure. Need to fallback. */
@ -1734,11 +1672,12 @@ upstream_write_cb(void *userarg)
_getdns_netreq_change_state(netreq, NET_REQ_ERRORED);
_getdns_check_dns_req_complete(netreq->owner);
}
if (!upstream->write_queue)
_getdns_upstream_shutdown(upstream);
return;
default:
/* Unqueue the netreq from the write_queue */
remove_from_write_queue(upstream, netreq);
if (netreq->owner->return_call_reporting &&
netreq->upstream->tls_obj &&
netreq->debug_tls_peer_cert.data == NULL &&
@ -1751,9 +1690,9 @@ upstream_write_cb(void *userarg)
netreq->debug_tls_auth_status = netreq->upstream->tls_auth_state;
upstream->queries_sent++;
/* Unqueue the netreq from the write_queue */
if (!(upstream->write_queue = netreq->write_queue_tail)) {
upstream->write_queue_last = NULL;
/* Empty write_queue?, then deschedule upstream write_cb */
if (upstream->write_queue == NULL) {
assert(upstream->write_queue_last == NULL);
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.write_cb = NULL;
/* Reschedule (if already reading) to clear writable */
@ -1896,7 +1835,6 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
if (upstreams->upstreams[i].conn_state == GETDNS_CONN_BACKOFF &&
upstreams->upstreams[i].conn_retry_time < now) {
upstreams->upstreams[i].conn_state = GETDNS_CONN_CLOSED;
upstreams->upstreams[i].conn_backoff_interval = 1;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : Re-instating upstream\n",
upstreams->upstreams[i].addr_str);
@ -1957,8 +1895,8 @@ upstream_select_stateful(getdns_network_req *netreq, getdns_transport_list_t tra
upstream->conn_state = GETDNS_CONN_CLOSED;
upstream->conn_backoff_interval = 1;
_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
"%-40s : No valid upstreams... promoting backed-off upstream %s for re-try...\n",
upstreams->upstreams[i].addr_str);
"%-40s : No valid upstreams... promoting this backed-off upstream for re-try...\n",
upstream->addr_str);
return upstream;
}
@ -2044,7 +1982,6 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport,
fd = tcp_connect(upstream, transport);
if (fd == -1) {
upstream_failed(upstream, 1);
_getdns_upstream_reset(upstream);
return -1;
}
upstream->loop = dnsreq->loop;
@ -2054,12 +1991,7 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport,
upstream->tls_obj = tls_create_object(dnsreq, fd, upstream);
if (upstream->tls_obj == NULL) {
upstream_failed(upstream, 1);
_getdns_upstream_reset(upstream);
#ifdef USE_WINSOCK
closesocket(fd);
#else
close(fd);
#endif
_getdns_closesocket(fd);
return -1;
}
upstream->tls_hs_state = GETDNS_HS_WRITE;
@ -2128,7 +2060,7 @@ upstream_find_for_netreq(getdns_network_req *netreq)
continue;
if (fd == -1) {
if (_getdns_EMFILE)
if (_getdns_resource_depletion())
return STUB_TRY_AGAIN_LATER;
return -1;
}
@ -2170,11 +2102,17 @@ fallback_on_write(getdns_network_req *netreq)
}
static void
upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout) {
upstream_reschedule_events(getdns_upstream *upstream) {
DEBUG_STUB("%s %-35s: FD: %d \n", STUB_DEBUG_SCHEDULE,
__FUNC__, upstream->fd);
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->event.ev)
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->fd == -1 || !( upstream->conn_state == GETDNS_CONN_SETUP
|| upstream->conn_state == GETDNS_CONN_OPEN ))
return;
if (!upstream->write_queue && upstream->event.write_cb) {
upstream->event.write_cb = NULL;
}
@ -2192,18 +2130,13 @@ upstream_reschedule_events(getdns_upstream *upstream, uint64_t idle_timeout) {
upstream->fd, TIMEOUT_FOREVER, &upstream->event);
else {
DEBUG_STUB("%s %-35s: FD: %d Connection idle - timeout is %d\n",
STUB_DEBUG_SCHEDULE, __FUNC__, upstream->fd, (int)idle_timeout);
/* TODO: Schedule a read also anyway,
* to digest timed out answers.
* Dont forget to schedule with upstream->fd then!
*
* upstream->event.read_cb = upstream_read_cb;
*/
STUB_DEBUG_SCHEDULE, __FUNC__, upstream->fd,
(int)upstream->keepalive_timeout);
upstream->event.read_cb = upstream_read_cb;
upstream->event.timeout_cb = upstream_idle_timeout_cb;
if (upstream->conn_state != GETDNS_CONN_OPEN)
idle_timeout = 0;
GETDNS_SCHEDULE_EVENT(upstream->loop, -1,
idle_timeout, &upstream->event);
GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd,
upstream->keepalive_timeout, &upstream->event);
}
}

View File

@ -116,30 +116,24 @@ getdns_sync_data_cleanup(getdns_sync_data *data)
upstream = &ctxt->upstreams->upstreams[i];
if (upstream->loop != &data->context->sync_eventloop.loop)
continue;
if (upstream->event.read_cb || upstream->event.write_cb) {
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
} else if (upstream->event.timeout_cb) {
/* Timeout's at upstream are idle-timeouts only.
* They should be fired on completion of the
* synchronous request.
*/
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->conn_state != GETDNS_CONN_OPEN ||
upstream->keepalive_timeout == 0)
(*upstream->event.timeout_cb)(upstream->event.userarg);
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
if (upstream->event.timeout_cb &&
( upstream->conn_state != GETDNS_CONN_OPEN
|| upstream->keepalive_timeout == 0)) {
(*upstream->event.timeout_cb)(upstream->event.userarg);
upstream->event.timeout_cb = NULL;
}
upstream->loop = data->context->extension;
upstream->is_sync_loop = 0;
if (upstream->event.read_cb || upstream->event.write_cb)
GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd,
TIMEOUT_FOREVER, &upstream->event);
else if (upstream->event.timeout_cb &&
upstream->conn_state == GETDNS_CONN_OPEN &&
upstream->keepalive_timeout != 0) {
GETDNS_SCHEDULE_EVENT(upstream->loop, upstream->fd,
upstream->keepalive_timeout, &upstream->event);
if ( upstream->event.read_cb || upstream->event.write_cb
|| upstream->event.timeout_cb) {
GETDNS_SCHEDULE_EVENT(upstream->loop,
( upstream->event.read_cb
|| upstream->event.write_cb ? upstream->fd : -1),
( upstream->event.timeout_cb
? upstream->keepalive_timeout : TIMEOUT_FOREVER ),
&upstream->event);
}
}
}

View File

@ -217,6 +217,7 @@ void assert_address_in_answer(struct extracted_response *ex_response, int a, int
case GETDNS_RRTYPE_A:
if(a && type == GETDNS_RRTYPE_A)
address_records++;
/* fallthrough */
case GETDNS_RRTYPE_AAAA:
if(aaaa && type == GETDNS_RRTYPE_AAAA)
address_records++;

View File

@ -65,7 +65,7 @@
CONTEXT_CREATE(TRUE);
ASSERT_RC(getdns_context_set_upstream_recursive_servers(context, NULL),
GETDNS_RETURN_INVALID_PARAMETER, "Return code from getdns_context_set_upstream_recursive_servers()");
GETDNS_RETURN_GOOD, "Return code from getdns_context_set_upstream_recursive_servers()");
CONTEXT_DESTROY;

View File

@ -3,5 +3,5 @@
export SRCDIR=`dirname $0`
( cd $SRCDIR
./tpkg clean
rm -fr build build-stub-only build-event-loops build-static-analysis install scan-build-reports .tpkg.var.master *.info
rm -fr build build-stub-only build-event-loops build-static-analysis install scan-build-reports .tpkg.var.master *.info Makefile
)

View File

@ -46,6 +46,10 @@ typedef unsigned short in_port_t;
#include <wincrypt.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_GETDNS_YAML2DICT
getdns_return_t getdns_yaml2dict(const char *, getdns_dict **dict);
#endif
@ -1279,7 +1283,9 @@ void read_line_cb(void *userarg)
if (listen_count)
(void) getdns_context_set_listen_addresses(
context, NULL, NULL, NULL);
(void) getdns_context_set_idle_timeout(context, 0);
if (interactive && !query_file)
(void) getdns_context_set_upstream_recursive_servers(
context, NULL);
return;
}
if (query_file && verbosity)
@ -1678,16 +1684,22 @@ static void stubby_log(void *userarg, uint64_t system,
#ifdef GETDNS_ON_WINDOWS
time_t tsec;
if (!verbosity)
return;
gettimeofday(&tv, NULL);
tsec = (time_t) tv.tv_sec;
gmtime_s(&tm, (const time_t *) &tsec);
#else
if (!verbosity)
return;
gettimeofday(&tv, NULL);
gmtime_r(&tv.tv_sec, &tm);
#endif
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) fprintf(stderr, "[%s.%.6d] UPSTREAM ", buf, (int)tv.tv_usec);
(void) vfprintf(stderr, fmt, ap);
}
@ -1741,10 +1753,10 @@ main(int argc, char **argv)
(void) parse_config_file(home_stubby_conf_fn, 0);
}
clear_listen_list_on_arg = 1;
(void) getdns_context_set_logfunc(context, NULL,
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, stubby_log);
}
(void) getdns_context_set_logfunc(context, NULL,
GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, stubby_log);
if ((r = parse_args(argc, argv)))
goto done_destroy_context;
clear_listen_list_on_arg = 0;
@ -1786,27 +1798,10 @@ main(int argc, char **argv)
}
else if (listen_count) {
assert(loop);
#ifndef GETDNS_ON_WINDOWS
if (i_am_stubby && !run_in_foreground) {
pid_t pid = fork();
if (pid == -1) {
perror("Could not fork of stubby daemon\n");
r = GETDNS_RETURN_GENERIC_ERROR;
} else if (pid) {
FILE *fh = fopen("/var/rub/stubby.pid", "w");
if (! fh)
fh = fopen("/tmp/stubby.pid", "w");
if (fh) {
fprintf(fh, "%d", (int)pid);
fclose(fh);
batch_mode = 0;
}
} else
loop->vmt->run(loop);
} else
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
loop->vmt->run(loop);
loop->vmt->run(loop);
} else
r = do_the_call();

View File

@ -188,7 +188,9 @@ typedef struct getdns_tcp_state {
typedef struct getdns_network_req
{
/* For storage in upstream->netreq_by_query_id */
_getdns_rbnode_t node;
_getdns_rbnode_t node;
/* The netreq_by_query_id tree in which this netreq was registered */
_getdns_rbtree_t *query_id_registered;
#ifdef HAVE_MDNS_SUPPORT
/*
* for storage of continuous query context in hash table of cached results.

View File

@ -218,18 +218,5 @@ INLINE uint64_t _getdns_ms_until_expiry2(uint64_t expires, uint64_t *now_ms)
return *now_ms >= expires ? 0 : expires - *now_ms;
}
#ifdef USE_WINSOCK
typedef u_short sa_family_t;
#define _getdns_EWOULDBLOCK (WSAGetLastError() == WSATRY_AGAIN ||\
WSAGetLastError() == WSAEWOULDBLOCK)
#define _getdns_EINPROGRESS (WSAGetLastError() == WSAEINPROGRESS)
#define _getdns_EMFILE (WSAGetLastError() == WSAEMFILE)
#else
#define _getdns_EWOULDBLOCK (errno == EAGAIN || errno == EWOULDBLOCK)
#define _getdns_EINPROGRESS (errno == EINPROGRESS)
#define _getdns_EMFILE (errno == EMFILE)
#endif
#endif
/* util-internal.h */

2
stubby

@ -1 +1 @@
Subproject commit d541e60530717f590d4a4a9d458f987cbe90fc59
Subproject commit a43be56e28f3a802f74b7c5b19b4b4c5fbaa908a