diff options
36 files changed, 2619 insertions, 1240 deletions
diff --git a/usr.sbin/unbound/Makefile.in b/usr.sbin/unbound/Makefile.in index d2895131343..c2f32673085 100644 --- a/usr.sbin/unbound/Makefile.in +++ b/usr.sbin/unbound/Makefile.in @@ -168,7 +168,7 @@ HOST_OBJ=unbound-host.lo HOST_OBJ_LINK=$(HOST_OBJ) $(SLDNS_OBJ) $(COMPAT_OBJ_WITHOUT_CTIMEARC4) @WIN_HOST_OBJ_LINK@ UBANCHOR_SRC=smallapp/unbound-anchor.c UBANCHOR_OBJ=unbound-anchor.lo -UBANCHOR_OBJ_LINK=$(UBANCHOR_OBJ) \ +UBANCHOR_OBJ_LINK=$(UBANCHOR_OBJ) parseutil.lo \ $(COMPAT_OBJ_WITHOUT_CTIME) @WIN_UBANCHOR_OBJ_LINK@ TESTBOUND_SRC=testcode/testbound.c testcode/testpkts.c \ daemon/worker.c daemon/acl_list.c daemon/daemon.c daemon/stats.c \ @@ -1178,7 +1178,7 @@ delayer.lo delayer.o: $(srcdir)/testcode/delayer.c config.h $(srcdir)/util/net_h unbound-control.lo unbound-control.o: $(srcdir)/smallapp/unbound-control.c config.h \ $(srcdir)/util/log.h $(srcdir)/util/config_file.h $(srcdir)/util/locks.h $(srcdir)/util/net_help.h unbound-anchor.lo unbound-anchor.o: $(srcdir)/smallapp/unbound-anchor.c config.h $(srcdir)/libunbound/unbound.h \ - $(srcdir)/sldns/rrdef.h \ + $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/parseutil.h \ petal.lo petal.o: $(srcdir)/testcode/petal.c config.h \ diff --git a/usr.sbin/unbound/README b/usr.sbin/unbound/README index 04f8bf03399..594ffeef676 100644 --- a/usr.sbin/unbound/README +++ b/usr.sbin/unbound/README @@ -1,6 +1,5 @@ -Unbound README +README for Unbound 1.5.6 * ./configure && make && make install -* on BSDs and Solaris use gmake (GNU make). * You can use libevent if you want. libevent is useful when using many (10000) outgoing ports. By default max 256 ports are opened at the same time and the builtin alternative is equally capable and a diff --git a/usr.sbin/unbound/acx_nlnetlabs.m4 b/usr.sbin/unbound/acx_nlnetlabs.m4 index 3a2e350823e..c9ca7558da5 100644 --- a/usr.sbin/unbound/acx_nlnetlabs.m4 +++ b/usr.sbin/unbound/acx_nlnetlabs.m4 @@ -2,7 +2,15 @@ # Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 20 +# Version 28 +# 2015-08-28 ACX_CHECK_PIE and ACX_CHECK_RELRO_NOW added. +# 2015-03-17 AHX_CONFIG_REALLOCARRAY added +# 2013-09-19 FLTO help text improved. +# 2013-07-18 Enable ACX_CHECK_COMPILER_FLAG to test for -Wstrict-prototypes +# 2013-06-25 FLTO has --disable-flto option. +# 2013-05-03 Update W32_SLEEP for newer mingw that links but not defines it. +# 2013-03-22 Fix ACX_RSRC_VERSION for long version numbers. +# 2012-02-09 Fix AHX_MEMCMP_BROKEN with undef in compat/memcmp.h. # 2012-01-20 Fix COMPILER_FLAGS_UNBOUND for gcc 4.6.2 assigned-not-used-warns. # 2011-12-05 Fix getaddrinfowithincludes on windows with fedora16 mingw32-gcc. # Fix ACX_MALLOC for redefined malloc error. @@ -87,6 +95,8 @@ # ACX_CHECK_MEMCMP_SIGNED - check if memcmp uses signed characters. # AHX_MEMCMP_BROKEN - replace memcmp func for CHECK_MEMCMP_SIGNED. # ACX_CHECK_SS_FAMILY - check for sockaddr_storage.ss_family +# ACX_CHECK_PIE - add --enable-pie option and check if works +# ACX_CHECK_RELRO_NOW - add --enable-relro-now option and check it # dnl Escape backslashes as \\, for C:\ paths, for the C preprocessor defines. @@ -100,7 +110,7 @@ dnl Calculate comma separated windows-resource numbers from package version. dnl Picks the first three(,0) or four numbers out of the name. dnl $1: variable for the result AC_DEFUN([ACX_RSRC_VERSION], -[$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*\([0-9]\)[^0-9]*$/\1,\2,\3,0/' `] +[$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9]*$/\1,\2,\3,0/' `] ]) dnl Routine to help check for compiler flags. @@ -115,7 +125,7 @@ AC_MSG_CHECKING(whether $CC supports -$1) cache=`echo $1 | sed 'y%.=/+-%___p_%'` AC_CACHE_VAL(cv_prog_cc_flag_$cache, [ -echo 'void f(){}' >conftest.c +echo 'void f(void){}' >conftest.c if test -z "`$CC $CPPFLAGS $CFLAGS -$1 -c conftest.c 2>&1`"; then eval "cv_prog_cc_flag_$cache=yes" else @@ -404,19 +414,22 @@ int test() { dnl Check if CC supports -flto. dnl in a way that supports clang and suncc (that flag does something else, dnl but fails to link). It sets it in CFLAGS if it works. -AC_DEFUN([ACX_CHECK_FLTO], -[AC_MSG_CHECKING([if $CC supports -flto]) -BAKCFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -flto" -AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ - if $CC $CFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then - CFLAGS="$BAKCFLAGS" - AC_MSG_RESULT(no) - else - AC_MSG_RESULT(yes) - fi - rm -f conftest conftest.c conftest.o -], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) +AC_DEFUN([ACX_CHECK_FLTO], [ + AC_ARG_ENABLE([flto], AS_HELP_STRING([--disable-flto], [Disable link-time optimization (gcc specific option)])) + AS_IF([test "x$enable_flto" != "xno"], [ + AC_MSG_CHECKING([if $CC supports -flto]) + BAKCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -flto" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + CFLAGS="$BAKCFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) + ]) ]) dnl Check the printf-format attribute (if any) @@ -1204,10 +1217,20 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result); #endif ]) +dnl provide reallocarray compat prototype. +dnl $1: unique name for compat code +AC_DEFUN([AHX_CONFIG_REALLOCARRAY], +[ +#ifndef HAVE_REALLOCARRAY +#define reallocarray reallocarray$1 +void* reallocarray(void *ptr, size_t nmemb, size_t size); +#endif +]) + dnl provide w32 compat definition for sleep AC_DEFUN([AHX_CONFIG_W32_SLEEP], [ -#ifndef HAVE_SLEEP +#if !defined(HAVE_SLEEP) || defined(HAVE_WINDOWS_H) #define sleep(x) Sleep((x)*1000) /* on win32 */ #endif /* HAVE_SLEEP */ ]) @@ -1326,9 +1349,7 @@ int main(void) dnl define memcmp to its replacement, pass unique id for program as arg AC_DEFUN([AHX_MEMCMP_BROKEN], [ #ifdef MEMCMP_IS_BROKEN -# ifdef memcmp -# undef memcmp -# endif +#include "compat/memcmp.h" #define memcmp memcmp_$1 int memcmp(const void *x, const void *y, size_t n); #endif @@ -1368,4 +1389,46 @@ AC_DEFUN([ACX_CHECK_SS_FAMILY], #endif ]) ]) +dnl Check if CC and linker support -fPIE and -pie. +dnl If so, sets them in CFLAGS / LDFLAGS. +AC_DEFUN([ACX_CHECK_PIE], [ + AC_ARG_ENABLE([pie], AS_HELP_STRING([--enable-pie], [Enable Position-Independent Executable (eg. to fully benefit from ASLR, small performance penalty)])) + AS_IF([test "x$enable_pie" = "xyes"], [ + AC_MSG_CHECKING([if $CC supports PIE]) + BAKLDFLAGS="$LDFLAGS" + BAKCFLAGS="$CFLAGS" + LDFLAGS="$LDFLAGS -pie" + CFLAGS="$CFLAGS -fPIE" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; AC_MSG_RESULT(no)]) + ]) +]) + +dnl Check if linker supports -Wl,-z,relro,-z,now. +dnl If so, adds it to LDFLAGS. +AC_DEFUN([ACX_CHECK_RELRO_NOW], [ + AC_ARG_ENABLE([relro_now], AS_HELP_STRING([--enable-relro-now], [Enable full relocation binding at load-time (RELRO NOW, to protect GOT and .dtor areas)])) + AS_IF([test "x$enable_relro_now" = "xyes"], [ + AC_MSG_CHECKING([if $CC supports -Wl,-z,relro,-z,now]) + BAKLDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" + AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [ + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + rm -f conftest conftest.c conftest.o + ], [LDFLAGS="$BAKLDFLAGS" ; AC_MSG_RESULT(no)]) + ]) +]) + dnl End of file diff --git a/usr.sbin/unbound/config.h.in b/usr.sbin/unbound/config.h.in index 63538a69215..7576e15090c 100644 --- a/usr.sbin/unbound/config.h.in +++ b/usr.sbin/unbound/config.h.in @@ -3,18 +3,12 @@ /* Directory to chroot to */ #undef CHROOT_DIR +/* Do sha512 definitions in config.h */ +#undef COMPAT_SHA512 + /* Pathname to the Unbound configuration file */ #undef CONFIGFILE -/* configure flags */ -#undef CONFIGURE_BUILD_WITH - -/* configure date */ -#undef CONFIGURE_DATE - -/* configure target system */ -#undef CONFIGURE_TARGET - /* Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work */ #undef DARWIN_BROKEN_SETREUID @@ -22,6 +16,9 @@ /* Whether daemon is deprecated */ #undef DEPRECATED_DAEMON +/* default dnstap socket path */ +#undef DNSTAP_SOCKET_PATH + /* Define if you want to use debug lock checking (slow). */ #undef ENABLE_LOCK_CHECKS @@ -30,6 +27,12 @@ internal symbols */ #undef EXPORT_ALL_SYMBOLS +/* Define to 1 if you have the `arc4random' function. */ +#undef HAVE_ARC4RANDOM + +/* Define to 1 if you have the `arc4random_uniform' function. */ +#undef HAVE_ARC4RANDOM_UNIFORM + /* Define to 1 if you have the <arpa/inet.h> header file. */ #undef HAVE_ARPA_INET_H @@ -39,7 +42,7 @@ /* Whether the C compiler accepts the "unused" attribute */ #undef HAVE_ATTR_UNUSED -/* Define to 1 if your system has a working `chown' function. */ +/* Define to 1 if you have the `chown' function. */ #undef HAVE_CHOWN /* Define to 1 if you have the `chroot' function. */ @@ -51,6 +54,26 @@ /* Define to 1 if you have the `daemon' function. */ #undef HAVE_DAEMON +/* Define to 1 if you have the declaration of `arc4random', and to 0 if you + don't. */ +#undef HAVE_DECL_ARC4RANDOM + +/* Define to 1 if you have the declaration of `arc4random_uniform', and to 0 + if you don't. */ +#undef HAVE_DECL_ARC4RANDOM_UNIFORM + +/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you + don't. */ +#undef HAVE_DECL_NID_SECP384R1 + +/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0 + if you don't. */ +#undef HAVE_DECL_NID_X9_62_PRIME256V1 + +/* Define to 1 if you have the declaration of `reallocarray', and to 0 if you + don't. */ +#undef HAVE_DECL_REALLOCARRAY + /* Define to 1 if you have the declaration of `sk_SSL_COMP_pop_free', and to 0 if you don't. */ #undef HAVE_DECL_SK_SSL_COMP_POP_FREE @@ -59,9 +82,30 @@ `SSL_COMP_get_compression_methods', and to 0 if you don't. */ #undef HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS +/* Define to 1 if you have the declaration of `SSL_CTX_set_ecdh_auto', and to + 0 if you don't. */ +#undef HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + +/* Define to 1 if you have the declaration of `strlcat', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCAT + +/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you + don't. */ +#undef HAVE_DECL_STRLCPY + /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H +/* Define to 1 if you have the <endian.h> header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the `endprotoent' function. */ +#undef HAVE_ENDPROTOENT + +/* Define to 1 if you have the `endservent' function. */ +#undef HAVE_ENDSERVENT + /* Define to 1 if you have the `event_base_free' function. */ #undef HAVE_EVENT_BASE_FREE @@ -98,6 +142,9 @@ /* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL +/* Define to 1 if you have the `FIPS_mode' function. */ +#undef HAVE_FIPS_MODE + /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK @@ -107,6 +154,12 @@ /* Whether getaddrinfo is available */ #undef HAVE_GETADDRINFO +/* Define to 1 if you have the `getauxval' function. */ +#undef HAVE_GETAUXVAL + +/* Define to 1 if you have the `getentropy' function. */ +#undef HAVE_GETENTROPY + /* Define to 1 if you have the <getopt.h> header file. */ #undef HAVE_GETOPT_H @@ -155,14 +208,8 @@ /* Define to 1 if you have the `kill' function. */ #undef HAVE_KILL -/* Define to 1 if you have the `ldns_key_EVP_unload_gost' function. */ -#undef HAVE_LDNS_KEY_EVP_UNLOAD_GOST - -/* Define to 1 if you have the <ldns/ldns.h> header file. */ -#undef HAVE_LDNS_LDNS_H - -/* Define to 1 if you have the `ldns' library (-lldns). */ -#undef HAVE_LIBLDNS +/* Define if we have LibreSSL */ +#undef HAVE_LIBRESSL /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R @@ -185,6 +232,9 @@ /* Define to 1 if you have the <netinet/in.h> header file. */ #undef HAVE_NETINET_IN_H +/* Use libnss for crypto */ +#undef HAVE_NSS + /* Define to 1 if you have the `OPENSSL_config' function. */ #undef HAVE_OPENSSL_CONFIG @@ -206,6 +256,9 @@ /* Define if you have POSIX threads libraries and header files. */ #undef HAVE_PTHREAD +/* Have PTHREAD_PRIO_INHERIT. */ +#undef HAVE_PTHREAD_PRIO_INHERIT + /* Define to 1 if the system has the type `pthread_rwlock_t'. */ #undef HAVE_PTHREAD_RWLOCK_T @@ -221,6 +274,9 @@ /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM +/* Define to 1 if you have the `reallocarray' function. */ +#undef HAVE_REALLOCARRAY + /* Define to 1 if you have the `recvmsg' function. */ #undef HAVE_RECVMSG @@ -251,6 +307,9 @@ /* Define to 1 if you have the `setusercontext' function. */ #undef HAVE_SETUSERCONTEXT +/* Define to 1 if you have the `SHA512_Update' function. */ +#undef HAVE_SHA512_UPDATE + /* Define to 1 if you have the `sigprocmask' function. */ #undef HAVE_SIGPROCMASK @@ -293,12 +352,21 @@ /* Define to 1 if you have the <string.h> header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strptime' function. */ #undef HAVE_STRPTIME +/* Define to 1 if `ipi_spec_dst' is a member of `struct in_pktinfo'. */ +#undef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST + +/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */ +#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN + /* Define if you have Swig libraries and header files. */ #undef HAVE_SWIG @@ -311,18 +379,27 @@ /* Define to 1 if you have the <sys/resource.h> header file. */ #undef HAVE_SYS_RESOURCE_H +/* Define to 1 if you have the <sys/sha2.h> header file. */ +#undef HAVE_SYS_SHA2_H + /* Define to 1 if you have the <sys/socket.h> header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the <sys/stat.h> header file. */ #undef HAVE_SYS_STAT_H +/* Define to 1 if you have the <sys/sysctl.h> header file. */ +#undef HAVE_SYS_SYSCTL_H + /* Define to 1 if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the <sys/uio.h> header file. */ #undef HAVE_SYS_UIO_H +/* Define to 1 if you have the <sys/un.h> header file. */ +#undef HAVE_SYS_UN_H + /* Define to 1 if you have the <sys/wait.h> header file. */ #undef HAVE_SYS_WAIT_H @@ -455,6 +532,9 @@ /* Shared data */ #undef SHARE_DIR +/* The size of `time_t', as computed by sizeof. */ +#undef SIZEOF_TIME_T + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS @@ -479,6 +559,15 @@ /* define this to enable debug checks. */ #undef UNBOUND_DEBUG +/* Define to 1 to enable dnstap support */ +#undef USE_DNSTAP + +/* Define this to enable ECDSA support. */ +#undef USE_ECDSA + +/* Define this to enable an EVP workaround for older openssl */ +#undef USE_ECDSA_EVP_WORKAROUND + /* Define this to enable GOST support. */ #undef USE_GOST @@ -526,6 +615,11 @@ `char[]'. */ #undef YYTEXT_POINTER +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS @@ -538,6 +632,9 @@ /* Define to 1 if on MINIX. */ #undef _MINIX +/* Enable for compile on Minix */ +#undef _NETBSD_SOURCE + /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE @@ -656,6 +753,12 @@ # define NDEBUG #endif +/** Use small-ldns codebase */ +#define USE_SLDNS 1 +#ifdef HAVE_SSL +# define LDNS_BUILD_CONFIG_HAVE_SSL 1 +#endif + #include <stdio.h> #include <string.h> #include <unistd.h> @@ -666,6 +769,10 @@ #include <stddef.h> #endif +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif + #ifdef HAVE_STDINT_H #include <stdint.h> #endif @@ -700,6 +807,16 @@ #include <ws2tcpip.h> #endif +#ifndef USE_WINSOCK +#define ARG_LL "%ll" +#else +#define ARG_LL "%I64" +#endif + +#ifndef AF_LOCAL +#define AF_LOCAL AF_UNIX +#endif + #ifdef HAVE_ATTR_FORMAT @@ -765,6 +882,12 @@ void *memmove(void *dest, const void *src, size_t n); #endif +#ifndef HAVE_STRLCAT +#define strlcat strlcat_unbound +size_t strlcat(char *dst, const char *src, size_t siz); +#endif + + #ifndef HAVE_STRLCPY #define strlcpy strlcpy_unbound size_t strlcpy(char *dst, const char *src, size_t siz); @@ -777,7 +900,13 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result); #endif -#ifndef HAVE_SLEEP +#ifndef HAVE_REALLOCARRAY +#define reallocarray reallocarrayunbound +void* reallocarray(void *ptr, size_t nmemb, size_t size); +#endif + + +#if !defined(HAVE_SLEEP) || defined(HAVE_WINDOWS_H) #define sleep(x) Sleep((x)*1000) /* on win32 */ #endif /* HAVE_SLEEP */ @@ -811,9 +940,7 @@ struct tm *gmtime_r(const time_t *timep, struct tm *result); #ifdef MEMCMP_IS_BROKEN -# ifdef memcmp -# undef memcmp -# endif +#include "compat/memcmp.h" #define memcmp memcmp_unbound int memcmp(const void *x, const void *y, size_t n); #endif @@ -831,6 +958,53 @@ struct tm; char *strptime(const char *s, const char *format, struct tm *tm); #endif +#ifdef HAVE_LIBRESSL +# if !HAVE_DECL_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t siz); +# endif +# if !HAVE_DECL_STRLCAT +size_t strlcat(char *dst, const char *src, size_t siz); +# endif +# if !HAVE_DECL_ARC4RANDOM && defined(HAVE_ARC4RANDOM) +uint32_t arc4random(void); +# endif +# if !HAVE_DECL_ARC4RANDOM_UNIFORM && defined(HAVE_ARC4RANDOM_UNIFORM) +uint32_t arc4random_uniform(uint32_t upper_bound); +# endif +# if !HAVE_DECL_REALLOCARRAY +void *reallocarray(void *ptr, size_t nmemb, size_t size); +# endif +#endif /* HAVE_LIBRESSL */ +#ifndef HAVE_ARC4RANDOM +void explicit_bzero(void* buf, size_t len); +int getentropy(void* buf, size_t len); +uint32_t arc4random(void); +void arc4random_buf(void* buf, size_t n); +void _ARC4_LOCK(void); +void _ARC4_UNLOCK(void); +#endif +#ifndef HAVE_ARC4RANDOM_UNIFORM +uint32_t arc4random_uniform(uint32_t upper_bound); +#endif +#ifdef COMPAT_SHA512 +#ifndef SHA512_DIGEST_LENGTH +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; +#endif /* SHA512_DIGEST_LENGTH */ +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, void*, size_t); +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 */ + + + #if defined(HAVE_EVENT_H) && !defined(HAVE_EVENT_BASE_ONCE) && !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) && (defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)) /* using version of libevent that is not threadsafe. */ # define LIBEVENT_SIGNAL_PROBLEM 1 @@ -845,8 +1019,6 @@ char *strptime(const char *s, const char *format, struct tm *tm); # endif #endif /* CHECKED_INET6 */ -/* maximum nesting of included files */ -#define MAXINCLUDES 10 #ifndef HAVE_GETADDRINFO struct sockaddr_storage; #include "compat/fake-rfc2553.h" diff --git a/usr.sbin/unbound/configure b/usr.sbin/unbound/configure index a4c011df476..6f9d442111d 100644 --- a/usr.sbin/unbound/configure +++ b/usr.sbin/unbound/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for unbound 1.5.4. +# Generated by GNU Autoconf 2.69 for unbound 1.5.6. # # Report bugs to <unbound-bugs@nlnetlabs.nl>. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.5.4' -PACKAGE_STRING='unbound 1.5.4' +PACKAGE_VERSION='1.5.6' +PACKAGE_STRING='unbound 1.5.6' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -804,6 +804,8 @@ with_username enable_checking enable_debug enable_flto +enable_pie +enable_relro_now enable_shared enable_static with_pic @@ -1389,7 +1391,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 unbound 1.5.4 to adapt to many kinds of systems. +\`configure' configures unbound 1.5.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1454,7 +1456,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.5.4:";; + short | recursive ) echo "Configuration of unbound 1.5.6:";; esac cat <<\_ACEOF @@ -1465,6 +1467,10 @@ Optional Features: --enable-checking Enable warnings, asserts, makefile-dependencies --enable-debug same as enable-checking --disable-flto Disable link-time optimization (gcc specific option) + --enable-pie Enable Position-Independent Executable (eg. to fully + benefit from ASLR, small performance penalty) + --enable-relro-now Enable full relocation binding at load-time (RELRO + NOW, to protect GOT and .dtor areas) --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] @@ -1629,7 +1635,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.5.4 +unbound configure 1.5.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2338,7 +2344,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 unbound $as_me 1.5.4, which was +It was created by unbound $as_me 1.5.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2690,11 +2696,11 @@ UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MINOR=5 -UNBOUND_VERSION_MICRO=4 +UNBOUND_VERSION_MICRO=6 LIBUNBOUND_CURRENT=5 -LIBUNBOUND_REVISION=7 +LIBUNBOUND_REVISION=9 LIBUNBOUND_AGE=3 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -2738,6 +2744,8 @@ LIBUNBOUND_AGE=3 # 1.5.2 had 5:5:3 # 1.5.3 had 5:6:3 # 1.5.4 had 5:7:3 +# 1.5.5 had 5:8:3 +# 1.5.6 had 5:9:3 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -5879,6 +5887,96 @@ rm -f core conftest.err conftest.$ac_objext \ fi + # Check whether --enable-pie was given. +if test "${enable_pie+set}" = set; then : + enableval=$enable_pie; +fi + + if test "x$enable_pie" = "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports PIE" >&5 +$as_echo_n "checking if $CC supports PIE... " >&6; } + BAKLDFLAGS="$LDFLAGS" + BAKCFLAGS="$CFLAGS" + LDFLAGS="$LDFLAGS -pie" + CFLAGS="$CFLAGS -fPIE" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + rm -f conftest conftest.c conftest.o + +else + LDFLAGS="$BAKLDFLAGS" ; CFLAGS="$BAKCFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + + # Check whether --enable-relro_now was given. +if test "${enable_relro_now+set}" = set; then : + enableval=$enable_relro_now; +fi + + if test "x$enable_relro_now" = "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -Wl,-z,relro,-z,now" >&5 +$as_echo_n "checking if $CC supports -Wl,-z,relro,-z,now... " >&6; } + BAKLDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,-z,relro,-z,now" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + if $CC $CFLAGS $LDFLAGS -o conftest conftest.c 2>&1 | grep "warning: no debug symbols in executable" >/dev/null; then + LDFLAGS="$BAKLDFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + fi + rm -f conftest conftest.c conftest.o + +else + LDFLAGS="$BAKLDFLAGS" ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : @@ -16101,7 +16199,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu as_fn_error $? "Python version >= 2.4.0 is required" "$LINENO" 5 fi - PY_MAJOR_VERSION="`$PYTHON -c "import sys; print(sys.version_info.major)"`" + PY_MAJOR_VERSION="`$PYTHON -c \"import sys; print(sys.version_info[0])\"`" # Have Python @@ -16684,7 +16782,7 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5 $as_echo_n "checking for LibreSSL... " >&6; } -if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then +if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -16845,6 +16943,36 @@ fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SK_SSL_COMP_POP_FREE $ac_have_decl _ACEOF +ac_fn_c_check_decl "$LINENO" "SSL_CTX_set_ecdh_auto" "ac_cv_have_decl_SSL_CTX_set_ecdh_auto" " +$ac_includes_default +#ifdef HAVE_OPENSSL_ERR_H +#include <openssl/err.h> +#endif + +#ifdef HAVE_OPENSSL_RAND_H +#include <openssl/rand.h> +#endif + +#ifdef HAVE_OPENSSL_CONF_H +#include <openssl/conf.h> +#endif + +#ifdef HAVE_OPENSSL_ENGINE_H +#include <openssl/engine.h> +#endif +#include <openssl/ssl.h> +#include <openssl/evp.h> + +" +if test "x$ac_cv_have_decl_SSL_CTX_set_ecdh_auto" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SSL_CTX_SET_ECDH_AUTO $ac_have_decl +_ACEOF fi @@ -18890,7 +19018,7 @@ _ACEOF -version=1.5.4 +version=1.5.6 date=`date +'%b %e, %Y'` @@ -19405,7 +19533,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 unbound $as_me 1.5.4, which was +This file was extended by unbound $as_me 1.5.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19471,7 +19599,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="\\ -unbound config.status 1.5.4 +unbound config.status 1.5.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/unbound/configure.ac b/usr.sbin/unbound/configure.ac index 00145cf76f9..c555a2a623c 100644 --- a/usr.sbin/unbound/configure.ac +++ b/usr.sbin/unbound/configure.ac @@ -10,14 +10,14 @@ sinclude(dnstap/dnstap.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MINOR],[5]) -m4_define([VERSION_MICRO],[4]) +m4_define([VERSION_MICRO],[6]) AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl, unbound) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=5 -LIBUNBOUND_REVISION=7 +LIBUNBOUND_REVISION=9 LIBUNBOUND_AGE=3 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -61,6 +61,8 @@ LIBUNBOUND_AGE=3 # 1.5.2 had 5:5:3 # 1.5.3 had 5:6:3 # 1.5.4 had 5:7:3 +# 1.5.5 had 5:8:3 +# 1.5.6 had 5:9:3 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -246,6 +248,8 @@ case "$debug_enabled" in ;; esac ACX_CHECK_FLTO +ACX_CHECK_PIE +ACX_CHECK_RELRO_NOW AC_C_INLINE ACX_CHECK_FORMAT_ATTRIBUTE @@ -475,7 +479,7 @@ if test x_$ub_test_python != x_no; then AC_ERROR([Python version >= 2.4.0 is required]) fi - PY_MAJOR_VERSION="`$PYTHON -c "import sys; print(sys.version_info.major)"`" + [PY_MAJOR_VERSION="`$PYTHON -c \"import sys; print(sys.version_info[0])\"`"] AC_SUBST(PY_MAJOR_VERSION) # Have Python AC_DEFINE(HAVE_PYTHON,1,[Define if you have Python libraries and header files.]) @@ -566,7 +570,7 @@ if test $USE_NSS = "no"; then ACX_WITH_SSL ACX_LIB_SSL AC_MSG_CHECKING([for LibreSSL]) -if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then +if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL]) # libressl provides these compat functions, but they may also be @@ -578,7 +582,7 @@ fi AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode]) -AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free], [], [], [ +AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H #include <openssl/err.h> diff --git a/usr.sbin/unbound/daemon/daemon.c b/usr.sbin/unbound/daemon/daemon.c index 9d6ce9fe47f..e763f724edb 100644 --- a/usr.sbin/unbound/daemon/daemon.c +++ b/usr.sbin/unbound/daemon/daemon.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -55,7 +55,17 @@ #ifdef HAVE_OPENSSL_ENGINE_H #include <openssl/engine.h> #endif -#include <ldns/ldns.h> + +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#include <sys/time.h> + +#ifdef HAVE_NSS +/* nss3 */ +#include "nss.h" +#endif + #include "daemon/daemon.h" #include "daemon/worker.h" #include "daemon/remote.h" @@ -73,6 +83,8 @@ #include "util/module.h" #include "util/random.h" #include "util/tube.h" +#include "util/net_help.h" +#include "sldns/keyraw.h" #include <signal.h> /** How many quit requests happened. */ @@ -97,8 +109,9 @@ int ub_c_lex_destroy(void); static RETSIGTYPE record_sigh(int sig) { #ifdef LIBEVENT_SIGNAL_PROBLEM - verbose(VERB_OPS, "quit on signal, no cleanup and statistics, " - "because installed libevent version is not threadsafe"); + /* cannot log, verbose here because locks may be held */ + /* quit on signal, no cleanup and statistics, + because installed libevent version is not threadsafe */ exit(0); #endif switch(sig) @@ -123,7 +136,8 @@ static RETSIGTYPE record_sigh(int sig) break; #endif default: - log_err("ignoring signal %d", sig); + /* ignoring signal */ + break; } } @@ -189,20 +203,29 @@ daemon_init(void) #endif /* USE_WINSOCK */ signal_handling_record(); checklock_start(); +#ifdef HAVE_SSL ERR_load_crypto_strings(); ERR_load_SSL_strings(); -#ifdef HAVE_OPENSSL_CONFIG +# ifdef HAVE_OPENSSL_CONFIG OPENSSL_config("unbound"); -#endif -#ifdef USE_GOST - (void)ldns_key_EVP_load_gost_id(); -#endif +# endif +# ifdef USE_GOST + (void)sldns_key_EVP_load_gost_id(); +# endif OpenSSL_add_all_algorithms(); -#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS +# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS /* grab the COMP method ptr because openssl leaks it */ comp_meth = (void*)SSL_COMP_get_compression_methods(); -#endif +# endif (void)SSL_library_init(); +# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) + if(!ub_openssl_lock_init()) + fatal_exit("could not init openssl locks"); +# endif +#elif defined(HAVE_NSS) + if(NSS_NoDB_Init(NULL) != SECSuccess) + fatal_exit("could not init NSS"); +#endif /* HAVE_SSL or HAVE_NSS */ #ifdef HAVE_TZSET /* init timezone info while we are not chrooted yet */ tzset(); @@ -234,9 +257,56 @@ daemon_open_shared_ports(struct daemon* daemon) { log_assert(daemon); if(daemon->cfg->port != daemon->listening_port) { - listening_ports_free(daemon->ports); - if(!(daemon->ports=listening_ports_open(daemon->cfg))) + size_t i; + struct listen_port* p0; + daemon->reuseport = 0; + /* free and close old ports */ + if(daemon->ports != NULL) { + for(i=0; i<daemon->num_ports; i++) + listening_ports_free(daemon->ports[i]); + free(daemon->ports); + daemon->ports = NULL; + } + /* see if we want to reuseport */ +#ifdef SO_REUSEPORT + if(daemon->cfg->so_reuseport && daemon->cfg->num_threads > 0) + daemon->reuseport = 1; +#endif + /* try to use reuseport */ + p0 = listening_ports_open(daemon->cfg, &daemon->reuseport); + if(!p0) { + listening_ports_free(p0); + return 0; + } + if(daemon->reuseport) { + /* reuseport was successful, allocate for it */ + daemon->num_ports = (size_t)daemon->cfg->num_threads; + } else { + /* do the normal, singleportslist thing, + * reuseport not enabled or did not work */ + daemon->num_ports = 1; + } + if(!(daemon->ports = (struct listen_port**)calloc( + daemon->num_ports, sizeof(*daemon->ports)))) { + listening_ports_free(p0); return 0; + } + daemon->ports[0] = p0; + if(daemon->reuseport) { + /* continue to use reuseport */ + for(i=1; i<daemon->num_ports; i++) { + if(!(daemon->ports[i]= + listening_ports_open(daemon->cfg, + &daemon->reuseport)) + || !daemon->reuseport ) { + for(i=0; i<daemon->num_ports; i++) + listening_ports_free(daemon->ports[i]); + free(daemon->ports); + daemon->ports = NULL; + return 0; + } + } + } daemon->listening_port = daemon->cfg->port; } if(!daemon->cfg->remote_control_enable && daemon->rc_port) { @@ -329,8 +399,25 @@ daemon_create_workers(struct daemon* daemon) verbose(VERB_ALGO, "total of %d outgoing ports available", numport); daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1); + if(daemon->reuseport && (int)daemon->num < (int)daemon->num_ports) { + log_warn("cannot reduce num-threads to %d because so-reuseport " + "so continuing with %d threads.", (int)daemon->num, + (int)daemon->num_ports); + daemon->num = (int)daemon->num_ports; + } daemon->workers = (struct worker**)calloc((size_t)daemon->num, sizeof(struct worker*)); + if(daemon->cfg->dnstap) { +#ifdef USE_DNSTAP + daemon->dtenv = dt_create(daemon->cfg->dnstap_socket_path, + (unsigned int)daemon->num); + if (!daemon->dtenv) + fatal_exit("dt_create failed"); + dt_apply_cfg(daemon->dtenv, daemon->cfg); +#else + fatal_exit("dnstap enabled in config but not built with dnstap support"); +#endif + } for(i=0; i<daemon->num; i++) { if(!(daemon->workers[i] = worker_create(daemon, i, shufport+numport*i/daemon->num, @@ -373,6 +460,7 @@ static void* thread_start(void* arg) { struct worker* worker = (struct worker*)arg; + int port_num = 0; log_thread_set(&worker->thread_num); ub_thread_blocksigs(); #ifdef THREADS_DISABLED @@ -380,7 +468,14 @@ thread_start(void* arg) tube_close_write(worker->cmd); close_other_pipes(worker->daemon, worker->thread_num); #endif - if(!worker_init(worker, worker->daemon->cfg, worker->daemon->ports, 0)) +#ifdef SO_REUSEPORT + if(worker->daemon->cfg->so_reuseport) + port_num = worker->thread_num % worker->daemon->num_ports; + else + port_num = 0; +#endif + if(!worker_init(worker, worker->daemon->cfg, + worker->daemon->ports[port_num], 0)) fatal_exit("Could not initialize thread"); worker_work(worker); @@ -453,7 +548,7 @@ daemon_fork(struct daemon* daemon) #if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) /* in libev the first inited base gets signals */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, 1)) + if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) fatal_exit("Could not initialize main thread"); #endif @@ -467,7 +562,7 @@ daemon_fork(struct daemon* daemon) */ #if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) /* libevent has the last inited base get signals (or any base) */ - if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports, 1)) + if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) fatal_exit("Could not initialize main thread"); #endif signal_handling_playback(daemon->workers[0]); @@ -507,17 +602,23 @@ daemon_cleanup(struct daemon* daemon) free(daemon->workers); daemon->workers = NULL; daemon->num = 0; +#ifdef USE_DNSTAP + dt_delete(daemon->dtenv); +#endif daemon->cfg = NULL; } void daemon_delete(struct daemon* daemon) { + size_t i; if(!daemon) return; modstack_desetup(&daemon->mods, daemon->env); daemon_remote_delete(daemon->rc); - listening_ports_free(daemon->ports); + for(i = 0; i < daemon->num_ports; i++) + listening_ports_free(daemon->ports[i]); + free(daemon->ports); listening_ports_free(daemon->rc_ports); if(daemon->env) { slabhash_delete(daemon->env->msg_cache); @@ -530,31 +631,40 @@ daemon_delete(struct daemon* daemon) free(daemon->chroot); free(daemon->pidfile); free(daemon->env); +#ifdef HAVE_SSL SSL_CTX_free((SSL_CTX*)daemon->listen_sslctx); SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx); +#endif free(daemon); #ifdef LEX_HAS_YYLEX_DESTROY /* lex cleanup */ ub_c_lex_destroy(); #endif /* libcrypto cleanup */ -#if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST) - ldns_key_EVP_unload_gost(); -#endif -#if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE -#ifndef S_SPLINT_S +#ifdef HAVE_SSL +# if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST) + sldns_key_EVP_unload_gost(); +# endif +# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE +# ifndef S_SPLINT_S sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free); -#endif -#endif -#ifdef HAVE_OPENSSL_CONFIG +# endif +# endif +# ifdef HAVE_OPENSSL_CONFIG EVP_cleanup(); ENGINE_cleanup(); CONF_modules_free(); -#endif +# endif CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */ ERR_remove_state(0); ERR_free_strings(); RAND_cleanup(); +# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) + ub_openssl_lock_delete(); +# endif +#elif defined(HAVE_NSS) + NSS_Shutdown(); +#endif /* HAVE_SSL or HAVE_NSS */ checklock_stop(); #ifdef USE_WINSOCK if(WSACleanup() != 0) { diff --git a/usr.sbin/unbound/daemon/remote.c b/usr.sbin/unbound/daemon/remote.c index 198909ded3e..d533e0867ff 100644 --- a/usr.sbin/unbound/daemon/remote.c +++ b/usr.sbin/unbound/daemon/remote.c @@ -245,9 +245,9 @@ daemon_remote_create(struct config_file* cfg) goto setup_error; } verbose(VERB_ALGO, "setup SSL certificates"); - if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) { + if (!SSL_CTX_use_certificate_chain_file(rc->ctx,s_cert)) { log_err("Error for server-cert-file: %s", s_cert); - log_crypto_err("Error in SSL_CTX use_certificate_file"); + log_crypto_err("Error in SSL_CTX use_certificate_chain_file"); goto setup_error; } if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { @@ -260,6 +260,23 @@ daemon_remote_create(struct config_file* cfg) log_crypto_err("Error in SSL_CTX check_private_key"); goto setup_error; } +#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + if(!SSL_CTX_set_ecdh_auto(rc->ctx,1)) { + log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); + } +#elif defined(USE_ECDSA) + if(1) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); + if (!ecdh) { + log_crypto_err("could not find p256, not enabling ECDHE"); + } else { + if (1 != SSL_CTX_set_tmp_ecdh (rc->ctx, ecdh)) { + log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); + } + EC_KEY_free (ecdh); + } + } +#endif if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { log_crypto_err("Error setting up SSL_CTX verify locations"); setup_error: @@ -1244,8 +1261,6 @@ struct del_info { size_t len; /** labels */ int labs; - /** now */ - time_t now; /** time to invalidate to */ time_t expired; /** number of rrsets removed */ @@ -1274,7 +1289,7 @@ infra_del_host(struct lruhash_entry* e, void* arg) d->timeout_AAAA = 0; d->timeout_other = 0; rtt_init(&d->rtt); - if(d->ttl >= inf->now) { + if(d->ttl > inf->expired) { d->ttl = inf->expired; inf->num_keys++; } @@ -1303,7 +1318,6 @@ do_flush_infra(SSL* ssl, struct worker* worker, char* arg) inf.name = 0; inf.len = 0; inf.labs = 0; - inf.now = *worker->env.now; inf.expired = *worker->env.now; inf.expired -= 3; /* handle 3 seconds skew between threads */ inf.num_rrsets = 0; @@ -1334,7 +1348,7 @@ zone_del_rrset(struct lruhash_entry* e, void* arg) if(dname_subdomain_c(k->rk.dname, inf->name)) { struct packed_rrset_data* d = (struct packed_rrset_data*)e->data; - if(d->ttl >= inf->now) { + if(d->ttl > inf->expired) { d->ttl = inf->expired; inf->num_rrsets++; } @@ -1350,7 +1364,7 @@ zone_del_msg(struct lruhash_entry* e, void* arg) struct msgreply_entry* k = (struct msgreply_entry*)e->key; if(dname_subdomain_c(k->key.qname, inf->name)) { struct reply_info* d = (struct reply_info*)e->data; - if(d->ttl >= inf->now) { + if(d->ttl > inf->expired) { d->ttl = inf->expired; inf->num_msgs++; } @@ -1366,7 +1380,7 @@ zone_del_kcache(struct lruhash_entry* e, void* arg) struct key_entry_key* k = (struct key_entry_key*)e->key; if(dname_subdomain_c(k->name, inf->name)) { struct key_entry_data* d = (struct key_entry_data*)e->data; - if(d->ttl >= inf->now) { + if(d->ttl > inf->expired) { d->ttl = inf->expired; inf->num_keys++; } @@ -1389,7 +1403,6 @@ do_flush_zone(SSL* ssl, struct worker* worker, char* arg) inf.name = nm; inf.len = nmlen; inf.labs = nmlabs; - inf.now = *worker->env.now; inf.expired = *worker->env.now; inf.expired -= 3; /* handle 3 seconds skew between threads */ inf.num_rrsets = 0; @@ -1459,7 +1472,6 @@ do_flush_bogus(SSL* ssl, struct worker* worker) struct del_info inf; /* what we do is to set them all expired */ inf.worker = worker; - inf.now = *worker->env.now; inf.expired = *worker->env.now; inf.expired -= 3; /* handle 3 seconds skew between threads */ inf.num_rrsets = 0; @@ -1535,7 +1547,6 @@ do_flush_negative(SSL* ssl, struct worker* worker) struct del_info inf; /* what we do is to set them all expired */ inf.worker = worker; - inf.now = *worker->env.now; inf.expired = *worker->env.now; inf.expired -= 3; /* handle 3 seconds skew between threads */ inf.num_rrsets = 0; @@ -1685,6 +1696,7 @@ parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names) } } } + dp->has_parent_side_NS = 1; return dp; } @@ -2267,11 +2279,17 @@ do_list_local_data(SSL* ssl, struct worker* worker) for(i=0; i<d->count + d->rrsig_count; i++) { if(!packed_rr_to_string(p->rrset, i, 0, s, slen)) { - if(!ssl_printf(ssl, "BADRR\n")) + if(!ssl_printf(ssl, "BADRR\n")) { + lock_rw_unlock(&z->lock); + lock_rw_unlock(&zones->lock); return; + } } - if(!ssl_printf(ssl, "%s\n", s)) + if(!ssl_printf(ssl, "%s\n", s)) { + lock_rw_unlock(&z->lock); + lock_rw_unlock(&zones->lock); return; + } } } } diff --git a/usr.sbin/unbound/dns64/dns64.c b/usr.sbin/unbound/dns64/dns64.c index 63cc8084e35..0de3f664334 100644 --- a/usr.sbin/unbound/dns64/dns64.c +++ b/usr.sbin/unbound/dns64/dns64.c @@ -618,8 +618,10 @@ dns64_synth_aaaa_data(const struct ub_packed_rrset_key* fk, dd->rr_ttl = (time_t*)&dd->rr_data[dd->count]; for(i = 0; i < fd->count; ++i) { if (fd->rr_len[i] != 6 || fd->rr_data[i][0] != 0 - || fd->rr_data[i][1] != 4) + || fd->rr_data[i][1] != 4) { + *dd_out = NULL; return; + } dd->rr_len[i] = 18; dd->rr_data[i] = (uint8_t*)&dd->rr_ttl[dd->count] + 18*i; @@ -638,6 +640,7 @@ dns64_synth_aaaa_data(const struct ub_packed_rrset_key* fk, */ if(!dk) { log_err("no key"); + *dd_out = NULL; return; } @@ -646,6 +649,7 @@ dns64_synth_aaaa_data(const struct ub_packed_rrset_key* fk, if(!dk->rk.dname) { log_err("out of memory"); + *dd_out = NULL; return; } diff --git a/usr.sbin/unbound/doc/Changelog b/usr.sbin/unbound/doc/Changelog index 525bb365e3d..afac05f7cbf 100644 --- a/usr.sbin/unbound/doc/Changelog +++ b/usr.sbin/unbound/doc/Changelog @@ -1,3 +1,114 @@ +15 October 2015: Wouter + - Fix segfault in the dns64 module in the formaterror error path. + - Fix sldns_wire2str_rdata_scan for malformed RRs. + - tag for 1.5.6rc1 release. + +14 October 2015: Wouter + - ANY responses include DNAME records if present, as per Evan Hunt's + remark in dnsop. + - Fix manpage to suggest using SIGTERM to terminate the server. + +9 October 2015: Wouter + - Default for ssl-port is port 853, the temporary port assignment + for secure domain name system traffic. + If you used to rely on the older default of port 443, you have + to put a clause in unbound.conf for that. The new value is likely + going to be the standardised port number for this traffic. + - iana portlist update. + +6 October 2015: Wouter + - 1.5.5 release. + - trunk tracks the development of 1.5.6. + +28 September 2015: Wouter + - MAX_TARGET_COUNT increased to 64, to fix up sporadic resolution + failures. + - tag for 1.5.5rc1 release. + - makedist.sh: pgp sig echo commands. + +25 September 2015: Wouter + - Fix unbound-control flush that does not succeed in removing data. + +22 September 2015: Wouter + - Fix config globbed include chroot treatment, this fixes reload of + globs (patch from Dag-Erling Smørgrav). + - iana portlist update. + - Fix #702: New IPs for for h.root-servers.net. + - Remove confusion comment from canonical_compare() function. + - Fix #705: ub_ctx_set_fwd() return value mishandled on windows. + - testbound selftest also works in non-debug mode. + - Fix minor error in unbound.conf.5.in + - Fix unbound.conf(5) access-control description for precedence + and default. + +31 August 2015: Wouter + - changed windows setup compression to be more transparent. + +28 August 2015: Wouter + - Fix #697: Get PY_MAJOR_VERSION failure at configure for python + 2.4 to 2.6. + - Feature #699: --enable-pie option to that builds PIE binary. + - Feature #700: --enable-relro-now option that enables full read-only + relocation. + +24 August 2015: Wouter + - Fix deadlock for local data add and zone add when unbound-control + list_local_data printout is interrupted. + - iana portlist update. + - Change default of harden-algo-downgrade to off. This is lenient + for algorithm rollover. + +13 August 2015: Wouter + - 5011 implementation does not insist on all algorithms, when + harden-algo-downgrade is turned off. + - Reap the child process that libunbound spawns. + +11 August 2015: Wouter + - Fix #694: configure script does not detect LibreSSL 2.2.2 + +4 August 2015: Wouter + - Document that local-zone nodefault matches exactly and transparent + can be used to release a subzone. + +3 August 2015: Wouter + - Document in the manual more text about configuring locally served + zones. + - Fix 5011 anchor update timer after reload. + - Fix mktime in unbound-anchor not using UTC. + +30 July 2015: Wouter + - please afl-gcc (llvm) for uninitialised variable warning. + - Added permit-small-holddown config to debug fast 5011 rollover. + +24 July 2015: Wouter + - Fix #690: Reload fails when so-reuseport is yes after changing + num-threads. + - iana portlist update. + +21 July 2015: Wouter + - Fix configure to detect SSL_CTX_set_ecdh_auto. + - iana portlist update. + +20 July 2015: Wouter + - Enable ECDHE for servers. Where available, use + SSL_CTX_set_ecdh_auto() for TLS-wrapped server configurations to + enable ECDHE. Otherwise, manually offer curve p256. + Client connections should automatically use ECDHE when available. + (thanks Daniel Kahn Gillmor) + +18 July 2015: Willem + - Allow certificate chain files to allow for intermediate certificates. + (thanks Daniel Kahn Gillmor) + +13 July 2015: Wouter + - makedist produces sha1 and sha256 files for created binaries too. + +9 July 2015: Wouter + - 1.5.4 release tag + - trunk has 1.5.5 in development. + - Fix #681: Setting forwarders with unbound-control forward + implicitly turns on forward-first. + 29 June 2015: Wouter - iana portlist update. - Fix alloc with log for allocation size checks. diff --git a/usr.sbin/unbound/doc/example.conf.in b/usr.sbin/unbound/doc/example.conf.in index 677598767bf..a96ccd3faf7 100644 --- a/usr.sbin/unbound/doc/example.conf.in +++ b/usr.sbin/unbound/doc/example.conf.in @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.5.4. +# See unbound.conf(5) man page, version 1.5.6. # # this is a comment. @@ -294,7 +294,7 @@ server: # Harden against algorithm downgrade when multiple algorithms are # advertised in the DS record. If no, allows the weakest algorithm # to validate the zone. - # harden-algo-downgrade: yes + # harden-algo-downgrade: no # Use 0x20-encoded random bits in the query to foil spoof attempts. # This feature is an experimental implementation of draft dns-0x20. @@ -444,6 +444,9 @@ server: # If the value 0 is given, missing anchors are not removed. # keep-missing: 31622400 # 366 days + # debug option that allows very small holddown times for key rollover + # permit-small-holddown: no + # the amount of memory to use for the key cache. # plain value in bytes or you can append k, m or G. default is "4Mb". # key-cache-size: 4m @@ -549,7 +552,7 @@ server: # default is "" (disabled). requires restart to take effect. # ssl-service-key: "path/to/privatekeyfile.key" # ssl-service-pem: "path/to/publiccertfile.pem" - # ssl-port: 443 + # ssl-port: 853 # request upstream over SSL (with plain DNS inside the SSL stream). # Default is no. Can be turned on and off with unbound-control. @@ -623,6 +626,8 @@ remote-control: # nameservers by hostname or by ipaddress. If you set stub-prime to yes, # the list is treated as priming hints (default is no). # With stub-first yes, it attempts without the stub if it fails. +# Consider adding domain-insecure: name and local-zone: name nodefault +# to the server: section if the stub is a locally served zone. # stub-zone: # name: "example.com" # stub-addr: 192.0.2.68 diff --git a/usr.sbin/unbound/doc/libunbound.3.in b/usr.sbin/unbound/doc/libunbound.3.in index 7ef77865b6e..8d1c6ce7206 100644 --- a/usr.sbin/unbound/doc/libunbound.3.in +++ b/usr.sbin/unbound/doc/libunbound.3.in @@ -1,4 +1,4 @@ -.TH "libunbound" "3" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "libunbound" "3" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" libunbound.3 -- unbound library functions manual .\" @@ -42,7 +42,7 @@ .B ub_ctx_zone_remove, .B ub_ctx_data_add, .B ub_ctx_data_remove -\- Unbound DNS validating resolver 1.5.4 functions. +\- Unbound DNS validating resolver 1.5.6 functions. .SH "SYNOPSIS" .B #include <unbound.h> .LP diff --git a/usr.sbin/unbound/doc/unbound-anchor.8.in b/usr.sbin/unbound/doc/unbound-anchor.8.in index 4632cf71d68..56edd21afc3 100644 --- a/usr.sbin/unbound/doc/unbound-anchor.8.in +++ b/usr.sbin/unbound/doc/unbound-anchor.8.in @@ -1,4 +1,4 @@ -.TH "unbound-anchor" "8" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound-anchor" "8" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound-anchor.8 -- unbound anchor maintenance utility manual .\" diff --git a/usr.sbin/unbound/doc/unbound-checkconf.8.in b/usr.sbin/unbound/doc/unbound-checkconf.8.in index e1a94cf7a81..b68da38fdb7 100644 --- a/usr.sbin/unbound/doc/unbound-checkconf.8.in +++ b/usr.sbin/unbound/doc/unbound-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "unbound-checkconf" "8" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound-checkconf" "8" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound-checkconf.8 -- unbound configuration checker manual .\" diff --git a/usr.sbin/unbound/doc/unbound-control.8.in b/usr.sbin/unbound/doc/unbound-control.8.in index 057eb0336fe..5d37478a477 100644 --- a/usr.sbin/unbound/doc/unbound-control.8.in +++ b/usr.sbin/unbound/doc/unbound-control.8.in @@ -1,4 +1,4 @@ -.TH "unbound-control" "8" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound-control" "8" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound-control.8 -- unbound remote control manual .\" diff --git a/usr.sbin/unbound/doc/unbound-host.1.in b/usr.sbin/unbound/doc/unbound-host.1.in index 568dbcd407d..3acf31819cb 100644 --- a/usr.sbin/unbound/doc/unbound-host.1.in +++ b/usr.sbin/unbound/doc/unbound-host.1.in @@ -1,4 +1,4 @@ -.TH "unbound\-host" "1" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound\-host" "1" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound-host.1 -- unbound DNS lookup utility .\" diff --git a/usr.sbin/unbound/doc/unbound.8.in b/usr.sbin/unbound/doc/unbound.8.in index e4ff3b8e9b1..db6f3110a40 100644 --- a/usr.sbin/unbound/doc/unbound.8.in +++ b/usr.sbin/unbound/doc/unbound.8.in @@ -1,4 +1,4 @@ -.TH "unbound" "8" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound" "8" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound.8 -- unbound manual .\" @@ -9,7 +9,7 @@ .\" .SH "NAME" .B unbound -\- Unbound DNS validating resolver 1.5.4. +\- Unbound DNS validating resolver 1.5.6. .SH "SYNOPSIS" .B unbound .RB [ \-h ] diff --git a/usr.sbin/unbound/doc/unbound.conf.5.in b/usr.sbin/unbound/doc/unbound.conf.5.in index f916e25885b..32f8b20fc12 100644 --- a/usr.sbin/unbound/doc/unbound.conf.5.in +++ b/usr.sbin/unbound/doc/unbound.conf.5.in @@ -1,4 +1,4 @@ -.TH "unbound.conf" "5" "Jul 9, 2015" "NLnet Labs" "unbound 1.5.4" +.TH "unbound.conf" "5" "Oct 20, 2015" "NLnet Labs" "unbound 1.5.6" .\" .\" unbound.conf.5 -- unbound.conf manual .\" @@ -260,7 +260,7 @@ trust (very large) TTL values. .TP .B cache\-min\-ttl: \fI<seconds> Time to live minimum for RRsets and messages in the cache. Default is 0. -If the the minimum kicks in, the data is cached for longer than the domain +If the minimum kicks in, the data is cached for longer than the domain owner intended, and thus less queries are made to look up the data. Zero makes sure the data in the cache is as the domain owner intended, higher values, especially more than an hour or so, can lead to trouble as @@ -326,7 +326,7 @@ The public key certificate pem file for the ssl service. Default is "", turned off. .TP .B ssl\-port: \fI<number> -The port number on which to provide TCP SSL service, default 443, only +The port number on which to provide TCP SSL service, default 853, only interfaces configured with that port number as @number get the SSL service. .TP .B do\-daemonize: \fI<yes or no> @@ -337,6 +337,7 @@ a daemon. Default is yes. The netblock is given as an IP4 or IP6 address with /size appended for a classless network block. The action can be \fIdeny\fR, \fIrefuse\fR, \fIallow\fR, \fIallow_snoop\fR, \fIdeny_non_local\fR or \fIrefuse_non_local\fR. +The most specific netblock match is used, if none match \fIdeny\fR is used. .IP The action \fIdeny\fR stops queries from hosts from that netblock. .IP @@ -522,7 +523,7 @@ to increase the max depth that is checked to. .B harden\-algo\-downgrade: \fI<yes or no> Harden against algorithm downgrade when multiple algorithms are advertised in the DS record. If no, allows the weakest algorithm to -validate the zone. Default is yes. Zone signers must produce zones +validate the zone. Default is no. Zone signers must produce zones that allow this feature to work, but sometimes they do not, and turning this option off avoids that validation failure. .TP @@ -756,6 +757,10 @@ mechanism work with zones that perform regular (non\-5011) rollovers. The default is 366 days. The value 0 does not remove missing anchors, as per the RFC. .TP +.B permit\-small\-holddown: \fI<yes or no> +Debug option that allows the autotrust 5011 rollover timers to assume +very small values. Default is no. +.TP .B key\-cache\-size: \fI<number> Number of bytes size of the key cache. Default is 4 megabytes. A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes @@ -850,7 +855,8 @@ infected machines without answering the queries. Used to turn off default contents for AS112 zones. The other types also turn off default contents for the zone. The 'nodefault' option has no other effect than turning off default contents for the -given zone. +given zone. Use \fInodefault\fR if you use exactly that zone, if you want to +use a subzone, use \fItransparent\fR. .P The default zones are localhost, reverse 127.0.0.1 and ::1, and the AS112 zones. The AS112 zones are reverse DNS zones for private use and reserved @@ -1079,6 +1085,12 @@ bit on replies for the private zone (authoritative servers do not set the AD bit). This setup makes unbound capable of answering queries for the private zone, and can even set the AD bit ('authentic'), but the AA ('authoritative') bit is not set on these replies. +.P +Consider adding \fBserver:\fR statements for \fBdomain\-insecure:\fR and +for \fBlocal\-zone:\fI name nodefault\fR for the zone if it is a locally +served zone. The insecure clause stops DNSSEC from invalidating the +zone. The local zone nodefault (or \fItransparent\fR) clause makes the +(reverse\-) zone bypass unbound's filtering of RFC1918 zones. .TP .B name: \fI<domain name> Name of the stub zone. diff --git a/usr.sbin/unbound/iterator/iter_hints.c b/usr.sbin/unbound/iterator/iter_hints.c index 25cae072375..d7f8158d11d 100644 --- a/usr.sbin/unbound/iterator/iter_hints.c +++ b/usr.sbin/unbound/iterator/iter_hints.c @@ -135,7 +135,7 @@ compile_time_root_prime(int do_ip4, int do_ip6) if(!ah(dp, "E.ROOT-SERVERS.NET.", "192.203.230.10")) goto failed; if(!ah(dp, "F.ROOT-SERVERS.NET.", "192.5.5.241")) goto failed; if(!ah(dp, "G.ROOT-SERVERS.NET.", "192.112.36.4")) goto failed; - if(!ah(dp, "H.ROOT-SERVERS.NET.", "128.63.2.53")) goto failed; + if(!ah(dp, "H.ROOT-SERVERS.NET.", "198.97.190.53")) goto failed; if(!ah(dp, "I.ROOT-SERVERS.NET.", "192.36.148.17")) goto failed; if(!ah(dp, "J.ROOT-SERVERS.NET.", "192.58.128.30")) goto failed; if(!ah(dp, "K.ROOT-SERVERS.NET.", "193.0.14.129")) goto failed; @@ -148,7 +148,7 @@ compile_time_root_prime(int do_ip4, int do_ip6) if(!ah(dp, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed; if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed; if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed; - if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::803f:235")) goto failed; + if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::53")) goto failed; if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed; if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed; if(!ah(dp, "K.ROOT-SERVERS.NET.", "2001:7fd::1")) goto failed; diff --git a/usr.sbin/unbound/iterator/iterator.h b/usr.sbin/unbound/iterator/iterator.h index aaf0fb3834b..9cf53b2b25a 100644 --- a/usr.sbin/unbound/iterator/iterator.h +++ b/usr.sbin/unbound/iterator/iterator.h @@ -54,7 +54,7 @@ struct iter_priv; struct rbtree_t; /** max number of targets spawned for a query and its subqueries */ -#define MAX_TARGET_COUNT 32 +#define MAX_TARGET_COUNT 64 /** max number of query restarts. Determines max number of CNAME chain. */ #define MAX_RESTART_COUNT 8 /** max number of referrals. Makes sure resolver does not run away */ diff --git a/usr.sbin/unbound/libunbound/libunbound.c b/usr.sbin/unbound/libunbound/libunbound.c index 23d489e2ead..7c2509ba8d5 100644 --- a/usr.sbin/unbound/libunbound/libunbound.c +++ b/usr.sbin/unbound/libunbound/libunbound.c @@ -65,6 +65,9 @@ #ifdef HAVE_PTHREAD #include <signal.h> #endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif #if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H) #include <windows.h> @@ -218,6 +221,12 @@ static void ub_stop_bg(struct ub_ctx* ctx) ub_thread_join(ctx->bg_tid); } else { lock_basic_unlock(&ctx->cfglock); +#ifndef UB_ON_WINDOWS + if(waitpid(ctx->bg_pid, NULL, 0) == -1) { + if(verbosity > 2) + log_err("waitpid: %s", strerror(errno)); + } +#endif } } else { diff --git a/usr.sbin/unbound/services/cache/dns.c b/usr.sbin/unbound/services/cache/dns.c index ba81afde4fd..e14e636dbfd 100644 --- a/usr.sbin/unbound/services/cache/dns.c +++ b/usr.sbin/unbound/services/cache/dns.c @@ -656,8 +656,9 @@ fill_any(struct module_env* env, time_t now = *env->now; struct dns_msg* msg = NULL; uint16_t lookup[] = {LDNS_RR_TYPE_A, LDNS_RR_TYPE_AAAA, - LDNS_RR_TYPE_MX, LDNS_RR_TYPE_SOA, LDNS_RR_TYPE_NS, 0}; - int i, num=5; /* number of RR types to look up */ + LDNS_RR_TYPE_MX, LDNS_RR_TYPE_SOA, LDNS_RR_TYPE_NS, + LDNS_RR_TYPE_DNAME, 0}; + int i, num=6; /* number of RR types to look up */ log_assert(lookup[num] == 0); for(i=0; i<num; i++) { diff --git a/usr.sbin/unbound/sldns/rrdef.h b/usr.sbin/unbound/sldns/rrdef.h index 678d2bc791e..ab65943a59e 100644 --- a/usr.sbin/unbound/sldns/rrdef.h +++ b/usr.sbin/unbound/sldns/rrdef.h @@ -342,7 +342,7 @@ enum sldns_enum_rdf_type /** A <character-string> encoding of the value field as specified * [RFC1035], Section 5.1., encoded as remaining rdata. - * For CAA. + * For CAA, URI. */ LDNS_RDF_TYPE_LONG_STR, diff --git a/usr.sbin/unbound/sldns/wire2str.c b/usr.sbin/unbound/sldns/wire2str.c index cec3bc7b08d..5cbd78eedb2 100644 --- a/usr.sbin/unbound/sldns/wire2str.c +++ b/usr.sbin/unbound/sldns/wire2str.c @@ -697,6 +697,9 @@ int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s, } w += n; } + if(*dlen != 0) { + goto failed; + } return w; } diff --git a/usr.sbin/unbound/smallapp/unbound-anchor.c b/usr.sbin/unbound/smallapp/unbound-anchor.c index e14ca733fd7..92bfa842877 100644 --- a/usr.sbin/unbound/smallapp/unbound-anchor.c +++ b/usr.sbin/unbound/smallapp/unbound-anchor.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -116,7 +116,8 @@ #include "config.h" #include "libunbound/unbound.h" -#include <ldns/rr.h> +#include "sldns/rrdef.h" +#include "sldns/parseutil.h" #include <expat.h> #ifndef HAVE_EXPAT_H #error "need libexpat to parse root-anchors.xml file." @@ -134,6 +135,7 @@ #include <openssl/rand.h> #endif #include <openssl/x509.h> +#include <openssl/x509v3.h> #include <openssl/pem.h> /** name of server in URL to fetch HTTPS from */ @@ -142,6 +144,8 @@ #define XMLNAME "root-anchors/root-anchors.xml" /** path on HTTPS server to p7s file */ #define P7SNAME "root-anchors/root-anchors.p7s" +/** name of the signer of the certificate */ +#define P7SIGNER "dnssec@iana.org" /** port number for https access */ #define HTTPS_PORT 443 @@ -184,6 +188,7 @@ usage() printf("-u name server in https url, default %s\n", URLNAME); printf("-x path pathname to xml in url, default %s\n", XMLNAME); printf("-s path pathname to p7s in url, default %s\n", P7SNAME); + printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER); printf("-4 work using IPv4 only\n"); printf("-6 work using IPv6 only\n"); printf("-f resolv.conf use given resolv.conf to resolve -u name\n"); @@ -240,7 +245,7 @@ get_builtin_ds(void) /** print hex data */ static void -print_data(char* msg, char* data, int len) +print_data(const char* msg, const char* data, int len) { int i; printf("%s: ", msg); @@ -264,8 +269,8 @@ ub_ctx_error_exit(struct ub_ctx* ctx, const char* str, const char* str2) * Create a new unbound context with the commandline settings applied */ static struct ub_ctx* -create_unbound_context(char* res_conf, char* root_hints, char* debugconf, - int ip4only, int ip6only) +create_unbound_context(const char* res_conf, const char* root_hints, + const char* debugconf, int ip4only, int ip6only) { int r; struct ub_ctx* ctx = ub_ctx_create(); @@ -302,7 +307,7 @@ create_unbound_context(char* res_conf, char* root_hints, char* debugconf, /** printout certificate in detail */ static void -verb_cert(char* msg, X509* x) +verb_cert(const char* msg, X509* x) { if(verb == 0 || verb == 1) return; if(verb == 2) { @@ -318,7 +323,7 @@ verb_cert(char* msg, X509* x) /** printout certificates in detail */ static void -verb_certs(char* msg, STACK_OF(X509)* sk) +verb_certs(const char* msg, STACK_OF(X509)* sk) { int i, num = sk_X509_num(sk); if(verb == 0 || verb == 1) return; @@ -356,7 +361,7 @@ read_cert_bio(BIO* bio) /* read the certificate file */ static STACK_OF(X509)* -read_cert_file(char* file) +read_cert_file(const char* file) { STACK_OF(X509)* sk; FILE* in; @@ -431,7 +436,7 @@ read_builtin_cert(void) /** read update cert file or use builtin */ static STACK_OF(X509)* -read_cert_or_builtin(char* file) +read_cert_or_builtin(const char* file) { STACK_OF(X509) *sk = read_cert_file(file); if(!sk) { @@ -455,7 +460,7 @@ do_list_builtin(void) /** printout IP address with message */ static void -verb_addr(char* msg, struct ip_list* ip) +verb_addr(const char* msg, struct ip_list* ip) { if(verb) { char out[100]; @@ -522,7 +527,7 @@ RR_to_ip(int tp, char* data, int len, int port) /** Resolve name, type, class and add addresses to iplist */ static void -resolve_host_ip(struct ub_ctx* ctx, char* host, int port, int tp, int cl, +resolve_host_ip(struct ub_ctx* ctx, const char* host, int port, int tp, int cl, struct ip_list** head) { struct ub_result* res = NULL; @@ -540,6 +545,11 @@ resolve_host_ip(struct ub_ctx* ctx, char* host, int port, int tp, int cl, ub_ctx_delete(ctx); exit(0); } + if(!res->havedata || res->rcode || !res->data) { + if(verb) printf("resolve %s %s: no result\n", host, + (tp==LDNS_RR_TYPE_A)?"A":"AAAA"); + return; + } for(i = 0; res->data[i]; i++) { struct ip_list* ip = RR_to_ip(tp, res->data[i], res->len[i], port); @@ -552,29 +562,27 @@ resolve_host_ip(struct ub_ctx* ctx, char* host, int port, int tp, int cl, /** parse a text IP address into a sockaddr */ static struct ip_list* -parse_ip_addr(char* str, int port) +parse_ip_addr(const char* str, int port) { socklen_t len = 0; - struct sockaddr_storage* addr = NULL; - struct sockaddr_in6 a6; - struct sockaddr_in a; + union { + struct sockaddr_in6 a6; + struct sockaddr_in a; + } addr; struct ip_list* ip; uint16_t p = (uint16_t)port; - memset(&a6, 0, sizeof(a6)); - memset(&a, 0, sizeof(a)); + memset(&addr, 0, sizeof(addr)); - if(inet_pton(AF_INET6, str, &a6.sin6_addr) > 0) { + if(inet_pton(AF_INET6, str, &addr.a6.sin6_addr) > 0) { /* it is an IPv6 */ - a6.sin6_family = AF_INET6; - a6.sin6_port = (in_port_t)htons(p); - addr = (struct sockaddr_storage*)&a6; - len = (socklen_t)sizeof(struct sockaddr_in6); + addr.a6.sin6_family = AF_INET6; + addr.a6.sin6_port = (in_port_t)htons(p); + len = (socklen_t)sizeof(addr.a6); } - if(inet_pton(AF_INET, str, &a.sin_addr) > 0) { + if(inet_pton(AF_INET, str, &addr.a.sin_addr) > 0) { /* it is an IPv4 */ - a.sin_family = AF_INET; - a.sin_port = (in_port_t)htons(p); - addr = (struct sockaddr_storage*)&a; + addr.a.sin_family = AF_INET; + addr.a.sin_port = (in_port_t)htons(p); len = (socklen_t)sizeof(struct sockaddr_in); } if(!len) return NULL; @@ -584,7 +592,7 @@ parse_ip_addr(char* str, int port) exit(0); } ip->len = len; - memmove(&ip->addr, addr, len); + memmove(&ip->addr, &addr, len); if(verb) printf("server address is %s\n", str); return ip; } @@ -604,8 +612,8 @@ parse_ip_addr(char* str, int port) * @return list of IP addresses. */ static struct ip_list* -resolve_name(char* host, int port, char* res_conf, char* root_hints, - char* debugconf, int ip4only, int ip6only) +resolve_name(const char* host, int port, const char* res_conf, + const char* root_hints, const char* debugconf, int ip4only, int ip6only) { struct ub_ctx* ctx; struct ip_list* list = NULL; @@ -669,7 +677,7 @@ pick_random_ip(struct ip_list* list) int sel; if(num == 0) return NULL; /* not perfect, but random enough */ - sel = (int)ldns_get_random() % num; + sel = (int)arc4random_uniform((uint32_t)num); /* skip over unused elements that we did not select */ while(sel > 0 && p) { if(!p->used) sel--; @@ -792,7 +800,7 @@ TLS_shutdown(int fd, SSL* ssl, SSL_CTX* sslctx) /** write a line over SSL */ static int -write_ssl_line(SSL* ssl, char* str, char* sec) +write_ssl_line(SSL* ssl, const char* str, const char* sec) { char buf[1024]; size_t l; @@ -908,7 +916,10 @@ read_data_chunk(SSL* ssl, size_t len) { size_t got = 0; int r; - char* data = malloc(len+1); + char* data; + if(len >= 0xfffffff0) + return NULL; /* to protect against integer overflow in malloc*/ + data = malloc(len+1); if(!data) { if(verb) printf("out of memory\n"); return NULL; @@ -1011,7 +1022,7 @@ do_chunked_read(SSL* ssl) /** start HTTP1.1 transaction on SSL */ static int -write_http_get(SSL* ssl, char* pathname, char* urlname) +write_http_get(SSL* ssl, const char* pathname, const char* urlname) { if(write_ssl_line(ssl, "GET /%s HTTP/1.1", pathname) && write_ssl_line(ssl, "Host: %s", urlname) && @@ -1082,7 +1093,7 @@ read_http_result(SSL* ssl) /** https to an IP addr, return BIO with pathname or NULL */ static BIO* -https_to_ip(struct ip_list* ip, char* pathname, char* urlname) +https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname) { int fd; SSL* ssl; @@ -1122,7 +1133,7 @@ https_to_ip(struct ip_list* ip, char* pathname, char* urlname) * @return a memory BIO with the file in it. */ static BIO* -https(struct ip_list* ip_list, char* pathname, char* urlname) +https(struct ip_list* ip_list, const char* pathname, const char* urlname) { struct ip_list* ip; BIO* bio = NULL; @@ -1204,7 +1215,7 @@ xml_selectbio(struct xml_data* data, const char* tag) * NOT zero terminated. * @param len: length of this part of the data. */ -void +static void xml_charhandle(void *userData, const XML_Char *s, int len) { struct xml_data* data = (struct xml_data*)userData; @@ -1222,7 +1233,7 @@ xml_charhandle(void *userData, const XML_Char *s, int len) printf("'\n"); } if(strcasecmp(data->tag, "Zone") == 0) { - if(BIO_write(data->czone, s, len) <= 0) { + if(BIO_write(data->czone, s, len) < 0) { if(verb) printf("out of memory in BIO_write\n"); exit(0); } @@ -1233,7 +1244,7 @@ xml_charhandle(void *userData, const XML_Char *s, int len) return; b = xml_selectbio(data, data->tag); if(b) { - if(BIO_write(b, s, len) <= 0) { + if(BIO_write(b, s, len) < 0) { if(verb) printf("out of memory in BIO_write\n"); exit(0); } @@ -1247,7 +1258,7 @@ xml_charhandle(void *userData, const XML_Char *s, int len) * @return the value or NULL. (ptr into atts). */ static const XML_Char* -find_att(const XML_Char **atts, XML_Char* name) +find_att(const XML_Char **atts, const XML_Char* name) { int i; for(i=0; atts[i]; i+=2) { @@ -1318,7 +1329,7 @@ xml_convertdate(const char* str) /* but ignore, (lenient) */ } - t = mktime(&tm); + t = sldns_mktime_from_utc(&tm); if(t == (time_t)-1) { if(verb) printf("xml_convertdate mktime failure\n"); return 0; @@ -1361,7 +1372,7 @@ handle_keydigest(struct xml_data* data, const XML_Char **atts) /** See if XML element equals the zone name */ static int -xml_is_zone_name(BIO* zone, char* name) +xml_is_zone_name(BIO* zone, const char* name) { char buf[1024]; char* z = NULL; @@ -1426,7 +1437,7 @@ xml_startelem(void *userData, const XML_Char *name, const XML_Char **atts) static void xml_append_str(BIO* b, const char* s) { - if(BIO_write(b, s, (int)strlen(s)) <= 0) { + if(BIO_write(b, s, (int)strlen(s)) < 0) { if(verb) printf("out of memory in BIO_write\n"); exit(0); } @@ -1450,7 +1461,7 @@ xml_append_bio(BIO* b, BIO* a) z[i] = ' '; } /* write to BIO */ - if(BIO_write(b, z, len) <= 0) { + if(BIO_write(b, z, len) < 0) { if(verb) printf("out of memory in BIO_write\n"); exit(0); } @@ -1498,6 +1509,20 @@ xml_endelem(void *userData, const XML_Char *name) } } +/* Stop the parser when an entity declaration is encountered. For safety. */ +static void +xml_entitydeclhandler(void *userData, + const XML_Char *ATTR_UNUSED(entityName), + int ATTR_UNUSED(is_parameter_entity), + const XML_Char *ATTR_UNUSED(value), int ATTR_UNUSED(value_length), + const XML_Char *ATTR_UNUSED(base), + const XML_Char *ATTR_UNUSED(systemId), + const XML_Char *ATTR_UNUSED(publicId), + const XML_Char *ATTR_UNUSED(notationName)) +{ + (void)XML_StopParser((XML_Parser)userData, XML_FALSE); +} + /** * XML parser setup of the callbacks for the tags */ @@ -1522,10 +1547,11 @@ xml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now) } snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s", ctime(&now)); - if(BIO_write(data->ds, buf, (int)strlen(buf)) <= 0) { + if(BIO_write(data->ds, buf, (int)strlen(buf)) < 0) { if(verb) printf("out of memory\n"); exit(0); } + XML_SetEntityDeclHandler(parser, xml_entitydeclhandler); XML_SetElementHandler(parser, xml_startelem, xml_endelem); XML_SetCharacterDataHandler(parser, xml_charhandle); } @@ -1578,8 +1604,6 @@ xml_parse(BIO* xml, time_t now) XML_ParserFree(parser); if(verb >= 4) { - char* pp = NULL; - int len; (void)BIO_seek(data.ds, 0); len = BIO_get_mem_data(data.ds, &pp); printf("got DS bio %d: '", len); @@ -1603,12 +1627,113 @@ xml_parse(BIO* xml, time_t now) } } +/* get key usage out of its extension, returns 0 if no key_usage extension */ +static unsigned long +get_usage_of_ex(X509* cert) +{ + unsigned long val = 0; + ASN1_BIT_STRING* s; + if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { + if(s->length > 0) { + val = s->data[0]; + if(s->length > 1) + val |= s->data[1] << 8; + } + ASN1_BIT_STRING_free(s); + } + return val; +} + +/** get valid signers from the list of signers in the signature */ +static STACK_OF(X509)* +get_valid_signers(PKCS7* p7, const char* p7signer) +{ + int i; + STACK_OF(X509)* validsigners = sk_X509_new_null(); + STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); + unsigned long usage = 0; + if(!validsigners) { + if(verb) printf("out of memory\n"); + sk_X509_free(signers); + return NULL; + } + if(!signers) { + if(verb) printf("no signers in pkcs7 signature\n"); + sk_X509_free(validsigners); + return NULL; + } + for(i=0; i<sk_X509_num(signers); i++) { + X509_NAME* nm = X509_get_subject_name( + sk_X509_value(signers, i)); + char buf[1024]; + if(!nm) { + if(verb) printf("signer %d: cert has no subject name\n", i); + continue; + } + if(verb && nm) { + char* nmline = X509_NAME_oneline(nm, buf, + (int)sizeof(buf)); + printf("signer %d: Subject: %s\n", i, + nmline?nmline:"no subject"); + if(verb >= 3 && X509_NAME_get_text_by_NID(nm, + NID_commonName, buf, (int)sizeof(buf))) + printf("commonName: %s\n", buf); + if(verb >= 3 && X509_NAME_get_text_by_NID(nm, + NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) + printf("emailAddress: %s\n", buf); + } + if(verb) { + int ku_loc = X509_get_ext_by_NID( + sk_X509_value(signers, i), NID_key_usage, -1); + if(verb >= 3 && ku_loc >= 0) { + X509_EXTENSION *ex = X509_get_ext( + sk_X509_value(signers, i), ku_loc); + if(ex) { + printf("keyUsage: "); + X509V3_EXT_print_fp(stdout, ex, 0, 0); + printf("\n"); + } + } + } + if(!p7signer || strcmp(p7signer, "")==0) { + /* there is no name to check, return all records */ + if(verb) printf("did not check commonName of signer\n"); + } else { + if(!X509_NAME_get_text_by_NID(nm, + NID_pkcs9_emailAddress, + buf, (int)sizeof(buf))) { + if(verb) printf("removed cert with no name\n"); + continue; /* no name, no use */ + } + if(strcmp(buf, p7signer) != 0) { + if(verb) printf("removed cert with wrong name\n"); + continue; /* wrong name, skip it */ + } + } + + /* check that the key usage allows digital signatures + * (the p7s) */ + usage = get_usage_of_ex(sk_X509_value(signers, i)); + if(!(usage & KU_DIGITAL_SIGNATURE)) { + if(verb) printf("removed cert with no key usage Digital Signature allowed\n"); + continue; + } + + /* we like this cert, add it to our list of valid + * signers certificates */ + sk_X509_push(validsigners, sk_X509_value(signers, i)); + } + sk_X509_free(signers); + return validsigners; +} + /** verify a PKCS7 signature, false on failure */ static int -verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust) +verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer) { PKCS7* p7; X509_STORE *store = X509_STORE_new(); + STACK_OF(X509)* validsigners; int secure = 0; int i; #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE @@ -1630,6 +1755,9 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust) #endif return 0; } +#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE + X509_VERIFY_PARAM_free(param); +#endif (void)BIO_reset(p7s); (void)BIO_reset(data); @@ -1654,7 +1782,15 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust) } if(verb >= 2) printf("setup the X509_STORE\n"); - if(PKCS7_verify(p7, NULL, store, data, NULL, 0) == 1) { + /* check what is in the Subject name of the certificates, + * and build a stack that contains only the right certificates */ + validsigners = get_valid_signers(p7, p7signer); + if(!validsigners) { + X509_STORE_free(store); + PKCS7_free(p7); + return 0; + } + if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) { secure = 1; if(verb) printf("the PKCS7 signature verified\n"); } else { @@ -1663,6 +1799,7 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust) } } + sk_X509_free(validsigners); X509_STORE_free(store); PKCS7_free(p7); return secure; @@ -1670,7 +1807,7 @@ verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust) /** write unsigned root anchor file, a 5011 revoked tp */ static void -write_unsigned_root(char* root_anchor_file) +write_unsigned_root(const char* root_anchor_file) { FILE* out; time_t now = time(NULL); @@ -1696,7 +1833,7 @@ write_unsigned_root(char* root_anchor_file) /** write root anchor file */ static void -write_root_anchor(char* root_anchor_file, BIO* ds) +write_root_anchor(const char* root_anchor_file, BIO* ds) { char* pp = NULL; int len; @@ -1722,13 +1859,13 @@ write_root_anchor(char* root_anchor_file, BIO* ds) /** Perform the verification and update of the trustanchor file */ static void -verify_and_update_anchor(char* root_anchor_file, BIO* xml, BIO* p7s, - STACK_OF(X509)* cert) +verify_and_update_anchor(const char* root_anchor_file, BIO* xml, BIO* p7s, + STACK_OF(X509)* cert, const char* p7signer) { BIO* ds; /* verify xml file */ - if(!verify_p7sig(xml, p7s, cert)) { + if(!verify_p7sig(xml, p7s, cert, p7signer)) { printf("the PKCS7 signature failed\n"); exit(0); } @@ -1751,10 +1888,11 @@ static void do_wsa_cleanup(void) { WSACleanup(); } /** perform actual certupdate work */ static int -do_certupdate(char* root_anchor_file, char* root_cert_file, - char* urlname, char* xmlname, char* p7sname, - char* res_conf, char* root_hints, char* debugconf, - int ip4only, int ip6only, int port, struct ub_result* dnskey) +do_certupdate(const char* root_anchor_file, const char* root_cert_file, + const char* urlname, const char* xmlname, const char* p7sname, + const char* p7signer, const char* res_conf, const char* root_hints, + const char* debugconf, int ip4only, int ip6only, int port, + struct ub_result* dnskey) { STACK_OF(X509)* cert; BIO *xml, *p7s; @@ -1785,7 +1923,7 @@ do_certupdate(char* root_anchor_file, char* root_cert_file, p7s = https(ip_list, p7sname, urlname); /* verify and update the root anchor */ - verify_and_update_anchor(root_anchor_file, xml, p7s, cert); + verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer); if(verb) printf("success: the anchor has been updated " "using the cert\n"); @@ -1808,7 +1946,7 @@ do_certupdate(char* root_anchor_file, char* root_cert_file, * 2 if it is OK. */ static int -try_read_anchor(char* file) +try_read_anchor(const char* file) { int empty = 1; char line[10240]; @@ -1852,7 +1990,7 @@ try_read_anchor(char* file) /** Write the builtin root anchor to a file */ static void -write_builtin_anchor(char* file) +write_builtin_anchor(const char* file) { const char* builtin_root_anchor = get_builtin_ds(); FILE* out = fopen(file, "w"); @@ -1878,7 +2016,7 @@ write_builtin_anchor(char* file) * @return 0 if trustpoint is insecure, 1 on success. Exit on failure. */ static int -provide_builtin(char* root_anchor_file, int* used_builtin) +provide_builtin(const char* root_anchor_file, int* used_builtin) { /* try to read it */ switch(try_read_anchor(root_anchor_file)) @@ -1900,7 +2038,7 @@ provide_builtin(char* root_anchor_file, int* used_builtin) * add an autotrust anchor for the root to the context */ static void -add_5011_probe_root(struct ub_ctx* ctx, char* root_anchor_file) +add_5011_probe_root(struct ub_ctx* ctx, const char* root_anchor_file) { int r; r = ub_ctx_set_option(ctx, "auto-trust-anchor-file:", root_anchor_file); @@ -1937,7 +2075,7 @@ prime_root_key(struct ub_ctx* ctx) /** see if ADDPEND keys exist in autotrust file (if possible) */ static int -read_if_pending_keys(char* file) +read_if_pending_keys(const char* file) { FILE* in = fopen(file, "r"); char line[8192]; @@ -1959,7 +2097,7 @@ read_if_pending_keys(char* file) /** read last successful probe time from autotrust file (if possible) */ static int32_t -read_last_success_time(char* file) +read_last_success_time(const char* file) { FILE* in = fopen(file, "r"); char line[1024]; @@ -1996,7 +2134,7 @@ read_last_success_time(char* file) * @return true if certupdate is ok. */ static int -probe_date_allows_certupdate(char* root_anchor_file) +probe_date_allows_certupdate(const char* root_anchor_file) { int has_pending_keys = read_if_pending_keys(root_anchor_file); int32_t last_success = read_last_success_time(root_anchor_file); @@ -2034,10 +2172,10 @@ probe_date_allows_certupdate(char* root_anchor_file) /** perform the unbound-anchor work */ static int -do_root_update_work(char* root_anchor_file, char* root_cert_file, - char* urlname, char* xmlname, char* p7sname, - char* res_conf, char* root_hints, char* debugconf, - int ip4only, int ip6only, int force, int port) +do_root_update_work(const char* root_anchor_file, const char* root_cert_file, + const char* urlname, const char* xmlname, const char* p7sname, + const char* p7signer, const char* res_conf, const char* root_hints, + const char* debugconf, int ip4only, int ip6only, int force, int port) { struct ub_ctx* ctx; struct ub_result* dnskey; @@ -2068,8 +2206,8 @@ do_root_update_work(char* root_anchor_file, char* root_cert_file, if((dnskey->rcode == 0 && probe_date_allows_certupdate(root_anchor_file)) || force) { if(do_certupdate(root_anchor_file, root_cert_file, urlname, - xmlname, p7sname, res_conf, root_hints, debugconf, - ip4only, ip6only, port, dnskey)) + xmlname, p7sname, p7signer, res_conf, root_hints, + debugconf, ip4only, ip6only, port, dnskey)) return 1; return used_builtin; } @@ -2087,17 +2225,18 @@ extern char* optarg; int main(int argc, char* argv[]) { int c; - char* root_anchor_file = ROOT_ANCHOR_FILE; - char* root_cert_file = ROOT_CERT_FILE; - char* urlname = URLNAME; - char* xmlname = XMLNAME; - char* p7sname = P7SNAME; - char* res_conf = NULL; - char* root_hints = NULL; - char* debugconf = NULL; + const char* root_anchor_file = ROOT_ANCHOR_FILE; + const char* root_cert_file = ROOT_CERT_FILE; + const char* urlname = URLNAME; + const char* xmlname = XMLNAME; + const char* p7sname = P7SNAME; + const char* p7signer = P7SIGNER; + const char* res_conf = NULL; + const char* root_hints = NULL; + const char* debugconf = NULL; int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT; /* parse the options */ - while( (c=getopt(argc, argv, "46C:FP:a:c:f:hlr:s:u:vx:")) != -1) { + while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) { switch(c) { case 'l': dolist = 1; @@ -2123,6 +2262,9 @@ int main(int argc, char* argv[]) case 's': p7sname = optarg; break; + case 'n': + p7signer = optarg; + break; case 'f': res_conf = optarg; break; @@ -2160,6 +2302,6 @@ int main(int argc, char* argv[]) if(dolist) do_list_builtin(); return do_root_update_work(root_anchor_file, root_cert_file, urlname, - xmlname, p7sname, res_conf, root_hints, debugconf, ip4only, - ip6only, force, port); + xmlname, p7sname, p7signer, res_conf, root_hints, debugconf, + ip4only, ip6only, force, port); } diff --git a/usr.sbin/unbound/smallapp/unbound-control.c b/usr.sbin/unbound/smallapp/unbound-control.c index b4af4d73383..8cd676ed877 100644 --- a/usr.sbin/unbound/smallapp/unbound-control.c +++ b/usr.sbin/unbound/smallapp/unbound-control.c @@ -163,7 +163,7 @@ setup_ctx(struct config_file* cfg) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3) ssl_err("could not set SSL_OP_NO_SSLv3"); - if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || + if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key and cert"); diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c index 5d31301fa00..db328f3307b 100644 --- a/usr.sbin/unbound/util/config_file.c +++ b/usr.sbin/unbound/util/config_file.c @@ -70,6 +70,8 @@ uid_t cfg_uid = (uid_t)-1; /** from cfg username, after daemonise setup performed */ gid_t cfg_gid = (gid_t)-1; +/** for debug allow small timeout values for fast rollovers */ +int autr_permit_small_holddown = 0; /** global config during parsing */ struct config_parser_state* cfg_parser = 0; @@ -98,7 +100,7 @@ config_create(void) cfg->tcp_upstream = 0; cfg->ssl_service_key = NULL; cfg->ssl_service_pem = NULL; - cfg->ssl_port = 443; + cfg->ssl_port = 853; cfg->ssl_upstream = 0; cfg->use_syslog = 1; cfg->log_time_ascii = 0; @@ -172,7 +174,7 @@ config_create(void) cfg->harden_dnssec_stripped = 1; cfg->harden_below_nxdomain = 0; cfg->harden_referral_path = 0; - cfg->harden_algo_downgrade = 1; + cfg->harden_algo_downgrade = 0; cfg->use_caps_bits_for_id = 0; cfg->caps_whitelist = NULL; cfg->private_address = NULL; @@ -200,6 +202,7 @@ config_create(void) cfg->add_holddown = 30*24*3600; cfg->del_holddown = 30*24*3600; cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */ + cfg->permit_small_holddown = 0; cfg->key_cache_size = 4 * 1024 * 1024; cfg->key_cache_slabs = 4; cfg->neg_cache_size = 1 * 1024 * 1024; @@ -444,6 +447,9 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown) else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown) else S_UNSIGNED_OR_ZERO("keep-missing:", keep_missing) + else if(strcmp(opt, "permit-small-holddown:") == 0) + { IS_YES_OR_NO; cfg->permit_small_holddown = (strcmp(val, "yes") == 0); + autr_permit_small_holddown = cfg->permit_small_holddown; } else S_MEMSIZE("key-cache-size:", key_cache_size) else S_POW2("key-cache-slabs:", key_cache_slabs) else S_MEMSIZE("neg-cache-size:", neg_cache_size) @@ -705,6 +711,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_UNS(opt, "add-holddown", add_holddown) else O_UNS(opt, "del-holddown", del_holddown) else O_UNS(opt, "keep-missing", keep_missing) + else O_YNO(opt, "permit-small-holddown", permit_small_holddown) else O_MEM(opt, "key-cache-size", key_cache_size) else O_DEC(opt, "key-cache-slabs", key_cache_slabs) else O_MEM(opt, "neg-cache-size", neg_cache_size) @@ -1243,6 +1250,7 @@ config_apply(struct config_file* config) MINIMAL_RESPONSES = config->minimal_responses; RRSET_ROUNDROBIN = config->rrset_roundrobin; log_set_time_asc(config->log_time_ascii); + autr_permit_small_holddown = config->permit_small_holddown; } void config_lookup_uid(struct config_file* cfg) diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h index 1c3c31dcf13..99b15e06ebc 100644 --- a/usr.sbin/unbound/util/config_file.h +++ b/usr.sbin/unbound/util/config_file.h @@ -269,6 +269,8 @@ struct config_file { unsigned int del_holddown; /** autotrust keep_missing time, in seconds. 0 is forever. */ unsigned int keep_missing; + /** permit small holddown values, allowing 5011 rollover very fast */ + int permit_small_holddown; /** size of the key cache */ size_t key_cache_size; @@ -368,6 +370,8 @@ struct config_file { extern uid_t cfg_uid; /** from cfg username, after daemonise setup performed */ extern gid_t cfg_gid; +/** debug and enable small timeouts */ +extern int autr_permit_small_holddown; /** * Stub config options diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex index 2661ffdf1ba..ba728622c15 100644 --- a/usr.sbin/unbound/util/configlexer.lex +++ b/usr.sbin/unbound/util/configlexer.lex @@ -7,10 +7,12 @@ * See LICENSE for the license. * */ - #include <ctype.h> #include <string.h> #include <strings.h> +#ifdef HAVE_GLOB_H +# include <glob.h> +#endif #include "util/config_file.h" #include "util/configparser.h" @@ -36,52 +38,131 @@ void ub_c_error(const char *message); struct inc_state { char* filename; int line; + YY_BUFFER_STATE buffer; + struct inc_state* next; }; -static struct inc_state parse_stack[MAXINCLUDES]; -static YY_BUFFER_STATE include_stack[MAXINCLUDES]; -static int config_include_stack_ptr = 0; +static struct inc_state* config_include_stack = NULL; +static int inc_depth = 0; static int inc_prev = 0; static int num_args = 0; +void init_cfg_parse(void) +{ + config_include_stack = NULL; + inc_depth = 0; + inc_prev = 0; + num_args = 0; +} + static void config_start_include(const char* filename) { FILE *input; + struct inc_state* s; + char* nm; + if(inc_depth++ > 100000) { + ub_c_error_msg("too many include files"); + return; + } if(strlen(filename) == 0) { ub_c_error_msg("empty include file name"); return; } - if(config_include_stack_ptr >= MAXINCLUDES) { - ub_c_error_msg("includes nested too deeply, skipped (>%d)", MAXINCLUDES); + s = (struct inc_state*)malloc(sizeof(*s)); + if(!s) { + ub_c_error_msg("include %s: malloc failure", filename); return; } if(cfg_parser->chroot && strncmp(filename, cfg_parser->chroot, strlen(cfg_parser->chroot)) == 0) { filename += strlen(cfg_parser->chroot); } + nm = strdup(filename); + if(!nm) { + ub_c_error_msg("include %s: strdup failure", filename); + free(s); + return; + } input = fopen(filename, "r"); if(!input) { ub_c_error_msg("cannot open include file '%s': %s", filename, strerror(errno)); + free(s); + free(nm); return; } - LEXOUT(("switch_to_include_file(%s) ", filename)); - parse_stack[config_include_stack_ptr].filename = cfg_parser->filename; - parse_stack[config_include_stack_ptr].line = cfg_parser->line; - include_stack[config_include_stack_ptr] = YY_CURRENT_BUFFER; - cfg_parser->filename = strdup(filename); + LEXOUT(("switch_to_include_file(%s)\n", filename)); + s->filename = cfg_parser->filename; + s->line = cfg_parser->line; + s->buffer = YY_CURRENT_BUFFER; + s->next = config_include_stack; + config_include_stack = s; + cfg_parser->filename = nm; cfg_parser->line = 1; yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE)); - ++config_include_stack_ptr; +} + +static void config_start_include_glob(const char* filename) +{ + + /* check for wildcards */ +#ifdef HAVE_GLOB + glob_t g; + size_t i; + int r, flags; + if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') && + !strchr(filename, '{') && !strchr(filename, '~'))) { + flags = 0 +#ifdef GLOB_ERR + | GLOB_ERR +#endif +#ifdef GLOB_NOSORT + | GLOB_NOSORT +#endif +#ifdef GLOB_BRACE + | GLOB_BRACE +#endif +#ifdef GLOB_TILDE + | GLOB_TILDE +#endif + ; + memset(&g, 0, sizeof(g)); + if(cfg_parser->chroot && strncmp(filename, cfg_parser->chroot, + strlen(cfg_parser->chroot)) == 0) { + filename += strlen(cfg_parser->chroot); + } + r = glob(filename, flags, NULL, &g); + if(r) { + /* some error */ + globfree(&g); + if(r == GLOB_NOMATCH) + return; /* no matches for pattern */ + config_start_include(filename); /* let original deal with it */ + return; + } + /* process files found, if any */ + for(i=0; i<(size_t)g.gl_pathc; i++) { + config_start_include(g.gl_pathv[i]); + } + globfree(&g); + return; + } +#endif /* HAVE_GLOB */ + + config_start_include(filename); } static void config_end_include(void) { - --config_include_stack_ptr; + struct inc_state* s = config_include_stack; + --inc_depth; + if(!s) return; free(cfg_parser->filename); - cfg_parser->filename = parse_stack[config_include_stack_ptr].filename; - cfg_parser->line = parse_stack[config_include_stack_ptr].line; + cfg_parser->filename = s->filename; + cfg_parser->line = s->line; yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(include_stack[config_include_stack_ptr]); + yy_switch_to_buffer(s->buffer); + config_include_stack = s->next; + free(s); } #ifndef yy_set_bol /* compat definition, for flex 2.4.6 */ @@ -143,10 +224,13 @@ ssl-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) } ssl-port{COLON} { YDVAR(1, VAR_SSL_PORT) } do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) } interface{COLON} { YDVAR(1, VAR_INTERFACE) } +ip-address{COLON} { YDVAR(1, VAR_INTERFACE) } outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) } interface-automatic{COLON} { YDVAR(1, VAR_INTERFACE_AUTOMATIC) } so-rcvbuf{COLON} { YDVAR(1, VAR_SO_RCVBUF) } so-sndbuf{COLON} { YDVAR(1, VAR_SO_SNDBUF) } +so-reuseport{COLON} { YDVAR(1, VAR_SO_REUSEPORT) } +ip-transparent{COLON} { YDVAR(1, VAR_IP_TRANSPARENT) } chroot{COLON} { YDVAR(1, VAR_CHROOT) } username{COLON} { YDVAR(1, VAR_USERNAME) } directory{COLON} { YDVAR(1, VAR_DIRECTORY) } @@ -160,14 +244,17 @@ msg-cache-slabs{COLON} { YDVAR(1, VAR_MSG_CACHE_SLABS) } rrset-cache-size{COLON} { YDVAR(1, VAR_RRSET_CACHE_SIZE) } rrset-cache-slabs{COLON} { YDVAR(1, VAR_RRSET_CACHE_SLABS) } cache-max-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_TTL) } +cache-max-negative-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_NEGATIVE_TTL) } cache-min-ttl{COLON} { YDVAR(1, VAR_CACHE_MIN_TTL) } infra-host-ttl{COLON} { YDVAR(1, VAR_INFRA_HOST_TTL) } infra-lame-ttl{COLON} { YDVAR(1, VAR_INFRA_LAME_TTL) } infra-cache-slabs{COLON} { YDVAR(1, VAR_INFRA_CACHE_SLABS) } infra-cache-numhosts{COLON} { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) } infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) } +infra-cache-min-rtt{COLON} { YDVAR(1, VAR_INFRA_CACHE_MIN_RTT) } num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) } jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) } +delay-close{COLON} { YDVAR(1, VAR_DELAY_CLOSE) } target-fetch-policy{COLON} { YDVAR(1, VAR_TARGET_FETCH_POLICY) } harden-short-bufsize{COLON} { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) } harden-large-queries{COLON} { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) } @@ -175,7 +262,9 @@ harden-glue{COLON} { YDVAR(1, VAR_HARDEN_GLUE) } harden-dnssec-stripped{COLON} { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) } harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) } harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) } +harden-algo-downgrade{COLON} { YDVAR(1, VAR_HARDEN_ALGO_DOWNGRADE) } use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) } +caps-whitelist{COLON} { YDVAR(1, VAR_CAPS_WHITELIST) } unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) } private-address{COLON} { YDVAR(1, VAR_PRIVATE_ADDRESS) } private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) } @@ -186,9 +275,11 @@ name{COLON} { YDVAR(1, VAR_NAME) } stub-addr{COLON} { YDVAR(1, VAR_STUB_ADDR) } stub-host{COLON} { YDVAR(1, VAR_STUB_HOST) } stub-prime{COLON} { YDVAR(1, VAR_STUB_PRIME) } +stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) } forward-zone{COLON} { YDVAR(0, VAR_FORWARD_ZONE) } forward-addr{COLON} { YDVAR(1, VAR_FORWARD_ADDR) } forward-host{COLON} { YDVAR(1, VAR_FORWARD_HOST) } +forward-first{COLON} { YDVAR(1, VAR_FORWARD_FIRST) } do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) } do-not-query-localhost{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) } access-control{COLON} { YDVAR(2, VAR_ACCESS_CONTROL) } @@ -219,12 +310,14 @@ val-nsec3-keysize-iterations{COLON} { add-holddown{COLON} { YDVAR(1, VAR_ADD_HOLDDOWN) } del-holddown{COLON} { YDVAR(1, VAR_DEL_HOLDDOWN) } keep-missing{COLON} { YDVAR(1, VAR_KEEP_MISSING) } +permit-small-holddown{COLON} { YDVAR(1, VAR_PERMIT_SMALL_HOLDDOWN) } use-syslog{COLON} { YDVAR(1, VAR_USE_SYSLOG) } log-time-ascii{COLON} { YDVAR(1, VAR_LOG_TIME_ASCII) } log-queries{COLON} { YDVAR(1, VAR_LOG_QUERIES) } local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) } local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) } local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) } +unblock-lan-zones{COLON} { YDVAR(1, VAR_UNBLOCK_LAN_ZONES) } statistics-interval{COLON} { YDVAR(1, VAR_STATISTICS_INTERVAL) } statistics-cumulative{COLON} { YDVAR(1, VAR_STATISTICS_CUMULATIVE) } extended-statistics{COLON} { YDVAR(1, VAR_EXTENDED_STATISTICS) } @@ -232,6 +325,7 @@ remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) } control-enable{COLON} { YDVAR(1, VAR_CONTROL_ENABLE) } control-interface{COLON} { YDVAR(1, VAR_CONTROL_INTERFACE) } control-port{COLON} { YDVAR(1, VAR_CONTROL_PORT) } +control-use-cert{COLON} { YDVAR(1, VAR_CONTROL_USE_CERT) } server-key-file{COLON} { YDVAR(1, VAR_SERVER_KEY_FILE) } server-cert-file{COLON} { YDVAR(1, VAR_SERVER_CERT_FILE) } control-key-file{COLON} { YDVAR(1, VAR_CONTROL_KEY_FILE) } @@ -239,6 +333,36 @@ control-cert-file{COLON} { YDVAR(1, VAR_CONTROL_CERT_FILE) } python-script{COLON} { YDVAR(1, VAR_PYTHON_SCRIPT) } python{COLON} { YDVAR(0, VAR_PYTHON) } domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) } +minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) } +rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) } +max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) } +dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } +dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } +dnstap{COLON} { YDVAR(0, VAR_DNSTAP) } +dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) } +dnstap-socket-path{COLON} { YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } +dnstap-send-identity{COLON} { YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) } +dnstap-send-version{COLON} { YDVAR(1, VAR_DNSTAP_SEND_VERSION) } +dnstap-identity{COLON} { YDVAR(1, VAR_DNSTAP_IDENTITY) } +dnstap-version{COLON} { YDVAR(1, VAR_DNSTAP_VERSION) } +dnstap-log-resolver-query-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) } +dnstap-log-resolver-response-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) } +dnstap-log-client-query-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) } +dnstap-log-client-response-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) } +dnstap-log-forwarder-query-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) } +dnstap-log-forwarder-response-messages{COLON} { + YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } +ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) } +ratelimit-slabs{COLON} { YDVAR(1, VAR_RATELIMIT_SLABS) } +ratelimit-size{COLON} { YDVAR(1, VAR_RATELIMIT_SIZE) } +ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } +ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } +ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) } <INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } /* Quoted strings. Strip leading and ending quotes */ @@ -295,7 +419,7 @@ domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) } <include>\" { LEXOUT(("IQS ")); BEGIN(include_quoted); } <include>{UNQUOTEDLETTER}* { LEXOUT(("Iunquotedstr(%s) ", yytext)); - config_start_include(yytext); + config_start_include_glob(yytext); BEGIN(inc_prev); } <include_quoted><<EOF>> { @@ -308,12 +432,13 @@ domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) } <include_quoted>\" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; - config_start_include(yytext); + config_start_include_glob(yytext); BEGIN(inc_prev); } <INITIAL,val><<EOF>> { + LEXOUT(("LEXEOF ")); yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ - if (config_include_stack_ptr == 0) { + if (!config_include_stack) { yyterminate(); } else { fclose(yyin); diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y index 09f77c5782f..d6db3c86f7d 100644 --- a/usr.sbin/unbound/util/configparser.y +++ b/usr.sbin/unbound/util/configparser.y @@ -23,16 +23,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %{ @@ -95,21 +95,39 @@ extern struct config_parser_state* cfg_parser; %token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE %token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE %token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE +%token VAR_CONTROL_USE_CERT %token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT %token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD VAR_LOG_TIME_ASCII %token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN %token VAR_VAL_SIG_SKEW_MAX VAR_CACHE_MIN_TTL VAR_VAL_LOG_LEVEL %token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN %token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH -%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_HARDEN_BELOW_NXDOMAIN +%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT VAR_HARDEN_BELOW_NXDOMAIN %token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM -%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT +%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST +%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN +%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE VAR_UNBLOCK_LAN_ZONES +%token VAR_INFRA_CACHE_MIN_RTT +%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL +%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH +%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION +%token VAR_DNSTAP_IDENTITY VAR_DNSTAP_VERSION +%token VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES +%token VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES +%token VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES +%token VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES +%token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES +%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES +%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT +%token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE +%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR +%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvar: serverstart contents_server | stubstart contents_stub | forwardstart contents_forward | pythonstart contents_py | - rcstart contents_rc + rcstart contents_rc | dtstart contents_dt ; /* server: declaration */ @@ -159,7 +177,16 @@ content_server: server_num_threads | server_verbosity | server_port | server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_tcp_upstream | server_ssl_upstream | - server_ssl_service_key | server_ssl_service_pem | server_ssl_port + server_ssl_service_key | server_ssl_service_pem | server_ssl_port | + server_minimal_responses | server_rrset_roundrobin | server_max_udp_size | + server_so_reuseport | server_delay_close | server_unblock_lan_zones | + server_dns64_prefix | server_dns64_synthall | + server_infra_cache_min_rtt | server_harden_algo_downgrade | + server_ip_transparent | server_ratelimit | server_ratelimit_slabs | + server_ratelimit_size | server_ratelimit_for_domain | + server_ratelimit_below_domain | server_ratelimit_factor | + server_caps_whitelist | server_cache_max_negative_ttl | + server_permit_small_holddown ; stubstart: VAR_STUB_ZONE { @@ -175,7 +202,7 @@ stubstart: VAR_STUB_ZONE ; contents_stub: contents_stub content_stub | ; -content_stub: stub_name | stub_host | stub_addr | stub_prime +content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first ; forwardstart: VAR_FORWARD_ZONE { @@ -191,7 +218,7 @@ forwardstart: VAR_FORWARD_ZONE ; contents_forward: contents_forward content_forward | ; -content_forward: forward_name | forward_host | forward_addr +content_forward: forward_name | forward_host | forward_addr | forward_first ; server_num_threads: VAR_NUM_THREADS STRING_ARG { @@ -592,6 +619,26 @@ server_so_sndbuf: VAR_SO_SNDBUF STRING_ARG free($2); } ; +server_so_reuseport: VAR_SO_REUSEPORT STRING_ARG + { + OUTYY(("P(server_so_reuseport:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->so_reuseport = + (strcmp($2, "yes")==0); + free($2); + } + ; +server_ip_transparent: VAR_IP_TRANSPARENT STRING_ARG + { + OUTYY(("P(server_ip_transparent:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->ip_transparent = + (strcmp($2, "yes")==0); + free($2); + } + ; server_edns_buffer_size: VAR_EDNS_BUFFER_SIZE STRING_ARG { OUTYY(("P(server_edns_buffer_size:%s)\n", $2)); @@ -655,6 +702,25 @@ server_jostle_timeout: VAR_JOSTLE_TIMEOUT STRING_ARG free($2); } ; +server_delay_close: VAR_DELAY_CLOSE STRING_ARG + { + OUTYY(("P(server_delay_close:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->delay_close = atoi($2); + free($2); + } + ; +server_unblock_lan_zones: VAR_UNBLOCK_LAN_ZONES STRING_ARG + { + OUTYY(("P(server_unblock_lan_zones:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->unblock_lan_zones = + (strcmp($2, "yes")==0); + free($2); + } + ; server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG { OUTYY(("P(server_rrset_cache_size:%s)\n", $2)); @@ -723,6 +789,15 @@ server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING_ARG free($2); } ; +server_infra_cache_min_rtt: VAR_INFRA_CACHE_MIN_RTT STRING_ARG + { + OUTYY(("P(server_infra_cache_min_rtt:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->infra_cache_min_rtt = atoi($2); + free($2); + } + ; server_target_fetch_policy: VAR_TARGET_FETCH_POLICY STRING_ARG { OUTYY(("P(server_target_fetch_policy:%s)\n", $2)); @@ -790,6 +865,16 @@ server_harden_referral_path: VAR_HARDEN_REFERRAL_PATH STRING_ARG free($2); } ; +server_harden_algo_downgrade: VAR_HARDEN_ALGO_DOWNGRADE STRING_ARG + { + OUTYY(("P(server_harden_algo_downgrade:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->harden_algo_downgrade = + (strcmp($2, "yes")==0); + free($2); + } + ; server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG { OUTYY(("P(server_use_caps_for_id:%s)\n", $2)); @@ -800,6 +885,13 @@ server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG free($2); } ; +server_caps_whitelist: VAR_CAPS_WHITELIST STRING_ARG + { + OUTYY(("P(server_caps_whitelist:%s)\n", $2)); + if(!cfg_strlist_insert(&cfg_parser->cfg->caps_whitelist, $2)) + yyerror("out of memory"); + } + ; server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG { OUTYY(("P(server_private_address:%s)\n", $2)); @@ -862,9 +954,12 @@ server_access_control: VAR_ACCESS_CONTROL STRING_ARG STRING_ARG { OUTYY(("P(server_access_control:%s %s)\n", $2, $3)); if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 && + strcmp($3, "deny_non_local")!=0 && + strcmp($3, "refuse_non_local")!=0 && strcmp($3, "allow")!=0 && strcmp($3, "allow_snoop")!=0) { - yyerror("expected deny, refuse, allow or allow_snoop " + yyerror("expected deny, refuse, deny_non_local, " + "refuse_non_local, allow or allow_snoop " "in access control action"); } else { if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3)) @@ -932,6 +1027,15 @@ server_cache_max_ttl: VAR_CACHE_MAX_TTL STRING_ARG free($2); } ; +server_cache_max_negative_ttl: VAR_CACHE_MAX_NEGATIVE_TTL STRING_ARG + { + OUTYY(("P(server_cache_max_negative_ttl:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->max_negative_ttl = atoi($2); + free($2); + } + ; server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG { OUTYY(("P(server_cache_min_ttl:%s)\n", $2)); @@ -1022,6 +1126,15 @@ server_keep_missing: VAR_KEEP_MISSING STRING_ARG free($2); } ; +server_permit_small_holddown: VAR_PERMIT_SMALL_HOLDDOWN STRING_ARG + { + OUTYY(("P(server_permit_small_holddown:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->permit_small_holddown = + (strcmp($2, "yes")==0); + free($2); + } server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG { OUTYY(("P(server_key_cache_size:%s)\n", $2)); @@ -1057,10 +1170,12 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 && strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0 - && strcmp($3, "typetransparent")!=0) + && strcmp($3, "typetransparent")!=0 && + strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0) yyerror("local-zone type: expected static, deny, " "refuse, redirect, transparent, " - "typetransparent or nodefault"); + "typetransparent, inform, inform_deny " + "or nodefault"); else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_nodefault, $2)) @@ -1095,6 +1210,114 @@ server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG } } ; +server_minimal_responses: VAR_MINIMAL_RESPONSES STRING_ARG + { + OUTYY(("P(server_minimal_responses:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->minimal_responses = + (strcmp($2, "yes")==0); + free($2); + } + ; +server_rrset_roundrobin: VAR_RRSET_ROUNDROBIN STRING_ARG + { + OUTYY(("P(server_rrset_roundrobin:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->rrset_roundrobin = + (strcmp($2, "yes")==0); + free($2); + } + ; +server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG + { + OUTYY(("P(server_max_udp_size:%s)\n", $2)); + cfg_parser->cfg->max_udp_size = atoi($2); + free($2); + } + ; +server_dns64_prefix: VAR_DNS64_PREFIX STRING_ARG + { + OUTYY(("P(dns64_prefix:%s)\n", $2)); + free(cfg_parser->cfg->dns64_prefix); + cfg_parser->cfg->dns64_prefix = $2; + } + ; +server_dns64_synthall: VAR_DNS64_SYNTHALL STRING_ARG + { + OUTYY(("P(server_dns64_synthall:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dns64_synthall = (strcmp($2, "yes")==0); + free($2); + } + ; +server_ratelimit: VAR_RATELIMIT STRING_ARG + { + OUTYY(("P(server_ratelimit:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->ratelimit = atoi($2); + free($2); + } + ; +server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG + { + OUTYY(("P(server_ratelimit_size:%s)\n", $2)); + if(!cfg_parse_memsize($2, &cfg_parser->cfg->ratelimit_size)) + yyerror("memory size expected"); + free($2); + } + ; +server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG + { + OUTYY(("P(server_ratelimit_slabs:%s)\n", $2)); + if(atoi($2) == 0) + yyerror("number expected"); + else { + cfg_parser->cfg->ratelimit_slabs = atoi($2); + if(!is_pow2(cfg_parser->cfg->ratelimit_slabs)) + yyerror("must be a power of 2"); + } + free($2); + } + ; +server_ratelimit_for_domain: VAR_RATELIMIT_FOR_DOMAIN STRING_ARG STRING_ARG + { + OUTYY(("P(server_ratelimit_for_domain:%s %s)\n", $2, $3)); + if(atoi($3) == 0 && strcmp($3, "0") != 0) { + yyerror("number expected"); + } else { + if(!cfg_str2list_insert(&cfg_parser->cfg-> + ratelimit_for_domain, $2, $3)) + fatal_exit("out of memory adding " + "ratelimit-for-domain"); + } + } + ; +server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG + { + OUTYY(("P(server_ratelimit_below_domain:%s %s)\n", $2, $3)); + if(atoi($3) == 0 && strcmp($3, "0") != 0) { + yyerror("number expected"); + } else { + if(!cfg_str2list_insert(&cfg_parser->cfg-> + ratelimit_below_domain, $2, $3)) + fatal_exit("out of memory adding " + "ratelimit-below-domain"); + } + } + ; +server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG + { + OUTYY(("P(server_ratelimit_factor:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->ratelimit_factor = atoi($2); + free($2); + } + ; stub_name: VAR_NAME STRING_ARG { OUTYY(("P(name:%s)\n", $2)); @@ -1119,6 +1342,15 @@ stub_addr: VAR_STUB_ADDR STRING_ARG yyerror("out of memory"); } ; +stub_first: VAR_STUB_FIRST STRING_ARG + { + OUTYY(("P(stub-first:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->stubs->isfirst=(strcmp($2, "yes")==0); + free($2); + } + ; stub_prime: VAR_STUB_PRIME STRING_ARG { OUTYY(("P(stub-prime:%s)\n", $2)); @@ -1153,6 +1385,15 @@ forward_addr: VAR_FORWARD_ADDR STRING_ARG yyerror("out of memory"); } ; +forward_first: VAR_FORWARD_FIRST STRING_ARG + { + OUTYY(("P(forward-first:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->forwards->isfirst=(strcmp($2, "yes")==0); + free($2); + } + ; rcstart: VAR_REMOTE_CONTROL { OUTYY(("\nP(remote-control:)\n")); @@ -1162,7 +1403,7 @@ contents_rc: contents_rc content_rc | ; content_rc: rc_control_enable | rc_control_interface | rc_control_port | rc_server_key_file | rc_server_cert_file | rc_control_key_file | - rc_control_cert_file + rc_control_cert_file | rc_control_use_cert ; rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG { @@ -1190,6 +1431,16 @@ rc_control_interface: VAR_CONTROL_INTERFACE STRING_ARG yyerror("out of memory"); } ; +rc_control_use_cert: VAR_CONTROL_USE_CERT STRING_ARG + { + OUTYY(("P(control_use_cert:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->remote_control_use_cert = + (strcmp($2, "yes")==0); + free($2); + } + ; rc_server_key_file: VAR_SERVER_KEY_FILE STRING_ARG { OUTYY(("P(rc_server_key_file:%s)\n", $2)); @@ -1218,6 +1469,122 @@ rc_control_cert_file: VAR_CONTROL_CERT_FILE STRING_ARG cfg_parser->cfg->control_cert_file = $2; } ; +dtstart: VAR_DNSTAP + { + OUTYY(("\nP(dnstap:)\n")); + } + ; +contents_dt: contents_dt content_dt + | ; +content_dt: dt_dnstap_enable | dt_dnstap_socket_path | + dt_dnstap_send_identity | dt_dnstap_send_version | + dt_dnstap_identity | dt_dnstap_version | + dt_dnstap_log_resolver_query_messages | + dt_dnstap_log_resolver_response_messages | + dt_dnstap_log_client_query_messages | + dt_dnstap_log_client_response_messages | + dt_dnstap_log_forwarder_query_messages | + dt_dnstap_log_forwarder_response_messages + ; +dt_dnstap_enable: VAR_DNSTAP_ENABLE STRING_ARG + { + OUTYY(("P(dt_dnstap_enable:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap = (strcmp($2, "yes")==0); + } + ; +dt_dnstap_socket_path: VAR_DNSTAP_SOCKET_PATH STRING_ARG + { + OUTYY(("P(dt_dnstap_socket_path:%s)\n", $2)); + free(cfg_parser->cfg->dnstap_socket_path); + cfg_parser->cfg->dnstap_socket_path = $2; + } + ; +dt_dnstap_send_identity: VAR_DNSTAP_SEND_IDENTITY STRING_ARG + { + OUTYY(("P(dt_dnstap_send_identity:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_send_identity = (strcmp($2, "yes")==0); + } + ; +dt_dnstap_send_version: VAR_DNSTAP_SEND_VERSION STRING_ARG + { + OUTYY(("P(dt_dnstap_send_version:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_send_version = (strcmp($2, "yes")==0); + } + ; +dt_dnstap_identity: VAR_DNSTAP_IDENTITY STRING_ARG + { + OUTYY(("P(dt_dnstap_identity:%s)\n", $2)); + free(cfg_parser->cfg->dnstap_identity); + cfg_parser->cfg->dnstap_identity = $2; + } + ; +dt_dnstap_version: VAR_DNSTAP_VERSION STRING_ARG + { + OUTYY(("P(dt_dnstap_version:%s)\n", $2)); + free(cfg_parser->cfg->dnstap_version); + cfg_parser->cfg->dnstap_version = $2; + } + ; +dt_dnstap_log_resolver_query_messages: VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_resolver_query_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_resolver_query_messages = + (strcmp($2, "yes")==0); + } + ; +dt_dnstap_log_resolver_response_messages: VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_resolver_response_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_resolver_response_messages = + (strcmp($2, "yes")==0); + } + ; +dt_dnstap_log_client_query_messages: VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_client_query_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_client_query_messages = + (strcmp($2, "yes")==0); + } + ; +dt_dnstap_log_client_response_messages: VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_client_response_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_client_response_messages = + (strcmp($2, "yes")==0); + } + ; +dt_dnstap_log_forwarder_query_messages: VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_forwarder_query_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_forwarder_query_messages = + (strcmp($2, "yes")==0); + } + ; +dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES STRING_ARG + { + OUTYY(("P(dt_dnstap_log_forwarder_response_messages:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->dnstap_log_forwarder_response_messages = + (strcmp($2, "yes")==0); + } + ; pythonstart: VAR_PYTHON { OUTYY(("\nP(python:)\n")); diff --git a/usr.sbin/unbound/util/data/msgencode.c b/usr.sbin/unbound/util/data/msgencode.c index a48a0a910b3..43464e9bbe0 100644 --- a/usr.sbin/unbound/util/data/msgencode.c +++ b/usr.sbin/unbound/util/data/msgencode.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -40,7 +40,6 @@ */ #include "config.h" -#include <ldns/wire2host.h> #include "util/data/msgencode.h" #include "util/data/msgreply.h" #include "util/data/msgparse.h" @@ -48,6 +47,7 @@ #include "util/log.h" #include "util/regional.h" #include "util/net_help.h" +#include "sldns/sbuffer.h" /** return code that means the function ran out of memory. negative so it does * not conflict with DNS rcodes. */ @@ -243,7 +243,7 @@ compress_tree_store(uint8_t* dname, int labs, size_t offset, /** compress a domain name */ static int -write_compressed_dname(ldns_buffer* pkt, uint8_t* dname, int labs, +write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs, struct compress_tree_node* p) { /* compress it */ @@ -253,37 +253,37 @@ write_compressed_dname(ldns_buffer* pkt, uint8_t* dname, int labs, if(labs == 1) { /* write root label */ - if(ldns_buffer_remaining(pkt) < 1) + if(sldns_buffer_remaining(pkt) < 1) return 0; - ldns_buffer_write_u8(pkt, 0); + sldns_buffer_write_u8(pkt, 0); return 1; } /* copy the first couple of labels */ while(labcopy--) { lablen = *dname++; - if(ldns_buffer_remaining(pkt) < (size_t)lablen+1) + if(sldns_buffer_remaining(pkt) < (size_t)lablen+1) return 0; - ldns_buffer_write_u8(pkt, lablen); - ldns_buffer_write(pkt, dname, lablen); + sldns_buffer_write_u8(pkt, lablen); + sldns_buffer_write(pkt, dname, lablen); dname += lablen; } /* insert compression ptr */ - if(ldns_buffer_remaining(pkt) < 2) + if(sldns_buffer_remaining(pkt) < 2) return 0; ptr = PTR_CREATE(p->offset); - ldns_buffer_write_u16(pkt, ptr); + sldns_buffer_write_u16(pkt, ptr); return 1; } /** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */ static int -compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, +compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, struct regional* region, struct compress_tree_node** tree, size_t owner_pos, uint16_t* owner_ptr, int owner_labs) { struct compress_tree_node* p; - struct compress_tree_node** insertpt; + struct compress_tree_node** insertpt = NULL; if(!*owner_ptr) { /* compress first time dname */ if((p = compress_tree_lookup(tree, key->rk.dname, @@ -296,13 +296,13 @@ compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, owner_labs, p)) return RETVAL_TRUNC; /* check if typeclass+4 ttl + rdatalen is available */ - if(ldns_buffer_remaining(pkt) < 4+4+2) + if(sldns_buffer_remaining(pkt) < 4+4+2) return RETVAL_TRUNC; } else { /* no compress */ - if(ldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2) + if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2) return RETVAL_TRUNC; - ldns_buffer_write(pkt, key->rk.dname, + sldns_buffer_write(pkt, key->rk.dname, key->rk.dname_len); if(owner_pos <= PTR_MAX_OFFSET) *owner_ptr = htons(PTR_CREATE(owner_pos)); @@ -313,13 +313,13 @@ compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, } else { /* always compress 2nd-further RRs in RRset */ if(owner_labs == 1) { - if(ldns_buffer_remaining(pkt) < 1+4+4+2) + if(sldns_buffer_remaining(pkt) < 1+4+4+2) return RETVAL_TRUNC; - ldns_buffer_write_u8(pkt, 0); + sldns_buffer_write_u8(pkt, 0); } else { - if(ldns_buffer_remaining(pkt) < 2+4+4+2) + if(sldns_buffer_remaining(pkt) < 2+4+4+2) return RETVAL_TRUNC; - ldns_buffer_write(pkt, owner_ptr, 2); + sldns_buffer_write(pkt, owner_ptr, 2); } } return RETVAL_OK; @@ -327,12 +327,12 @@ compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, /** compress any domain name to the packet, return RETVAL_* */ static int -compress_any_dname(uint8_t* dname, ldns_buffer* pkt, int labs, +compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs, struct regional* region, struct compress_tree_node** tree) { struct compress_tree_node* p; struct compress_tree_node** insertpt = NULL; - size_t pos = ldns_buffer_position(pkt); + size_t pos = sldns_buffer_position(pkt); if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) { if(!write_compressed_dname(pkt, dname, labs, p)) return RETVAL_TRUNC; @@ -346,27 +346,27 @@ compress_any_dname(uint8_t* dname, ldns_buffer* pkt, int labs, } /** return true if type needs domain name compression in rdata */ -static const ldns_rr_descriptor* +static const sldns_rr_descriptor* type_rdata_compressable(struct ub_packed_rrset_key* key) { uint16_t t = ntohs(key->rk.type); - if(ldns_rr_descript(t) && - ldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS) - return ldns_rr_descript(t); + if(sldns_rr_descript(t) && + sldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS) + return sldns_rr_descript(t); return 0; } /** compress domain names in rdata, return RETVAL_* */ static int -compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen, +compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, struct regional* region, struct compress_tree_node** tree, - const ldns_rr_descriptor* desc) + const sldns_rr_descriptor* desc) { int labs, r, rdf = 0; - size_t dname_len, len, pos = ldns_buffer_position(pkt); + size_t dname_len, len, pos = sldns_buffer_position(pkt); uint8_t count = desc->_dname_count; - ldns_buffer_skip(pkt, 2); /* rdata len fill in later */ + sldns_buffer_skip(pkt, 2); /* rdata len fill in later */ /* space for rdatalen checked for already */ rdata += 2; todolen -= 2; @@ -390,9 +390,9 @@ compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen, } if(len) { /* copy over */ - if(ldns_buffer_remaining(pkt) < len) + if(sldns_buffer_remaining(pkt) < len) return RETVAL_TRUNC; - ldns_buffer_write(pkt, rdata, len); + sldns_buffer_write(pkt, rdata, len); todolen -= len; rdata += len; } @@ -400,19 +400,19 @@ compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen, } /* copy remainder */ if(todolen > 0) { - if(ldns_buffer_remaining(pkt) < todolen) + if(sldns_buffer_remaining(pkt) < todolen) return RETVAL_TRUNC; - ldns_buffer_write(pkt, rdata, todolen); + sldns_buffer_write(pkt, rdata, todolen); } /* set rdata len */ - ldns_buffer_write_u16_at(pkt, pos, ldns_buffer_position(pkt)-pos-2); + sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2); return RETVAL_OK; } /** Returns true if RR type should be included */ static int -rrset_belongs_in_reply(ldns_pkt_section s, uint16_t rrtype, uint16_t qtype, +rrset_belongs_in_reply(sldns_pkt_section s, uint16_t rrtype, uint16_t qtype, int dnssec) { if(dnssec) @@ -440,12 +440,12 @@ rrset_belongs_in_reply(ldns_pkt_section s, uint16_t rrtype, uint16_t qtype, /** store rrset in buffer in wireformat, return RETVAL_* */ static int -packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, - uint16_t* num_rrs, uint32_t timenow, struct regional* region, +packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, + uint16_t* num_rrs, time_t timenow, struct regional* region, int do_data, int do_sig, struct compress_tree_node** tree, - ldns_pkt_section s, uint16_t qtype, int dnssec) + sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) { - size_t i, owner_pos; + size_t i, j, owner_pos; int r, owner_labs; uint16_t owner_ptr = 0; struct packed_rrset_data* data = (struct packed_rrset_data*) @@ -456,31 +456,33 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, return RETVAL_OK; owner_labs = dname_count_labels(key->rk.dname); - owner_pos = ldns_buffer_position(pkt); + owner_pos = sldns_buffer_position(pkt); if(do_data) { - const ldns_rr_descriptor* c = type_rdata_compressable(key); + const sldns_rr_descriptor* c = type_rdata_compressable(key); for(i=0; i<data->count; i++) { + /* rrset roundrobin */ + j = (i + rr_offset) % data->count; if((r=compress_owner(key, pkt, region, tree, owner_pos, &owner_ptr, owner_labs)) != RETVAL_OK) return r; - ldns_buffer_write(pkt, &key->rk.type, 2); - ldns_buffer_write(pkt, &key->rk.rrset_class, 2); - if(data->rr_ttl[i] < timenow) - ldns_buffer_write_u32(pkt, 0); - else ldns_buffer_write_u32(pkt, - data->rr_ttl[i]-timenow); + sldns_buffer_write(pkt, &key->rk.type, 2); + sldns_buffer_write(pkt, &key->rk.rrset_class, 2); + if(data->rr_ttl[j] < timenow) + sldns_buffer_write_u32(pkt, 0); + else sldns_buffer_write_u32(pkt, + data->rr_ttl[j]-timenow); if(c) { - if((r=compress_rdata(pkt, data->rr_data[i], - data->rr_len[i], region, tree, c)) + if((r=compress_rdata(pkt, data->rr_data[j], + data->rr_len[j], region, tree, c)) != RETVAL_OK) return r; } else { - if(ldns_buffer_remaining(pkt) < data->rr_len[i]) + if(sldns_buffer_remaining(pkt) < data->rr_len[j]) return RETVAL_TRUNC; - ldns_buffer_write(pkt, data->rr_data[i], - data->rr_len[i]); + sldns_buffer_write(pkt, data->rr_data[j], + data->rr_len[j]); } } } @@ -489,28 +491,28 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, size_t total = data->count+data->rrsig_count; for(i=data->count; i<total; i++) { if(owner_ptr && owner_labs != 1) { - if(ldns_buffer_remaining(pkt) < + if(sldns_buffer_remaining(pkt) < 2+4+4+data->rr_len[i]) return RETVAL_TRUNC; - ldns_buffer_write(pkt, &owner_ptr, 2); + sldns_buffer_write(pkt, &owner_ptr, 2); } else { if((r=compress_any_dname(key->rk.dname, pkt, owner_labs, region, tree)) != RETVAL_OK) return r; - if(ldns_buffer_remaining(pkt) < + if(sldns_buffer_remaining(pkt) < 4+4+data->rr_len[i]) return RETVAL_TRUNC; } - ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); - ldns_buffer_write(pkt, &key->rk.rrset_class, 2); + sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); + sldns_buffer_write(pkt, &key->rk.rrset_class, 2); if(data->rr_ttl[i] < timenow) - ldns_buffer_write_u32(pkt, 0); - else ldns_buffer_write_u32(pkt, + sldns_buffer_write_u32(pkt, 0); + else sldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow); /* rrsig rdata cannot be compressed, perform 100+ byte * memcopy. */ - ldns_buffer_write(pkt, data->rr_data[i], + sldns_buffer_write(pkt, data->rr_data[i], data->rr_len[i]); } } @@ -526,9 +528,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, /** store msg section in wireformat buffer, return RETVAL_* */ static int insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, - ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow, + sldns_buffer* pkt, size_t rrsets_before, time_t timenow, struct regional* region, struct compress_tree_node** tree, - ldns_pkt_section s, uint16_t qtype, int dnssec) + sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) { int r; size_t i, setstart; @@ -537,36 +539,36 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) dnssec = 1; /* include all types in ANY answer */ for(i=0; i<num_rrsets; i++) { - setstart = ldns_buffer_position(pkt); + setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 1, tree, - s, qtype, dnssec)) + s, qtype, dnssec, rr_offset)) != RETVAL_OK) { /* Bad, but if due to size must set TC bit */ /* trim off the rrset neatly. */ - ldns_buffer_set_position(pkt, setstart); + sldns_buffer_set_position(pkt, setstart); return r; } } } else { for(i=0; i<num_rrsets; i++) { - setstart = ldns_buffer_position(pkt); + setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 0, tree, - s, qtype, dnssec)) + s, qtype, dnssec, rr_offset)) != RETVAL_OK) { - ldns_buffer_set_position(pkt, setstart); + sldns_buffer_set_position(pkt, setstart); return r; } } if(dnssec) for(i=0; i<num_rrsets; i++) { - setstart = ldns_buffer_position(pkt); + setstart = sldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 0, 1, tree, - s, qtype, dnssec)) + s, qtype, dnssec, rr_offset)) != RETVAL_OK) { - ldns_buffer_set_position(pkt, setstart); + sldns_buffer_set_position(pkt, setstart); return r; } } @@ -577,44 +579,70 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, /** store query section in wireformat buffer, return RETVAL */ static int insert_query(struct query_info* qinfo, struct compress_tree_node** tree, - ldns_buffer* buffer, struct regional* region) + sldns_buffer* buffer, struct regional* region) { - if(ldns_buffer_remaining(buffer) < + if(sldns_buffer_remaining(buffer) < qinfo->qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ if(!compress_tree_store(qinfo->qname, dname_count_labels(qinfo->qname), - ldns_buffer_position(buffer), region, NULL, tree)) + sldns_buffer_position(buffer), region, NULL, tree)) return RETVAL_OUTMEM; - if(ldns_buffer_current(buffer) == qinfo->qname) - ldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len); - else ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); - ldns_buffer_write_u16(buffer, qinfo->qtype); - ldns_buffer_write_u16(buffer, qinfo->qclass); + if(sldns_buffer_current(buffer) == qinfo->qname) + sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len); + else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); + sldns_buffer_write_u16(buffer, qinfo->qtype); + sldns_buffer_write_u16(buffer, qinfo->qclass); return RETVAL_OK; } +static int +positive_answer(struct reply_info* rep, uint16_t qtype) { + size_t i; + if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR) + return 0; + + for(i=0;i<rep->an_numrrsets; i++) { + if(ntohs(rep->rrsets[i]->rk.type) == qtype) { + /* in case it is a wildcard with DNSSEC, there will + * be NSEC/NSEC3 records in the authority section + * that we cannot remove */ + for(i=rep->an_numrrsets; i<rep->an_numrrsets+ + rep->ns_numrrsets; i++) { + if(ntohs(rep->rrsets[i]->rk.type) == + LDNS_RR_TYPE_NSEC || + ntohs(rep->rrsets[i]->rk.type) == + LDNS_RR_TYPE_NSEC3) + return 0; + } + return 1; + } + } + return 0; +} + int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, - uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, + uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, struct regional* region, uint16_t udpsize, int dnssec) { uint16_t ancount=0, nscount=0, arcount=0; struct compress_tree_node* tree = 0; int r; + size_t rr_offset; - ldns_buffer_clear(buffer); - if(udpsize < ldns_buffer_limit(buffer)) - ldns_buffer_set_limit(buffer, udpsize); - if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) + sldns_buffer_clear(buffer); + if(udpsize < sldns_buffer_limit(buffer)) + sldns_buffer_set_limit(buffer, udpsize); + if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) return 0; - ldns_buffer_write(buffer, &id, sizeof(uint16_t)); - ldns_buffer_write_u16(buffer, flags); - ldns_buffer_write_u16(buffer, rep->qdcount); + sldns_buffer_write(buffer, &id, sizeof(uint16_t)); + sldns_buffer_write_u16(buffer, flags); + sldns_buffer_write_u16(buffer, rep->qdcount); /* set an, ns, ar counts to zero in case of small packets */ - ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); + sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); /* insert query section */ if(rep->qdcount) { @@ -622,60 +650,67 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ - ldns_buffer_write_u16_at(buffer, 4, 0); - LDNS_TC_SET(ldns_buffer_begin(buffer)); - ldns_buffer_flip(buffer); + sldns_buffer_write_u16_at(buffer, 4, 0); + LDNS_TC_SET(sldns_buffer_begin(buffer)); + sldns_buffer_flip(buffer); return 1; } return 0; } } + /* roundrobin offset. using query id for random number. With ntohs + * for different roundrobins for sequential id client senders. */ + rr_offset = RRSET_ROUNDROBIN?ntohs(id):0; /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, - dnssec)) != RETVAL_OK) { + dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ - ldns_buffer_write_u16_at(buffer, 6, ancount); - LDNS_TC_SET(ldns_buffer_begin(buffer)); - ldns_buffer_flip(buffer); + sldns_buffer_write_u16_at(buffer, 6, ancount); + LDNS_TC_SET(sldns_buffer_begin(buffer)); + sldns_buffer_flip(buffer); return 1; } return 0; } - ldns_buffer_write_u16_at(buffer, 6, ancount); - - /* insert auth section */ - if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, - rep->an_numrrsets, timenow, region, &tree, - LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* create truncated message */ - ldns_buffer_write_u16_at(buffer, 8, nscount); - LDNS_TC_SET(ldns_buffer_begin(buffer)); - ldns_buffer_flip(buffer); - return 1; + sldns_buffer_write_u16_at(buffer, 6, ancount); + + /* if response is positive answer, auth/add sections are not required */ + if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { + /* insert auth section */ + if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, + rep->an_numrrsets, timenow, region, &tree, + LDNS_SECTION_AUTHORITY, qinfo->qtype, + dnssec, rr_offset)) != RETVAL_OK) { + if(r == RETVAL_TRUNC) { + /* create truncated message */ + sldns_buffer_write_u16_at(buffer, 8, nscount); + LDNS_TC_SET(sldns_buffer_begin(buffer)); + sldns_buffer_flip(buffer); + return 1; + } + return 0; } - return 0; - } - ldns_buffer_write_u16_at(buffer, 8, nscount); + sldns_buffer_write_u16_at(buffer, 8, nscount); - /* insert add section */ - if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, - rep->an_numrrsets + rep->ns_numrrsets, timenow, region, - &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, - dnssec)) != RETVAL_OK) { - if(r == RETVAL_TRUNC) { - /* no need to set TC bit, this is the additional */ - ldns_buffer_write_u16_at(buffer, 10, arcount); - ldns_buffer_flip(buffer); - return 1; + /* insert add section */ + if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, + rep->an_numrrsets + rep->ns_numrrsets, timenow, region, + &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, + dnssec, rr_offset)) != RETVAL_OK) { + if(r == RETVAL_TRUNC) { + /* no need to set TC bit, this is the additional */ + sldns_buffer_write_u16_at(buffer, 10, arcount); + sldns_buffer_flip(buffer); + return 1; + } + return 0; } - return 0; + sldns_buffer_write_u16_at(buffer, 10, arcount); } - ldns_buffer_write_u16_at(buffer, 10, arcount); - ldns_buffer_flip(buffer); + sldns_buffer_flip(buffer); return 1; } @@ -689,31 +724,31 @@ calc_edns_field_size(struct edns_data* edns) } void -attach_edns_record(ldns_buffer* pkt, struct edns_data* edns) +attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) { size_t len; if(!edns || !edns->edns_present) return; /* inc additional count */ - ldns_buffer_write_u16_at(pkt, 10, - ldns_buffer_read_u16_at(pkt, 10) + 1); - len = ldns_buffer_limit(pkt); - ldns_buffer_clear(pkt); - ldns_buffer_set_position(pkt, len); + sldns_buffer_write_u16_at(pkt, 10, + sldns_buffer_read_u16_at(pkt, 10) + 1); + len = sldns_buffer_limit(pkt); + sldns_buffer_clear(pkt); + sldns_buffer_set_position(pkt, len); /* write EDNS record */ - ldns_buffer_write_u8(pkt, 0); /* '.' label */ - ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ - ldns_buffer_write_u16(pkt, edns->udp_size); /* class */ - ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ - ldns_buffer_write_u8(pkt, edns->edns_version); - ldns_buffer_write_u16(pkt, edns->bits); - ldns_buffer_write_u16(pkt, 0); /* rdatalen */ - ldns_buffer_flip(pkt); + sldns_buffer_write_u8(pkt, 0); /* '.' label */ + sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ + sldns_buffer_write_u16(pkt, edns->udp_size); /* class */ + sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ + sldns_buffer_write_u8(pkt, edns->edns_version); + sldns_buffer_write_u16(pkt, edns->bits); + sldns_buffer_write_u16(pkt, 0); /* rdatalen */ + sldns_buffer_flip(pkt); } int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, - uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow, + uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure) { @@ -751,54 +786,54 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, } void -qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo) +qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ - ldns_buffer_clear(pkt); - log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); - ldns_buffer_skip(pkt, 2); /* id done later */ - ldns_buffer_write_u16(pkt, flags); - ldns_buffer_write_u16(pkt, 1); /* query count */ - ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ - ldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); - ldns_buffer_write_u16(pkt, qinfo->qtype); - ldns_buffer_write_u16(pkt, qinfo->qclass); - ldns_buffer_flip(pkt); + sldns_buffer_clear(pkt); + log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); + sldns_buffer_skip(pkt, 2); /* id done later */ + sldns_buffer_write_u16(pkt, flags); + sldns_buffer_write_u16(pkt, 1); /* query count */ + sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ + sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); + sldns_buffer_write_u16(pkt, qinfo->qtype); + sldns_buffer_write_u16(pkt, qinfo->qclass); + sldns_buffer_flip(pkt); } void -error_encode(ldns_buffer* buf, int r, struct query_info* qinfo, +error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, uint16_t qid, uint16_t qflags, struct edns_data* edns) { uint16_t flags; - ldns_buffer_clear(buf); - ldns_buffer_write(buf, &qid, sizeof(uint16_t)); + sldns_buffer_clear(buf); + sldns_buffer_write(buf, &qid, sizeof(uint16_t)); flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ - ldns_buffer_write_u16(buf, flags); + sldns_buffer_write_u16(buf, flags); if(qinfo) flags = 1; else flags = 0; - ldns_buffer_write_u16(buf, flags); + sldns_buffer_write_u16(buf, flags); flags = 0; - ldns_buffer_write(buf, &flags, sizeof(uint16_t)); - ldns_buffer_write(buf, &flags, sizeof(uint16_t)); - ldns_buffer_write(buf, &flags, sizeof(uint16_t)); + sldns_buffer_write(buf, &flags, sizeof(uint16_t)); + sldns_buffer_write(buf, &flags, sizeof(uint16_t)); + sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { - if(ldns_buffer_current(buf) == qinfo->qname) - ldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); - else ldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); - ldns_buffer_write_u16(buf, qinfo->qtype); - ldns_buffer_write_u16(buf, qinfo->qclass); + if(sldns_buffer_current(buf) == qinfo->qname) + sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); + else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); + sldns_buffer_write_u16(buf, qinfo->qtype); + sldns_buffer_write_u16(buf, qinfo->qclass); } - ldns_buffer_flip(buf); + sldns_buffer_flip(buf); if(edns) { struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = 0; es.bits &= EDNS_DO; - if(ldns_buffer_limit(buf) + calc_edns_field_size(&es) > + if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > edns->udp_size) return; attach_edns_record(buf, &es); diff --git a/usr.sbin/unbound/util/iana_ports.inc b/usr.sbin/unbound/util/iana_ports.inc index 86264e11544..47496fc8d2f 100644 --- a/usr.sbin/unbound/util/iana_ports.inc +++ b/usr.sbin/unbound/util/iana_ports.inc @@ -33,7 +33,6 @@ 48, 49, 50, -51, 52, 53, 54, @@ -651,6 +650,7 @@ 780, 800, 801, +802, 810, 828, 829, @@ -660,6 +660,7 @@ 833, 847, 848, +853, 860, 861, 862, @@ -692,10 +693,8 @@ 1022, 1025, 1026, +1027, 1029, -1030, -1031, -1032, 1033, 1034, 1035, @@ -894,6 +893,7 @@ 1229, 1230, 1231, +1232, 1233, 1234, 1235, @@ -937,7 +937,6 @@ 1273, 1274, 1275, -1276, 1277, 1278, 1279, @@ -1068,7 +1067,6 @@ 1404, 1405, 1406, -1407, 1408, 1409, 1410, @@ -1303,6 +1301,7 @@ 1641, 1642, 1643, +1644, 1645, 1646, 1647, @@ -2017,7 +2016,6 @@ 2367, 2368, 2370, -2371, 2372, 2381, 2382, @@ -2046,7 +2044,6 @@ 2405, 2406, 2407, -2408, 2409, 2410, 2411, @@ -2064,6 +2061,7 @@ 2423, 2424, 2425, +2426, 2427, 2428, 2429, @@ -2201,6 +2199,7 @@ 2561, 2562, 2563, +2564, 2565, 2566, 2567, @@ -2487,7 +2486,6 @@ 2852, 2853, 2854, -2855, 2856, 2857, 2858, @@ -3064,6 +3062,7 @@ 3451, 3452, 3453, +3454, 3455, 3456, 3457, @@ -3443,7 +3442,6 @@ 3838, 3839, 3840, -3841, 3842, 3843, 3844, @@ -3793,11 +3791,11 @@ 4321, 4322, 4323, -4324, 4325, 4326, 4327, 4328, +4333, 4340, 4341, 4342, @@ -3820,6 +3818,7 @@ 4359, 4361, 4362, +4366, 4368, 4369, 4370, @@ -3842,9 +3841,12 @@ 4404, 4405, 4406, +4412, +4413, 4425, 4426, 4430, +4432, 4441, 4442, 4443, @@ -3867,6 +3869,7 @@ 4486, 4488, 4500, +4534, 4535, 4536, 4537, @@ -3954,12 +3957,17 @@ 4743, 4744, 4745, +4747, 4749, 4750, 4751, 4752, +4753, 4784, 4785, +4789, +4790, +4791, 4800, 4801, 4802, @@ -3997,6 +4005,7 @@ 4899, 4900, 4914, +4936, 4937, 4940, 4941, @@ -4007,6 +4016,7 @@ 4952, 4969, 4970, +4980, 4986, 4987, 4988, @@ -4049,6 +4059,7 @@ 5050, 5051, 5052, +5053, 5055, 5056, 5057, @@ -4067,6 +4078,7 @@ 5072, 5073, 5074, +5078, 5079, 5080, 5081, @@ -4086,6 +4098,7 @@ 5111, 5112, 5116, +5120, 5133, 5136, 5137, @@ -4150,6 +4163,7 @@ 5315, 5343, 5344, +5349, 5350, 5351, 5352, @@ -4164,6 +4178,7 @@ 5361, 5362, 5363, +5364, 5397, 5398, 5399, @@ -4215,6 +4230,7 @@ 5463, 5464, 5465, +5474, 5500, 5501, 5502, @@ -4228,6 +4244,7 @@ 5556, 5567, 5568, +5569, 5573, 5580, 5581, @@ -4252,6 +4269,7 @@ 5632, 5633, 5634, +5670, 5671, 5672, 5673, @@ -4265,6 +4283,8 @@ 5681, 5682, 5683, +5684, +5687, 5688, 5689, 5713, @@ -4341,11 +4361,14 @@ 6072, 6073, 6074, +6080, +6081, 6082, 6083, 6085, 6086, 6087, +6088, 6100, 6101, 6102, @@ -4359,6 +4382,7 @@ 6110, 6111, 6112, +6118, 6122, 6123, 6124, @@ -4378,6 +4402,8 @@ 6162, 6163, 6200, +6201, +6209, 6222, 6241, 6242, @@ -4393,6 +4419,7 @@ 6306, 6315, 6316, +6317, 6320, 6321, 6322, @@ -4403,17 +4430,20 @@ 6350, 6355, 6360, +6363, 6370, 6382, 6389, 6390, 6417, +6419, 6420, 6421, 6443, 6444, 6445, 6446, +6455, 6456, 6471, 6480, @@ -4436,6 +4466,7 @@ 6508, 6509, 6510, +6511, 6514, 6515, 6543, @@ -4461,6 +4492,11 @@ 6626, 6627, 6628, +6633, +6634, +6635, +6636, +6653, 6657, 6670, 6671, @@ -4480,6 +4516,7 @@ 6769, 6770, 6771, +6784, 6785, 6786, 6787, @@ -4532,9 +4569,11 @@ 7024, 7025, 7030, +7040, 7070, 7071, 7080, +7095, 7099, 7100, 7101, @@ -4552,9 +4591,11 @@ 7170, 7171, 7174, +7181, 7200, 7201, 7227, +7235, 7262, 7272, 7273, @@ -4578,6 +4619,7 @@ 7401, 7402, 7410, +7411, 7421, 7426, 7427, @@ -4605,6 +4647,7 @@ 7560, 7566, 7570, +7574, 7588, 7624, 7627, @@ -4626,6 +4669,7 @@ 7725, 7726, 7727, +7728, 7734, 7738, 7741, @@ -4636,6 +4680,7 @@ 7778, 7779, 7781, +7784, 7786, 7787, 7789, @@ -4645,9 +4690,11 @@ 7799, 7800, 7801, +7802, 7810, 7845, 7846, +7872, 7880, 7887, 7900, @@ -4657,6 +4704,7 @@ 7913, 7932, 7933, +7962, 7967, 7979, 7980, @@ -4687,6 +4735,7 @@ 8057, 8058, 8059, +8060, 8074, 8080, 8081, @@ -4735,6 +4784,7 @@ 8301, 8320, 8321, +8322, 8351, 8376, 8377, @@ -4742,6 +4792,7 @@ 8379, 8380, 8383, +8384, 8400, 8401, 8402, @@ -4751,28 +4802,32 @@ 8442, 8443, 8444, +8445, 8450, 8472, 8473, 8474, 8500, 8501, +8503, 8554, 8555, 8567, 8600, +8609, 8610, 8611, 8612, 8613, 8614, +8675, 8686, -8699, 8732, 8733, 8763, 8764, 8765, +8766, 8770, 8786, 8787, @@ -4797,6 +4852,8 @@ 8912, 8913, 8954, +8980, +8981, 8989, 8990, 8991, @@ -4804,6 +4861,7 @@ 9000, 9001, 9002, +9006, 9007, 9009, 9020, @@ -4858,6 +4916,7 @@ 9217, 9222, 9255, +9277, 9278, 9279, 9280, @@ -4921,7 +4980,7 @@ 9801, 9802, 9875, -9876, +9878, 9888, 9889, 9898, @@ -4935,6 +4994,7 @@ 9951, 9952, 9953, +9955, 9956, 9966, 9987, @@ -4955,6 +5015,7 @@ 10007, 10008, 10009, +10023, 10050, 10051, 10080, @@ -4979,8 +5040,10 @@ 10200, 10201, 10252, +10253, 10260, 10288, +10439, 10500, 10540, 10541, @@ -4991,10 +5054,13 @@ 10805, 10810, 10860, +10880, 10990, 11000, 11001, +11095, 11106, +11108, 11111, 11112, 11161, @@ -5011,9 +5077,12 @@ 11321, 11367, 11371, +11430, 11600, 11720, +11723, 11751, +11796, 11876, 11877, 11967, @@ -5026,6 +5095,7 @@ 12006, 12007, 12008, +12009, 12012, 12013, 12109, @@ -5057,9 +5127,11 @@ 13820, 13821, 13822, +13894, 13929, 14000, 14001, +14002, 14033, 14034, 14141, @@ -5100,8 +5172,11 @@ 17007, 17185, 17219, +17220, 17221, 17222, +17224, +17225, 17234, 17235, 17500, @@ -5126,6 +5201,7 @@ 18881, 18888, 19000, +19007, 19191, 19194, 19283, @@ -5137,6 +5213,7 @@ 19539, 19540, 19541, +19788, 19999, 20000, 20001, @@ -5172,6 +5249,7 @@ 22005, 22273, 22305, +22335, 22343, 22347, 22350, @@ -5200,13 +5278,16 @@ 24242, 24249, 24321, +24322, 24386, 24465, 24554, +24577, 24676, 24677, 24678, 24680, +24850, 24922, 25000, 25001, @@ -5223,6 +5304,8 @@ 25901, 25902, 25903, +25954, +25955, 26000, 26133, 26208, @@ -5239,11 +5322,16 @@ 27782, 27999, 28000, +28119, +28200, 28240, 29167, 30001, 30002, +30003, +30004, 30260, +30832, 30999, 31029, 31416, @@ -5272,6 +5360,7 @@ 32896, 33123, 33331, +33334, 33434, 33656, 34249, @@ -5281,11 +5370,15 @@ 34963, 34964, 34980, +35001, +35004, 35355, 36001, +36411, 36865, 37475, 37654, +38002, 38201, 38202, 38203, @@ -5296,23 +5389,27 @@ 40843, 40853, 41111, +41230, 41794, 41795, 42508, 42509, 42510, +43000, 43188, 43189, 43190, +43210, +43439, 43440, 43441, 44321, 44322, -44323, 44544, 44553, 44600, 44818, +44900, 45000, 45054, 45678, @@ -5320,10 +5417,12 @@ 45966, 46999, 47000, +47100, 47557, 47624, 47806, 47808, +47809, 48000, 48001, 48002, @@ -5332,3 +5431,4 @@ 48129, 48556, 48619, +48653, diff --git a/usr.sbin/unbound/util/net_help.c b/usr.sbin/unbound/util/net_help.c index b3d104067b9..eb03cd0ae6d 100644 --- a/usr.sbin/unbound/util/net_help.c +++ b/usr.sbin/unbound/util/net_help.c @@ -631,9 +631,9 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem) SSL_CTX_free(ctx); return NULL; } - if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { + if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error for cert file: %s", pem); - log_crypto_err("error in SSL_CTX use_certificate_file"); + log_crypto_err("error in SSL_CTX use_certificate_chain_file"); SSL_CTX_free(ctx); return NULL; } @@ -649,6 +649,23 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem) SSL_CTX_free(ctx); return NULL; } +#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + if(!SSL_CTX_set_ecdh_auto(ctx,1)) { + log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); + } +#elif defined(USE_ECDSA) + if(1) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); + if (!ecdh) { + log_crypto_err("could not find p256, not enabling ECDHE"); + } else { + if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { + log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); + } + EC_KEY_free (ecdh); + } + } +#endif if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { @@ -688,7 +705,7 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem) return NULL; } if(key && key[0]) { - if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { + if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error in client certificate %s", pem); log_crypto_err("error in certificate file"); SSL_CTX_free(ctx); diff --git a/usr.sbin/unbound/validator/autotrust.c b/usr.sbin/unbound/validator/autotrust.c index 8c3a7c67221..e63b086e6a0 100644 --- a/usr.sbin/unbound/validator/autotrust.c +++ b/usr.sbin/unbound/validator/autotrust.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -41,7 +41,6 @@ * It was modified to fit into unbound. The state table process is the same. */ #include "config.h" -#include <ldns/ldns.h> #include "validator/autotrust.h" #include "validator/val_anchor.h" #include "validator/val_utils.h" @@ -58,6 +57,13 @@ #include "services/mesh.h" #include "services/cache/rrset.h" #include "validator/val_kcache.h" +#include "sldns/sbuffer.h" +#include "sldns/wire2str.h" +#include "sldns/str2wire.h" +#include "sldns/keyraw.h" +#include "sldns/rrdef.h" +#include <stdarg.h> +#include <ctype.h> /** number of times a key must be seen before it can become valid */ #define MIN_PENDINGCOUNT 2 @@ -138,8 +144,11 @@ verbose_key(struct autr_ta* ta, enum verbosity_value level, va_list args; va_start(args, format); if(verbosity >= level) { - char* str = ldns_rdf2str(ldns_rr_owner(ta->rr)); - int keytag = (int)ldns_calc_keytag(ta->rr); + char* str = sldns_wire2str_dname(ta->rr, ta->dname_len); + int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata( + ta->rr, ta->rr_len, ta->dname_len), + sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, + ta->dname_len)); char msg[MAXSYSLOGMSGLEN]; vsnprintf(msg, sizeof(msg), format, args); verbose(level, "%s key %d %s", str?str:"??", keytag, msg); @@ -242,7 +251,7 @@ parse_comments(char* str, struct autr_ta* ta) if (pos < 0 || !timestamp) ta->last_change = 0; else - ta->last_change = (uint32_t)timestamp; + ta->last_change = (time_t)timestamp; free(comment); return 1; @@ -262,55 +271,76 @@ str_contains_data(char* str, char comment) return 0; } -/** Get DNSKEY flags */ +/** Get DNSKEY flags + * rdata without rdatalen in front of it. */ static int -dnskey_flags(ldns_rr* rr) +dnskey_flags(uint16_t t, uint8_t* rdata, size_t len) { - if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) + uint16_t f; + if(t != LDNS_RR_TYPE_DNSKEY) return 0; - return (int)ldns_read_uint16(ldns_rdf_data(ldns_rr_dnskey_flags(rr))); + if(len < 2) + return 0; + memmove(&f, rdata, 2); + f = ntohs(f); + return (int)f; } +/** Check if KSK DNSKEY. + * pass rdata without rdatalen in front of it */ +static int +rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len) +{ + return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP); +} -/** Check if KSK DNSKEY */ +/** Check if TA is KSK DNSKEY */ static int -rr_is_dnskey_sep(ldns_rr* rr) +ta_is_dnskey_sep(struct autr_ta* ta) { - return (dnskey_flags(rr)&DNSKEY_BIT_SEP); + return (dnskey_flags( + sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len), + sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len), + sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) + ) & DNSKEY_BIT_SEP); } -/** Check if REVOKED DNSKEY */ +/** Check if REVOKED DNSKEY + * pass rdata without rdatalen in front of it */ static int -rr_is_dnskey_revoked(ldns_rr* rr) +rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len) { - return (dnskey_flags(rr)&LDNS_KEY_REVOKE_KEY); + return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY); } /** create ta */ static struct autr_ta* -autr_ta_create(ldns_rr* rr) +autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len) { struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta)); if(!ta) { - ldns_rr_free(rr); + free(rr); return NULL; } ta->rr = rr; + ta->rr_len = rr_len; + ta->dname_len = dname_len; return ta; } /** create tp */ static struct trust_anchor* -autr_tp_create(struct val_anchors* anchors, ldns_rdf* own, uint16_t dc) +autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len, + uint16_t dc) { struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp)); if(!tp) return NULL; - tp->name = memdup(ldns_rdf_data(own), ldns_rdf_size(own)); + tp->name = memdup(own, own_len); if(!tp->name) { free(tp); return NULL; } - tp->namelen = ldns_rdf_size(own); + tp->namelen = own_len; tp->namelabs = dname_count_labels(tp->name); tp->node.key = tp; tp->dclass = dc; @@ -371,7 +401,7 @@ void autr_point_delete(struct trust_anchor* tp) struct autr_ta* p = tp->autr->keys, *np; while(p) { np = p->next; - ldns_rr_free(p->rr); + free(p->rr); free(p); p = np; } @@ -384,13 +414,12 @@ void autr_point_delete(struct trust_anchor* tp) /** find or add a new trust point for autotrust */ static struct trust_anchor* -find_add_tp(struct val_anchors* anchors, ldns_rr* rr) +find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, + size_t dname_len) { struct trust_anchor* tp; - ldns_rdf* own = ldns_rr_owner(rr); - tp = anchor_find(anchors, ldns_rdf_data(own), - dname_count_labels(ldns_rdf_data(own)), - ldns_rdf_size(own), ldns_rr_get_class(rr)); + tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len, + sldns_wirerr_get_class(rr, rr_len, dname_len)); if(tp) { if(!tp->autr) { log_err("anchor cannot be with and without autotrust"); @@ -399,22 +428,23 @@ find_add_tp(struct val_anchors* anchors, ldns_rr* rr) } return tp; } - tp = autr_tp_create(anchors, ldns_rr_owner(rr), ldns_rr_get_class(rr)); + tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr, + rr_len, dname_len)); lock_basic_lock(&tp->lock); return tp; } /** Add trust anchor from RR */ static struct autr_ta* -add_trustanchor_frm_rr(struct val_anchors* anchors, ldns_rr* rr, - struct trust_anchor** tp) +add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, + size_t dname_len, struct trust_anchor** tp) { - struct autr_ta* ta = autr_ta_create(rr); + struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len); if(!ta) return NULL; - *tp = find_add_tp(anchors, rr); + *tp = find_add_tp(anchors, rr, rr_len, dname_len); if(!*tp) { - ldns_rr_free(ta->rr); + free(ta->rr); free(ta); return NULL; } @@ -431,34 +461,51 @@ add_trustanchor_frm_rr(struct val_anchors* anchors, ldns_rr* rr, * @param str: string with anchor and comments, if any comments. * @param tp: trust point returned. * @param origin: what to use for @ + * @param origin_len: length of origin * @param prev: previous rr name + * @param prev_len: length of prev * @param skip: if true, the result is NULL, but not an error, skip it. * @return new key in trust point. */ static struct autr_ta* add_trustanchor_frm_str(struct val_anchors* anchors, char* str, - struct trust_anchor** tp, ldns_rdf* origin, ldns_rdf** prev, int* skip) + struct trust_anchor** tp, uint8_t* origin, size_t origin_len, + uint8_t** prev, size_t* prev_len, int* skip) { - ldns_rr* rr; - ldns_status lstatus; + uint8_t rr[LDNS_RR_BUF_SIZE]; + size_t rr_len = sizeof(rr), dname_len; + uint8_t* drr; + int lstatus; if (!str_contains_data(str, ';')) { *skip = 1; return NULL; /* empty line */ } - if (LDNS_STATUS_OK != - (lstatus = ldns_rr_new_frm_str(&rr, str, 0, origin, prev))) - { - log_err("ldns error while converting string to RR: %s", - ldns_get_errorstr_by_id(lstatus)); - return NULL; - } - if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY && - ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS) { - ldns_rr_free(rr); + if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len, + 0, origin, origin_len, *prev, *prev_len))) + { + log_err("ldns error while converting string to RR at%d: %s: %s", + LDNS_WIREPARSE_OFFSET(lstatus), + sldns_get_errorstr_parse(lstatus), str); + return NULL; + } + free(*prev); + *prev = memdup(rr, dname_len); + *prev_len = dname_len; + if(!*prev) { + log_err("malloc failure in add_trustanchor"); + return NULL; + } + if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY && + sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) { *skip = 1; return NULL; /* only DS and DNSKEY allowed */ } - return add_trustanchor_frm_rr(anchors, rr, tp); + drr = memdup(rr, rr_len); + if(!drr) { + log_err("malloc failure in add trustanchor"); + return NULL; + } + return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp); } /** @@ -466,19 +513,23 @@ add_trustanchor_frm_str(struct val_anchors* anchors, char* str, * @param anchors: all points. * @param str: comments line * @param fname: filename - * @param origin: $ORIGIN. + * @param origin: the $ORIGIN. + * @param origin_len: length of origin * @param prev: passed to ldns. + * @param prev_len: length of prev * @param skip: if true, the result is NULL, but not an error, skip it. * @return false on failure, otherwise the tp read. */ static struct trust_anchor* load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, - ldns_rdf* origin, ldns_rdf** prev, int* skip) + uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, + int* skip) { - struct autr_ta* ta = NULL; - struct trust_anchor* tp = NULL; + struct autr_ta* ta = NULL; + struct trust_anchor* tp = NULL; - ta = add_trustanchor_frm_str(anchors, str, &tp, origin, prev, skip); + ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len, + prev, prev_len, skip); if(!ta) return NULL; lock_basic_lock(&tp->lock); @@ -498,70 +549,228 @@ load_trustanchor(struct val_anchors* anchors, char* str, const char* fname, return tp; } +/** iterator for DSes from keylist. return true if a next element exists */ +static int +assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len, + size_t* dname_len) +{ + while(*list) { + if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, + (*list)->dname_len) == LDNS_RR_TYPE_DS) { + *rr = (*list)->rr; + *rr_len = (*list)->rr_len; + *dname_len = (*list)->dname_len; + *list = (*list)->next; + return 1; + } + *list = (*list)->next; + } + return 0; +} + +/** iterator for DNSKEYs from keylist. return true if a next element exists */ +static int +assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len, + size_t* dname_len) +{ + while(*list) { + if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, + (*list)->dname_len) != LDNS_RR_TYPE_DS && + ((*list)->s == AUTR_STATE_VALID || + (*list)->s == AUTR_STATE_MISSING)) { + *rr = (*list)->rr; + *rr_len = (*list)->rr_len; + *dname_len = (*list)->dname_len; + *list = (*list)->next; + return 1; + } + *list = (*list)->next; + } + return 0; +} + +/** see if iterator-list has any elements in it, or it is empty */ +static int +assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*, + size_t*), struct autr_ta* list) +{ + uint8_t* rr = NULL; + size_t rr_len = 0, dname_len = 0; + return iter(&list, &rr, &rr_len, &dname_len); +} + +/** number of elements in iterator list */ +static size_t +assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*, + size_t*), struct autr_ta* list) +{ + uint8_t* rr = NULL; + size_t i = 0, rr_len = 0, dname_len = 0; + while(iter(&list, &rr, &rr_len, &dname_len)) { + i++; + } + return i; +} + +/** + * Create a ub_packed_rrset_key allocated on the heap. + * It therefore does not have the correct ID value, and cannot be used + * inside the cache. It can be used in storage outside of the cache. + * Keys for the cache have to be obtained from alloc.h . + * @param iter: iterator over the elements in the list. It filters elements. + * @param list: the list. + * @return key allocated or NULL on failure. + */ +static struct ub_packed_rrset_key* +ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*, + size_t*), struct autr_ta* list) +{ + uint8_t* rr = NULL; + size_t rr_len = 0, dname_len = 0; + struct ub_packed_rrset_key* k; + if(!iter(&list, &rr, &rr_len, &dname_len)) + return NULL; + k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k)); + if(!k) + return NULL; + k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); + k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); + k->rk.dname_len = dname_len; + k->rk.dname = memdup(rr, dname_len); + if(!k->rk.dname) { + free(k); + return NULL; + } + return k; +} + +/** + * Create packed_rrset data on the heap. + * @param iter: iterator over the elements in the list. It filters elements. + * @param list: the list. + * @return data allocated or NULL on failure. + */ +static struct packed_rrset_data* +packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*, + size_t*), struct autr_ta* list) +{ + uint8_t* rr = NULL; + size_t rr_len = 0, dname_len = 0; + struct packed_rrset_data* data; + size_t count=0, rrsig_count=0, len=0, i, total; + uint8_t* nextrdata; + struct autr_ta* list_i; + time_t ttl = 0; + + list_i = list; + while(iter(&list_i, &rr, &rr_len, &dname_len)) { + if(sldns_wirerr_get_type(rr, rr_len, dname_len) == + LDNS_RR_TYPE_RRSIG) + rrsig_count++; + else count++; + /* sizeof the rdlength + rdatalen */ + len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); + ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len); + } + if(count == 0 && rrsig_count == 0) + return NULL; + + /* allocate */ + total = count + rrsig_count; + len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) + + sizeof(uint8_t*)); + data = (struct packed_rrset_data*)calloc(1, len); + if(!data) + return NULL; + + /* fill it */ + data->ttl = ttl; + data->count = count; + data->rrsig_count = rrsig_count; + data->rr_len = (size_t*)((uint8_t*)data + + sizeof(struct packed_rrset_data)); + data->rr_data = (uint8_t**)&(data->rr_len[total]); + data->rr_ttl = (time_t*)&(data->rr_data[total]); + nextrdata = (uint8_t*)&(data->rr_ttl[total]); + + /* fill out len, ttl, fields */ + list_i = list; + i = 0; + while(iter(&list_i, &rr, &rr_len, &dname_len)) { + data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, + dname_len); + if(data->rr_ttl[i] < data->ttl) + data->ttl = data->rr_ttl[i]; + data->rr_len[i] = 2 /* the rdlength */ + + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); + i++; + } + + /* fixup rest of ptrs */ + for(i=0; i<total; i++) { + data->rr_data[i] = nextrdata; + nextrdata += data->rr_len[i]; + } + + /* copy data in there */ + list_i = list; + i = 0; + while(iter(&list_i, &rr, &rr_len, &dname_len)) { + memmove(data->rr_data[i], + sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), + data->rr_len[i]); + i++; + } + + if(data->rrsig_count && data->count == 0) { + data->count = data->rrsig_count; /* rrset type is RRSIG */ + data->rrsig_count = 0; + } + return data; +} + /** * Assemble the trust anchors into DS and DNSKEY packed rrsets. * Uses only VALID and MISSING DNSKEYs. - * Read the ldns_rrs and builds packed rrsets + * Read the sldns_rrs and builds packed rrsets * @param tp: the trust point. Must be locked. * @return false on malloc failure. */ static int autr_assemble(struct trust_anchor* tp) { - ldns_rr_list* ds, *dnskey; - struct autr_ta* ta; struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL; - ds = ldns_rr_list_new(); - dnskey = ldns_rr_list_new(); - if(!ds || !dnskey) { - ldns_rr_list_free(ds); - ldns_rr_list_free(dnskey); - return 0; - } - for(ta = tp->autr->keys; ta; ta = ta->next) { - if(ldns_rr_get_type(ta->rr) == LDNS_RR_TYPE_DS) { - if(!ldns_rr_list_push_rr(ds, ta->rr)) { - ldns_rr_list_free(ds); - ldns_rr_list_free(dnskey); - return 0; - } - } else if(ta->s == AUTR_STATE_VALID || - ta->s == AUTR_STATE_MISSING) { - if(!ldns_rr_list_push_rr(dnskey, ta->rr)) { - ldns_rr_list_free(ds); - ldns_rr_list_free(dnskey); - return 0; - } - } - } - /* make packed rrset keys - malloced with no ID number, they * are not in the cache */ /* make packed rrset data (if there is a key) */ - - if(ldns_rr_list_rr_count(ds) > 0) { - ubds = ub_packed_rrset_heap_key(ds); - if(!ubds) + if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) { + ubds = ub_packed_rrset_heap_key( + assemble_iterate_ds, tp->autr->keys); + if(!ubds) goto error_cleanup; - ubds->entry.data = packed_rrset_heap_data(ds); + ubds->entry.data = packed_rrset_heap_data( + assemble_iterate_ds, tp->autr->keys); if(!ubds->entry.data) goto error_cleanup; } - if(ldns_rr_list_rr_count(dnskey) > 0) { - ubdnskey = ub_packed_rrset_heap_key(dnskey); + + /* make packed DNSKEY data */ + if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) { + ubdnskey = ub_packed_rrset_heap_key( + assemble_iterate_dnskey, tp->autr->keys); if(!ubdnskey) goto error_cleanup; - ubdnskey->entry.data = packed_rrset_heap_data(dnskey); + ubdnskey->entry.data = packed_rrset_heap_data( + assemble_iterate_dnskey, tp->autr->keys); if(!ubdnskey->entry.data) { error_cleanup: autr_rrset_delete(ubds); autr_rrset_delete(ubdnskey); - ldns_rr_list_free(ds); - ldns_rr_list_free(dnskey); return 0; } } + /* we have prepared the new keys so nothing can go wrong any more. * And we are sure we cannot be left without trustanchor after * any errors. Put in the new keys and remove old ones. */ @@ -573,11 +782,10 @@ autr_assemble(struct trust_anchor* tp) /* assign the data to replace the old */ tp->ds_rrset = ubds; tp->dnskey_rrset = ubdnskey; - tp->numDS = ldns_rr_list_rr_count(ds); - tp->numDNSKEY = ldns_rr_list_rr_count(dnskey); - - ldns_rr_list_free(ds); - ldns_rr_list_free(dnskey); + tp->numDS = assemble_iterate_count(assemble_iterate_ds, + tp->autr->keys); + tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey, + tp->autr->keys); return 1; } @@ -601,27 +809,28 @@ parse_id(struct val_anchors* anchors, char* line) { struct trust_anchor *tp; int r; - ldns_rdf* rdf; uint16_t dclass; + uint8_t* dname; + size_t dname_len; /* read the owner name */ char* next = strchr(line, ' '); if(!next) return NULL; next[0] = 0; - rdf = ldns_dname_new_frm_str(line); - if(!rdf) + dname = sldns_str2wire_dname(line, &dname_len); + if(!dname) return NULL; /* read the class */ dclass = parse_int(next+1, &r); if(r == -1) { - ldns_rdf_deep_free(rdf); + free(dname); return NULL; } /* find the trust point */ - tp = autr_tp_create(anchors, rdf, dclass); - ldns_rdf_deep_free(rdf); + tp = autr_tp_create(anchors, dname, dname_len, dclass); + free(dname); return tp; } @@ -677,12 +886,12 @@ parse_var_line(char* line, struct val_anchors* anchors, } else if(strncmp(line, ";;query_interval: ", 18) == 0) { if(!tp) return -1; lock_basic_lock(&tp->lock); - tp->autr->query_interval = (uint32_t)parse_int(line+18, &r); + tp->autr->query_interval = (time_t)parse_int(line+18, &r); lock_basic_unlock(&tp->lock); } else if(strncmp(line, ";;retry_time: ", 14) == 0) { if(!tp) return -1; lock_basic_lock(&tp->lock); - tp->autr->retry_time = (uint32_t)parse_int(line+14, &r); + tp->autr->retry_time = (time_t)parse_int(line+14, &r); lock_basic_unlock(&tp->lock); } return r; @@ -690,17 +899,19 @@ parse_var_line(char* line, struct val_anchors* anchors, /** handle origin lines */ static int -handle_origin(char* line, ldns_rdf** origin) +handle_origin(char* line, uint8_t** origin, size_t* origin_len) { - while(isspace((int)*line)) + size_t len = 0; + while(isspace((unsigned char)*line)) line++; if(strncmp(line, "$ORIGIN", 7) != 0) return 0; - ldns_rdf_deep_free(*origin); + free(*origin); line += 7; - while(isspace((int)*line)) + while(isspace((unsigned char)*line)) line++; - *origin = ldns_dname_new_frm_str(line); + *origin = sldns_str2wire_dname(line, &len); + *origin_len = len; if(!*origin) log_warn("malloc failure or parse error in $ORIGIN"); return 1; @@ -781,7 +992,8 @@ int autr_read_file(struct val_anchors* anchors, const char* nm) struct trust_anchor *tp = NULL, *tp2; int r; /* for $ORIGIN parsing */ - ldns_rdf *origin=NULL, *prev=NULL; + uint8_t *origin=NULL, *prev=NULL; + size_t origin_len=0, prev_len=0; if (!(fd = fopen(nm, "r"))) { log_err("unable to open %s for reading: %s", @@ -794,25 +1006,25 @@ int autr_read_file(struct val_anchors* anchors, const char* nm) log_err("could not parse auto-trust-anchor-file " "%s line %d", nm, line_nr); fclose(fd); - ldns_rdf_deep_free(origin); - ldns_rdf_deep_free(prev); + free(origin); + free(prev); return 0; } else if(r == 1) { continue; } else if(r == 2) { log_warn("trust anchor %s has been revoked", nm); fclose(fd); - ldns_rdf_deep_free(origin); - ldns_rdf_deep_free(prev); + free(origin); + free(prev); return 1; } if (!str_contains_data(line, ';')) continue; /* empty lines allowed */ - if(handle_origin(line, &origin)) + if(handle_origin(line, &origin, &origin_len)) continue; r = 0; - if(!(tp2=load_trustanchor(anchors, line, nm, origin, &prev, - &r))) { + if(!(tp2=load_trustanchor(anchors, line, nm, origin, + origin_len, &prev, &prev_len, &r))) { if(!r) log_err("failed to load trust anchor from %s " "at line %i, skipping", nm, line_nr); /* try to do the rest */ @@ -823,15 +1035,15 @@ int autr_read_file(struct val_anchors* anchors, const char* nm) "the file may only contain keys for one name, " "remove keys for other domain names", nm); fclose(fd); - ldns_rdf_deep_free(origin); - ldns_rdf_deep_free(prev); + free(origin); + free(prev); return 0; } tp = tp2; } fclose(fd); - ldns_rdf_deep_free(origin); - ldns_rdf_deep_free(prev); + free(origin); + free(prev); if(!tp) { log_err("failed to read %s", nm); return 0; @@ -865,39 +1077,24 @@ trustanchor_state2str(autr_state_t s) /** print ID to file */ static int -print_id(FILE* out, char* fname, struct module_env* env, - uint8_t* nm, size_t nmlen, uint16_t dclass) +print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass) { - ldns_rdf rdf; -#ifdef UNBOUND_DEBUG - ldns_status s; -#endif - - memset(&rdf, 0, sizeof(rdf)); - ldns_rdf_set_data(&rdf, nm); - ldns_rdf_set_size(&rdf, nmlen); - ldns_rdf_set_type(&rdf, LDNS_RDF_TYPE_DNAME); - - ldns_buffer_clear(env->scratch_buffer); -#ifdef UNBOUND_DEBUG - s = -#endif - ldns_rdf2buffer_str_dname(env->scratch_buffer, &rdf); - log_assert(s == LDNS_STATUS_OK); - ldns_buffer_write_u8(env->scratch_buffer, 0); - ldns_buffer_flip(env->scratch_buffer); - if(fprintf(out, ";;id: %s %d\n", - (char*)ldns_buffer_begin(env->scratch_buffer), - (int)dclass) < 0) { + char* s = sldns_wire2str_dname(nm, nmlen); + if(!s) { + log_err("malloc failure in write to %s", fname); + return 0; + } + if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) { log_err("could not write to %s: %s", fname, strerror(errno)); + free(s); return 0; } + free(s); return 1; } static int -autr_write_contents(FILE* out, char* fn, struct module_env* env, - struct trust_anchor* tp) +autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) { char tmi[32]; struct autr_ta* ta; @@ -919,7 +1116,7 @@ autr_write_contents(FILE* out, char* fn, struct module_env* env, return 0; } } - if(!print_id(out, fn, env, tp->name, tp->namelen, tp->dclass)) { + if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) { return 0; } if(fprintf(out, ";;last_queried: %u ;;%s", @@ -947,9 +1144,10 @@ autr_write_contents(FILE* out, char* fn, struct module_env* env, if(ta->s == AUTR_STATE_REMOVED) continue; /* only store keys */ - if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY) + if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) + != LDNS_RR_TYPE_DNSKEY) continue; - str = ldns_rr2str(ta->rr); + str = sldns_wire2str_rr(ta->rr, ta->rr_len); if(!str || !str[0]) { free(str); log_err("malloc failure writing %s", fn); @@ -976,28 +1174,40 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp) char* fname = tp->autr->file; char tempf[2048]; log_assert(tp->autr); + if(!env) { + log_err("autr_write_file: Module environment is NULL."); + return; + } /* unique name with pid number and thread number */ snprintf(tempf, sizeof(tempf), "%s.%d-%d", fname, (int)getpid(), - env&&env->worker?*(int*)env->worker:0); + env->worker?*(int*)env->worker:0); verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf); out = fopen(tempf, "w"); if(!out) { - log_err("could not open autotrust file for writing, %s: %s", + fatal_exit("could not open autotrust file for writing, %s: %s", tempf, strerror(errno)); return; } - if(!autr_write_contents(out, tempf, env, tp)) { + if(!autr_write_contents(out, tempf, tp)) { /* failed to write contents (completely) */ fclose(out); unlink(tempf); - log_err("could not completely write: %s", fname); + fatal_exit("could not completely write: %s", fname); + return; + } + if(fclose(out) != 0) { + fatal_exit("could not complete write: %s: %s", + fname, strerror(errno)); + unlink(tempf); return; } /* success; overwrite actual file */ - fclose(out); verbose(VERB_ALGO, "autotrust: replaced %s", fname); +#ifdef UB_ON_WINDOWS + (void)unlink(fname); /* windows does not replace file with rename() */ +#endif if(rename(tempf, fname) < 0) { - log_err("rename(%s to %s): %s", tempf, fname, strerror(errno)); + fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno)); } } @@ -1015,7 +1225,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve, { char* reason = NULL; uint8_t sigalg[ALGO_NEEDS_MAX+1]; - int downprot = 1; + int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason); /* sigalg is ignored, it returns algorithms signalled to exist, but @@ -1027,24 +1237,30 @@ verify_dnskey(struct module_env* env, struct val_env* ve, return sec == sec_status_secure; } +static int32_t +rrsig_get_expiry(uint8_t* d, size_t len) +{ + /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */ + if(len < 2+8+4) + return 0; + return sldns_read_uint32(d+2+8); +} + /** Find minimum expiration interval from signatures */ -static uint32_t -min_expiry(struct module_env* env, ldns_rr_list* rrset) +static time_t +min_expiry(struct module_env* env, struct packed_rrset_data* dd) { size_t i; - uint32_t t, r = 15 * 24 * 3600; /* 15 days max */ - for(i=0; i<ldns_rr_list_rr_count(rrset); i++) { - ldns_rr* rr = ldns_rr_list_rr(rrset, i); - if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) - continue; - t = ldns_rdf2native_int32(ldns_rr_rrsig_expiration(rr)); - if(t - *env->now > 0) { - t -= *env->now; + int32_t t, r = 15 * 24 * 3600; /* 15 days max */ + for(i=dd->count; i<dd->count+dd->rrsig_count; i++) { + t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]); + if((int32_t)t - (int32_t)*env->now > 0) { + t -= (int32_t)*env->now; if(t < r) r = t; } } - return r; + return (time_t)r; } /** Is rr self-signed revoked key */ @@ -1083,131 +1299,92 @@ seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked) static void revoke_dnskey(struct autr_ta* ta, int off) { - ldns_rdf* rdf; - uint16_t flags; - log_assert(ta && ta->rr); - if(ldns_rr_get_type(ta->rr) != LDNS_RR_TYPE_DNSKEY) + uint16_t flags; + uint8_t* data; + if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) != + LDNS_RR_TYPE_DNSKEY) return; - rdf = ldns_rr_dnskey_flags(ta->rr); - flags = ldns_read_uint16(ldns_rdf_data(rdf)); - + if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2) + return; + data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len); + flags = sldns_read_uint16(data); if (off && (flags&LDNS_KEY_REVOKE_KEY)) flags ^= LDNS_KEY_REVOKE_KEY; /* flip */ else flags |= LDNS_KEY_REVOKE_KEY; - ldns_write_uint16(ldns_rdf_data(rdf), flags); + sldns_write_uint16(data, flags); } -/** Compare two RR buffers skipping the REVOKED bit */ +/** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */ static int -ldns_rr_compare_wire_skip_revbit(ldns_buffer* rr1_buf, ldns_buffer* rr2_buf) -{ - size_t rr1_len, rr2_len, min_len, i, offset; - rr1_len = ldns_buffer_capacity(rr1_buf); - rr2_len = ldns_buffer_capacity(rr2_buf); - /* jump past dname (checked in earlier part) and especially past TTL */ - offset = 0; - while (offset < rr1_len && *ldns_buffer_at(rr1_buf, offset) != 0) - offset += *ldns_buffer_at(rr1_buf, offset) + 1; - /* jump to rdata section (PAST the rdata length field) */ - offset += 11; /* 0-dname-end + type + class + ttl + rdatalen */ - min_len = (rr1_len < rr2_len) ? rr1_len : rr2_len; +dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len) +{ + size_t i; + if(a_len != b_len) + return -1; /* compare RRs RDATA byte for byte. */ - for(i = offset; i < min_len; i++) + for(i = 0; i < a_len; i++) { - uint8_t *rdf1, *rdf2; - rdf1 = ldns_buffer_at(rr1_buf, i); - rdf2 = ldns_buffer_at(rr2_buf, i); - if (i==(offset+1)) - { + uint8_t rdf1, rdf2; + rdf1 = a[i]; + rdf2 = b[i]; + if(i==1) { /* this is the second part of the flags field */ - *rdf1 = *rdf1 | LDNS_KEY_REVOKE_KEY; - *rdf2 = *rdf2 | LDNS_KEY_REVOKE_KEY; + rdf1 |= LDNS_KEY_REVOKE_KEY; + rdf2 |= LDNS_KEY_REVOKE_KEY; } - if (*rdf1 < *rdf2) return -1; - else if (*rdf1 > *rdf2) return 1; + if (rdf1 < rdf2) return -1; + else if (rdf1 > rdf2) return 1; } return 0; } -/** Compare two RRs skipping the REVOKED bit */ -static int -ldns_rr_compare_skip_revbit(const ldns_rr* rr1, const ldns_rr* rr2, int* result) -{ - size_t rr1_len, rr2_len; - ldns_buffer* rr1_buf; - ldns_buffer* rr2_buf; - *result = ldns_rr_compare_no_rdata(rr1, rr2); - if (*result == 0) - { - rr1_len = ldns_rr_uncompressed_size(rr1); - rr2_len = ldns_rr_uncompressed_size(rr2); - rr1_buf = ldns_buffer_new(rr1_len); - rr2_buf = ldns_buffer_new(rr2_len); - if(!rr1_buf || !rr2_buf) { - ldns_buffer_free(rr1_buf); - ldns_buffer_free(rr2_buf); - return 0; - } - if (ldns_rr2buffer_wire_canonical(rr1_buf, rr1, - LDNS_SECTION_ANY) != LDNS_STATUS_OK) - { - ldns_buffer_free(rr1_buf); - ldns_buffer_free(rr2_buf); - return 0; - } - if (ldns_rr2buffer_wire_canonical(rr2_buf, rr2, - LDNS_SECTION_ANY) != LDNS_STATUS_OK) { - ldns_buffer_free(rr1_buf); - ldns_buffer_free(rr2_buf); - return 0; - } - *result = ldns_rr_compare_wire_skip_revbit(rr1_buf, rr2_buf); - ldns_buffer_free(rr1_buf); - ldns_buffer_free(rr2_buf); - } - return 1; -} - - -/** compare two trust anchors */ +/** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */ static int -ta_compare(ldns_rr* a, ldns_rr* b, int* result) -{ - if (!a && !b) *result = 0; - else if (!a) *result = -1; - else if (!b) *result = 1; - else if (ldns_rr_get_type(a) != ldns_rr_get_type(b)) - *result = (int)ldns_rr_get_type(a) - (int)ldns_rr_get_type(b); - else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DNSKEY) { - if(!ldns_rr_compare_skip_revbit(a, b, result)) - return 0; +ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len) +{ + if(!a) return -1; + else if(!b) return -1; + else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t) + return (int)sldns_wirerr_get_type(a->rr, a->rr_len, + a->dname_len) - (int)t; + else if(t == LDNS_RR_TYPE_DNSKEY) { + return dnskey_compare_skip_revbit( + sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len), + sldns_wirerr_get_rdatalen(a->rr, a->rr_len, + a->dname_len), b, b_len); + } + else if(t == LDNS_RR_TYPE_DS) { + if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) != + b_len) + return -1; + return memcmp(sldns_wirerr_get_rdata(a->rr, + a->rr_len, a->dname_len), b, b_len); } - else if (ldns_rr_get_type(a) == LDNS_RR_TYPE_DS) - *result = ldns_rr_compare(a, b); - else *result = -1; - return 1; + return -1; } /** * Find key * @param tp: to search in - * @param rr: to look for + * @param t: rr type of the rdata. + * @param rdata: to look for (no rdatalen in it) + * @param rdata_len: length of rdata * @param result: returns NULL or the ta key looked for. * @return false on malloc failure during search. if true examine result. */ static int -find_key(struct trust_anchor* tp, ldns_rr* rr, struct autr_ta** result) +find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len, + struct autr_ta** result) { struct autr_ta* ta; - int ret; - if(!tp || !rr) + if(!tp || !rdata) { + *result = NULL; return 0; + } for(ta=tp->autr->keys; ta; ta=ta->next) { - if(!ta_compare(ta->rr, rr, &ret)) - return 0; - if(ret == 0) { + if(ta_compare(ta, t, rdata, rdata_len) == 0) { *result = ta; return 1; } @@ -1216,17 +1393,30 @@ find_key(struct trust_anchor* tp, ldns_rr* rr, struct autr_ta** result) return 1; } -/** add key and clone RR and tp already locked */ +/** add key and clone RR and tp already locked. rdata without rdlen. */ static struct autr_ta* -add_key(struct trust_anchor* tp, ldns_rr* rr) +add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len) { - ldns_rr* c; struct autr_ta* ta; - c = ldns_rr_clone(rr); - if(!c) return NULL; - ta = autr_ta_create(c); + uint8_t* rr; + size_t rr_len, dname_len; + uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY); + uint16_t rrclass = htons(LDNS_RR_CLASS_IN); + uint16_t rdlen = htons(rdata_len); + dname_len = tp->namelen; + ttl = htonl(ttl); + rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len; + rr = (uint8_t*)malloc(rr_len); + if(!rr) return NULL; + memmove(rr, tp->name, tp->namelen); + memmove(rr+dname_len, &rrtype, 2); + memmove(rr+dname_len+2, &rrclass, 2); + memmove(rr+dname_len+4, &ttl, 4); + memmove(rr+dname_len+8, &rdlen, 2); + memmove(rr+dname_len+10, rdata, rdata_len); + ta = autr_ta_create(rr, rr_len, dname_len); if(!ta) { - ldns_rr_free(c); + /* rr freed in autr_ta_create */ return NULL; } /* link in, tp already locked */ @@ -1236,7 +1426,7 @@ add_key(struct trust_anchor* tp, ldns_rr* rr) } /** get TTL from DNSKEY rrset */ -static uint32_t +static time_t key_ttl(struct ub_packed_rrset_key* k) { struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; @@ -1245,10 +1435,10 @@ key_ttl(struct ub_packed_rrset_key* k) /** update the time values for the trustpoint */ static void -set_tp_times(struct trust_anchor* tp, uint32_t rrsig_exp_interval, - uint32_t origttl, int* changed) +set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, + time_t origttl, int* changed) { - uint32_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; + time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; /* x = MIN(15days, ttl/2, expire/2) */ x = 15 * 24 * 3600; @@ -1257,9 +1447,11 @@ set_tp_times(struct trust_anchor* tp, uint32_t rrsig_exp_interval, if(rrsig_exp_interval/2 < x) x = rrsig_exp_interval/2; /* MAX(1hr, x) */ - if(x < 3600) - tp->autr->query_interval = 3600; - else tp->autr->query_interval = x; + if(!autr_permit_small_holddown) { + if(x < 3600) + tp->autr->query_interval = 3600; + else tp->autr->query_interval = x; + } else tp->autr->query_interval = x; /* x= MIN(1day, ttl/10, expire/10) */ x = 24 * 3600; @@ -1268,9 +1460,11 @@ set_tp_times(struct trust_anchor* tp, uint32_t rrsig_exp_interval, if(rrsig_exp_interval/10 < x) x = rrsig_exp_interval/10; /* MAX(1hr, x) */ - if(x < 3600) - tp->autr->retry_time = 3600; - else tp->autr->retry_time = x; + if(!autr_permit_small_holddown) { + if(x < 3600) + tp->autr->retry_time = 3600; + else tp->autr->retry_time = x; + } else tp->autr->retry_time = x; if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { *changed = 1; @@ -1299,21 +1493,19 @@ check_contains_revoked(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, int* changed) { - ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset, - env->scratch_buffer); + struct packed_rrset_data* dd = (struct packed_rrset_data*) + dnskey_rrset->entry.data; size_t i; - if(!r) { - log_err("malloc failure"); - return; - } - for(i=0; i<ldns_rr_list_rr_count(r); i++) { - ldns_rr* rr = ldns_rr_list_rr(r, i); + log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); + for(i=0; i<dd->count; i++) { struct autr_ta* ta = NULL; - if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) - continue; - if(!rr_is_dnskey_sep(rr) || !rr_is_dnskey_revoked(rr)) + if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2) || + !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2)) continue; /* not a revoked KSK */ - if(!find_key(tp, rr, &ta)) { + if(!find_key(tp, ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { log_err("malloc failure"); continue; /* malloc fail in compare*/ } @@ -1321,8 +1513,18 @@ check_contains_revoked(struct module_env* env, struct val_env* ve, continue; /* key not found */ if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) { /* checked if there is an rrsig signed by this key. */ - log_assert(dnskey_calc_keytag(dnskey_rrset, i) == - ldns_calc_keytag(rr)); /* checks conversion*/ + /* same keytag, but stored can be revoked already, so + * compare keytags, with +0 or +128(REVOKE flag) */ + log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 == + sldns_calc_keytag_raw(sldns_wirerr_get_rdata( + ta->rr, ta->rr_len, ta->dname_len), + sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, + ta->dname_len)) || + dnskey_calc_keytag(dnskey_rrset, i) == + sldns_calc_keytag_raw(sldns_wirerr_get_rdata( + ta->rr, ta->rr_len, ta->dname_len), + sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, + ta->dname_len))); /* checks conversion*/ verbose_key(ta, VERB_ALGO, "is self-signed revoked"); if(!ta->revoked) *changed = 1; @@ -1330,7 +1532,6 @@ check_contains_revoked(struct module_env* env, struct val_env* ve, do_revoked(env, ta, changed); } } - ldns_rr_list_deep_free(r); } /** See if a DNSKEY is verified by one of the DSes */ @@ -1377,20 +1578,18 @@ update_events(struct module_env* env, struct val_env* ve, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, int* changed) { - ldns_rr_list* r = packed_rrset_to_rr_list(dnskey_rrset, - env->scratch_buffer); + struct packed_rrset_data* dd = (struct packed_rrset_data*) + dnskey_rrset->entry.data; size_t i; - if(!r) - return 0; + log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); init_events(tp); - for(i=0; i<ldns_rr_list_rr_count(r); i++) { - ldns_rr* rr = ldns_rr_list_rr(r, i); + for(i=0; i<dd->count; i++) { struct autr_ta* ta = NULL; - if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) - continue; - if(!rr_is_dnskey_sep(rr)) + if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2)) continue; - if(rr_is_dnskey_revoked(rr)) { + if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2)) { /* self-signed revoked keys already detected before, * other revoked keys are not 'added' again */ continue; @@ -1406,12 +1605,13 @@ update_events(struct module_env* env, struct val_env* ve, } /* is it new? if revocation bit set, find the unrevoked key */ - if(!find_key(tp, rr, &ta)) { - ldns_rr_list_deep_free(r); /* malloc fail in compare*/ + if(!find_key(tp, ntohs(dnskey_rrset->rk.type), + dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { return 0; } if(!ta) { - ta = add_key(tp, rr); + ta = add_key(tp, (uint32_t)dd->rr_ttl[i], + dd->rr_data[i]+2, dd->rr_len[i]-2); *changed = 1; /* first time seen, do we have DSes? if match: VALID */ if(ta && tp->ds_rrset && key_matches_a_ds(env, ve, @@ -1421,14 +1621,12 @@ update_events(struct module_env* env, struct val_env* ve, } } if(!ta) { - ldns_rr_list_deep_free(r); return 0; } seen_trustanchor(ta, 1); verbose_key(ta, VERB_ALGO, "in DNS response"); } - set_tp_times(tp, min_expiry(env, r), key_ttl(dnskey_rrset), changed); - ldns_rr_list_deep_free(r); + set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed); return 1; } @@ -1441,21 +1639,21 @@ update_events(struct module_env* env, struct val_env* ve, * @param holddown: the timer value * @return number of seconds the holddown has passed. */ -static int -check_holddown(struct module_env* env, struct autr_ta* ta, +static time_t +check_holddown(struct module_env* env, struct autr_ta* ta, unsigned int holddown) { - unsigned int elapsed; - if((unsigned)*env->now < (unsigned)ta->last_change) { + time_t elapsed; + if(*env->now < ta->last_change) { log_warn("time goes backwards. delaying key holddown"); return 0; } - elapsed = (unsigned)*env->now - (unsigned)ta->last_change; - if (elapsed > holddown) { - return (int) (elapsed-holddown); + elapsed = *env->now - ta->last_change; + if (elapsed > (time_t)holddown) { + return elapsed-(time_t)holddown; } - verbose_key(ta, VERB_ALGO, "holddown time %d seconds to go", - (int) (holddown-elapsed)); + verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go", + (long long) ((time_t)holddown-elapsed)); return 0; } @@ -1495,11 +1693,11 @@ do_addtime(struct module_env* env, struct autr_ta* anchor, int* c) /* This not according to RFC, this is 30 days, but the RFC demands * MAX(30days, TTL expire time of first DNSKEY set with this key), * The value may be too small if a very large TTL was used. */ - int exceeded = check_holddown(env, anchor, env->cfg->add_holddown); + time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown); if (exceeded && anchor->s == AUTR_STATE_ADDPEND) { verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded " - "%d seconds ago, and pending-count %d", exceeded, - anchor->pending_count); + ARG_LL "d seconds ago, and pending-count %d", + (long long)exceeded, anchor->pending_count); if(anchor->pending_count >= MIN_PENDINGCOUNT) { set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); anchor->pending_count = 0; @@ -1514,10 +1712,10 @@ do_addtime(struct module_env* env, struct autr_ta* anchor, int* c) static void do_remtime(struct module_env* env, struct autr_ta* anchor, int* c) { - int exceeded = check_holddown(env, anchor, env->cfg->del_holddown); + time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown); if(exceeded && anchor->s == AUTR_STATE_REVOKED) { verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded " - "%d seconds ago", exceeded); + ARG_LL "d seconds ago", (long long)exceeded); set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED); } } @@ -1619,16 +1817,17 @@ init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed) int validksk = 0; for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { /* last_change test makes sure it was manually configured */ - if (ldns_rr_get_type(anchor->rr) == LDNS_RR_TYPE_DNSKEY && + if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len, + anchor->dname_len) == LDNS_RR_TYPE_DNSKEY && anchor->last_change == 0 && - !rr_is_dnskey_sep(anchor->rr) && + !ta_is_dnskey_sep(anchor) && anchor->s == AUTR_STATE_VALID) validzsk++; } if(validzsk == 0) return 0; for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { - if (rr_is_dnskey_sep(anchor->rr) && + if (ta_is_dnskey_sep(anchor) && anchor->s == AUTR_STATE_ADDPEND) { verbose_key(anchor, VERB_ALGO, "trust KSK from " "ZSK(config)"); @@ -1646,12 +1845,12 @@ remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, int* changed) { struct autr_ta* anchor; - int exceeded; + time_t exceeded; int valid = 0; /* see if we have anchors that are valid */ for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { /* Only do KSKs */ - if (!rr_is_dnskey_sep(anchor->rr)) + if (!ta_is_dnskey_sep(anchor)) continue; if (anchor->s == AUTR_STATE_VALID) valid++; @@ -1674,7 +1873,7 @@ remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, if(anchor->s == AUTR_STATE_START) continue; /* remove ZSKs if a KSK is present */ - if (!rr_is_dnskey_sep(anchor->rr)) { + if (!ta_is_dnskey_sep(anchor)) { if(valid > 0) { verbose_key(anchor, VERB_ALGO, "remove ZSK " "[%d key(s) VALID]", valid); @@ -1694,8 +1893,8 @@ remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, * one valid KSK: remove missing trust anchor */ if (exceeded && valid > 0) { verbose_key(anchor, VERB_ALGO, "keep-missing time " - "exceeded %d seconds ago, [%d key(s) VALID]", - exceeded, valid); + "exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]", + (long long)exceeded, valid); set_trustanchor_state(env, anchor, changed, AUTR_STATE_REMOVED); } @@ -1709,7 +1908,7 @@ do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed) struct autr_ta* anchor; for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { /* Only do KSKs */ - if(!rr_is_dnskey_sep(anchor->rr)) + if(!ta_is_dnskey_sep(anchor)) continue; anchor_state_update(env, anchor, changed); } @@ -1723,7 +1922,7 @@ autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c) { struct autr_ta* anchor; for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { - if(rr_is_dnskey_sep(anchor->rr) && + if(ta_is_dnskey_sep(anchor) && anchor->s == AUTR_STATE_ADDPEND) do_addtime(env, anchor, c); } @@ -1739,10 +1938,11 @@ autr_cleanup_keys(struct trust_anchor* tp) while(p) { /* do we want to remove this key? */ if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED || - ldns_rr_get_type(p->rr) != LDNS_RR_TYPE_DNSKEY) { + sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len) + != LDNS_RR_TYPE_DNSKEY) { struct autr_ta* np = p->next; /* remove */ - ldns_rr_free(p->rr); + free(p->rr); free(p); /* snip and go to next item */ *prevp = np; @@ -1759,15 +1959,19 @@ autr_cleanup_keys(struct trust_anchor* tp) /** calculate next probe time */ static time_t -calc_next_probe(struct module_env* env, uint32_t wait) +calc_next_probe(struct module_env* env, time_t wait) { /* make it random, 90-100% */ - uint32_t rnd, rest; - if(wait < 3600) - wait = 3600; + time_t rnd, rest; + if(!autr_permit_small_holddown) { + if(wait < 3600) + wait = 3600; + } else { + if(wait == 0) wait = 1; + } rnd = wait/10; rest = wait-rnd; - rnd = (uint32_t)ub_random_max(env->rnd, (long int)rnd); + rnd = (time_t)ub_random_max(env->rnd, (long int)rnd); return (time_t)(*env->now + rest + rnd); } @@ -1787,7 +1991,7 @@ reset_worker_timer(struct module_env* env) { struct timeval tv; #ifndef S_SPLINT_S - uint32_t next = (uint32_t)wait_probe_time(env->anchors); + time_t next = (time_t)wait_probe_time(env->anchors); /* in case this is libunbound, no timer */ if(!env->probe_timer) return; @@ -1797,7 +2001,7 @@ reset_worker_timer(struct module_env* env) #endif tv.tv_usec = 0; comm_timer_set(env->probe_timer, &tv); - verbose(VERB_ALGO, "scheduled next probe in %d sec", (int)tv.tv_sec); + verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec); } /** set next probe for trust anchor */ @@ -1848,6 +2052,7 @@ static void autr_tp_remove(struct module_env* env, struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset) { + struct trust_anchor* del_tp; struct trust_anchor key; struct autr_point_data pd; time_t mold, mnew; @@ -1873,19 +2078,24 @@ autr_tp_remove(struct module_env* env, struct trust_anchor* tp, /* take from tree. It could be deleted by someone else,hence (void). */ lock_basic_lock(&env->anchors->lock); - (void)rbtree_delete(env->anchors->tree, &key); + del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key); mold = wait_probe_time(env->anchors); (void)rbtree_delete(&env->anchors->autr->probe, &key); mnew = wait_probe_time(env->anchors); anchors_init_parents_locked(env->anchors); lock_basic_unlock(&env->anchors->lock); - /* save on disk */ - tp->autr->next_probe_time = 0; /* no more probing for it */ - autr_write_file(env, tp); + /* if !del_tp then the trust point is no longer present in the tree, + * it was deleted by someone else, who will write the zonefile and + * clean up the structure */ + if(del_tp) { + /* save on disk */ + del_tp->autr->next_probe_time = 0; /* no more probing for it */ + autr_write_file(env, del_tp); - /* delete */ - autr_point_delete(tp); + /* delete */ + autr_point_delete(del_tp); + } if(mold != mnew) { reset_worker_timer(env); } @@ -2008,7 +2218,7 @@ static void autr_debug_print_ta(struct autr_ta* ta) { char buf[32]; - char* str = ldns_rr2str(ta->rr); + char* str = sldns_wire2str_rr(ta->rr, ta->rr_len); if(!str) { log_info("out of memory in debug_print_ta"); return; @@ -2034,20 +2244,11 @@ autr_debug_print_tp(struct trust_anchor* tp) log_info("trust point %s : %d", buf, (int)tp->dclass); log_info("assembled %d DS and %d DNSKEYs", (int)tp->numDS, (int)tp->numDNSKEY); - if(0) { /* turned off because it prints to stderr */ - ldns_buffer* bf = ldns_buffer_new(70000); - ldns_rr_list* list; - if(tp->ds_rrset) { - list = packed_rrset_to_rr_list(tp->ds_rrset, bf); - ldns_rr_list_print(stderr, list); - ldns_rr_list_deep_free(list); - } - if(tp->dnskey_rrset) { - list = packed_rrset_to_rr_list(tp->dnskey_rrset, bf); - ldns_rr_list_print(stderr, list); - ldns_rr_list_deep_free(list); - } - ldns_buffer_free(bf); + if(tp->ds_rrset) { + log_packed_rrset(0, "DS:", tp->ds_rrset); + } + if(tp->dnskey_rrset) { + log_packed_rrset(0, "DNSKEY:", tp->dnskey_rrset); } log_info("file %s", tp->autr->file); ctime_r(&tp->autr->last_queried, buf); @@ -2083,7 +2284,7 @@ autr_debug_print(struct val_anchors* anchors) } void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode), - ldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), + sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus)) { /* retry was set before the query was done, @@ -2108,7 +2309,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) struct query_info qinfo; uint16_t qflags = BIT_RD; struct edns_data edns; - ldns_buffer* buf = env->scratch_buffer; + sldns_buffer* buf = env->scratch_buffer; qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen); if(!qinfo.qname) { log_err("out of memory making 5011 probe"); @@ -2124,8 +2325,8 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) edns.ext_rcode = 0; edns.edns_version = 0; edns.bits = EDNS_DO; - if(ldns_buffer_capacity(buf) < 65535) - edns.udp_size = (uint16_t)ldns_buffer_capacity(buf); + if(sldns_buffer_capacity(buf) < 65535) + edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); else edns.udp_size = 65535; /* can't hold the lock while mesh_run is processing */ @@ -2147,7 +2348,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) /** fetch first to-probe trust-anchor and lock it and set retrytime */ static struct trust_anchor* -todo_probe(struct module_env* env, uint32_t* next) +todo_probe(struct module_env* env, time_t* next) { struct trust_anchor* tp; rbnode_t* el; @@ -2156,15 +2357,17 @@ todo_probe(struct module_env* env, uint32_t* next) if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { /* in case of revoked anchors */ lock_basic_unlock(&env->anchors->lock); + /* signal that there are no anchors to probe */ + *next = 0; return NULL; } tp = (struct trust_anchor*)el->key; lock_basic_lock(&tp->lock); /* is it eligible? */ - if((uint32_t)tp->autr->next_probe_time > *env->now) { + if((time_t)tp->autr->next_probe_time > *env->now) { /* no more to probe */ - *next = (uint32_t)tp->autr->next_probe_time - *env->now; + *next = (time_t)tp->autr->next_probe_time - *env->now; lock_basic_unlock(&tp->lock); lock_basic_unlock(&env->anchors->lock); return NULL; @@ -2179,12 +2382,13 @@ todo_probe(struct module_env* env, uint32_t* next) return tp; } -uint32_t +time_t autr_probe_timer(struct module_env* env) { struct trust_anchor* tp; - uint32_t next_probe = 3600; + time_t next_probe = 3600; int num = 0; + if(autr_permit_small_holddown) next_probe = 1; verbose(VERB_ALGO, "autotrust probe timer callback"); /* while there are still anchors to probe */ while( (tp = todo_probe(env, &next_probe)) ) { @@ -2193,7 +2397,7 @@ autr_probe_timer(struct module_env* env) num++; } regional_free_all(env->scratch); - if(num == 0) + if(next_probe == 0) return 0; /* no trust points to probe */ verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); return next_probe; diff --git a/usr.sbin/unbound/validator/val_sigcrypt.c b/usr.sbin/unbound/validator/val_sigcrypt.c index 436b5e84487..a2f12652938 100644 --- a/usr.sbin/unbound/validator/val_sigcrypt.c +++ b/usr.sbin/unbound/validator/val_sigcrypt.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -41,8 +41,8 @@ * bridging between RR wireformat data and crypto calls. */ #include "config.h" -#include <ldns/ldns.h> #include "validator/val_sigcrypt.h" +#include "validator/val_secalgo.h" #include "validator/validator.h" #include "util/data/msgreply.h" #include "util/data/msgparse.h" @@ -51,9 +51,14 @@ #include "util/module.h" #include "util/net_help.h" #include "util/regional.h" - -#ifndef HAVE_SSL -#error "Need SSL library to do digital signature cryptography" +#include "sldns/keyraw.h" +#include "sldns/sbuffer.h" +#include "sldns/parseutil.h" +#include "sldns/wire2str.h" + +#include <ctype.h> +#if !defined(HAVE_SSL) && !defined(HAVE_NSS) +#error "Need crypto library to do digital signature cryptography" #endif #ifdef HAVE_OPENSSL_ERR_H @@ -265,38 +270,9 @@ ds_get_sigdata(struct ub_packed_rrset_key* k, size_t idx, uint8_t** digest, static size_t ds_digest_size_algo(struct ub_packed_rrset_key* k, size_t idx) { - switch(ds_get_digest_algo(k, idx)) { -#ifdef HAVE_EVP_SHA1 - case LDNS_SHA1: - return SHA_DIGEST_LENGTH; -#endif -#ifdef HAVE_EVP_SHA256 - case LDNS_SHA256: - return SHA256_DIGEST_LENGTH; -#endif -#ifdef USE_GOST - case LDNS_HASH_GOST: - if(EVP_get_digestbyname("md_gost94")) - return 32; - else return 0; -#endif - default: break; - } - return 0; + return ds_digest_size_supported(ds_get_digest_algo(k, idx)); } -#ifdef USE_GOST -/** Perform GOST hash */ -static int -do_gost94(unsigned char* data, size_t len, unsigned char* dest) -{ - const EVP_MD* md = EVP_get_digestbyname("md_gost94"); - if(!md) - return 0; - return ldns_digest_evp(data, (unsigned int)len, dest, md); -} -#endif - /** * Create a DS digest for a DNSKEY entry. * @@ -314,7 +290,7 @@ ds_create_dnskey_digest(struct module_env* env, struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, uint8_t* digest) { - ldns_buffer* b = env->scratch_buffer; + sldns_buffer* b = env->scratch_buffer; uint8_t* dnskey_rdata; size_t dnskey_len; rrset_get_rdata(dnskey_rrset, dnskey_idx, &dnskey_rdata, &dnskey_len); @@ -322,38 +298,16 @@ ds_create_dnskey_digest(struct module_env* env, /* create digest source material in buffer * digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA); * DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key. */ - ldns_buffer_clear(b); - ldns_buffer_write(b, dnskey_rrset->rk.dname, + sldns_buffer_clear(b); + sldns_buffer_write(b, dnskey_rrset->rk.dname, dnskey_rrset->rk.dname_len); - query_dname_tolower(ldns_buffer_begin(b)); - ldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/ - ldns_buffer_flip(b); + query_dname_tolower(sldns_buffer_begin(b)); + sldns_buffer_write(b, dnskey_rdata+2, dnskey_len-2); /* skip rdatalen*/ + sldns_buffer_flip(b); - switch(ds_get_digest_algo(ds_rrset, ds_idx)) { -#ifdef HAVE_EVP_SHA1 - case LDNS_SHA1: - (void)SHA1((unsigned char*)ldns_buffer_begin(b), - ldns_buffer_limit(b), (unsigned char*)digest); - return 1; -#endif -#ifdef HAVE_EVP_SHA256 - case LDNS_SHA256: - (void)SHA256((unsigned char*)ldns_buffer_begin(b), - ldns_buffer_limit(b), (unsigned char*)digest); - return 1; -#endif -#ifdef USE_GOST - case LDNS_HASH_GOST: - if(do_gost94((unsigned char*)ldns_buffer_begin(b), - ldns_buffer_limit(b), (unsigned char*)digest)) - return 1; -#endif - default: - verbose(VERB_QUERY, "unknown DS digest algorithm %d", - (int) ds_get_digest_algo(ds_rrset, ds_idx)); - break; - } - return 0; + return secalgo_ds_digest(ds_get_digest_algo(ds_rrset, ds_idx), + (unsigned char*)sldns_buffer_begin(b), sldns_buffer_limit(b), + (unsigned char*)digest); } int ds_digest_match_dnskey(struct module_env* env, @@ -402,33 +356,6 @@ ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, return (ds_digest_size_algo(ds_rrset, ds_idx) != 0); } -/** return true if DNSKEY algorithm id is supported */ -static int -dnskey_algo_id_is_supported(int id) -{ - switch(id) { - case LDNS_DSA: - case LDNS_DSA_NSEC3: - case LDNS_RSASHA1: - case LDNS_RSASHA1_NSEC3: - case LDNS_RSAMD5: -#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2) - case LDNS_RSASHA256: -#endif -#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2) - case LDNS_RSASHA512: -#endif - return 1; -#ifdef USE_GOST - case LDNS_ECC_GOST: - /* we support GOST if it can be loaded */ - return ldns_key_EVP_load_gost_id(); -#endif - default: - return 0; - } -} - int ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx) @@ -443,7 +370,7 @@ dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx) size_t len; rrset_get_rdata(dnskey_rrset, dnskey_idx, &data, &len); /* do not pass rdatalen to ldns */ - return ldns_calc_keytag_raw(data+2, len-2); + return sldns_calc_keytag_raw(data+2, len-2); } int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset, @@ -592,10 +519,14 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, (uint8_t)rrset_get_sig_algo(rrset, i)); } } - verbose(VERB_ALGO, "rrset failed to verify: no valid signatures for " - "%d algorithms", (int)algo_needs_num_missing(&needs)); if(sigalg && (alg=algo_needs_missing(&needs)) != 0) { + verbose(VERB_ALGO, "rrset failed to verify: " + "no valid signatures for %d algorithms", + (int)algo_needs_num_missing(&needs)); algo_needs_reason(env, alg, reason, "no signatures"); + } else { + verbose(VERB_ALGO, "rrset failed to verify: " + "no valid signatures"); } return sec_status_bogus; } @@ -603,7 +534,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s) { char buf[256]; - ldns_lookup_table *t = ldns_lookup_by_id(ldns_algorithms, alg); + sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg); if(t&&t->name) snprintf(buf, sizeof(buf), "%s with algorithm %s", s, t->name); else snprintf(buf, sizeof(buf), "%s with algorithm ALG%u", s, @@ -652,7 +583,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, - uint32_t now, struct ub_packed_rrset_key* rrset, + time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t sig_idx, struct rbtree_t** sortree, char** reason) { @@ -713,7 +644,7 @@ struct canon_rr { */ static int canonical_compare_byfield(struct packed_rrset_data* d, - const ldns_rr_descriptor* desc, size_t i, size_t j) + const sldns_rr_descriptor* desc, size_t i, size_t j) { /* sweep across rdata, keep track of some state: * which rr field, and bytes left in field. @@ -857,17 +788,13 @@ canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) { struct packed_rrset_data* d = (struct packed_rrset_data*) rrset->entry.data; - const ldns_rr_descriptor* desc; + const sldns_rr_descriptor* desc; uint16_t type = ntohs(rrset->rk.type); size_t minlen; int c; if(i==j) return 0; - /* in case rdata-len is to be compared for canonical order - c = memcmp(d->rr_data[i], d->rr_data[j], 2); - if(c != 0) - return c; */ switch(type) { /* These RR types have only a name as RDATA. @@ -881,7 +808,12 @@ canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) case LDNS_RR_TYPE_MR: case LDNS_RR_TYPE_PTR: case LDNS_RR_TYPE_DNAME: - return query_dname_compare(d->rr_data[i]+2, + /* the wireread function has already checked these + * dname's for correctness, and this double checks */ + if(!dname_valid(d->rr_data[i]+2, d->rr_len[i]-2) || + !dname_valid(d->rr_data[j]+2, d->rr_len[j]-2)) + return 0; + return query_dname_compare(d->rr_data[i]+2, d->rr_data[j]+2); /* These RR types have STR and fixed size rdata fields @@ -904,7 +836,7 @@ canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j) case LDNS_RR_TYPE_PX: case LDNS_RR_TYPE_NAPTR: case LDNS_RR_TYPE_SRV: - desc = ldns_rr_descript(type); + desc = sldns_rr_descript(type); log_assert(desc); /* this holds for the types that need canonicalizing */ log_assert(desc->_minimum == desc->_maximum); @@ -977,15 +909,15 @@ canonical_sort(struct ub_packed_rrset_key* rrset, struct packed_rrset_data* d, * @param can_owner_len: length of canonical owner name. */ static void -insert_can_owner(ldns_buffer* buf, struct ub_packed_rrset_key* k, +insert_can_owner(sldns_buffer* buf, struct ub_packed_rrset_key* k, uint8_t* sig, uint8_t** can_owner, size_t* can_owner_len) { int rrsig_labels = (int)sig[3]; int fqdn_labels = dname_signame_label_count(k->rk.dname); - *can_owner = ldns_buffer_current(buf); + *can_owner = sldns_buffer_current(buf); if(rrsig_labels == fqdn_labels) { /* no change */ - ldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); + sldns_buffer_write(buf, k->rk.dname, k->rk.dname_len); query_dname_tolower(*can_owner); *can_owner_len = k->rk.dname_len; return; @@ -1001,8 +933,8 @@ insert_can_owner(ldns_buffer* buf, struct ub_packed_rrset_key* k, dname_remove_label(&nm, &len); } *can_owner_len = len+2; - ldns_buffer_write(buf, (uint8_t*)"\001*", 2); - ldns_buffer_write(buf, nm, len); + sldns_buffer_write(buf, (uint8_t*)"\001*", 2); + sldns_buffer_write(buf, nm, len); query_dname_tolower(*can_owner); } } @@ -1014,10 +946,10 @@ insert_can_owner(ldns_buffer* buf, struct ub_packed_rrset_key* k, * @param len: length of the rdata (including rdatalen uint16). */ static void -canonicalize_rdata(ldns_buffer* buf, struct ub_packed_rrset_key* rrset, +canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, size_t len) { - uint8_t* datstart = ldns_buffer_current(buf)-len+2; + uint8_t* datstart = sldns_buffer_current(buf)-len+2; switch(ntohs(rrset->rk.type)) { case LDNS_RR_TYPE_NXT: case LDNS_RR_TYPE_NS: @@ -1108,6 +1040,71 @@ canonicalize_rdata(ldns_buffer* buf, struct ub_packed_rrset_key* rrset, } } +int rrset_canonical_equal(struct regional* region, + struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) +{ + struct rbtree_t sortree1, sortree2; + struct canon_rr *rrs1, *rrs2, *p1, *p2; + struct packed_rrset_data* d1=(struct packed_rrset_data*)k1->entry.data; + struct packed_rrset_data* d2=(struct packed_rrset_data*)k2->entry.data; + struct ub_packed_rrset_key fk; + struct packed_rrset_data fd; + size_t flen[2]; + uint8_t* fdata[2]; + + /* basic compare */ + if(k1->rk.dname_len != k2->rk.dname_len || + k1->rk.flags != k2->rk.flags || + k1->rk.type != k2->rk.type || + k1->rk.rrset_class != k2->rk.rrset_class || + query_dname_compare(k1->rk.dname, k2->rk.dname) != 0) + return 0; + if(d1->ttl != d2->ttl || + d1->count != d2->count || + d1->rrsig_count != d2->rrsig_count || + d1->trust != d2->trust || + d1->security != d2->security) + return 0; + + /* init */ + memset(&fk, 0, sizeof(fk)); + memset(&fd, 0, sizeof(fd)); + fk.entry.data = &fd; + fd.count = 2; + fd.rr_len = flen; + fd.rr_data = fdata; + rbtree_init(&sortree1, &canonical_tree_compare); + rbtree_init(&sortree2, &canonical_tree_compare); + if(d1->count > RR_COUNT_MAX || d2->count > RR_COUNT_MAX) + return 1; /* protection against integer overflow */ + rrs1 = regional_alloc(region, sizeof(struct canon_rr)*d1->count); + rrs2 = regional_alloc(region, sizeof(struct canon_rr)*d2->count); + if(!rrs1 || !rrs2) return 1; /* alloc failure */ + + /* sort */ + canonical_sort(k1, d1, &sortree1, rrs1); + canonical_sort(k2, d2, &sortree2, rrs2); + + /* compare canonical-sorted RRs for canonical-equality */ + if(sortree1.count != sortree2.count) + return 0; + p1 = (struct canon_rr*)rbtree_first(&sortree1); + p2 = (struct canon_rr*)rbtree_first(&sortree2); + while(p1 != (struct canon_rr*)RBTREE_NULL && + p2 != (struct canon_rr*)RBTREE_NULL) { + flen[0] = d1->rr_len[p1->rr_idx]; + flen[1] = d2->rr_len[p2->rr_idx]; + fdata[0] = d1->rr_data[p1->rr_idx]; + fdata[1] = d2->rr_data[p2->rr_idx]; + + if(canonical_compare(&fk, 0, 1) != 0) + return 0; + p1 = (struct canon_rr*)rbtree_next(&p1->node); + p2 = (struct canon_rr*)rbtree_next(&p2->node); + } + return 1; +} + /** * Create canonical form of rrset in the scratch buffer. * @param region: temporary region. @@ -1121,7 +1118,7 @@ canonicalize_rdata(ldns_buffer* buf, struct ub_packed_rrset_key* rrset, * @return false on alloc error. */ static int -rrset_canonical(struct regional* region, ldns_buffer* buf, +rrset_canonical(struct regional* region, sldns_buffer* buf, struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, struct rbtree_t** sortree) { @@ -1136,6 +1133,8 @@ rrset_canonical(struct regional* region, ldns_buffer* buf, sizeof(rbtree_t)); if(!*sortree) return 0; + if(d->count > RR_COUNT_MAX) + return 0; /* integer overflow protection */ rrs = regional_alloc(region, sizeof(struct canon_rr)*d->count); if(!rrs) { *sortree = NULL; @@ -1145,13 +1144,13 @@ rrset_canonical(struct regional* region, ldns_buffer* buf, canonical_sort(k, d, *sortree, rrs); } - ldns_buffer_clear(buf); - ldns_buffer_write(buf, sig, siglen); + sldns_buffer_clear(buf); + sldns_buffer_write(buf, sig, siglen); /* canonicalize signer name */ - query_dname_tolower(ldns_buffer_begin(buf)+18); + query_dname_tolower(sldns_buffer_begin(buf)+18); RBTREE_FOR(walk, struct canon_rr*, (*sortree)) { /* see if there is enough space left in the buffer */ - if(ldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + if(sldns_buffer_remaining(buf) < can_owner_len + 2 + 2 + 4 + d->rr_len[walk->rr_idx]) { log_err("verify: failed to canonicalize, " "rrset too big"); @@ -1159,17 +1158,17 @@ rrset_canonical(struct regional* region, ldns_buffer* buf, } /* determine canonical owner name */ if(can_owner) - ldns_buffer_write(buf, can_owner, can_owner_len); + sldns_buffer_write(buf, can_owner, can_owner_len); else insert_can_owner(buf, k, sig, &can_owner, &can_owner_len); - ldns_buffer_write(buf, &k->rk.type, 2); - ldns_buffer_write(buf, &k->rk.rrset_class, 2); - ldns_buffer_write(buf, sig+4, 4); - ldns_buffer_write(buf, d->rr_data[walk->rr_idx], + sldns_buffer_write(buf, &k->rk.type, 2); + sldns_buffer_write(buf, &k->rk.rrset_class, 2); + sldns_buffer_write(buf, sig+4, 4); + sldns_buffer_write(buf, d->rr_data[walk->rr_idx], d->rr_len[walk->rr_idx]); canonicalize_rdata(buf, k, d->rr_len[walk->rr_idx]); } - ldns_buffer_flip(buf); + sldns_buffer_flip(buf); return 1; } @@ -1288,282 +1287,21 @@ adjust_ttl(struct val_env* ve, uint32_t unow, * * Use the smallest of these. */ - if(d->ttl > (uint32_t)origttl) { + if(d->ttl > (time_t)origttl) { verbose(VERB_QUERY, "rrset TTL larger than original TTL," " adjusting TTL downwards"); d->ttl = origttl; } - if(expittl > 0 && d->ttl > (uint32_t)expittl) { + if(expittl > 0 && d->ttl > (time_t)expittl) { verbose(VERB_ALGO, "rrset TTL larger than sig expiration ttl," " adjusting TTL downwards"); d->ttl = expittl; } } - -/** - * Output a libcrypto openssl error to the logfile. - * @param str: string to add to it. - * @param e: the error to output, error number from ERR_get_error(). - */ -static void -log_crypto_error(const char* str, unsigned long e) -{ - char buf[128]; - /* or use ERR_error_string if ERR_error_string_n is not avail TODO */ - ERR_error_string_n(e, buf, sizeof(buf)); - /* buf now contains */ - /* error:[error code]:[library name]:[function name]:[reason string] */ - log_err("%s crypto %s", str, buf); -} - -/** - * Setup DSA key digest in DER encoding ... - * @param sig: input is signature output alloced ptr (unless failure). - * caller must free alloced ptr if this routine returns true. - * @param len: intput is initial siglen, output is output len. - * @return false on failure. - */ -static int -setup_dsa_sig(unsigned char** sig, unsigned int* len) -{ - unsigned char* orig = *sig; - unsigned int origlen = *len; - int newlen; - BIGNUM *R, *S; - DSA_SIG *dsasig; - - /* extract the R and S field from the sig buffer */ - if(origlen < 1 + 2*SHA_DIGEST_LENGTH) - return 0; - R = BN_new(); - if(!R) return 0; - (void) BN_bin2bn(orig + 1, SHA_DIGEST_LENGTH, R); - S = BN_new(); - if(!S) return 0; - (void) BN_bin2bn(orig + 21, SHA_DIGEST_LENGTH, S); - dsasig = DSA_SIG_new(); - if(!dsasig) return 0; - - dsasig->r = R; - dsasig->s = S; - *sig = NULL; - newlen = i2d_DSA_SIG(dsasig, sig); - if(newlen < 0) { - free(*sig); - return 0; - } - *len = (unsigned int)newlen; - DSA_SIG_free(dsasig); - return 1; -} - -/** - * Setup key and digest for verification. Adjust sig if necessary. - * - * @param algo: key algorithm - * @param evp_key: EVP PKEY public key to create. - * @param digest_type: digest type to use - * @param key: key to setup for. - * @param keylen: length of key. - * @return false on failure. - */ -static int -setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, - unsigned char* key, size_t keylen) -{ - DSA* dsa; - RSA* rsa; - - switch(algo) { - case LDNS_DSA: - case LDNS_DSA_NSEC3: - *evp_key = EVP_PKEY_new(); - if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return sec_status_unchecked; - } - dsa = ldns_key_buf2dsa_raw(key, keylen); - if(!dsa) { - verbose(VERB_QUERY, "verify: " - "ldns_key_buf2dsa_raw failed"); - return 0; - } - if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_DSA failed"); - return 0; - } - *digest_type = EVP_dss1(); - - break; - case LDNS_RSASHA1: - case LDNS_RSASHA1_NSEC3: -#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2) - case LDNS_RSASHA256: -#endif -#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2) - case LDNS_RSASHA512: -#endif - *evp_key = EVP_PKEY_new(); - if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return sec_status_unchecked; - } - rsa = ldns_key_buf2rsa_raw(key, keylen); - if(!rsa) { - verbose(VERB_QUERY, "verify: " - "ldns_key_buf2rsa_raw SHA failed"); - return 0; - } - if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_RSA SHA failed"); - return 0; - } - - /* select SHA version */ -#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2) - if(algo == LDNS_RSASHA256) - *digest_type = EVP_sha256(); - else -#endif -#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2) - if(algo == LDNS_RSASHA512) - *digest_type = EVP_sha512(); - else -#endif - *digest_type = EVP_sha1(); - - break; - case LDNS_RSAMD5: - *evp_key = EVP_PKEY_new(); - if(!*evp_key) { - log_err("verify: malloc failure in crypto"); - return sec_status_unchecked; - } - rsa = ldns_key_buf2rsa_raw(key, keylen); - if(!rsa) { - verbose(VERB_QUERY, "verify: " - "ldns_key_buf2rsa_raw MD5 failed"); - return 0; - } - if(EVP_PKEY_assign_RSA(*evp_key, rsa) == 0) { - verbose(VERB_QUERY, "verify: " - "EVP_PKEY_assign_RSA MD5 failed"); - return 0; - } - *digest_type = EVP_md5(); - - break; -#ifdef USE_GOST - case LDNS_ECC_GOST: - *evp_key = ldns_gost2pkey_raw(key, keylen); - if(!*evp_key) { - verbose(VERB_QUERY, "verify: " - "ldns_gost2pkey_raw failed"); - return 0; - } - *digest_type = EVP_get_digestbyname("md_gost94"); - if(!*digest_type) { - verbose(VERB_QUERY, "verify: " - "EVP_getdigest md_gost94 failed"); - return 0; - } - break; -#endif - default: - verbose(VERB_QUERY, "verify: unknown algorithm %d", - algo); - return 0; - } - return 1; -} - -/** - * Check a canonical sig+rrset and signature against a dnskey - * @param buf: buffer with data to verify, the first rrsig part and the - * canonicalized rrset. - * @param algo: DNSKEY algorithm. - * @param sigblock: signature rdata field from RRSIG - * @param sigblock_len: length of sigblock data. - * @param key: public key data from DNSKEY RR. - * @param keylen: length of keydata. - * @param reason: bogus reason in more detail. - * @return secure if verification succeeded, bogus on crypto failure, - * unchecked on format errors and alloc failures. - */ -static enum sec_status -verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock, - unsigned int sigblock_len, unsigned char* key, unsigned int keylen, - char** reason) -{ - const EVP_MD *digest_type; - EVP_MD_CTX ctx; - int res, dofree = 0; - EVP_PKEY *evp_key = NULL; - - if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) { - verbose(VERB_QUERY, "verify: failed to setup key"); - *reason = "use of key for crypto failed"; - EVP_PKEY_free(evp_key); - return sec_status_bogus; - } - /* if it is a DSA signature in bind format, convert to DER format */ - if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && - sigblock_len == 1+2*SHA_DIGEST_LENGTH) { - if(!setup_dsa_sig(&sigblock, &sigblock_len)) { - verbose(VERB_QUERY, "verify: failed to setup DSA sig"); - *reason = "use of key for DSA crypto failed"; - EVP_PKEY_free(evp_key); - return sec_status_bogus; - } - dofree = 1; - } - - /* do the signature cryptography work */ - EVP_MD_CTX_init(&ctx); - if(EVP_VerifyInit(&ctx, digest_type) == 0) { - verbose(VERB_QUERY, "verify: EVP_VerifyInit failed"); - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - return sec_status_unchecked; - } - if(EVP_VerifyUpdate(&ctx, (unsigned char*)ldns_buffer_begin(buf), - (unsigned int)ldns_buffer_limit(buf)) == 0) { - verbose(VERB_QUERY, "verify: EVP_VerifyUpdate failed"); - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - return sec_status_unchecked; - } - - res = EVP_VerifyFinal(&ctx, sigblock, sigblock_len, evp_key); - if(EVP_MD_CTX_cleanup(&ctx) == 0) { - verbose(VERB_QUERY, "verify: EVP_MD_CTX_cleanup failed"); - EVP_PKEY_free(evp_key); - if(dofree) free(sigblock); - return sec_status_unchecked; - } - EVP_PKEY_free(evp_key); - - if(dofree) - free(sigblock); - - if(res == 1) { - return sec_status_secure; - } else if(res == 0) { - verbose(VERB_QUERY, "verify: signature mismatch"); - *reason = "signature crypto failed"; - return sec_status_bogus; - } - - log_crypto_error("verify:", ERR_get_error()); - return sec_status_unchecked; -} - enum sec_status -dnskey_verify_rrset_sig(struct regional* region, ldns_buffer* buf, - struct val_env* ve, uint32_t now, +dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, + struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, size_t sig_idx, struct rbtree_t** sortree, int* buf_canon, char** reason) diff --git a/usr.sbin/unbound/validator/validator.c b/usr.sbin/unbound/validator/validator.c index 74068659f01..f8b429e52b5 100644 --- a/usr.sbin/unbound/validator/validator.c +++ b/usr.sbin/unbound/validator/validator.c @@ -2769,7 +2769,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, vq->state = VAL_VALIDATE_STATE; return; } - downprot = 1; + downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve, dnskey, vq->ds_rrset, downprot, &reason); |