MFV r361322:

Update unbound 1.9.6 --> 1.10.1.

Bug Fixes:
 - CVE-2020-12662 Unbound can be tricked into amplifying an incoming
   query into a large number of queries directed to a target.
 - CVE-2020-12663 Malformed answers from upstream name servers can be
   used to make Unbound unresponsive.

Reported by:	emaste
MFC after:	3 days
Relnotes:	yes
Security:	CVE-2020-12662, CVE-2020-12663
This commit is contained in:
Cy Schubert 2020-05-21 21:00:46 +00:00
commit 091e9e469b
92 changed files with 5254 additions and 1590 deletions

12
contrib/unbound/.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['https://nlnetlabs.nl/funding/']

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ Unbound is a validating, recursive, caching DNS resolver. It is designed to be
fast and lean and incorporates modern features based on open standards. If you fast and lean and incorporates modern features based on open standards. If you
have any feedback, we would love to hear from you. Dont hesitate to have any feedback, we would love to hear from you. Dont hesitate to
[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new) [create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
or post a message on the [Unbound mailing list](https://nlnetlabs.nl/mailman/listinfo/unbound-users). or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
You can lean more about Unbound by reading our You can lean more about Unbound by reading our
[documentation](https://nlnetlabs.nl/documentation/unbound/). [documentation](https://nlnetlabs.nl/documentation/unbound/).

View File

@ -1,6 +1,6 @@
# generated automatically by aclocal 1.15.1 -*- Autoconf -*- # generated automatically by aclocal 1.16.1 -*- Autoconf -*-
# Copyright (C) 1996-2017 Free Software Foundation, Inc. # Copyright (C) 1996-2018 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
@ -736,6 +736,7 @@ _LT_CONFIG_SAVE_COMMANDS([
cat <<_LT_EOF >> "$cfgfile" cat <<_LT_EOF >> "$cfgfile"
#! $SHELL #! $SHELL
# Generated automatically by $as_me ($PACKAGE) $VERSION # Generated automatically by $as_me ($PACKAGE) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh. # NOTE: Changes made to this file will be lost: look at ltmain.sh.
# Provide generalized library-building support services. # Provide generalized library-building support services.
@ -2872,6 +2873,9 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
# before this can be enabled. # before this can be enabled.
hardcode_into_libs=yes hardcode_into_libs=yes
# Add ABI-specific directories to the system library path.
sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
# Ideally, we could use ldconfig to report *all* directores which are # Ideally, we could use ldconfig to report *all* directores which are
# searched for libraries, however this is still not possible. Aside from not # searched for libraries, however this is still not possible. Aside from not
# being certain /sbin/ldconfig is available, command # being certain /sbin/ldconfig is available, command
@ -2880,7 +2884,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
# appending ld.so.conf contents (and includes) to the search path. # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
fi fi
# We used to test for /lib/ld.so.1 and disable shared libraries on # We used to test for /lib/ld.so.1 and disable shared libraries on
@ -2892,18 +2896,6 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
dynamic_linker='GNU/Linux ld.so' dynamic_linker='GNU/Linux ld.so'
;; ;;
netbsdelf*-gnu)
version_type=linux
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='NetBSD ld.elf_so'
;;
netbsd*) netbsd*)
version_type=sunos version_type=sunos
need_lib_prefix=no need_lib_prefix=no
@ -3563,7 +3555,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
lt_cv_deplibs_check_method=pass_all lt_cv_deplibs_check_method=pass_all
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
else else
@ -4441,7 +4433,7 @@ m4_if([$1], [CXX], [
;; ;;
esac esac
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
;; ;;
*qnx* | *nto*) *qnx* | *nto*)
# QNX uses GNU C++, but need to define -shared option too, otherwise # QNX uses GNU C++, but need to define -shared option too, otherwise
@ -4953,9 +4945,6 @@ m4_if([$1], [CXX], [
;; ;;
esac esac
;; ;;
linux* | k*bsd*-gnu | gnu*)
_LT_TAGVAR(link_all_deplibs, $1)=no
;;
*) *)
_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
;; ;;
@ -5018,9 +5007,6 @@ dnl Note also adjust exclude_expsyms for C++ above.
openbsd* | bitrig*) openbsd* | bitrig*)
with_gnu_ld=no with_gnu_ld=no
;; ;;
linux* | k*bsd*-gnu | gnu*)
_LT_TAGVAR(link_all_deplibs, $1)=no
;;
esac esac
_LT_TAGVAR(ld_shlibs, $1)=yes _LT_TAGVAR(ld_shlibs, $1)=yes
@ -5275,7 +5261,7 @@ _LT_EOF
fi fi
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc= wlarc=
@ -5796,7 +5782,6 @@ _LT_EOF
if test yes = "$lt_cv_irix_exported_symbol"; then if test yes = "$lt_cv_irix_exported_symbol"; then
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi fi
_LT_TAGVAR(link_all_deplibs, $1)=no
else else
_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
@ -5818,7 +5803,7 @@ _LT_EOF
esac esac
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else else
@ -9059,9 +9044,9 @@ m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
dnl serial 11 (pkg-config-0.29.1) # serial 11 (pkg-config-0.29.1)
dnl
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
dnl dnl
@ -9335,9 +9320,77 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR ])dnl PKG_CHECK_VAR
dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND],
dnl [DESCRIPTION], [DEFAULT])
dnl ------------------------------------------
dnl
dnl Prepare a "--with-" configure option using the lowercase
dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and
dnl PKG_CHECK_MODULES in a single macro.
AC_DEFUN([PKG_WITH_MODULES],
[
m4_pushdef([with_arg], m4_tolower([$1]))
m4_pushdef([description],
[m4_default([$5], [build with ]with_arg[ support])])
m4_pushdef([def_arg], [m4_default([$6], [auto])])
m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes])
m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no])
m4_case(def_arg,
[yes],[m4_pushdef([with_without], [--without-]with_arg)],
[m4_pushdef([with_without],[--with-]with_arg)])
AC_ARG_WITH(with_arg,
AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),,
[AS_TR_SH([with_]with_arg)=def_arg])
AS_CASE([$AS_TR_SH([with_]with_arg)],
[yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)],
[auto],[PKG_CHECK_MODULES([$1],[$2],
[m4_n([def_action_if_found]) $3],
[m4_n([def_action_if_not_found]) $4])])
m4_popdef([with_arg])
m4_popdef([description])
m4_popdef([def_arg])
])dnl PKG_WITH_MODULES
dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [DESCRIPTION], [DEFAULT])
dnl -----------------------------------------------
dnl
dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES
dnl check._[VARIABLE-PREFIX] is exported as make variable.
AC_DEFUN([PKG_HAVE_WITH_MODULES],
[
PKG_WITH_MODULES([$1],[$2],,,[$3],[$4])
AM_CONDITIONAL([HAVE_][$1],
[test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"])
])dnl PKG_HAVE_WITH_MODULES
dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES,
dnl [DESCRIPTION], [DEFAULT])
dnl ------------------------------------------------------
dnl
dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after
dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make
dnl and preprocessor variable.
AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES],
[
PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4])
AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"],
[AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])])
])dnl PKG_HAVE_DEFINE_WITH_MODULES
# AM_CONDITIONAL -*- Autoconf -*- # AM_CONDITIONAL -*- Autoconf -*-
# Copyright (C) 1997-2017 Free Software Foundation, Inc. # Copyright (C) 1997-2018 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,
@ -9368,7 +9421,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]]) Usually this means the macro was only invoked conditionally.]])
fi])]) fi])])
# Copyright (C) 2006-2017 Free Software Foundation, Inc. # Copyright (C) 2006-2018 Free Software Foundation, Inc.
# #
# This file is free software; the Free Software Foundation # This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it, # gives unlimited permission to copy and/or distribute it,

View File

@ -64,26 +64,26 @@
#ifdef HAVE_SYS_ENDIAN_H #ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h> # include <sys/endian.h>
#endif #endif
#ifdef HAVE_LIBKERN_OSBYTEORDER_H
/* In practice this is specific to MacOS X. We assume it doesn't have
* htobe64/be64toh but has alternatives with a different name. */
# include <libkern/OSByteOrder.h>
# define htobe64(x) OSSwapHostToBigInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
#endif
/* Some compilers do not define __BYTE_ORDER__, like IBM XLC on AIX */ #ifndef HAVE_HTOBE64
#ifndef be64toh # ifdef HAVE_LIBKERN_OSBYTEORDER_H
#if defined(__sun) || defined(_AIX) /* In practice this is specific to MacOS X. We assume it doesn't have
# if __BIG_ENDIAN__ * htobe64/be64toh but has alternatives with a different name. */
# define be64toh(n) (n) # include <libkern/OSByteOrder.h>
# define htobe64(n) (n) # define htobe64(x) OSSwapHostToBigInt64(x)
# define be64toh(x) OSSwapBigToHostInt64(x)
# else # else
# define be64toh(n) (((uint64_t)htonl((n) & 0xFFFFFFFF) << 32) | htonl((n) >> 32)) /* not OSX */
# define htobe64(n) (((uint64_t)htonl((n) & 0xFFFFFFFF) << 32) | htonl((n) >> 32)) /* Some compilers do not define __BYTE_ORDER__, like IBM XLC on AIX */
# endif # if __BIG_ENDIAN__
#endif # define be64toh(n) (n)
#endif /* be64toh */ # define htobe64(n) (n)
# else
# define be64toh(n) (((uint64_t)htonl((n) & 0xFFFFFFFF) << 32) | htonl((n) >> 32))
# define htobe64(n) (((uint64_t)htonl((n) & 0xFFFFFFFF) << 32) | htonl((n) >> 32))
# endif /* _ENDIAN */
# endif /* HAVE_LIBKERN_OSBYTEORDER_H */
#endif /* HAVE_BE64TOH */
/** the unit test testframe for cachedb, its module state contains /** the unit test testframe for cachedb, its module state contains
* a cache for a couple queries (in memory). */ * a cache for a couple queries (in memory). */
@ -218,10 +218,6 @@ static int
cachedb_apply_cfg(struct cachedb_env* cachedb_env, struct config_file* cfg) cachedb_apply_cfg(struct cachedb_env* cachedb_env, struct config_file* cfg)
{ {
const char* backend_str = cfg->cachedb_backend; const char* backend_str = cfg->cachedb_backend;
/* If unspecified we use the in-memory test DB. */
if(!backend_str)
backend_str = "testframe";
cachedb_env->backend = cachedb_find_backend(backend_str); cachedb_env->backend = cachedb_find_backend(backend_str);
if(!cachedb_env->backend) { if(!cachedb_env->backend) {
log_err("cachedb: cannot find backend name '%s'", backend_str); log_err("cachedb: cannot find backend name '%s'", backend_str);
@ -259,6 +255,15 @@ cachedb_init(struct module_env* env, int id)
return 0; return 0;
} }
cachedb_env->enabled = 1; cachedb_env->enabled = 1;
if(env->cfg->serve_expired_reply_ttl)
log_warn(
"cachedb: serve-expired-reply-ttl is set but not working for data "
"originating from the external cache; 0 TLL is used for those.");
if(env->cfg->serve_expired_client_timeout)
log_warn(
"cachedb: serve-expired-client-timeout is set but not working for "
"data originating from the external cache; expired data are used "
"in the reply without first trying to refresh the data.");
return 1; return 1;
} }
@ -329,8 +334,7 @@ calc_hash(struct module_qstate* qstate, char* buf, size_t len)
size_t clen = 0; size_t clen = 0;
uint8_t hash[CACHEDB_HASHSIZE/8]; uint8_t hash[CACHEDB_HASHSIZE/8];
const char* hex = "0123456789ABCDEF"; const char* hex = "0123456789ABCDEF";
const char* secret = qstate->env->cfg->cachedb_secret ? const char* secret = qstate->env->cfg->cachedb_secret;
qstate->env->cfg->cachedb_secret : "default";
size_t i; size_t i;
/* copy the hash info into the clear buffer */ /* copy the hash info into the clear buffer */
@ -433,8 +437,14 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
&expiry, sizeof(expiry)); &expiry, sizeof(expiry));
expiry = be64toh(expiry); expiry = be64toh(expiry);
/* Check if we are allowed to return expired entries:
* - serve_expired needs to be set
* - if SERVE_EXPIRED_TTL is set make sure that the record is not older
* than that. */
if((time_t)expiry < *qstate->env->now && if((time_t)expiry < *qstate->env->now &&
!qstate->env->cfg->serve_expired) (!qstate->env->cfg->serve_expired ||
(SERVE_EXPIRED_TTL &&
*qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL)))
return 0; return 0;
return 1; return 1;
@ -445,15 +455,15 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
static void static void
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract) packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
{ {
size_t i; size_t i;
size_t total = data->count + data->rrsig_count; size_t total = data->count + data->rrsig_count;
if(subtract >= 0 && data->ttl > subtract) if(subtract >= 0 && data->ttl > subtract)
data->ttl -= subtract; data->ttl -= subtract;
else data->ttl = 0; else data->ttl = 0;
for(i=0; i<total; i++) { for(i=0; i<total; i++) {
if(subtract >= 0 && data->rr_ttl[i] > subtract) if(subtract >= 0 && data->rr_ttl[i] > subtract)
data->rr_ttl[i] -= subtract; data->rr_ttl[i] -= subtract;
else data->rr_ttl[i] = 0; else data->rr_ttl[i] = 0;
} }
} }
@ -465,7 +475,8 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
size_t i; size_t i;
if(adjust >= 0 && msg->rep->ttl > adjust) if(adjust >= 0 && msg->rep->ttl > adjust)
msg->rep->ttl -= adjust; msg->rep->ttl -= adjust;
else msg->rep->ttl = 0; else
msg->rep->ttl = 0;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
@ -673,7 +684,8 @@ cachedb_handle_query(struct module_qstate* qstate,
return; return;
} }
/* lookup inside unbound's internal cache */ /* lookup inside unbound's internal cache.
* This does not look for expired entries. */
if(cachedb_intcache_lookup(qstate)) { if(cachedb_intcache_lookup(qstate)) {
if(verbosity >= VERB_ALGO) { if(verbosity >= VERB_ALGO) {
if(qstate->return_msg->rep) if(qstate->return_msg->rep)
@ -681,8 +693,9 @@ cachedb_handle_query(struct module_qstate* qstate,
&qstate->return_msg->qinfo, &qstate->return_msg->qinfo,
qstate->return_msg->rep); qstate->return_msg->rep);
else log_info("cachedb internal cache lookup: rcode %s", else log_info("cachedb internal cache lookup: rcode %s",
sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)? sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)
sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name:"??"); ?sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name
:"??");
} }
/* we are done with the query */ /* we are done with the query */
qstate->ext_state[id] = module_finished; qstate->ext_state[id] = module_finished;
@ -697,6 +710,19 @@ cachedb_handle_query(struct module_qstate* qstate,
qstate->return_msg->rep); qstate->return_msg->rep);
/* store this result in internal cache */ /* store this result in internal cache */
cachedb_intcache_store(qstate); cachedb_intcache_store(qstate);
/* In case we have expired data but there is a client timer for expired
* answers, pass execution to next module in order to try updating the
* data first.
* TODO: this needs revisit. The expired data stored from cachedb has
* 0 TTL which is picked up by iterator later when looking in the cache.
* Document that ext cachedb does not work properly with
* serve_stale_reply_ttl yet. */
if(qstate->need_refetch && qstate->serve_expired_data &&
qstate->serve_expired_data->timer) {
qstate->return_msg = NULL;
qstate->ext_state[id] = module_wait_module;
return;
}
/* we are done with the query */ /* we are done with the query */
qstate->ext_state[id] = module_finished; qstate->ext_state[id] = module_finished;
return; return;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: getentropy_solaris.c,v 1.13 2018/11/20 08:04:28 deraadt Exp $ */ /* $OpenBSD: getentropy_solaris.c,v 1.4 2014/07/12 20:41:47 wouter Exp $ */
/* /*
* Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org>
@ -15,12 +15,9 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Emulation of getentropy(2) as documented at:
* http://man.openbsd.org/getentropy.2
*/ */
#include "config.h" #include "config.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -37,7 +34,6 @@
#include <stdint.h> #include <stdint.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <link.h>
#include <termios.h> #include <termios.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
@ -71,14 +67,17 @@
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) #define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) #define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) #define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
int getentropy(void *buf, size_t len); int getentropy(void *buf, size_t len);
#ifdef CAN_REFERENCE_MAIN
extern int main(int, char *argv[]);
#endif
static int gotdata(char *buf, size_t len);
static int getentropy_urandom(void *buf, size_t len, const char *path, static int getentropy_urandom(void *buf, size_t len, const char *path,
int devfscheck); int devfscheck);
static int getentropy_fallback(void *buf, size_t len); static int getentropy_fallback(void *buf, size_t len);
static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
int int
getentropy(void *buf, size_t len) getentropy(void *buf, size_t len)
@ -87,7 +86,7 @@ getentropy(void *buf, size_t len)
if (len > 256) { if (len > 256) {
errno = EIO; errno = EIO;
return (-1); return -1;
} }
/* /*
@ -154,6 +153,22 @@ getentropy(void *buf, size_t len)
return (ret); return (ret);
} }
/*
* Basic sanity checking; wish we could do better.
*/
static int
gotdata(char *buf, size_t len)
{
char any_set = 0;
size_t i;
for (i = 0; i < len; ++i)
any_set |= buf[i];
if (any_set == 0)
return -1;
return 0;
}
static int static int
getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
{ {
@ -200,11 +215,13 @@ getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck)
i += ret; i += ret;
} }
close(fd); close(fd);
errno = save_errno; if (gotdata(buf, len) == 0) {
return (0); /* satisfied */ errno = save_errno;
return 0; /* satisfied */
}
nodevrandom: nodevrandom:
errno = EIO; errno = EIO;
return (-1); return -1;
} }
static const int cl[] = { static const int cl[] = {
@ -232,15 +249,6 @@ static const int cl[] = {
#endif #endif
}; };
static int
getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data)
{
SHA512_CTX *ctx = data;
SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr));
return (0);
}
static int static int
getentropy_fallback(void *buf, size_t len) getentropy_fallback(void *buf, size_t len)
{ {
@ -278,8 +286,6 @@ getentropy_fallback(void *buf, size_t len)
cnt += (int)tv.tv_usec; cnt += (int)tv.tv_usec;
} }
dl_iterate_phdr(getentropy_phdr, &ctx);
for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++)
HX(clock_gettime(cl[ii], &ts) == -1, ts); HX(clock_gettime(cl[ii], &ts) == -1, ts);
@ -300,6 +306,9 @@ getentropy_fallback(void *buf, size_t len)
HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
sigset); sigset);
#ifdef CAN_REFERENCE_MAIN
HF(main); /* an addr in program */
#endif
HF(getentropy); /* an addr in this library */ HF(getentropy); /* an addr in this library */
HF(printf); /* an addr in libc */ HF(printf); /* an addr in libc */
p = (char *)&p; p = (char *)&p;
@ -422,8 +431,11 @@ getentropy_fallback(void *buf, size_t len)
memcpy((char *)buf + i, results, min(sizeof(results), len - i)); memcpy((char *)buf + i, results, min(sizeof(results), len - i));
i += min(sizeof(results), len - i); i += min(sizeof(results), len - i);
} }
explicit_bzero(&ctx, sizeof ctx); memset(results, 0, sizeof results);
explicit_bzero(results, sizeof results); if (gotdata(buf, len) == 0) {
errno = save_errno; errno = save_errno;
return (0); /* satisfied */ return 0; /* satisfied */
}
errno = EIO;
return -1;
} }

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,15 @@
/* Whether the C compiler accepts the "weak" attribute */ /* Whether the C compiler accepts the "weak" attribute */
#undef HAVE_ATTR_WEAK #undef HAVE_ATTR_WEAK
/* If we have be64toh */
#undef HAVE_BE64TOH
/* Define to 1 if you have the <bsd/stdlib.h> header file. */
#undef HAVE_BSD_STDLIB_H
/* Define to 1 if you have the <bsd/string.h> header file. */
#undef HAVE_BSD_STRING_H
/* Define to 1 if you have the `chown' function. */ /* Define to 1 if you have the `chown' function. */
#undef HAVE_CHOWN #undef HAVE_CHOWN
@ -284,6 +293,9 @@
/* If you have HMAC_Update */ /* If you have HMAC_Update */
#undef HAVE_HMAC_UPDATE #undef HAVE_HMAC_UPDATE
/* If we have htobe64 */
#undef HAVE_HTOBE64
/* Define to 1 if you have the `inet_aton' function. */ /* Define to 1 if you have the `inet_aton' function. */
#undef HAVE_INET_ATON #undef HAVE_INET_ATON
@ -311,6 +323,9 @@
/* Define to 1 if you have the `kill' function. */ /* Define to 1 if you have the `kill' function. */
#undef HAVE_KILL #undef HAVE_KILL
/* Use portable libbsd functions */
#undef HAVE_LIBBSD
/* Define to 1 if you have the <libkern/OSByteOrder.h> header file. */ /* Define to 1 if you have the <libkern/OSByteOrder.h> header file. */
#undef HAVE_LIBKERN_OSBYTEORDER_H #undef HAVE_LIBKERN_OSBYTEORDER_H
@ -1231,6 +1246,11 @@ char *strptime(const char *s, const char *format, struct tm *tm);
void *reallocarray(void *ptr, size_t nmemb, size_t size); void *reallocarray(void *ptr, size_t nmemb, size_t size);
#endif #endif
#ifdef HAVE_LIBBSD
#include <bsd/string.h>
#include <bsd/stdlib.h>
#endif
#ifdef HAVE_LIBRESSL #ifdef HAVE_LIBRESSL
# if !HAVE_DECL_STRLCPY # if !HAVE_DECL_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz);

View File

@ -1,8 +1,8 @@
#! /bin/sh #!/usr/bin/sh
# Configuration validation subroutine script. # Configuration validation subroutine script.
# Copyright 1992-2018 Free Software Foundation, Inc. # Copyright 1992-2016 Free Software Foundation, Inc.
timestamp='2018-02-22' timestamp='2016-09-05'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -15,7 +15,7 @@ timestamp='2018-02-22'
# General Public License for more details. # General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, see <https://www.gnu.org/licenses/>. # along with this program; if not, see <http://www.gnu.org/licenses/>.
# #
# As a special exception to the GNU General Public License, if you # As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a # distribute this file as part of a program that contains a
@ -33,7 +33,7 @@ timestamp='2018-02-22'
# Otherwise, we print the canonical config type on stdout and succeed. # Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from: # You can get the latest version of this script from:
# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
# This file is supposed to be the same for all GNU packages # This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases # and recognize all the CPU types, system types and aliases
@ -57,7 +57,7 @@ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Canonicalize a configuration name. Canonicalize a configuration name.
Options: Operation modes:
-h, --help print this help, then exit -h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit -t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit -v, --version print version number, then exit
@ -67,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\ version="\
GNU config.sub ($timestamp) GNU config.sub ($timestamp)
Copyright 1992-2018 Free Software Foundation, Inc. Copyright 1992-2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -94,7 +94,7 @@ while test $# -gt 0 ; do
*local*) *local*)
# First pass through any local machine types. # First pass through any local machine types.
echo "$1" echo $1
exit ;; exit ;;
* ) * )
@ -112,7 +112,7 @@ esac
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations. # Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
@ -120,16 +120,16 @@ case $maybe_os in
kopensolaris*-gnu* | cloudabi*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \
storm-chaos* | os2-emx* | rtmk-nova*) storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os os=-$maybe_os
basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;; ;;
android-linux) android-linux)
os=-linux-android os=-linux-android
basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
;; ;;
*) *)
basic_machine=`echo "$1" | sed 's/-[^-]*$//'` basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ "$basic_machine" != "$1" ] if [ $basic_machine != $1 ]
then os=`echo "$1" | sed 's/.*-/-/'` then os=`echo $1 | sed 's/.*-/-/'`
else os=; fi else os=; fi
;; ;;
esac esac
@ -178,44 +178,44 @@ case $os in
;; ;;
-sco6) -sco6)
os=-sco5v6 os=-sco5v6
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco5) -sco5)
os=-sco3.2v5 os=-sco3.2v5
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco4) -sco4)
os=-sco3.2v4 os=-sco3.2v4
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco3.2.[4-9]*) -sco3.2.[4-9]*)
os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco3.2v[4-9]*) -sco3.2v[4-9]*)
# Don't forget version if it is 3.2v4 or newer. # Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco5v6*) -sco5v6*)
# Don't forget version if it is 3.2v4 or newer. # Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-sco*) -sco*)
os=-sco3.2v2 os=-sco3.2v2
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-udk*) -udk*)
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-isc) -isc)
os=-isc2.2 os=-isc2.2
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-clix*) -clix*)
basic_machine=clipper-intergraph basic_machine=clipper-intergraph
;; ;;
-isc*) -isc*)
basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;; ;;
-lynx*178) -lynx*178)
os=-lynxos178 os=-lynxos178
@ -227,7 +227,10 @@ case $os in
os=-lynxos os=-lynxos
;; ;;
-ptx*) -ptx*)
basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
;;
-windowsnt*)
os=`echo $os | sed -e 's/windowsnt/winnt/'`
;; ;;
-psos*) -psos*)
os=-psos os=-psos
@ -260,7 +263,7 @@ case $basic_machine in
| fido | fr30 | frv | ft32 \ | fido | fr30 | frv | ft32 \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \ | hexagon \
| i370 | i860 | i960 | ia16 | ia64 \ | i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \ | ip2k | iq2000 \
| k1om \ | k1om \
| le32 | le64 \ | le32 | le64 \
@ -296,9 +299,8 @@ case $basic_machine in
| nios | nios2 | nios2eb | nios2el \ | nios | nios2 | nios2eb | nios2el \
| ns16k | ns32k \ | ns16k | ns32k \
| open8 | or1k | or1knd | or32 \ | open8 | or1k | or1knd | or32 \
| pdp10 | pj | pjl \ | pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \ | powerpc | powerpc64 | powerpc64le | powerpcle \
| pru \
| pyramid \ | pyramid \
| riscv32 | riscv64 \ | riscv32 | riscv64 \
| rl78 | rx \ | rl78 | rx \
@ -312,7 +314,7 @@ case $basic_machine in
| ubicom32 \ | ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| visium \ | visium \
| wasm32 \ | we32k \
| x86 | xc16x | xstormy16 | xtensa \ | x86 | xc16x | xstormy16 | xtensa \
| z8k | z80) | z8k | z80)
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
@ -333,7 +335,7 @@ case $basic_machine in
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
os=-none os=-none
;; ;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;; ;;
ms1) ms1)
basic_machine=mt-unknown basic_machine=mt-unknown
@ -362,7 +364,7 @@ case $basic_machine in
;; ;;
# Object if more than one company name word. # Object if more than one company name word.
*-*-*) *-*-*)
echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1 exit 1
;; ;;
# Recognize the basic CPU types with company name. # Recognize the basic CPU types with company name.
@ -385,7 +387,7 @@ case $basic_machine in
| h8300-* | h8500-* \ | h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \ | hexagon-* \
| i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \ | ip2k-* | iq2000-* \
| k1om-* \ | k1om-* \
| le32-* | le64-* \ | le32-* | le64-* \
@ -426,7 +428,6 @@ case $basic_machine in
| orion-* \ | orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pru-* \
| pyramid-* \ | pyramid-* \
| riscv32-* | riscv64-* \ | riscv32-* | riscv64-* \
| rl78-* | romp-* | rs6000-* | rx-* \ | rl78-* | romp-* | rs6000-* | rx-* \
@ -443,7 +444,6 @@ case $basic_machine in
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \ | vax-* \
| visium-* \ | visium-* \
| wasm32-* \
| we32k-* \ | we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \ | xstormy16-* | xtensa*-* \
@ -457,7 +457,7 @@ case $basic_machine in
# Recognize the various machine names and aliases which stand # Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS. # for a CPU type and a company and sometimes even an OS.
386bsd) 386bsd)
basic_machine=i386-pc basic_machine=i386-unknown
os=-bsd os=-bsd
;; ;;
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
@ -491,7 +491,7 @@ case $basic_machine in
basic_machine=x86_64-pc basic_machine=x86_64-pc
;; ;;
amd64-*) amd64-*)
basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
amdahl) amdahl)
basic_machine=580-amdahl basic_machine=580-amdahl
@ -536,7 +536,7 @@ case $basic_machine in
os=-linux os=-linux
;; ;;
blackfin-*) blackfin-*)
basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux os=-linux
;; ;;
bluegene*) bluegene*)
@ -544,13 +544,13 @@ case $basic_machine in
os=-cnk os=-cnk
;; ;;
c54x-*) c54x-*)
basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
c55x-*) c55x-*)
basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
c6x-*) c6x-*)
basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
c90) c90)
basic_machine=c90-cray basic_machine=c90-cray
@ -639,7 +639,7 @@ case $basic_machine in
basic_machine=rs6000-bull basic_machine=rs6000-bull
os=-bosx os=-bosx
;; ;;
dpx2*) dpx2* | dpx2*-bull)
basic_machine=m68k-bull basic_machine=m68k-bull
os=-sysv3 os=-sysv3
;; ;;
@ -648,7 +648,7 @@ case $basic_machine in
os=$os"spe" os=$os"spe"
;; ;;
e500v[12]-*) e500v[12]-*)
basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
os=$os"spe" os=$os"spe"
;; ;;
ebmon29k) ebmon29k)
@ -740,6 +740,9 @@ case $basic_machine in
hp9k8[0-9][0-9] | hp8[0-9][0-9]) hp9k8[0-9][0-9] | hp8[0-9][0-9])
basic_machine=hppa1.0-hp basic_machine=hppa1.0-hp
;; ;;
hppa-next)
os=-nextstep3
;;
hppaosf) hppaosf)
basic_machine=hppa1.1-hp basic_machine=hppa1.1-hp
os=-osf os=-osf
@ -752,26 +755,26 @@ case $basic_machine in
basic_machine=i370-ibm basic_machine=i370-ibm
;; ;;
i*86v32) i*86v32)
basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32 os=-sysv32
;; ;;
i*86v4*) i*86v4*)
basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4 os=-sysv4
;; ;;
i*86v) i*86v)
basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv os=-sysv
;; ;;
i*86sol2) i*86sol2)
basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2 os=-solaris2
;; ;;
i386mach) i386mach)
basic_machine=i386-mach basic_machine=i386-mach
os=-mach os=-mach
;; ;;
vsta) i386-vsta | vsta)
basic_machine=i386-unknown basic_machine=i386-unknown
os=-vsta os=-vsta
;; ;;
@ -790,16 +793,19 @@ case $basic_machine in
os=-sysv os=-sysv
;; ;;
leon-*|leon[3-9]-*) leon-*|leon[3-9]-*)
basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
;; ;;
m68knommu) m68knommu)
basic_machine=m68k-unknown basic_machine=m68k-unknown
os=-linux os=-linux
;; ;;
m68knommu-*) m68knommu-*)
basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux os=-linux
;; ;;
m88k-omron*)
basic_machine=m88k-omron
;;
magnum | m3230) magnum | m3230)
basic_machine=mips-mips basic_machine=mips-mips
os=-sysv os=-sysv
@ -831,10 +837,10 @@ case $basic_machine in
os=-mint os=-mint
;; ;;
mips3*-*) mips3*-*)
basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;; ;;
mips3*) mips3*)
basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;; ;;
monitor) monitor)
basic_machine=m68k-rom68k basic_machine=m68k-rom68k
@ -853,7 +859,7 @@ case $basic_machine in
os=-msdos os=-msdos
;; ;;
ms1-*) ms1-*)
basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;; ;;
msys) msys)
basic_machine=i686-pc basic_machine=i686-pc
@ -895,7 +901,7 @@ case $basic_machine in
basic_machine=v70-nec basic_machine=v70-nec
os=-sysv os=-sysv
;; ;;
next | m*-next) next | m*-next )
basic_machine=m68k-next basic_machine=m68k-next
case $os in case $os in
-nextstep* ) -nextstep* )
@ -940,12 +946,6 @@ case $basic_machine in
nsr-tandem) nsr-tandem)
basic_machine=nsr-tandem basic_machine=nsr-tandem
;; ;;
nsv-tandem)
basic_machine=nsv-tandem
;;
nsx-tandem)
basic_machine=nsx-tandem
;;
op50n-* | op60c-*) op50n-* | op60c-*)
basic_machine=hppa1.1-oki basic_machine=hppa1.1-oki
os=-proelf os=-proelf
@ -978,7 +978,7 @@ case $basic_machine in
os=-linux os=-linux
;; ;;
parisc-*) parisc-*)
basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux os=-linux
;; ;;
pbd) pbd)
@ -994,7 +994,7 @@ case $basic_machine in
basic_machine=i386-pc basic_machine=i386-pc
;; ;;
pc98-*) pc98-*)
basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentium | p5 | k5 | k6 | nexgen | viac3) pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc basic_machine=i586-pc
@ -1009,16 +1009,16 @@ case $basic_machine in
basic_machine=i786-pc basic_machine=i786-pc
;; ;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumpro-* | p6-* | 6x86-* | athlon-*) pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pentium4-*) pentium4-*)
basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
pn) pn)
basic_machine=pn-gould basic_machine=pn-gould
@ -1028,23 +1028,23 @@ case $basic_machine in
ppc | ppcbe) basic_machine=powerpc-unknown ppc | ppcbe) basic_machine=powerpc-unknown
;; ;;
ppc-* | ppcbe-*) ppc-* | ppcbe-*)
basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppcle | powerpclittle) ppcle | powerpclittle)
basic_machine=powerpcle-unknown basic_machine=powerpcle-unknown
;; ;;
ppcle-* | powerpclittle-*) ppcle-* | powerpclittle-*)
basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64) basic_machine=powerpc64-unknown ppc64) basic_machine=powerpc64-unknown
;; ;;
ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ppc64le | powerpc64little) ppc64le | powerpc64little)
basic_machine=powerpc64le-unknown basic_machine=powerpc64le-unknown
;; ;;
ppc64le-* | powerpc64little-*) ppc64le-* | powerpc64little-*)
basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
ps2) ps2)
basic_machine=i386-ibm basic_machine=i386-ibm
@ -1098,10 +1098,17 @@ case $basic_machine in
sequent) sequent)
basic_machine=i386-sequent basic_machine=i386-sequent
;; ;;
sh)
basic_machine=sh-hitachi
os=-hms
;;
sh5el) sh5el)
basic_machine=sh5le-unknown basic_machine=sh5le-unknown
;; ;;
simso-wrs) sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs basic_machine=sparclite-wrs
os=-vxworks os=-vxworks
;; ;;
@ -1120,7 +1127,7 @@ case $basic_machine in
os=-sysv4 os=-sysv4
;; ;;
strongarm-* | thumb-*) strongarm-* | thumb-*)
basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
;; ;;
sun2) sun2)
basic_machine=m68000-sun basic_machine=m68000-sun
@ -1242,9 +1249,6 @@ case $basic_machine in
basic_machine=hppa1.1-winbond basic_machine=hppa1.1-winbond
os=-proelf os=-proelf
;; ;;
x64)
basic_machine=x86_64-pc
;;
xbox) xbox)
basic_machine=i686-pc basic_machine=i686-pc
os=-mingw32 os=-mingw32
@ -1253,12 +1257,20 @@ case $basic_machine in
basic_machine=xps100-honeywell basic_machine=xps100-honeywell
;; ;;
xscale-* | xscalee[bl]-*) xscale-* | xscalee[bl]-*)
basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
;; ;;
ymp) ymp)
basic_machine=ymp-cray basic_machine=ymp-cray
os=-unicos os=-unicos
;; ;;
z8k-*-coff)
basic_machine=z8k-unknown
os=-sim
;;
z80-*-coff)
basic_machine=z80-unknown
os=-sim
;;
none) none)
basic_machine=none-none basic_machine=none-none
os=-none os=-none
@ -1287,6 +1299,10 @@ case $basic_machine in
vax) vax)
basic_machine=vax-dec basic_machine=vax-dec
;; ;;
pdp10)
# there are many clones, so DEC is not a safe bet
basic_machine=pdp10-unknown
;;
pdp11) pdp11)
basic_machine=pdp11-dec basic_machine=pdp11-dec
;; ;;
@ -1296,6 +1312,9 @@ case $basic_machine in
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown basic_machine=sh-unknown
;; ;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
basic_machine=sparc-sun
;;
cydra) cydra)
basic_machine=cydra-cydrome basic_machine=cydra-cydrome
;; ;;
@ -1315,7 +1334,7 @@ case $basic_machine in
# Make sure to match an already-canonicalized machine name. # Make sure to match an already-canonicalized machine name.
;; ;;
*) *)
echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1 exit 1
;; ;;
esac esac
@ -1323,10 +1342,10 @@ esac
# Here we canonicalize certain aliases for manufacturers. # Here we canonicalize certain aliases for manufacturers.
case $basic_machine in case $basic_machine in
*-digital*) *-digital*)
basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
;; ;;
*-commodore*) *-commodore*)
basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
;; ;;
*) *)
;; ;;
@ -1337,8 +1356,8 @@ esac
if [ x"$os" != x"" ] if [ x"$os" != x"" ]
then then
case $os in case $os in
# First match some system type aliases that might get confused # First match some system type aliases
# with valid system types. # that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception. # -solaris* is a basic system type, with this one exception.
-auroraux) -auroraux)
os=-auroraux os=-auroraux
@ -1349,19 +1368,18 @@ case $os in
-solaris) -solaris)
os=-solaris2 os=-solaris2
;; ;;
-svr4*)
os=-sysv4
;;
-unixware*) -unixware*)
os=-sysv4.2uw os=-sysv4.2uw
;; ;;
-gnu/linux*) -gnu/linux*)
os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
;; ;;
# es1800 is here to avoid being matched by es* (a different OS) # First accept the basic system types.
-es1800*)
os=-ose
;;
# Now accept the basic system types.
# The portable systems comes first. # The portable systems comes first.
# Each alternative MUST end in a * to match a version number. # Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4. # -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
@ -1371,26 +1389,25 @@ case $os in
| -aos* | -aros* | -cloudabi* | -sortix* \ | -aos* | -aros* | -cloudabi* | -sortix* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -windiss* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
| -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ | -onefs* | -tirtos* | -phoenix*)
| -midnightbsd*)
# Remember, each alternative MUST END IN *, to match a version number. # Remember, each alternative MUST END IN *, to match a version number.
;; ;;
-qnx*) -qnx*)
@ -1407,12 +1424,12 @@ case $os in
-nto*) -nto*)
os=`echo $os | sed -e 's|nto|nto-qnx|'` os=`echo $os | sed -e 's|nto|nto-qnx|'`
;; ;;
-sim | -xray | -os68k* | -v88r* \ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;; ;;
-mac*) -mac*)
os=`echo "$os" | sed -e 's|mac|macos|'` os=`echo $os | sed -e 's|mac|macos|'`
;; ;;
-linux-dietlibc) -linux-dietlibc)
os=-linux-dietlibc os=-linux-dietlibc
@ -1421,10 +1438,10 @@ case $os in
os=`echo $os | sed -e 's|linux|linux-gnu|'` os=`echo $os | sed -e 's|linux|linux-gnu|'`
;; ;;
-sunos5*) -sunos5*)
os=`echo "$os" | sed -e 's|sunos5|solaris2|'` os=`echo $os | sed -e 's|sunos5|solaris2|'`
;; ;;
-sunos6*) -sunos6*)
os=`echo "$os" | sed -e 's|sunos6|solaris3|'` os=`echo $os | sed -e 's|sunos6|solaris3|'`
;; ;;
-opened*) -opened*)
os=-openedition os=-openedition
@ -1435,6 +1452,12 @@ case $os in
-wince*) -wince*)
os=-wince os=-wince
;; ;;
-osfrose*)
os=-osfrose
;;
-osf*)
os=-osf
;;
-utek*) -utek*)
os=-bsd os=-bsd
;; ;;
@ -1459,7 +1482,7 @@ case $os in
-nova*) -nova*)
os=-rtmk-nova os=-rtmk-nova
;; ;;
-ns2) -ns2 )
os=-nextstep2 os=-nextstep2
;; ;;
-nsk*) -nsk*)
@ -1481,7 +1504,7 @@ case $os in
-oss*) -oss*)
os=-sysv3 os=-sysv3
;; ;;
-svr4*) -svr4)
os=-sysv4 os=-sysv4
;; ;;
-svr3) -svr3)
@ -1496,28 +1519,24 @@ case $os in
-ose*) -ose*)
os=-ose os=-ose
;; ;;
-es1800*)
os=-ose
;;
-xenix)
os=-xenix
;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint os=-mint
;; ;;
-aros*)
os=-aros
;;
-zvmoe) -zvmoe)
os=-zvmoe os=-zvmoe
;; ;;
-dicos*) -dicos*)
os=-dicos os=-dicos
;; ;;
-pikeos*)
# Until real need of OS specific support for
# particular features comes up, bare metal
# configurations are quite functional.
case $basic_machine in
arm*)
os=-eabi
;;
*)
os=-elf
;;
esac
;;
-nacl*) -nacl*)
;; ;;
-ios) -ios)
@ -1527,7 +1546,7 @@ case $os in
*) *)
# Get rid of the `-' at the beginning of $os. # Get rid of the `-' at the beginning of $os.
os=`echo $os | sed 's/[^-]*-//'` os=`echo $os | sed 's/[^-]*-//'`
echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
exit 1 exit 1
;; ;;
esac esac
@ -1617,12 +1636,12 @@ case $basic_machine in
sparc-* | *-sun) sparc-* | *-sun)
os=-sunos4.1.1 os=-sunos4.1.1
;; ;;
pru-*)
os=-elf
;;
*-be) *-be)
os=-beos os=-beos
;; ;;
*-haiku)
os=-haiku
;;
*-ibm) *-ibm)
os=-aix os=-aix
;; ;;
@ -1662,7 +1681,7 @@ case $basic_machine in
m88k-omron*) m88k-omron*)
os=-luna os=-luna
;; ;;
*-next) *-next )
os=-nextstep os=-nextstep
;; ;;
*-sequent) *-sequent)
@ -1677,6 +1696,9 @@ case $basic_machine in
i370-*) i370-*)
os=-mvs os=-mvs
;; ;;
*-next)
os=-nextstep3
;;
*-gould) *-gould)
os=-sysv os=-sysv
;; ;;
@ -1786,15 +1808,15 @@ case $basic_machine in
vendor=stratus vendor=stratus
;; ;;
esac esac
basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;; ;;
esac esac
echo "$basic_machine$os" echo $basic_machine$os
exit exit
# Local variables: # Local variables:
# eval: (add-hook 'write-file-functions 'time-stamp) # eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='" # time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d" # time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'" # time-stamp-end: "'"

View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for unbound 1.9.6. # Generated by GNU Autoconf 2.69 for unbound 1.10.1.
# #
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>. # Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
# #
@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='unbound' PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound' PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.9.6' PACKAGE_VERSION='1.10.1'
PACKAGE_STRING='unbound 1.9.6' PACKAGE_STRING='unbound 1.10.1'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL='' PACKAGE_URL=''
@ -673,8 +673,10 @@ UNBOUND_EVENT_UNINSTALL
UNBOUND_EVENT_INSTALL UNBOUND_EVENT_INSTALL
SUBNET_HEADER SUBNET_HEADER
SUBNET_OBJ SUBNET_OBJ
PC_LIBBSD_DEPENDENCY
SSLLIB SSLLIB
HAVE_SSL HAVE_SSL
PC_CRYPTO_DEPENDENCY
CONFIG_DATE CONFIG_DATE
NETBSD_LINTFLAGS NETBSD_LINTFLAGS
PYUNBOUND_UNINSTALL PYUNBOUND_UNINSTALL
@ -801,7 +803,6 @@ infodir
docdir docdir
oldincludedir oldincludedir
includedir includedir
runstatedir
localstatedir localstatedir
sharedstatedir sharedstatedir
sysconfdir sysconfdir
@ -860,6 +861,7 @@ enable_swig_version_check
with_nss with_nss
with_nettle with_nettle
with_ssl with_ssl
with_libbsd
enable_sha1 enable_sha1
enable_sha2 enable_sha2
enable_subnet enable_subnet
@ -948,7 +950,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc' sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com' sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var' localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include' includedir='${prefix}/include'
oldincludedir='/usr/include' oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1201,15 +1202,6 @@ do
| -silent | --silent | --silen | --sile | --sil) | -silent | --silent | --silen | --sile | --sil)
silent=yes ;; silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;; ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1347,7 +1339,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \ datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir libdir localedir mandir
do do
eval ac_val=\$$ac_var eval ac_val=\$$ac_var
# Remove trailing slashes. # Remove trailing slashes.
@ -1460,7 +1452,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # 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. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures unbound 1.9.6 to adapt to many kinds of systems. \`configure' configures unbound 1.10.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1500,7 +1492,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var] --localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib] --libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include] --includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include] --oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1526,7 +1517,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.9.6:";; short | recursive ) echo "Configuration of unbound 1.10.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@ -1632,6 +1623,7 @@ Optional Packages:
--with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl --with-ssl=pathname enable SSL (will check /usr/local/ssl /usr/lib/ssl
/usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw /usr/ssl /usr/pkg /usr/local /opt/local /usr/sfw
/usr) /usr)
--with-libbsd Use portable libbsd functions
--with-libevent=pathname --with-libevent=pathname
use libevent (will check /usr/local /opt/local use libevent (will check /usr/local /opt/local
/usr/lib /usr/pkg /usr/sfw /usr or you can specify /usr/lib /usr/pkg /usr/sfw /usr or you can specify
@ -1748,7 +1740,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
unbound configure 1.9.6 unbound configure 1.10.1
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@ -2457,7 +2449,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by unbound $as_me 1.9.6, which was It was created by unbound $as_me 1.10.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@ -2807,13 +2799,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=9 UNBOUND_VERSION_MINOR=10
UNBOUND_VERSION_MICRO=6 UNBOUND_VERSION_MICRO=1
LIBUNBOUND_CURRENT=9 LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=6 LIBUNBOUND_REVISION=8
LIBUNBOUND_AGE=1 LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0 # 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0 # 1.0.1 had 0:13:0
@ -2887,6 +2879,8 @@ LIBUNBOUND_AGE=1
# 1.9.4 had 9:4:1 # 1.9.4 had 9:4:1
# 1.9.5 had 9:5:1 # 1.9.5 had 9:5:1
# 1.9.6 had 9:6:1 # 1.9.6 had 9:6:1
# 1.10.0 had 9:7:1
# 1.10.1 had 9:8:1
# Current -- the number of the binary API that we're implementing # Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary # Revision -- which iteration of the implementation of the binary
@ -8061,7 +8055,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
lt_cv_deplibs_check_method=pass_all lt_cv_deplibs_check_method=pass_all
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
else else
@ -11526,9 +11520,6 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
openbsd* | bitrig*) openbsd* | bitrig*)
with_gnu_ld=no with_gnu_ld=no
;; ;;
linux* | k*bsd*-gnu | gnu*)
link_all_deplibs=no
;;
esac esac
ld_shlibs=yes ld_shlibs=yes
@ -11783,7 +11774,7 @@ _LT_EOF
fi fi
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
wlarc= wlarc=
@ -12453,7 +12444,6 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
if test yes = "$lt_cv_irix_exported_symbol"; then if test yes = "$lt_cv_irix_exported_symbol"; then
archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
fi fi
link_all_deplibs=no
else else
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
@ -12475,7 +12465,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
esac esac
;; ;;
netbsd* | netbsdelf*-gnu) netbsd*)
if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
else else
@ -13570,6 +13560,9 @@ fi
# before this can be enabled. # before this can be enabled.
hardcode_into_libs=yes hardcode_into_libs=yes
# Add ABI-specific directories to the system library path.
sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
# Ideally, we could use ldconfig to report *all* directores which are # Ideally, we could use ldconfig to report *all* directores which are
# searched for libraries, however this is still not possible. Aside from not # searched for libraries, however this is still not possible. Aside from not
# being certain /sbin/ldconfig is available, command # being certain /sbin/ldconfig is available, command
@ -13578,7 +13571,7 @@ fi
# appending ld.so.conf contents (and includes) to the search path. # appending ld.so.conf contents (and includes) to the search path.
if test -f /etc/ld.so.conf; then if test -f /etc/ld.so.conf; then
lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
fi fi
# We used to test for /lib/ld.so.1 and disable shared libraries on # We used to test for /lib/ld.so.1 and disable shared libraries on
@ -13590,18 +13583,6 @@ fi
dynamic_linker='GNU/Linux ld.so' dynamic_linker='GNU/Linux ld.so'
;; ;;
netbsdelf*-gnu)
version_type=linux
need_lib_prefix=no
need_version=no
library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
soname_spec='${libname}${release}${shared_ext}$major'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
hardcode_into_libs=yes
dynamic_linker='NetBSD ld.elf_so'
;;
netbsd*) netbsd*)
version_type=sunos version_type=sunos
need_lib_prefix=no need_lib_prefix=no
@ -15668,7 +15649,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -15714,7 +15695,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -15738,7 +15719,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -15783,7 +15764,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -15807,7 +15788,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -17783,6 +17764,8 @@ $as_echo "#define HAVE_NSS 1" >>confdefs.h
fi fi
LIBS="$LIBS -lnss3 -lnspr4" LIBS="$LIBS -lnss3 -lnspr4"
SSLLIB="" SSLLIB=""
PC_CRYPTO_DEPENDENCY="nss nspr"
fi fi
@ -17826,6 +17809,8 @@ done
fi fi
LIBS="$LIBS -lhogweed -lnettle -lgmp" LIBS="$LIBS -lhogweed -lnettle -lgmp"
SSLLIB="" SSLLIB=""
PC_CRYPTO_DEPENDENCY="hogweed nettle"
fi fi
@ -18176,6 +18161,9 @@ rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext conftest$ac_exeext conftest.$ac_ext
SSLLIB="-lssl" SSLLIB="-lssl"
PC_CRYPTO_DEPENDENCY="libcrypto libssl"
# check if -lcrypt32 is needed because CAPIENG needs that. (on windows) # check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
BAKLIBS="$LIBS" BAKLIBS="$LIBS"
LIBS="-lssl $LIBS" LIBS="-lssl $LIBS"
@ -18466,6 +18454,96 @@ fi
fi fi
# libbsd
# Check whether --with-libbsd was given.
if test "${with_libbsd+set}" = set; then :
withval=$with_libbsd;
for ac_header in bsd/string.h bsd/stdlib.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
fi
done
if test "x$ac_cv_header_bsd_string_h" = xyes -a "x$ac_cv_header_bsd_stdlib_h" = xyes; then
for func in strlcpy strlcat arc4random arc4random_uniform reallocarray; do
as_ac_Search=`$as_echo "ac_cv_search_$func" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing $func" >&5
$as_echo_n "checking for library containing $func... " >&6; }
if eval \${$as_ac_Search+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char $func ();
int
main ()
{
return $func ();
;
return 0;
}
_ACEOF
for ac_lib in '' bsd; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
eval "$as_ac_Search=\$ac_res"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if eval \${$as_ac_Search+:} false; then :
break
fi
done
if eval \${$as_ac_Search+:} false; then :
else
eval "$as_ac_Search=no"
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
eval ac_res=\$$as_ac_Search
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
eval ac_res=\$$as_ac_Search
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
$as_echo "#define HAVE_LIBBSD 1" >>confdefs.h
PC_LIBBSD_DEPENDENCY=libbsd
fi
done
fi
fi
# Check whether --enable-sha1 was given. # Check whether --enable-sha1 was given.
if test "${enable_sha1+set}" = set; then : if test "${enable_sha1+set}" = set; then :
@ -18769,9 +18847,7 @@ fi
use_dsa="no" use_dsa="no"
case "$enable_dsa" in case "$enable_dsa" in
no) yes)
;;
*)
# detect if DSA is supported, and turn it off if not. # detect if DSA is supported, and turn it off if not.
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
ac_fn_c_check_func "$LINENO" "DSA_SIG_new" "ac_cv_func_DSA_SIG_new" ac_fn_c_check_func "$LINENO" "DSA_SIG_new" "ac_cv_func_DSA_SIG_new"
@ -18824,6 +18900,10 @@ _ACEOF
fi fi
;; ;;
*)
# disable dsa by default, RFC 8624 section 3.1, validators MUST NOT
# support DSA for DNSSEC Validation.
;;
esac esac
# Check whether --enable-ed25519 was given. # Check whether --enable-ed25519 was given.
@ -19948,6 +20028,75 @@ _ACEOF
fi fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for htobe64" >&5
$as_echo_n "checking for htobe64... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
int
main ()
{
unsigned long long x = htobe64(0); printf("%u", (unsigned)x);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_HTOBE64 1" >>confdefs.h
else
{ $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
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for be64toh" >&5
$as_echo_n "checking for be64toh... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
int
main ()
{
unsigned long long x = be64toh(0); printf("%u", (unsigned)x);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_BE64TOH 1" >>confdefs.h
else
{ $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
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing setusercontext" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing setusercontext" >&5
$as_echo_n "checking for library containing setusercontext... " >&6; } $as_echo_n "checking for library containing setusercontext... " >&6; }
if ${ac_cv_search_setusercontext+:} false; then : if ${ac_cv_search_setusercontext+:} false; then :
@ -21450,12 +21599,12 @@ _ACEOF
version=1.9.6 version=1.10.1
date=`date +'%b %e, %Y'` date=`date +'%b %e, %Y'`
ac_config_files="$ac_config_files Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service" ac_config_files="$ac_config_files Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service contrib/unbound_portable.service"
ac_config_headers="$ac_config_headers config.h" ac_config_headers="$ac_config_headers config.h"
@ -21969,7 +22118,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by unbound $as_me 1.9.6, which was This file was extended by unbound $as_me 1.10.1, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@ -22035,7 +22184,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
unbound config.status 1.9.6 unbound config.status 1.10.1
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"
@ -22461,6 +22610,7 @@ do
"contrib/libunbound.pc") CONFIG_FILES="$CONFIG_FILES contrib/libunbound.pc" ;; "contrib/libunbound.pc") CONFIG_FILES="$CONFIG_FILES contrib/libunbound.pc" ;;
"contrib/unbound.socket") CONFIG_FILES="$CONFIG_FILES contrib/unbound.socket" ;; "contrib/unbound.socket") CONFIG_FILES="$CONFIG_FILES contrib/unbound.socket" ;;
"contrib/unbound.service") CONFIG_FILES="$CONFIG_FILES contrib/unbound.service" ;; "contrib/unbound.service") CONFIG_FILES="$CONFIG_FILES contrib/unbound.service" ;;
"contrib/unbound_portable.service") CONFIG_FILES="$CONFIG_FILES contrib/unbound_portable.service" ;;
"config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
@ -23027,6 +23177,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
cat <<_LT_EOF >> "$cfgfile" cat <<_LT_EOF >> "$cfgfile"
#! $SHELL #! $SHELL
# Generated automatically by $as_me ($PACKAGE) $VERSION # Generated automatically by $as_me ($PACKAGE) $VERSION
# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh. # NOTE: Changes made to this file will be lost: look at ltmain.sh.
# Provide generalized library-building support services. # Provide generalized library-building support services.

View File

@ -10,15 +10,15 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing # must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[9]) m4_define([VERSION_MINOR],[10])
m4_define([VERSION_MICRO],[6]) m4_define([VERSION_MICRO],[1])
AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues, unbound) AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues, unbound)
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9 LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=6 LIBUNBOUND_REVISION=8
LIBUNBOUND_AGE=1 LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0 # 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0 # 1.0.1 had 0:13:0
@ -92,6 +92,8 @@ LIBUNBOUND_AGE=1
# 1.9.4 had 9:4:1 # 1.9.4 had 9:4:1
# 1.9.5 had 9:5:1 # 1.9.5 had 9:5:1
# 1.9.6 had 9:6:1 # 1.9.6 had 9:6:1
# 1.10.0 had 9:7:1
# 1.10.1 had 9:8:1
# Current -- the number of the binary API that we're implementing # Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary # Revision -- which iteration of the implementation of the binary
@ -760,6 +762,8 @@ AC_ARG_WITH([nss], AC_HELP_STRING([--with-nss=path],
fi fi
LIBS="$LIBS -lnss3 -lnspr4" LIBS="$LIBS -lnss3 -lnspr4"
SSLLIB="" SSLLIB=""
PC_CRYPTO_DEPENDENCY="nss nspr"
AC_SUBST(PC_CRYPTO_DEPENDENCY)
] ]
) )
@ -780,6 +784,8 @@ AC_ARG_WITH([nettle], AC_HELP_STRING([--with-nettle=path],
fi fi
LIBS="$LIBS -lhogweed -lnettle -lgmp" LIBS="$LIBS -lhogweed -lnettle -lgmp"
SSLLIB="" SSLLIB=""
PC_CRYPTO_DEPENDENCY="hogweed nettle"
AC_SUBST(PC_CRYPTO_DEPENDENCY)
] ]
) )
@ -789,6 +795,9 @@ ACX_WITH_SSL
ACX_LIB_SSL ACX_LIB_SSL
SSLLIB="-lssl" SSLLIB="-lssl"
PC_CRYPTO_DEPENDENCY="libcrypto libssl"
AC_SUBST(PC_CRYPTO_DEPENDENCY)
# check if -lcrypt32 is needed because CAPIENG needs that. (on windows) # check if -lcrypt32 is needed because CAPIENG needs that. (on windows)
BAKLIBS="$LIBS" BAKLIBS="$LIBS"
LIBS="-lssl $LIBS" LIBS="-lssl $LIBS"
@ -880,6 +889,19 @@ fi
fi fi
AC_SUBST(SSLLIB) AC_SUBST(SSLLIB)
# libbsd
AC_ARG_WITH([libbsd], AC_HELP_STRING([--with-libbsd], [Use portable libbsd functions]), [
AC_CHECK_HEADERS([bsd/string.h bsd/stdlib.h],,, [AC_INCLUDES_DEFAULT])
if test "x$ac_cv_header_bsd_string_h" = xyes -a "x$ac_cv_header_bsd_stdlib_h" = xyes; then
for func in strlcpy strlcat arc4random arc4random_uniform reallocarray; do
AC_SEARCH_LIBS([$func], [bsd], [
AC_DEFINE(HAVE_LIBBSD, 1, [Use portable libbsd functions])
PC_LIBBSD_DEPENDENCY=libbsd
AC_SUBST(PC_LIBBSD_DEPENDENCY)
])
done
fi
])
AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support])) AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support]))
case "$enable_sha1" in case "$enable_sha1" in
@ -1064,9 +1086,7 @@ esac
AC_ARG_ENABLE(dsa, AC_HELP_STRING([--disable-dsa], [Disable DSA support])) AC_ARG_ENABLE(dsa, AC_HELP_STRING([--disable-dsa], [Disable DSA support]))
use_dsa="no" use_dsa="no"
case "$enable_dsa" in case "$enable_dsa" in
no) yes)
;;
*)
# detect if DSA is supported, and turn it off if not. # detect if DSA is supported, and turn it off if not.
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
AC_CHECK_FUNC(DSA_SIG_new, [ AC_CHECK_FUNC(DSA_SIG_new, [
@ -1097,6 +1117,10 @@ AC_INCLUDES_DEFAULT
AC_DEFINE_UNQUOTED([USE_DSA], [1], [Define this to enable DSA support.]) AC_DEFINE_UNQUOTED([USE_DSA], [1], [Define this to enable DSA support.])
fi fi
;; ;;
*)
# disable dsa by default, RFC 8624 section 3.1, validators MUST NOT
# support DSA for DNSSEC Validation.
;;
esac esac
AC_ARG_ENABLE(ed25519, AC_HELP_STRING([--disable-ed25519], [Disable ED25519 support])) AC_ARG_ENABLE(ed25519, AC_HELP_STRING([--disable-ed25519], [Disable ED25519 support]))
@ -1467,6 +1491,35 @@ AC_INCLUDES_DEFAULT
#include <ws2tcpip.h> #include <ws2tcpip.h>
#endif #endif
]) ])
AC_MSG_CHECKING([for htobe64])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
], [unsigned long long x = htobe64(0); printf("%u", (unsigned)x);])],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_HTOBE64, 1, [If we have htobe64]),
AC_MSG_RESULT(no))
AC_MSG_CHECKING([for be64toh])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
# include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
# include <sys/endian.h>
#endif
], [unsigned long long x = be64toh(0); printf("%u", (unsigned)x);])],
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_BE64TOH, 1, [If we have be64toh]),
AC_MSG_RESULT(no))
AC_SEARCH_LIBS([setusercontext], [util]) AC_SEARCH_LIBS([setusercontext], [util])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4]) AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])]) AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
@ -1945,6 +1998,11 @@ char *strptime(const char *s, const char *format, struct tm *tm);
void *reallocarray(void *ptr, size_t nmemb, size_t size); void *reallocarray(void *ptr, size_t nmemb, size_t size);
#endif #endif
#ifdef HAVE_LIBBSD
#include <bsd/string.h>
#include <bsd/stdlib.h>
#endif
#ifdef HAVE_LIBRESSL #ifdef HAVE_LIBRESSL
# if !HAVE_DECL_STRLCPY # if !HAVE_DECL_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz); size_t strlcpy(char *dst, const char *src, size_t siz);
@ -2046,6 +2104,6 @@ dnl if this is a distro tarball, that was already done by makedist.sh
AC_SUBST(version, [VERSION_MAJOR.VERSION_MINOR.VERSION_MICRO]) AC_SUBST(version, [VERSION_MAJOR.VERSION_MINOR.VERSION_MICRO])
AC_SUBST(date, [`date +'%b %e, %Y'`]) AC_SUBST(date, [`date +'%b %e, %Y'`])
AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service]) AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8 doc/unbound-host.1 smallapp/unbound-control-setup.sh dnstap/dnstap_config.h dnscrypt/dnscrypt_config.h contrib/libunbound.pc contrib/unbound.socket contrib/unbound.service contrib/unbound_portable.service])
AC_CONFIG_HEADER([config.h]) AC_CONFIG_HEADER([config.h])
AC_OUTPUT AC_OUTPUT

View File

@ -27,10 +27,12 @@ distribution but may be helpful.
works like the BIND feature (removes AAAA records unless AAAA-only domain). works like the BIND feature (removes AAAA records unless AAAA-only domain).
Useful for certain 'broken IPv6 default route' scenarios. Useful for certain 'broken IPv6 default route' scenarios.
Patch from Stephane Lapie for ASAHI Net. Patch from Stephane Lapie for ASAHI Net.
* unbound_smf22.tar.gz: Solaris SMF installation/removal scripts. * unbound_smf23.tar.gz: Solaris SMF installation/removal scripts.
Contributed by Yuri Voinov. Contributed by Yuri Voinov.
* unbound.socket and unbound.service: systemd files for unbound, install them * unbound.socket and unbound.service: systemd files for unbound, install them
in /usr/lib/systemd/system. Contributed by Sami Kerola and Pavel Odintsov. in /usr/lib/systemd/system. Contributed by Sami Kerola and Pavel Odintsov.
* unbound_portable.service.in: systemd file for use unbound as portable service,
see comments in the file. Contributed by Frzk.
* redirect-bogus.patch: Return configured address for bogus A and AAAA answers, * redirect-bogus.patch: Return configured address for bogus A and AAAA answers,
instead of SERVFAIL. Contributed by SIDN. instead of SERVFAIL. Contributed by SIDN.
* fastrpz.patch: fastrpz support from Farsight Security. * fastrpz.patch: fastrpz support from Farsight Security.
@ -49,3 +51,5 @@ distribution but may be helpful.
compile. From Saksham Manchanda (Secure64). Please note that we think compile. From Saksham Manchanda (Secure64). Please note that we think
this will drop DNSKEY and DS lookups for tlds and hence break DNSSEC this will drop DNSKEY and DS lookups for tlds and hence break DNSSEC
lookups for downstream clients. lookups for downstream clients.
* drop2rpz: perl script that converts the Spamhaus DROP-List in RPZ-Format,
contributed by Andreas Schulze.

View File

@ -0,0 +1,39 @@
#!/usr/bin/perl
# usage: curl --silent https://www.spamhaus.org/drop/drop.txt | $0 > /path/to/spamhaus-drop.rpz.local
#
# unbound.conf:
# rpz:
# name: "spamhaus-drop.rpz.local."
# zonefile: "/path/tp/spamhaus-drop.rpz.local"
# rpz-log: yes
# rpz-log-name: "spamhaus-drop"
#
use strict;
use vars qw{$o1 $o2 $o3 $o4 $m};
# trailing dots required
my $origin = 'drop.spamhaus.org.rpz.local.';
my $mname = 'localhost.';
my $rname = 'root.localhost.';
my $ns = $mname;
my $rpz_action = '.'; # return NXDOMAIN
#my $rpz_action = '*.'; # return NODATA
#my $rpz_action = 'rpz-drop.'; # drop the query
print "$origin SOA $mname $rname 1 43200 7200 2419200 3600\n";
print "$origin NS $ns\n";
while(<>) {
if(($o1, $o2, $o3, $o4, $m) = m{(\d+)\.(\d+)\.(\d+)\.(\d+)/(\d+)}) {
print "$m.$o4.$o3.$o2.$o1.rpz-ip.$origin CNAME $rpz_action\n";
} else {
print "$_";
}
}
# add a testpoint: ask for "dns.google"
# print "32.8.8.8.8.rpz-ip.$origin CNAME $rpz_action\n";
exit;

View File

@ -2,7 +2,7 @@ Description: based on the included patch contrib/fastrpz.patch
Author: fastrpz@farsightsecurity.com Author: fastrpz@farsightsecurity.com
--- ---
diff --git a/Makefile.in b/Makefile.in diff --git a/Makefile.in b/Makefile.in
index 721c01b6..56bfb560 100644 index a20058cc..495779cc 100644
--- a/Makefile.in --- a/Makefile.in
+++ b/Makefile.in +++ b/Makefile.in
@@ -23,6 +23,8 @@ CHECKLOCK_SRC=testcode/checklocks.c @@ -23,6 +23,8 @@ CHECKLOCK_SRC=testcode/checklocks.c
@ -14,7 +14,7 @@ index 721c01b6..56bfb560 100644
DNSCRYPT_SRC=@DNSCRYPT_SRC@ DNSCRYPT_SRC=@DNSCRYPT_SRC@
DNSCRYPT_OBJ=@DNSCRYPT_OBJ@ DNSCRYPT_OBJ=@DNSCRYPT_OBJ@
WITH_PYTHONMODULE=@WITH_PYTHONMODULE@ WITH_PYTHONMODULE=@WITH_PYTHONMODULE@
@@ -126,7 +128,7 @@ validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c \ @@ -127,7 +129,7 @@ validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c \
edns-subnet/edns-subnet.c edns-subnet/subnetmod.c \ edns-subnet/edns-subnet.c edns-subnet/subnetmod.c \
edns-subnet/addrtree.c edns-subnet/subnet-whitelist.c \ edns-subnet/addrtree.c edns-subnet/subnet-whitelist.c \
cachedb/cachedb.c cachedb/redis.c respip/respip.c $(CHECKLOCK_SRC) \ cachedb/cachedb.c cachedb/redis.c respip/respip.c $(CHECKLOCK_SRC) \
@ -23,7 +23,7 @@ index 721c01b6..56bfb560 100644
COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \ COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \
as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \
iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \ iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \
@@ -139,7 +141,7 @@ autotrust.lo val_anchor.lo \ @@ -140,7 +142,7 @@ autotrust.lo val_anchor.lo rpz.lo \
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \ validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo redis.lo authzone.lo \ val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo redis.lo authzone.lo \
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \ $(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
@ -32,7 +32,7 @@ index 721c01b6..56bfb560 100644
COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \ COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \
outside_network.lo outside_network.lo
COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo
@@ -409,6 +411,11 @@ dnscrypt.lo dnscrypt.o: $(srcdir)/dnscrypt/dnscrypt.c config.h \ @@ -410,6 +412,11 @@ dnscrypt.lo dnscrypt.o: $(srcdir)/dnscrypt/dnscrypt.c config.h \
$(srcdir)/util/config_file.h $(srcdir)/util/log.h \ $(srcdir)/util/config_file.h $(srcdir)/util/log.h \
$(srcdir)/util/netevent.h $(srcdir)/util/netevent.h
@ -45,10 +45,10 @@ index 721c01b6..56bfb560 100644
pythonmod.lo pythonmod.o: $(srcdir)/pythonmod/pythonmod.c config.h \ pythonmod.lo pythonmod.o: $(srcdir)/pythonmod/pythonmod.c config.h \
pythonmod/interface.h \ pythonmod/interface.h \
diff --git a/config.h.in b/config.h.in diff --git a/config.h.in b/config.h.in
index 8c2aa3b9..efaf6450 100644 index 78d47fed..e33073e4 100644
--- a/config.h.in --- a/config.h.in
+++ b/config.h.in +++ b/config.h.in
@@ -1325,4 +1325,11 @@ void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file, @@ -1345,4 +1345,11 @@ void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
/** the version of unbound-control that this software implements */ /** the version of unbound-control that this software implements */
#define UNBOUND_CONTROL_VERSION 1 #define UNBOUND_CONTROL_VERSION 1
@ -62,7 +62,7 @@ index 8c2aa3b9..efaf6450 100644
+/** turn on fastrpz response policy zones */ +/** turn on fastrpz response policy zones */
+#undef ENABLE_FASTRPZ +#undef ENABLE_FASTRPZ
diff --git a/configure.ac b/configure.ac diff --git a/configure.ac b/configure.ac
index 5276d441..9d74592e 100644 index 2b91dd3c..e6063d17 100644
--- a/configure.ac --- a/configure.ac
+++ b/configure.ac +++ b/configure.ac
@@ -6,6 +6,7 @@ sinclude(ax_pthread.m4) @@ -6,6 +6,7 @@ sinclude(ax_pthread.m4)
@ -73,7 +73,7 @@ index 5276d441..9d74592e 100644
sinclude(dnscrypt/dnscrypt.m4) sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing # must be numbers. ac_defun because of later processing
@@ -1726,6 +1727,9 @@ case "$enable_ipset" in @@ -1778,6 +1779,9 @@ case "$enable_ipset" in
;; ;;
esac esac
@ -84,7 +84,7 @@ index 5276d441..9d74592e 100644
# on openBSD, the implicit rule make $< work. # on openBSD, the implicit rule make $< work.
# on Solaris, it does not work ($? is changed sources, $^ lists dependencies). # on Solaris, it does not work ($? is changed sources, $^ lists dependencies).
diff --git a/daemon/daemon.c b/daemon/daemon.c diff --git a/daemon/daemon.c b/daemon/daemon.c
index 0b1200a2..5857c18b 100644 index 8b0fc348..7ffb9221 100644
--- a/daemon/daemon.c --- a/daemon/daemon.c
+++ b/daemon/daemon.c +++ b/daemon/daemon.c
@@ -91,6 +91,9 @@ @@ -91,6 +91,9 @@
@ -112,7 +112,7 @@ index 0b1200a2..5857c18b 100644
#endif #endif
} }
for(i=0; i<daemon->num; i++) { for(i=0; i<daemon->num; i++) {
@@ -724,6 +735,9 @@ daemon_cleanup(struct daemon* daemon) @@ -731,6 +742,9 @@ daemon_cleanup(struct daemon* daemon)
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
dnsc_delete(daemon->dnscenv); dnsc_delete(daemon->dnscenv);
daemon->dnscenv = NULL; daemon->dnscenv = NULL;
@ -123,10 +123,10 @@ index 0b1200a2..5857c18b 100644
daemon->cfg = NULL; daemon->cfg = NULL;
} }
diff --git a/daemon/daemon.h b/daemon/daemon.h diff --git a/daemon/daemon.h b/daemon/daemon.h
index 5749dbef..64ce230f 100644 index 3effbafb..4d4c34da 100644
--- a/daemon/daemon.h --- a/daemon/daemon.h
+++ b/daemon/daemon.h +++ b/daemon/daemon.h
@@ -136,6 +136,11 @@ struct daemon { @@ -138,6 +138,11 @@ struct daemon {
/** the dnscrypt environment */ /** the dnscrypt environment */
struct dnsc_env* dnscenv; struct dnsc_env* dnscenv;
#endif #endif
@ -139,10 +139,10 @@ index 5749dbef..64ce230f 100644
/** /**
diff --git a/daemon/worker.c b/daemon/worker.c diff --git a/daemon/worker.c b/daemon/worker.c
index e2ce0e87..f031c656 100644 index eb7fdf2f..1982228d 100644
--- a/daemon/worker.c --- a/daemon/worker.c
+++ b/daemon/worker.c +++ b/daemon/worker.c
@@ -75,6 +75,9 @@ @@ -76,6 +76,9 @@
#include "libunbound/context.h" #include "libunbound/context.h"
#include "libunbound/libworker.h" #include "libunbound/libworker.h"
#include "sldns/sbuffer.h" #include "sldns/sbuffer.h"
@ -152,7 +152,7 @@ index e2ce0e87..f031c656 100644
#include "sldns/wire2str.h" #include "sldns/wire2str.h"
#include "util/shm_side/shm_main.h" #include "util/shm_side/shm_main.h"
#include "dnscrypt/dnscrypt.h" #include "dnscrypt/dnscrypt.h"
@@ -533,8 +536,27 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, @@ -534,8 +537,27 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
/* not secure */ /* not secure */
secure = 0; secure = 0;
break; break;
@ -180,10 +180,10 @@ index e2ce0e87..f031c656 100644
/* return this delegation from the cache */ /* return this delegation from the cache */
edns_bak = *edns; edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION; edns->edns_version = EDNS_ADVERTISED_VERSION;
@@ -699,6 +721,23 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, @@ -710,6 +732,23 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
secure = 0; *is_secure_answer = 0;
} }
} else secure = 0; } else *is_secure_answer = 0;
+#ifdef ENABLE_FASTRPZ +#ifdef ENABLE_FASTRPZ
+ if(repinfo->rpz) { + if(repinfo->rpz) {
+ /* Scan the cached answer for RPZ hits. + /* Scan the cached answer for RPZ hits.
@ -204,7 +204,7 @@ index e2ce0e87..f031c656 100644
edns_bak = *edns; edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION; edns->edns_version = EDNS_ADVERTISED_VERSION;
@@ -1410,6 +1449,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error, @@ -1435,6 +1474,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from", log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->addr, repinfo->addrlen); &repinfo->addr, repinfo->addrlen);
goto send_reply; goto send_reply;
@ -220,14 +220,14 @@ index e2ce0e87..f031c656 100644
} }
/* If we've found a local alias, replace the qname with the alias /* If we've found a local alias, replace the qname with the alias
@@ -1458,12 +1506,21 @@ lookup_cache: @@ -1485,12 +1533,21 @@ lookup_cache:
h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) { if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */ /* answer from cache - we have acquired a readlock on it */
- if(answer_from_cache(worker, &qinfo, - if(answer_from_cache(worker, &qinfo,
+ ret = answer_from_cache(worker, &qinfo, + ret = answer_from_cache(worker, &qinfo,
cinfo, &need_drop, &alias_rrset, &partial_rep, cinfo, &need_drop, &is_expired_answer, &is_secure_answer,
(struct reply_info*)e->data, &alias_rrset, &partial_rep, (struct reply_info*)e->data,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer), *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo, sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
- &edns)) { - &edns)) {
@ -244,7 +244,7 @@ index e2ce0e87..f031c656 100644
/* prefetch it if the prefetch TTL expired. /* prefetch it if the prefetch TTL expired.
* Note that if there is more than one pass * Note that if there is more than one pass
* its qname must be that used for cache * its qname must be that used for cache
@@ -1518,11 +1575,19 @@ lookup_cache: @@ -1547,11 +1604,19 @@ lookup_cache:
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
} }
if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) {
@ -267,10 +267,10 @@ index e2ce0e87..f031c656 100644
} }
verbose(VERB_ALGO, "answer norec from cache -- " verbose(VERB_ALGO, "answer norec from cache -- "
diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in
index 4bdfcd56..69e70627 100644 index 38c2d298..3b07f392 100644
--- a/doc/unbound.conf.5.in --- a/doc/unbound.conf.5.in
+++ b/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in
@@ -1801,6 +1801,81 @@ List domain for which the AAAA records are ignored and the A record is @@ -1828,6 +1828,81 @@ List domain for which the AAAA records are ignored and the A record is
used by dns64 processing instead. Can be entered multiple times, list a used by dns64 processing instead. Can be entered multiple times, list a
new domain for which it applies, one per line. Applies also to names new domain for which it applies, one per line. Applies also to names
underneath the name given. underneath the name given.
@ -3106,10 +3106,10 @@ index a2f1b570..e1e4a738 100644
* Count number of time-outs. Used to prevent resolving failures when * Count number of time-outs. Used to prevent resolving failures when
* the QNAME minimisation QTYPE is blocked. */ * the QNAME minimisation QTYPE is blocked. */
diff --git a/services/cache/dns.c b/services/cache/dns.c diff --git a/services/cache/dns.c b/services/cache/dns.c
index aa4efec7..5dd3412e 100644 index 2a5bca4a..6de8863a 100644
--- a/services/cache/dns.c --- a/services/cache/dns.c
+++ b/services/cache/dns.c +++ b/services/cache/dns.c
@@ -945,6 +945,14 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, @@ -967,6 +967,14 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
struct regional* region, uint32_t flags) struct regional* region, uint32_t flags)
{ {
struct reply_info* rep = NULL; struct reply_info* rep = NULL;
@ -3125,10 +3125,10 @@ index aa4efec7..5dd3412e 100644
rep = reply_info_copy(msgrep, env->alloc, NULL); rep = reply_info_copy(msgrep, env->alloc, NULL);
if(!rep) if(!rep)
diff --git a/services/mesh.c b/services/mesh.c diff --git a/services/mesh.c b/services/mesh.c
index d4f814d5..624a9d95 100644 index 9114ef4c..3dc518e5 100644
--- a/services/mesh.c --- a/services/mesh.c
+++ b/services/mesh.c +++ b/services/mesh.c
@@ -60,6 +60,9 @@ @@ -61,6 +61,9 @@
#include "sldns/wire2str.h" #include "sldns/wire2str.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "util/data/dname.h" #include "util/data/dname.h"
@ -3138,7 +3138,7 @@ index d4f814d5..624a9d95 100644
#include "respip/respip.h" #include "respip/respip.h"
#include "services/listen_dnsport.h" #include "services/listen_dnsport.h"
@@ -1076,6 +1079,13 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, @@ -1195,6 +1198,13 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
else secure = 0; else secure = 0;
if(!rep && rcode == LDNS_RCODE_NOERROR) if(!rep && rcode == LDNS_RCODE_NOERROR)
rcode = LDNS_RCODE_SERVFAIL; rcode = LDNS_RCODE_SERVFAIL;
@ -3152,7 +3152,7 @@ index d4f814d5..624a9d95 100644
/* send the reply */ /* send the reply */
/* We don't reuse the encoded answer if either the previous or current /* We don't reuse the encoded answer if either the previous or current
* response has a local alias. We could compare the alias records * response has a local alias. We could compare the alias records
@@ -1255,6 +1265,7 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh, @@ -1415,6 +1425,7 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
key.s.is_valrec = valrec; key.s.is_valrec = valrec;
key.s.qinfo = *qinfo; key.s.qinfo = *qinfo;
key.s.query_flags = qflags; key.s.query_flags = qflags;
@ -3160,7 +3160,7 @@ index d4f814d5..624a9d95 100644
/* We are searching for a similar mesh state when we DO want to /* We are searching for a similar mesh state when we DO want to
* aggregate the state. Thus unique is set to NULL. (default when we * aggregate the state. Thus unique is set to NULL. (default when we
* desire aggregation).*/ * desire aggregation).*/
@@ -1301,6 +1312,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, @@ -1461,6 +1472,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
if(!r) if(!r)
return 0; return 0;
r->query_reply = *rep; r->query_reply = *rep;
@ -3172,10 +3172,10 @@ index d4f814d5..624a9d95 100644
if(edns->opt_list) { if(edns->opt_list) {
r->edns.opt_list = edns_opt_copy_region(edns->opt_list, r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
diff --git a/util/config_file.c b/util/config_file.c diff --git a/util/config_file.c b/util/config_file.c
index 119b2223..ce43a234 100644 index 52ca5a18..0660248f 100644
--- a/util/config_file.c --- a/util/config_file.c
+++ b/util/config_file.c +++ b/util/config_file.c
@@ -1434,6 +1434,8 @@ config_delete(struct config_file* cfg) @@ -1460,6 +1460,8 @@ config_delete(struct config_file* cfg)
free(cfg->dnstap_socket_path); free(cfg->dnstap_socket_path);
free(cfg->dnstap_identity); free(cfg->dnstap_identity);
free(cfg->dnstap_version); free(cfg->dnstap_version);
@ -3185,10 +3185,10 @@ index 119b2223..ce43a234 100644
config_deldblstrlist(cfg->ratelimit_below_domain); config_deldblstrlist(cfg->ratelimit_below_domain);
config_delstrlist(cfg->python_script); config_delstrlist(cfg->python_script);
diff --git a/util/config_file.h b/util/config_file.h diff --git a/util/config_file.h b/util/config_file.h
index b3ef930a..56173b80 100644 index 8739ca2a..a2dcf215 100644
--- a/util/config_file.h --- a/util/config_file.h
+++ b/util/config_file.h +++ b/util/config_file.h
@@ -494,6 +494,11 @@ struct config_file { @@ -499,6 +499,11 @@ struct config_file {
/** true to disable DNSSEC lameness check in iterator */ /** true to disable DNSSEC lameness check in iterator */
int disable_dnssec_lame_check; int disable_dnssec_lame_check;
@ -3201,10 +3201,10 @@ index b3ef930a..56173b80 100644
int ip_ratelimit; int ip_ratelimit;
/** number of slabs for ip_ratelimit cache */ /** number of slabs for ip_ratelimit cache */
diff --git a/util/configlexer.lex b/util/configlexer.lex diff --git a/util/configlexer.lex b/util/configlexer.lex
index a86ddf55..b56bcfb4 100644 index deedffa5..301458a3 100644
--- a/util/configlexer.lex --- a/util/configlexer.lex
+++ b/util/configlexer.lex +++ b/util/configlexer.lex
@@ -438,6 +438,10 @@ dnstap-log-forwarder-query-messages{COLON} { @@ -446,6 +446,10 @@ dnstap-log-forwarder-query-messages{COLON} {
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) } YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
dnstap-log-forwarder-response-messages{COLON} { dnstap-log-forwarder-response-messages{COLON} {
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
@ -3216,7 +3216,7 @@ index a86ddf55..b56bcfb4 100644
ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) } ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) }
ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) } ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) }
diff --git a/util/configparser.y b/util/configparser.y diff --git a/util/configparser.y b/util/configparser.y
index 10227a2f..cdbcf7cd 100644 index d471babe..cb6b1d63 100644
--- a/util/configparser.y --- a/util/configparser.y
+++ b/util/configparser.y +++ b/util/configparser.y
@@ -125,6 +125,7 @@ extern struct config_parser_state* cfg_parser; @@ -125,6 +125,7 @@ extern struct config_parser_state* cfg_parser;
@ -3227,7 +3227,7 @@ index 10227a2f..cdbcf7cd 100644
%token VAR_RESPONSE_IP_TAG VAR_RESPONSE_IP VAR_RESPONSE_IP_DATA %token VAR_RESPONSE_IP_TAG VAR_RESPONSE_IP VAR_RESPONSE_IP_DATA
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT %token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
%token VAR_DISABLE_DNSSEC_LAME_CHECK %token VAR_DISABLE_DNSSEC_LAME_CHECK
@@ -171,7 +172,7 @@ extern struct config_parser_state* cfg_parser; @@ -173,7 +174,7 @@ extern struct config_parser_state* cfg_parser;
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -3236,7 +3236,7 @@ index 10227a2f..cdbcf7cd 100644
forwardstart contents_forward | pythonstart contents_py | forwardstart contents_forward | pythonstart contents_py |
rcstart contents_rc | dtstart contents_dt | viewstart contents_view | rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
dnscstart contents_dnsc | cachedbstart contents_cachedb | dnscstart contents_dnsc | cachedbstart contents_cachedb |
@@ -2726,6 +2727,50 @@ dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MES @@ -2837,6 +2838,50 @@ dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MES
free($2); free($2);
} }
; ;
@ -3288,10 +3288,10 @@ index 10227a2f..cdbcf7cd 100644
{ {
OUTYY(("\nP(python:)\n")); OUTYY(("\nP(python:)\n"));
diff --git a/util/data/msgencode.c b/util/data/msgencode.c diff --git a/util/data/msgencode.c b/util/data/msgencode.c
index a51a4b9b..475dfce9 100644 index be69f628..f10773aa 100644
--- a/util/data/msgencode.c --- a/util/data/msgencode.c
+++ b/util/data/msgencode.c +++ b/util/data/msgencode.c
@@ -590,6 +590,35 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, @@ -592,6 +592,35 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
return RETVAL_OK; return RETVAL_OK;
} }
@ -3327,7 +3327,7 @@ index a51a4b9b..475dfce9 100644
/** store query section in wireformat buffer, return RETVAL */ /** store query section in wireformat buffer, return RETVAL */
static int static int
insert_query(struct query_info* qinfo, struct compress_tree_node** tree, insert_query(struct query_info* qinfo, struct compress_tree_node** tree,
@@ -777,6 +806,19 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, @@ -779,6 +808,19 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
} }
sldns_buffer_write_u16_at(buffer, 10, arcount); sldns_buffer_write_u16_at(buffer, 10, arcount);
} }
@ -3348,10 +3348,10 @@ index a51a4b9b..475dfce9 100644
sldns_buffer_flip(buffer); sldns_buffer_flip(buffer);
return 1; return 1;
diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c
index 7b9d5494..e44b2ce5 100644 index 4b0294f9..3b3838f6 100644
--- a/util/data/packed_rrset.c --- a/util/data/packed_rrset.c
+++ b/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c
@@ -255,6 +255,10 @@ sec_status_to_string(enum sec_status s) @@ -256,6 +256,10 @@ sec_status_to_string(enum sec_status s)
case sec_status_insecure: return "sec_status_insecure"; case sec_status_insecure: return "sec_status_insecure";
case sec_status_secure_sentinel_fail: return "sec_status_secure_sentinel_fail"; case sec_status_secure_sentinel_fail: return "sec_status_secure_sentinel_fail";
case sec_status_secure: return "sec_status_secure"; case sec_status_secure: return "sec_status_secure";
@ -3363,7 +3363,7 @@ index 7b9d5494..e44b2ce5 100644
return "unknown_sec_status_value"; return "unknown_sec_status_value";
} }
diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h
index 3a5335dd..20113217 100644 index 729877ba..ccd1a0c2 100644
--- a/util/data/packed_rrset.h --- a/util/data/packed_rrset.h
+++ b/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h
@@ -193,7 +193,15 @@ enum sec_status { @@ -193,7 +193,15 @@ enum sec_status {
@ -3384,7 +3384,7 @@ index 3a5335dd..20113217 100644
/** /**
diff --git a/util/netevent.c b/util/netevent.c diff --git a/util/netevent.c b/util/netevent.c
index 980bb8be..d537d288 100644 index 9fe5da2d..037e70d1 100644
--- a/util/netevent.c --- a/util/netevent.c
+++ b/util/netevent.c +++ b/util/netevent.c
@@ -57,6 +57,9 @@ @@ -57,6 +57,9 @@
@ -3427,7 +3427,7 @@ index 980bb8be..d537d288 100644
if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
another UDP port. Note rep.c cannot be reused with TCP fd. */ another UDP port. Note rep.c cannot be reused with TCP fd. */
break; break;
@@ -3184,6 +3196,9 @@ comm_point_send_reply(struct comm_reply *repinfo) @@ -3192,6 +3204,9 @@ comm_point_send_reply(struct comm_reply *repinfo)
repinfo->c->tcp_timeout_msec); repinfo->c->tcp_timeout_msec);
} }
} }
@ -3437,7 +3437,7 @@ index 980bb8be..d537d288 100644
} }
void void
@@ -3193,6 +3208,9 @@ comm_point_drop_reply(struct comm_reply* repinfo) @@ -3201,6 +3216,9 @@ comm_point_drop_reply(struct comm_reply* repinfo)
return; return;
log_assert(repinfo->c); log_assert(repinfo->c);
log_assert(repinfo->c->type != comm_tcp_accept); log_assert(repinfo->c->type != comm_tcp_accept);
@ -3447,7 +3447,7 @@ index 980bb8be..d537d288 100644
if(repinfo->c->type == comm_udp) if(repinfo->c->type == comm_udp)
return; return;
if(repinfo->c->tcp_req_info) if(repinfo->c->tcp_req_info)
@@ -3214,6 +3232,9 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec) @@ -3222,6 +3240,9 @@ comm_point_start_listening(struct comm_point* c, int newfd, int msec)
{ {
verbose(VERB_ALGO, "comm point start listening %d (%d msec)", verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
c->fd==-1?newfd:c->fd, msec); c->fd==-1?newfd:c->fd, msec);
@ -3473,10 +3473,10 @@ index d80c72b3..0233292f 100644
uint8_t client_nonce[crypto_box_HALF_NONCEBYTES]; uint8_t client_nonce[crypto_box_HALF_NONCEBYTES];
uint8_t nmkey[crypto_box_BEFORENMBYTES]; uint8_t nmkey[crypto_box_BEFORENMBYTES];
diff --git a/validator/validator.c b/validator/validator.c diff --git a/validator/validator.c b/validator/validator.c
index 4c560a8e..71de3760 100644 index c3ca0a27..15251988 100644
--- a/validator/validator.c --- a/validator/validator.c
+++ b/validator/validator.c +++ b/validator/validator.c
@@ -2755,6 +2755,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, @@ -2761,6 +2761,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
default: default:
/* NSEC proof did not work, try next */ /* NSEC proof did not work, try next */
break; break;
@ -3489,7 +3489,7 @@ index 4c560a8e..71de3760 100644
} }
sec = nsec3_prove_nods(qstate->env, ve, sec = nsec3_prove_nods(qstate->env, ve,
@@ -2788,6 +2794,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq, @@ -2794,6 +2800,12 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
default: default:
/* NSEC3 proof did not work */ /* NSEC3 proof did not work */
break; break;

View File

@ -7,8 +7,8 @@ Name: unbound
Description: Library with validating, recursive, and caching DNS resolver Description: Library with validating, recursive, and caching DNS resolver
URL: http://www.unbound.net URL: http://www.unbound.net
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Requires: libcrypto libssl @PC_LIBEVENT_DEPENDENCY@ Requires: @PC_CRYPTO_DEPENDENCY@ @PC_LIBEVENT_DEPENDENCY@
Requires.private: @PC_PY_DEPENDENCY@ Requires.private: @PC_PY_DEPENDENCY@ @PC_LIBBSD_DEPENDENCY@
Libs: -L${libdir} -lunbound -lssl -lcrypto Libs: -L${libdir} -lunbound
Libs.private: @SSLLIB@ @LIBS@ Libs.private: @SSLLIB@ @LIBS@
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@ -1,3 +1,44 @@
; For further details about the directives used in this unit file, including
; the below, please refer to systemd's official documentation, available at
; https://www.freedesktop.org/software/systemd/man/systemd.exec.html.
;
;
; - `ProtectSystem=strict` implies we mount the entire file system hierarchy
; read-only for the processes invoked by the unit except for the API file
; system subtrees /dev, /proc and /sys (which are protected by
; PrivateDevices=, ProtectKernelTunables=, ProtectControlGroups=).
;
; - `PrivateTmp=yes` secures access to temporary files of the process, and
; makes sharing between processes via /tmp or /var/tmp impossible.
;
; - `ProtectHome=yes` makes the directories /home, /root, and /run/user
; inaccessible and empty for processes invoked by the unit.
;
; - `ProtectControlGroups=yes` makes the Linux Control Groups hierarchies
; (accessible through /sys/fs/cgroup) read-only to all processes invoked by
; the unit. It also implies `MountAPIVFS=yes`.
;
; - `RuntimeDirectory=unbound` creates a /run/unbound directory, owned by the
; unit User and Group with read-write permissions (0755) as soon as the
; unit starts. This allows unbound to store its pidfile. The directory and
; its content are automatically removed by systemd when the unit stops.
;
; - `NoNewPrivileges=yes` ensures that the service process and all its
; children can never gain new privileges through execve().
;
; - `RestrictSUIDSGID=yes` ensures that any attempts to set the set-user-ID
; (SUID) or set-group-ID (SGID) bits on files or directories will be denied.
;
; - `RestrictRealTime=yes` ensures that any attempts to enable realtime
; scheduling in a process invoked by the unit will be denied.
;
; - `RestrictNamespaces=yes` ensures that access to any kind of namespacing
; is prohibited.
;
; - `LockPersonality=yes` locks down the personality system call so that the
; kernel execution domain may not be changed from the default.
;
;
[Unit] [Unit]
Description=Validating, recursive, and caching DNS resolver Description=Validating, recursive, and caching DNS resolver
Documentation=man:unbound(8) Documentation=man:unbound(8)
@ -10,10 +51,10 @@ WantedBy=multi-user.target
[Service] [Service]
ExecReload=+/bin/kill -HUP $MAINPID ExecReload=+/bin/kill -HUP $MAINPID
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
NotifyAccess=main NotifyAccess=main
Type=notify Type=notify
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
MemoryDenyWriteExecute=true MemoryDenyWriteExecute=true
NoNewPrivileges=true NoNewPrivileges=true
PrivateDevices=true PrivateDevices=true
@ -22,13 +63,9 @@ ProtectHome=true
ProtectControlGroups=true ProtectControlGroups=true
ProtectKernelModules=true ProtectKernelModules=true
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/run @UNBOUND_RUN_DIR@ @UNBOUND_CHROOT_DIR@ RuntimeDirectory=unbound
TemporaryFileSystem=@UNBOUND_CHROOT_DIR@/dev:ro ConfigurationDirectory=unbound
TemporaryFileSystem=@UNBOUND_CHROOT_DIR@/run:ro StateDirectory=unbound
BindReadOnlyPaths=-/run/systemd/notify:@UNBOUND_CHROOT_DIR@/run/systemd/notify
BindPaths=-@UNBOUND_PIDFILE@:@UNBOUND_CHROOT_DIR@@UNBOUND_PIDFILE@
BindReadOnlyPaths=-/dev/urandom:@UNBOUND_CHROOT_DIR@/dev/urandom
BindPaths=-/dev/log:@UNBOUND_CHROOT_DIR@/dev/log
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictRealtime=true RestrictRealtime=true
SystemCallArchitectures=native SystemCallArchitectures=native
@ -36,3 +73,12 @@ SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module mount @obsolete
RestrictNamespaces=yes RestrictNamespaces=yes
LockPersonality=yes LockPersonality=yes
RestrictSUIDSGID=yes RestrictSUIDSGID=yes
ReadWritePaths=@UNBOUND_RUN_DIR@ @UNBOUND_CHROOT_DIR@
# Below rules are needed when chroot is enabled (usually it's enabled by default).
# If chroot is disabled like chrooot: "" then they may be safely removed.
TemporaryFileSystem=@UNBOUND_CHROOT_DIR@/dev:ro
TemporaryFileSystem=@UNBOUND_CHROOT_DIR@/run:ro
BindReadOnlyPaths=-/run/systemd/notify:@UNBOUND_CHROOT_DIR@/run/systemd/notify
BindReadOnlyPaths=-/dev/urandom:@UNBOUND_CHROOT_DIR@/dev/urandom
BindPaths=-/dev/log:@UNBOUND_CHROOT_DIR@/dev/log

View File

@ -242,6 +242,8 @@ if test "$1" = "config" ; then
p_config "total.num.prefetch" "cache prefetch" "ABSOLUTE" p_config "total.num.prefetch" "cache prefetch" "ABSOLUTE"
p_config "num.query.tcp" "TCP queries" "ABSOLUTE" p_config "num.query.tcp" "TCP queries" "ABSOLUTE"
p_config "num.query.tcpout" "TCP out queries" "ABSOLUTE" p_config "num.query.tcpout" "TCP out queries" "ABSOLUTE"
p_config "num.query.tls" "TLS queries" "ABSOLUTE"
p_config "num.query.tls.resume" "TLS resumes" "ABSOLUTE"
p_config "num.query.ipv6" "IPv6 queries" "ABSOLUTE" p_config "num.query.ipv6" "IPv6 queries" "ABSOLUTE"
p_config "unwanted.queries" "queries that failed acl" "ABSOLUTE" p_config "unwanted.queries" "queries that failed acl" "ABSOLUTE"
p_config "unwanted.replies" "unwanted or unsolicited replies" "ABSOLUTE" p_config "unwanted.replies" "unwanted or unsolicited replies" "ABSOLUTE"
@ -443,7 +445,8 @@ hits)
for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state | for x in `grep "^thread[0-9][0-9]*\.num\.queries=" $state |
sed -e 's/=.*//'` total.num.queries \ sed -e 's/=.*//'` total.num.queries \
total.num.cachehits total.num.prefetch num.query.tcp \ total.num.cachehits total.num.prefetch num.query.tcp \
num.query.tcpout num.query.ipv6 unwanted.queries \ num.query.tcpout num.query.tls num.query.tls.resume \
num.query.ipv6 unwanted.queries \
unwanted.replies; do unwanted.replies; do
if grep "^"$x"=" $state >/dev/null 2>&1; then if grep "^"$x"=" $state >/dev/null 2>&1; then
print_value $x print_value $x

View File

@ -0,0 +1,49 @@
; This unit file is provided to run unbound as portable service.
; https://systemd.io/PORTABLE_SERVICES/
;
; To use this unit file, please make sure you either compile unbound with the
; following options:
;
; - --with-chroot-dir=""
;
; Or put the following options in your unbound configuration file:
;
; - chroot: ""
;
;
[Unit]
Description=Validating, recursive, and caching DNS resolver
Documentation=man:unbound(8)
After=network.target
Before=network-online.target nss-lookup.target
Wants=nss-lookup.target
[Install]
WantedBy=multi-user.target
[Service]
ExecReload=+/bin/kill -HUP $MAINPID
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
NotifyAccess=main
Type=notify
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
MemoryDenyWriteExecute=true
NoNewPrivileges=true
PrivateDevices=true
PrivateTmp=true
ProtectHome=true
ProtectControlGroups=true
ProtectKernelModules=true
ProtectSystem=strict
RuntimeDirectory=unbound
ConfigurationDirectory=unbound
StateDirectory=unbound
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictRealtime=true
SystemCallArchitectures=native
SystemCallFilter=~@clock @cpu-emulation @debug @keyring @module mount @obsolete @resources
RestrictNamespaces=yes
LockPersonality=yes
RestrictSUIDSGID=yes
BindPaths=/run/systemd/notify
BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout

Binary file not shown.

View File

@ -617,7 +617,8 @@ daemon_fork(struct daemon* daemon)
have_view_respip_cfg; have_view_respip_cfg;
/* read auth zonefiles */ /* read auth zonefiles */
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1)) if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
&daemon->use_rpz))
fatal_exit("auth_zones could not be setup"); fatal_exit("auth_zones could not be setup");
/* setup modules */ /* setup modules */
@ -629,6 +630,12 @@ daemon_fork(struct daemon* daemon)
if(daemon->use_response_ip && if(daemon->use_response_ip &&
modstack_find(&daemon->mods, "respip") < 0) modstack_find(&daemon->mods, "respip") < 0)
fatal_exit("response-ip options require respip module"); fatal_exit("response-ip options require respip module");
/* RPZ response ip triggers don't work as expected without the respip
* module. To avoid run-time operational surprise we reject such
* configuration. */
if(daemon->use_rpz &&
modstack_find(&daemon->mods, "respip") < 0)
fatal_exit("RPZ requires the respip module");
/* first create all the worker structures, so we can pass /* first create all the worker structures, so we can pass
* them to the newly created threads. * them to the newly created threads.

View File

@ -132,6 +132,8 @@ struct daemon {
struct respip_set* respip_set; struct respip_set* respip_set;
/** some response-ip tags or actions are configured if true */ /** some response-ip tags or actions are configured if true */
int use_response_ip; int use_response_ip;
/** some RPZ policies are configured */
int use_rpz;
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
/** the dnscrypt environment */ /** the dnscrypt environment */
struct dnsc_env* dnscenv; struct dnsc_env* dnscenv;

View File

@ -69,6 +69,7 @@
#include "services/mesh.h" #include "services/mesh.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "services/authzone.h" #include "services/authzone.h"
#include "services/rpz.h"
#include "util/storage/slabhash.h" #include "util/storage/slabhash.h"
#include "util/fptr_wlist.h" #include "util/fptr_wlist.h"
#include "util/data/dname.h" #include "util/data/dname.h"
@ -719,8 +720,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
(unsigned long)s->svr.num_queries_missed_cache)) return 0; (unsigned long)s->svr.num_queries_missed_cache)) return 0;
if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%lu\n", nm, if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%lu\n", nm,
(unsigned long)s->svr.num_queries_prefetch)) return 0; (unsigned long)s->svr.num_queries_prefetch)) return 0;
if(!ssl_printf(ssl, "%s.num.zero_ttl"SQ"%lu\n", nm, if(!ssl_printf(ssl, "%s.num.expired"SQ"%lu\n", nm,
(unsigned long)s->svr.zero_ttl_responses)) return 0; (unsigned long)s->svr.ans_expired)) return 0;
if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%lu\n", nm, if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%lu\n", nm,
(unsigned long)s->mesh_replies_sent)) return 0; (unsigned long)s->mesh_replies_sent)) return 0;
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
@ -1045,6 +1046,16 @@ print_ext(RES* ssl, struct ub_stats_info* s)
(unsigned)s->svr.infra_cache_count)) return 0; (unsigned)s->svr.infra_cache_count)) return 0;
if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n", if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n",
(unsigned)s->svr.key_cache_count)) return 0; (unsigned)s->svr.key_cache_count)) return 0;
/* applied RPZ actions */
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
if(i == RPZ_NO_OVERRIDE_ACTION)
continue;
if(inhibit_zero && s->svr.rpz_action[i] == 0)
continue;
if(!ssl_printf(ssl, "num.rpz.action.%s"SQ"%lu\n",
rpz_action_to_string(i),
(unsigned long)s->svr.rpz_action[i])) return 0;
}
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
if(!ssl_printf(ssl, "dnscrypt_shared_secret.cache.count"SQ"%u\n", if(!ssl_printf(ssl, "dnscrypt_shared_secret.cache.count"SQ"%u\n",
(unsigned)s->svr.shared_secret_cache_count)) return 0; (unsigned)s->svr.shared_secret_cache_count)) return 0;
@ -1479,6 +1490,27 @@ do_view_data_remove(RES* ssl, struct worker* worker, char* arg)
lock_rw_unlock(&v->lock); lock_rw_unlock(&v->lock);
} }
/** Remove RR data from stdin from view */
static void
do_view_datas_remove(RES* ssl, struct worker* worker, char* arg)
{
struct view* v;
v = views_find_view(worker->daemon->views,
arg, 1 /* get write lock*/);
if(!v) {
ssl_printf(ssl,"no view with name: %s\n", arg);
return;
}
if(!v->local_zones){
lock_rw_unlock(&v->lock);
ssl_printf(ssl, "removed 0 datas\n");
return;
}
do_datas_remove(ssl, v->local_zones);
lock_rw_unlock(&v->lock);
}
/** cache lookup of nameservers */ /** cache lookup of nameservers */
static void static void
do_lookup(RES* ssl, struct worker* worker, char* arg) do_lookup(RES* ssl, struct worker* worker, char* arg)
@ -2506,8 +2538,10 @@ do_auth_zone_transfer(RES* ssl, struct worker* worker, char* arg)
if(!az || !auth_zones_startprobesequence(az, &worker->env, nm, nmlen, if(!az || !auth_zones_startprobesequence(az, &worker->env, nm, nmlen,
LDNS_RR_CLASS_IN)) { LDNS_RR_CLASS_IN)) {
(void)ssl_printf(ssl, "error zone xfr task not found %s\n", arg); (void)ssl_printf(ssl, "error zone xfr task not found %s\n", arg);
free(nm);
return; return;
} }
free(nm);
send_ok(ssl); send_ok(ssl);
} }
@ -2989,6 +3023,8 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
do_view_zone_add(ssl, worker, skipwhite(p+15)); do_view_zone_add(ssl, worker, skipwhite(p+15));
} else if(cmdcmp(p, "view_local_data_remove", 22)) { } else if(cmdcmp(p, "view_local_data_remove", 22)) {
do_view_data_remove(ssl, worker, skipwhite(p+22)); do_view_data_remove(ssl, worker, skipwhite(p+22));
} else if(cmdcmp(p, "view_local_datas_remove", 23)){
do_view_datas_remove(ssl, worker, skipwhite(p+23));
} else if(cmdcmp(p, "view_local_data", 15)) { } else if(cmdcmp(p, "view_local_data", 15)) {
do_view_data_add(ssl, worker, skipwhite(p+15)); do_view_data_add(ssl, worker, skipwhite(p+15));
} else if(cmdcmp(p, "view_local_datas", 16)) { } else if(cmdcmp(p, "view_local_datas", 16)) {

View File

@ -271,8 +271,10 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
s->svr.ans_secure += (long long)worker->env.mesh->ans_secure; s->svr.ans_secure += (long long)worker->env.mesh->ans_secure;
s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus; s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus;
s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata; s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata;
for(i=0; i<16; i++) for(i=0; i<UB_STATS_RCODE_NUM; i++)
s->svr.ans_rcode[i] += (long long)worker->env.mesh->ans_rcode[i]; s->svr.ans_rcode[i] += (long long)worker->env.mesh->ans_rcode[i];
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
s->svr.rpz_action[i] += (long long)worker->env.mesh->rpz_action[i];
timehist_export(worker->env.mesh->histogram, s->svr.hist, timehist_export(worker->env.mesh->histogram, s->svr.hist,
NUM_BUCKETS_HIST); NUM_BUCKETS_HIST);
/* values from outside network */ /* values from outside network */
@ -398,6 +400,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache; total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
total->svr.num_queries_prefetch += a->svr.num_queries_prefetch; total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
total->svr.sum_query_list_size += a->svr.sum_query_list_size; total->svr.sum_query_list_size += a->svr.sum_query_list_size;
total->svr.ans_expired += a->svr.ans_expired;
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
total->svr.num_query_dnscrypt_crypted += a->svr.num_query_dnscrypt_crypted; total->svr.num_query_dnscrypt_crypted += a->svr.num_query_dnscrypt_crypted;
total->svr.num_query_dnscrypt_cert += a->svr.num_query_dnscrypt_cert; total->svr.num_query_dnscrypt_cert += a->svr.num_query_dnscrypt_cert;
@ -430,7 +433,6 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.qEDNS += a->svr.qEDNS; total->svr.qEDNS += a->svr.qEDNS;
total->svr.qEDNS_DO += a->svr.qEDNS_DO; total->svr.qEDNS_DO += a->svr.qEDNS_DO;
total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata; total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
total->svr.zero_ttl_responses += a->svr.zero_ttl_responses;
total->svr.ans_secure += a->svr.ans_secure; total->svr.ans_secure += a->svr.ans_secure;
total->svr.ans_bogus += a->svr.ans_bogus; total->svr.ans_bogus += a->svr.ans_bogus;
total->svr.unwanted_replies += a->svr.unwanted_replies; total->svr.unwanted_replies += a->svr.unwanted_replies;
@ -446,6 +448,8 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.ans_rcode[i] += a->svr.ans_rcode[i]; total->svr.ans_rcode[i] += a->svr.ans_rcode[i];
for(i=0; i<NUM_BUCKETS_HIST; i++) for(i=0; i<NUM_BUCKETS_HIST; i++)
total->svr.hist[i] += a->svr.hist[i]; total->svr.hist[i] += a->svr.hist[i];
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
total->svr.rpz_action[i] += a->svr.rpz_action[i];
} }
total->mesh_num_states += a->mesh_num_states; total->mesh_num_states += a->mesh_num_states;

View File

@ -259,21 +259,10 @@ checkrlimits(struct config_file* cfg)
#endif /* S_SPLINT_S */ #endif /* S_SPLINT_S */
} }
/** set default logfile identity based on value from argv[0] at startup **/
static void
log_ident_set_fromdefault(struct config_file* cfg,
const char *log_default_identity)
{
if(cfg->log_identity == NULL || cfg->log_identity[0] == 0)
log_ident_set(log_default_identity);
else
log_ident_set(cfg->log_identity);
}
/** set verbosity, check rlimits, cache settings */ /** set verbosity, check rlimits, cache settings */
static void static void
apply_settings(struct daemon* daemon, struct config_file* cfg, apply_settings(struct daemon* daemon, struct config_file* cfg,
int cmdline_verbose, int debug_mode, const char* log_default_identity) int cmdline_verbose, int debug_mode)
{ {
/* apply if they have changed */ /* apply if they have changed */
verbosity = cmdline_verbose + cfg->verbosity; verbosity = cmdline_verbose + cfg->verbosity;
@ -289,7 +278,7 @@ apply_settings(struct daemon* daemon, struct config_file* cfg,
log_warn("use-systemd and do-daemonize should not be enabled at the same time"); log_warn("use-systemd and do-daemonize should not be enabled at the same time");
} }
log_ident_set_fromdefault(cfg, log_default_identity); log_ident_set_or_default(cfg->log_identity);
} }
#ifdef HAVE_KILL #ifdef HAVE_KILL
@ -639,11 +628,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
* @param cmdline_verbose: verbosity resulting from commandline -v. * @param cmdline_verbose: verbosity resulting from commandline -v.
* These increase verbosity as specified in the config file. * These increase verbosity as specified in the config file.
* @param debug_mode: if set, do not daemonize. * @param debug_mode: if set, do not daemonize.
* @param log_default_identity: Default identity to report in logs
* @param need_pidfile: if false, no pidfile is checked or created. * @param need_pidfile: if false, no pidfile is checked or created.
*/ */
static void static void
run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity, int need_pidfile) run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pidfile)
{ {
struct config_file* cfg = NULL; struct config_file* cfg = NULL;
struct daemon* daemon = NULL; struct daemon* daemon = NULL;
@ -667,7 +655,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char*
"or unbound-checkconf", cfgfile); "or unbound-checkconf", cfgfile);
log_warn("Continuing with default config settings"); log_warn("Continuing with default config settings");
} }
apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity); apply_settings(daemon, cfg, cmdline_verbose, debug_mode);
if(!done_setup) if(!done_setup)
config_lookup_uid(cfg); config_lookup_uid(cfg);
@ -733,6 +721,7 @@ main(int argc, char* argv[])
log_init(NULL, 0, NULL); log_init(NULL, 0, NULL);
log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]; log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0];
log_ident_set_default(log_ident_default);
log_ident_set(log_ident_default); log_ident_set(log_ident_default);
/* parse the options */ /* parse the options */
while( (c=getopt(argc, argv, "c:dhpvw:V")) != -1) { while( (c=getopt(argc, argv, "c:dhpvw:V")) != -1) {
@ -783,7 +772,7 @@ main(int argc, char* argv[])
return 1; return 1;
} }
run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default, need_pidfile); run_daemon(cfgfile, cmdline_verbose, debug_mode, need_pidfile);
log_init(NULL, 0, NULL); /* close logfile */ log_init(NULL, 0, NULL); /* close logfile */
#ifndef unbound_testbound #ifndef unbound_testbound
if(log_get_lock()) { if(log_get_lock()) {

View File

@ -61,6 +61,7 @@
#include "services/authzone.h" #include "services/authzone.h"
#include "services/mesh.h" #include "services/mesh.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "services/rpz.h"
#include "util/data/msgparse.h" #include "util/data/msgparse.h"
#include "util/data/msgencode.h" #include "util/data/msgencode.h"
#include "util/data/dname.h" #include "util/data/dname.h"
@ -572,9 +573,10 @@ static int
apply_respip_action(struct worker* worker, const struct query_info* qinfo, apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep, struct respip_client_info* cinfo, struct reply_info* rep,
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset, struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp) struct reply_info** encode_repp, struct auth_zones* az)
{ {
struct respip_action_info actinfo = {respip_none, NULL}; struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
if(qinfo->qtype != LDNS_RR_TYPE_A && if(qinfo->qtype != LDNS_RR_TYPE_A &&
qinfo->qtype != LDNS_RR_TYPE_AAAA && qinfo->qtype != LDNS_RR_TYPE_AAAA &&
@ -582,7 +584,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1; return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
alias_rrset, 0, worker->scratchpad)) alias_rrset, 0, worker->scratchpad, az))
return 0; return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply /* xxx_deny actions mean dropping the reply, unless the original reply
@ -595,9 +597,19 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
/* If address info is returned, it means the action should be an /* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */ * 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) { if(actinfo.addrinfo) {
respip_inform_print(actinfo.addrinfo, qinfo->qname, respip_inform_print(&actinfo, qinfo->qname,
qinfo->qtype, qinfo->qclass, qinfo->local_alias, qinfo->qtype, qinfo->qclass, qinfo->local_alias,
repinfo); repinfo);
if(worker->stats.extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
worker->stats.rpz_action[RPZ_DISABLED_ACTION]++;
if(actinfo.rpz_cname_override)
worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
else
worker->stats.rpz_action[
respip_action_to_rpz_action(actinfo.action)]++;
}
} }
return 1; return 1;
@ -613,10 +625,10 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
* be completely dropped, '*need_drop' will be set to 1. */ * be completely dropped, '*need_drop' will be set to 1. */
static int static int
answer_from_cache(struct worker* worker, struct query_info* qinfo, answer_from_cache(struct worker* worker, struct query_info* qinfo,
struct respip_client_info* cinfo, int* need_drop, struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer,
struct ub_packed_rrset_key** alias_rrset, int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** partial_repp, struct reply_info** partial_repp,
struct reply_info* rep, uint16_t id, uint16_t flags, struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns) struct comm_reply* repinfo, struct edns_data* edns)
{ {
struct edns_data edns_bak; struct edns_data edns_bak;
@ -624,38 +636,37 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
uint16_t udpsize = edns->udp_size; uint16_t udpsize = edns->udp_size;
struct reply_info* encode_rep = rep; struct reply_info* encode_rep = rep;
struct reply_info* partial_rep = *partial_repp; struct reply_info* partial_rep = *partial_repp;
int secure;
int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
&& worker->env.need_to_validate; && worker->env.need_to_validate;
*partial_repp = NULL; /* avoid accidental further pass */ *partial_repp = NULL; /* avoid accidental further pass */
if(worker->env.cfg->serve_expired) {
if(worker->env.cfg->serve_expired_ttl && /* Check TTL */
rep->serve_expired_ttl < timenow) if(rep->ttl < timenow) {
return 0; /* Check if we need to serve expired now */
if(!rrset_array_lock(rep->ref, rep->rrset_count, 0)) if(worker->env.cfg->serve_expired &&
return 0; !worker->env.cfg->serve_expired_client_timeout) {
/* below, rrsets with ttl before timenow become TTL 0 in if(worker->env.cfg->serve_expired_ttl &&
* the response */ rep->serve_expired_ttl < timenow)
/* This response was served with zero TTL */ return 0;
if (timenow >= rep->ttl) { if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
worker->stats.zero_ttl_responses++; return 0;
} *is_expired_answer = 1;
} else { } else {
/* see if it is possible */
if(rep->ttl < timenow) {
/* the rrsets may have been updated in the meantime. /* the rrsets may have been updated in the meantime.
* we will refetch the message format from the * we will refetch the message format from the
* authoritative server * authoritative server
*/ */
return 0; return 0;
} }
} else {
if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
return 0; return 0;
/* locked and ids and ttls are OK. */
} }
/* locked and ids and ttls are OK. */
/* check CNAME chain (if any) */ /* check CNAME chain (if any) */
if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
htons(LDNS_RR_TYPE_DNAME))) { htons(LDNS_RR_TYPE_DNAME))) {
if(!reply_check_cname_chain(qinfo, rep)) { if(!reply_check_cname_chain(qinfo, rep)) {
/* cname chain invalid, redo iterator steps */ /* cname chain invalid, redo iterator steps */
@ -674,31 +685,31 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad)) LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
goto bail_out; goto bail_out;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns); qinfo, id, flags, edns);
rrset_array_unlock_touch(worker->env.rrset_cache, rrset_array_unlock_touch(worker->env.rrset_cache,
worker->scratchpad, rep->ref, rep->rrset_count); worker->scratchpad, rep->ref, rep->rrset_count);
if(worker->stats.extended) { if(worker->stats.extended) {
worker->stats.ans_bogus ++; worker->stats.ans_bogus ++;
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++; worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
} }
return 1; return 1;
} else if( rep->security == sec_status_unchecked && must_validate) { } else if(rep->security == sec_status_unchecked && must_validate) {
verbose(VERB_ALGO, "Cache reply: unchecked entry needs " verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
"validation"); "validation");
goto bail_out; /* need to validate cache entry first */ goto bail_out; /* need to validate cache entry first */
} else if(rep->security == sec_status_secure) { } else if(rep->security == sec_status_secure) {
if(reply_all_rrsets_secure(rep)) if(reply_all_rrsets_secure(rep)) {
secure = 1; *is_secure_answer = 1;
else { } else {
if(must_validate) { if(must_validate) {
verbose(VERB_ALGO, "Cache reply: secure entry" verbose(VERB_ALGO, "Cache reply: secure entry"
" changed status"); " changed status");
goto bail_out; /* rrset changed, re-verify */ goto bail_out; /* rrset changed, re-verify */
} }
secure = 0; *is_secure_answer = 0;
} }
} else secure = 0; } else *is_secure_answer = 0;
edns_bak = *edns; edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION; edns->edns_version = EDNS_ADVERTISED_VERSION;
@ -709,17 +720,21 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad)) (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
goto bail_out; goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if(worker->daemon->use_response_ip && !partial_rep && if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!apply_respip_action(worker, qinfo, cinfo, rep, repinfo, alias_rrset, !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
&encode_rep)) { repinfo, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
goto bail_out; goto bail_out;
} else if(partial_rep && } else if(partial_rep &&
!respip_merge_cname(partial_rep, qinfo, rep, cinfo, !respip_merge_cname(partial_rep, qinfo, rep, cinfo,
must_validate, &encode_rep, worker->scratchpad)) { must_validate, &encode_rep, worker->scratchpad,
worker->env.auth_zones)) {
goto bail_out; goto bail_out;
} }
if(encode_rep != rep) if(encode_rep != rep) {
secure = 0; /* if rewritten, it can't be considered "secure" */ /* if rewritten, it can't be considered "secure" */
*is_secure_answer = 0;
}
if(!encode_rep || *alias_rrset) { if(!encode_rep || *alias_rrset) {
if(!encode_rep) if(!encode_rep)
*need_drop = 1; *need_drop = 1;
@ -736,7 +751,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
repinfo->c, worker->scratchpad) || repinfo->c, worker->scratchpad) ||
!reply_info_answer_encode(qinfo, encode_rep, id, flags, !reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad, repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad)) LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL; edns->opt_list = NULL;
@ -747,10 +762,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
* is bad while holding locks. */ * is bad while holding locks. */
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad, rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
rep->ref, rep->rrset_count); rep->ref, rep->rrset_count);
if(worker->stats.extended) {
if(secure) worker->stats.ans_secure++;
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
}
/* go and return this buffer to the client */ /* go and return this buffer to the client */
return 1; return 1;
@ -1085,6 +1096,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct acl_addr* acladdr; struct acl_addr* acladdr;
int rc = 0; int rc = 0;
int need_drop = 0; int need_drop = 0;
int is_expired_answer = 0;
int is_secure_answer = 0;
/* We might have to chase a CNAME chain internally, in which case /* We might have to chase a CNAME chain internally, in which case
* we'll have up to two replies and combine them to build a complete * we'll have up to two replies and combine them to build a complete
* answer. These variables control this case. */ * answer. These variables control this case. */
@ -1364,6 +1377,18 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_insrcode(&worker->stats, c->buffer); server_stats_insrcode(&worker->stats, c->buffer);
goto send_reply; goto send_reply;
} }
if(worker->env.auth_zones &&
rpz_apply_qname_trigger(worker->env.auth_zones,
&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
return 0;
}
server_stats_insrcode(&worker->stats, c->buffer);
goto send_reply;
}
if(worker->env.auth_zones && if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env, auth_zones_answer(worker->env.auth_zones, &worker->env,
&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) { &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
@ -1434,7 +1459,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* If we may apply IP-based actions to the answer, build the client /* If we may apply IP-based actions to the answer, build the client
* information. As this can be expensive, skip it if there is * information. As this can be expensive, skip it if there is
* absolutely no possibility of it. */ * absolutely no possibility of it. */
if(worker->daemon->use_response_ip && if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
(qinfo.qtype == LDNS_RR_TYPE_A || (qinfo.qtype == LDNS_RR_TYPE_A ||
qinfo.qtype == LDNS_RR_TYPE_AAAA || qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qinfo.qtype == LDNS_RR_TYPE_ANY)) { qinfo.qtype == LDNS_RR_TYPE_ANY)) {
@ -1455,12 +1480,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* each pass. We should still pass the original qinfo to * each pass. We should still pass the original qinfo to
* answer_from_cache(), however, since it's used to build the reply. */ * answer_from_cache(), however, since it's used to build the reply. */
if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) { if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) {
is_expired_answer = 0;
is_secure_answer = 0;
h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) { if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */ /* answer from cache - we have acquired a readlock on it */
if(answer_from_cache(worker, &qinfo, if(answer_from_cache(worker, &qinfo,
cinfo, &need_drop, &alias_rrset, &partial_rep, cinfo, &need_drop, &is_expired_answer, &is_secure_answer,
(struct reply_info*)e->data, &alias_rrset, &partial_rep, (struct reply_info*)e->data,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer), *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo, sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) { &edns)) {
@ -1468,9 +1495,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* Note that if there is more than one pass * Note that if there is more than one pass
* its qname must be that used for cache * its qname must be that used for cache
* lookup. */ * lookup. */
if((worker->env.cfg->prefetch || worker->env.cfg->serve_expired) if((worker->env.cfg->prefetch && *worker->env.now >=
&& *worker->env.now >= ((struct reply_info*)e->data)->prefetch_ttl) ||
((struct reply_info*)e->data)->prefetch_ttl) { (worker->env.cfg->serve_expired &&
*worker->env.now >= ((struct reply_info*)e->data)->ttl)) {
time_t leeway = ((struct reply_info*)e-> time_t leeway = ((struct reply_info*)e->
data)->ttl - *worker->env.now; data)->ttl - *worker->env.now;
if(((struct reply_info*)e->data)->ttl if(((struct reply_info*)e->data)->ttl
@ -1555,6 +1584,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
comm_point_drop_reply(repinfo); comm_point_drop_reply(repinfo);
return 0; return 0;
} }
if(is_expired_answer) {
worker->stats.ans_expired++;
}
if(worker->stats.extended) {
if(is_secure_answer) worker->stats.ans_secure++;
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
}
#ifdef USE_DNSTAP #ifdef USE_DNSTAP
if(worker->dtenv.log_client_response_messages) if(worker->dtenv.log_client_response_messages)
dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, dt_msg_send_client_response(&worker->dtenv, &repinfo->addr,
@ -1830,6 +1866,10 @@ worker_init(struct worker* worker, struct config_file *cfg,
return 0; return 0;
} }
worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env); worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
/* Pass on daemon variables that we would need in the mesh area */
worker->env.mesh->use_response_ip = worker->daemon->use_response_ip;
worker->env.mesh->use_rpz = worker->daemon->use_rpz;
worker->env.detach_subs = &mesh_detach_subs; worker->env.detach_subs = &mesh_detach_subs;
worker->env.attach_sub = &mesh_attach_sub; worker->env.attach_sub = &mesh_attach_sub;
worker->env.add_sub = &mesh_add_sub; worker->env.add_sub = &mesh_add_sub;

View File

@ -1,6 +1,175 @@
20 February 2020: Wouter
- Updated contrib/unbound_smf23.tar.gz with Solaris SMF service for
Unbound from Yuri Voinov.
17 February 2020: Ralph
- Add respip to supported module-config options in unbound-checkconf.
17 February 2020: George
- Remove unused variable.
17 February 2020: Wouter
- contrib/drop2rpz: perl script that converts the Spamhaus DROP-List
in RPZ-Format, contributed by Andreas Schulze.
14 February 2020: Wouter
- Fix spelling in unbound.conf.5.in.
- Stop unbound-checkconf from insisting that auth-zone and rpz
zonefiles have to exist. They can not exist, and download later.
13 February 2020: Wouter
- tag for 1.10.0rc1 release.
12 February 2020: Wouter
- Fix with libnettle make test with dsa disabled.
- Fix contrib/fastrpz.patch to apply cleanly. Fix for serve-stale
fixes, but it does not compile, conflicts with new rpz code.
- Fix to clean memory leak of respip_addr.lock when ip_tree deleted.
- Fix compile warning when threads disabled.
- updated version number to 1.10.0.
10 February 2020: George
- Document 'ub_result.was_ratelimited' in libunbound.
- Fix use after free on log-identity after a reload; Fixes #163.
6 February 2020: George
- Fix num_reply_states and num_detached_states counting with
serve_expired_callback.
- Cleaner code in mesh_serve_expired_lookup.
- Document in unbound.conf manpage that configuration clauses can be
repeated in the configuration file.
6 February 2020: Wouter
- Fix num_reply_addr counting in mesh and tcp drop due to size
after serve_stale commit.
- Fix to create and destroy rpz_lock in auth_zones structure.
- Fix to lock zone before adding rpz qname trigger.
- Fix to lock and release once in mesh_serve_expired_lookup.
- Fix to put braces around empty if body when threading is disabled.
5 February 2020: George
- Added serve-stale functionality as described in
draft-ietf-dnsop-serve-stale-10. `serve-expired-*` options can be used
to configure the behavior.
- Updated cachedb to honor `serve-expired-ttl`; Fixes #107.
- Renamed statistic `num.zero_ttl` to `num.expired` as expired replies
come with a configurable TTL value (`serve-expired-reply-ttl`).
- Fixed stats when replying with cached, cname-aliased records.
- Added missing default values for redis cachedb backend.
3 February 2020: Ralph
- Add assertion to please static analyzer
31 January 2020: Wouter
- Fix fclose on error in TLS session ticket code.
30 January 2020: Ralph
- Fix memory leak in error condition remote.c
- Fix double free in error condition view.c
- Fix memory leak in do_auth_zone_transfer on success
- Merge RPZ support into master. Only QNAME and Response IP triggers are
supported.
- Stop working on socket when socket() call returns an error.
- Check malloc return values in TLS session ticket code
30 January 2020: Wouter
- Fix subnet tests for disabled DSA algorithm by default.
- Update contrib/fastrpz.patch for clean diff with current code.
- Merge PR#151: Fixes for systemd units, by Maryse47, Edmonds
and Frzk. Updates the unbound.service systemd file and adds
a portable systemd service file.
- updated .gitignore for added contrib file.
- Add build rule for ipset to Makefile
- Add getentropy_freebsd.o to Makefile dependencies.
29 January 2020: Ralph
- Merge PR#156 from Alexander Berkes; Added unbound-control
view_local_datas_remove command.
29 January 2020: Wouter
- Fix #157: undefined reference to `htobe64'.
28 January 2020: Ralph
- Merge PR#147; change rfc reference for reserved top level dns names.
28 January 2020: Wouter
- iana portlist updated.
- Fix to silence the tls handshake errors for broken pipe and reset
by peer, unless verbosity is set to 2 or higher.
27 January 2020: Ralph
- Merge PR#154; Allow use of libbsd functions with configure option
--with-libbsd. By Robert Edmonds and Steven Chamberlain.
- Merge PR#148; Add some TLS stats to unbound_munin_. By Fredrik Pettai.
27 January 2020: Wouter
- Merge PR#155 from Robert Edmonds: contrib/libunbound.pc.in: Fixes
to Libs/Requires for crypto library dependencies.
- Fix #153: Disable validation for DSA algorithms. RFC 8624
compliance.
23 January 2020: Wouter
- Merge PR#150 from Frzk: Systemd unit without chroot. It add
contrib/unbound_nochroot.service.in, a systemd file for use with
chroot: "", see comments in the file, it uses systemd protections
instead.
14 January 2020: Wouter
- Removed the dnscrypt_queries and dnscrypt_queries_chacha tests,
because dnscrypt-proxy (2.0.36) does not support the test setup
any more, and also the config file format does not seem to have
the appropriate keys to recreate that setup.
- Fix crash after reload where a stats lookup could reference old key
cache and neg cache structures.
- Fix for memory leak when edns subnet config options are read when
compiled without edns subnet support.
- Fix auth zone support for NSEC3 records without salt.
10 January 2020: Wouter
- Fix the relationship between serve-expired and prefetch options,
patch from Saksham Manchanda from Secure64.
- Fix unreachable code in ssl set options code.
8 January 2020: Ralph
- Fix #138: stop binding pidfile inside chroot dir in systemd service
file.
8 January 2020: Wouter
- Fix 'make test' to work for --disable-sha1 configure option.
- Fix out-of-bounds null-byte write in sldns_bget_token_par while
parsing type WKS, reported by Luis Merino from X41 D-Sec.
- Updated sldns_bget_token_par fix for also space for the zero
delimiter after the character. And update for more spare space.
6 January 2020: George
- Downgrade compat/getentropy_solaris.c to version 1.4 from OpenBSD.
The dl_iterate_phdr() function introduced in newer versions raises
compilation errors on solaris 10.
- Changes to compat/getentropy_solaris.c for,
ifdef stdint.h inclusion for older systems.
ifdef sha2.h inclusion for older systems.
6 January 2020: Wouter
- Merge #135 from Florian Obser: Use passed in neg and key cache
if non-NULL.
- Fix #140: Document slave not downloading new zonefile upon update.
16 December 2019: George
- Update mailing list URL.
12 December 2019: Ralph
- Master is 1.9.7 in development.
- Fix typo to let serve-expired-ttl work with ub_ctx_set_option(), by
Florian Obser
10 December 2019: Wouter
- Fix to make auth zone IXFR to fallback to AXFR if a single
response RR is received over TCP with the SOA in it.
6 December 2019: Wouter 6 December 2019: Wouter
- Fix ipsecmod compile. - Fix ipsecmod compile.
- Fix Makefile.in for ipset module compile, from Adi Prasaja. - Fix Makefile.in for ipset module compile, from Adi Prasaja.
- release-1.9.6 tag, which became the 1.9.6 release
5 December 2019: Wouter 5 December 2019: Wouter
- unbound-fuzzers.tar.bz2: three programs for fuzzing, that are 1:1 - unbound-fuzzers.tar.bz2: three programs for fuzzing, that are 1:1

View File

@ -1,4 +1,4 @@
README for Unbound 1.9.6 README for Unbound 1.10.1
Copyright 2007 NLnet Labs Copyright 2007 NLnet Labs
http://unbound.net http://unbound.net

View File

@ -1,7 +1,7 @@
# #
# Example configuration file. # Example configuration file.
# #
# See unbound.conf(5) man page, version 1.9.6. # See unbound.conf(5) man page, version 1.10.1.
# #
# this is a comment. # this is a comment.
@ -558,8 +558,8 @@ server:
# that set CD but cannot validate themselves. # that set CD but cannot validate themselves.
# ignore-cd-flag: no # ignore-cd-flag: no
# Serve expired responses from cache, with TTL 0 in the response, # Serve expired responses from cache, with serve-expired-reply-ttl in
# and then attempt to fetch the data afresh. # the response, and then attempt to fetch the data afresh.
# serve-expired: no # serve-expired: no
# #
# Limit serving of expired responses to configured seconds after # Limit serving of expired responses to configured seconds after
@ -571,6 +571,16 @@ server:
# that the expired records will be served as long as there are queries # that the expired records will be served as long as there are queries
# for it. # for it.
# serve-expired-ttl-reset: no # serve-expired-ttl-reset: no
#
# TTL value to use when replying with expired data.
# serve-expired-reply-ttl: 30
#
# Time in milliseconds before replying to the client with expired data.
# This essentially enables the serve-stale behavior as specified in
# draft-ietf-dnsop-serve-stale-10 that first tries to resolve before
# immediately responding with expired data. 0 disables this behavior.
# A recommended value is 1800.
# serve-expired-client-timeout: 0
# Have the validator log failed validations for your diagnosis. # Have the validator log failed validations for your diagnosis.
# 0: off. 1: A line per failed user query. 2: With reason and bad IP. # 0: off. 1: A line per failed user query. 2: With reason and bad IP.
@ -1006,3 +1016,20 @@ remote-control:
# name-v6: "list-v6" # name-v6: "list-v6"
# #
# Response Policy Zones
# RPZ policies. Applied in order of configuration. QNAME and Response IP
# Address trigger are the only supported triggers. Supported actions are:
# NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. Policies can be loaded from
# file, using zone transfer, or using HTTP. The respip module needs to be added
# to the module-config, e.g.: module-config: "respip validator iterator".
# rpz:
# name: "rpz.example.com"
# zonefile: "rpz.example.com"
# master: 192.0.2.0
# allow-notify: 192.0.2.0/32
# url: http://www.example.com/rpz.example.org.zone
# rpz-action-override: cname
# rpz-cname-override: www.example.org
# rpz-log: yes
# rpz-log-name: "example policy"
# tags: "example"

View File

@ -1,4 +1,4 @@
.TH "libunbound" "3" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "libunbound" "3" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" libunbound.3 -- unbound library functions manual .\" libunbound.3 -- unbound library functions manual
.\" .\"
@ -44,7 +44,7 @@
.B ub_ctx_zone_remove, .B ub_ctx_zone_remove,
.B ub_ctx_data_add, .B ub_ctx_data_add,
.B ub_ctx_data_remove .B ub_ctx_data_remove
\- Unbound DNS validating resolver 1.9.6 functions. \- Unbound DNS validating resolver 1.10.1 functions.
.SH "SYNOPSIS" .SH "SYNOPSIS"
.B #include <unbound.h> .B #include <unbound.h>
.LP .LP
@ -396,12 +396,13 @@ The result of the DNS resolution and validation is returned as
char* canonname; /* canonical name of result */ char* canonname; /* canonical name of result */
int rcode; /* additional error code in case of no data */ int rcode; /* additional error code in case of no data */
void* answer_packet; /* full network format answer packet */ void* answer_packet; /* full network format answer packet */
int answer_len; /* length of packet in octets */ int answer_len; /* length of packet in octets */
int havedata; /* true if there is data */ int havedata; /* true if there is data */
int nxdomain; /* true if nodata because name does not exist */ int nxdomain; /* true if nodata because name does not exist */
int secure; /* true if result is secure */ int secure; /* true if result is secure */
int bogus; /* true if a security failure happened */ int bogus; /* true if a security failure happened */
char* why_bogus; /* string with error if bogus */ char* why_bogus; /* string with error if bogus */
int was_ratelimited; /* true if the query was ratelimited (SERVFAIL) by unbound */
int ttl; /* number of seconds the result is valid */ int ttl; /* number of seconds the result is valid */
}; };
.fi .fi

View File

@ -1,4 +1,4 @@
.TH "unbound-anchor" "8" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound-anchor" "8" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual .\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\" .\"

View File

@ -1,4 +1,4 @@
.TH "unbound-checkconf" "8" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound-checkconf" "8" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound-checkconf.8 -- unbound configuration checker manual .\" unbound-checkconf.8 -- unbound configuration checker manual
.\" .\"

View File

@ -1,4 +1,4 @@
.TH "unbound-control" "8" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound-control" "8" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound-control.8 -- unbound remote control manual .\" unbound-control.8 -- unbound remote control manual
.\" .\"
@ -323,6 +323,9 @@ serial check). And then the zone is transferred for a newer zone version.
.B view_local_data_remove \fIview\fR \fIname .B view_local_data_remove \fIview\fR \fIname
\fIlocal_data_remove\fR for given view. \fIlocal_data_remove\fR for given view.
.TP .TP
.B view_local_datas_remove \fIview\fR
Remove a list of \fIlocal_data\fR for given view from stdin. Like local_datas_remove.
.TP
.B view_local_datas \fIview\fR .B view_local_datas \fIview\fR
Add a list of \fIlocal_data\fR for given view from stdin. Like local_datas. Add a list of \fIlocal_data\fR for given view from stdin. Like local_datas.
.SH "EXIT CODE" .SH "EXIT CODE"
@ -379,8 +382,8 @@ and resulted in recursive processing, taking a slot in the requestlist.
Not part of the recursivereplies (or the histogram thereof) or cachemiss, Not part of the recursivereplies (or the histogram thereof) or cachemiss,
as a cache response was sent. as a cache response was sent.
.TP .TP
.I threadX.num.zero_ttl .I threadX.num.expired
number of replies with ttl zero, because they served an expired cache entry. number of replies that served an expired cache entry.
.TP .TP
.I threadX.num.recursivereplies .I threadX.num.recursivereplies
The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries. The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries.
@ -443,7 +446,7 @@ summed over threads.
.I total.num.prefetch .I total.num.prefetch
summed over threads. summed over threads.
.TP .TP
.I total.num.zero_ttl .I total.num.expired
summed over threads. summed over threads.
.TP .TP
.I total.num.recursivereplies .I total.num.recursivereplies
@ -660,6 +663,11 @@ Number of queries that got an answer that contained EDNS client subnet data.
Number of queries answered from the edns client subnet cache. These are Number of queries answered from the edns client subnet cache. These are
counted as cachemiss by the main counters, but hit the client subnet counted as cachemiss by the main counters, but hit the client subnet
specific cache, after getting processed by the edns client subnet module. specific cache, after getting processed by the edns client subnet module.
.TP
.I num.rpz.action.<rpz_action>
Number of queries answered using configured RPZ policy, per RPZ action type.
Possible actions are: nxdomain, nodata, passthru, drop, local_data, disabled,
and cname_override.
.SH "FILES" .SH "FILES"
.TP .TP
.I @ub_conf_file@ .I @ub_conf_file@

View File

@ -1,4 +1,4 @@
.TH "unbound\-host" "1" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound\-host" "1" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound-host.1 -- unbound DNS lookup utility .\" unbound-host.1 -- unbound DNS lookup utility
.\" .\"

View File

@ -1,4 +1,4 @@
.TH "unbound" "8" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound" "8" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound.8 -- unbound manual .\" unbound.8 -- unbound manual
.\" .\"
@ -9,7 +9,7 @@
.\" .\"
.SH "NAME" .SH "NAME"
.B unbound .B unbound
\- Unbound DNS validating resolver 1.9.6. \- Unbound DNS validating resolver 1.10.1.
.SH "SYNOPSIS" .SH "SYNOPSIS"
.B unbound .B unbound
.RB [ \-h ] .RB [ \-h ]

View File

@ -1,4 +1,4 @@
.TH "unbound.conf" "5" "dec 12, 2019" "NLnet Labs" "unbound 1.9.6" .TH "unbound.conf" "5" "May 19, 2020" "NLnet Labs" "unbound 1.10.1"
.\" .\"
.\" unbound.conf.5 -- unbound.conf manual .\" unbound.conf.5 -- unbound.conf manual
.\" .\"
@ -63,8 +63,10 @@ server:
access\-control: 2001:DB8::/64 allow access\-control: 2001:DB8::/64 allow
.fi .fi
.SH "FILE FORMAT" .SH "FILE FORMAT"
There must be whitespace between keywords. Attribute keywords end with a colon ':'. There must be whitespace between keywords. Attribute keywords end with a
An attribute is followed by its containing attributes, or a value. colon ':'. An attribute is followed by a value, or its containing attributes
in which case it is referred to as a clause. Clauses can be repeated throughout
the file (or included files) to group attributes under the same clause.
.P .P
Files can be included using the Files can be included using the
.B include: .B include:
@ -1070,20 +1072,35 @@ The default value is "no".
.TP .TP
.B serve\-expired: \fI<yes or no> .B serve\-expired: \fI<yes or no>
If enabled, unbound attempts to serve old responses from cache with a If enabled, unbound attempts to serve old responses from cache with a
TTL of 0 in the response without waiting for the actual resolution to finish. TTL of \fBserve\-expired\-reply\-ttl\fR in the response without waiting for the
The actual resolution answer ends up in the cache later on. Default is "no". actual resolution to finish. The actual resolution answer ends up in the cache
later on. Default is "no".
.TP .TP
.B serve\-expired\-ttl: \fI<seconds> .B serve\-expired\-ttl: \fI<seconds>
Limit serving of expired responses to configured seconds after expiration. 0 Limit serving of expired responses to configured seconds after expiration. 0
disables the limit. This option only applies when \fBserve\-expired\fR is disables the limit. This option only applies when \fBserve\-expired\fR is
enabled. The default is 0. enabled. A suggested value per draft-ietf-dnsop-serve-stale-10 is between
86400 (1 day) and 259200 (3 days). The default is 0.
.TP .TP
.B serve\-expired\-ttl\-reset: \fI<yes or no> .B serve\-expired\-ttl\-reset: \fI<yes or no>
Set the TTL of expired records to the \fBserve\-expired\-ttl\fR value after a Set the TTL of expired records to the \fBserve\-expired\-ttl\fR value after a
failed attempt to retrieve the record from upstream. This makes sure that the failed attempt to retrieve the record from upstream. This makes sure that the
expired records will be served as long as there are queries for it. Default is expired records will be served as long as there are queries for it. Default is
"no". "no".
.TP .TP
.B serve\-expired\-reply\-ttl: \fI<seconds>
TTL value to use when replying with expired data. If
\fBserve\-expired\-client\-timeout\fR is also used then it is RECOMMENDED to
use 30 as the value (draft-ietf-dnsop-serve-stale-10). The default is 30.
.TP
.B serve\-expired\-client\-timeout: \fI<msec>
Time in milliseconds before replying to the client with expired data. This
essentially enables the serve-stale behavior as specified in
draft-ietf-dnsop-serve-stale-10 that first tries to resolve before immediately
responding with expired data. A recommended value per
draft-ietf-dnsop-serve-stale-10 is 1800. Setting this to 0 will disable this
behavior. Default is 0.
.TP
.B val\-nsec3\-keysize\-iterations: \fI<"list of values"> .B val\-nsec3\-keysize\-iterations: \fI<"list of values">
List of keysize and iteration count values, separated by spaces, surrounded List of keysize and iteration count values, separated by spaces, surrounded
by quotes. Default is "1024 150 2048 500 4096 2500". This determines the by quotes. Default is "1024 150 2048 500 4096 2500". This determines the
@ -1296,7 +1313,7 @@ local\-data: "onion. 10800 IN
SOA localhost. nobody.invalid. 1 3600 1200 604800 10800" SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
.fi .fi
.TP 10 .TP 10
\h'5'\fItest (RFC 2606)\fR \h'5'\fItest (RFC 6761)\fR
Default content: Default content:
.nf .nf
local\-zone: "test." static local\-zone: "test." static
@ -1305,7 +1322,7 @@ local\-data: "test. 10800 IN
SOA localhost. nobody.invalid. 1 3600 1200 604800 10800" SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
.fi .fi
.TP 10 .TP 10
\h'5'\fIinvalid (RFC 2606)\fR \h'5'\fIinvalid (RFC 6761)\fR
Default content: Default content:
.nf .nf
local\-zone: "invalid." static local\-zone: "invalid." static
@ -1680,6 +1697,12 @@ Name of the authority zone.
Where to download a copy of the zone from, with AXFR and IXFR. Multiple Where to download a copy of the zone from, with AXFR and IXFR. Multiple
masters can be specified. They are all tried if one fails. masters can be specified. They are all tried if one fails.
With the "ip#name" notation a AXFR over TLS can be used. With the "ip#name" notation a AXFR over TLS can be used.
If you point it at another Unbound instance, it would not work because
that does not support AXFR/IXFR for the zone, but if you used \fBurl:\fR to download
the zonefile as a text file from a webserver that would work.
If you specify the hostname, you cannot use the domain from the zonefile,
because it may not have that when retrieving that data, instead use a plain
IP address to avoid a circular dependency on retrieving that IP address.
.TP .TP
.B url: \fI<url to zonefile> .B url: \fI<url to zonefile>
Where to download a zonefile for the zone. With http or https. An example Where to download a zonefile for the zone. With http or https. An example
@ -1691,6 +1714,10 @@ see if the SOA serial number has changed, reducing the number of downloads.
If none of the urls work, the masters are tried with IXFR and AXFR. If none of the urls work, the masters are tried with IXFR and AXFR.
For https, the \fBtls\-cert\-bundle\fR and the hostname from the url are used For https, the \fBtls\-cert\-bundle\fR and the hostname from the url are used
to authenticate the connection. to authenticate the connection.
If you specify a hostname in the URL, you cannot use the domain from the
zonefile, because it may not have that when retrieving that data, instead
use a plain IP address to avoid a circular dependency on retrieving that IP
address. Avoid dependencies on name lookups by using a notation like "http://192.0.2.1/unbound-master/example.com.zone", with an explicit IP address.
.TP .TP
.B allow\-notify: \fI<IP address or host name or netblockIP/prefix> .B allow\-notify: \fI<IP address or host name or netblockIP/prefix>
With allow\-notify you can specify additional sources of notifies. With allow\-notify you can specify additional sources of notifies.
@ -2014,6 +2041,13 @@ to the query without performing iterative DNS resolution.
If Unbound cannot even find an answer in the backend, it resolves the If Unbound cannot even find an answer in the backend, it resolves the
query as usual, and stores the answer in the backend. query as usual, and stores the answer in the backend.
.P .P
This module interacts with the \fBserve\-expired\-*\fR options and will reply
with expired data if unbound is configured for that. Currently the use
of \fBserve\-expired\-client\-timeout:\fR and
\fBserve\-expired\-reply\-ttl:\fR is not consistent for data originating from
the external cache as these will result in a reply with 0 TTL without trying to
update the data first, ignoring the configured values.
.P
If Unbound was built with If Unbound was built with
\fB\-\-with\-libhiredis\fR \fB\-\-with\-libhiredis\fR
on a system that has installed the hiredis C client library of Redis, on a system that has installed the hiredis C client library of Redis,
@ -2080,6 +2114,70 @@ If this timeout expires Unbound closes the connection, treats it as
if the Redis server does not have the requested data, and will try to if the Redis server does not have the requested data, and will try to
re-establish a new connection later. re-establish a new connection later.
This option defaults to 100 milliseconds. This option defaults to 100 milliseconds.
.SS Response Policy Zone Options
.LP
Response Policy Zones are configured with \fBrpz:\fR, and each one must have a
\fBname:\fR. There can be multiple ones, by listing multiple rpz clauses, each
with a different name. RPZ clauses are applied in order of configuration. The
\fBrespip\fR module needs to be added to the \fBmodule-config\fR, e.g.:
\fBmodule-config: "respip validator iterator"\fR.
.P
Only the QNAME and Response IP Address triggers are supported. The supported RPZ
actions are: NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. RPZ QNAME triggers
are applied after
\fBlocal-zones\fR and before \fBauth-zones\fR.
.TP
.B name: \fI<zone name>
Name of the authority zone.
.TP
.B master: \fI<IP address or host name>
Where to download a copy of the zone from, with AXFR and IXFR. Multiple
masters can be specified. They are all tried if one fails.
.TP
.B url: \fI<url to zonefile>
Where to download a zonefile for the zone. With http or https. An example
for the url is "http://www.example.com/example.org.zone". Multiple url
statements can be given, they are tried in turn. If only urls are given
the SOA refresh timer is used to wait for making new downloads. If also
masters are listed, the masters are first probed with UDP SOA queries to
see if the SOA serial number has changed, reducing the number of downloads.
If none of the urls work, the masters are tried with IXFR and AXFR.
For https, the \fBtls\-cert\-bundle\fR and the hostname from the url are used
to authenticate the connection.
.TP
.B allow\-notify: \fI<IP address or host name or netblockIP/prefix>
With allow\-notify you can specify additional sources of notifies.
When notified, the server attempts to first probe and then zone transfer.
If the notify is from a master, it first attempts that master. Otherwise
other masters are attempted. If there are no masters, but only urls, the
file is downloaded when notified. The masters from master: statements are
allowed notify by default.
.TP
.B zonefile: \fI<filename>
The filename where the zone is stored. If not given then no zonefile is used.
If the file does not exist or is empty, unbound will attempt to fetch zone
data (eg. from the master servers).
.TP
.B rpz\-action\-override: \fI<action>
Always use this RPZ action for matching triggers from this zone. Possible action
are: nxdomain, nodata, passthru, drop, disabled and cname.
.TP
.B rpz\-cname\-override: \fI<domain>
The CNAME target domain to use if the cname action is configured for
\fBrpz\-action\-override\fR.
.TP
.B rpz\-log: \fI<yes or no>
Log all applied RPZ actions for this RPZ zone. Default is no.
.TP
.B rpz\-log\-name: \fI<name>
Specify a string to be part of the log line, for easy referencing.
.TP
.B tags: \fI<list of tags>
Limit the policies from this RPZ clause to clients with a matching tag. Tags
need to be defined in \fBdefine\-tag\fR and can be assigned to client addresses
using \fBaccess\-control\-tag\fR. Enclose list of tags in quotes ("") and put
spaces between tags. If no tags are specified the policies from this clause will
be applied for all clients.
.SH "MEMORY CONTROL EXAMPLE" .SH "MEMORY CONTROL EXAMPLE"
In the example config settings below memory usage is reduced. Some service In the example config settings below memory usage is reduced. Some service
levels are lower, notable very large data and a high TCP load are no longer levels are lower, notable very large data and a high TCP load are no longer

View File

@ -431,7 +431,7 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
} }
qstate->return_msg = tomsg(NULL, &qstate->qinfo, qstate->return_msg = tomsg(NULL, &qstate->qinfo,
(struct reply_info *)node->elem, qstate->region, *env->now, (struct reply_info *)node->elem, qstate->region, *env->now, 0,
env->scratch); env->scratch);
scope = (uint8_t)node->scope; scope = (uint8_t)node->scope;
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/usr/bin/sh
# install - install a program, script, or datafile # install - install a program, script, or datafile
scriptversion=2014-09-12.12; # UTC scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was # This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the # later released in X11R6 (xc/config/util/install.sh) with the
@ -324,41 +324,34 @@ do
# is incompatible with FreeBSD 'install' when (umask & 300) != 0. # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;; ;;
*) *)
# $RANDOM is not portable (e.g. dash); use it when possible to
# lower collision chance
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
# create the $tmpdir first (and fail if unsuccessful) to make sure
# that nobody tries to guess the $tmpdir name.
if (umask $mkdir_umask && if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then then
if test -z "$dir_arg" || { if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m. # Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't. # other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$tmpdir"`
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;; d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;; d????-?--*) different_mode=755;;
*) false;; *) false;;
esac && esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && { $mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
} }
} }
then posix_mkdir=: then posix_mkdir=:
fi fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" rmdir "$tmpdir/d" "$tmpdir"
else else
# Remove any dirs left behind by ancient mkdir implementations. # Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi fi
trap '' 0;; trap '' 0;;
esac;; esac;;

View File

@ -84,7 +84,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
} }
for(a = dp->target_list; a; a = a->next_target) { for(a = dp->target_list; a; a = a->next_target) {
if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen, if(!delegpt_add_addr(copy, region, &a->addr, a->addrlen,
a->bogus, a->lame, a->tls_auth_name)) a->bogus, a->lame, a->tls_auth_name, NULL))
return NULL; return NULL;
} }
return copy; return copy;
@ -161,7 +161,7 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr,
int int
delegpt_add_target(struct delegpt* dp, struct regional* region, delegpt_add_target(struct delegpt* dp, struct regional* region,
uint8_t* name, size_t namelen, struct sockaddr_storage* addr, uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t bogus, uint8_t lame) socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions)
{ {
struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen);
log_assert(!dp->dp_type_mlc); log_assert(!dp->dp_type_mlc);
@ -176,13 +176,14 @@ delegpt_add_target(struct delegpt* dp, struct regional* region,
if(ns->got4 && ns->got6) if(ns->got4 && ns->got6)
ns->resolved = 1; ns->resolved = 1;
} }
return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, NULL); return delegpt_add_addr(dp, region, addr, addrlen, bogus, lame, NULL,
additions);
} }
int int
delegpt_add_addr(struct delegpt* dp, struct regional* region, delegpt_add_addr(struct delegpt* dp, struct regional* region,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus,
uint8_t lame, char* tls_auth_name) uint8_t lame, char* tls_auth_name, int* additions)
{ {
struct delegpt_addr* a; struct delegpt_addr* a;
log_assert(!dp->dp_type_mlc); log_assert(!dp->dp_type_mlc);
@ -194,6 +195,8 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
a->lame = 0; a->lame = 0;
return 1; return 1;
} }
if(additions)
*additions = 1;
a = (struct delegpt_addr*)regional_alloc(region, a = (struct delegpt_addr*)regional_alloc(region,
sizeof(struct delegpt_addr)); sizeof(struct delegpt_addr));
@ -382,10 +385,10 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
continue; continue;
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) { if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
if(!delegpt_add_rrset_A(dp, region, s, 0)) if(!delegpt_add_rrset_A(dp, region, s, 0, NULL))
return NULL; return NULL;
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) { } else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
if(!delegpt_add_rrset_AAAA(dp, region, s, 0)) if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL))
return NULL; return NULL;
} }
} }
@ -416,7 +419,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
int int
delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
struct ub_packed_rrset_key* ak, uint8_t lame) struct ub_packed_rrset_key* ak, uint8_t lame, int* additions)
{ {
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
size_t i; size_t i;
@ -432,7 +435,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE); memmove(&sa.sin_addr, d->rr_data[i]+2, INET_SIZE);
if(!delegpt_add_target(dp, region, ak->rk.dname, if(!delegpt_add_target(dp, region, ak->rk.dname,
ak->rk.dname_len, (struct sockaddr_storage*)&sa, ak->rk.dname_len, (struct sockaddr_storage*)&sa,
len, (d->security==sec_status_bogus), lame)) len, (d->security==sec_status_bogus), lame, additions))
return 0; return 0;
} }
return 1; return 1;
@ -440,7 +443,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
int int
delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
struct ub_packed_rrset_key* ak, uint8_t lame) struct ub_packed_rrset_key* ak, uint8_t lame, int* additions)
{ {
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
size_t i; size_t i;
@ -456,7 +459,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE); memmove(&sa.sin6_addr, d->rr_data[i]+2, INET6_SIZE);
if(!delegpt_add_target(dp, region, ak->rk.dname, if(!delegpt_add_target(dp, region, ak->rk.dname,
ak->rk.dname_len, (struct sockaddr_storage*)&sa, ak->rk.dname_len, (struct sockaddr_storage*)&sa,
len, (d->security==sec_status_bogus), lame)) len, (d->security==sec_status_bogus), lame, additions))
return 0; return 0;
} }
return 1; return 1;
@ -464,20 +467,33 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
int int
delegpt_add_rrset(struct delegpt* dp, struct regional* region, delegpt_add_rrset(struct delegpt* dp, struct regional* region,
struct ub_packed_rrset_key* rrset, uint8_t lame) struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions)
{ {
if(!rrset) if(!rrset)
return 1; return 1;
if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS) if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
return delegpt_rrset_add_ns(dp, region, rrset, lame); return delegpt_rrset_add_ns(dp, region, rrset, lame);
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A) else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
return delegpt_add_rrset_A(dp, region, rrset, lame); return delegpt_add_rrset_A(dp, region, rrset, lame, additions);
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA) else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
return delegpt_add_rrset_AAAA(dp, region, rrset, lame); return delegpt_add_rrset_AAAA(dp, region, rrset, lame,
additions);
log_warn("Unknown rrset type added to delegpt"); log_warn("Unknown rrset type added to delegpt");
return 1; return 1;
} }
void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype)
{
if(ns) {
if(qtype == LDNS_RR_TYPE_A)
ns->got4 = 2;
else if(qtype == LDNS_RR_TYPE_AAAA)
ns->got6 = 2;
if(ns->got4 && ns->got6)
ns->resolved = 1;
}
}
void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg) void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg)
{ {
struct reply_info* rep = (struct reply_info*)msg->entry.data; struct reply_info* rep = (struct reply_info*)msg->entry.data;
@ -487,14 +503,7 @@ void delegpt_add_neg_msg(struct delegpt* dp, struct msgreply_entry* msg)
if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) { if(FLAGS_GET_RCODE(rep->flags) != 0 || rep->an_numrrsets == 0) {
struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname, struct delegpt_ns* ns = delegpt_find_ns(dp, msg->key.qname,
msg->key.qname_len); msg->key.qname_len);
if(ns) { delegpt_mark_neg(ns, msg->key.qtype);
if(msg->key.qtype == LDNS_RR_TYPE_A)
ns->got4 = 1;
else if(msg->key.qtype == LDNS_RR_TYPE_AAAA)
ns->got6 = 1;
if(ns->got4 && ns->got6)
ns->resolved = 1;
}
} }
} }

View File

@ -106,9 +106,10 @@ struct delegpt_ns {
* and marked true if got4 and got6 are both true. * and marked true if got4 and got6 are both true.
*/ */
int resolved; int resolved;
/** if the ipv4 address is in the delegpt */ /** if the ipv4 address is in the delegpt, 0=not, 1=yes 2=negative,
* negative means it was done, but no content. */
uint8_t got4; uint8_t got4;
/** if the ipv6 address is in the delegpt */ /** if the ipv6 address is in the delegpt, 0=not, 1=yes 2=negative */
uint8_t got6; uint8_t got6;
/** /**
* If the name is parent-side only and thus dispreferred. * If the name is parent-side only and thus dispreferred.
@ -215,11 +216,12 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
* @param addrlen: the length of addr. * @param addrlen: the length of addr.
* @param bogus: security status for the address, pass true if bogus. * @param bogus: security status for the address, pass true if bogus.
* @param lame: address is lame. * @param lame: address is lame.
* @param additions: will be set to 1 if a new address is added
* @return false on error. * @return false on error.
*/ */
int delegpt_add_target(struct delegpt* dp, struct regional* regional, int delegpt_add_target(struct delegpt* dp, struct regional* regional,
uint8_t* name, size_t namelen, struct sockaddr_storage* addr, uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t bogus, uint8_t lame); socklen_t addrlen, uint8_t bogus, uint8_t lame, int* additions);
/** /**
* Add A RRset to delegpt. * Add A RRset to delegpt.
@ -227,10 +229,11 @@ int delegpt_add_target(struct delegpt* dp, struct regional* regional,
* @param regional: where to allocate the info. * @param regional: where to allocate the info.
* @param rrset: RRset A to add. * @param rrset: RRset A to add.
* @param lame: rrset is lame, disprefer it. * @param lame: rrset is lame, disprefer it.
* @param additions: will be set to 1 if a new address is added
* @return 0 on alloc error. * @return 0 on alloc error.
*/ */
int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional, int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
struct ub_packed_rrset_key* rrset, uint8_t lame); struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions);
/** /**
* Add AAAA RRset to delegpt. * Add AAAA RRset to delegpt.
@ -238,10 +241,11 @@ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
* @param regional: where to allocate the info. * @param regional: where to allocate the info.
* @param rrset: RRset AAAA to add. * @param rrset: RRset AAAA to add.
* @param lame: rrset is lame, disprefer it. * @param lame: rrset is lame, disprefer it.
* @param additions: will be set to 1 if a new address is added
* @return 0 on alloc error. * @return 0 on alloc error.
*/ */
int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
struct ub_packed_rrset_key* rrset, uint8_t lame); struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions);
/** /**
* Add any RRset to delegpt. * Add any RRset to delegpt.
@ -250,10 +254,11 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
* @param regional: where to allocate the info. * @param regional: where to allocate the info.
* @param rrset: RRset to add, NS, A, AAAA. * @param rrset: RRset to add, NS, A, AAAA.
* @param lame: rrset is lame, disprefer it. * @param lame: rrset is lame, disprefer it.
* @param additions: will be set to 1 if a new address is added
* @return 0 on alloc error. * @return 0 on alloc error.
*/ */
int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
struct ub_packed_rrset_key* rrset, uint8_t lame); struct ub_packed_rrset_key* rrset, uint8_t lame, int* additions);
/** /**
* Add address to the delegation point. No servername is associated or checked. * Add address to the delegation point. No servername is associated or checked.
@ -264,11 +269,12 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
* @param bogus: if address is bogus. * @param bogus: if address is bogus.
* @param lame: if address is lame. * @param lame: if address is lame.
* @param tls_auth_name: TLS authentication name (or NULL). * @param tls_auth_name: TLS authentication name (or NULL).
* @param additions: will be set to 1 if a new address is added
* @return false on error. * @return false on error.
*/ */
int delegpt_add_addr(struct delegpt* dp, struct regional* regional, int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
struct sockaddr_storage* addr, socklen_t addrlen, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t bogus, uint8_t lame, char* tls_auth_name); uint8_t bogus, uint8_t lame, char* tls_auth_name, int* additions);
/** /**
* Find NS record in name list of delegation point. * Find NS record in name list of delegation point.
@ -341,6 +347,14 @@ size_t delegpt_count_targets(struct delegpt* dp);
struct delegpt* delegpt_from_message(struct dns_msg* msg, struct delegpt* delegpt_from_message(struct dns_msg* msg,
struct regional* regional); struct regional* regional);
/**
* Mark negative return in delegation point for specific nameserver.
* sets the got4 or got6 to negative, updates the ns->resolved.
* @param ns: the nameserver in the delegpt.
* @param qtype: A or AAAA (host order).
*/
void delegpt_mark_neg(struct delegpt_ns* ns, uint16_t qtype);
/** /**
* Add negative message to delegation point. * Add negative message to delegation point.
* @param dp: delegation point. * @param dp: delegation point.

View File

@ -185,8 +185,9 @@ mark_additional_rrset(sldns_buffer* pkt, struct msg_parse* msg,
/** Get target name of a CNAME */ /** Get target name of a CNAME */
static int static int
parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname, parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname,
size_t* snamelen) size_t* snamelen, sldns_buffer* pkt)
{ {
size_t oldpos, dlen;
if(rrset->rr_count != 1) { if(rrset->rr_count != 1) {
struct rr_parse* sig; struct rr_parse* sig;
verbose(VERB_ALGO, "Found CNAME rrset with " verbose(VERB_ALGO, "Found CNAME rrset with "
@ -204,6 +205,19 @@ parse_get_cname_target(struct rrset_parse* rrset, uint8_t** sname,
*sname = rrset->rr_first->ttl_data + sizeof(uint32_t) *sname = rrset->rr_first->ttl_data + sizeof(uint32_t)
+ sizeof(uint16_t); /* skip ttl, rdatalen */ + sizeof(uint16_t); /* skip ttl, rdatalen */
*snamelen = rrset->rr_first->size - sizeof(uint16_t); *snamelen = rrset->rr_first->size - sizeof(uint16_t);
if(rrset->rr_first->outside_packet) {
if(!dname_valid(*sname, *snamelen))
return 0;
return 1;
}
oldpos = sldns_buffer_position(pkt);
sldns_buffer_set_position(pkt, (size_t)(*sname - sldns_buffer_begin(pkt)));
dlen = pkt_dname_len(pkt);
sldns_buffer_set_position(pkt, oldpos);
if(dlen == 0)
return 0; /* parse fail on the rdata name */
*snamelen = dlen;
return 1; return 1;
} }
@ -215,7 +229,7 @@ synth_cname(uint8_t* qname, size_t qnamelen, struct rrset_parse* dname_rrset,
/* we already know that sname is a strict subdomain of DNAME owner */ /* we already know that sname is a strict subdomain of DNAME owner */
uint8_t* dtarg = NULL; uint8_t* dtarg = NULL;
size_t dtarglen; size_t dtarglen;
if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen)) if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen, pkt))
return 0; return 0;
if(qnamelen <= dname_rrset->dname_len) if(qnamelen <= dname_rrset->dname_len)
return 0; return 0;
@ -388,7 +402,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
/* check next cname */ /* check next cname */
uint8_t* t = NULL; uint8_t* t = NULL;
size_t tlen = 0; size_t tlen = 0;
if(!parse_get_cname_target(nx, &t, &tlen)) if(!parse_get_cname_target(nx, &t, &tlen, pkt))
return 0; return 0;
if(dname_pkt_compare(pkt, alias, t) == 0) { if(dname_pkt_compare(pkt, alias, t) == 0) {
/* it's OK and better capitalized */ /* it's OK and better capitalized */
@ -439,7 +453,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
size_t tlen = 0; size_t tlen = 0;
if(synth_cname(sname, snamelen, nx, alias, if(synth_cname(sname, snamelen, nx, alias,
&aliaslen, pkt) && &aliaslen, pkt) &&
parse_get_cname_target(rrset, &t, &tlen) && parse_get_cname_target(rrset, &t, &tlen, pkt) &&
dname_pkt_compare(pkt, alias, t) == 0) { dname_pkt_compare(pkt, alias, t) == 0) {
/* the synthesized CNAME equals the /* the synthesized CNAME equals the
* current CNAME. This CNAME is the * current CNAME. This CNAME is the
@ -460,7 +474,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
} }
/* move to next name in CNAME chain */ /* move to next name in CNAME chain */
if(!parse_get_cname_target(rrset, &sname, &snamelen)) if(!parse_get_cname_target(rrset, &sname, &snamelen, pkt))
return 0; return 0;
prev = rrset; prev = rrset;
rrset = rrset->rrset_all_next; rrset = rrset->rrset_all_next;

View File

@ -1142,7 +1142,7 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
log_rrset_key(VERB_ALGO, "found parent-side", akey); log_rrset_key(VERB_ALGO, "found parent-side", akey);
ns->done_pside4 = 1; ns->done_pside4 = 1;
/* a negative-cache-element has no addresses it adds */ /* a negative-cache-element has no addresses it adds */
if(!delegpt_add_rrset_A(dp, region, akey, 1)) if(!delegpt_add_rrset_A(dp, region, akey, 1, NULL))
log_err("malloc failure in lookup_parent_glue"); log_err("malloc failure in lookup_parent_glue");
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
} }
@ -1154,7 +1154,7 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
log_rrset_key(VERB_ALGO, "found parent-side", akey); log_rrset_key(VERB_ALGO, "found parent-side", akey);
ns->done_pside6 = 1; ns->done_pside6 = 1;
/* a negative-cache-element has no addresses it adds */ /* a negative-cache-element has no addresses it adds */
if(!delegpt_add_rrset_AAAA(dp, region, akey, 1)) if(!delegpt_add_rrset_AAAA(dp, region, akey, 1, NULL))
log_err("malloc failure in lookup_parent_glue"); log_err("malloc failure in lookup_parent_glue");
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
} }

View File

@ -72,6 +72,8 @@
/* in msec */ /* in msec */
int UNKNOWN_SERVER_NICENESS = 376; int UNKNOWN_SERVER_NICENESS = 376;
static void target_count_increase_nx(struct iter_qstate* iq, int num);
int int
iter_init(struct module_env* env, int id) iter_init(struct module_env* env, int id)
{ {
@ -150,6 +152,7 @@ iter_new(struct module_qstate* qstate, int id)
iq->sent_count = 0; iq->sent_count = 0;
iq->ratelimit_ok = 0; iq->ratelimit_ok = 0;
iq->target_count = NULL; iq->target_count = NULL;
iq->dp_target_count = 0;
iq->wait_priming_stub = 0; iq->wait_priming_stub = 0;
iq->refetch_glue = 0; iq->refetch_glue = 0;
iq->dnssec_expected = 0; iq->dnssec_expected = 0;
@ -221,6 +224,7 @@ final_state(struct iter_qstate* iq)
static void static void
error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
{ {
struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id]; struct iter_qstate* super_iq = (struct iter_qstate*)super->minfo[id];
if(qstate->qinfo.qtype == LDNS_RR_TYPE_A || if(qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
@ -246,7 +250,11 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
super->region, super_iq->dp)) super->region, super_iq->dp))
log_err("out of memory adding missing"); log_err("out of memory adding missing");
} }
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* mark as failed */ dpns->resolved = 1; /* mark as failed */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
(dpns->got6 == 2 || !ie->supports_ipv6))
target_count_increase_nx(super_iq, 1);
} }
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) { if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
/* prime failed to get delegation */ /* prime failed to get delegation */
@ -621,7 +629,7 @@ static void
target_count_create(struct iter_qstate* iq) target_count_create(struct iter_qstate* iq)
{ {
if(!iq->target_count) { if(!iq->target_count) {
iq->target_count = (int*)calloc(2, sizeof(int)); iq->target_count = (int*)calloc(3, sizeof(int));
/* if calloc fails we simply do not track this number */ /* if calloc fails we simply do not track this number */
if(iq->target_count) if(iq->target_count)
iq->target_count[0] = 1; iq->target_count[0] = 1;
@ -634,6 +642,15 @@ target_count_increase(struct iter_qstate* iq, int num)
target_count_create(iq); target_count_create(iq);
if(iq->target_count) if(iq->target_count)
iq->target_count[1] += num; iq->target_count[1] += num;
iq->dp_target_count++;
}
static void
target_count_increase_nx(struct iter_qstate* iq, int num)
{
target_count_create(iq);
if(iq->target_count)
iq->target_count[2] += num;
} }
/** /**
@ -656,13 +673,15 @@ target_count_increase(struct iter_qstate* iq, int num)
* @param subq_ret: if newly allocated, the subquerystate, or NULL if it does * @param subq_ret: if newly allocated, the subquerystate, or NULL if it does
* not need initialisation. * not need initialisation.
* @param v: if true, validation is done on the subquery. * @param v: if true, validation is done on the subquery.
* @param detached: true if this qstate should not attach to the subquery
* @return false on error (malloc). * @return false on error (malloc).
*/ */
static int static int
generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, struct module_qstate* qstate, int id, uint16_t qclass, struct module_qstate* qstate, int id,
struct iter_qstate* iq, enum iter_state initial_state, struct iter_qstate* iq, enum iter_state initial_state,
enum iter_state finalstate, struct module_qstate** subq_ret, int v) enum iter_state finalstate, struct module_qstate** subq_ret, int v,
int detached)
{ {
struct module_qstate* subq = NULL; struct module_qstate* subq = NULL;
struct iter_qstate* subiq = NULL; struct iter_qstate* subiq = NULL;
@ -689,11 +708,23 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
valrec = 1; valrec = 1;
} }
/* attach subquery, lookup existing or make a new one */ if(detached) {
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); struct mesh_state* sub = NULL;
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec, fptr_ok(fptr_whitelist_modenv_add_sub(
&subq)) { qstate->env->add_sub));
return 0; if(!(*qstate->env->add_sub)(qstate, &qinf,
qflags, prime, valrec, &subq, &sub)){
return 0;
}
}
else {
/* attach subquery, lookup existing or make a new one */
fptr_ok(fptr_whitelist_modenv_attach_sub(
qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime,
valrec, &subq)) {
return 0;
}
} }
*subq_ret = subq; *subq_ret = subq;
if(subq) { if(subq) {
@ -716,6 +747,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
subiq->target_count = iq->target_count; subiq->target_count = iq->target_count;
if(iq->target_count) if(iq->target_count)
iq->target_count[0] ++; /* extra reference */ iq->target_count[0] ++; /* extra reference */
subiq->dp_target_count = 0;
subiq->num_current_queries = 0; subiq->num_current_queries = 0;
subiq->depth = iq->depth+1; subiq->depth = iq->depth+1;
outbound_list_init(&subiq->outlist); outbound_list_init(&subiq->outlist);
@ -759,7 +791,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id,
* the normal INIT state logic (which would cause an infloop). */ * the normal INIT state logic (which would cause an infloop). */
if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS, if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS,
qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE,
&subq, 0)) { &subq, 0, 0)) {
verbose(VERB_ALGO, "could not prime root"); verbose(VERB_ALGO, "could not prime root");
return 0; return 0;
} }
@ -850,7 +882,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id,
* redundant INIT state processing. */ * redundant INIT state processing. */
if(!generate_sub_request(stub_dp->name, stub_dp->namelen, if(!generate_sub_request(stub_dp->name, stub_dp->namelen,
LDNS_RR_TYPE_NS, qclass, qstate, id, iq, LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0)) { QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) {
verbose(VERB_ALGO, "could not prime stub"); verbose(VERB_ALGO, "could not prime stub");
errinf(qstate, "could not generate lookup for stub prime"); errinf(qstate, "could not generate lookup for stub prime");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@ -1025,7 +1057,7 @@ generate_a_aaaa_check(struct module_qstate* qstate, struct iter_qstate* iq,
if(!generate_sub_request(s->rk.dname, s->rk.dname_len, if(!generate_sub_request(s->rk.dname, s->rk.dname_len,
ntohs(s->rk.type), ntohs(s->rk.rrset_class), ntohs(s->rk.type), ntohs(s->rk.rrset_class),
qstate, id, iq, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
verbose(VERB_ALGO, "could not generate addr check"); verbose(VERB_ALGO, "could not generate addr check");
return; return;
} }
@ -1069,7 +1101,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); iq->dp->name, LDNS_RR_TYPE_NS, iq->qchase.qclass);
if(!generate_sub_request(iq->dp->name, iq->dp->namelen, if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq, LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
verbose(VERB_ALGO, "could not generate ns check"); verbose(VERB_ALGO, "could not generate ns check");
return; return;
} }
@ -1126,7 +1158,7 @@ generate_dnskey_prefetch(struct module_qstate* qstate,
iq->dp->name, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass); iq->dp->name, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass);
if(!generate_sub_request(iq->dp->name, iq->dp->namelen, if(!generate_sub_request(iq->dp->name, iq->dp->namelen,
LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass, qstate, id, iq, LDNS_RR_TYPE_DNSKEY, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) { INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) {
/* we'll be slower, but it'll work */ /* we'll be slower, but it'll work */
verbose(VERB_ALGO, "could not generate dnskey prefetch"); verbose(VERB_ALGO, "could not generate dnskey prefetch");
return; return;
@ -1315,6 +1347,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
iq->refetch_glue = 0; iq->refetch_glue = 0;
iq->query_restart_count++; iq->query_restart_count++;
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region); sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
if(qstate->env->cfg->qname_minimisation) if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE; iq->minimisation_state = INIT_MINIMISE_STATE;
@ -1693,7 +1726,7 @@ generate_parentside_target_query(struct module_qstate* qstate,
{ {
struct module_qstate* subq; struct module_qstate* subq;
if(!generate_sub_request(name, namelen, qtype, qclass, qstate, if(!generate_sub_request(name, namelen, qtype, qclass, qstate,
id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0))
return 0; return 0;
if(subq) { if(subq) {
struct iter_qstate* subiq = struct iter_qstate* subiq =
@ -1744,7 +1777,7 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
{ {
struct module_qstate* subq; struct module_qstate* subq;
if(!generate_sub_request(name, namelen, qtype, qclass, qstate, if(!generate_sub_request(name, namelen, qtype, qclass, qstate,
id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) id, iq, INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0))
return 0; return 0;
log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass); log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass);
return 1; return 1;
@ -1783,6 +1816,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
"number of glue fetches %d", s, iq->target_count[1]); "number of glue fetches %d", s, iq->target_count[1]);
return 0; return 0;
} }
if(iq->dp_target_count > MAX_DP_TARGET_COUNT) {
char s[LDNS_MAX_DOMAINLEN+1];
dname_str(qstate->qinfo.qname, s);
verbose(VERB_QUERY, "request %s has exceeded the maximum "
"number of glue fetches %d to a single delegation point",
s, iq->dp_target_count);
return 0;
}
iter_mark_cycle_targets(qstate, iq->dp); iter_mark_cycle_targets(qstate, iq->dp);
missing = (int)delegpt_count_missing_targets(iq->dp); missing = (int)delegpt_count_missing_targets(iq->dp);
@ -1896,7 +1937,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
for(a = p->target_list; a; a=a->next_target) { for(a = p->target_list; a; a=a->next_target) {
(void)delegpt_add_addr(iq->dp, qstate->region, (void)delegpt_add_addr(iq->dp, qstate->region,
&a->addr, a->addrlen, a->bogus, &a->addr, a->addrlen, a->bogus,
a->lame, a->tls_auth_name); a->lame, a->tls_auth_name, NULL);
} }
} }
iq->dp->has_parent_side_NS = 1; iq->dp->has_parent_side_NS = 1;
@ -1913,6 +1954,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
iq->refetch_glue = 1; iq->refetch_glue = 1;
iq->query_restart_count++; iq->query_restart_count++;
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
if(qstate->env->cfg->qname_minimisation) if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE; iq->minimisation_state = INIT_MINIMISE_STATE;
return next_state(iq, INIT_REQUEST_STATE); return next_state(iq, INIT_REQUEST_STATE);
@ -2078,7 +2120,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
iq->dsns_point, LDNS_RR_TYPE_NS, iq->qchase.qclass); iq->dsns_point, LDNS_RR_TYPE_NS, iq->qchase.qclass);
if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len, if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len,
LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq, LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) { INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0, 0)) {
errinf_dname(qstate, "for DS query parent-child nameserver search, could not generate NS lookup for", iq->dsns_point); errinf_dname(qstate, "for DS query parent-child nameserver search, could not generate NS lookup for", iq->dsns_point);
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
} }
@ -2136,6 +2178,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
errinf(qstate, "exceeded the maximum number of sends"); errinf(qstate, "exceeded the maximum number of sends");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL); return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
} }
if(iq->target_count && iq->target_count[2] > MAX_TARGET_NX) {
verbose(VERB_QUERY, "request has exceeded the maximum "
" number of nxdomain nameserver lookups with %d",
iq->target_count[2]);
errinf(qstate, "exceeded the maximum nameserver nxdomains");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* Make sure we have a delegation point, otherwise priming failed /* Make sure we have a delegation point, otherwise priming failed
* or another failure occurred */ * or another failure occurred */
@ -2240,12 +2289,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qinfo_out.qtype, iq->qinfo_out.qclass, iq->qinfo_out.qtype, iq->qinfo_out.qclass,
qstate->query_flags, qstate->region, qstate->query_flags, qstate->region,
qstate->env->scratch, 0); qstate->env->scratch, 0);
if(msg && msg->rep->an_numrrsets == 0 if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
&& FLAGS_GET_RCODE(msg->rep->flags) ==
LDNS_RCODE_NOERROR) LDNS_RCODE_NOERROR)
/* no need to send query if it is already /* no need to send query if it is already
* cached as NOERROR/NODATA */ * cached as NOERROR */
return 1; return 1;
if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
LDNS_RCODE_NXDOMAIN &&
qstate->env->need_to_validate &&
qstate->env->cfg->harden_below_nxdomain) {
if(msg->rep->security == sec_status_secure) {
iq->response = msg;
return final_state(iq);
}
if(msg->rep->security == sec_status_unchecked) {
struct module_qstate* subq = NULL;
if(!generate_sub_request(
iq->qinfo_out.qname,
iq->qinfo_out.qname_len,
iq->qinfo_out.qtype,
iq->qinfo_out.qclass,
qstate, id, iq,
INIT_REQUEST_STATE,
FINISHED_STATE, &subq, 1, 1))
verbose(VERB_ALGO,
"could not validate NXDOMAIN "
"response");
}
}
if(msg && FLAGS_GET_RCODE(msg->rep->flags) ==
LDNS_RCODE_NXDOMAIN) {
/* return and add a label in the next
* minimisation iteration.
*/
return 1;
}
} }
} }
if(iq->minimisation_state == SKIP_MINIMISE_STATE) { if(iq->minimisation_state == SKIP_MINIMISE_STATE) {
@ -2321,6 +2399,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
* generated query will immediately be discarded due to depth and * generated query will immediately be discarded due to depth and
* that servfail is cached, which is not good as opportunism goes. */ * that servfail is cached, which is not good as opportunism goes. */
if(iq->depth < ie->max_dependency_depth if(iq->depth < ie->max_dependency_depth
&& iq->num_target_queries == 0
&& (!iq->target_count || iq->target_count[2]==0)
&& iq->sent_count < TARGET_FETCH_STOP) { && iq->sent_count < TARGET_FETCH_STOP) {
tf_policy = ie->target_fetch_policy[iq->depth]; tf_policy = ie->target_fetch_policy[iq->depth];
} }
@ -2366,6 +2446,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->num_current_queries++; /* RespState decrements it*/ iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */ iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE; iq->state = QUERY_RESP_STATE;
return 1; return 1;
} }
@ -2453,6 +2534,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->num_current_queries++; /* RespState decrements it*/ iq->num_current_queries++; /* RespState decrements it*/
iq->referral_count++; /* make sure we don't loop */ iq->referral_count++; /* make sure we don't loop */
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
iq->state = QUERY_RESP_STATE; iq->state = QUERY_RESP_STATE;
return 1; return 1;
} }
@ -2747,7 +2829,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* Make subrequest to validate intermediate /* Make subrequest to validate intermediate
* NXDOMAIN if harden-below-nxdomain is * NXDOMAIN if harden-below-nxdomain is
* enabled. */ * enabled. */
if(qstate->env->cfg->harden_below_nxdomain) { if(qstate->env->cfg->harden_below_nxdomain &&
qstate->env->need_to_validate) {
struct module_qstate* subq = NULL; struct module_qstate* subq = NULL;
log_query_info(VERB_QUERY, log_query_info(VERB_QUERY,
"schedule NXDOMAIN validation:", "schedule NXDOMAIN validation:",
@ -2759,16 +2842,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->response->qinfo.qclass, iq->response->qinfo.qclass,
qstate, id, iq, qstate, id, iq,
INIT_REQUEST_STATE, INIT_REQUEST_STATE,
FINISHED_STATE, &subq, 1)) FINISHED_STATE, &subq, 1, 1))
verbose(VERB_ALGO, verbose(VERB_ALGO,
"could not validate NXDOMAIN " "could not validate NXDOMAIN "
"response"); "response");
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
fptr_ok(fptr_whitelist_modenv_detach_subs(
qstate->env->detach_subs));
(*qstate->env->detach_subs)(qstate);
iq->num_target_queries = 0;
} }
} }
return next_state(iq, QUERYTARGETS_STATE); return next_state(iq, QUERYTARGETS_STATE);
@ -2852,6 +2929,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* Count this as a referral. */ /* Count this as a referral. */
iq->referral_count++; iq->referral_count++;
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
/* see if the next dp is a trust anchor, or a DS was sent /* see if the next dp is a trust anchor, or a DS was sent
* along, indicating dnssec is expected for next zone */ * along, indicating dnssec is expected for next zone */
iq->dnssec_expected = iter_indicates_dnssec(qstate->env, iq->dnssec_expected = iter_indicates_dnssec(qstate->env,
@ -2928,6 +3006,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dsns_point = NULL; iq->dsns_point = NULL;
iq->auth_zone_response = 0; iq->auth_zone_response = 0;
iq->sent_count = 0; iq->sent_count = 0;
iq->dp_target_count = 0;
if(iq->minimisation_state != MINIMISE_STATE) if(iq->minimisation_state != MINIMISE_STATE)
/* Only count as query restart when it is not an extra /* Only count as query restart when it is not an extra
* query as result of qname minimisation. */ * query as result of qname minimisation. */
@ -3120,7 +3199,7 @@ processPrimeResponse(struct module_qstate* qstate, int id)
if(!generate_sub_request(qstate->qinfo.qname, if(!generate_sub_request(qstate->qinfo.qname,
qstate->qinfo.qname_len, qstate->qinfo.qtype, qstate->qinfo.qname_len, qstate->qinfo.qtype,
qstate->qinfo.qclass, qstate, id, iq, qstate->qinfo.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1)) { INIT_REQUEST_STATE, FINISHED_STATE, &subq, 1, 0)) {
verbose(VERB_ALGO, "could not generate prime check"); verbose(VERB_ALGO, "could not generate prime check");
} }
generate_a_aaaa_check(qstate, iq, id); generate_a_aaaa_check(qstate, iq, id);
@ -3148,6 +3227,7 @@ static void
processTargetResponse(struct module_qstate* qstate, int id, processTargetResponse(struct module_qstate* qstate, int id,
struct module_qstate* forq) struct module_qstate* forq)
{ {
struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id]; struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id]; struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
struct ub_packed_rrset_key* rrset; struct ub_packed_rrset_key* rrset;
@ -3185,7 +3265,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
log_rrset_key(VERB_ALGO, "add parentside glue to dp", log_rrset_key(VERB_ALGO, "add parentside glue to dp",
iq->pside_glue); iq->pside_glue);
if(!delegpt_add_rrset(foriq->dp, forq->region, if(!delegpt_add_rrset(foriq->dp, forq->region,
iq->pside_glue, 1)) iq->pside_glue, 1, NULL))
log_err("out of memory adding pside glue"); log_err("out of memory adding pside glue");
} }
@ -3196,6 +3276,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
* response type was ANSWER. */ * response type was ANSWER. */
rrset = reply_find_answer_rrset(&iq->qchase, qstate->return_msg->rep); rrset = reply_find_answer_rrset(&iq->qchase, qstate->return_msg->rep);
if(rrset) { if(rrset) {
int additions = 0;
/* if CNAMEs have been followed - add new NS to delegpt. */ /* if CNAMEs have been followed - add new NS to delegpt. */
/* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */ /* BTW. RFC 1918 says NS should not have got CNAMEs. Robust. */
if(!delegpt_find_ns(foriq->dp, rrset->rk.dname, if(!delegpt_find_ns(foriq->dp, rrset->rk.dname,
@ -3207,13 +3288,23 @@ processTargetResponse(struct module_qstate* qstate, int id,
} }
/* if dpns->lame then set the address(es) lame too */ /* if dpns->lame then set the address(es) lame too */
if(!delegpt_add_rrset(foriq->dp, forq->region, rrset, if(!delegpt_add_rrset(foriq->dp, forq->region, rrset,
dpns->lame)) dpns->lame, &additions))
log_err("out of memory adding targets"); log_err("out of memory adding targets");
if(!additions) {
/* no new addresses, increase the nxns counter, like
* this could be a list of wildcards with no new
* addresses */
target_count_increase_nx(foriq, 1);
}
verbose(VERB_ALGO, "added target response"); verbose(VERB_ALGO, "added target response");
delegpt_log(VERB_ALGO, foriq->dp); delegpt_log(VERB_ALGO, foriq->dp);
} else { } else {
verbose(VERB_ALGO, "iterator TargetResponse failed"); verbose(VERB_ALGO, "iterator TargetResponse failed");
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* fail the target */ dpns->resolved = 1; /* fail the target */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
(dpns->got6 == 2 || !ie->supports_ipv6))
target_count_increase_nx(foriq, 1);
} }
} }
@ -3387,7 +3478,7 @@ processCollectClass(struct module_qstate* qstate, int id)
qstate->qinfo.qname_len, qstate->qinfo.qtype, qstate->qinfo.qname_len, qstate->qinfo.qtype,
c, qstate, id, iq, INIT_REQUEST_STATE, c, qstate, id, iq, INIT_REQUEST_STATE,
FINISHED_STATE, &subq, FINISHED_STATE, &subq,
(int)!(qstate->query_flags&BIT_CD))) { (int)!(qstate->query_flags&BIT_CD), 0)) {
errinf(qstate, "could not generate class ANY" errinf(qstate, "could not generate class ANY"
" lookup query"); " lookup query");
return error_response(qstate, id, return error_response(qstate, id,

View File

@ -55,6 +55,11 @@ struct rbtree_type;
/** max number of targets spawned for a query and its subqueries */ /** max number of targets spawned for a query and its subqueries */
#define MAX_TARGET_COUNT 64 #define MAX_TARGET_COUNT 64
/** max number of target lookups per qstate, per delegation point */
#define MAX_DP_TARGET_COUNT 16
/** max number of nxdomains allowed for target lookups for a query and
* its subqueries */
#define MAX_TARGET_NX 5
/** max number of query restarts. Determines max number of CNAME chain. */ /** max number of query restarts. Determines max number of CNAME chain. */
#define MAX_RESTART_COUNT 8 #define MAX_RESTART_COUNT 8
/** max number of referrals. Makes sure resolver does not run away */ /** max number of referrals. Makes sure resolver does not run away */
@ -305,9 +310,14 @@ struct iter_qstate {
int sent_count; int sent_count;
/** number of target queries spawned in [1], for this query and its /** number of target queries spawned in [1], for this query and its
* subqueries, the malloced-array is shared, [0] refcount. */ * subqueries, the malloced-array is shared, [0] refcount.
* in [2] the number of nxdomains is counted. */
int* target_count; int* target_count;
/** number of target lookups per delegation point. Reset to 0 after
* receiving referral answer. Not shared with subqueries. */
int dp_target_count;
/** if true, already tested for ratelimiting and passed the test */ /** if true, already tested for ratelimiting and passed the test */
int ratelimit_ok; int ratelimit_ok;

View File

@ -55,6 +55,7 @@
int int
context_finalize(struct ub_ctx* ctx) context_finalize(struct ub_ctx* ctx)
{ {
int is_rpz = 0;
struct config_file* cfg = ctx->env->cfg; struct config_file* cfg = ctx->env->cfg;
verbosity = cfg->verbosity; verbosity = cfg->verbosity;
if(ctx_logfile_overridden && !ctx->logfile_override) { if(ctx_logfile_overridden && !ctx->logfile_override) {
@ -76,7 +77,7 @@ context_finalize(struct ub_ctx* ctx)
return UB_NOMEM; return UB_NOMEM;
if(!local_zones_apply_cfg(ctx->local_zones, cfg)) if(!local_zones_apply_cfg(ctx->local_zones, cfg))
return UB_INITFAIL; return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1)) if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz))
return UB_INITFAIL; return UB_INITFAIL;
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
cfg->msg_cache_slabs)) { cfg->msg_cache_slabs)) {

View File

@ -561,7 +561,6 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
if(!qinfo->qname) { if(!qinfo->qname) {
return 0; return 0;
} }
qinfo->local_alias = NULL;
edns->edns_present = 1; edns->edns_present = 1;
edns->ext_rcode = 0; edns->ext_rcode = 0;
edns->edns_version = 0; edns->edns_version = 0;

View File

@ -204,8 +204,9 @@ struct ub_result {
char* why_bogus; char* why_bogus;
/** /**
* If the query or one of its subqueries was ratelimited. Useful if * If the query or one of its subqueries was ratelimited. Useful if
* ratelimiting is enabled and answer is SERVFAIL. * ratelimiting is enabled and answer to the client is SERVFAIL as a
* result.
*/ */
int was_ratelimited; int was_ratelimited;
@ -654,6 +655,8 @@ struct ub_shm_stat_info {
#define UB_STATS_OPCODE_NUM 16 #define UB_STATS_OPCODE_NUM 16
/** number of histogram buckets */ /** number of histogram buckets */
#define UB_STATS_BUCKET_NUM 40 #define UB_STATS_BUCKET_NUM 40
/** number of RPZ actions */
#define UB_STATS_RPZ_ACTION_NUM 10
/** per worker statistics. */ /** per worker statistics. */
struct ub_server_stats { struct ub_server_stats {
@ -733,8 +736,8 @@ struct ub_server_stats {
long long unwanted_queries; long long unwanted_queries;
/** usage of tcp accept list */ /** usage of tcp accept list */
long long tcp_accept_usage; long long tcp_accept_usage;
/** answers served from expired cache */ /** expired answers served from cache */
long long zero_ttl_responses; long long ans_expired;
/** histogram data exported to array /** histogram data exported to array
* if the array is the same size, no data is lost, and * if the array is the same size, no data is lost, and
* if all histograms are same size (is so by default) then * if all histograms are same size (is so by default) then
@ -785,6 +788,8 @@ struct ub_server_stats {
long long mem_stream_wait; long long mem_stream_wait;
/** number of TLS connection resume */ /** number of TLS connection resume */
long long qtls_resume; long long qtls_resume;
/** RPZ action stats */
long long rpz_action[UB_STATS_RPZ_ACTION_NUM];
}; };
/** /**

View File

@ -12,6 +12,7 @@
#include "config.h" #include "config.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "services/authzone.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "sldns/str2wire.h" #include "sldns/str2wire.h"
#include "util/config_file.h" #include "util/config_file.h"
@ -25,30 +26,6 @@
#include "services/view.h" #include "services/view.h"
#include "sldns/rrdef.h" #include "sldns/rrdef.h"
/**
* Conceptual set of IP addresses for response AAAA or A records that should
* trigger special actions.
*/
struct respip_set {
struct regional* region;
struct rbtree_type ip_tree;
char* const* tagname; /* shallow copy of tag names, for logging */
int num_tags; /* number of tagname entries */
};
/** An address span with response control information */
struct resp_addr {
/** node in address tree */
struct addr_tree_node node;
/** tag bitlist */
uint8_t* taglist;
/** length of the taglist (in bytes) */
size_t taglen;
/** action for this address span */
enum respip_action action;
/** "local data" for this node */
struct ub_packed_rrset_key* data;
};
/** Subset of resp_addr.node, used for inform-variant logging */ /** Subset of resp_addr.node, used for inform-variant logging */
struct respip_addr_info { struct respip_addr_info {
@ -88,14 +65,28 @@ respip_set_create(void)
return NULL; return NULL;
} }
addr_tree_init(&set->ip_tree); addr_tree_init(&set->ip_tree);
lock_rw_init(&set->lock);
return set; return set;
} }
/** helper traverse to delete resp_addr nodes */
static void
resp_addr_del(rbnode_type* n, void* ATTR_UNUSED(arg))
{
struct resp_addr* r = (struct resp_addr*)n->key;
lock_rw_destroy(&r->lock);
#ifdef THREADS_DISABLED
(void)r;
#endif
}
void void
respip_set_delete(struct respip_set* set) respip_set_delete(struct respip_set* set)
{ {
if(!set) if(!set)
return; return;
lock_rw_destroy(&set->lock);
traverse_postorder(&set->ip_tree, resp_addr_del, NULL);
regional_destroy(set->region); regional_destroy(set->region);
free(set); free(set);
} }
@ -108,12 +99,49 @@ respip_set_get_tree(struct respip_set* set)
return &set->ip_tree; return &set->ip_tree;
} }
struct resp_addr*
respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, int create, const char* ipstr)
{
struct resp_addr* node;
node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net);
if(!node && create) {
node = regional_alloc_zero(set->region, sizeof(*node));
if(!node) {
log_err("out of memory");
return NULL;
}
lock_rw_init(&node->lock);
node->action = respip_none;
if(!addr_tree_insert(&set->ip_tree, &node->node, addr,
addrlen, net)) {
/* We know we didn't find it, so this should be
* impossible. */
log_warn("unexpected: duplicate address: %s", ipstr);
}
}
return node;
}
void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node)
{
struct resp_addr* prev;
prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node);
lock_rw_destroy(&node->lock);
rbtree_delete(&set->ip_tree, node);
/* no free'ing, all allocated in region */
if(!prev)
addr_tree_init_parents((rbtree_type*)set);
else
addr_tree_init_parents_node(&prev->node);
}
/** returns the node in the address tree for the specified netblock string; /** returns the node in the address tree for the specified netblock string;
* non-existent node will be created if 'create' is true */ * non-existent node will be created if 'create' is true */
static struct resp_addr* static struct resp_addr*
respip_find_or_create(struct respip_set* set, const char* ipstr, int create) respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
{ {
struct resp_addr* node;
struct sockaddr_storage addr; struct sockaddr_storage addr;
int net; int net;
socklen_t addrlen; socklen_t addrlen;
@ -122,22 +150,8 @@ respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
log_err("cannot parse netblock: '%s'", ipstr); log_err("cannot parse netblock: '%s'", ipstr);
return NULL; return NULL;
} }
node = (struct resp_addr*)addr_tree_find(&set->ip_tree, &addr, addrlen, net); return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create,
if(!node && create) { ipstr);
node = regional_alloc_zero(set->region, sizeof(*node));
if(!node) {
log_err("out of memory");
return NULL;
}
node->action = respip_none;
if(!addr_tree_insert(&set->ip_tree, &node->node, &addr,
addrlen, net)) {
/* We know we didn't find it, so this should be
* impossible. */
log_warn("unexpected: duplicate address: %s", ipstr);
}
}
return node;
} }
static int static int
@ -191,6 +205,10 @@ respip_action_cfg(struct respip_set* set, const char* ipstr,
action = respip_always_refuse; action = respip_always_refuse;
else if(strcmp(actnstr, "always_nxdomain") == 0) else if(strcmp(actnstr, "always_nxdomain") == 0)
action = respip_always_nxdomain; action = respip_always_nxdomain;
else if(strcmp(actnstr, "always_nodata") == 0)
action = respip_always_nodata;
else if(strcmp(actnstr, "always_deny") == 0)
action = respip_always_deny;
else { else {
log_err("unknown response-ip action %s", actnstr); log_err("unknown response-ip action %s", actnstr);
return 0; return 0;
@ -232,8 +250,43 @@ new_rrset(struct regional* region, uint16_t rrtype, uint16_t rrclass)
} }
/** enter local data as resource records into a response-ip node */ /** enter local data as resource records into a response-ip node */
static int
int
respip_enter_rr(struct regional* region, struct resp_addr* raddr, respip_enter_rr(struct regional* region, struct resp_addr* raddr,
uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
size_t rdata_len, const char* rrstr, const char* netblockstr)
{
struct packed_rrset_data* pd;
struct sockaddr* sa;
sa = (struct sockaddr*)&raddr->node.addr;
if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) {
log_err("CNAME response-ip data (%s) can not co-exist with other "
"response-ip data for netblock %s", rrstr, netblockstr);
return 0;
} else if (raddr->data &&
raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
log_err("response-ip data (%s) can not be added; CNAME response-ip "
"data already in place for netblock %s", rrstr, netblockstr);
return 0;
} else if((rrtype != LDNS_RR_TYPE_CNAME) &&
((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
(sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
log_err("response-ip data %s record type does not correspond "
"to netblock %s address family", rrstr, netblockstr);
return 0;
}
if(!raddr->data) {
raddr->data = new_rrset(region, rrtype, rrclass);
if(!raddr->data)
return 0;
}
pd = raddr->data->entry.data;
return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
}
static int
respip_enter_rrstr(struct regional* region, struct resp_addr* raddr,
const char* rrstr, const char* netblock) const char* rrstr, const char* netblock)
{ {
uint8_t* nm; uint8_t* nm;
@ -244,8 +297,6 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
size_t rdata_len = 0; size_t rdata_len = 0;
char buf[65536]; char buf[65536];
char bufshort[64]; char bufshort[64];
struct packed_rrset_data* pd;
struct sockaddr* sa;
int ret; int ret;
if(raddr->action != respip_redirect if(raddr->action != respip_redirect
&& raddr->action != respip_inform_redirect) { && raddr->action != respip_inform_redirect) {
@ -265,31 +316,8 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
return 0; return 0;
} }
free(nm); free(nm);
sa = (struct sockaddr*)&raddr->node.addr; return respip_enter_rr(region, raddr, rrtype, rrclass, ttl, rdata,
if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) { rdata_len, rrstr, netblock);
log_err("CNAME response-ip data (%s) can not co-exist with other "
"response-ip data for netblock %s", rrstr, netblock);
return 0;
} else if (raddr->data &&
raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
log_err("response-ip data (%s) can not be added; CNAME response-ip "
"data already in place for netblock %s", rrstr, netblock);
return 0;
} else if((rrtype != LDNS_RR_TYPE_CNAME) &&
((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
(sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
log_err("response-ip data %s record type does not correspond "
"to netblock %s address family", rrstr, netblock);
return 0;
}
if(!raddr->data) {
raddr->data = new_rrset(region, rrtype, rrclass);
if(!raddr->data)
return 0;
}
pd = raddr->data->entry.data;
return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
} }
static int static int
@ -303,7 +331,7 @@ respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr)
"response-ip node for %s not found", rrstr, ipstr); "response-ip node for %s not found", rrstr, ipstr);
return 0; return 0;
} }
return respip_enter_rr(set->region, node, rrstr, ipstr); return respip_enter_rrstr(set->region, node, rrstr, ipstr);
} }
static int static int
@ -564,9 +592,10 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
* rep->rrsets for the RRset that contains the matching IP address record * rep->rrsets for the RRset that contains the matching IP address record
* (the index is normally 0, but can be larger than that if this is a CNAME * (the index is normally 0, but can be larger than that if this is a CNAME
* chain or type-ANY response). * chain or type-ANY response).
* Returns resp_addr holding read lock.
*/ */
static const struct resp_addr* static struct resp_addr*
respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree, respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
size_t* rrset_id) size_t* rrset_id)
{ {
size_t i; size_t i;
@ -574,6 +603,7 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
struct sockaddr_storage ss; struct sockaddr_storage ss;
socklen_t addrlen; socklen_t addrlen;
lock_rw_rdlock(&rs->lock);
for(i=0; i<rep->an_numrrsets; i++) { for(i=0; i<rep->an_numrrsets; i++) {
size_t j; size_t j;
const struct packed_rrset_data* rd; const struct packed_rrset_data* rd;
@ -585,15 +615,17 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
for(j = 0; j < rd->count; j++) { for(j = 0; j < rd->count; j++) {
if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen)) if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen))
continue; continue;
ra = (struct resp_addr*)addr_tree_lookup(iptree, &ss, ra = (struct resp_addr*)addr_tree_lookup(&rs->ip_tree,
addrlen); &ss, addrlen);
if(ra) { if(ra) {
*rrset_id = i; *rrset_id = i;
lock_rw_rdlock(&ra->lock);
lock_rw_unlock(&rs->lock);
return ra; return ra;
} }
} }
} }
lock_rw_unlock(&rs->lock);
return NULL; return NULL;
} }
@ -642,8 +674,8 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region,
* Note that this function distinguishes error conditions from "success but * Note that this function distinguishes error conditions from "success but
* not overridden". This is because we want to avoid accidentally applying * not overridden". This is because we want to avoid accidentally applying
* the "no data" action in case of error. * the "no data" action in case of error.
* @param raddr: address span that requires an action
* @param action: action to apply * @param action: action to apply
* @param data: RRset to use for override
* @param qtype: original query type * @param qtype: original query type
* @param rep: original reply message * @param rep: original reply message
* @param rrset_id: the rrset ID in 'rep' to which the action should apply * @param rrset_id: the rrset ID in 'rep' to which the action should apply
@ -658,14 +690,15 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region,
* @return 1 if overridden, 0 if not overridden, -1 on error. * @return 1 if overridden, 0 if not overridden, -1 on error.
*/ */
static int static int
respip_data_answer(const struct resp_addr* raddr, enum respip_action action, respip_data_answer(enum respip_action action,
struct ub_packed_rrset_key* data,
uint16_t qtype, const struct reply_info* rep, uint16_t qtype, const struct reply_info* rep,
size_t rrset_id, struct reply_info** new_repp, int tag, size_t rrset_id, struct reply_info** new_repp, int tag,
struct config_strlist** tag_datas, size_t tag_datas_size, struct config_strlist** tag_datas, size_t tag_datas_size,
char* const* tagname, int num_tags, char* const* tagname, int num_tags,
struct ub_packed_rrset_key** redirect_rrsetp, struct regional* region) struct ub_packed_rrset_key** redirect_rrsetp, struct regional* region)
{ {
struct ub_packed_rrset_key* rp = raddr->data; struct ub_packed_rrset_key* rp = data;
struct reply_info* new_rep; struct reply_info* new_rep;
*redirect_rrsetp = NULL; *redirect_rrsetp = NULL;
@ -703,7 +736,7 @@ respip_data_answer(const struct resp_addr* raddr, enum respip_action action,
* to replace the rrset's dname. Note that, unlike local data, we * to replace the rrset's dname. Note that, unlike local data, we
* rename the dname for other actions than redirect. This is because * rename the dname for other actions than redirect. This is because
* response-ip-data isn't associated to any specific name. */ * response-ip-data isn't associated to any specific name. */
if(rp == raddr->data) { if(rp == data) {
rp = copy_rrset(rp, region); rp = copy_rrset(rp, region);
if(!rp) if(!rp)
return -1; return -1;
@ -761,6 +794,7 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
return 1; return 1;
} else if(action == respip_static || action == respip_redirect || } else if(action == respip_static || action == respip_redirect ||
action == respip_always_nxdomain || action == respip_always_nxdomain ||
action == respip_always_nodata ||
action == respip_inform_redirect) { action == respip_inform_redirect) {
/* Since we don't know about other types of the owner name, /* Since we don't know about other types of the owner name,
* we generally return NOERROR/NODATA unless an NXDOMAIN action * we generally return NOERROR/NODATA unless an NXDOMAIN action
@ -794,16 +828,22 @@ populate_action_info(struct respip_action_info* actinfo,
enum respip_action action, const struct resp_addr* raddr, enum respip_action action, const struct resp_addr* raddr,
const struct ub_packed_rrset_key* ATTR_UNUSED(rrset), const struct ub_packed_rrset_key* ATTR_UNUSED(rrset),
int ATTR_UNUSED(tag), const struct respip_set* ATTR_UNUSED(ipset), int ATTR_UNUSED(tag), const struct respip_set* ATTR_UNUSED(ipset),
int ATTR_UNUSED(action_only), struct regional* region) int ATTR_UNUSED(action_only), struct regional* region, int rpz_used,
int rpz_log, char* log_name, int rpz_cname_override)
{ {
if(action == respip_none || !raddr) if(action == respip_none || !raddr)
return 1; return 1;
actinfo->action = action; actinfo->action = action;
actinfo->rpz_used = rpz_used;
actinfo->rpz_log = rpz_log;
actinfo->log_name = log_name;
actinfo->rpz_cname_override = rpz_cname_override;
/* for inform variants, make a copy of the matched address block for /* for inform variants, make a copy of the matched address block for
* later logging. We make a copy to proactively avoid disruption if * later logging. We make a copy to proactively avoid disruption if
* and when we allow a dynamic update to the respip tree. */ * and when we allow a dynamic update to the respip tree. */
if(action == respip_inform || action == respip_inform_deny) { if(action == respip_inform || action == respip_inform_deny ||
rpz_used) {
struct respip_addr_info* a = struct respip_addr_info* a =
regional_alloc_zero(region, sizeof(*a)); regional_alloc_zero(region, sizeof(*a));
if(!a) { if(!a) {
@ -819,12 +859,39 @@ populate_action_info(struct respip_action_info* actinfo,
return 1; return 1;
} }
static int
respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
enum respip_action* action,
struct ub_packed_rrset_key** data, int* rpz_log, char** log_name,
int* rpz_cname_override, struct regional* region, int* is_rpz)
{
if(r->action_override == RPZ_DISABLED_ACTION) {
*is_rpz = 0;
return 1;
}
else if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
*action = raddr->action;
else
*action = rpz_action_to_respip_action(r->action_override);
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION &&
r->cname_override) {
*data = r->cname_override;
*rpz_cname_override = 1;
}
*rpz_log = r->log;
if(r->log_name)
if(!(*log_name = regional_strdup(region, r->log_name)))
return 0;
*is_rpz = 1;
return 1;
}
int int
respip_rewrite_reply(const struct query_info* qinfo, respip_rewrite_reply(const struct query_info* qinfo,
const struct respip_client_info* cinfo, const struct reply_info* rep, const struct respip_client_info* cinfo, const struct reply_info* rep,
struct reply_info** new_repp, struct respip_action_info* actinfo, struct reply_info** new_repp, struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset, int search_only, struct ub_packed_rrset_key** alias_rrset, int search_only,
struct regional* region) struct regional* region, struct auth_zones* az)
{ {
const uint8_t* ctaglist; const uint8_t* ctaglist;
size_t ctaglen; size_t ctaglen;
@ -837,9 +904,15 @@ respip_rewrite_reply(const struct query_info* qinfo,
size_t rrset_id = 0; size_t rrset_id = 0;
enum respip_action action = respip_none; enum respip_action action = respip_none;
int tag = -1; int tag = -1;
const struct resp_addr* raddr = NULL; struct resp_addr* raddr = NULL;
int ret = 1; int ret = 1;
struct ub_packed_rrset_key* redirect_rrset = NULL; struct ub_packed_rrset_key* redirect_rrset = NULL;
struct rpz* r;
struct ub_packed_rrset_key* data = NULL;
int rpz_used = 0;
int rpz_log = 0;
int rpz_cname_override = 0;
char* log_name = NULL;
if(!cinfo) if(!cinfo)
goto done; goto done;
@ -852,6 +925,8 @@ respip_rewrite_reply(const struct query_info* qinfo,
view = cinfo->view; view = cinfo->view;
ipset = cinfo->respip_set; ipset = cinfo->respip_set;
log_assert(ipset);
/** Try to use response-ip config from the view first; use /** Try to use response-ip config from the view first; use
* global response-ip config if we don't have the view or we don't * global response-ip config if we don't have the view or we don't
* have the matching per-view config (and the view allows the use * have the matching per-view config (and the view allows the use
@ -866,7 +941,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
lock_rw_rdlock(&view->lock); lock_rw_rdlock(&view->lock);
if(view->respip_set) { if(view->respip_set) {
if((raddr = respip_addr_lookup(rep, if((raddr = respip_addr_lookup(rep,
&view->respip_set->ip_tree, &rrset_id))) { view->respip_set, &rrset_id))) {
/** for per-view respip directives the action /** for per-view respip directives the action
* can only be direct (i.e. not tag-based) */ * can only be direct (i.e. not tag-based) */
action = raddr->action; action = raddr->action;
@ -875,7 +950,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(!raddr && !view->isfirst) if(!raddr && !view->isfirst)
goto done; goto done;
} }
if(!raddr && ipset && (raddr = respip_addr_lookup(rep, &ipset->ip_tree, if(!raddr && (raddr = respip_addr_lookup(rep, ipset,
&rrset_id))) { &rrset_id))) {
action = (enum respip_action)local_data_find_tag_action( action = (enum respip_action)local_data_find_tag_action(
raddr->taglist, raddr->taglen, ctaglist, ctaglen, raddr->taglist, raddr->taglen, ctaglist, ctaglen,
@ -883,6 +958,29 @@ respip_rewrite_reply(const struct query_info* qinfo,
(enum localzone_type)raddr->action, &tag, (enum localzone_type)raddr->action, &tag,
ipset->tagname, ipset->num_tags); ipset->tagname, ipset->num_tags);
} }
lock_rw_rdlock(&az->rpz_lock);
for(r = az->rpz_first; r && !raddr; r = r->next) {
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, ctaglist, ctaglen)) {
if((raddr = respip_addr_lookup(rep,
r->respip_set, &rrset_id))) {
if(!respip_use_rpz(raddr, r, &action, &data,
&rpz_log, &log_name, &rpz_cname_override,
region, &rpz_used)) {
log_err("out of memory");
lock_rw_unlock(&raddr->lock);
lock_rw_unlock(&az->rpz_lock);
return 0;
}
if(!rpz_used) {
lock_rw_unlock(&raddr->lock);
raddr = NULL;
actinfo->rpz_disabled++;
}
}
}
}
lock_rw_unlock(&az->rpz_lock);
if(raddr && !search_only) { if(raddr && !search_only) {
int result = 0; int result = 0;
@ -891,10 +989,13 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(action != respip_always_refuse if(action != respip_always_refuse
&& action != respip_always_transparent && action != respip_always_transparent
&& action != respip_always_nxdomain && action != respip_always_nxdomain
&& (result = respip_data_answer(raddr, action, && action != respip_always_nodata
qinfo->qtype, rep, rrset_id, new_repp, tag, tag_datas, && action != respip_always_deny
tag_datas_size, ipset->tagname, ipset->num_tags, && (result = respip_data_answer(action,
&redirect_rrset, region)) < 0) { (data) ? data : raddr->data, qinfo->qtype, rep,
rrset_id, new_repp, tag, tag_datas, tag_datas_size,
ipset->tagname, ipset->num_tags, &redirect_rrset,
region)) < 0) {
ret = 0; ret = 0;
goto done; goto done;
} }
@ -925,7 +1026,11 @@ respip_rewrite_reply(const struct query_info* qinfo,
*alias_rrset = redirect_rrset; *alias_rrset = redirect_rrset;
/* on success, populate respip result structure */ /* on success, populate respip result structure */
ret = populate_action_info(actinfo, action, raddr, ret = populate_action_info(actinfo, action, raddr,
redirect_rrset, tag, ipset, search_only, region); redirect_rrset, tag, ipset, search_only, region,
rpz_used, rpz_log, log_name, rpz_cname_override);
}
if(raddr) {
lock_rw_unlock(&raddr->lock);
} }
return ret; return ret;
} }
@ -981,14 +1086,15 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA || qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) && qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
qstate->return_msg && qstate->return_msg->rep) { qstate->return_msg && qstate->return_msg->rep) {
struct respip_action_info actinfo = {respip_none, NULL};
struct reply_info* new_rep = qstate->return_msg->rep; struct reply_info* new_rep = qstate->return_msg->rep;
struct ub_packed_rrset_key* alias_rrset = NULL; struct ub_packed_rrset_key* alias_rrset = NULL;
struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
if(!respip_rewrite_reply(&qstate->qinfo, if(!respip_rewrite_reply(&qstate->qinfo,
qstate->client_info, qstate->return_msg->rep, qstate->client_info, qstate->return_msg->rep,
&new_rep, &actinfo, &alias_rrset, 0, &new_rep, &actinfo, &alias_rrset, 0,
qstate->region)) { qstate->region, qstate->env->auth_zones)) {
goto servfail; goto servfail;
} }
if(actinfo.action != respip_none) { if(actinfo.action != respip_none) {
@ -1004,9 +1110,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
} else { } else {
qstate->respip_action_info = NULL; qstate->respip_action_info = NULL;
} }
if (new_rep == qstate->return_msg->rep && if (actinfo.action == respip_always_deny ||
(new_rep == qstate->return_msg->rep &&
(actinfo.action == respip_deny || (actinfo.action == respip_deny ||
actinfo.action == respip_inform_deny)) { actinfo.action == respip_inform_deny))) {
/* for deny-variant actions (unless response-ip /* for deny-variant actions (unless response-ip
* data is applied), mark the query state so * data is applied), mark the query state so
* the response will be dropped for all * the response will be dropped for all
@ -1034,14 +1141,16 @@ int
respip_merge_cname(struct reply_info* base_rep, respip_merge_cname(struct reply_info* base_rep,
const struct query_info* qinfo, const struct reply_info* tgt_rep, const struct query_info* qinfo, const struct reply_info* tgt_rep,
const struct respip_client_info* cinfo, int must_validate, const struct respip_client_info* cinfo, int must_validate,
struct reply_info** new_repp, struct regional* region) struct reply_info** new_repp, struct regional* region,
struct auth_zones* az)
{ {
struct reply_info* new_rep; struct reply_info* new_rep;
struct reply_info* tmp_rep = NULL; /* just a placeholder */ struct reply_info* tmp_rep = NULL; /* just a placeholder */
struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */ struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */
uint16_t tgt_rcode; uint16_t tgt_rcode;
size_t i, j; size_t i, j;
struct respip_action_info actinfo = {respip_none, NULL}; struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
/* If the query for the CNAME target would result in an unusual rcode, /* If the query for the CNAME target would result in an unusual rcode,
* we generally translate it as a failure for the base query * we generally translate it as a failure for the base query
@ -1060,7 +1169,7 @@ respip_merge_cname(struct reply_info* base_rep,
/* see if the target reply would be subject to a response-ip action. */ /* see if the target reply would be subject to a response-ip action. */
if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo, if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo,
&alias_rrset, 1, region)) &alias_rrset, 1, region, az))
return 0; return 0;
if(actinfo.action != respip_none) { if(actinfo.action != respip_none) {
log_info("CNAME target of redirect response-ip action would " log_info("CNAME target of redirect response-ip action would "
@ -1112,7 +1221,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo, if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo,
qstate->return_msg->rep, super->client_info, qstate->return_msg->rep, super->client_info,
super->env->need_to_validate, &new_rep, super->region)) super->env->need_to_validate, &new_rep, super->region,
qstate->env->auth_zones))
goto fail; goto fail;
super->return_msg->rep = new_rep; super->return_msg->rep = new_rep;
return; return;
@ -1171,12 +1281,15 @@ respip_set_is_empty(const struct respip_set* set)
} }
void void
respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname, respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias, uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
struct comm_reply* repinfo) struct comm_reply* repinfo)
{ {
char srcip[128], respip[128], txt[512]; char srcip[128], respip[128], txt[512];
unsigned port; unsigned port;
struct respip_addr_info* respip_addr = respip_actinfo->addrinfo;
size_t txtlen = 0;
const char* actionstr = NULL;
if(local_alias) if(local_alias)
qname = local_alias->rrset->rk.dname; qname = local_alias->rrset->rk.dname;
@ -1186,7 +1299,23 @@ respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname,
addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip)); addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip));
addr_to_str(&respip_addr->addr, respip_addr->addrlen, addr_to_str(&respip_addr->addr, respip_addr->addrlen,
respip, sizeof(respip)); respip, sizeof(respip));
snprintf(txt, sizeof(txt), "%s/%d inform %s@%u", respip, if(respip_actinfo->rpz_log) {
respip_addr->net, srcip, port); txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, "%s",
"RPZ applied ");
if(respip_actinfo->rpz_cname_override)
actionstr = rpz_action_to_string(
RPZ_CNAME_OVERRIDE_ACTION);
else
actionstr = rpz_action_to_string(
respip_action_to_rpz_action(
respip_actinfo->action));
}
if(respip_actinfo->log_name) {
txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen,
"[%s] ", respip_actinfo->log_name);
}
snprintf(txt+txtlen, sizeof(txt)-txtlen,
"%s/%d %s %s@%u", respip, respip_addr->net,
(actionstr) ? actionstr : "inform", srcip, port);
log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass); log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass);
} }

View File

@ -14,23 +14,42 @@
#include "util/module.h" #include "util/module.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "util/locks.h"
/** /**
* Set of response IP addresses with associated actions and tags. * Conceptual set of IP addresses for response AAAA or A records that should
* Forward declaration only here. Actual definition is hidden within the * trigger special actions.
* module.
*/ */
struct respip_set; struct respip_set {
struct regional* region;
struct rbtree_type ip_tree;
lock_rw_type lock; /* lock on the respip tree */
char* const* tagname; /* shallow copy of tag names, for logging */
int num_tags; /* number of tagname entries */
};
/** An address span with response control information */
struct resp_addr {
/** node in address tree */
struct addr_tree_node node;
/** lock on the node item */
lock_rw_type lock;
/** tag bitlist */
uint8_t* taglist;
/** length of the taglist (in bytes) */
size_t taglen;
/** action for this address span */
enum respip_action action;
/** "local data" for this node */
struct ub_packed_rrset_key* data;
};
/**
* Forward declaration for the structure that represents a node in the
* respip_set address tree
*/
struct resp_addr;
/** /**
* Forward declaration for the structure that represents a tree of view data. * Forward declaration for the structure that represents a tree of view data.
*/ */
struct views; struct views;
struct respip_addr_info; struct respip_addr_info;
@ -60,6 +79,11 @@ struct respip_client_info {
*/ */
struct respip_action_info { struct respip_action_info {
enum respip_action action; enum respip_action action;
int rpz_used;
int rpz_log;
int rpz_disabled;
char* log_name;
int rpz_cname_override;
struct respip_addr_info* addrinfo; /* set only for inform variants */ struct respip_addr_info* addrinfo; /* set only for inform variants */
}; };
@ -124,12 +148,14 @@ int respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
* @param new_repp: pointer placeholder for the merged reply. will be intact * @param new_repp: pointer placeholder for the merged reply. will be intact
* on error. * on error.
* @param region: allocator to build *new_repp. * @param region: allocator to build *new_repp.
* @param az: auth zones containing RPZ information.
* @return 1 on success, 0 on error. * @return 1 on success, 0 on error.
*/ */
int respip_merge_cname(struct reply_info* base_rep, int respip_merge_cname(struct reply_info* base_rep,
const struct query_info* qinfo, const struct reply_info* tgt_rep, const struct query_info* qinfo, const struct reply_info* tgt_rep,
const struct respip_client_info* cinfo, int must_validate, const struct respip_client_info* cinfo, int must_validate,
struct reply_info** new_repp, struct regional* region); struct reply_info** new_repp, struct regional* region,
struct auth_zones* az);
/** /**
* See if any IP-based action should apply to any IP address of AAAA/A answer * See if any IP-based action should apply to any IP address of AAAA/A answer
@ -148,6 +174,7 @@ int respip_merge_cname(struct reply_info* base_rep,
* @param alias_rrset: must not be NULL. * @param alias_rrset: must not be NULL.
* @param search_only: if true, only check if an action would apply. actionp * @param search_only: if true, only check if an action would apply. actionp
* will be set (or intact) accordingly but the modified reply won't be built. * will be set (or intact) accordingly but the modified reply won't be built.
* @param az: auth zones containing RPZ information.
* @param region: allocator to build *new_repp. * @param region: allocator to build *new_repp.
* @return 1 on success, 0 on error. * @return 1 on success, 0 on error.
*/ */
@ -156,7 +183,7 @@ int respip_rewrite_reply(const struct query_info* qinfo,
const struct reply_info *rep, struct reply_info** new_repp, const struct reply_info *rep, struct reply_info** new_repp,
struct respip_action_info* actinfo, struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset, struct ub_packed_rrset_key** alias_rrset,
int search_only, struct regional* region); int search_only, struct regional* region, struct auth_zones* az);
/** /**
* Get the response-ip function block. * Get the response-ip function block.
@ -213,7 +240,7 @@ int respip_set_is_empty(const struct respip_set* set);
/** /**
* print log information for a query subject to an inform or inform-deny * print log information for a query subject to an inform or inform-deny
* response-ip action. * response-ip action.
* @param respip_addr: response-ip information that causes the action * @param respip_actinfo: response-ip information that causes the action
* @param qname: query name in the context, will be ignored if local_alias is * @param qname: query name in the context, will be ignored if local_alias is
* non-NULL. * non-NULL.
* @param qtype: query type, in host byte order. * @param qtype: query type, in host byte order.
@ -223,8 +250,48 @@ int respip_set_is_empty(const struct respip_set* set);
* query name. * query name.
* @param repinfo: reply info containing the client's source address and port. * @param repinfo: reply info containing the client's source address and port.
*/ */
void respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname, void respip_inform_print(struct respip_action_info* respip_actinfo,
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias, uint8_t* qname, uint16_t qtype, uint16_t qclass,
struct comm_reply* repinfo); struct local_rrset* local_alias, struct comm_reply* repinfo);
/**
* Find resp_addr in tree, create and add to tree if it does not exist.
* @param set: struct containing the tree and region to alloc new node on.
* should hold write lock.
* @param addr: address to look up.
* @param addrlen: length of addr.
* @param net: netblock to lookup.
* @param create: create node if it does not exist when 1.
* @param ipstr: human redable ip string, for logging.
* @return newly created of found node, not holding lock.
*/
struct resp_addr*
respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, int create, const char* ipstr);
/**
* Add RR to resp_addr's RRset. Create RRset if not existing.
* @param region: region to alloc RR(set).
* @param raddr: resp_addr containing RRset. Must hold write lock.
* @param rrtype: RR type.
* @param rrclass: RR class.
* @param ttl: TTL.
* @param rdata: RDATA.
* @param rdata_len: length of rdata.
* @param rrstr: RR as string, for logging
* @param netblockstr: netblock as string, for logging
* @return 0 on error
*/
int
respip_enter_rr(struct regional* region, struct resp_addr* raddr,
uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
size_t rdata_len, const char* rrstr, const char* netblockstr);
/**
* Delete resp_addr node from tree.
* @param set: struct containing tree. Must hold write lock.
* @param node: node to delete. Not locked.
*/
void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
#endif /* RESPIP_RESPIP_H */ #endif /* RESPIP_RESPIP_H */

View File

@ -299,6 +299,8 @@ struct auth_zones* auth_zones_create(void)
lock_protect(&az->lock, &az->ztree, sizeof(az->ztree)); lock_protect(&az->lock, &az->ztree, sizeof(az->ztree));
lock_protect(&az->lock, &az->xtree, sizeof(az->xtree)); lock_protect(&az->lock, &az->xtree, sizeof(az->xtree));
/* also lock protects the rbnode's in struct auth_zone, auth_xfer */ /* also lock protects the rbnode's in struct auth_zone, auth_xfer */
lock_rw_init(&az->rpz_lock);
lock_protect(&az->rpz_lock, &az->rpz_first, sizeof(az->rpz_first));
return az; return az;
} }
@ -381,11 +383,25 @@ auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg))
/** delete an auth zone structure (tree remove must be done elsewhere) */ /** delete an auth zone structure (tree remove must be done elsewhere) */
static void static void
auth_zone_delete(struct auth_zone* z) auth_zone_delete(struct auth_zone* z, struct auth_zones* az)
{ {
if(!z) return; if(!z) return;
lock_rw_destroy(&z->lock); lock_rw_destroy(&z->lock);
traverse_postorder(&z->data, auth_data_del, NULL); traverse_postorder(&z->data, auth_data_del, NULL);
if(az && z->rpz) {
/* keep RPZ linked list intact */
lock_rw_wrlock(&az->rpz_lock);
if(z->rpz->prev)
z->rpz->prev->next = z->rpz->next;
else
az->rpz_first = z->rpz->next;
if(z->rpz->next)
z->rpz->next->prev = z->rpz->prev;
lock_rw_unlock(&az->rpz_lock);
}
if(z->rpz)
rpz_delete(z->rpz);
free(z->name); free(z->name);
free(z->zonefile); free(z->zonefile);
free(z); free(z);
@ -415,7 +431,7 @@ auth_zone_create(struct auth_zones* az, uint8_t* nm, size_t nmlen,
/* z lock protects all, except rbtree itself, which is az->lock */ /* z lock protects all, except rbtree itself, which is az->lock */
if(!rbtree_insert(&az->ztree, &z->node)) { if(!rbtree_insert(&az->ztree, &z->node)) {
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
auth_zone_delete(z); auth_zone_delete(z, NULL);
log_warn("duplicate auth zone"); log_warn("duplicate auth zone");
return NULL; return NULL;
} }
@ -660,23 +676,6 @@ domain_remove_rrset(struct auth_data* node, uint16_t rr_type)
} }
} }
/** find an rr index in the rrset. returns true if found */
static int
az_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index)
{
size_t i;
for(i=0; i<d->count; i++) {
if(d->rr_len[i] != len)
continue;
if(memcmp(d->rr_data[i], rdata, len) == 0) {
*index = i;
return 1;
}
}
return 0;
}
/** find an rrsig index in the rrset. returns true if found */ /** find an rrsig index in the rrset. returns true if found */
static int static int
az_rrset_find_rrsig(struct packed_rrset_data* d, uint8_t* rdata, size_t len, az_rrset_find_rrsig(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
@ -1178,6 +1177,12 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
log_err("cannot add RR to domain"); log_err("cannot add RR to domain");
return 0; return 0;
} }
if(z->rpz) {
if(!(rpz_insert_rr(z->rpz, z->namelen, dname, dname_len,
rr_type, rr_class, rr_ttl, rdata, rdatalen, rr,
rr_len)))
return 0;
}
return 1; return 1;
} }
@ -1192,7 +1197,7 @@ az_domain_remove_rr(struct auth_data* node, uint16_t rr_type,
/* find the plain RR of the given type */ /* find the plain RR of the given type */
if((rrset=az_domain_rrset(node, rr_type))!= NULL) { if((rrset=az_domain_rrset(node, rr_type))!= NULL) {
if(az_rrset_find_rr(rrset->data, rdata, rdatalen, &index)) { if(packed_rrset_find_rr(rrset->data, rdata, rdatalen, &index)) {
if(rrset->data->count == 1 && if(rrset->data->count == 1 &&
rrset->data->rrsig_count == 0) { rrset->data->rrsig_count == 0) {
/* last RR, delete the rrset */ /* last RR, delete the rrset */
@ -1293,6 +1298,10 @@ az_remove_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
(void)rbtree_delete(&z->data, node); (void)rbtree_delete(&z->data, node);
auth_data_delete(node); auth_data_delete(node);
} }
if(z->rpz) {
rpz_remove_rr(z->rpz, z->namelen, dname, dname_len, rr_type,
rr_class, rdata, rdatalen);
}
return 1; return 1;
} }
@ -1585,6 +1594,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
/* clear the data tree */ /* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL); traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp); rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
/* default TTL to 3600 */ /* default TTL to 3600 */
@ -1604,6 +1616,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
return 0; return 0;
} }
fclose(in); fclose(in);
if(z->rpz)
rpz_finish_config(z->rpz);
return 1; return 1;
} }
@ -1877,6 +1892,18 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
z->for_downstream = c->for_downstream; z->for_downstream = c->for_downstream;
z->for_upstream = c->for_upstream; z->for_upstream = c->for_upstream;
z->fallback_enabled = c->fallback_enabled; z->fallback_enabled = c->fallback_enabled;
if(c->isrpz && !z->rpz){
if(!(z->rpz = rpz_create(c))){
fatal_exit("Could not setup RPZ zones");
return 0;
}
lock_rw_wrlock(&az->rpz_lock);
z->rpz->next = az->rpz_first;
if(az->rpz_first)
az->rpz_first->prev = z->rpz;
az->rpz_first = z->rpz;
lock_rw_unlock(&az->rpz_lock);
}
/* xfer zone */ /* xfer zone */
if(x) { if(x) {
@ -1947,14 +1974,14 @@ az_delete_deleted_zones(struct auth_zones* az)
auth_xfer_delete(xfr); auth_xfer_delete(xfr);
} }
(void)rbtree_delete(&az->ztree, &z->node); (void)rbtree_delete(&az->ztree, &z->node);
auth_zone_delete(z); auth_zone_delete(z, az);
z = next; z = next;
} }
lock_rw_unlock(&az->lock); lock_rw_unlock(&az->lock);
} }
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup) int setup, int* is_rpz)
{ {
struct config_auth* p; struct config_auth* p;
az_setall_deleted(az); az_setall_deleted(az);
@ -1963,6 +1990,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
log_warn("auth-zone without a name, skipped"); log_warn("auth-zone without a name, skipped");
continue; continue;
} }
*is_rpz = (*is_rpz || p->isrpz);
if(!auth_zones_cfg(az, p)) { if(!auth_zones_cfg(az, p)) {
log_err("cannot config auth zone %s", p->name); log_err("cannot config auth zone %s", p->name);
return 0; return 0;
@ -2063,7 +2091,7 @@ static void
auth_zone_del(rbnode_type* n, void* ATTR_UNUSED(arg)) auth_zone_del(rbnode_type* n, void* ATTR_UNUSED(arg))
{ {
struct auth_zone* z = (struct auth_zone*)n->key; struct auth_zone* z = (struct auth_zone*)n->key;
auth_zone_delete(z); auth_zone_delete(z, NULL);
} }
/** helper traverse to delete xfer zones */ /** helper traverse to delete xfer zones */
@ -2078,6 +2106,7 @@ void auth_zones_delete(struct auth_zones* az)
{ {
if(!az) return; if(!az) return;
lock_rw_destroy(&az->lock); lock_rw_destroy(&az->lock);
lock_rw_destroy(&az->rpz_lock);
traverse_postorder(&az->ztree, auth_zone_del, NULL); traverse_postorder(&az->ztree, auth_zone_del, NULL);
traverse_postorder(&az->xtree, auth_xfer_del, NULL); traverse_postorder(&az->xtree, auth_xfer_del, NULL);
free(az); free(az);
@ -2586,12 +2615,14 @@ az_nsec3_hash(uint8_t* buf, size_t buflen, uint8_t* nm, size_t nmlen,
/* hashfunc(name, salt) */ /* hashfunc(name, salt) */
memmove(p, nm, nmlen); memmove(p, nm, nmlen);
query_dname_tolower(p); query_dname_tolower(p);
memmove(p+nmlen, salt, saltlen); if(salt && saltlen > 0)
memmove(p+nmlen, salt, saltlen);
(void)secalgo_nsec3_hash(algo, p, nmlen+saltlen, (unsigned char*)buf); (void)secalgo_nsec3_hash(algo, p, nmlen+saltlen, (unsigned char*)buf);
for(i=0; i<iter; i++) { for(i=0; i<iter; i++) {
/* hashfunc(hash, salt) */ /* hashfunc(hash, salt) */
memmove(p, buf, hlen); memmove(p, buf, hlen);
memmove(p+hlen, salt, saltlen); if(salt && saltlen > 0)
memmove(p+hlen, salt, saltlen);
(void)secalgo_nsec3_hash(algo, p, hlen+saltlen, (void)secalgo_nsec3_hash(algo, p, hlen+saltlen,
(unsigned char*)buf); (unsigned char*)buf);
} }
@ -4688,6 +4719,10 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
/* clear the data tree */ /* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL); traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp); rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
xfr->have_zone = 0; xfr->have_zone = 0;
xfr->serial = 0; xfr->serial = 0;
@ -4784,6 +4819,10 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
/* clear the data tree */ /* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL); traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp); rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
xfr->have_zone = 0; xfr->have_zone = 0;
xfr->serial = 0; xfr->serial = 0;
@ -4969,6 +5008,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
if(xfr->have_zone) if(xfr->have_zone)
xfr->lease_time = *env->now; xfr->lease_time = *env->now;
if(z->rpz)
rpz_finish_config(z->rpz);
/* unlock */ /* unlock */
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
@ -5530,9 +5572,12 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
xfr->task_transfer->rr_scan_num == 0 && xfr->task_transfer->rr_scan_num == 0 &&
LDNS_ANCOUNT(wire)==1) { LDNS_ANCOUNT(wire)==1) {
verbose(VERB_ALGO, "xfr to %s ended, " verbose(VERB_ALGO, "xfr to %s ended, "
"IXFR reply that zone has serial %u", "IXFR reply that zone has serial %u,"
" fallback from IXFR to AXFR",
xfr->task_transfer->master->host, xfr->task_transfer->master->host,
(unsigned)serial); (unsigned)serial);
xfr->task_transfer->ixfr_fail = 1;
*gonextonfail = 0;
return 0; return 0;
} }

View File

@ -46,6 +46,7 @@
#include "util/rbtree.h" #include "util/rbtree.h"
#include "util/locks.h" #include "util/locks.h"
#include "services/mesh.h" #include "services/mesh.h"
#include "services/rpz.h"
struct ub_packed_rrset_key; struct ub_packed_rrset_key;
struct regional; struct regional;
struct config_file; struct config_file;
@ -81,6 +82,11 @@ struct auth_zones {
size_t num_query_up; size_t num_query_up;
/** number of queries downstream */ /** number of queries downstream */
size_t num_query_down; size_t num_query_down;
/** first rpz item in linked list */
struct rpz* rpz_first;
/** rw lock for rpz linked list, needed when iterating or editing linked
* list. */
lock_rw_type rpz_lock;
}; };
/** /**
@ -126,6 +132,8 @@ struct auth_zone {
/** for upstream: this zone answers queries that unbound intends to /** for upstream: this zone answers queries that unbound intends to
* send upstream. */ * send upstream. */
int for_upstream; int for_upstream;
/** RPZ zones */
struct rpz* rpz;
/** zone has been deleted */ /** zone has been deleted */
int zone_deleted; int zone_deleted;
/** deletelist pointer, unused normally except during delete */ /** deletelist pointer, unused normally except during delete */
@ -460,10 +468,11 @@ struct auth_zones* auth_zones_create(void);
* @param az: auth zones structure * @param az: auth zones structure
* @param cfg: config to apply. * @param cfg: config to apply.
* @param setup: if true, also sets up values in the auth zones structure * @param setup: if true, also sets up values in the auth zones structure
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
* @return false on failure. * @return false on failure.
*/ */
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup); int setup, int* is_rpz);
/** initial pick up of worker timeouts, ties events to worker event loop /** initial pick up of worker timeouts, ties events to worker event loop
* @param az: auth zones structure * @param az: auth zones structure

View File

@ -45,6 +45,7 @@
#include "validator/val_utils.h" #include "validator/val_utils.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "services/cache/rrset.h" #include "services/cache/rrset.h"
#include "util/data/msgparse.h"
#include "util/data/msgreply.h" #include "util/data/msgreply.h"
#include "util/data/packed_rrset.h" #include "util/data/packed_rrset.h"
#include "util/data/dname.h" #include "util/data/dname.h"
@ -73,15 +74,15 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
time_t leeway, int pside, struct reply_info* qrep, time_t leeway, int pside, struct reply_info* qrep,
struct regional* region) struct regional* region)
{ {
size_t i; size_t i;
/* see if rrset already exists in cache, if not insert it. */ /* see if rrset already exists in cache, if not insert it. */
for(i=0; i<rep->rrset_count; i++) { for(i=0; i<rep->rrset_count; i++) {
rep->ref[i].key = rep->rrsets[i]; rep->ref[i].key = rep->rrsets[i];
rep->ref[i].id = rep->rrsets[i]->id; rep->ref[i].id = rep->rrsets[i]->id;
/* update ref if it was in the cache */ /* update ref if it was in the cache */
switch(rrset_cache_update(env->rrset_cache, &rep->ref[i], switch(rrset_cache_update(env->rrset_cache, &rep->ref[i],
env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)== env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)==
LDNS_RR_TYPE_NS && !pside)?0:leeway))) { LDNS_RR_TYPE_NS && !pside)?0:leeway))) {
case 0: /* ref unchanged, item inserted */ case 0: /* ref unchanged, item inserted */
break; break;
case 2: /* ref updated, cache is superior */ case 2: /* ref updated, cache is superior */
@ -104,9 +105,9 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
* the fallthrough warning */ * the fallthrough warning */
/* fallthrough */ /* fallthrough */
case 1: /* ref updated, item inserted */ case 1: /* ref updated, item inserted */
rep->rrsets[i] = rep->ref[i].key; rep->rrsets[i] = rep->ref[i].key;
} }
} }
} }
/** delete message from message cache */ /** delete message from message cache */
@ -272,7 +273,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
akey = rrset_cache_lookup(env->rrset_cache, ns->name, akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(akey) { if(akey) {
if(!delegpt_add_rrset_A(dp, region, akey, 0)) { if(!delegpt_add_rrset_A(dp, region, akey, 0, NULL)) {
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
return 0; return 0;
} }
@ -292,7 +293,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass,
akey = rrset_cache_lookup(env->rrset_cache, ns->name, akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
if(akey) { if(akey) {
if(!delegpt_add_rrset_AAAA(dp, region, akey, 0)) { if(!delegpt_add_rrset_AAAA(dp, region, akey, 0, NULL)) {
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
return 0; return 0;
} }
@ -326,7 +327,8 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
akey = rrset_cache_lookup(env->rrset_cache, ns->name, akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(akey) { if(akey) {
if(!delegpt_add_rrset_A(dp, region, akey, ns->lame)) { if(!delegpt_add_rrset_A(dp, region, akey, ns->lame,
NULL)) {
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
return 0; return 0;
} }
@ -346,7 +348,8 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
akey = rrset_cache_lookup(env->rrset_cache, ns->name, akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
if(akey) { if(akey) {
if(!delegpt_add_rrset_AAAA(dp, region, akey, ns->lame)) { if(!delegpt_add_rrset_AAAA(dp, region, akey, ns->lame,
NULL)) {
lock_rw_unlock(&akey->entry.lock); lock_rw_unlock(&akey->entry.lock);
return 0; return 0;
} }
@ -532,31 +535,51 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
} }
struct dns_msg* struct dns_msg*
tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
struct regional* region, time_t now, struct regional* scratch) struct regional* region, time_t now, int allow_expired,
struct regional* scratch)
{ {
struct dns_msg* msg; struct dns_msg* msg;
size_t i; size_t i;
if(now > r->ttl) int is_expired = 0;
return NULL; time_t now_control = now;
if(now > r->ttl) {
/* Check if we are allowed to serve expired */
if(allow_expired) {
if(env->cfg->serve_expired_ttl &&
r->serve_expired_ttl < now) {
return NULL;
}
} else {
return NULL;
}
/* Change the current time so we can pass the below TTL checks when
* serving expired data. */
now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
is_expired = 1;
}
msg = gen_dns_msg(region, q, r->rrset_count); msg = gen_dns_msg(region, q, r->rrset_count);
if(!msg) if(!msg) return NULL;
return NULL;
msg->rep->flags = r->flags; msg->rep->flags = r->flags;
msg->rep->qdcount = r->qdcount; msg->rep->qdcount = r->qdcount;
msg->rep->ttl = r->ttl - now; msg->rep->ttl = is_expired
?SERVE_EXPIRED_REPLY_TTL
:r->ttl - now;
if(r->prefetch_ttl > now) if(r->prefetch_ttl > now)
msg->rep->prefetch_ttl = r->prefetch_ttl - now; msg->rep->prefetch_ttl = r->prefetch_ttl - now;
else msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); else
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->security = r->security; msg->rep->security = r->security;
msg->rep->an_numrrsets = r->an_numrrsets; msg->rep->an_numrrsets = r->an_numrrsets;
msg->rep->ns_numrrsets = r->ns_numrrsets; msg->rep->ns_numrrsets = r->ns_numrrsets;
msg->rep->ar_numrrsets = r->ar_numrrsets; msg->rep->ar_numrrsets = r->ar_numrrsets;
msg->rep->rrset_count = r->rrset_count; msg->rep->rrset_count = r->rrset_count;
msg->rep->authoritative = r->authoritative; msg->rep->authoritative = r->authoritative;
if(!rrset_array_lock(r->ref, r->rrset_count, now)) if(!rrset_array_lock(r->ref, r->rrset_count, now_control)) {
return NULL; return NULL;
}
if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons( if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons(
LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons( LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons(
LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) { LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) {
@ -570,7 +593,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
return NULL; return NULL;
} }
for(i=0; i<msg->rep->rrset_count; i++) { for(i=0; i<msg->rep->rrset_count; i++) {
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i], msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
region, now); region, now);
if(!msg->rep->rrsets[i]) { if(!msg->rep->rrsets[i]) {
rrset_array_unlock(r->ref, r->rrset_count); rrset_array_unlock(r->ref, r->rrset_count);
@ -797,7 +820,7 @@ dns_cache_lookup(struct module_env* env,
if(e) { if(e) {
struct msgreply_entry* key = (struct msgreply_entry*)e->key; struct msgreply_entry* key = (struct msgreply_entry*)e->key;
struct reply_info* data = (struct reply_info*)e->data; struct reply_info* data = (struct reply_info*)e->data;
struct dns_msg* msg = tomsg(env, &key->key, data, region, now, struct dns_msg* msg = tomsg(env, &key->key, data, region, now, 0,
scratch); scratch);
if(msg) { if(msg) {
lock_rw_unlock(&e->lock); lock_rw_unlock(&e->lock);
@ -899,37 +922,38 @@ dns_cache_lookup(struct module_env* env,
* Empty nonterminals are NOERROR, so an NXDOMAIN for foo * Empty nonterminals are NOERROR, so an NXDOMAIN for foo
* means bla.foo also does not exist. The DNSSEC proofs are * means bla.foo also does not exist. The DNSSEC proofs are
* the same. We search upwards for NXDOMAINs. */ * the same. We search upwards for NXDOMAINs. */
if(env->cfg->harden_below_nxdomain) if(env->cfg->harden_below_nxdomain) {
while(!dname_is_root(k.qname)) { while(!dname_is_root(k.qname)) {
dname_remove_label(&k.qname, &k.qname_len); dname_remove_label(&k.qname, &k.qname_len);
h = query_info_hash(&k, flags);
e = slabhash_lookup(env->msg_cache, h, &k, 0);
if(!e && k.qtype != LDNS_RR_TYPE_A &&
env->cfg->qname_minimisation) {
k.qtype = LDNS_RR_TYPE_A;
h = query_info_hash(&k, flags); h = query_info_hash(&k, flags);
e = slabhash_lookup(env->msg_cache, h, &k, 0); e = slabhash_lookup(env->msg_cache, h, &k, 0);
} if(!e && k.qtype != LDNS_RR_TYPE_A &&
if(e) { env->cfg->qname_minimisation) {
struct reply_info* data = (struct reply_info*)e->data; k.qtype = LDNS_RR_TYPE_A;
struct dns_msg* msg; h = query_info_hash(&k, flags);
if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN e = slabhash_lookup(env->msg_cache, h, &k, 0);
&& data->security == sec_status_secure
&& (data->an_numrrsets == 0 ||
ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
&& (msg=tomsg(env, &k, data, region, now, scratch))){
lock_rw_unlock(&e->lock);
msg->qinfo.qname=qname;
msg->qinfo.qname_len=qnamelen;
/* check that DNSSEC really works out */
msg->rep->security = sec_status_unchecked;
iter_scrub_nxdomain(msg);
return msg;
} }
lock_rw_unlock(&e->lock); if(e) {
struct reply_info* data = (struct reply_info*)e->data;
struct dns_msg* msg;
if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
&& data->security == sec_status_secure
&& (data->an_numrrsets == 0 ||
ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
&& (msg=tomsg(env, &k, data, region, now, 0, scratch))) {
lock_rw_unlock(&e->lock);
msg->qinfo.qname=qname;
msg->qinfo.qname_len=qnamelen;
/* check that DNSSEC really works out */
msg->rep->security = sec_status_unchecked;
iter_scrub_nxdomain(msg);
return msg;
}
lock_rw_unlock(&e->lock);
}
k.qtype = qtype;
} }
k.qtype = qtype; }
}
/* fill common RR types for ANY response to avoid requery */ /* fill common RR types for ANY response to avoid requery */
if(qtype == LDNS_RR_TYPE_ANY) { if(qtype == LDNS_RR_TYPE_ANY) {

View File

@ -143,11 +143,14 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
* @param r: reply info that, together with qname, will make up the dns message. * @param r: reply info that, together with qname, will make up the dns message.
* @param region: where to allocate dns message. * @param region: where to allocate dns message.
* @param now: the time now, for check if TTL on cache entry is ok. * @param now: the time now, for check if TTL on cache entry is ok.
* @param allow_expired: if true and serve-expired is enabled, it will allow
* for expired dns_msg to be generated based on the configured serve-expired
* logic.
* @param scratch: where to allocate temporary data. * @param scratch: where to allocate temporary data.
* */ * */
struct dns_msg* tomsg(struct module_env* env, struct query_info* q, struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
struct reply_info* r, struct regional* region, time_t now, struct reply_info* r, struct regional* region, time_t now,
struct regional* scratch); int allow_expired, struct regional* scratch);
/** /**
* Find cached message * Find cached message
@ -160,7 +163,7 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
* @param region: where to allocate result. * @param region: where to allocate result.
* @param scratch: where to allocate temporary data. * @param scratch: where to allocate temporary data.
* @param no_partial: if true, only complete messages and not a partial * @param no_partial: if true, only complete messages and not a partial
* one (with only the start of the CNAME chain and not the rest). * one (with only the start of the CNAME chain and not the rest).
* @return new response message (alloced in region, rrsets do not have IDs). * @return new response message (alloced in region, rrsets do not have IDs).
* or NULL on error or if not found in cache. * or NULL on error or if not found in cache.
* TTLs are made relative to the current time. * TTLs are made relative to the current time.

View File

@ -41,7 +41,6 @@
#include "config.h" #include "config.h"
#include "services/localzone.h" #include "services/localzone.h"
#include "sldns/str2wire.h" #include "sldns/str2wire.h"
#include "sldns/sbuffer.h"
#include "util/regional.h" #include "util/regional.h"
#include "util/config_file.h" #include "util/config_file.h"
#include "util/data/dname.h" #include "util/data/dname.h"
@ -395,9 +394,30 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
return 1; return 1;
} }
/** find a data node by exact name */ /** Delete RR from local-zone RRset, wastes memory as the deleted RRs cannot be
static struct local_data* * free'd (regionally alloc'd) */
lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs) int
local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index)
{
log_assert(pd->count > 0);
if(index >= pd->count) {
log_warn("Trying to remove RR with out of bound index");
return 0;
}
if(index + 1 < pd->count) {
/* not removing last element */
size_t nexti = index + 1;
size_t num = pd->count - nexti;
memmove(pd->rr_len+index, pd->rr_len+nexti, sizeof(*pd->rr_len)*num);
memmove(pd->rr_ttl+index, pd->rr_ttl+nexti, sizeof(*pd->rr_ttl)*num);
memmove(pd->rr_data+index, pd->rr_data+nexti, sizeof(*pd->rr_data)*num);
}
pd->count--;
return 1;
}
struct local_data*
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
{ {
struct local_data key; struct local_data key;
key.node.key = &key; key.node.key = &key;
@ -412,7 +432,7 @@ static int
lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen, lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, struct local_data** res) int nmlabs, struct local_data** res)
{ {
struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs); struct local_data* ld = local_zone_find_data(z, nm, nmlen, nmlabs);
if(!ld) { if(!ld) {
/* create a domain name to store rr. */ /* create a domain name to store rr. */
ld = (struct local_data*)regional_alloc_zero(z->region, ld = (struct local_data*)regional_alloc_zero(z->region,
@ -443,42 +463,19 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
return 1; return 1;
} }
/** enter data RR into auth zone */ int
static int local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata, size_t rdata_len, const char* rrstr)
{ {
uint8_t* nm;
size_t nmlen;
int nmlabs;
struct local_data* node; struct local_data* node;
struct local_rrset* rrset; struct local_rrset* rrset;
struct packed_rrset_data* pd; struct packed_rrset_data* pd;
uint16_t rrtype = 0, rrclass = 0;
time_t ttl = 0;
uint8_t rr[LDNS_RR_BUF_SIZE];
uint8_t* rdata;
size_t rdata_len;
if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
sizeof(rr), &rdata, &rdata_len)) {
log_err("bad local-data: %s", rrstr);
return 0;
}
log_assert(z->dclass == rrclass);
if((z->type == local_zone_redirect ||
z->type == local_zone_inform_redirect) &&
query_dname_compare(z->name, nm) != 0) {
log_err("local-data in redirect zone must reside at top of zone"
", not at %s", rrstr);
free(nm);
return 0;
}
nmlabs = dname_count_size_labels(nm, &nmlen);
if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) { if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
free(nm);
return 0; return 0;
} }
log_assert(node); log_assert(node);
free(nm);
/* Reject it if we would end up having CNAME and other data (including /* Reject it if we would end up having CNAME and other data (including
* another CNAME) for a redirect zone. */ * another CNAME) for a redirect zone. */
@ -520,6 +517,39 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr); return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr);
} }
/** enter data RR into auth zone */
int
lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
{
uint8_t* nm;
size_t nmlen;
int nmlabs, ret;
uint16_t rrtype = 0, rrclass = 0;
time_t ttl = 0;
uint8_t rr[LDNS_RR_BUF_SIZE];
uint8_t* rdata;
size_t rdata_len;
if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
sizeof(rr), &rdata, &rdata_len)) {
log_err("bad local-data: %s", rrstr);
return 0;
}
log_assert(z->dclass == rrclass);
if((z->type == local_zone_redirect ||
z->type == local_zone_inform_redirect) &&
query_dname_compare(z->name, nm) != 0) {
log_err("local-data in redirect zone must reside at top of zone"
", not at %s", rrstr);
free(nm);
return 0;
}
nmlabs = dname_count_size_labels(nm, &nmlen);
ret = local_zone_enter_rr(z, nm, nmlen, nmlabs, rrtype, rrclass, ttl,
rdata, rdata_len, rrstr);
free(nm);
return ret;
}
/** enter a data RR into auth data; a zone for it must exist */ /** enter a data RR into auth data; a zone for it must exist */
static int static int
lz_enter_rr_str(struct local_zones* zones, const char* rr) lz_enter_rr_str(struct local_zones* zones, const char* rr)
@ -823,12 +853,12 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
log_err("out of memory adding default zone"); log_err("out of memory adding default zone");
return 0; return 0;
} }
/* test. zone (RFC 7686) */ /* test. zone (RFC 6761) */
if(!add_empty_default(zones, cfg, "test.")) { if(!add_empty_default(zones, cfg, "test.")) {
log_err("out of memory adding default zone"); log_err("out of memory adding default zone");
return 0; return 0;
} }
/* invalid. zone (RFC 7686) */ /* invalid. zone (RFC 6761) */
if(!add_empty_default(zones, cfg, "invalid.")) { if(!add_empty_default(zones, cfg, "invalid.")) {
log_err("out of memory adding default zone"); log_err("out of memory adding default zone");
return 0; return 0;
@ -1113,6 +1143,22 @@ local_zones_find(struct local_zones* zones,
return (struct local_zone*)rbtree_search(&zones->ztree, &key); return (struct local_zone*)rbtree_search(&zones->ztree, &key);
} }
struct local_zone*
local_zones_find_le(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
int* exact)
{
struct local_zone key;
rbnode_type *node;
key.node.key = &key;
key.dclass = dclass;
key.name = name;
key.namelen = len;
key.namelabs = labs;
*exact = rbtree_find_less_equal(&zones->ztree, &key, &node);
return (struct local_zone*)node;
}
/** print all RRsets in local zone */ /** print all RRsets in local zone */
static void static void
local_zone_out(struct local_zone* z) local_zone_out(struct local_zone* z)
@ -1309,8 +1355,7 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
return result; return result;
} }
/** answer local data match */ int
static int
local_data_answer(struct local_zone* z, struct module_env* env, local_data_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct comm_reply* repinfo, sldns_buffer* buf,
@ -1362,16 +1407,69 @@ local_data_answer(struct local_zone* z, struct module_env* env,
lz_type == local_zone_inform_redirect) && lz_type == local_zone_inform_redirect) &&
qinfo->qtype != LDNS_RR_TYPE_CNAME && qinfo->qtype != LDNS_RR_TYPE_CNAME &&
lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) { lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
uint8_t* ctarget;
size_t ctargetlen = 0;
qinfo->local_alias = qinfo->local_alias =
regional_alloc_zero(temp, sizeof(struct local_rrset)); regional_alloc_zero(temp, sizeof(struct local_rrset));
if(!qinfo->local_alias) if(!qinfo->local_alias)
return 0; /* out of memory */ return 0; /* out of memory */
qinfo->local_alias->rrset = qinfo->local_alias->rrset = regional_alloc_init(
regional_alloc_init(temp, lr->rrset, sizeof(*lr->rrset)); temp, lr->rrset, sizeof(*lr->rrset));
if(!qinfo->local_alias->rrset) if(!qinfo->local_alias->rrset)
return 0; /* out of memory */ return 0; /* out of memory */
qinfo->local_alias->rrset->rk.dname = qinfo->qname; qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
get_cname_target(lr->rrset, &ctarget, &ctargetlen);
if(!ctargetlen)
return 0; /* invalid cname */
if(dname_is_wild(ctarget)) {
/* synthesize cname target */
struct packed_rrset_data* d;
/* -3 for wildcard label and root label from qname */
size_t newtargetlen = qinfo->qname_len + ctargetlen - 3;
log_assert(ctargetlen >= 3);
log_assert(qinfo->qname_len >= 1);
if(newtargetlen > LDNS_MAX_DOMAINLEN) {
qinfo->local_alias = NULL;
local_error_encode(qinfo, env, edns, repinfo,
buf, temp, LDNS_RCODE_YXDOMAIN,
(LDNS_RCODE_YXDOMAIN|BIT_AA));
return 1;
}
memset(&qinfo->local_alias->rrset->entry, 0,
sizeof(qinfo->local_alias->rrset->entry));
qinfo->local_alias->rrset->entry.key =
qinfo->local_alias->rrset;
qinfo->local_alias->rrset->entry.hash =
rrset_key_hash(&qinfo->local_alias->rrset->rk);
d = (struct packed_rrset_data*)regional_alloc_zero(temp,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t)
+ newtargetlen);
if(!d)
return 0; /* out of memory */
qinfo->local_alias->rrset->entry.data = d;
d->ttl = 0; /* 0 for synthesized CNAME TTL */
d->count = 1;
d->rrsig_count = 0;
d->trust = rrset_trust_ans_noAA;
d->rr_len = (size_t*)((uint8_t*)d +
sizeof(struct packed_rrset_data));
d->rr_len[0] = newtargetlen + sizeof(uint16_t);
packed_rrset_ptr_fixup(d);
d->rr_ttl[0] = d->ttl;
sldns_write_uint16(d->rr_data[0], newtargetlen);
/* write qname */
memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname,
qinfo->qname_len - 1);
/* write cname target wilcard wildcard label */
memmove(d->rr_data[0] + sizeof(uint16_t) +
qinfo->qname_len - 1, ctarget + 2,
ctargetlen - 2);
}
return 1; return 1;
} }
if(lz_type == local_zone_redirect || if(lz_type == local_zone_redirect ||
@ -1416,26 +1514,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
return (lr == NULL); return (lr == NULL);
} }
/** int
* Answer in case where no exact match is found. local_zones_zone_answer(struct local_zone* z, struct module_env* env,
* @param z: zone for query.
* @param env: module environment.
* @param qinfo: query.
* @param edns: edns from query.
* @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
* @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
* @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
static int
lz_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp, struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type) struct local_data* ld, enum localzone_type lz_type)
{ {
if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { if(lz_type == local_zone_deny ||
lz_type == local_zone_always_deny ||
lz_type == local_zone_inform_deny) {
/** no reply at all, signal caller by clearing buffer. */ /** no reply at all, signal caller by clearing buffer. */
sldns_buffer_clear(buf); sldns_buffer_clear(buf);
sldns_buffer_flip(buf); sldns_buffer_flip(buf);
@ -1448,7 +1535,8 @@ lz_zone_answer(struct local_zone* z, struct module_env* env,
} else if(lz_type == local_zone_static || } else if(lz_type == local_zone_static ||
lz_type == local_zone_redirect || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect || lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nxdomain) { lz_type == local_zone_always_nxdomain ||
lz_type == local_zone_always_nodata) {
/* for static, reply nodata or nxdomain /* for static, reply nodata or nxdomain
* for redirect, reply nodata */ * for redirect, reply nodata */
/* no additional section processing, /* no additional section processing,
@ -1457,7 +1545,8 @@ lz_zone_answer(struct local_zone* z, struct module_env* env,
* or using closest match for returning delegation downwards * or using closest match for returning delegation downwards
*/ */
int rcode = (ld || lz_type == local_zone_redirect || int rcode = (ld || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect)? lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nodata)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
if(z->soa) if(z->soa)
return local_encode(qinfo, env, edns, repinfo, buf, temp, return local_encode(qinfo, env, edns, repinfo, buf, temp,
@ -1640,6 +1729,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
if(lzt != local_zone_always_refuse if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent && lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain && lzt != local_zone_always_nxdomain
&& lzt != local_zone_always_nodata
&& lzt != local_zone_always_deny
&& local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs, && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
&ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) { &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
@ -1647,7 +1738,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
* a local alias. */ * a local alias. */
return !qinfo->local_alias; return !qinfo->local_alias;
} }
r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt); r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
return r && !qinfo->local_alias; /* see above */ return r && !qinfo->local_alias; /* see above */
} }
@ -1669,7 +1760,10 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_always_transparent: return "always_transparent"; case local_zone_always_transparent: return "always_transparent";
case local_zone_always_refuse: return "always_refuse"; case local_zone_always_refuse: return "always_refuse";
case local_zone_always_nxdomain: return "always_nxdomain"; case local_zone_always_nxdomain: return "always_nxdomain";
case local_zone_always_nodata: return "always_nodata";
case local_zone_always_deny: return "always_deny";
case local_zone_noview: return "noview"; case local_zone_noview: return "noview";
case local_zone_invalid: return "invalid";
} }
return "badtyped"; return "badtyped";
} }
@ -1700,6 +1794,10 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_refuse; *t = local_zone_always_refuse;
else if(strcmp(type, "always_nxdomain") == 0) else if(strcmp(type, "always_nxdomain") == 0)
*t = local_zone_always_nxdomain; *t = local_zone_always_nxdomain;
else if(strcmp(type, "always_nodata") == 0)
*t = local_zone_always_nodata;
else if(strcmp(type, "always_deny") == 0)
*t = local_zone_always_deny;
else if(strcmp(type, "noview") == 0) else if(strcmp(type, "noview") == 0)
*t = local_zone_noview; *t = local_zone_noview;
else if(strcmp(type, "nodefault") == 0) else if(strcmp(type, "nodefault") == 0)
@ -1843,7 +1941,7 @@ del_empty_term(struct local_zone* z, struct local_data* d,
return; return;
dname_remove_label(&name, &len); dname_remove_label(&name, &len);
labs--; labs--;
d = lz_find_node(z, name, len, labs); d = local_zone_find_data(z, name, len, labs);
} }
} }
@ -1876,7 +1974,7 @@ void local_zones_del_data(struct local_zones* zones,
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS); z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
if(z) { if(z) {
lock_rw_wrlock(&z->lock); lock_rw_wrlock(&z->lock);
d = lz_find_node(z, name, len, labs); d = local_zone_find_data(z, name, len, labs);
if(d) { if(d) {
del_local_rrset(d, LDNS_RR_TYPE_DS); del_local_rrset(d, LDNS_RR_TYPE_DS);
del_empty_term(z, d, name, len, labs); del_empty_term(z, d, name, len, labs);
@ -1897,7 +1995,7 @@ void local_zones_del_data(struct local_zones* zones,
lock_rw_unlock(&zones->lock); lock_rw_unlock(&zones->lock);
/* find the domain */ /* find the domain */
d = lz_find_node(z, name, len, labs); d = local_zone_find_data(z, name, len, labs);
if(d) { if(d) {
/* no memory recycling for zone deletions ... */ /* no memory recycling for zone deletions ... */
d->rrsets = NULL; d->rrsets = NULL;

View File

@ -46,6 +46,7 @@
#include "util/storage/dnstree.h" #include "util/storage/dnstree.h"
#include "util/module.h" #include "util/module.h"
#include "services/view.h" #include "services/view.h"
#include "sldns/sbuffer.h"
struct packed_rrset_data; struct packed_rrset_data;
struct ub_packed_rrset_key; struct ub_packed_rrset_key;
struct regional; struct regional;
@ -91,8 +92,14 @@ enum localzone_type {
local_zone_always_refuse, local_zone_always_refuse,
/** answer with nxdomain, even when there is local data */ /** answer with nxdomain, even when there is local data */
local_zone_always_nxdomain, local_zone_always_nxdomain,
/** answer with noerror/nodata, even when there is local data */
local_zone_always_nodata,
/** drop query, even when there is local data */
local_zone_always_deny,
/** answer not from the view, but global or no-answer */ /** answer not from the view, but global or no-answer */
local_zone_noview local_zone_noview,
/** Invalid type, cannot be used to generate answer */
local_zone_invalid
}; };
/** /**
@ -310,6 +317,25 @@ int local_zones_answer(struct local_zones* zones, struct module_env* env,
struct config_strlist** tag_datas, size_t tag_datas_size, struct config_strlist** tag_datas, size_t tag_datas_size,
char** tagname, int num_tags, struct view* view); char** tagname, int num_tags, struct view* view);
/**
* Answer using the local zone only (not local data used).
* @param z: zone for query.
* @param env: module environment.
* @param qinfo: query.
* @param edns: edns from query.
* @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
* @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
* @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type);
/** /**
* Parse the string into localzone type. * Parse the string into localzone type.
* *
@ -340,6 +366,22 @@ const char* local_zone_type2str(enum localzone_type t);
struct local_zone* local_zones_find(struct local_zones* zones, struct local_zone* local_zones_find(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass); uint8_t* name, size_t len, int labs, uint16_t dclass);
/**
* Find zone that with exactly or smaller name/class
* User must lock the tree or result zone.
* @param zones: the zones tree
* @param name: dname to lookup
* @param len: length of name.
* @param labs: labelcount of name.
* @param dclass: class to lookup.
* @param exact: 1 on return is this is an exact match.
* @return the exact or smaller local_zone or NULL.
*/
struct local_zone*
local_zones_find_le(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
int* exact);
/** /**
* Add a new zone. Caller must hold the zones lock. * Add a new zone. Caller must hold the zones lock.
* Adjusts the other zones as well (parent pointers) after insertion. * Adjusts the other zones as well (parent pointers) after insertion.
@ -473,6 +515,15 @@ int rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
int rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd, int rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr); uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr);
/**
* Remove RR from rrset that is created using localzone's rrset_insert_rr.
* @param pd: the RRset containing the RR to remove
* @param index: index of RR to remove
* @return: 1 on success; 0 otherwise.
*/
int
local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index);
/** /**
* Valid response ip actions for the IP-response-driven-action feature; * Valid response ip actions for the IP-response-driven-action feature;
* defined here instead of in the respip module to enable sharing of enum * defined here instead of in the respip module to enable sharing of enum
@ -501,6 +552,10 @@ enum respip_action {
respip_always_refuse = local_zone_always_refuse, respip_always_refuse = local_zone_always_refuse,
/** answer with 'no such domain' response */ /** answer with 'no such domain' response */
respip_always_nxdomain = local_zone_always_nxdomain, respip_always_nxdomain = local_zone_always_nxdomain,
/** answer with nodata response */
respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */
respip_always_deny = local_zone_always_deny,
/* The rest of the values are only possible as /* The rest of the values are only possible as
* access-control-tag-action */ * access-control-tag-action */
@ -513,6 +568,64 @@ enum respip_action {
respip_transparent = local_zone_transparent, respip_transparent = local_zone_transparent,
/** gives response data (if any), else nodata answer. */ /** gives response data (if any), else nodata answer. */
respip_typetransparent = local_zone_typetransparent, respip_typetransparent = local_zone_typetransparent,
/** type invalid */
respip_invalid = local_zone_invalid,
}; };
/**
* Get local data from local zone and encode answer.
* @param z: local zone to use
* @param env: module env
* @param qinfo: qinfo
* @param edns: edns data, for message encoding
* @param repinfo: reply info, for message encoding
* @param buf: commpoint buffer
* @param temp: scratchpad region
* @param labs: number of labels in qname
* @param ldp: where to store local data
* @param lz_type: type of local zone
* @param tag: matching tag index
* @param tag_datas: alc specific tag data list
* @param tag_datas_size: size of tag_datas
* @param tagname: list of names of tags, for logging purpose
* @param num_tags: number of tags
* @return 1 on success
*/
int
local_data_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags);
/**
* Add RR to local zone.
* @param z: local zone to add RR to
* @param nm: dname of RR
* @param nmlen: length of nm
* @param nmlabs: number of labels of nm
* @param rrtype: RR type
* @param rrclass: RR class
* @param ttl: TTL of RR to add
* @param rdata: RDATA of RR to add
* @param rdata_len: length of rdata
* @param rrstr: RR in string format, for logging
* @return: 1 on success
*/
int
local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata, size_t rdata_len, const char* rrstr);
/**
* Find a data node by exact name for a local zone
* @param z: local_zone containing data tree
* @param nm: name of local-data element to find
* @param nmlen: length of nm
* @param nmlabs: labs of nm
* @return local_data on exact match, NULL otherwise.
*/
struct local_data*
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs);
#endif /* SERVICES_LOCALZONE_H */ #endif /* SERVICES_LOCALZONE_H */

View File

@ -46,6 +46,7 @@
#include "services/mesh.h" #include "services/mesh.h"
#include "services/outbound_list.h" #include "services/outbound_list.h"
#include "services/cache/dns.h" #include "services/cache/dns.h"
#include "services/cache/rrset.h"
#include "util/log.h" #include "util/log.h"
#include "util/net_help.h" #include "util/net_help.h"
#include "util/module.h" #include "util/module.h"
@ -127,7 +128,7 @@ timeval_smaller(const struct timeval* x, const struct timeval* y)
#endif #endif
} }
/* /**
* Compare two response-ip client info entries for the purpose of mesh state * Compare two response-ip client info entries for the purpose of mesh state
* compare. It returns 0 if ci_a and ci_b are considered equal; otherwise * compare. It returns 0 if ci_a and ci_b are considered equal; otherwise
* 1 or -1 (they mean 'ci_a is larger/smaller than ci_b', respectively, but * 1 or -1 (they mean 'ci_a is larger/smaller than ci_b', respectively, but
@ -250,6 +251,7 @@ mesh_create(struct module_stack* stack, struct module_env* env)
mesh->num_forever_states = 0; mesh->num_forever_states = 0;
mesh->stats_jostled = 0; mesh->stats_jostled = 0;
mesh->stats_dropped = 0; mesh->stats_dropped = 0;
mesh->ans_expired = 0;
mesh->max_reply_states = env->cfg->num_queries_per_thread; mesh->max_reply_states = env->cfg->num_queries_per_thread;
mesh->max_forever_states = (mesh->max_reply_states+1)/2; mesh->max_forever_states = (mesh->max_reply_states+1)/2;
#ifndef S_SPLINT_S #ifndef S_SPLINT_S
@ -345,6 +347,97 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
return 0; return 0;
} }
struct dns_msg*
mesh_serve_expired_lookup(struct module_qstate* qstate,
struct query_info* lookup_qinfo)
{
hashvalue_type h;
struct lruhash_entry* e;
struct dns_msg* msg;
struct reply_info* data;
struct msgreply_entry* key;
time_t timenow = *qstate->env->now;
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
/* Lookup cache */
h = query_info_hash(lookup_qinfo, qstate->query_flags);
e = slabhash_lookup(qstate->env->msg_cache, h, lookup_qinfo, 0);
if(!e) return NULL;
key = (struct msgreply_entry*)e->key;
data = (struct reply_info*)e->data;
msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow,
qstate->env->cfg->serve_expired, qstate->env->scratch);
if(!msg)
goto bail_out;
/* Check CNAME chain (if any)
* This is part of tomsg above; no need to check now. */
/* Check security status of the cached answer.
* tomsg above has a subset of these checks, so we are leaving
* these as is.
* In case of bogus or revalidation we don't care to reply here. */
if(must_validate && (msg->rep->security == sec_status_bogus ||
msg->rep->security == sec_status_secure_sentinel_fail)) {
verbose(VERB_ALGO, "Serve expired: bogus answer found in cache");
goto bail_out;
} else if(msg->rep->security == sec_status_unchecked && must_validate) {
verbose(VERB_ALGO, "Serve expired: unchecked entry needs "
"validation");
goto bail_out; /* need to validate cache entry first */
} else if(msg->rep->security == sec_status_secure &&
!reply_all_rrsets_secure(msg->rep) && must_validate) {
verbose(VERB_ALGO, "Serve expired: secure entry"
" changed status");
goto bail_out; /* rrset changed, re-verify */
}
lock_rw_unlock(&e->lock);
return msg;
bail_out:
lock_rw_unlock(&e->lock);
return NULL;
}
/** Init the serve expired data structure */
static int
mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
{
struct timeval t;
/* Create serve_expired_data if not there yet */
if(!mstate->s.serve_expired_data) {
mstate->s.serve_expired_data = (struct serve_expired_data*)
regional_alloc_zero(
mstate->s.region, sizeof(struct serve_expired_data));
if(!mstate->s.serve_expired_data)
return 0;
}
/* Don't overwrite the function if already set */
mstate->s.serve_expired_data->get_cached_answer =
mstate->s.serve_expired_data->get_cached_answer?
mstate->s.serve_expired_data->get_cached_answer:
mesh_serve_expired_lookup;
/* In case this timer already popped, start it again */
if(!mstate->s.serve_expired_data->timer) {
mstate->s.serve_expired_data->timer = comm_timer_create(
mstate->s.env->worker_base, mesh_serve_expired_callback, mstate);
if(!mstate->s.serve_expired_data->timer)
return 0;
#ifndef S_SPLINT_S
t.tv_sec = timeout/1000;
t.tv_usec = (timeout%1000)*1000;
#endif
comm_timer_set(mstate->s.serve_expired_data->timer, &t);
}
return 1;
}
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags, struct respip_client_info* cinfo, uint16_t qflags,
struct edns_data* edns, struct comm_reply* rep, uint16_t qid) struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
@ -354,6 +447,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
int was_detached = 0; int was_detached = 0;
int was_noreply = 0; int was_noreply = 0;
int added = 0; int added = 0;
int timeout = mesh->env->cfg->serve_expired?
mesh->env->cfg->serve_expired_client_timeout:0;
struct sldns_buffer* r_buffer = rep->c->buffer; struct sldns_buffer* r_buffer = rep->c->buffer;
if(rep->c->tcp_req_info) { if(rep->c->tcp_req_info) {
r_buffer = rep->c->tcp_req_info->spool_buffer; r_buffer = rep->c->tcp_req_info->spool_buffer;
@ -366,7 +461,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
verbose(VERB_ALGO, "Too many queries. dropping " verbose(VERB_ALGO, "Too many queries. dropping "
"incoming query."); "incoming query.");
comm_point_drop_reply(rep); comm_point_drop_reply(rep);
mesh->stats_dropped ++; mesh->stats_dropped++;
return; return;
} }
/* for this new reply state, the reply address is free, /* for this new reply state, the reply address is free,
@ -376,8 +471,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(mesh->num_reply_addrs > mesh->max_reply_states*16) { if(mesh->num_reply_addrs > mesh->max_reply_states*16) {
verbose(VERB_ALGO, "Too many requests queued. " verbose(VERB_ALGO, "Too many requests queued. "
"dropping incoming query."); "dropping incoming query.");
mesh->stats_dropped++;
comm_point_drop_reply(rep); comm_point_drop_reply(rep);
mesh->stats_dropped++;
return; return;
} }
} }
@ -427,23 +522,16 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
mesh->num_detached_states++; mesh->num_detached_states++;
added = 1; added = 1;
} }
if(!s->reply_list && !s->cb_list && s->super_set.count == 0) if(!s->reply_list && !s->cb_list) {
was_detached = 1;
if(!s->reply_list && !s->cb_list)
was_noreply = 1; was_noreply = 1;
if(s->super_set.count == 0) {
was_detached = 1;
}
}
/* add reply to s */ /* add reply to s */
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
log_err("mesh_new_client: out of memory; SERVFAIL"); log_err("mesh_new_client: out of memory; SERVFAIL");
servfail_mem: goto servfail_mem;
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
if(added)
mesh_state_delete(&s->s);
return;
} }
if(rep->c->tcp_req_info) { if(rep->c->tcp_req_info) {
if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) { if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) {
@ -451,6 +539,11 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
goto servfail_mem; goto servfail_mem;
} }
} }
/* add serve expired timer if required and not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) {
log_err("mesh_new_client: out of memory initializing serve expired");
goto servfail_mem;
}
/* update statistics */ /* update statistics */
if(was_detached) { if(was_detached) {
log_assert(mesh->num_detached_states > 0); log_assert(mesh->num_detached_states > 0);
@ -475,6 +568,18 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
} }
if(added) if(added)
mesh_run(mesh, s, module_event_new, NULL); mesh_run(mesh, s, module_event_new, NULL);
return;
servfail_mem:
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
comm_point_send_reply(rep);
if(added)
mesh_state_delete(&s->s);
return;
} }
int int
@ -484,6 +589,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
{ {
struct mesh_state* s = NULL; struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list, mesh->env); int unique = unique_mesh_state(edns->opt_list, mesh->env);
int timeout = mesh->env->cfg->serve_expired?
mesh->env->cfg->serve_expired_client_timeout:0;
int was_detached = 0; int was_detached = 0;
int was_noreply = 0; int was_noreply = 0;
int added = 0; int added = 0;
@ -522,15 +629,21 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
mesh->num_detached_states++; mesh->num_detached_states++;
added = 1; added = 1;
} }
if(!s->reply_list && !s->cb_list && s->super_set.count == 0) if(!s->reply_list && !s->cb_list) {
was_detached = 1;
if(!s->reply_list && !s->cb_list)
was_noreply = 1; was_noreply = 1;
if(s->super_set.count == 0) {
was_detached = 1;
}
}
/* add reply to s */ /* add reply to s */
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) { if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
if(added) if(added)
mesh_state_delete(&s->s); mesh_state_delete(&s->s);
return 0; return 0;
}
/* add serve expired timer if not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) {
return 0;
} }
/* update statistics */ /* update statistics */
if(was_detached) { if(was_detached) {
@ -546,15 +659,6 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
return 1; return 1;
} }
static void mesh_schedule_prefetch(struct mesh_area* mesh,
struct query_info* qinfo, uint16_t qflags, time_t leeway, int run);
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway)
{
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
}
/* Internal backend routine of mesh_new_prefetch(). It takes one additional /* Internal backend routine of mesh_new_prefetch(). It takes one additional
* parameter, 'run', which controls whether to run the prefetch state * parameter, 'run', which controls whether to run the prefetch state
* immediately. When this function is called internally 'run' could be * immediately. When this function is called internally 'run' could be
@ -631,6 +735,12 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
mesh_run(mesh, s, module_event_new, NULL); mesh_run(mesh, s, module_event_new, NULL);
} }
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, time_t leeway)
{
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
}
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
struct comm_reply* reply, int what) struct comm_reply* reply, int what)
{ {
@ -703,6 +813,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
mstate->s.env = env; mstate->s.env = env;
mstate->s.mesh_info = mstate; mstate->s.mesh_info = mstate;
mstate->s.prefetch_leeway = 0; mstate->s.prefetch_leeway = 0;
mstate->s.serve_expired_data = NULL;
mstate->s.no_cache_lookup = 0; mstate->s.no_cache_lookup = 0;
mstate->s.no_cache_store = 0; mstate->s.no_cache_store = 0;
mstate->s.need_refetch = 0; mstate->s.need_refetch = 0;
@ -742,6 +853,11 @@ mesh_state_cleanup(struct mesh_state* mstate)
if(!mstate) if(!mstate)
return; return;
mesh = mstate->s.env->mesh; mesh = mstate->s.env->mesh;
/* Stop and delete the serve expired timer */
if(mstate->s.serve_expired_data && mstate->s.serve_expired_data->timer) {
comm_timer_delete(mstate->s.serve_expired_data->timer);
mstate->s.serve_expired_data->timer = NULL;
}
/* drop unsent replies */ /* drop unsent replies */
if(!mstate->replies_sent) { if(!mstate->replies_sent) {
struct mesh_reply* rep = mstate->reply_list; struct mesh_reply* rep = mstate->reply_list;
@ -752,6 +868,7 @@ mesh_state_cleanup(struct mesh_state* mstate)
mstate->reply_list = NULL; mstate->reply_list = NULL;
for(; rep; rep=rep->next) { for(; rep; rep=rep->next) {
comm_point_drop_reply(&rep->query_reply); comm_point_drop_reply(&rep->query_reply);
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--; mesh->num_reply_addrs--;
} }
while((cb = mstate->cb_list)!=NULL) { while((cb = mstate->cb_list)!=NULL) {
@ -759,6 +876,7 @@ mesh_state_cleanup(struct mesh_state* mstate)
fptr_ok(fptr_whitelist_mesh_cb(cb->cb)); fptr_ok(fptr_whitelist_mesh_cb(cb->cb));
(*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL, (*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL,
sec_status_unchecked, NULL, 0); sec_status_unchecked, NULL, 0);
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--; mesh->num_reply_addrs--;
} }
} }
@ -826,7 +944,7 @@ find_in_subsub(struct mesh_state* m, struct mesh_state* tofind, size_t *c)
} }
/** find cycle for already looked up mesh_state */ /** find cycle for already looked up mesh_state */
static int static int
mesh_detect_cycle_found(struct module_qstate* qstate, struct mesh_state* dep_m) mesh_detect_cycle_found(struct module_qstate* qstate, struct mesh_state* dep_m)
{ {
struct mesh_state* cyc_m = qstate->mesh_info; struct mesh_state* cyc_m = qstate->mesh_info;
@ -1038,6 +1156,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
} }
} }
free(reason); free(reason);
log_assert(m->s.env->mesh->num_reply_addrs > 0);
m->s.env->mesh->num_reply_addrs--; m->s.env->mesh->num_reply_addrs--;
} }
@ -1139,6 +1258,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
comm_point_send_reply(&r->query_reply); comm_point_send_reply(&r->query_reply);
} }
/* account */ /* account */
log_assert(m->s.env->mesh->num_reply_addrs > 0);
m->s.env->mesh->num_reply_addrs--; m->s.env->mesh->num_reply_addrs--;
end_time = *m->s.env->now_tv; end_time = *m->s.env->now_tv;
timeval_subtract(&duration, &end_time, &r->start_time); timeval_subtract(&duration, &end_time, &r->start_time);
@ -1164,37 +1284,76 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
void mesh_query_done(struct mesh_state* mstate) void mesh_query_done(struct mesh_state* mstate)
{ {
struct mesh_reply* r; struct mesh_reply* r, *reply_list = NULL;
struct mesh_reply* prev = NULL; struct mesh_reply* prev = NULL;
struct sldns_buffer* prev_buffer = NULL; struct sldns_buffer* prev_buffer = NULL;
struct mesh_cb* c; struct mesh_cb* c;
struct reply_info* rep = (mstate->s.return_msg? struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL); mstate->s.return_msg->rep:NULL);
if((mstate->s.return_rcode == LDNS_RCODE_SERVFAIL || /* No need for the serve expired timer anymore; we are going to reply. */
(rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) if(mstate->s.serve_expired_data) {
comm_timer_delete(mstate->s.serve_expired_data->timer);
mstate->s.serve_expired_data->timer = NULL;
}
if(mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
(rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) {
/* we are SERVFAILing; check for expired asnwer here */
mesh_serve_expired_callback(mstate);
if((mstate->reply_list || mstate->cb_list)
&& mstate->s.env->cfg->log_servfail && mstate->s.env->cfg->log_servfail
&& !mstate->s.env->cfg->val_log_squelch) { && !mstate->s.env->cfg->val_log_squelch) {
char* err = errinf_to_str_servfail(&mstate->s); char* err = errinf_to_str_servfail(&mstate->s);
if(err) if(err)
log_err("%s", err); log_err("%s", err);
free(err); free(err);
}
} }
for(r = mstate->reply_list; r; r = r->next) { if(mstate->reply_list) {
/* set the reply_list to NULL during the mesh_query_done
* processing, so that calls back into the mesh from
* tcp_req_info (deciding to drop the reply and thus
* unregister the mesh_reply from the mstate) are stopped
* because the list is empty.
* The mstate is then likely not a reply_state, and maybe
* also a detached_state.
*/
reply_list = mstate->reply_list;
mstate->reply_list = NULL;
if(!mstate->reply_list && !mstate->cb_list) {
/* was a reply state, not anymore */
log_assert(mstate->s.env->mesh->num_reply_states > 0);
mstate->s.env->mesh->num_reply_states--;
}
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
mstate->s.env->mesh->num_detached_states++;
}
for(r = reply_list; r; r = r->next) {
/* if a response-ip address block has been stored the /* if a response-ip address block has been stored the
* information should be logged for each client. */ * information should be logged for each client. */
if(mstate->s.respip_action_info && if(mstate->s.respip_action_info &&
mstate->s.respip_action_info->addrinfo) { mstate->s.respip_action_info->addrinfo) {
respip_inform_print(mstate->s.respip_action_info->addrinfo, respip_inform_print(mstate->s.respip_action_info,
r->qname, mstate->s.qinfo.qtype, r->qname, mstate->s.qinfo.qtype,
mstate->s.qinfo.qclass, r->local_alias, mstate->s.qinfo.qclass, r->local_alias,
&r->query_reply); &r->query_reply);
if(mstate->s.env->cfg->stat_extended &&
mstate->s.respip_action_info->rpz_used) {
if(mstate->s.respip_action_info->rpz_disabled)
mstate->s.env->mesh->rpz_action[RPZ_DISABLED_ACTION]++;
if(mstate->s.respip_action_info->rpz_cname_override)
mstate->s.env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
else
mstate->s.env->mesh->rpz_action[respip_action_to_rpz_action(
mstate->s.respip_action_info->action)]++;
}
} }
/* if this query is determined to be dropped during the /* if this query is determined to be dropped during the
* mesh processing, this is the point to take that action. */ * mesh processing, this is the point to take that action. */
if(mstate->s.is_drop) if(mstate->s.is_drop) {
comm_point_drop_reply(&r->query_reply); comm_point_drop_reply(&r->query_reply);
else { } else {
struct sldns_buffer* r_buffer = r->query_reply.c->buffer; struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
if(r->query_reply.c->tcp_req_info) { if(r->query_reply.c->tcp_req_info) {
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
@ -1216,6 +1375,7 @@ void mesh_query_done(struct mesh_state* mstate)
* changed, eg. by adds from the callback routine */ * changed, eg. by adds from the callback routine */
if(!mstate->reply_list && mstate->cb_list && !c->next) { if(!mstate->reply_list && mstate->cb_list && !c->next) {
/* was a reply state, not anymore */ /* was a reply state, not anymore */
log_assert(mstate->s.env->mesh->num_reply_states > 0);
mstate->s.env->mesh->num_reply_states--; mstate->s.env->mesh->num_reply_states--;
} }
mstate->cb_list = c->next; mstate->cb_list = c->next;
@ -1581,7 +1741,9 @@ mesh_stats_clear(struct mesh_area* mesh)
timehist_clear(mesh->histogram); timehist_clear(mesh->histogram);
mesh->ans_secure = 0; mesh->ans_secure = 0;
mesh->ans_bogus = 0; mesh->ans_bogus = 0;
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*16); mesh->ans_expired = 0;
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*UB_STATS_RCODE_NUM);
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
mesh->ans_nodata = 0; mesh->ans_nodata = 0;
} }
@ -1647,6 +1809,7 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
if(prev) prev->next = n->next; if(prev) prev->next = n->next;
else m->reply_list = n->next; else m->reply_list = n->next;
/* delete it, but allocated in m region */ /* delete it, but allocated in m region */
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--; mesh->num_reply_addrs--;
/* prev = prev; */ /* prev = prev; */
@ -1667,3 +1830,176 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
mesh->num_reply_states--; mesh->num_reply_states--;
} }
} }
static int
apply_respip_action(struct module_qstate* qstate,
const struct query_info* qinfo, struct respip_client_info* cinfo,
struct respip_action_info* actinfo, struct reply_info* rep,
struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
{
if(qinfo->qtype != LDNS_RR_TYPE_A &&
qinfo->qtype != LDNS_RR_TYPE_AAAA &&
qinfo->qtype != LDNS_RR_TYPE_ANY)
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo,
alias_rrset, 0, qstate->region, az))
return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply
* was redirected to response-ip data. */
if((actinfo->action == respip_deny ||
actinfo->action == respip_inform_deny) &&
*encode_repp == rep)
*encode_repp = NULL;
return 1;
}
void
mesh_serve_expired_callback(void* arg)
{
struct mesh_state* mstate = (struct mesh_state*) arg;
struct module_qstate* qstate = &mstate->s;
struct mesh_reply* r;
struct mesh_area* mesh = qstate->env->mesh;
struct dns_msg* msg;
struct mesh_cb* c;
struct mesh_reply* prev = NULL;
struct sldns_buffer* prev_buffer = NULL;
struct sldns_buffer* r_buffer = NULL;
struct reply_info* partial_rep = NULL;
struct ub_packed_rrset_key* alias_rrset = NULL;
struct reply_info* encode_rep = NULL;
struct respip_action_info actinfo;
struct query_info* lookup_qinfo = &qstate->qinfo;
struct query_info qinfo_tmp;
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
if(!qstate->serve_expired_data) return;
verbose(VERB_ALGO, "Serve expired: Trying to reply with expired data");
comm_timer_delete(qstate->serve_expired_data->timer);
qstate->serve_expired_data->timer = NULL;
if(qstate->blacklist || qstate->no_cache_lookup || qstate->is_drop) {
verbose(VERB_ALGO,
"Serve expired: Not allowed to look into cache for stale");
return;
}
/* The following while is used instead of the `goto lookup_cache`
* like in the worker. */
while(1) {
fptr_ok(fptr_whitelist_serve_expired_lookup(
qstate->serve_expired_data->get_cached_answer));
msg = qstate->serve_expired_data->get_cached_answer(qstate,
lookup_qinfo);
if(!msg)
return;
/* Reset these in case we pass a second time from here. */
encode_rep = msg->rep;
memset(&actinfo, 0, sizeof(actinfo));
actinfo.action = respip_none;
alias_rrset = NULL;
if((mesh->use_response_ip || mesh->use_rpz) &&
!partial_rep && !apply_respip_action(qstate, &qstate->qinfo,
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
qstate->env->auth_zones)) {
return;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
qstate->client_info, must_validate, &encode_rep, qstate->region,
qstate->env->auth_zones)) {
return;
}
if(!encode_rep || alias_rrset) {
if(!encode_rep) {
/* Needs drop */
return;
} else {
/* A partial CNAME chain is found. */
partial_rep = encode_rep;
}
}
/* We've found a partial reply ending with an
* alias. Replace the lookup qinfo for the
* alias target and lookup the cache again to
* (possibly) complete the reply. As we're
* passing the "base" reply, there will be no
* more alias chasing. */
if(partial_rep) {
memset(&qinfo_tmp, 0, sizeof(qinfo_tmp));
get_cname_target(alias_rrset, &qinfo_tmp.qname,
&qinfo_tmp.qname_len);
if(!qinfo_tmp.qname) {
log_err("Serve expired: unexpected: invalid answer alias");
return;
}
qinfo_tmp.qtype = qstate->qinfo.qtype;
qinfo_tmp.qclass = qstate->qinfo.qclass;
lookup_qinfo = &qinfo_tmp;
continue;
}
break;
}
if(verbosity >= VERB_ALGO)
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
r = mstate->reply_list;
mstate->reply_list = NULL;
if(!mstate->reply_list && !mstate->cb_list) {
log_assert(mesh->num_reply_states > 0);
mesh->num_reply_states--;
if(mstate->super_set.count == 0) {
mesh->num_detached_states++;
}
}
for(; r; r = r->next) {
/* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) {
respip_inform_print(&actinfo, r->qname,
qstate->qinfo.qtype, qstate->qinfo.qclass,
r->local_alias, &r->query_reply);
if(qstate->env->cfg->stat_extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
qstate->env->mesh->rpz_action[RPZ_DISABLED_ACTION]++;
if(actinfo.rpz_cname_override)
qstate->env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
else
qstate->env->mesh->rpz_action[
respip_action_to_rpz_action(actinfo.action)]++;
}
}
r_buffer = r->query_reply.c->buffer;
if(r->query_reply.c->tcp_req_info)
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep,
r, r_buffer, prev, prev_buffer);
if(r->query_reply.c->tcp_req_info)
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
prev = r;
prev_buffer = r_buffer;
/* Account for each reply sent. */
mesh->ans_expired++;
}
while((c = mstate->cb_list) != NULL) {
/* take this cb off the list; so that the list can be
* changed, eg. by adds from the callback routine */
if(!mstate->reply_list && mstate->cb_list && !c->next) {
/* was a reply state, not anymore */
log_assert(qstate->env->mesh->num_reply_states > 0);
qstate->env->mesh->num_reply_states--;
}
mstate->cb_list = c->next;
if(!mstate->reply_list && !mstate->cb_list &&
mstate->super_set.count == 0)
qstate->env->mesh->num_detached_states++;
mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c);
}
}

View File

@ -51,6 +51,8 @@
#include "util/data/msgparse.h" #include "util/data/msgparse.h"
#include "util/module.h" #include "util/module.h"
#include "services/modstack.h" #include "services/modstack.h"
#include "services/rpz.h"
#include "libunbound/unbound.h"
struct sldns_buffer; struct sldns_buffer;
struct mesh_state; struct mesh_state;
struct mesh_reply; struct mesh_reply;
@ -110,6 +112,8 @@ struct mesh_area {
size_t stats_jostled; size_t stats_jostled;
/** stats, cumulative number of incoming client msgs dropped */ /** stats, cumulative number of incoming client msgs dropped */
size_t stats_dropped; size_t stats_dropped;
/** stats, number of expired replies sent */
size_t ans_expired;
/** number of replies sent */ /** number of replies sent */
size_t replies_sent; size_t replies_sent;
/** sum of waiting times for the replies */ /** sum of waiting times for the replies */
@ -121,9 +125,11 @@ struct mesh_area {
/** (extended stats) bogus replies */ /** (extended stats) bogus replies */
size_t ans_bogus; size_t ans_bogus;
/** (extended stats) rcodes in replies */ /** (extended stats) rcodes in replies */
size_t ans_rcode[16]; size_t ans_rcode[UB_STATS_RCODE_NUM];
/** (extended stats) rcode nodata in replies */ /** (extended stats) rcode nodata in replies */
size_t ans_nodata; size_t ans_nodata;
/** (extended stats) type of applied RPZ action */
size_t rpz_action[UB_STATS_RPZ_ACTION_NUM];
/** backup of query if other operations recurse and need the /** backup of query if other operations recurse and need the
* network buffers */ * network buffers */
@ -142,6 +148,11 @@ struct mesh_area {
struct mesh_state* jostle_last; struct mesh_state* jostle_last;
/** timeout for jostling. if age is lower, it does not get jostled. */ /** timeout for jostling. if age is lower, it does not get jostled. */
struct timeval jostle_max; struct timeval jostle_max;
/** If we need to use response ip (value passed from daemon)*/
int use_response_ip;
/** If we need to use RPZ (value passed from daemon) */
int use_rpz;
}; };
/** /**
@ -643,4 +654,22 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
struct comm_point* cp); struct comm_point* cp);
/** Callback for when the serve expired client timer has run out. Tries to
* find an expired answer in the cache and reply that to the client.
* @param arg: the argument passed to the callback.
*/
void mesh_serve_expired_callback(void* arg);
/**
* Try to get a (expired) cached answer.
* This needs to behave like the worker's answer_from_cache() in order to have
* the same behavior as when replying from cache.
* @param qstate: the module qstate.
* @param lookup_qinfo: the query info to look for in the cache.
* @return dns_msg if a cached answer was found, otherwise NULL.
*/
struct dns_msg*
mesh_serve_expired_lookup(struct module_qstate* qstate,
struct query_info* lookup_qinfo);
#endif /* SERVICES_MESH_H */ #endif /* SERVICES_MESH_H */

View File

@ -293,6 +293,9 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
/* open socket */ /* open socket */
s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss); s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss);
if(s == -1)
return 0;
if(!pick_outgoing_tcp(w, s)) if(!pick_outgoing_tcp(w, s))
return 0; return 0;
@ -1971,7 +1974,6 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
sq->pending = NULL; /* removed after callback */ sq->pending = NULL; /* removed after callback */
if(error == NETEVENT_TIMEOUT) { if(error == NETEVENT_TIMEOUT) {
int rto = 0;
if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000) { if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000) {
/* fallback to 1480/1280 */ /* fallback to 1480/1280 */
sq->status = serviced_query_UDP_EDNS_FRAG; sq->status = serviced_query_UDP_EDNS_FRAG;
@ -1987,9 +1989,9 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
sq->status = serviced_query_UDP_EDNS; sq->status = serviced_query_UDP_EDNS;
} }
sq->retry++; sq->retry++;
if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen, if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
sq->zone, sq->zonelen, sq->qtype, -1, sq->last_rtt, sq->zone, sq->zonelen, sq->qtype, -1, sq->last_rtt,
(time_t)now.tv_sec))) (time_t)now.tv_sec))
log_err("out of memory in UDP exponential backoff"); log_err("out of memory in UDP exponential backoff");
if(sq->retry < OUTBOUND_UDP_RETRY) { if(sq->retry < OUTBOUND_UDP_RETRY) {
log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10, log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,201 @@
/*
* services/rpz.h - rpz service
*
* Copyright (c) 2019, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to enable RPZ service.
*/
#ifndef SERVICES_RPZ_H
#define SERVICES_RPZ_H
#include "services/localzone.h"
#include "util/locks.h"
#include "util/log.h"
#include "util/config_file.h"
#include "services/authzone.h"
#include "sldns/sbuffer.h"
#include "daemon/stats.h"
#include "respip/respip.h"
/**
* RPZ triggers, only the QNAME trigger is currently supported in Unbound.
*/
enum rpz_trigger {
RPZ_QNAME_TRIGGER = 0,
/* unsupported triggers */
RPZ_CLIENT_IP_TRIGGER, /* rpz-client-ip */
RPZ_RESPONSE_IP_TRIGGER, /* rpz-ip */
RPZ_NSDNAME_TRIGGER, /* rpz-nsdname */
RPZ_NSIP_TRIGGER, /* rpz-nsip */
RPZ_INVALID_TRIGGER, /* dname does not contain valid trigger */
};
/**
* RPZ actions.
*/
enum rpz_action {
RPZ_NXDOMAIN_ACTION = 0,/* CNAME . */
RPZ_NODATA_ACTION, /* CNAME *. */
RPZ_PASSTHRU_ACTION, /* CNAME rpz-passthru. */
RPZ_DROP_ACTION, /* CNAME rpz-drop. */
RPZ_TCP_ONLY_ACTION, /* CNAME rpz-tcp-only. */
RPZ_INVALID_ACTION, /* CNAME with (child of) TLD starting with
"rpz-" in target, SOA, NS, DNAME and
DNSSEC-related records. */
RPZ_LOCAL_DATA_ACTION, /* anything else */
/* RPZ override actions */
RPZ_DISABLED_ACTION, /* RPZ action disabled using override */
RPZ_NO_OVERRIDE_ACTION, /* RPZ action no override*/
RPZ_CNAME_OVERRIDE_ACTION, /* RPZ CNAME action override*/
};
/**
* RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
* linked list to keep configuration order. Iterating or changing the linked
* list requires the rpz_lock from struct auth_zones.
*/
struct rpz {
struct local_zones* local_zones;
struct respip_set* respip_set;
uint8_t* taglist;
size_t taglistlen;
enum rpz_action action_override;
struct ub_packed_rrset_key* cname_override;
int log;
char* log_name;
struct rpz* next;
struct rpz* prev;
struct regional* region;
};
/**
* Create policy from RR and add to this RPZ.
* @param r: the rpz to add the policy to.
* @param aznamelen: the length of the auth-zone name
* @param dname: dname of the RR
* @param dnamelen: length of the dname
* @param rr_type: RR type of the RR
* @param rr_class: RR class of the RR
* @param rr_ttl: TTL of the RR
* @param rdatawl: rdata of the RR, prepended with the rdata size
* @param rdatalen: length if the RR, including the prepended rdata size
* @param rr: the complete RR, for logging purposes
* @param rr_len: the length of the complete RR
* @return: 0 on error
*/
int rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len);
/**
* Delete policy matching RR, used for IXFR.
* @param r: the rpz to add the policy to.
* @param aznamelen: the length of the auth-zone name
* @param dname: dname of the RR
* @param dnamelen: length of the dname
* @param rr_type: RR type of the RR
* @param rr_class: RR class of the RR
* @param rdatawl: rdata of the RR, prepended with the rdata size
* @param rdatalen: length if the RR, including the prepended rdata size
*/
void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl,
size_t rdatalen);
/**
* Walk over the RPZ zones to find and apply a QNAME trigger policy.
* @param az: auth_zones struct, containing first RPZ item and RPZ lock
* @param env: module env
* @param qinfo: qinfo containing qname and qtype
* @param edns: edns data
* @param buf: buffer to write answer to
* @param temp: scratchpad
* @param repinfo: reply info
* @param taglist: taglist to lookup.
* @param taglen: lenth of taglist.
* @param stats: worker stats struct
* @return: 1 if client answer is ready, 0 to continue resolving
*/
int rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
/**
* Delete RPZ
* @param r: RPZ struct to delete
*/
void rpz_delete(struct rpz* r);
/**
* Clear local-zones and respip data in RPZ, used after reloading file or
* AXFR/HTTP transfer.
* @param r: RPZ to use
*/
int rpz_clear(struct rpz* r);
/**
* Create RPZ. RPZ must be added to linked list after creation.
* @return: the newly created RPZ
*/
struct rpz* rpz_create(struct config_auth* p);
/**
* String for RPZ action enum
* @param a: RPZ action to get string for
* @return: string for RPZ action
*/
const char* rpz_action_to_string(enum rpz_action a);
enum rpz_action
respip_action_to_rpz_action(enum respip_action a);
/**
* Prepare RPZ after procesing feed content.
* @param r: RPZ to use
*/
void rpz_finish_config(struct rpz* r);
/**
* Classify respip action for RPZ action
* @param a: RPZ action
* @return: the respip action
*/
enum respip_action
rpz_action_to_respip_action(enum rpz_action a);
#endif /* SERVICES_RPZ_H */

View File

@ -198,8 +198,6 @@ views_apply_cfg(struct views* vs, struct config_file* cfg)
log_err("failed to insert " log_err("failed to insert "
"default zones into " "default zones into "
"local-zone list"); "local-zone list");
free(nd_str);
free(nd_type);
lock_rw_unlock(&v->lock); lock_rw_unlock(&v->lock);
return 0; return 0;
} }

View File

@ -120,7 +120,7 @@ sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l
if (line_nr) { if (line_nr) {
*line_nr = *line_nr + 1; *line_nr = *line_nr + 1;
} }
if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { if (limit > 0 && (i+1 >= limit || (size_t)(t-token)+1 >= limit)) {
*t = '\0'; *t = '\0';
return -1; return -1;
} }
@ -141,7 +141,8 @@ sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l
if (c != '\0' && c != '\n') { if (c != '\0' && c != '\n') {
i++; i++;
} }
if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { /* is there space for the character and the zero after it */
if (limit > 0 && (i+1 >= limit || (size_t)(t-token)+1 >= limit)) {
*t = '\0'; *t = '\0';
return -1; return -1;
} }
@ -326,8 +327,8 @@ sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
/* in parentheses */ /* in parentheses */
/* do not write ' ' if we want to skip spaces */ /* do not write ' ' if we want to skip spaces */
if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' ')))) { if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' ')))) {
/* check for space for the space character */ /* check for space for the space character and a zero delimiter after that. */
if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { if (limit > 0 && (i+1 >= limit || (size_t)(t-token)+1 >= limit)) {
*t = '\0'; *t = '\0';
return -1; return -1;
} }
@ -354,7 +355,7 @@ sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
} }
i++; i++;
if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { if (limit > 0 && (i+1 >= limit || (size_t)(t-token)+1 >= limit)) {
*t = '\0'; *t = '\0';
return -1; return -1;
} }

View File

@ -80,7 +80,7 @@ static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
for (s = str; *s; s++, q++) { for (s = str; *s; s++, q++) {
if (q >= buf + *olen) if (q >= buf + *olen)
return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf); return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
if (q > buf + LDNS_MAX_DOMAINLEN) if (q >= buf + LDNS_MAX_DOMAINLEN)
return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf); return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
switch (*s) { switch (*s) {
case '.': case '.':
@ -117,7 +117,7 @@ static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
if(rel) *rel = 1; if(rel) *rel = 1;
if (q >= buf + *olen) if (q >= buf + *olen)
return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf); return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
if (q > buf + LDNS_MAX_DOMAINLEN) { if (q >= buf + LDNS_MAX_DOMAINLEN) {
return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf); return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
} }
if (label_len > LDNS_MAX_LABELLEN) { if (label_len > LDNS_MAX_LABELLEN) {

View File

@ -548,10 +548,7 @@ morechecks(struct config_file* cfg)
/* check that the modules listed in module_conf exist */ /* check that the modules listed in module_conf exist */
check_modules_exist(cfg->module_conf); check_modules_exist(cfg->module_conf);
/* There should be no reason for 'respip' module not to work with /* Respip is known to *not* work with dns64. */
* dns64, but it's not explicitly confirmed, so the combination is
* excluded below. It's simply unknown yet for the combination of
* respip and other modules. */
if(strcmp(cfg->module_conf, "iterator") != 0 if(strcmp(cfg->module_conf, "iterator") != 0
&& strcmp(cfg->module_conf, "validator iterator") != 0 && strcmp(cfg->module_conf, "validator iterator") != 0
&& strcmp(cfg->module_conf, "dns64 validator iterator") != 0 && strcmp(cfg->module_conf, "dns64 validator iterator") != 0
@ -560,7 +557,9 @@ morechecks(struct config_file* cfg)
&& strcmp(cfg->module_conf, "respip validator iterator") != 0 && strcmp(cfg->module_conf, "respip validator iterator") != 0
#ifdef WITH_PYTHONMODULE #ifdef WITH_PYTHONMODULE
&& strcmp(cfg->module_conf, "python iterator") != 0 && strcmp(cfg->module_conf, "python iterator") != 0
&& strcmp(cfg->module_conf, "python respip iterator") != 0
&& strcmp(cfg->module_conf, "python validator iterator") != 0 && strcmp(cfg->module_conf, "python validator iterator") != 0
&& strcmp(cfg->module_conf, "python respip validator iterator") != 0
&& strcmp(cfg->module_conf, "validator python iterator") != 0 && strcmp(cfg->module_conf, "validator python iterator") != 0
&& strcmp(cfg->module_conf, "dns64 python iterator") != 0 && strcmp(cfg->module_conf, "dns64 python iterator") != 0
&& strcmp(cfg->module_conf, "dns64 python validator iterator") != 0 && strcmp(cfg->module_conf, "dns64 python validator iterator") != 0
@ -570,7 +569,9 @@ morechecks(struct config_file* cfg)
#endif #endif
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
&& strcmp(cfg->module_conf, "validator cachedb iterator") != 0 && strcmp(cfg->module_conf, "validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "respip validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "cachedb iterator") != 0 && strcmp(cfg->module_conf, "cachedb iterator") != 0
&& strcmp(cfg->module_conf, "respip cachedb iterator") != 0
&& strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0
#endif #endif
@ -580,39 +581,61 @@ morechecks(struct config_file* cfg)
&& strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0
&& strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0 && strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "python cachedb iterator") != 0 && strcmp(cfg->module_conf, "python cachedb iterator") != 0
&& strcmp(cfg->module_conf, "python respip cachedb iterator") != 0
&& strcmp(cfg->module_conf, "python validator cachedb iterator") != 0 && strcmp(cfg->module_conf, "python validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "python respip validator cachedb iterator") != 0
&& strcmp(cfg->module_conf, "cachedb python iterator") != 0 && strcmp(cfg->module_conf, "cachedb python iterator") != 0
&& strcmp(cfg->module_conf, "respip cachedb python iterator") != 0
&& strcmp(cfg->module_conf, "validator cachedb python iterator") != 0 && strcmp(cfg->module_conf, "validator cachedb python iterator") != 0
&& strcmp(cfg->module_conf, "respip validator cachedb python iterator") != 0
&& strcmp(cfg->module_conf, "validator python cachedb iterator") != 0 && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0
&& strcmp(cfg->module_conf, "respip validator python cachedb iterator") != 0
#endif #endif
#ifdef CLIENT_SUBNET #ifdef CLIENT_SUBNET
&& strcmp(cfg->module_conf, "subnetcache iterator") != 0 && strcmp(cfg->module_conf, "subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "respip subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache validator iterator") != 0 && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "respip subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "dns64 subnetcache iterator") != 0 && strcmp(cfg->module_conf, "dns64 subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "dns64 subnetcache validator iterator") != 0 && strcmp(cfg->module_conf, "dns64 subnetcache validator iterator") != 0
#endif #endif
#if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET) #if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
&& strcmp(cfg->module_conf, "python subnetcache iterator") != 0 && strcmp(cfg->module_conf, "python subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "python respip subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache python iterator") != 0 && strcmp(cfg->module_conf, "subnetcache python iterator") != 0
&& strcmp(cfg->module_conf, "respip subnetcache python iterator") != 0
&& strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0 && strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "python respip subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0 && strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0
&& strcmp(cfg->module_conf, "respip subnetcache python validator iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0 && strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0
&& strcmp(cfg->module_conf, "respip subnetcache validator python iterator") != 0
#endif #endif
#ifdef USE_IPSECMOD #ifdef USE_IPSECMOD
&& strcmp(cfg->module_conf, "ipsecmod iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod respip iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
#endif #endif
#if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD) #if defined(WITH_PYTHONMODULE) && defined(USE_IPSECMOD)
&& strcmp(cfg->module_conf, "python ipsecmod iterator") != 0 && strcmp(cfg->module_conf, "python ipsecmod iterator") != 0
&& strcmp(cfg->module_conf, "python ipsecmod respip iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod python iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod python iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod python respip iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod validator iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod respip validator iterator") != 0
&& strcmp(cfg->module_conf, "python ipsecmod validator iterator") != 0 && strcmp(cfg->module_conf, "python ipsecmod validator iterator") != 0
&& strcmp(cfg->module_conf, "python ipsecmod respip validator iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod python validator iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod python validator iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod python respip validator iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod validator python iterator") != 0 && strcmp(cfg->module_conf, "ipsecmod validator python iterator") != 0
&& strcmp(cfg->module_conf, "ipsecmod respip validator python iterator") != 0
#endif #endif
#ifdef USE_IPSET #ifdef USE_IPSET
&& strcmp(cfg->module_conf, "validator ipset iterator") != 0 && strcmp(cfg->module_conf, "validator ipset iterator") != 0
&& strcmp(cfg->module_conf, "validator ipset respip iterator") != 0
&& strcmp(cfg->module_conf, "ipset iterator") != 0 && strcmp(cfg->module_conf, "ipset iterator") != 0
&& strcmp(cfg->module_conf, "ipset respip iterator") != 0
#endif #endif
) { ) {
fatal_exit("module conf '%s' is not known to work", fatal_exit("module conf '%s' is not known to work",
@ -676,8 +699,9 @@ check_hints(struct config_file* cfg)
static void static void
check_auth(struct config_file* cfg) check_auth(struct config_file* cfg)
{ {
int is_rpz = 0;
struct auth_zones* az = auth_zones_create(); struct auth_zones* az = auth_zones_create();
if(!az || !auth_zones_apply_cfg(az, cfg, 0)) { if(!az || !auth_zones_apply_cfg(az, cfg, 0i, &is_rpz)) {
fatal_exit("Could not setup authority zones"); fatal_exit("Could not setup authority zones");
} }
auth_zones_delete(az); auth_zones_delete(az);

View File

@ -62,6 +62,7 @@
#include "daemon/stats.h" #include "daemon/stats.h"
#include "sldns/wire2str.h" #include "sldns/wire2str.h"
#include "sldns/pkthdr.h" #include "sldns/pkthdr.h"
#include "services/rpz.h"
#ifdef HAVE_SYS_IPC_H #ifdef HAVE_SYS_IPC_H
#include "sys/ipc.h" #include "sys/ipc.h"
@ -157,6 +158,8 @@ usage(void)
printf(" view_local_datas view add list of local-data to view\n"); printf(" view_local_datas view add list of local-data to view\n");
printf(" one entry per line read from stdin\n"); printf(" one entry per line read from stdin\n");
printf(" view_local_data_remove view name remove local-data in view\n"); printf(" view_local_data_remove view name remove local-data in view\n");
printf(" view_local_datas_remove view remove list of local-data from view\n");
printf(" one entry per line read from stdin\n");
printf("Version %s\n", PACKAGE_VERSION); printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n"); printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT); printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
@ -208,7 +211,7 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
s->svr.num_queries - s->svr.num_queries_missed_cache); s->svr.num_queries - s->svr.num_queries_missed_cache);
PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache); PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache);
PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch); PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch);
PR_UL_NM("num.zero_ttl", s->svr.zero_ttl_responses); PR_UL_NM("num.expired", s->svr.ans_expired);
PR_UL_NM("num.recursivereplies", s->mesh_replies_sent); PR_UL_NM("num.recursivereplies", s->mesh_replies_sent);
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted); PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted);
@ -372,6 +375,14 @@ static void print_extended(struct ub_stats_info* s)
PR_UL("rrset.cache.count", s->svr.rrset_cache_count); PR_UL("rrset.cache.count", s->svr.rrset_cache_count);
PR_UL("infra.cache.count", s->svr.infra_cache_count); PR_UL("infra.cache.count", s->svr.infra_cache_count);
PR_UL("key.cache.count", s->svr.key_cache_count); PR_UL("key.cache.count", s->svr.key_cache_count);
/* applied RPZ actions */
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
if(i == RPZ_NO_OVERRIDE_ACTION)
continue;
if(inhibit_zero && s->svr.rpz_action[i] == 0)
continue;
PR_UL_SUB("num.rpz.action", rpz_action_to_string(i), s->svr.rpz_action[i]);
}
#ifdef USE_DNSCRYPT #ifdef USE_DNSCRYPT
PR_UL("dnscrypt_shared_secret.cache.count", PR_UL("dnscrypt_shared_secret.cache.count",
s->svr.shared_secret_cache_count); s->svr.shared_secret_cache_count);
@ -493,9 +504,11 @@ setup_ctx(struct config_file* cfg)
ctx = SSL_CTX_new(SSLv23_client_method()); ctx = SSL_CTX_new(SSLv23_client_method());
if(!ctx) if(!ctx)
ssl_err("could not allocate SSL_CTX pointer"); ssl_err("could not allocate SSL_CTX pointer");
#if SSL_OP_NO_SSLv2 != 0
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
!= SSL_OP_NO_SSLv2) != SSL_OP_NO_SSLv2)
ssl_err("could not set SSL_OP_NO_SSLv2"); ssl_err("could not set SSL_OP_NO_SSLv2");
#endif
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
!= SSL_OP_NO_SSLv3) != SSL_OP_NO_SSLv3)
ssl_err("could not set SSL_OP_NO_SSLv3"); ssl_err("could not set SSL_OP_NO_SSLv3");
@ -704,7 +717,8 @@ check_args_for_listcmd(int argc, char* argv[])
fatal_exit("too many arguments for command '%s', " fatal_exit("too many arguments for command '%s', "
"content is piped in from stdin", argv[0]); "content is piped in from stdin", argv[0]);
} }
if(argc >= 1 && strcmp(argv[0], "view_local_datas") == 0 && if(argc >= 1 && (strcmp(argv[0], "view_local_datas") == 0 ||
strcmp(argv[0], "view_local_datas_remove") == 0) &&
argc >= 3) { argc >= 3) {
fatal_exit("too many arguments for command '%s', " fatal_exit("too many arguments for command '%s', "
"content is piped in from stdin", argv[0]); "content is piped in from stdin", argv[0]);
@ -753,7 +767,8 @@ go_cmd(SSL* ssl, int fd, int quiet, int argc, char* argv[])
strcmp(argv[0], "local_zones_remove") == 0 || strcmp(argv[0], "local_zones_remove") == 0 ||
strcmp(argv[0], "local_datas") == 0 || strcmp(argv[0], "local_datas") == 0 ||
strcmp(argv[0], "view_local_datas") == 0 || strcmp(argv[0], "view_local_datas") == 0 ||
strcmp(argv[0], "local_datas_remove") == 0)) { strcmp(argv[0], "local_datas_remove") == 0 ||
strcmp(argv[0], "view_local_datas_remove") == 0)) {
send_file(ssl, fd, stdin, buf, sizeof(buf)); send_file(ssl, fd, stdin, buf, sizeof(buf));
send_eof(ssl, fd); send_eof(ssl, fd);
} }

View File

@ -246,6 +246,8 @@ config_create(void)
cfg->serve_expired = 0; cfg->serve_expired = 0;
cfg->serve_expired_ttl = 0; cfg->serve_expired_ttl = 0;
cfg->serve_expired_ttl_reset = 0; cfg->serve_expired_ttl_reset = 0;
cfg->serve_expired_reply_ttl = 30;
cfg->serve_expired_client_timeout = 0;
cfg->add_holddown = 30*24*3600; cfg->add_holddown = 30*24*3600;
cfg->del_holddown = 30*24*3600; cfg->del_holddown = 30*24*3600;
cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */ cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */
@ -327,9 +329,14 @@ config_create(void)
cfg->ipsecmod_strict = 0; cfg->ipsecmod_strict = 0;
#endif #endif
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
cfg->cachedb_backend = NULL; if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
cfg->cachedb_secret = NULL; if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
#endif #ifdef USE_REDIS
if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit;
cfg->redis_timeout = 100;
cfg->redis_server_port = 6379;
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET #ifdef USE_IPSET
cfg->ipset_name_v4 = NULL; cfg->ipset_name_v4 = NULL;
cfg->ipset_name_v6 = NULL; cfg->ipset_name_v6 = NULL;
@ -581,10 +588,15 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("val-permissive-mode:", val_permissive_mode)
else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("aggressive-nsec:", aggressive_nsec)
else S_YNO("ignore-cd-flag:", ignore_cd) else S_YNO("ignore-cd-flag:", ignore_cd)
else S_YNO("serve-expired:", serve_expired) else if(strcmp(opt, "serve-expired:") == 0)
else if(strcmp(opt, "serve_expired_ttl:") == 0) { IS_YES_OR_NO; cfg->serve_expired = (strcmp(val, "yes") == 0);
SERVE_EXPIRED = cfg->serve_expired; }
else if(strcmp(opt, "serve-expired-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->serve_expired_ttl = atoi(val); SERVE_EXPIRED_TTL=(time_t)cfg->serve_expired_ttl;} { IS_NUMBER_OR_ZERO; cfg->serve_expired_ttl = atoi(val); SERVE_EXPIRED_TTL=(time_t)cfg->serve_expired_ttl;}
else S_YNO("serve-expired-ttl-reset:", serve_expired_ttl_reset) else S_YNO("serve-expired-ttl-reset:", serve_expired_ttl_reset)
else if(strcmp(opt, "serve-expired-reply-ttl:") == 0)
{ IS_NUMBER_OR_ZERO; cfg->serve_expired_reply_ttl = atoi(val); SERVE_EXPIRED_REPLY_TTL=(time_t)cfg->serve_expired_reply_ttl;}
else S_NUMBER_OR_ZERO("serve-expired-client-timeout:", serve_expired_client_timeout)
else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations) else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown) else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown)
else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown) else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown)
@ -977,6 +989,8 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "serve-expired", serve_expired) else O_YNO(opt, "serve-expired", serve_expired)
else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl) else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl)
else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset) else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset)
else O_DEC(opt, "serve-expired-reply-ttl", serve_expired_reply_ttl)
else O_DEC(opt, "serve-expired-client-timeout", serve_expired_client_timeout)
else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations) else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
else O_UNS(opt, "add-holddown", add_holddown) else O_UNS(opt, "add-holddown", add_holddown)
else O_UNS(opt, "del-holddown", del_holddown) else O_UNS(opt, "del-holddown", del_holddown)
@ -1098,7 +1112,12 @@ config_get_option(struct config_file* cfg, const char* opt,
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
else O_STR(opt, "backend", cachedb_backend) else O_STR(opt, "backend", cachedb_backend)
else O_STR(opt, "secret-seed", cachedb_secret) else O_STR(opt, "secret-seed", cachedb_secret)
#endif #ifdef USE_REDIS
else O_STR(opt, "redis-server-host", redis_server_host)
else O_DEC(opt, "redis-server-port", redis_server_port)
else O_DEC(opt, "redis-timeout", redis_timeout)
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET #ifdef USE_IPSET
else O_STR(opt, "name-v4", ipset_name_v4) else O_STR(opt, "name-v4", ipset_name_v4)
else O_STR(opt, "name-v6", ipset_name_v6) else O_STR(opt, "name-v6", ipset_name_v6)
@ -1279,6 +1298,10 @@ config_delauth(struct config_auth* p)
config_delstrlist(p->urls); config_delstrlist(p->urls);
config_delstrlist(p->allow_notify); config_delstrlist(p->allow_notify);
free(p->zonefile); free(p->zonefile);
free(p->rpz_taglist);
free(p->rpz_action_override);
free(p->rpz_cname);
free(p->rpz_log_name);
free(p); free(p);
} }
@ -1381,7 +1404,10 @@ config_delete(struct config_file* cfg)
config_delstrlist(cfg->tls_session_ticket_keys.first); config_delstrlist(cfg->tls_session_ticket_keys.first);
free(cfg->tls_ciphers); free(cfg->tls_ciphers);
free(cfg->tls_ciphersuites); free(cfg->tls_ciphersuites);
free(cfg->log_identity); if(cfg->log_identity) {
log_ident_revert_to_default();
free(cfg->log_identity);
}
config_del_strarray(cfg->ifs, cfg->num_ifs); config_del_strarray(cfg->ifs, cfg->num_ifs);
config_del_strarray(cfg->out_ifs, cfg->num_out_ifs); config_del_strarray(cfg->out_ifs, cfg->num_out_ifs);
config_delstubs(cfg->stubs); config_delstubs(cfg->stubs);
@ -1444,7 +1470,10 @@ config_delete(struct config_file* cfg)
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
free(cfg->cachedb_backend); free(cfg->cachedb_backend);
free(cfg->cachedb_secret); free(cfg->cachedb_secret);
#endif #ifdef USE_REDIS
free(cfg->redis_server_host);
#endif /* USE_REDIS */
#endif /* USE_CACHEDB */
#ifdef USE_IPSET #ifdef USE_IPSET
free(cfg->ipset_name_v4); free(cfg->ipset_name_v4);
free(cfg->ipset_name_v6); free(cfg->ipset_name_v6);
@ -1942,7 +1971,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
return strdup(buf); return strdup(buf);
} }
int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2, int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
size_t list2len) size_t list2len)
{ {
size_t i; size_t i;
@ -1960,7 +1989,9 @@ config_apply(struct config_file* config)
{ {
MAX_TTL = (time_t)config->max_ttl; MAX_TTL = (time_t)config->max_ttl;
MIN_TTL = (time_t)config->min_ttl; MIN_TTL = (time_t)config->min_ttl;
SERVE_EXPIRED = config->serve_expired;
SERVE_EXPIRED_TTL = (time_t)config->serve_expired_ttl; SERVE_EXPIRED_TTL = (time_t)config->serve_expired_ttl;
SERVE_EXPIRED_REPLY_TTL = (time_t)config->serve_expired_reply_ttl;
MAX_NEG_TTL = (time_t)config->max_negative_ttl; MAX_NEG_TTL = (time_t)config->max_negative_ttl;
RTT_MIN_TIMEOUT = config->infra_cache_min_rtt; RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size; EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;

View File

@ -362,6 +362,11 @@ struct config_file {
int serve_expired_ttl; int serve_expired_ttl;
/** reset serve expired TTL after failed update attempt */ /** reset serve expired TTL after failed update attempt */
int serve_expired_ttl_reset; int serve_expired_ttl_reset;
/** TTL for the serve expired replies */
int serve_expired_reply_ttl;
/** serve expired entries only after trying to update the entries and this
* timeout (in milliseconds) is reached */
int serve_expired_client_timeout;
/** nsec3 maximum iterations per key size, string */ /** nsec3 maximum iterations per key size, string */
char* val_nsec3_key_iterations; char* val_nsec3_key_iterations;
/** autotrust add holddown time, in seconds */ /** autotrust add holddown time, in seconds */
@ -641,6 +646,21 @@ struct config_auth {
/** fallback to recursion to authorities if zone expired and other /** fallback to recursion to authorities if zone expired and other
* reasons perhaps (like, query bogus) */ * reasons perhaps (like, query bogus) */
int fallback_enabled; int fallback_enabled;
/** this zone is used to create local-zone policies */
int isrpz;
/** rpz tags (or NULL) */
uint8_t* rpz_taglist;
/** length of the taglist (in bytes) */
size_t rpz_taglistlen;
/** Override RPZ action for this zone, regardless of zone content */
char* rpz_action_override;
/** Log when this RPZ policy is applied */
int rpz_log;
/** Display this name in the log when RPZ policy is applied */
char* rpz_log_name;
/** Always reply with this CNAME target if the cname override action is
* used */
char* rpz_cname;
}; };
/** /**
@ -1043,7 +1063,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
* @param list2len: length in bytes of second list. * @param list2len: length in bytes of second list.
* @return true if there are tags in common, 0 if not. * @return true if there are tags in common, 0 if not.
*/ */
int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2, int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
size_t list2len); size_t list2len);
/** /**

View File

@ -317,6 +317,12 @@ forward-no-cache{COLON} { YDVAR(1, VAR_FORWARD_NO_CACHE) }
forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) } forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) } forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) } auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) }
rpz{COLON} { YDVAR(0, VAR_RPZ) }
tags{COLON} { YDVAR(1, VAR_TAGS) }
rpz-action-override{COLON} { YDVAR(1, VAR_RPZ_ACTION_OVERRIDE) }
rpz-cname-override{COLON} { YDVAR(1, VAR_RPZ_CNAME_OVERRIDE) }
rpz-log{COLON} { YDVAR(1, VAR_RPZ_LOG) }
rpz-log-name{COLON} { YDVAR(1, VAR_RPZ_LOG_NAME) }
zonefile{COLON} { YDVAR(1, VAR_ZONEFILE) } zonefile{COLON} { YDVAR(1, VAR_ZONEFILE) }
master{COLON} { YDVAR(1, VAR_MASTER) } master{COLON} { YDVAR(1, VAR_MASTER) }
url{COLON} { YDVAR(1, VAR_URL) } url{COLON} { YDVAR(1, VAR_URL) }
@ -364,6 +370,8 @@ ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) }
serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) } serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) }
serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) } serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) }
serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) } serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) }
serve-expired-reply-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_REPLY_TTL) }
serve-expired-client-timeout{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_CLIENT_TIMEOUT) }
fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) } fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) }
fake-sha1{COLON} { YDVAR(1, VAR_FAKE_SHA1) } fake-sha1{COLON} { YDVAR(1, VAR_FAKE_SHA1) }
val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) } val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) }

View File

@ -143,10 +143,11 @@ extern struct config_parser_state* cfg_parser;
%token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION %token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
%token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW %token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_SERVE_EXPIRED_TTL %token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_SERVE_EXPIRED_TTL
%token VAR_SERVE_EXPIRED_TTL_RESET VAR_FAKE_DSA VAR_FAKE_SHA1 %token VAR_SERVE_EXPIRED_TTL_RESET VAR_SERVE_EXPIRED_REPLY_TTL
%token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING %token VAR_SERVE_EXPIRED_CLIENT_TIMEOUT VAR_FAKE_DSA
%token VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY %token VAR_FAKE_SHA1 VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR
%token VAR_ROOT_KEY_SENTINEL %token VAR_TRUST_ANCHOR_SIGNALING VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD
%token VAR_SHM_ENABLE VAR_SHM_KEY VAR_ROOT_KEY_SENTINEL
%token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER %token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
%token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT %token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
%token VAR_DNSCRYPT_PROVIDER_CERT_ROTATED %token VAR_DNSCRYPT_PROVIDER_CERT_ROTATED
@ -166,8 +167,9 @@ extern struct config_parser_state* cfg_parser;
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY %token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY %token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES
%token VAR_TLS_SESSION_TICKET_KEYS
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
%% %%
toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -175,7 +177,8 @@ toplevelvar: serverstart contents_server | stubstart contents_stub |
forwardstart contents_forward | pythonstart contents_py | forwardstart contents_forward | pythonstart contents_py |
rcstart contents_rc | dtstart contents_dt | viewstart contents_view | rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
dnscstart contents_dnsc | cachedbstart contents_cachedb | dnscstart contents_dnsc | cachedbstart contents_cachedb |
ipsetstart contents_ipset | authstart contents_auth ipsetstart contents_ipset | authstart contents_auth |
rpzstart contents_rpz
; ;
/* server: declaration */ /* server: declaration */
@ -254,6 +257,7 @@ content_server: server_num_threads | server_verbosity | server_port |
server_access_control_tag_data | server_access_control_view | server_access_control_tag_data | server_access_control_view |
server_qname_minimisation_strict | server_serve_expired | server_qname_minimisation_strict | server_serve_expired |
server_serve_expired_ttl | server_serve_expired_ttl_reset | server_serve_expired_ttl | server_serve_expired_ttl_reset |
server_serve_expired_reply_ttl | server_serve_expired_client_timeout |
server_fake_dsa | server_log_identity | server_use_systemd | server_fake_dsa | server_log_identity | server_use_systemd |
server_response_ip_tag | server_response_ip | server_response_ip_data | server_response_ip_tag | server_response_ip | server_response_ip_data |
server_shm_enable | server_shm_key | server_fake_sha1 | server_shm_enable | server_shm_key | server_fake_sha1 |
@ -335,6 +339,7 @@ authstart: VAR_AUTH_ZONE
s->for_downstream = 1; s->for_downstream = 1;
s->for_upstream = 1; s->for_upstream = 1;
s->fallback_enabled = 0; s->fallback_enabled = 0;
s->isrpz = 0;
} else } else
yyerror("out of memory"); yyerror("out of memory");
} }
@ -345,6 +350,92 @@ content_auth: auth_name | auth_zonefile | auth_master | auth_url |
auth_for_downstream | auth_for_upstream | auth_fallback_enabled | auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
auth_allow_notify auth_allow_notify
; ;
rpz_tag: VAR_TAGS STRING_ARG
{
uint8_t* bitlist;
size_t len = 0;
OUTYY(("P(server_local_zone_tag:%s)\n", $2));
bitlist = config_parse_taglist(cfg_parser->cfg, $2,
&len);
free($2);
if(!bitlist) {
yyerror("could not parse tags, (define-tag them first)");
}
if(bitlist) {
cfg_parser->cfg->auths->rpz_taglist = bitlist;
cfg_parser->cfg->auths->rpz_taglistlen = len;
}
}
;
rpz_action_override: VAR_RPZ_ACTION_OVERRIDE STRING_ARG
{
OUTYY(("P(rpz_action_override:%s)\n", $2));
if(strcmp($2, "nxdomain")!=0 && strcmp($2, "nodata")!=0 &&
strcmp($2, "passthru")!=0 && strcmp($2, "drop")!=0 &&
strcmp($2, "cname")!=0 && strcmp($2, "disabled")!=0) {
yyerror("rpz-action-override action: expected nxdomain, "
"nodata, passthru, drop, cname or disabled");
free($2);
cfg_parser->cfg->auths->rpz_action_override = NULL;
}
else {
cfg_parser->cfg->auths->rpz_action_override = $2;
}
}
;
rpz_cname_override: VAR_RPZ_CNAME_OVERRIDE STRING_ARG
{
OUTYY(("P(rpz_cname_override:%s)\n", $2));
free(cfg_parser->cfg->auths->rpz_cname);
cfg_parser->cfg->auths->rpz_cname = $2;
}
;
rpz_log: VAR_RPZ_LOG STRING_ARG
{
OUTYY(("P(rpz_log:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->auths->rpz_log = (strcmp($2, "yes")==0);
free($2);
}
;
rpz_log_name: VAR_RPZ_LOG_NAME STRING_ARG
{
OUTYY(("P(rpz_log_name:%s)\n", $2));
free(cfg_parser->cfg->auths->rpz_log_name);
cfg_parser->cfg->auths->rpz_log_name = $2;
}
;
rpzstart: VAR_RPZ
{
struct config_auth* s;
OUTYY(("\nP(rpz:)\n"));
s = (struct config_auth*)calloc(1, sizeof(struct config_auth));
if(s) {
s->next = cfg_parser->cfg->auths;
cfg_parser->cfg->auths = s;
/* defaults for RPZ auth zone */
s->for_downstream = 0;
s->for_upstream = 0;
s->fallback_enabled = 0;
s->isrpz = 1;
} else
yyerror("out of memory");
}
;
contents_rpz: contents_rpz content_rpz
| ;
content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
auth_allow_notify | rpz_action_override | rpz_cname_override |
rpz_log | rpz_log_name
;
server_num_threads: VAR_NUM_THREADS STRING_ARG server_num_threads: VAR_NUM_THREADS STRING_ARG
{ {
OUTYY(("P(server_num_threads:%s)\n", $2)); OUTYY(("P(server_num_threads:%s)\n", $2));
@ -429,6 +520,7 @@ server_send_client_subnet: VAR_SEND_CLIENT_SUBNET STRING_ARG
fatal_exit("out of memory adding client-subnet"); fatal_exit("out of memory adding client-subnet");
#else #else
OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
free($2);
#endif #endif
} }
; ;
@ -441,6 +533,7 @@ server_client_subnet_zone: VAR_CLIENT_SUBNET_ZONE STRING_ARG
fatal_exit("out of memory adding client-subnet-zone"); fatal_exit("out of memory adding client-subnet-zone");
#else #else
OUTYY(("P(Compiled without edns subnet option, ignoring)\n")); OUTYY(("P(Compiled without edns subnet option, ignoring)\n"));
free($2);
#endif #endif
} }
; ;
@ -1666,12 +1759,30 @@ server_serve_expired_ttl_reset: VAR_SERVE_EXPIRED_TTL_RESET STRING_ARG
free($2); free($2);
} }
; ;
server_serve_expired_reply_ttl: VAR_SERVE_EXPIRED_REPLY_TTL STRING_ARG
{
OUTYY(("P(server_serve_expired_reply_ttl:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->serve_expired_reply_ttl = atoi($2);
free($2);
}
;
server_serve_expired_client_timeout: VAR_SERVE_EXPIRED_CLIENT_TIMEOUT STRING_ARG
{
OUTYY(("P(server_serve_expired_client_timeout:%s)\n", $2));
if(atoi($2) == 0 && strcmp($2, "0") != 0)
yyerror("number expected");
else cfg_parser->cfg->serve_expired_client_timeout = atoi($2);
free($2);
}
;
server_fake_dsa: VAR_FAKE_DSA STRING_ARG server_fake_dsa: VAR_FAKE_DSA STRING_ARG
{ {
OUTYY(("P(server_fake_dsa:%s)\n", $2)); OUTYY(("P(server_fake_dsa:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no."); yyerror("expected yes or no.");
#ifdef HAVE_SSL #if defined(HAVE_SSL) || defined(HAVE_NETTLE)
else fake_dsa = (strcmp($2, "yes")==0); else fake_dsa = (strcmp($2, "yes")==0);
if(fake_dsa) if(fake_dsa)
log_warn("test option fake_dsa is enabled"); log_warn("test option fake_dsa is enabled");
@ -1684,7 +1795,7 @@ server_fake_sha1: VAR_FAKE_SHA1 STRING_ARG
OUTYY(("P(server_fake_sha1:%s)\n", $2)); OUTYY(("P(server_fake_sha1:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no."); yyerror("expected yes or no.");
#ifdef HAVE_SSL #if defined(HAVE_SSL) || defined(HAVE_NETTLE)
else fake_sha1 = (strcmp($2, "yes")==0); else fake_sha1 = (strcmp($2, "yes")==0);
if(fake_sha1) if(fake_sha1)
log_warn("test option fake_sha1 is enabled"); log_warn("test option fake_sha1 is enabled");
@ -2898,9 +3009,6 @@ cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG
{ {
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
OUTYY(("P(backend:%s)\n", $2)); OUTYY(("P(backend:%s)\n", $2));
if(cfg_parser->cfg->cachedb_backend)
yyerror("cachedb backend override, there must be one "
"backend");
free(cfg_parser->cfg->cachedb_backend); free(cfg_parser->cfg->cachedb_backend);
cfg_parser->cfg->cachedb_backend = $2; cfg_parser->cfg->cachedb_backend = $2;
#else #else
@ -2913,9 +3021,6 @@ cachedb_secret_seed: VAR_CACHEDB_SECRETSEED STRING_ARG
{ {
#ifdef USE_CACHEDB #ifdef USE_CACHEDB
OUTYY(("P(secret-seed:%s)\n", $2)); OUTYY(("P(secret-seed:%s)\n", $2));
if(cfg_parser->cfg->cachedb_secret)
yyerror("cachedb secret-seed override, there must be "
"only one secret");
free(cfg_parser->cfg->cachedb_secret); free(cfg_parser->cfg->cachedb_secret);
cfg_parser->cfg->cachedb_secret = $2; cfg_parser->cfg->cachedb_secret = $2;
#else #else

View File

@ -233,17 +233,28 @@ int
dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
{ {
uint8_t len1, len2; uint8_t len1, len2;
int count1 = 0, count2 = 0;
log_assert(pkt && d1 && d2); log_assert(pkt && d1 && d2);
len1 = *d1++; len1 = *d1++;
len2 = *d2++; len2 = *d2++;
while( len1 != 0 || len2 != 0 ) { while( len1 != 0 || len2 != 0 ) {
/* resolve ptrs */ /* resolve ptrs */
if(LABEL_IS_PTR(len1)) { if(LABEL_IS_PTR(len1)) {
if((size_t)PTR_OFFSET(len1, *d1)
>= sldns_buffer_limit(pkt))
return -1;
if(count1++ > MAX_COMPRESS_PTRS)
return -1;
d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
len1 = *d1++; len1 = *d1++;
continue; continue;
} }
if(LABEL_IS_PTR(len2)) { if(LABEL_IS_PTR(len2)) {
if((size_t)PTR_OFFSET(len2, *d2)
>= sldns_buffer_limit(pkt))
return 1;
if(count2++ > MAX_COMPRESS_PTRS)
return 1;
d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
len2 = *d2++; len2 = *d2++;
continue; continue;
@ -302,12 +313,18 @@ dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t labuf[LDNS_MAX_LABELLEN+1];
uint8_t lablen; uint8_t lablen;
int i; int i;
int count = 0;
/* preserve case of query, make hash label by label */ /* preserve case of query, make hash label by label */
lablen = *dname++; lablen = *dname++;
while(lablen) { while(lablen) {
if(LABEL_IS_PTR(lablen)) { if(LABEL_IS_PTR(lablen)) {
/* follow pointer */ /* follow pointer */
if((size_t)PTR_OFFSET(lablen, *dname)
>= sldns_buffer_limit(pkt))
return h;
if(count++ > MAX_COMPRESS_PTRS)
return h;
dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
lablen = *dname++; lablen = *dname++;
continue; continue;
@ -341,6 +358,9 @@ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
return; return;
} }
/* follow pointer */ /* follow pointer */
if((size_t)PTR_OFFSET(lablen, *dname)
>= sldns_buffer_limit(pkt))
return;
dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
lablen = *dname++; lablen = *dname++;
continue; continue;
@ -369,6 +389,7 @@ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
{ {
uint8_t lablen; uint8_t lablen;
int count = 0;
if(!out) out = stdout; if(!out) out = stdout;
if(!dname) return; if(!dname) return;
@ -382,6 +403,15 @@ void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
fputs("??compressionptr??", out); fputs("??compressionptr??", out);
return; return;
} }
if((size_t)PTR_OFFSET(lablen, *dname)
>= sldns_buffer_limit(pkt)) {
fputs("??compressionptr??", out);
return;
}
if(count++ > MAX_COMPRESS_PTRS) {
fputs("??compressionptr??", out);
return;
}
dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
lablen = *dname++; lablen = *dname++;
continue; continue;
@ -558,6 +588,34 @@ dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
return 1; return 1;
} }
int
dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
{
size_t len;
/* 1 byte needed for the label length */
if(dnamelen < 1)
return 0;
len = *dname;
while(len <= dnamelen) {
if(!(*dname)) {
if(*dname == *label)
return 1; /* empty label match */
/* termination label found, stop iterating */
return 0;
}
if(*dname == *label && *label &&
memlowercmp(dname+1, label+1, *dname) == 0)
return 1;
len += *dname;
dname += *dname;
dname++;
len++;
}
return 0;
}
int int
dname_buffer_write(sldns_buffer* pkt, uint8_t* dname) dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
{ {

View File

@ -196,6 +196,15 @@ int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
*/ */
int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr); int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr);
/**
* Check if dname contains label
* @param dname: dname
* @param dnamelen: length of dname
* @param label: label to be checked for presence in dname
* @return: 1 if dname has this label, 0 otherwise
*/
int dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label);
/** /**
* See if domain name d1 is a strict subdomain of d2. * See if domain name d1 is a strict subdomain of d2.
* That is a subdomain, but not equal. * That is a subdomain, but not equal.

View File

@ -480,7 +480,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
sldns_buffer_write(pkt, &key->rk.type, 2); sldns_buffer_write(pkt, &key->rk.type, 2);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2); sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
if(data->rr_ttl[j] < timenow) if(data->rr_ttl[j] < timenow)
sldns_buffer_write_u32(pkt, 0); sldns_buffer_write_u32(pkt,
SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
else sldns_buffer_write_u32(pkt, else sldns_buffer_write_u32(pkt,
data->rr_ttl[j]-timenow); data->rr_ttl[j]-timenow);
if(c) { if(c) {
@ -517,7 +518,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG); sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2); sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
if(data->rr_ttl[i] < timenow) if(data->rr_ttl[i] < timenow)
sldns_buffer_write_u32(pkt, 0); sldns_buffer_write_u32(pkt,
SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
else sldns_buffer_write_u32(pkt, else sldns_buffer_write_u32(pkt,
data->rr_ttl[i]-timenow); data->rr_ttl[i]-timenow);
/* rrsig rdata cannot be compressed, perform 100+ byte /* rrsig rdata cannot be compressed, perform 100+ byte

View File

@ -55,7 +55,11 @@ smart_compare(sldns_buffer* pkt, uint8_t* dnow,
{ {
if(LABEL_IS_PTR(*dnow)) { if(LABEL_IS_PTR(*dnow)) {
/* ptr points to a previous dname */ /* ptr points to a previous dname */
uint8_t* p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); uint8_t* p;
if((size_t)PTR_OFFSET(dnow[0], dnow[1])
>= sldns_buffer_limit(pkt))
return -1;
p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1]));
if( p == dprfirst || p == dprlast ) if( p == dprfirst || p == dprlast )
return 0; return 0;
/* prev dname is also a ptr, both ptrs are the same. */ /* prev dname is also a ptr, both ptrs are the same. */

View File

@ -79,8 +79,12 @@ extern time_t MAX_TTL;
extern time_t MIN_TTL; extern time_t MIN_TTL;
/** Maximum Negative TTL that is allowed */ /** Maximum Negative TTL that is allowed */
extern time_t MAX_NEG_TTL; extern time_t MAX_NEG_TTL;
/** If we serve expired entries and prefetch them */
extern int SERVE_EXPIRED;
/** Time to serve records after expiration */ /** Time to serve records after expiration */
extern time_t SERVE_EXPIRED_TTL; extern time_t SERVE_EXPIRED_TTL;
/** TTL to use for expired records */
extern time_t SERVE_EXPIRED_REPLY_TTL;
/** Negative cache time (for entries without any RRs.) */ /** Negative cache time (for entries without any RRs.) */
#define NORR_TTL 5 /* seconds */ #define NORR_TTL 5 /* seconds */

View File

@ -61,8 +61,12 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
time_t MIN_TTL = 0; time_t MIN_TTL = 0;
/** MAX Negative TTL, for SOA records in authority section */ /** MAX Negative TTL, for SOA records in authority section */
time_t MAX_NEG_TTL = 3600; /* one hour */ time_t MAX_NEG_TTL = 3600; /* one hour */
/** If we serve expired entries and prefetch them */
int SERVE_EXPIRED = 0;
/** Time to serve records after expiration */ /** Time to serve records after expiration */
time_t SERVE_EXPIRED_TTL = 0; time_t SERVE_EXPIRED_TTL = 0;
/** TTL to use for expired records */
time_t SERVE_EXPIRED_REPLY_TTL = 30;
/** allocate qinfo, return 0 on error */ /** allocate qinfo, return 0 on error */
static int static int

View File

@ -40,6 +40,7 @@
*/ */
#include "config.h" #include "config.h"
#include "util/data/msgparse.h"
#include "util/data/packed_rrset.h" #include "util/data/packed_rrset.h"
#include "util/data/dname.h" #include "util/data/dname.h"
#include "util/storage/lookup3.h" #include "util/storage/lookup3.h"
@ -351,11 +352,11 @@ packed_rrset_copy_region(struct ub_packed_rrset_key* key,
/* make TTLs relative - once per rrset */ /* make TTLs relative - once per rrset */
for(i=0; i<d->count + d->rrsig_count; i++) { for(i=0; i<d->count + d->rrsig_count; i++) {
if(d->rr_ttl[i] < now) if(d->rr_ttl[i] < now)
d->rr_ttl[i] = 0; d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
else d->rr_ttl[i] -= now; else d->rr_ttl[i] -= now;
} }
if(d->ttl < now) if(d->ttl < now)
d->ttl = 0; d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
else d->ttl -= now; else d->ttl -= now;
return ck; return ck;
} }
@ -386,3 +387,19 @@ packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
packed_rrset_ttl_add(dd, now); packed_rrset_ttl_add(dd, now);
return dk; return dk;
} }
int
packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index)
{
size_t i;
for(i=0; i<d->count; i++) {
if(d->rr_len[i] != len)
continue;
if(memcmp(d->rr_data[i], rdata, len) == 0) {
*index = i;
return 1;
}
}
return 0;
}

View File

@ -446,4 +446,17 @@ struct ub_packed_rrset_key* packed_rrset_copy_alloc(
struct ub_packed_rrset_key* key, struct alloc_cache* alloc, struct ub_packed_rrset_key* key, struct alloc_cache* alloc,
time_t now); time_t now);
/**
* Find RR index in packed rrset
* Raw comparison, does not canonicalize RDATA
* @param d: packed rrset
* @param rdata: RDATA of RR to find
* @param len: length of rdata
* @param index: pointer to int to store index of found RR
* @return 1 if RR found, 0 otherwise
*/
int
packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index);
#endif /* UTIL_DATA_PACKED_RRSET_H */ #endif /* UTIL_DATA_PACKED_RRSET_H */

View File

@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
else if(fptr == &auth_xfer_timer) return 1; else if(fptr == &auth_xfer_timer) return 1;
else if(fptr == &auth_xfer_probe_timer_callback) return 1; else if(fptr == &auth_xfer_probe_timer_callback) return 1;
else if(fptr == &auth_xfer_transfer_timer_callback) return 1; else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
else if(fptr == &mesh_serve_expired_callback) return 1;
return 0; return 0;
} }
@ -619,3 +620,9 @@ int fptr_whitelist_inplace_cb_query_response(
return 0; return 0;
} }
int fptr_whitelist_serve_expired_lookup(serve_expired_lookup_func_type* fptr)
{
if(fptr == &mesh_serve_expired_lookup)
return 1;
return 0;
}

View File

@ -377,6 +377,13 @@ int fptr_whitelist_inplace_cb_edns_back_parsed(
int fptr_whitelist_inplace_cb_query_response( int fptr_whitelist_inplace_cb_query_response(
inplace_cb_query_response_func_type* fptr); inplace_cb_query_response_func_type* fptr);
/**
* Check function pointer whitelist for serve_expired_lookup func values.
* @param fptr: function pointer to check.
* @return false if not in whitelist.
*/
int fptr_whitelist_serve_expired_lookup(serve_expired_lookup_func_type* fptr);
/** Due to module breakage by fptr wlist, these test app declarations /** Due to module breakage by fptr wlist, these test app declarations
* are presented here */ * are presented here */
/** /**

View File

@ -3904,6 +3904,7 @@
4600, 4600,
4601, 4601,
4621, 4621,
4646,
4658, 4658,
4659, 4659,
4660, 4660,

View File

@ -74,6 +74,7 @@ static lock_basic_type log_lock;
#endif #endif
/** the identity of this executable/process */ /** the identity of this executable/process */
static const char* ident="unbound"; static const char* ident="unbound";
static const char* default_ident="unbound";
#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS) #if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
/** are we using syslog(3) to log to */ /** are we using syslog(3) to log to */
static int logging_to_syslog = 0; static int logging_to_syslog = 0;
@ -181,6 +182,24 @@ void log_ident_set(const char* id)
ident = id; ident = id;
} }
void log_ident_set_default(const char* id)
{
default_ident = id;
}
void log_ident_revert_to_default()
{
ident = default_ident;
}
void log_ident_set_or_default(const char* identity)
{
if(identity == NULL || identity[0] == 0)
log_ident_set(default_ident);
else
log_ident_set(identity);
}
void log_set_time_asc(int use_asc) void log_set_time_asc(int use_asc)
{ {
log_time_asc = use_asc; log_time_asc = use_asc;

View File

@ -107,11 +107,29 @@ void log_thread_set(int* num);
int log_thread_get(void); int log_thread_get(void);
/** /**
* Set identity to print, default is 'unbound'. * Set identity to print, default is 'unbound'.
* @param id: string to print. Name of executable. * @param id: string to print. Name of executable.
*/ */
void log_ident_set(const char* id); void log_ident_set(const char* id);
/**
* Set default identity to print, default is 'unbound'.
* @param id: string to print. Name of executable.
*/
void log_ident_set_default(const char* id);
/**
* Revert identity to print, back to the recorded default value.
*/
void log_ident_revert_to_default(void);
/**
* Set identity to print if there is an identity, otherwise
* set the default.
* @param identity: the identity to set.
*/
void log_ident_set_or_default(const char* identity);
/** /**
* Set if the time value is printed ascii or decimal in log entries. * Set if the time value is printed ascii or decimal in log entries.
* @param use_asc: if true, ascii is printed, otherwise decimal. * @param use_asc: if true, ascii is printed, otherwise decimal.

View File

@ -306,6 +306,17 @@ typedef int inplace_cb_edns_back_parsed_func_type(struct module_qstate* qstate,
typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate, typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate,
struct dns_msg* response, int id, void* cb_args); struct dns_msg* response, int id, void* cb_args);
/**
* Function called when looking for (expired) cached answers during the serve
* expired logic.
* Called as func(qstate, lookup_qinfo)
* Where:
* qstate: the query state.
* lookup_qinfo: the qinfo to lookup for.
*/
typedef struct dns_msg* serve_expired_lookup_func_type(
struct module_qstate* qstate, struct query_info* lookup_qinfo);
/** /**
* Module environment. * Module environment.
* Services and data provided to the module. * Services and data provided to the module.
@ -571,6 +582,14 @@ struct sock_list {
struct respip_action_info; struct respip_action_info;
/**
* Struct to hold relevant data for serve expired
*/
struct serve_expired_data {
struct comm_timer* timer;
serve_expired_lookup_func_type* get_cached_answer;
};
/** /**
* Module state, per query. * Module state, per query.
*/ */
@ -612,6 +631,8 @@ struct module_qstate {
struct mesh_state* mesh_info; struct mesh_state* mesh_info;
/** how many seconds before expiry is this prefetched (0 if not) */ /** how many seconds before expiry is this prefetched (0 if not) */
time_t prefetch_leeway; time_t prefetch_leeway;
/** serve expired data */
struct serve_expired_data* serve_expired_data;
/** incoming edns options from the front end */ /** incoming edns options from the front end */
struct edns_option* edns_opts_front_in; struct edns_option* edns_opts_front_in;

View File

@ -284,6 +284,113 @@ int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
return 1; return 1;
} }
/* RPZ format address dname to network byte order address */
static int ipdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* af)
{
uint8_t* ia;
size_t dnamelabs = dname_count_labels(dname);
uint8_t lablen;
char* e = NULL;
int z = 0;
size_t len = 0;
int i;
*af = AF_INET;
/* need 1 byte for label length */
if(dnamelen < 1)
return 0;
if(dnamelabs > 6 ||
dname_has_label(dname, dnamelen, (uint8_t*)"\002zz")) {
*af = AF_INET6;
}
len = *dname;
lablen = *dname++;
i = (*af == AF_INET) ? 3 : 15;
if(*af == AF_INET6) {
struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
memset(sa, 0, *addrlen);
sa->sin6_family = AF_INET6;
ia = (uint8_t*)&sa->sin6_addr;
} else { /* ip4 */
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
memset(sa, 0, *addrlen);
sa->sin_family = AF_INET;
ia = (uint8_t*)&sa->sin_addr;
}
while(lablen && i >= 0 && len <= dnamelen) {
char buff[LDNS_MAX_LABELLEN+1];
uint16_t chunk; /* big enough to not overflow on IPv6 hextet */
if((*af == AF_INET && (lablen > 3 || dnamelabs > 6)) ||
(*af == AF_INET6 && (lablen > 4 || dnamelabs > 10))) {
return 0;
}
if(memcmp(dname, "zz", 2) == 0 && *af == AF_INET6) {
/* Add one or more 0 labels. Address is initialised at
* 0, so just skip the zero part. */
int zl = 11 - dnamelabs;
if(z || zl < 0)
return 0;
z = 1;
i -= (zl*2);
} else {
memcpy(buff, dname, lablen);
buff[lablen] = '\0';
chunk = strtol(buff, &e, (*af == AF_INET) ? 10 : 16);
if(!e || *e != '\0' || (*af == AF_INET && chunk > 255))
return 0;
if(*af == AF_INET) {
log_assert(i < 4 && i >= 0);
ia[i] = (uint8_t)chunk;
i--;
} else {
log_assert(i < 16 && i >= 1);
/* ia in network byte order */
ia[i-1] = (uint8_t)(chunk >> 8);
ia[i] = (uint8_t)(chunk & 0x00FF);
i -= 2;
}
}
dname += lablen;
lablen = *dname++;
len += lablen;
}
if(i != -1)
/* input too short */
return 0;
return 1;
}
int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af)
{
char buff[3 /* 3 digit netblock */ + 1];
size_t nlablen;
if(dnamelen < 1 || *dname > 3)
/* netblock invalid */
return 0;
nlablen = *dname;
if(dnamelen < 1 + nlablen)
return 0;
memcpy(buff, dname+1, nlablen);
buff[nlablen] = '\0';
*net = atoi(buff);
if(*net == 0 && strcmp(buff, "0") != 0)
return 0;
dname += nlablen;
dname++;
if(!ipdnametoaddr(dname, dnamelen-1-nlablen, addr, addrlen, af))
return 0;
if((*af == AF_INET6 && *net > 128) || (*af == AF_INET && *net > 32))
return 0;
return 1;
}
int authextstrtoaddr(char* str, struct sockaddr_storage* addr, int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
socklen_t* addrlen, char** auth_name) socklen_t* addrlen, char** auth_name)
{ {
@ -728,11 +835,13 @@ listen_sslctx_setup(void* ctxt)
#ifdef HAVE_SSL #ifdef HAVE_SSL
SSL_CTX* ctx = (SSL_CTX*)ctxt; SSL_CTX* ctx = (SSL_CTX*)ctxt;
/* no SSLv2, SSLv3 because has defects */ /* no SSLv2, SSLv3 because has defects */
#if SSL_OP_NO_SSLv2 != 0
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
!= SSL_OP_NO_SSLv2){ != SSL_OP_NO_SSLv2){
log_crypto_err("could not set SSL_OP_NO_SSLv2"); log_crypto_err("could not set SSL_OP_NO_SSLv2");
return 0; return 0;
} }
#endif
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
!= SSL_OP_NO_SSLv3){ != SSL_OP_NO_SSLv3){
log_crypto_err("could not set SSL_OP_NO_SSLv3"); log_crypto_err("could not set SSL_OP_NO_SSLv3");
@ -968,12 +1077,14 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem, int wincert)
log_crypto_err("could not allocate SSL_CTX pointer"); log_crypto_err("could not allocate SSL_CTX pointer");
return NULL; return NULL;
} }
#if SSL_OP_NO_SSLv2 != 0
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)
!= SSL_OP_NO_SSLv2) { != SSL_OP_NO_SSLv2) {
log_crypto_err("could not set SSL_OP_NO_SSLv2"); log_crypto_err("could not set SSL_OP_NO_SSLv2");
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
return NULL; return NULL;
} }
#endif
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
!= SSL_OP_NO_SSLv3) { != SSL_OP_NO_SSLv3) {
log_crypto_err("could not set SSL_OP_NO_SSLv3"); log_crypto_err("could not set SSL_OP_NO_SSLv3");
@ -1160,13 +1271,21 @@ int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_ses
s++; s++;
} }
keys = calloc(s, sizeof(struct tls_session_ticket_key)); keys = calloc(s, sizeof(struct tls_session_ticket_key));
if(!keys)
return 0;
memset(keys, 0, s*sizeof(*keys)); memset(keys, 0, s*sizeof(*keys));
ticket_keys = keys; ticket_keys = keys;
for(p = tls_session_ticket_keys; p; p = p->next) { for(p = tls_session_ticket_keys; p; p = p->next) {
size_t n; size_t n;
unsigned char *data = (unsigned char *)malloc(80); unsigned char *data;
FILE *f = fopen(p->str, "r"); FILE *f;
data = (unsigned char *)malloc(80);
if(!data)
return 0;
f = fopen(p->str, "r");
if(!f) { if(!f) {
log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno)); log_err("could not read tls-session-ticket-key %s: %s", p->str, strerror(errno));
free(data); free(data);

View File

@ -471,4 +471,19 @@ int tls_session_ticket_key_cb(void *s, unsigned char* key_name,unsigned char* iv
/** Free memory used for TLS session ticket keys */ /** Free memory used for TLS session ticket keys */
void listen_sslctx_delete_ticket_keys(void); void listen_sslctx_delete_ticket_keys(void);
/**
* RPZ format netblock to network byte order address and netblock
* example RPZ netblock format dnames:
* - 24.10.100.51.198.rpz-ip -> 198.51.100.10/24
* - 32.10.zz.db8.2001.rpz-ip -> 2001:db8:0:0:0:0:0:10/32
* @param dname: the dname containing RPZ format netblock
* @param dnamelen: length of dname
* @param addr: where to store sockaddr.
* @param addrlen: length of stored sockaddr is returned.
* @param net: where to store netmask
* @param af: where to store address family.
* @return 0 on error.
*/
int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af);
#endif /* NET_HELP_H */ #endif /* NET_HELP_H */

View File

@ -1120,6 +1120,14 @@ ssl_handshake(struct comm_point* c)
return 0; /* closed */ return 0; /* closed */
} else if(want == SSL_ERROR_SYSCALL) { } else if(want == SSL_ERROR_SYSCALL) {
/* SYSCALL and errno==0 means closed uncleanly */ /* SYSCALL and errno==0 means closed uncleanly */
#ifdef EPIPE
if(errno == EPIPE && verbosity < 2)
return 0; /* silence 'broken pipe' */
#endif
#ifdef ECONNRESET
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
if(errno != 0) if(errno != 0)
log_err("SSL_handshake syscall: %s", log_err("SSL_handshake syscall: %s",
strerror(errno)); strerror(errno));

View File

@ -78,7 +78,7 @@
*/ */
#define MAX_VALUE 0x7fffffff #define MAX_VALUE 0x7fffffff
#if defined(HAVE_SSL) #if defined(HAVE_SSL) || defined(HAVE_LIBBSD)
struct ub_randstate* struct ub_randstate*
ub_initstate(struct ub_randstate* ATTR_UNUSED(from)) ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
{ {
@ -183,10 +183,10 @@ long int ub_random(struct ub_randstate* s)
} }
return x & MAX_VALUE; return x & MAX_VALUE;
} }
#endif /* HAVE_SSL or HAVE_NSS or HAVE_NETTLE */ #endif /* HAVE_SSL or HAVE_LIBBSD or HAVE_NSS or HAVE_NETTLE */
#if defined(HAVE_NSS) || defined(HAVE_NETTLE) #if defined(HAVE_NSS) || defined(HAVE_NETTLE) && !defined(HAVE_LIBBSD)
long int long int
ub_random_max(struct ub_randstate* state, long int x) ub_random_max(struct ub_randstate* state, long int x)
{ {
@ -198,7 +198,7 @@ ub_random_max(struct ub_randstate* state, long int x)
v = ub_random(state); v = ub_random(state);
return (v % x); return (v % x);
} }
#endif /* HAVE_NSS or HAVE_NETTLE */ #endif /* HAVE_NSS or HAVE_NETTLE and !HAVE_LIBBSD */
void void
ub_randfree(struct ub_randstate* s) ub_randfree(struct ub_randstate* s)

View File

@ -104,11 +104,12 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
return rbtree_insert(tree, &node->node) != NULL; return rbtree_insert(tree, &node->node) != NULL;
} }
void addr_tree_init_parents(rbtree_type* tree) void addr_tree_init_parents_node(struct addr_tree_node* node)
{ {
struct addr_tree_node* node, *prev = NULL, *p; struct addr_tree_node* prev = NULL, *p;
int m; int m;
RBTREE_FOR(node, struct addr_tree_node*, tree) { for(; (rbnode_type*)node != RBTREE_NULL;
node = (struct addr_tree_node*)rbtree_next((rbnode_type*)node)) {
node->parent = NULL; node->parent = NULL;
if(!prev || prev->addrlen != node->addrlen) { if(!prev || prev->addrlen != node->addrlen) {
prev = node; prev = node;
@ -130,6 +131,12 @@ void addr_tree_init_parents(rbtree_type* tree)
} }
} }
void addr_tree_init_parents(rbtree_type* tree)
{
addr_tree_init_parents_node(
(struct addr_tree_node*)rbtree_first(tree));
}
void name_tree_init_parents(rbtree_type* tree) void name_tree_init_parents(rbtree_type* tree)
{ {
struct name_tree_node* node, *prev = NULL, *p; struct name_tree_node* node, *prev = NULL, *p;

View File

@ -173,6 +173,13 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
*/ */
void addr_tree_init_parents(rbtree_type* tree); void addr_tree_init_parents(rbtree_type* tree);
/**
* Initialize parent pointers in partial addr tree.
* Reinitialize pointer for part of tree, used after node deletion
* @param node: node to start parent pointer initialization for.
*/
void addr_tree_init_parents_node(struct addr_tree_node* node);
/** /**
* Lookup closest encloser in addr tree. * Lookup closest encloser in addr tree.
* @param tree: addr tree * @param tree: addr tree

View File

@ -54,6 +54,11 @@
#error "Need crypto library to do digital signature cryptography" #error "Need crypto library to do digital signature cryptography"
#endif #endif
/** fake DSA support for unit tests */
int fake_dsa = 0;
/** fake SHA1 support for unit tests */
int fake_sha1 = 0;
/* OpenSSL implementation */ /* OpenSSL implementation */
#ifdef HAVE_SSL #ifdef HAVE_SSL
#ifdef HAVE_OPENSSL_ERR_H #ifdef HAVE_OPENSSL_ERR_H
@ -72,11 +77,6 @@
#include <openssl/engine.h> #include <openssl/engine.h>
#endif #endif
/** fake DSA support for unit tests */
int fake_dsa = 0;
/** fake SHA1 support for unit tests */
int fake_sha1 = 0;
/** /**
* Output a libcrypto openssl error to the logfile. * Output a libcrypto openssl error to the logfile.
* @param str: string to add to it. * @param str: string to add to it.
@ -1509,13 +1509,21 @@ dnskey_algo_id_is_supported(int id)
{ {
/* uses libnettle */ /* uses libnettle */
switch(id) { switch(id) {
#if defined(USE_DSA) && defined(USE_SHA1)
case LDNS_DSA: case LDNS_DSA:
case LDNS_DSA_NSEC3: case LDNS_DSA_NSEC3:
#if defined(USE_DSA) && defined(USE_SHA1)
return 1;
#else
if(fake_dsa || fake_sha1) return 1;
return 0;
#endif #endif
#ifdef USE_SHA1
case LDNS_RSASHA1: case LDNS_RSASHA1:
case LDNS_RSASHA1_NSEC3: case LDNS_RSASHA1_NSEC3:
#ifdef USE_SHA1
return 1;
#else
if(fake_sha1) return 1;
return 0;
#endif #endif
#ifdef USE_SHA2 #ifdef USE_SHA2
case LDNS_RSASHA256: case LDNS_RSASHA256:
@ -1820,6 +1828,15 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
return sec_status_bogus; return sec_status_bogus;
} }
#ifndef USE_DSA
if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1))
return sec_status_secure;
#endif
#ifndef USE_SHA1
if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3))
return sec_status_secure;
#endif
switch(algo) { switch(algo) {
#if defined(USE_DSA) && defined(USE_SHA1) #if defined(USE_DSA) && defined(USE_SHA1)
case LDNS_DSA: case LDNS_DSA:

View File

@ -121,6 +121,8 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
log_err("out of memory"); log_err("out of memory");
return 0; return 0;
} }
if (env->key_cache)
val_env->kcache = env->key_cache;
if(!val_env->kcache) if(!val_env->kcache)
val_env->kcache = key_cache_create(cfg); val_env->kcache = key_cache_create(cfg);
if(!val_env->kcache) { if(!val_env->kcache) {
@ -146,6 +148,8 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env,
log_err("validator: cannot apply nsec3 key iterations"); log_err("validator: cannot apply nsec3 key iterations");
return 0; return 0;
} }
if (env->neg_cache)
val_env->neg_cache = env->neg_cache;
if(!val_env->neg_cache) if(!val_env->neg_cache)
val_env->neg_cache = val_neg_create(cfg, val_env->neg_cache = val_neg_create(cfg,
val_env->nsec3_maxiter[val_env->nsec3_keyiter_count-1]); val_env->nsec3_maxiter[val_env->nsec3_keyiter_count-1]);
@ -196,7 +200,9 @@ val_deinit(struct module_env* env, int id)
anchors_delete(env->anchors); anchors_delete(env->anchors);
env->anchors = NULL; env->anchors = NULL;
key_cache_delete(val_env->kcache); key_cache_delete(val_env->kcache);
env->key_cache = NULL;
neg_cache_delete(val_env->neg_cache); neg_cache_delete(val_env->neg_cache);
env->neg_cache = NULL;
free(val_env->nsec3_keysize); free(val_env->nsec3_keysize);
free(val_env->nsec3_maxiter); free(val_env->nsec3_maxiter);
free(val_env); free(val_env);

View File

@ -24,13 +24,13 @@ SRCS= alloc.c as112.c authzone.c autotrust.c cachedb.c config_file.c \
mesh.c mini_event.c modstack.c module.c msgencode.c msgparse.c \ mesh.c mini_event.c modstack.c module.c msgencode.c msgparse.c \
msgreply.c net_help.c netevent.c outbound_list.c outside_network.c \ msgreply.c net_help.c netevent.c outbound_list.c outside_network.c \
packed_rrset.c parse.c parseutil.c random.c rbtree.c redis.c \ packed_rrset.c parse.c parseutil.c random.c rbtree.c redis.c \
regional.c respip.c rrdef.c rrset.c rtt.c sbuffer.c slabhash.c \ regional.c respip.c rpz.c rrdef.c rrset.c rtt.c sbuffer.c slabhash.c \
str2wire.c tcp_conn_limit.c timehist.c tube.c ub_event_pluggable.c \ str2wire.c tcp_conn_limit.c timehist.c tube.c ub_event_pluggable.c \
val_anchor.c val_kcache.c val_kentry.c val_neg.c val_nsec.c \ val_anchor.c val_kcache.c val_kentry.c val_neg.c val_nsec.c \
val_nsec3.c val_secalgo.c val_sigcrypt.c val_utils.c validator.c \ val_nsec3.c val_secalgo.c val_sigcrypt.c val_utils.c validator.c \
view.c winsock_event.c wire2str.c view.c winsock_event.c wire2str.c
WARNS?= 3 WARNS?= 2
NO_WTHREAD_SAFETY= true NO_WTHREAD_SAFETY= true
LIBADD= ssl crypto pthread LIBADD= ssl crypto pthread