dnstap.lo dnstap.o: $(srcdir)/dnstap/dnstap.c config.h dnstap/dnstap_config.h \
dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h $(srcdir)/dnstap/dnstap.h \
$(srcdir)/util/config_file.h $(srcdir)/util/log.h \
- $(srcdir)/util/netevent.h $(srcdir)/util/net_help.h
+ $(srcdir)/util/netevent.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/locks.h
dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h: $(srcdir)/dnstap/dnstap.proto
@-if test ! -d dnstap; then $(INSTALL) -d dnstap; fi
$(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
$(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/iterator/iter_delegpt.h \
$(srcdir)/services/outside_network.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/parseutil.h \
- $(srcdir)/sldns/wire2str.h
+ $(srcdir)/sldns/wire2str.h $(srcdir)/util/edns.h
stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \
$(srcdir)/libunbound/unbound.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
if test -z "$PYTHON"; then
- AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
+ AC_MSG_ERROR([Cannot find 'python$PYTHON_VERSION' in your system path. You can use the environment variable 'PYTHON_VERSION=version_number' for an explicit version.])
PYTHON_VERSION=""
fi
/**
* Hash the query name, type, class and dbacess-secret into lookup buffer.
- * @param qstate: query state with query info
- * and env->cfg with secret.
+ * @param qinfo: query info
+ * @param env: with env->cfg with secret.
* @param buf: returned buffer with hash to lookup
* @param len: length of the buffer.
*/
static void
-calc_hash(struct module_qstate* qstate, char* buf, size_t len)
+calc_hash(struct query_info* qinfo, struct module_env* env, char* buf,
+ size_t len)
{
uint8_t clear[1024];
size_t clen = 0;
uint8_t hash[CACHEDB_HASHSIZE/8];
const char* hex = "0123456789ABCDEF";
- const char* secret = qstate->env->cfg->cachedb_secret;
+ const char* secret = env->cfg->cachedb_secret;
size_t i;
/* copy the hash info into the clear buffer */
- if(clen + qstate->qinfo.qname_len < sizeof(clear)) {
- memmove(clear+clen, qstate->qinfo.qname,
- qstate->qinfo.qname_len);
- clen += qstate->qinfo.qname_len;
+ if(clen + qinfo->qname_len < sizeof(clear)) {
+ memmove(clear+clen, qinfo->qname, qinfo->qname_len);
+ clen += qinfo->qname_len;
}
if(clen + 4 < sizeof(clear)) {
- uint16_t t = htons(qstate->qinfo.qtype);
- uint16_t c = htons(qstate->qinfo.qclass);
+ uint16_t t = htons(qinfo->qtype);
+ uint16_t c = htons(qinfo->qclass);
memmove(clear+clen, &t, 2);
memmove(clear+clen+2, &c, 2);
clen += 4;
int* msg_expired)
{
char key[(CACHEDB_HASHSIZE/8)*2+1];
- calc_hash(qstate, key, sizeof(key));
+ calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
/* call backend to fetch data for key into scratch buffer */
if( !(*ie->backend->lookup)(qstate->env, ie, key,
cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
{
char key[(CACHEDB_HASHSIZE/8)*2+1];
- calc_hash(qstate, key, sizeof(key));
+ calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
/* prepare data in scratch buffer */
if(!prep_data(qstate, qstate->env->scratch_buffer))
* going to be now-3 seconds. Making it expired
* in the cache. */
set_msg_ttl(qstate->return_msg, (time_t)-3);
+ /* The expired entry does not get checked by the validator
+ * and we need a validation value for it. */
+ if(qstate->env->cfg->cachedb_check_when_serve_expired)
+ qstate->return_msg->rep->security = sec_status_insecure;
}
(void)dns_cache_store(qstate->env, &qstate->qinfo,
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
*/
static struct module_func_block cachedb_block = {
"cachedb",
- &cachedb_init, &cachedb_deinit, &cachedb_operate,
+ NULL, NULL, &cachedb_init, &cachedb_deinit, &cachedb_operate,
&cachedb_inform_super, &cachedb_clear, &cachedb_get_mem
};
}
void cachedb_msg_remove(struct module_qstate* qstate)
+{
+ cachedb_msg_remove_qinfo(qstate->env, &qstate->qinfo);
+}
+
+void cachedb_msg_remove_qinfo(struct module_env* env, struct query_info* qinfo)
{
char key[(CACHEDB_HASHSIZE/8)*2+1];
- int id = modstack_find(qstate->env->modstack, "cachedb");
- struct cachedb_env* ie = (struct cachedb_env*)qstate->env->modinfo[id];
+ int id = modstack_find(env->modstack, "cachedb");
+ struct cachedb_env* ie = (struct cachedb_env*)env->modinfo[id];
- log_query_info(VERB_ALGO, "cachedb msg remove", &qstate->qinfo);
- calc_hash(qstate, key, sizeof(key));
- sldns_buffer_clear(qstate->env->scratch_buffer);
- sldns_buffer_write_u32(qstate->env->scratch_buffer, 0);
- sldns_buffer_flip(qstate->env->scratch_buffer);
+ log_query_info(VERB_ALGO, "cachedb msg remove", qinfo);
+ calc_hash(qinfo, env, key, sizeof(key));
+ sldns_buffer_clear(env->scratch_buffer);
+ sldns_buffer_write_u32(env->scratch_buffer, 0);
+ sldns_buffer_flip(env->scratch_buffer);
/* call backend */
- (*ie->backend->store)(qstate->env, ie, key,
- sldns_buffer_begin(qstate->env->scratch_buffer),
- sldns_buffer_limit(qstate->env->scratch_buffer),
+ (*ie->backend->store)(env, ie, key,
+ sldns_buffer_begin(env->scratch_buffer),
+ sldns_buffer_limit(env->scratch_buffer),
0);
}
#endif /* USE_CACHEDB */
* @param qstate: query state.
*/
void cachedb_msg_remove(struct module_qstate* qstate);
+
+/**
+ * Remove message from the cachedb cache, by query info.
+ * @param env: module environment to look up cachedb state.
+ * @param qinfo: the message to remove.
+ */
+void cachedb_msg_remove_qinfo(struct module_env* env,
+ struct query_info* qinfo);
# shellcheck disable=SC2006,SC2268 # see below for rationale
-timestamp='2024-01-01'
+timestamp='2024-07-27'
# 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
dummy=$tmp/dummy
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
,,) echo "int x;" > "$dummy.c"
- for driver in cc gcc c89 c99 ; do
+ for driver in cc gcc c17 c99 c89 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
CC_FOR_BUILD=$driver
break
sed 's/^ //' << EOF > "$dummy.c"
#include <sys/systemcfg.h>
+ int
main()
{
if (!__power_pc())
#include <stdlib.h>
#include <unistd.h>
- int main ()
+ int
+ main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
#endif
#endif
#endif
+int
main ()
{
#if defined (sony)
/* config.h.in. Generated from configure.ac by autoheader. */
+/* apply the fallthrough attribute. */
+#undef ATTR_FALLTHROUGH
+
/* apply the noreturn attribute to a function that exits the program */
#undef ATTR_NORETURN
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
+/* Whether the C compiler accepts the "fallthrough" attribute */
+#undef HAVE_ATTR_FALLTHROUGH
+
/* Whether the C compiler accepts the "format" attribute */
#undef HAVE_ATTR_FORMAT
/* Define to 1 if you have the <net/if.h> header file. */
#undef HAVE_NET_IF_H
+/* Define to 1 if you have the <net/pfvar.h> header file. */
+#undef HAVE_NET_PFVAR_H
+
/* Define this to use nghttp2 client. */
#undef HAVE_NGHTTP2
function. */
#undef HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_EVP_CB
+/* Define to 1 if you have the `SSL_CTX_set_tmp_ecdh' function. */
+#undef HAVE_SSL_CTX_SET_TMP_ECDH
+
/* Define to 1 if you have the `SSL_get0_alpn_selected' function. */
#undef HAVE_SSL_GET0_ALPN_SELECTED
# define calloc(n,s) unbound_stat_calloc_log(n, s, __FILE__, __LINE__, __func__)
# define free(p) unbound_stat_free_log(p, __FILE__, __LINE__, __func__)
# define realloc(p,s) unbound_stat_realloc_log(p, s, __FILE__, __LINE__, __func__)
+# define strdup(s) unbound_stat_strdup_log(s, __FILE__, __LINE__, __func__)
void *unbound_stat_malloc(size_t size);
void *unbound_stat_calloc(size_t nmemb, size_t size);
void unbound_stat_free(void *ptr);
const char* func);
void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
int line, const char* func);
+char *unbound_stat_strdup_log(const char *s, const char* file, int line,
+ const char* func);
#elif defined(UNBOUND_ALLOC_LITE)
# include "util/alloc.h"
#endif /* UNBOUND_ALLOC_LITE and UNBOUND_ALLOC_STATS */
# Configuration validation subroutine script.
# Copyright 1992-2024 Free Software Foundation, Inc.
-# shellcheck disable=SC2006,SC2268 # see below for rationale
+# shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale
-timestamp='2024-01-01'
+timestamp='2024-05-27'
# 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
esac
# Split fields of configuration type
-# shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read field1 field2 field3 field4 <<EOF
$1
# parts
maybe_os=$field2-$field3
case $maybe_os in
- nto-qnx* | linux-* | uclinux-uclibc* \
- | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
+ cloudabi*-eabi* \
+ | kfreebsd*-gnu* \
+ | knetbsd*-gnu* \
+ | kopensolaris*-gnu* \
+ | linux-* \
+ | managarm-* \
+ | netbsd*-eabi* \
+ | netbsd*-gnu* \
+ | nto-qnx* \
+ | os2-emx* \
+ | rtmk-nova* \
+ | storm-chaos* \
+ | uclinux-gnu* \
+ | uclinux-uclibc* \
| windows-* )
basic_machine=$field1
basic_os=$maybe_os
esac
;;
*-*)
- # A lone config we happen to match not fitting any pattern
case $field1-$field2 in
+ # Shorthands that happen to contain a single dash
+ convex-c[12] | convex-c3[248])
+ basic_machine=$field2-convex
+ basic_os=
+ ;;
decstation-3100)
basic_machine=mips-dec
basic_os=
*-*)
# Second component is usually, but not always the OS
case $field2 in
- # Prevent following clause from handling this valid os
+ # Do not treat sunos as a manufacturer
sun*os*)
basic_machine=$field1
basic_os=$field2
;;
- zephyr*)
- basic_machine=$field1-unknown
- basic_os=$field2
- ;;
# Manufacturers
- dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
- | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
- | unicom* | ibm* | next | hp | isi* | apollo | altos* \
- | convergent* | ncr* | news | 32* | 3600* | 3100* \
- | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
- | ultra | tti* | harris | dolphin | highlevel | gould \
- | cbm | ns | masscomp | apple | axis | knuth | cray \
- | microblaze* | sim | cisco \
- | oki | wec | wrs | winbond)
+ 3100* \
+ | 32* \
+ | 3300* \
+ | 3600* \
+ | 7300* \
+ | acorn \
+ | altos* \
+ | apollo \
+ | apple \
+ | atari \
+ | att* \
+ | axis \
+ | be \
+ | bull \
+ | cbm \
+ | ccur \
+ | cisco \
+ | commodore \
+ | convergent* \
+ | convex* \
+ | cray \
+ | crds \
+ | dec* \
+ | delta* \
+ | dg \
+ | digital \
+ | dolphin \
+ | encore* \
+ | gould \
+ | harris \
+ | highlevel \
+ | hitachi* \
+ | hp \
+ | ibm* \
+ | intergraph \
+ | isi* \
+ | knuth \
+ | masscomp \
+ | microblaze* \
+ | mips* \
+ | motorola* \
+ | ncr* \
+ | news \
+ | next \
+ | ns \
+ | oki \
+ | omron* \
+ | pc533* \
+ | rebel \
+ | rom68k \
+ | rombug \
+ | semi \
+ | sequent* \
+ | siemens \
+ | sgi* \
+ | siemens \
+ | sim \
+ | sni \
+ | sony* \
+ | stratus \
+ | sun \
+ | sun[234]* \
+ | tektronix \
+ | tti* \
+ | ultra \
+ | unicom* \
+ | wec \
+ | winbond \
+ | wrs)
basic_machine=$field1-$field2
basic_os=
;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
+ ;;
*)
basic_machine=$field1
basic_os=$field2
basic_machine=arm-unknown
basic_os=cegcc
;;
- convex-c1)
- basic_machine=c1-convex
- basic_os=bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- basic_os=bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- basic_os=bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- basic_os=bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- basic_os=bsd
- ;;
cray)
basic_machine=j90-cray
basic_os=unicos
vendor=dec
basic_os=tops20
;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
+ delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
cpu=m68k
vendor=motorola
;;
- dpx2*)
+ # This used to be dpx2*, but that gets the RS6000-based
+ # DPX/20 and the x86-based DPX/2-100 wrong. See
+ # https://oldskool.silicium.org/stations/bull_dpx20.htm
+ # https://www.feb-patrimoine.com/english/bull_dpx2.htm
+ # https://www.feb-patrimoine.com/english/unix_and_bull.htm
+ dpx2 | dpx2[23]00 | dpx2[23]xx)
cpu=m68k
vendor=bull
- basic_os=sysv3
+ ;;
+ dpx2100 | dpx21xx)
+ cpu=i386
+ vendor=bull
+ ;;
+ dpx20)
+ cpu=rs6000
+ vendor=bull
;;
encore | umax | mmax)
cpu=ns32k
next | m*-next)
cpu=m68k
vendor=next
- case $basic_os in
- openstep*)
- ;;
- nextstep*)
- ;;
- ns2*)
- basic_os=nextstep2
- ;;
- *)
- basic_os=nextstep3
- ;;
- esac
;;
np1)
cpu=np1
;;
*-*)
- # shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read cpu vendor <<EOF
$basic_machine
# Decode basic machines in the full and proper CPU-Company form.
case $cpu-$vendor in
- # Here we handle the default manufacturer of certain CPU types in canonical form. It is in
- # some cases the only manufacturer, in others, it is the most popular.
+ # Here we handle the default manufacturer of certain CPU types in canonical form.
+ # It is in some cases the only manufacturer, in others, it is the most popular.
+ c[12]-convex | c[12]-unknown | c3[248]-convex | c3[248]-unknown)
+ vendor=convex
+ basic_os=${basic_os:-bsd}
+ ;;
craynv-unknown)
vendor=cray
basic_os=${basic_os:-unicosmp}
;;
c90-unknown | c90-cray)
vendor=cray
- basic_os=${Basic_os:-unicos}
+ basic_os=${basic_os:-unicos}
;;
fx80-unknown)
vendor=alliant
vendor=alt
basic_os=${basic_os:-linux-gnueabihf}
;;
- dpx20-unknown | dpx20-bull)
- cpu=rs6000
- vendor=bull
+
+ # Normalized CPU+vendor pairs that imply an OS, if not otherwise specified
+ m68k-isi)
+ basic_os=${basic_os:-sysv}
+ ;;
+ m68k-sony)
+ basic_os=${basic_os:-newsos}
+ ;;
+ m68k-tektronix)
+ basic_os=${basic_os:-bsd}
+ ;;
+ m88k-harris)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ i386-bull | m68k-bull)
+ basic_os=${basic_os:-sysv3}
+ ;;
+ rs6000-bull)
basic_os=${basic_os:-bosx}
;;
+ mips-sni)
+ basic_os=${basic_os:-sysv4}
+ ;;
# Here we normalize CPU types irrespective of the vendor
amd64-*)
;;
blackfin-*)
cpu=bfin
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
c54x-*)
cpu=tic54x
;;
m68knommu-*)
cpu=m68k
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
cpu=s12z
;;
parisc-*)
cpu=hppa
- basic_os=linux
+ basic_os=${basic_os:-linux}
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
cpu=i586
pentium4-*)
cpu=i786
;;
- pc98-*)
- cpu=i386
- ;;
ppc-* | ppcbe-*)
cpu=powerpc
;;
tx39el-*)
cpu=mipstx39el
;;
- x64-*)
- cpu=x86_64
- ;;
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
# Recognize the canonical CPU types that are allowed with any
# company name.
case $cpu in
- 1750a | 580 \
+ 1750a \
+ | 580 \
+ | [cjt]90 \
| a29k \
- | aarch64 | aarch64_be | aarch64c | arm64ec \
+ | aarch64 \
+ | aarch64_be \
+ | aarch64c \
| abacus \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
- | alphapca5[67] | alpha64pca5[67] \
+ | alpha \
+ | alpha64 \
+ | alpha64ev56 \
+ | alpha64ev6[78] \
+ | alpha64ev[4-8] \
+ | alpha64pca5[67] \
+ | alphaev56 \
+ | alphaev6[78] \
+ | alphaev[4-8] \
+ | alphapca5[67] \
| am33_2.0 \
| amdgcn \
- | arc | arceb | arc32 | arc64 \
- | arm | arm[lb]e | arme[lb] | armv* \
- | avr | avr32 \
+ | arc \
+ | arc32 \
+ | arc64 \
+ | arceb \
+ | arm \
+ | arm64e \
+ | arm64ec \
+ | arm[lb]e \
+ | arme[lb] \
+ | armv* \
| asmjs \
+ | avr \
+ | avr32 \
| ba \
- | be32 | be64 \
- | bfin | bpf | bs2000 \
- | c[123]* | c30 | [cjt]90 | c4x \
- | c8051 | clipper | craynv | csky | cydra \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | elxsi | epiphany \
- | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
- | javascript \
- | h8300 | h8500 \
- | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | be32 \
+ | be64 \
+ | bfin \
+ | bpf \
+ | bs2000 \
+ | c30 \
+ | c4x \
+ | c8051 \
+ | c[123]* \
+ | clipper \
+ | craynv \
+ | csky \
+ | cydra \
+ | d10v \
+ | d30v \
+ | dlx \
+ | dsp16xx \
+ | e2k \
+ | elxsi \
+ | epiphany \
+ | f30[01] \
+ | f700 \
+ | fido \
+ | fr30 \
+ | frv \
+ | ft32 \
+ | fx80 \
+ | h8300 \
+ | h8500 \
| hexagon \
- | i370 | i*86 | i860 | i960 | ia16 | ia64 \
- | ip2k | iq2000 \
+ | hppa \
+ | hppa1.[01] \
+ | hppa2.0 \
+ | hppa2.0[nw] \
+ | hppa64 \
+ | i*86 \
+ | i370 \
+ | i860 \
+ | i960 \
+ | ia16 \
+ | ia64 \
+ | ip2k \
+ | iq2000 \
+ | javascript \
| k1om \
| kvx \
- | le32 | le64 \
+ | le32 \
+ | le64 \
| lm32 \
- | loongarch32 | loongarch64 \
- | m32c | m32r | m32rle \
- | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
- | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
- | m88110 | m88k | maxq | mb | mcore | mep | metag \
- | microblaze | microblazeel \
+ | loongarch32 \
+ | loongarch64 \
+ | m32c \
+ | m32r \
+ | m32rle \
+ | m5200 \
+ | m68000 \
+ | m680[012346]0 \
+ | m6811 \
+ | m6812 \
+ | m68360 \
+ | m683?2 \
+ | m68hc11 \
+ | m68hc12 \
+ | m68hcs12x \
+ | m68k \
+ | m88110 \
+ | m88k \
+ | maxq \
+ | mb \
+ | mcore \
+ | mep \
+ | metag \
+ | microblaze \
+ | microblazeel \
| mips* \
| mmix \
- | mn10200 | mn10300 \
+ | mn10200 \
+ | mn10300 \
| moxie \
- | mt \
| msp430 \
+ | mt \
| nanomips* \
- | nds32 | nds32le | nds32be \
+ | nds32 \
+ | nds32be \
+ | nds32le \
| nfp \
- | nios | nios2 | nios2eb | nios2el \
- | none | np1 | ns16k | ns32k | nvptx \
+ | nios \
+ | nios2 \
+ | nios2eb \
+ | nios2el \
+ | none \
+ | np1 \
+ | ns16k \
+ | ns32k \
+ | nvptx \
| open8 \
| or1k* \
| or32 \
| orion \
+ | pdp10 \
+ | pdp11 \
| picochip \
- | pdp10 | pdp11 | pj | pjl | pn | power \
- | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+ | pj \
+ | pjl \
+ | pn \
+ | power \
+ | powerpc \
+ | powerpc64 \
+ | powerpc64le \
+ | powerpcle \
+ | powerpcspe \
| pru \
| pyramid \
- | riscv | riscv32 | riscv32be | riscv64 | riscv64be \
- | rl78 | romp | rs6000 | rx \
- | s390 | s390x \
+ | riscv \
+ | riscv32 \
+ | riscv32be \
+ | riscv64 \
+ | riscv64be \
+ | rl78 \
+ | romp \
+ | rs6000 \
+ | rx \
+ | s390 \
+ | s390x \
| score \
- | sh | shl \
- | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
- | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+ | sh \
+ | sh64 \
+ | sh64le \
+ | sh[12345][lb]e \
+ | sh[1234] \
+ | sh[1234]e[lb] \
+ | sh[23]e \
+ | sh[23]ele \
+ | sh[24]a \
+ | sh[24]ae[lb] \
+ | sh[lb]e \
+ | she[lb] \
+ | shl \
+ | sparc \
+ | sparc64 \
+ | sparc64b \
+ | sparc64v \
+ | sparc86x \
+ | sparclet \
| sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+ | sparcv8 \
+ | sparcv9 \
+ | sparcv9b \
+ | sparcv9v \
| spu \
+ | sv1 \
+ | sx* \
| tahoe \
| thumbv7* \
- | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+ | tic30 \
+ | tic4x \
+ | tic54x \
+ | tic55x \
+ | tic6x \
+ | tic80 \
| tron \
| ubicom32 \
- | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | v70 \
+ | v810 \
+ | v850 \
+ | v850e \
+ | v850e1 \
+ | v850e2 \
+ | v850e2v3 \
+ | v850es \
| vax \
| vc4 \
| visium \
| w65 \
- | wasm32 | wasm64 \
+ | wasm32 \
+ | wasm64 \
| we32k \
- | x86 | x86_64 | xc16x | xgate | xps100 \
- | xstormy16 | xtensa* \
+ | x86 \
+ | x86_64 \
+ | xc16x \
+ | xgate \
+ | xps100 \
+ | xstormy16 \
+ | xtensa* \
| ymp \
- | z8k | z80)
+ | z80 \
+ | z8k)
;;
*)
os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
;;
*-*)
- # shellcheck disable=SC2162
saved_IFS=$IFS
IFS="-" read kernel os <<EOF
$basic_os
unixware*)
os=sysv4.2uw
;;
+ # The marketing names for NeXT's operating systems were
+ # NeXTSTEP, NeXTSTEP 2, OpenSTEP 3, OpenSTEP 4. 'openstep' is
+ # mapped to 'openstep3', but 'openstep1' and 'openstep2' are
+ # mapped to 'nextstep' and 'nextstep2', consistent with the
+ # treatment of SunOS/Solaris.
+ ns | ns1 | nextstep | nextstep1 | openstep1)
+ os=nextstep
+ ;;
+ ns2 | nextstep2 | openstep2)
+ os=nextstep2
+ ;;
+ ns3 | nextstep3 | openstep | openstep3)
+ os=openstep3
+ ;;
+ ns4 | nextstep4 | openstep4)
+ os=openstep4
+ ;;
# es1800 is here to avoid being matched by es* (a different OS)
es1800*)
os=ose
;;
utek*)
os=bsd
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|tektronix|'`
;;
dynix*)
os=bsd
386bsd)
os=bsd
;;
- ctix* | uts*)
+ ctix*)
os=sysv
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|convergent|'`
;;
- nova*)
- os=rtmk-nova
+ uts*)
+ os=sysv
;;
- ns2)
- os=nextstep2
+ nova*)
+ kernel=rtmk
+ os=nova
;;
# Preserve the version number of sinix5.
sinix5.*)
os=`echo "$os" | sed -e 's|sinix|sysv|'`
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
sinix*)
os=sysv4
+ vendor=`echo "$vendor" | sed -e 's|^unknown$|sni|'`
;;
tpf*)
os=tpf
os=
obj=elf
;;
+ # The -sgi and -siemens entries must be before the mips- entry
+ # or we get the wrong os.
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
+ ;;
mips*-cisco)
os=
obj=elf
os=
obj=coff
;;
- *-tti) # must be before sparc entry or we get the wrong os.
+ # This must be before the sparc-* entry or we get the wrong os.
+ *-tti)
os=sysv3
;;
sparc-* | *-sun)
os=hpux
;;
*-hitachi)
- os=hiux
+ os=hiuxwe2
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
os=sysv
*-encore)
os=bsd
;;
- *-sgi)
- os=irix
- ;;
- *-siemens)
- os=sysv4
- ;;
*-masscomp)
os=rtu
;;
ghcjs)
;;
# Now accept the basic system types.
- # The portable systems comes first.
# Each alternative MUST end in a * to match a version number.
- gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
- | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
- | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
- | hiux* | abug | nacl* | netware* | windows* \
- | os9* | macos* | osx* | ios* | tvos* | watchos* \
- | mpw* | magic* | mmixware* | mon960* | lnews* \
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
- | aos* | aros* | cloudabi* | sortix* | twizzler* \
- | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
- | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
- | mirbsd* | netbsd* | dicos* | openedition* | ose* \
- | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
- | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
- | bosx* | nextstep* | cxux* | oabi* \
- | ptx* | ecoff* | winnt* | domain* | vsta* \
- | udi* | lites* | ieee* | go32* | aux* | hcos* \
- | chorusrdb* | cegcc* | glidix* | serenity* \
- | cygwin* | msys* | moss* | proelf* | rtems* \
- | midipix* | mingw32* | mingw64* | mint* \
- | uxpv* | beos* | mpeix* | udk* | moxiebox* \
- | interix* | uwin* | mks* | rhapsody* | darwin* \
- | openstep* | oskit* | conix* | pw32* | nonstopux* \
- | storm-chaos* | tops10* | tenex* | tops20* | its* \
- | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
- | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
- | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
- | skyos* | haiku* | rdos* | toppers* | drops* | es* \
- | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
- | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
- | fiwix* | mlibc* | cos* | mbr* | ironclad* )
+ abug \
+ | aix* \
+ | amdhsa* \
+ | amigados* \
+ | amigaos* \
+ | android* \
+ | aof* \
+ | aos* \
+ | aros* \
+ | atheos* \
+ | auroraux* \
+ | aux* \
+ | beos* \
+ | bitrig* \
+ | bme* \
+ | bosx* \
+ | bsd* \
+ | cegcc* \
+ | chorusos* \
+ | chorusrdb* \
+ | clix* \
+ | cloudabi* \
+ | cnk* \
+ | conix* \
+ | cos* \
+ | cxux* \
+ | cygwin* \
+ | darwin* \
+ | dgux* \
+ | dicos* \
+ | dnix* \
+ | domain* \
+ | dragonfly* \
+ | drops* \
+ | ebmon* \
+ | ecoff* \
+ | ekkobsd* \
+ | emscripten* \
+ | emx* \
+ | es* \
+ | fiwix* \
+ | freebsd* \
+ | fuchsia* \
+ | genix* \
+ | genode* \
+ | glidix* \
+ | gnu* \
+ | go32* \
+ | haiku* \
+ | hcos* \
+ | hiux* \
+ | hms* \
+ | hpux* \
+ | ieee* \
+ | interix* \
+ | ios* \
+ | iris* \
+ | irix* \
+ | ironclad* \
+ | isc* \
+ | its* \
+ | l4re* \
+ | libertybsd* \
+ | lites* \
+ | lnews* \
+ | luna* \
+ | lynxos* \
+ | mach* \
+ | macos* \
+ | magic* \
+ | mbr* \
+ | midipix* \
+ | midnightbsd* \
+ | mingw32* \
+ | mingw64* \
+ | minix* \
+ | mint* \
+ | mirbsd* \
+ | mks* \
+ | mlibc* \
+ | mmixware* \
+ | mon960* \
+ | morphos* \
+ | moss* \
+ | moxiebox* \
+ | mpeix* \
+ | mpw* \
+ | msdos* \
+ | msys* \
+ | mvs* \
+ | nacl* \
+ | netbsd* \
+ | netware* \
+ | newsos* \
+ | nextstep* \
+ | nindy* \
+ | nonstopux* \
+ | nova* \
+ | nsk* \
+ | nucleus* \
+ | nx6 \
+ | nx7 \
+ | oabi* \
+ | ohos* \
+ | onefs* \
+ | openbsd* \
+ | openedition* \
+ | openstep* \
+ | os108* \
+ | os2* \
+ | os400* \
+ | os68k* \
+ | os9* \
+ | ose* \
+ | osf* \
+ | oskit* \
+ | osx* \
+ | palmos* \
+ | phoenix* \
+ | plan9* \
+ | powermax* \
+ | powerunix* \
+ | proelf* \
+ | psos* \
+ | psp* \
+ | ptx* \
+ | pw32* \
+ | qnx* \
+ | rdos* \
+ | redox* \
+ | rhapsody* \
+ | riscix* \
+ | riscos* \
+ | rtems* \
+ | rtmk* \
+ | rtu* \
+ | scout* \
+ | secbsd* \
+ | sei* \
+ | serenity* \
+ | sim* \
+ | skyos* \
+ | solaris* \
+ | solidbsd* \
+ | sortix* \
+ | storm-chaos* \
+ | sunos \
+ | sunos[34]* \
+ | superux* \
+ | syllable* \
+ | sym* \
+ | sysv* \
+ | tenex* \
+ | tirtos* \
+ | toppers* \
+ | tops10* \
+ | tops20* \
+ | tpf* \
+ | tvos* \
+ | twizzler* \
+ | uclinux* \
+ | udi* \
+ | udk* \
+ | ultrix* \
+ | unicos* \
+ | uniplus* \
+ | unleashed* \
+ | unos* \
+ | uwin* \
+ | uxpv* \
+ | v88r* \
+ |*vms* \
+ | vos* \
+ | vsta* \
+ | vxsim* \
+ | vxworks* \
+ | wasi* \
+ | watchos* \
+ | wince* \
+ | windiss* \
+ | windows* \
+ | winnt* \
+ | xenix* \
+ | xray* \
+ | zephyr* \
+ | zvmoe* )
;;
# This one is extra strict with allowed versions
sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
case $kernel-$os-$obj in
linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
| linux-mlibc*- | linux-musl*- | linux-newlib*- \
- | linux-relibc*- | linux-uclibc*- )
+ | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
;;
- uclinux-uclibc*- )
+ uclinux-uclibc*- | uclinux-gnu*- )
;;
managarm-mlibc*- | managarm-kernel*- )
;;
echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
exit 1
;;
- kfreebsd*-gnu*- | kopensolaris*-gnu*-)
+ kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
;;
vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
;;
;;
os2-emx-)
;;
+ rtmk-nova-)
+ ;;
*-eabi*- | *-gnueabi*-)
;;
none--*)
*-riscix*)
vendor=acorn
;;
- *-sunos*)
+ *-sunos* | *-solaris*)
vendor=sun
;;
*-cnk* | *-aix*)
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for unbound 1.20.0.
+# Generated by GNU Autoconf 2.71 for unbound 1.21.0.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.20.0'
-PACKAGE_STRING='unbound 1.20.0'
+PACKAGE_VERSION='1.21.0'
+PACKAGE_STRING='unbound 1.21.0'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures unbound 1.20.0 to adapt to many kinds of systems.
+\`configure' configures unbound 1.21.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of unbound 1.20.0:";;
+ short | recursive ) echo "Configuration of unbound 1.21.0:";;
esac
cat <<\_ACEOF
--disable-libtool-lock avoid locking (might break parallel builds)
--disable-rpath disable hardcoded rpath (default=enabled)
--disable-largefile omit support for large files
- --enable-systemd compile with systemd support
+ --enable-systemd compile with systemd support (requires libsystemd,
+ pkg-config)
--enable-alloc-checks enable to memory allocation statistics, for debug
purposes
--enable-alloc-lite enable for lightweight alloc assertions, for debug
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unbound configure 1.20.0
+unbound configure 1.21.0
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by unbound $as_me 1.20.0, which was
+It was created by unbound $as_me 1.21.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
UNBOUND_VERSION_MAJOR=1
-UNBOUND_VERSION_MINOR=20
+UNBOUND_VERSION_MINOR=21
UNBOUND_VERSION_MICRO=0
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=27
+LIBUNBOUND_REVISION=28
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
# 1.19.2 had 9:25:1
# 1.19.3 had 9:26:1
# 1.20.0 had 9:27:1
+# 1.21.0 had 9:28:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
printf "%s\n" "#define ATTR_WEAK __attribute__((weak))" >>confdefs.h
+else
+
+printf "%s\n" "#define ATTR_WEAK /**/" >>confdefs.h
+
fi
printf "%s\n" "#define ATTR_NORETURN __attribute__((__noreturn__))" >>confdefs.h
+else
+
+printf "%s\n" "#define ATTR_NORETURN /**/" >>confdefs.h
+
+fi
+
+
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"fallthrough\" attribute" >&5
+printf %s "checking whether the C compiler (${CC-cc}) accepts the \"fallthrough\" attribute... " >&6; }
+BAKCFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+if test ${ac_cv_c_fallthrough_attribute+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_c_fallthrough_attribute=no
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <stdio.h>
+void f(int x) {
+ int y = 0;
+ switch(x) {
+ case 1:
+ y = 1;
+ __attribute__((fallthrough));
+ /* fallthrough */
+ case 2:
+ y++;
+ break;
+ case 3:
+ y = 3;
+ break;
+ }
+ printf("%d", y);
+}
+
+int
+main (void)
+{
+
+ f(1);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_c_fallthrough_attribute="yes"
+else $as_nop
+ ac_cv_c_fallthrough_attribute="no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+
+fi
+
+CFLAGS="$BAKCFLAGS"
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_fallthrough_attribute" >&5
+printf "%s\n" "$ac_cv_c_fallthrough_attribute" >&6; }
+if test $ac_cv_c_fallthrough_attribute = yes; then
+
+printf "%s\n" "#define HAVE_ATTR_FALLTHROUGH 1" >>confdefs.h
+
+
+printf "%s\n" "#define ATTR_FALLTHROUGH __attribute__((fallthrough));" >>confdefs.h
+
+else
+
+printf "%s\n" "#define ATTR_FALLTHROUGH /**/" >>confdefs.h
+
fi
if test "x$enable_systemd" != xno
then :
-
+ if test -n "$PKG_CONFIG"; then
+ have_systemd=no
pkg_failed=no
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
# Put the nasty error message in config.log where it belongs
echo "$SYSTEMD_PKG_ERRORS" >&5
- have_systemd=no
+ as_fn_error $? "Package requirements (libsystemd) were not met:
+
+$SYSTEMD_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables SYSTEMD_CFLAGS
+and SYSTEMD_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
- have_systemd=no
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables SYSTEMD_CFLAGS
+and SYSTEMD_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
else
SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
if test "x$have_systemd" != "xyes"
then :
+ have_systemd_daemon=no
pkg_failed=no
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD_DAEMON" >&5
# Put the nasty error message in config.log where it belongs
echo "$SYSTEMD_DAEMON_PKG_ERRORS" >&5
- have_systemd_daemon=no
+ as_fn_error $? "Package requirements (libsystemd-daemon) were not met:
+
+$SYSTEMD_DAEMON_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables SYSTEMD_DAEMON_CFLAGS
+and SYSTEMD_DAEMON_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
elif test $pkg_failed = untried; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
- have_systemd_daemon=no
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables SYSTEMD_DAEMON_CFLAGS
+and SYSTEMD_DAEMON_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
else
SYSTEMD_DAEMON_CFLAGS=$pkg_cv_SYSTEMD_DAEMON_CFLAGS
SYSTEMD_DAEMON_LIBS=$pkg_cv_SYSTEMD_DAEMON_LIBS
*) :
;;
esac
-
+ else
+ as_fn_error $? "systemd enabled but need pkg-config to configure for it" "$LINENO" 5
+ fi
fi
if test "x$have_systemd" = xyes; then
if test -z "$PYTHON"; then
- as_fn_error $? "Cannot find python$PYTHON_VERSION in your system path" "$LINENO" 5
+ as_fn_error $? "Cannot find 'python$PYTHON_VERSION' in your system path. You can use the environment variable 'PYTHON_VERSION=version_number' for an explicit version." "$LINENO" 5
PYTHON_VERSION=""
fi
printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "SSL_CTX_set_tmp_ecdh" "ac_cv_func_SSL_CTX_set_tmp_ecdh"
+if test "x$ac_cv_func_SSL_CTX_set_tmp_ecdh" = xyes
+then :
+ printf "%s\n" "#define HAVE_SSL_CTX_SET_TMP_ECDH 1" >>confdefs.h
+
+fi
# these check_funcs need -lssl
;;
*)
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
+ ac_fn_c_check_func "$LINENO" "EVP_PKEY_fromdata" "ac_cv_func_EVP_PKEY_fromdata"
+if test "x$ac_cv_func_EVP_PKEY_fromdata" = xyes
+then :
+
+ # with EVP_PKEY_fromdata, check if EC is not disabled
+ ac_fn_check_decl "$LINENO" "OPENSSL_NO_EC" "ac_cv_have_decl_OPENSSL_NO_EC" "$ac_includes_default
+#include <openssl/evp.h>
+
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
+if test "x$ac_cv_have_decl_OPENSSL_NO_EC" = xyes
+then :
+ as_fn_error $? "OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5
+
+fi
+
+else $as_nop
+
+ # without EVP_PKEY_fromdata, older openssl, check for support
ac_fn_c_check_func "$LINENO" "ECDSA_sign" "ac_cv_func_ECDSA_sign"
if test "x$ac_cv_func_ECDSA_sign" = xyes
then :
else $as_nop
as_fn_error $? "OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa" "$LINENO" 5
+fi
+
+
fi
ac_fn_check_decl "$LINENO" "NID_X9_62_prime256v1" "ac_cv_have_decl_NID_X9_62_prime256v1" "$ac_includes_default
else $as_nop
-
+ if test -n "$PKG_CONFIG"; then
pkg_failed=no
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PROTOBUFC" >&5
LIBS="$LIBS $PROTOBUFC_LIBS"
fi
-
+ else
+ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
+ if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/include/google"
+ else
+ if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/local/include/google"
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ fi
+ fi
+ fi
fi
IPSET_OBJ="ipset.lo"
+ # BSD's pf
+ for ac_header in net/pfvar.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "net/pfvar.h" "ac_cv_header_net_pfvar_h" "
+ #include <netinet/in.h>
+ #include <net/if.h>
+
+"
+if test "x$ac_cv_header_net_pfvar_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_NET_PFVAR_H 1" >>confdefs.h
+
+else $as_nop
+
# mnl
# Check whether --with-libmnl was given.
if test x_$found_libmnl != x_yes; then
as_fn_error $? "Could not find libmnl, libmnl.h" "$LINENO" 5
fi
+
+fi
+
+done
;;
no|*)
# nothing
-version=1.20.0
+version=1.21.0
date=`date +'%b %e, %Y'`
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by unbound $as_me 1.20.0, which was
+This file was extended by unbound $as_me 1.21.0, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-unbound config.status 1.20.0
+unbound config.status 1.21.0
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
-
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
-m4_define([VERSION_MINOR],[20])
+m4_define([VERSION_MINOR],[21])
m4_define([VERSION_MICRO],[0])
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_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
-LIBUNBOUND_REVISION=27
+LIBUNBOUND_REVISION=28
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
# 1.19.2 had 9:25:1
# 1.19.3 had 9:26:1
# 1.20.0 had 9:27:1
+# 1.21.0 had 9:28:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
if test $ac_cv_c_weak_attribute = yes; then
AC_DEFINE(HAVE_ATTR_WEAK, 1, [Whether the C compiler accepts the "weak" attribute])
AC_DEFINE(ATTR_WEAK, [__attribute__((weak))], [apply the weak attribute to a symbol])
+else
+ AC_DEFINE(ATTR_WEAK,[], [apply the weak attribute to a symbol])
fi
])dnl End of CHECK_WEAK_ATTRIBUTE
if test $ac_cv_c_noreturn_attribute = yes; then
AC_DEFINE(HAVE_ATTR_NORETURN, 1, [Whether the C compiler accepts the "noreturn" attribute])
AC_DEFINE(ATTR_NORETURN, [__attribute__((__noreturn__))], [apply the noreturn attribute to a function that exits the program])
+else
+ AC_DEFINE(ATTR_NORETURN,[], [apply the noreturn attribute to a function that exits the program])
fi
])dnl End of CHECK_NORETURN_ATTRIBUTE
CHECK_NORETURN_ATTRIBUTE
+AC_DEFUN([CHECK_FALLTHROUGH_ATTRIBUTE],
+[AC_REQUIRE([AC_PROG_CC])
+AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "fallthrough" attribute)
+BAKCFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+AC_CACHE_VAL(ac_cv_c_fallthrough_attribute,
+[ac_cv_c_fallthrough_attribute=no
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h>
+void f(int x) {
+ int y = 0;
+ switch(x) {
+ case 1:
+ y = 1;
+ __attribute__((fallthrough));
+ /* fallthrough */
+ case 2:
+ y++;
+ break;
+ case 3:
+ y = 3;
+ break;
+ }
+ printf("%d", y);
+}
+]], [[
+ f(1);
+]])],[ac_cv_c_fallthrough_attribute="yes"],[ac_cv_c_fallthrough_attribute="no"])
+])
+CFLAGS="$BAKCFLAGS"
+
+AC_MSG_RESULT($ac_cv_c_fallthrough_attribute)
+if test $ac_cv_c_fallthrough_attribute = yes; then
+ AC_DEFINE(HAVE_ATTR_FALLTHROUGH, 1, [Whether the C compiler accepts the "fallthrough" attribute])
+ AC_DEFINE(ATTR_FALLTHROUGH, [__attribute__((fallthrough));], [apply the fallthrough attribute.])
+else
+ AC_DEFINE(ATTR_FALLTHROUGH,[], [apply the fallthrough attribute.])
+fi
+])dnl End of CHECK_FALLTHROUGH_ATTRIBUTE
+
+CHECK_FALLTHROUGH_ATTRIBUTE
+
if test "$srcdir" != "."; then
CPPFLAGS="$CPPFLAGS -I$srcdir"
fi
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
-AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
+AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex SSL_CTX_set_tmp_ecdh])
# these check_funcs need -lssl
BAKLIBS="$LIBS"
;;
*)
if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then
+ AC_CHECK_FUNC(EVP_PKEY_fromdata, [
+ # with EVP_PKEY_fromdata, check if EC is not disabled
+ AC_CHECK_DECL([OPENSSL_NO_EC], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])
+ ], [], [AC_INCLUDES_DEFAULT
+#include <openssl/evp.h>
+ ])
+ ], [
+ # without EVP_PKEY_fromdata, older openssl, check for support
AC_CHECK_FUNC(ECDSA_sign, [], [AC_MSG_ERROR([OpenSSL does not support ECDSA: please upgrade or rerun with --disable-ecdsa])])
AC_CHECK_FUNC(SHA384_Init, [], [AC_MSG_ERROR([OpenSSL does not support SHA384: please upgrade or rerun with --disable-ecdsa])])
+ ])
AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [], [AC_MSG_ERROR([OpenSSL does not support the ECDSA curves: please upgrade or rerun with --disable-ecdsa])], [AC_INCLUDES_DEFAULT
#include <openssl/evp.h>
])
IPSET_OBJ="ipset.lo"
AC_SUBST(IPSET_OBJ)
+ # BSD's pf
+ AC_CHECK_HEADERS([net/pfvar.h], [], [
# mnl
AC_ARG_WITH(libmnl, AS_HELP_STRING([--with-libmnl=path],[specify explicit path for libmnl.]),
[ ],[ withval="yes" ])
if test x_$found_libmnl != x_yes; then
AC_MSG_ERROR([Could not find libmnl, libmnl.h])
fi
+ ], [
+ #include <netinet/in.h>
+ #include <net/if.h>
+ ])
;;
no|*)
# nothing
# define calloc(n,s) unbound_stat_calloc_log(n, s, __FILE__, __LINE__, __func__)
# define free(p) unbound_stat_free_log(p, __FILE__, __LINE__, __func__)
# define realloc(p,s) unbound_stat_realloc_log(p, s, __FILE__, __LINE__, __func__)
+# define strdup(s) unbound_stat_strdup_log(s, __FILE__, __LINE__, __func__)
void *unbound_stat_malloc(size_t size);
void *unbound_stat_calloc(size_t nmemb, size_t size);
void unbound_stat_free(void *ptr);
const char* func);
void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
int line, const char* func);
+char *unbound_stat_strdup_log(const char *s, const char* file, int line,
+ const char* func);
#elif defined(UNBOUND_ALLOC_LITE)
# include "util/alloc.h"
#endif /* UNBOUND_ALLOC_LITE and UNBOUND_ALLOC_STATS */
return 1;
}
+int
+daemon_privileged(struct daemon* daemon)
+{
+ daemon->env->cfg = daemon->cfg;
+ daemon->env->alloc = &daemon->superalloc;
+ daemon->env->worker = NULL;
+ if(!modstack_call_startup(&daemon->mods, daemon->cfg->module_conf,
+ daemon->env)) {
+ fatal_exit("failed to startup modules");
+ }
+ return 1;
+}
+
/**
* Setup modules. setup module stack.
* @param daemon: the daemon
daemon->env->cfg = daemon->cfg;
daemon->env->alloc = &daemon->superalloc;
daemon->env->worker = NULL;
+ if(daemon->mods_inited) {
+ modstack_call_deinit(&daemon->mods, daemon->env);
+ }
daemon->env->need_to_validate = 0; /* set by module init below */
- if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf,
+ if(!modstack_call_init(&daemon->mods, daemon->cfg->module_conf,
daemon->env)) {
- fatal_exit("failed to setup modules");
+ fatal_exit("failed to init modules");
}
+ daemon->mods_inited = 1;
log_edns_known_options(VERB_ALGO, daemon->env);
}
{
int i;
- for(i=0; i<daemon->num; i++) {
+ /* daemon->num may be different during reloads (after configuration
+ * read). Use old_num which has the correct value used to setup the
+ * worker_allocs */
+ for(i=0; i<daemon->old_num; i++) {
alloc_clear(daemon->worker_allocs[i]);
free(daemon->worker_allocs[i]);
}
"dnscrypt support");
#endif
}
+ if(daemon->cfg->cookie_secret_file &&
+ daemon->cfg->cookie_secret_file[0]) {
+ if(!(daemon->cookie_secrets = cookie_secrets_create()))
+ fatal_exit("Could not create cookie_secrets: out of memory");
+ if(!cookie_secrets_apply_cfg(daemon->cookie_secrets,
+ daemon->cfg->cookie_secret_file))
+ fatal_exit("Could not setup cookie_secrets");
+ }
/* create global local_zones */
if(!(daemon->local_zones = local_zones_create()))
fatal_exit("Could not create local zones: out of memory");
daemon->views = NULL;
if(daemon->env->auth_zones)
auth_zones_cleanup(daemon->env->auth_zones);
- /* key cache is cleared by module desetup during next daemon_fork() */
+ /* key cache is cleared by module deinit during next daemon_fork() */
daemon_remote_clear(daemon->rc);
for(i=0; i<daemon->num; i++)
worker_delete(daemon->workers[i]);
size_t i;
if(!daemon)
return;
- modstack_desetup(&daemon->mods, daemon->env);
+ modstack_call_deinit(&daemon->mods, daemon->env);
+ modstack_call_destartup(&daemon->mods, daemon->env);
+ modstack_free(&daemon->mods);
daemon_remote_delete(daemon->rc);
for(i = 0; i < daemon->num_ports; i++)
listening_ports_free(daemon->ports[i]);
acl_list_delete(daemon->acl);
acl_list_delete(daemon->acl_interface);
tcl_list_delete(daemon->tcl);
+ cookie_secrets_delete(daemon->cookie_secrets);
listen_desetup_locks();
free(daemon->chroot);
free(daemon->pidfile);
struct daemon_remote;
struct respip_set;
struct shm_main_info;
+struct cookie_secrets;
#include "dnstap/dnstap_config.h"
#ifdef USE_DNSTAP
struct module_env* env;
/** stack of module callbacks */
struct module_stack mods;
+ /** The module stack has been inited */
+ int mods_inited;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
/** access control, which interfaces are allowed to connect */
#endif
/** reuse existing cache on reload if other conditions allow it. */
int reuse_cache;
+ /** the EDNS cookie secrets from the cookie-secret-file */
+ struct cookie_secrets* cookie_secrets;
};
/**
*/
int daemon_open_shared_ports(struct daemon* daemon);
+/**
+ * Do daemon setup that needs privileges
+ * like opening privileged ports or opening device files.
+ * The cfg member pointer must have been set for the daemon.
+ * @param daemon: the daemon.
+ * @return: false on error.
+ */
+int daemon_privileged(struct daemon* daemon);
+
/**
* Fork workers and start service.
* When the routine exits, it is no longer forked.
#include "sldns/wire2str.h"
#include "sldns/sbuffer.h"
#include "util/timeval_func.h"
+#include "util/edns.h"
+#ifdef USE_CACHEDB
+#include "cachedb/cachedb.h"
+#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
/** what to put on statistics lines between var and value, ": " or "=" */
#define SQ "="
+/** Acceptable lengths of str lines */
+#define MAX_CMD_STRLINE 1024
+#define MAX_STDIN_STRLINE 2048
+
static int
remote_setup_ctx(struct daemon_remote* rc, struct config_file* cfg)
{
(void)ssl_printf(ssl, "ok\n");
}
+/** tell other processes to execute the command */
+static void
+distribute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
+{
+ int i;
+ if(!cmd || !ssl)
+ return;
+ /* skip i=0 which is me */
+ for(i=1; i<rc->worker->daemon->num; i++) {
+ worker_send_cmd(rc->worker->daemon->workers[i],
+ worker_cmd_remote);
+ if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd,
+ (uint8_t*)cmd, strlen(cmd)+1, 0)) {
+ (void)ssl_printf(ssl, "error could not distribute cmd\n");
+ return;
+ }
+ }
+}
+
/** do the stop command */
static void
do_stop(RES* ssl, struct worker* worker)
/** Do the local_zones command */
static void
-do_zones_add(RES* ssl, struct local_zones* zones)
+do_zones_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
{
- char buf[2048];
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_zone ";
int num = 0;
- while(ssl_read_line(ssl, buf, sizeof(buf))) {
- if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0))
+ size_t cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
break; /* zero byte line or end of transmission */
- if(!perform_zone_add(ssl, zones, buf)) {
- if(!ssl_printf(ssl, "error for input line: %s\n", buf))
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
+ if(!perform_zone_add(ssl, worker->daemon->local_zones,
+ buf+cmd_len)) {
+ if(!ssl_printf(ssl, "error for input line: %s\n",
+ buf+cmd_len))
return;
}
- else
- num++;
+ else num++;
}
(void)ssl_printf(ssl, "added %d zones\n", num);
}
/** Do the local_zones_remove command */
static void
-do_zones_remove(RES* ssl, struct local_zones* zones)
+do_zones_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker)
{
- char buf[2048];
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_zone_remove ";
int num = 0;
- while(ssl_read_line(ssl, buf, sizeof(buf))) {
- if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0))
+ size_t cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
break; /* zero byte line or end of transmission */
- if(!perform_zone_remove(ssl, zones, buf)) {
- if(!ssl_printf(ssl, "error for input line: %s\n", buf))
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
+ if(!perform_zone_remove(ssl, worker->daemon->local_zones,
+ buf+cmd_len)) {
+ if(!ssl_printf(ssl, "error for input line: %s\n",
+ buf+cmd_len))
return;
}
- else
- num++;
+ else num++;
}
(void)ssl_printf(ssl, "removed %d zones\n", num);
}
/** Do the local_datas command */
static void
-do_datas_add(RES* ssl, struct local_zones* zones)
+do_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
{
- char buf[2048];
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_data ";
int num = 0, line = 0;
- while(ssl_read_line(ssl, buf, sizeof(buf))) {
- if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0))
+ size_t cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
break; /* zero byte line or end of transmission */
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
line++;
- if(perform_data_add(ssl, zones, buf, line))
+ if(perform_data_add(ssl, worker->daemon->local_zones,
+ buf+cmd_len, line))
num++;
}
(void)ssl_printf(ssl, "added %d datas\n", num);
/** Do the local_datas_remove command */
static void
-do_datas_remove(RES* ssl, struct local_zones* zones)
+do_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker)
{
- char buf[2048];
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "local_data_remove ";
int num = 0;
- while(ssl_read_line(ssl, buf, sizeof(buf))) {
- if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0))
+ size_t cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
break; /* zero byte line or end of transmission */
- if(!perform_data_remove(ssl, zones, buf)) {
- if(!ssl_printf(ssl, "error for input line: %s\n", buf))
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
+ if(!perform_data_remove(ssl, worker->daemon->local_zones,
+ buf+cmd_len)) {
+ if(!ssl_printf(ssl, "error for input line: %s\n",
+ buf+cmd_len))
return;
}
- else
- num++;
+ else num++;
}
(void)ssl_printf(ssl, "removed %d datas\n", num);
}
/** Add new RR data from stdin to view */
static void
-do_view_datas_add(RES* ssl, struct worker* worker, char* arg)
+do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
+ char* arg)
{
struct view* v;
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "view_local_data ";
+ size_t cmd_len;
+ int num = 0, line = 0;
v = views_find_view(worker->daemon->views,
arg, 1 /* get write lock*/);
if(!v) {
return;
}
}
- do_datas_add(ssl, v->local_zones);
+ /* put the view name in the command buf */
+ (void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
+ cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
+ break; /* zero byte line or end of transmission */
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
+ line++;
+ if(perform_data_add(ssl, v->local_zones, buf+cmd_len, line))
+ num++;
+ }
lock_rw_unlock(&v->lock);
+ (void)ssl_printf(ssl, "added %d datas\n", num);
}
/** Remove RR data from view */
/** Remove RR data from stdin from view */
static void
-do_view_datas_remove(RES* ssl, struct worker* worker, char* arg)
+do_view_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker,
+ char* arg)
{
struct view* v;
+ char buf[MAX_CMD_STRLINE + MAX_STDIN_STRLINE] = "view_local_data_remove ";
+ int num = 0;
+ size_t cmd_len;
v = views_find_view(worker->daemon->views,
arg, 1 /* get write lock*/);
if(!v) {
ssl_printf(ssl, "removed 0 datas\n");
return;
}
-
- do_datas_remove(ssl, v->local_zones);
+ /* put the view name in the command buf */
+ (void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
+ cmd_len = strlen(buf);
+ while(ssl_read_line(ssl, buf+cmd_len, MAX_STDIN_STRLINE)) {
+ if(buf[0+cmd_len] == 0 ||
+ (buf[0+cmd_len] == 0x04 && buf[1+cmd_len] == 0))
+ break; /* zero byte line or end of transmission */
+#ifdef THREADS_DISABLED
+ /* distribute single item command */
+ if(rc) distribute_cmd(rc, ssl, buf);
+#else
+ (void)rc; /* unused */
+#endif
+ if(!perform_data_remove(ssl, v->local_zones, buf+cmd_len)) {
+ if(!ssl_printf(ssl, "error for input line: %s\n",
+ buf+cmd_len))
+ return;
+ }
+ else num++;
+ }
lock_rw_unlock(&v->lock);
+ (void)ssl_printf(ssl, "removed %d datas\n", num);
}
/** cache lookup of nameservers */
/** flush something from rrset and msg caches */
static void
do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
- uint16_t t, uint16_t c)
+ uint16_t t, uint16_t c, int remcachedb)
{
hashvalue_type h;
struct query_info k;
h = query_info_hash(&k, BIT_CD);
slabhash_remove(worker->env.msg_cache, h, &k);
}
+#ifdef USE_CACHEDB
+ if(remcachedb && worker->env.cachedb_enabled)
+ cachedb_msg_remove_qinfo(&worker->env, &k);
+#else
+ (void)remcachedb;
+#endif
+}
+
+/** parse '+c' option, modifies string to return remainder. */
+static int
+parse_remcachedb(RES* ssl, char** arg, int* pc)
+{
+ *arg = skipwhite(*arg);
+ if((*arg)[0] == '+' && (*arg)[1] == 'c') {
+ char* arg2;
+ *pc = 1;
+ if(!find_arg2(ssl, *arg, &arg2))
+ return 0;
+ *arg = arg2;
+ return 1;
+ }
+ /* The option was not found, no problem */
+ return 1;
}
/** flush a type */
size_t nmlen;
char* arg2;
uint16_t t;
+ int pc = 0; /* '+c' option */
+ if(!parse_remcachedb(ssl, &arg, &pc))
+ return;
if(!find_arg2(ssl, arg, &arg2))
return;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
t = sldns_get_rr_type_by_name(arg2);
if(t == 0 && strcmp(arg2, "TYPE0") != 0) {
+ (void)ssl_printf(ssl, "error parsing RRset type: '%s'\n", arg2);
+ free(nm);
return;
}
- do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN);
+ do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN, pc);
free(nm);
send_ok(ssl);
socklen_t addrlen;
/** socket address for host deletion */
struct sockaddr_storage addr;
+ /** if cachedb information should be flushed too */
+ int remcachedb;
};
/** callback to delete hosts in infra cache */
inf.num_msgs = 0;
inf.num_keys = 0;
inf.addrlen = len;
+ inf.remcachedb = 0;
memmove(&inf.addr, &addr, len);
slabhash_traverse(worker->env.infra_cache->hosts, 1, &infra_del_host,
&inf);
d->serve_expired_ttl = inf->expired;
inf->num_msgs++;
}
+#ifdef USE_CACHEDB
+ if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+ cachedb_msg_remove_qinfo(&inf->worker->env, &k->key);
+#endif
}
}
int nmlabs;
size_t nmlen;
struct del_info inf;
+ int pc = 0; /* '+c' option */
+ if(!parse_remcachedb(ssl, &arg, &pc))
+ return;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
/* delete all RRs and key entries from zone */
inf.num_rrsets = 0;
inf.num_msgs = 0;
inf.num_keys = 0;
+ inf.remcachedb = pc;
slabhash_traverse(&worker->env.rrset_cache->table, 1,
&zone_del_rrset, &inf);
if(d->security == sec_status_bogus) {
d->ttl = inf->expired;
inf->num_msgs++;
+#ifdef USE_CACHEDB
+ if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+ cachedb_msg_remove_qinfo(&inf->worker->env,
+ &((struct msgreply_entry*)e->key)->key);
+#endif
}
}
/** remove all bogus rrsets, msgs and keys from cache */
static void
-do_flush_bogus(RES* ssl, struct worker* worker)
+do_flush_bogus(RES* ssl, struct worker* worker, char* arg)
{
struct del_info inf;
+ int pc = 0; /* '+c' option */
+ if(!parse_remcachedb(ssl, &arg, &pc))
+ return;
/* what we do is to set them all expired */
inf.worker = worker;
inf.expired = *worker->env.now;
inf.num_rrsets = 0;
inf.num_msgs = 0;
inf.num_keys = 0;
+ inf.remcachedb = pc;
slabhash_traverse(&worker->env.rrset_cache->table, 1,
&bogus_del_rrset, &inf);
if(FLAGS_GET_RCODE(d->flags) != 0 || d->an_numrrsets == 0) {
d->ttl = inf->expired;
inf->num_msgs++;
+#ifdef USE_CACHEDB
+ if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+ cachedb_msg_remove_qinfo(&inf->worker->env,
+ &((struct msgreply_entry*)e->key)->key);
+#endif
}
}
/** remove all negative(NODATA,NXDOMAIN), and servfail messages from cache */
static void
-do_flush_negative(RES* ssl, struct worker* worker)
+do_flush_negative(RES* ssl, struct worker* worker, char* arg)
{
struct del_info inf;
+ int pc = 0; /* '+c' option */
+ if(!parse_remcachedb(ssl, &arg, &pc))
+ return;
/* what we do is to set them all expired */
inf.worker = worker;
inf.expired = *worker->env.now;
inf.num_rrsets = 0;
inf.num_msgs = 0;
inf.num_keys = 0;
+ inf.remcachedb = pc;
slabhash_traverse(&worker->env.rrset_cache->table, 1,
&negative_del_rrset, &inf);
uint8_t* nm;
int nmlabs;
size_t nmlen;
+ int pc = 0; /* '+c' option */
+ if(!parse_remcachedb(ssl, &arg, &pc))
+ return;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
return;
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN);
- do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN, pc);
+ do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN, pc);
free(nm);
send_ok(ssl);
return dp;
}
-/** do the status command */
+/** do the forward command */
static void
do_forward(RES* ssl, struct worker* worker, char* args)
{
do_rpz_enable_disable(ssl, worker, arg, 0);
}
-/** tell other processes to execute the command */
+/** Write the cookie secrets to file, returns `0` on failure.
+ * Caller has to hold the lock. */
+static int
+cookie_secret_file_dump(RES* ssl, struct worker* worker) {
+ char const* secret_file = worker->env.cfg->cookie_secret_file;
+ struct cookie_secrets* cookie_secrets = worker->daemon->cookie_secrets;
+ char secret_hex[UNBOUND_COOKIE_SECRET_SIZE * 2 + 1];
+ FILE* f;
+ size_t i;
+ if(secret_file == NULL || secret_file[0]==0) {
+ (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
+ return 0;
+ }
+ log_assert( secret_file != NULL );
+
+ /* open write only and truncate */
+ if((f = fopen(secret_file, "w")) == NULL ) {
+ (void)ssl_printf(ssl, "unable to open cookie secret file %s: %s",
+ secret_file, strerror(errno));
+ return 0;
+ }
+ if(cookie_secrets == NULL) {
+ /* nothing to write */
+ fclose(f);
+ return 1;
+ }
+
+ for(i = 0; i < cookie_secrets->cookie_count; i++) {
+ struct cookie_secret const* cs = &cookie_secrets->
+ cookie_secrets[i];
+ ssize_t const len = hex_ntop(cs->cookie_secret,
+ UNBOUND_COOKIE_SECRET_SIZE, secret_hex,
+ sizeof(secret_hex));
+ (void)len; /* silence unused variable warning with -DNDEBUG */
+ log_assert( len == UNBOUND_COOKIE_SECRET_SIZE * 2 );
+ secret_hex[UNBOUND_COOKIE_SECRET_SIZE * 2] = '\0';
+ fprintf(f, "%s\n", secret_hex);
+ }
+ explicit_bzero(secret_hex, sizeof(secret_hex));
+ fclose(f);
+ return 1;
+}
+
+/** Activate cookie secret */
static void
-distribute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd)
-{
- int i;
- if(!cmd || !ssl)
+do_activate_cookie_secret(RES* ssl, struct worker* worker) {
+ char const* secret_file = worker->env.cfg->cookie_secret_file;
+ struct cookie_secrets* cookie_secrets = worker->daemon->cookie_secrets;
+
+ if(secret_file == NULL || secret_file[0] == 0) {
+ (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
return;
- /* skip i=0 which is me */
- for(i=1; i<rc->worker->daemon->num; i++) {
- worker_send_cmd(rc->worker->daemon->workers[i],
- worker_cmd_remote);
- if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd,
- (uint8_t*)cmd, strlen(cmd)+1, 0)) {
- ssl_printf(ssl, "error could not distribute cmd\n");
+ }
+ if(cookie_secrets == NULL) {
+ (void)ssl_printf(ssl, "error: there are no cookie_secrets.");
+ return;
+ }
+ lock_basic_lock(&cookie_secrets->lock);
+
+ if(cookie_secrets->cookie_count <= 1 ) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ (void)ssl_printf(ssl, "error: no staging cookie secret to activate\n");
+ return;
+ }
+ /* Only the worker 0 writes to file, the others update state. */
+ if(worker->thread_num == 0 && !cookie_secret_file_dump(ssl, worker)) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
+ secret_file);
+ return;
+ }
+ activate_cookie_secret(cookie_secrets);
+ if(worker->thread_num == 0)
+ (void)cookie_secret_file_dump(ssl, worker);
+ lock_basic_unlock(&cookie_secrets->lock);
+ send_ok(ssl);
+}
+
+/** Drop cookie secret */
+static void
+do_drop_cookie_secret(RES* ssl, struct worker* worker) {
+ char const* secret_file = worker->env.cfg->cookie_secret_file;
+ struct cookie_secrets* cookie_secrets = worker->daemon->cookie_secrets;
+
+ if(secret_file == NULL || secret_file[0] == 0) {
+ (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
+ return;
+ }
+ if(cookie_secrets == NULL) {
+ (void)ssl_printf(ssl, "error: there are no cookie_secrets.");
+ return;
+ }
+ lock_basic_lock(&cookie_secrets->lock);
+
+ if(cookie_secrets->cookie_count <= 1 ) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ (void)ssl_printf(ssl, "error: can not drop the currently active cookie secret\n");
+ return;
+ }
+ /* Only the worker 0 writes to file, the others update state. */
+ if(worker->thread_num == 0 && !cookie_secret_file_dump(ssl, worker)) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
+ secret_file);
+ return;
+ }
+ drop_cookie_secret(cookie_secrets);
+ if(worker->thread_num == 0)
+ (void)cookie_secret_file_dump(ssl, worker);
+ lock_basic_unlock(&cookie_secrets->lock);
+ send_ok(ssl);
+}
+
+/** Add cookie secret */
+static void
+do_add_cookie_secret(RES* ssl, struct worker* worker, char* arg) {
+ uint8_t secret[UNBOUND_COOKIE_SECRET_SIZE];
+ char const* secret_file = worker->env.cfg->cookie_secret_file;
+ struct cookie_secrets* cookie_secrets = worker->daemon->cookie_secrets;
+
+ if(secret_file == NULL || secret_file[0] == 0) {
+ (void)ssl_printf(ssl, "error: no cookie secret file configured\n");
+ return;
+ }
+ if(cookie_secrets == NULL) {
+ worker->daemon->cookie_secrets = cookie_secrets_create();
+ if(!worker->daemon->cookie_secrets) {
+ (void)ssl_printf(ssl, "error: out of memory");
return;
}
+ cookie_secrets = worker->daemon->cookie_secrets;
+ }
+ lock_basic_lock(&cookie_secrets->lock);
+
+ if(*arg == '\0') {
+ lock_basic_unlock(&cookie_secrets->lock);
+ (void)ssl_printf(ssl, "error: missing argument (cookie_secret)\n");
+ return;
+ }
+ if(strlen(arg) != 32) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ explicit_bzero(arg, strlen(arg));
+ (void)ssl_printf(ssl, "invalid cookie secret: invalid argument length\n");
+ (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n");
+ return;
}
+ if(hex_pton(arg, secret, UNBOUND_COOKIE_SECRET_SIZE) !=
+ UNBOUND_COOKIE_SECRET_SIZE ) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
+ explicit_bzero(arg, strlen(arg));
+ (void)ssl_printf(ssl, "invalid cookie secret: parse error\n");
+ (void)ssl_printf(ssl, "please provide a 128bit hex encoded secret\n");
+ return;
+ }
+ /* Only the worker 0 writes to file, the others update state. */
+ if(worker->thread_num == 0 && !cookie_secret_file_dump(ssl, worker)) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
+ explicit_bzero(arg, strlen(arg));
+ (void)ssl_printf(ssl, "error: writing to cookie secret file: \"%s\"\n",
+ secret_file);
+ return;
+ }
+ add_cookie_secret(cookie_secrets, secret, UNBOUND_COOKIE_SECRET_SIZE);
+ explicit_bzero(secret, UNBOUND_COOKIE_SECRET_SIZE);
+ if(worker->thread_num == 0)
+ (void)cookie_secret_file_dump(ssl, worker);
+ lock_basic_unlock(&cookie_secrets->lock);
+ explicit_bzero(arg, strlen(arg));
+ send_ok(ssl);
+}
+
+/** Print cookie secrets */
+static void
+do_print_cookie_secrets(RES* ssl, struct worker* worker) {
+ struct cookie_secrets* cookie_secrets = worker->daemon->cookie_secrets;
+ char secret_hex[UNBOUND_COOKIE_SECRET_SIZE * 2 + 1];
+ int i;
+
+ if(!cookie_secrets)
+ return; /* Output is empty. */
+ lock_basic_lock(&cookie_secrets->lock);
+ for(i = 0; (size_t)i < cookie_secrets->cookie_count; i++) {
+ struct cookie_secret const* cs = &cookie_secrets->
+ cookie_secrets[i];
+ ssize_t const len = hex_ntop(cs->cookie_secret,
+ UNBOUND_COOKIE_SECRET_SIZE, secret_hex,
+ sizeof(secret_hex));
+ (void)len; /* silence unused variable warning with -DNDEBUG */
+ log_assert( len == UNBOUND_COOKIE_SECRET_SIZE * 2 );
+ secret_hex[UNBOUND_COOKIE_SECRET_SIZE * 2] = '\0';
+ if (i == 0)
+ (void)ssl_printf(ssl, "active : %s\n", secret_hex);
+ else if (cookie_secrets->cookie_count == 2)
+ (void)ssl_printf(ssl, "staging: %s\n", secret_hex);
+ else
+ (void)ssl_printf(ssl, "staging[%d]: %s\n", i,
+ secret_hex);
+ }
+ lock_basic_unlock(&cookie_secrets->lock);
+ explicit_bzero(secret_hex, sizeof(secret_hex));
}
/** check for name with end-of-string, space or tab after it */
do_status(ssl, worker);
return;
} else if(cmdcmp(p, "dump_cache", 10)) {
+#ifdef THREADS_DISABLED
+ if(worker->daemon->num > 1) {
+ (void)ssl_printf(ssl, "dump_cache/load_cache is not "
+ "supported in multi-process operation\n");
+ return;
+ }
+#endif
(void)dump_cache(ssl, worker);
return;
} else if(cmdcmp(p, "load_cache", 10)) {
+#ifdef THREADS_DISABLED
+ if(worker->daemon->num > 1) {
+ /* The warning can't be printed when stdin is sending
+ * data; just return */
+ return;
+ }
+#endif
if(load_cache(ssl, worker)) send_ok(ssl);
return;
} else if(cmdcmp(p, "list_forwards", 13)) {
} else if(cmdcmp(p, "lookup", 6)) {
do_lookup(ssl, worker, skipwhite(p+6));
return;
+ /* The following are commands that read stdin.
+ * Each line needs to be distributed if THREADS_DISABLED.
+ */
+ } else if(cmdcmp(p, "local_zones_remove", 18)) {
+ do_zones_remove(rc, ssl, worker);
+ return;
+ } else if(cmdcmp(p, "local_zones", 11)) {
+ do_zones_add(rc, ssl, worker);
+ return;
+ } else if(cmdcmp(p, "local_datas_remove", 18)) {
+ do_datas_remove(rc, ssl, worker);
+ return;
+ } else if(cmdcmp(p, "local_datas", 11)) {
+ do_datas_add(rc, ssl, worker);
+ return;
+ } else if(cmdcmp(p, "view_local_datas_remove", 23)){
+ do_view_datas_remove(rc, ssl, worker, skipwhite(p+23));
+ return;
+ } else if(cmdcmp(p, "view_local_datas", 16)) {
+ do_view_datas_add(rc, ssl, worker, skipwhite(p+16));
+ return;
+ } else if(cmdcmp(p, "print_cookie_secrets", 20)) {
+ do_print_cookie_secrets(ssl, worker);
+ return;
}
#ifdef THREADS_DISABLED
do_verbosity(ssl, skipwhite(p+9));
} else if(cmdcmp(p, "local_zone_remove", 17)) {
do_zone_remove(ssl, worker->daemon->local_zones, skipwhite(p+17));
- } else if(cmdcmp(p, "local_zones_remove", 18)) {
- do_zones_remove(ssl, worker->daemon->local_zones);
} else if(cmdcmp(p, "local_zone", 10)) {
do_zone_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
- } else if(cmdcmp(p, "local_zones", 11)) {
- do_zones_add(ssl, worker->daemon->local_zones);
} else if(cmdcmp(p, "local_data_remove", 17)) {
do_data_remove(ssl, worker->daemon->local_zones, skipwhite(p+17));
- } else if(cmdcmp(p, "local_datas_remove", 18)) {
- do_datas_remove(ssl, worker->daemon->local_zones);
} else if(cmdcmp(p, "local_data", 10)) {
do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10));
- } else if(cmdcmp(p, "local_datas", 11)) {
- do_datas_add(ssl, worker->daemon->local_zones);
} else if(cmdcmp(p, "forward_add", 11)) {
do_forward_add(ssl, worker, skipwhite(p+11));
} else if(cmdcmp(p, "forward_remove", 14)) {
do_view_zone_add(ssl, worker, skipwhite(p+15));
} else if(cmdcmp(p, "view_local_data_remove", 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)) {
do_view_data_add(ssl, worker, skipwhite(p+15));
- } else if(cmdcmp(p, "view_local_datas", 16)) {
- do_view_datas_add(ssl, worker, skipwhite(p+16));
} else if(cmdcmp(p, "flush_zone", 10)) {
do_flush_zone(ssl, worker, skipwhite(p+10));
} else if(cmdcmp(p, "flush_type", 10)) {
} else if(cmdcmp(p, "get_option", 10)) {
do_get_option(ssl, worker, skipwhite(p+10));
} else if(cmdcmp(p, "flush_bogus", 11)) {
- do_flush_bogus(ssl, worker);
+ do_flush_bogus(ssl, worker, skipwhite(p+11));
} else if(cmdcmp(p, "flush_negative", 14)) {
- do_flush_negative(ssl, worker);
+ do_flush_negative(ssl, worker, skipwhite(p+14));
} else if(cmdcmp(p, "rpz_enable", 10)) {
do_rpz_enable(ssl, worker, skipwhite(p+10));
} else if(cmdcmp(p, "rpz_disable", 11)) {
do_rpz_disable(ssl, worker, skipwhite(p+11));
+ } else if(cmdcmp(p, "add_cookie_secret", 17)) {
+ do_add_cookie_secret(ssl, worker, skipwhite(p+17));
+ } else if(cmdcmp(p, "drop_cookie_secret", 18)) {
+ do_drop_cookie_secret(ssl, worker);
+ } else if(cmdcmp(p, "activate_cookie_secret", 22)) {
+ do_activate_cookie_secret(ssl, worker);
} else {
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
}
int r;
char pre[10];
char magic[7];
- char buf[1024];
+ char buf[MAX_CMD_STRLINE];
#ifdef USE_WINSOCK
/* makes it possible to set the socket blocking again. */
/* basically removes it from winsock_event ... */
else worker_send_cmd(who, worker_cmd_stats_noreset);
verbose(VERB_ALGO, "wait for stats reply");
if(tube_wait_timeout(worker->cmd, STATS_THREAD_WAIT) == 0) {
+#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
+# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
+ unsigned long pthid = 0;
+ if(verbosity >= VERB_OPS)
+ memcpy(&pthid, &who->thr_id, sizeof(unsigned long));
+# endif
+#endif
verbose(VERB_OPS, "no response from thread %d"
#ifdef HAVE_GETTID
" LWP %u"
#endif
#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
- , (unsigned long)*((unsigned long*)&who->thr_id)
+ , pthid
# endif
#endif
);
#endif
#ifdef HAVE_GETPWNAM
struct passwd *pwd = NULL;
+#endif
+ if(!daemon_privileged(daemon))
+ fatal_exit("could not do privileged setup");
+#ifdef HAVE_GETPWNAM
if(cfg->username && cfg->username[0]) {
if((pwd = getpwnam(cfg->username)) == NULL)
fatal_exit("user '%s' does not exist.", cfg->username);
* because that creates privilege escape problems, with the
* pidfile writable by unprivileged users, but used by
* privileged users. */
- if(cfg->username && cfg->username[0])
+ if(!(cfg->username && cfg->username[0]))
checkoldpid(daemon->pidfile, pidinchroot);
}
#endif
+ sizeof(worker->rndstate)
+ regional_get_mem(worker->scratchpad)
+ sizeof(*worker->env.scratch_buffer)
- + sldns_buffer_capacity(worker->env.scratch_buffer)
- + forwards_get_mem(worker->env.fwds)
- + hints_get_mem(worker->env.hints);
+ + sldns_buffer_capacity(worker->env.scratch_buffer);
+ if(worker->daemon->env->fwds)
+ log_info("forwards=%u", (unsigned)forwards_get_mem(worker->env.fwds));
+ if(worker->daemon->env->hints)
+ log_info("hints=%u", (unsigned)hints_get_mem(worker->env.hints));
if(worker->thread_num == 0)
me += acl_list_get_mem(worker->daemon->acl);
if(cur_serv) {
if((ret=parse_edns_from_query_pkt(
c->buffer, &edns, worker->env.cfg, c, repinfo,
(worker->env.now ? *worker->env.now : time(NULL)),
- worker->scratchpad)) != 0) {
+ worker->scratchpad,
+ worker->daemon->cookie_secrets)) != 0) {
struct edns_data reply_edns;
verbose(VERB_ALGO, "worker parse edns: formerror.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
iq->state = DNS64_NEW_QUERY;
iq->started_no_cache_store = qstate->no_cache_store;
qstate->no_cache_store = 1;
+ ATTR_FALLTHROUGH
/* fallthrough */
case module_event_pass:
qstate->ext_state[id] = handle_event_pass(qstate, id);
*/
static struct module_func_block dns64_block = {
"dns64",
- &dns64_init, &dns64_deinit, &dns64_operate, &dns64_inform_super,
- &dns64_clear, &dns64_get_mem
+ NULL, NULL, &dns64_init, &dns64_deinit, &dns64_operate,
+ &dns64_inform_super, &dns64_clear, &dns64_get_mem
};
/**
return 1;
}
+/** See if the message is sent due to dnstap sample rate */
+static int
+dt_sample_rate_limited(struct dt_env* env)
+{
+ lock_basic_lock(&env->sample_lock);
+ /* Sampling is every [n] packets. Where n==1, every packet is sent */
+ if(env->sample_rate > 1) {
+ int submit = 0;
+ /* if sampling is engaged... */
+ if (env->sample_rate_count > env->sample_rate) {
+ /* once the count passes the limit */
+ /* submit the message */
+ submit = 1;
+ /* and reset the count */
+ env->sample_rate_count = 0;
+ }
+ /* increment count regardless */
+ env->sample_rate_count++;
+ lock_basic_unlock(&env->sample_lock);
+ return !submit;
+ }
+ lock_basic_unlock(&env->sample_lock);
+ return 0;
+}
+
static void
dt_send(const struct dt_env *env, void *buf, size_t len_buf)
{
env = (struct dt_env *) calloc(1, sizeof(struct dt_env));
if (!env)
return NULL;
+ lock_basic_init(&env->sample_lock);
env->dtio = dt_io_thread_create();
if(!env->dtio) {
{
verbose(VERB_OPS, "dnstap Message/FORWARDER_RESPONSE enabled");
}
+ lock_basic_lock(&env->sample_lock);
+ if((env->sample_rate = (unsigned int)cfg->dnstap_sample_rate))
+ {
+ verbose(VERB_OPS, "dnstap SAMPLE_RATE enabled and set to \"%d\"", (int)env->sample_rate);
+ }
+ lock_basic_unlock(&env->sample_lock);
}
int
if (!env)
return;
dt_io_thread_delete(env->dtio);
+ lock_basic_destroy(&env->sample_lock);
free(env->identity);
free(env->version);
free(env);
struct dt_msg dm;
struct timeval qtime;
+ if(dt_sample_rate_limited(env))
+ return;
+
if(tstamp)
memcpy(&qtime, tstamp, sizeof(qtime));
else gettimeofday(&qtime, NULL);
struct dt_msg dm;
struct timeval rtime;
+ if(dt_sample_rate_limited(env))
+ return;
+
gettimeofday(&rtime, NULL);
/* type */
struct timeval qtime;
uint16_t qflags;
+ if(dt_sample_rate_limited(env))
+ return;
+
gettimeofday(&qtime, NULL);
qflags = sldns_buffer_read_u16_at(qmsg, 2);
struct dt_msg dm;
uint16_t qflags;
+ if(dt_sample_rate_limited(env))
+ return;
+
(void)qbuf_len; log_assert(qbuf_len >= sizeof(qflags));
memcpy(&qflags, qbuf, sizeof(qflags));
qflags = ntohs(qflags);
],
[
if test -n "$PKG_CONFIG"; then
- PKG_CHECK_MODULES([PROTOBUFC], [libprotobuf-c],
- [
- CFLAGS="$CFLAGS $PROTOBUFC_CFLAGS"
- LIBS="$LIBS $PROTOBUFC_LIBS"
- ],
- [
- # pkg-config failed; try falling back to known values
- # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
- if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
- CFLAGS="$CFLAGS -I/usr/include/google"
- else
- if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
- CFLAGS="$CFLAGS -I/usr/local/include/google"
- LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ PKG_CHECK_MODULES([PROTOBUFC], [libprotobuf-c],
+ [
+ CFLAGS="$CFLAGS $PROTOBUFC_CFLAGS"
+ LIBS="$LIBS $PROTOBUFC_LIBS"
+ ],
+ [
+ # pkg-config failed; try falling back to known values
+ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
+ if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/include/google"
else
- AC_MSG_ERROR([The protobuf-c package was not found with pkg-config. Please install protobuf-c!])
+ if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/local/include/google"
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ else
+ AC_MSG_ERROR([The protobuf-c package was not found with pkg-config. Please install protobuf-c!])
+ fi
fi
- fi
- ]
- )
+ ]
+ )
else
- # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
- if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
- CFLAGS="$CFLAGS -I/usr/include/google"
- else
- if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
- CFLAGS="$CFLAGS -I/usr/local/include/google"
- LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ # workaround for protobuf-c includes at old dir before protobuf-c-1.0.0
+ if test -f /usr/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/include/google"
+ else
+ if test -f /usr/local/include/google/protobuf-c/protobuf-c.h; then
+ CFLAGS="$CFLAGS -I/usr/local/include/google"
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ fi
fi
- fi
fi
]
)
tv.tv_usec = 0;
/* If it is already set, keep it running. */
if(!comm_timer_is_set(mq->wakeup_timer))
- comm_timer_set(mq->wakeup_timer, &tv);
+ comm_timer_set(mq->wakeup_timer, &tv);
} else {
tv.tv_sec = 0;
tv.tv_usec = 0;
}
}
if(!dtio->cur_msg)
- return; /* nothing to do */
+ return; /* nothing to do */
}
}
static void usage(char* argv[])
{
printf("usage: %s [options]\n", argv[0]);
- printf(" Listen to dnstap messages\n");
+ printf(" Listen to dnstap messages\n");
printf("stdout has dnstap log, stderr has verbose server log\n");
- printf("-u <socketpath> listen to unix socket with this file name\n");
- printf("-s <serverip[@port]> listen for TCP on the IP and port\n");
- printf("-t <serverip[@port]> listen for TLS on IP and port\n");
- printf("-x <server.key> server key file for TLS service\n");
- printf("-y <server.pem> server cert file for TLS service\n");
- printf("-z <verify.pem> cert file to verify client connections\n");
- printf("-l long format for DNS printout\n");
- printf("-v more verbose log output\n");
+ printf("-u <socketpath> listen to unix socket with this file name\n");
+ printf("-s <serverip[@port]> listen for TCP on the IP and port\n");
+ printf("-t <serverip[@port]> listen for TLS on IP and port\n");
+ printf("-x <server.key> server key file for TLS service\n");
+ printf("-y <server.pem> server cert file for TLS service\n");
+ printf("-z <verify.pem> cert file to verify client connections\n");
+ printf("-l long format for DNS printout\n");
+ printf("-v more verbose log output\n");
printf("-c internal unit test and exit\n");
- printf("-h this help text\n");
+ printf("-h this help text\n");
exit(1);
}
+9 August 2024: Wouter
+ - Fix spelling for the cache-min-negative-ttl entry in the
+ example.conf.
+
+8 August 2024: Wouter
+ - Fix CAMP issues with global quota. Thanks to Huayi Duan, Marco
+ Bearzi, Jodok Vieli, and Cagin Tanir from NetSec group, ETH Zurich.
+ - Fix CacheFlush issues with limit on NS RRs. Thanks to Yehuda Afek,
+ Anat Bremler-Barr, Shoham Danino and Yuval Shavitt (Tel-Aviv
+ University and Reichman University).
+ - Set version number to 1.21.0 for release.
+ - Fix that for windows the module startup is called and sets up
+ the module-config.
+
+2 August 2024: Wouter
+ - Fix that alloc stats has strdup checks, it stops debuggers from
+ complaining about mismatch at free time.
+ - Fix testbound for alloc stats strdup in util/alloc.c.
+ - Merge #1090: Cookie secret file. Adds
+ `cookie-secret-file: "unbound_cookiesecrets.txt"` option to store
+ cookie secrets for EDNS COOKIE secret rollover. The remote control
+ add_cookie_secret, activate_cookie_secret and drop_cookie_secret
+ commands can be used for rollover, the command print_cookie_secrets
+ shows the values in use.
+ - Fix that alloc stats for forwards and hints are printed, and when
+ alloc stats is enabled, the unit test for unbound control waits for
+ reloads to complete.
+
+1 August 2024: Wouter
+ - Fix dnstap test program, cleans up to have clean memory on exit,
+ for tap_data_free, does not delete NULL items. Also it does not try
+ to free the tail, specifically in the free of the list since that
+ picked up the next item in the list for its loop causing invalid
+ free. Added internal unit test to unbound-dnstap-socket for that.
+ - Fix that the worker mem report with alloc stats does not attempt
+ to print memory use of forwards and hints if they have been
+ deleted already.
+
+31 July 2024: Wouter
+ - Fix for #1114: Fix that cache fill for forward-host names is
+ performed, so that with nonzero target-fetch-policy it fetches
+ forwarder addresses and uses them from cache. Also updated that
+ delegation point cache fill routines use CDflag for AAAA message
+ lookups, so that its negative lookup stops a recursion since the
+ cache uses the bit for disambiguation for dns64 but the recursion
+ uses CDflag for the AAAA target lookups, so the check correctly
+ stops a useless recursion by its cache lookup.
+
+30 July 2024: Wouter
+ - Fix to document parameters of auth_zone_verify_zonemd_with_key.
+
+25 July 2024: Wouter
+ - Add root key 38696 from 2024 for DNSSEC validation. It is added
+ to the default root keys in unbound-anchor. The content can be
+ inspected with `unbound-anchor -l`.
+
+23 July 2024: Yorgos
+ - Fix #1106: ratelimit-below-domain logs the wrong FROM address.
+ - Cleanup ede.tdir test.
+ - For #935 and #1104, clarify RPZ order and semantics.
+
+23 July 2024: Wouter
+ - Merge #1110: Make fallthrough explicit for libworker.c.
+ - For #1110: Test for fallthrough attribute in configure and add
+ fallthrough attribute annotations.
+ - Fix compile when the compiler does not support the noreturn
+ attribute.
+ - Fix to have empty definition when not supported for weak attribute.
+ - Fix uninitialized variable warning in create_tcp_accept_sock.
+ - Fix link of dnstap without openssl.
+ - Fix link of unbound-dnstap-socket without openssl.
+
+19 July 2024: Wouter
+ - Add dnstap-sample-rate that logs only 1/N messages, for high volume
+ server environments. Thanks Dan Luther.
+ - Fix dnstap wakeup, a running wakeup timer is left to expire and not
+ increased, a timer is started when the dtio thread is sleeping,
+ the timer set disabled when the dtio thread goes to sleep, and
+ after sleep the thread checks to see if there are messages to log
+ immediately.
+
+16 July 2024: Wouter
+ - For #1103: Fix to drop mesh state reference for the http2 stream
+ associated with the reply, not the currently active stream. And
+ it does not remove it twice on a mesh_send_reply call. The reply
+ h2_stream is NULL when not in use, for more initialisation.
+
+15 July 2024: Wouter
+ - For #1103: fix to also drop mesh state reference when the discard
+ limit is reached, when there is an error making a new recursion
+ state and when the connection is dropped with is_drop.
+
+12 July 2024: Yorgos
+ - Add RPZ tag tests in acl_interface.tdir.
+ - For #1102: clearer text for using interface-* options for the
+ loopback interface.
+
+12 July 2024: Wouter
+ - Fix #1103: unbound 1.20.0 segmentation fault with nghttp2.
+ - For #1103: fix to also drop mesh state reference when a h2 reply is
+ dropped.
+
+10 July 2024: Wouter
+ - For #773: In contrib/unbound.service.in set unbound to start after
+ network-online.target. Also for contrib/unbound_portable.service.in.
+
+9 July 2024: Yorgos
+ - Update list of known EDE codes.
+
+8 July 2024: Wouter
+ - Fix that validation reason failure that uses string print uses
+ separate buffer that is passed, from the scratch validation buffer.
+ - Fixup algo_needs_reason string buffer length.
+ - Fix shadowed error string variable in validator dnskey handling.
+
+5 July 2024: Yorgos
+ - Don't check for message TTL changes if the RRsets remain the same.
+
+5 July 2024: Wouter
+ - Fix for neater printout for error for missing DS response.
+ - Fix neater printout.
+ - Fix #1099: Unbound core dump on SIGSEGV.
+ - Fix for #1099: Fix to check for deleted RRset when the contents
+ is updated and fetched after it is stored, and also check for a
+ changed RRset.
+
+4 July 2024: Wouter
+ - Fix to print details about the failure to lookup a DNSKEY record
+ when validation fails due to the missing DNSKEY. Also for key prime
+ and DS lookups.
+
+3 July 2024: Yorgos
+ - Fix for repeated use of a DNAME record: first overallocate and then
+ move the exact size of the init value to avoid false positive heap
+ overflow reads from address sanitizers.
+
+3 July 2024: Wouter
+ - Fix #144: Port ipset to BSD pf tables.
+ - Add unit test skip files and bison and flex output to gitignore.
+ - Fix to use modstack_init in zonemd unit test.
+ - Fix to remove unneeded linebreak in fptr_wlist.c.
+ - Fix compile warnings in fptr_wlist.c.
+
+2 July 2024: Wouter
+ - Fix to remove unused include from the readzone test program.
+ - Fix unused variable warning in do_cache_remove.
+ - Fix compile warning in worker pthread id printout.
+
+17 June 2024: Wouter
+ - Fix ip-ratelimit-cookie setting, it was not applied.
+
+26 June 2024: Yorgos
+ - Explicitly set the RD bit for the mesh query flags when prefetching.
+ These queries have no waiting client but they need to be treated as
+ recursive.
+
+21 June 2024: Yorgos
+ - Fix pkg-config availability check in dnstap/dnstap.m4 and
+ systemd.m4.
+
+19 June 2024: Yorgos
+ - Fix #1092: Ubuntu 22.04 Jammy fails to compile unbound 1.20.0; by
+ adding helpful text for the Python interpreter version and allowing
+ the default pkg-config unavailability error message to be shown.
+
+17 June 2024: Wouter
+ - Fix #1091: Build fails with OpenSSL >= 3.0 built with
+ OPENSSL_NO_DEPRECATED.
+
+7 June 2024: Wouter
+ - Add unit test for validation of repeated use of a DNAME record.
+
+6 June 2024: Wouter
+ - Fix memory leak in setup of dsa sig.
+ - Fix typos for 'the the' in text.
+ - Fix validation for repeated use of a DNAME record.
+
+4 June 2024: Yorgos
+ - Merge #1080: AddressSanitizer detection in tdir tests and memory leak
+ fixes.
+ - Fix memory leak when reload_keep_cache is used and num-threads
+ changes.
+ - Fix memory leak on exit for unbound-dnstap-socket; creates false
+ negatives during testing.
+
+3 June 2024: Wouter
+ - Fix to squelch connection reset by peer errors from log. And fix
+ that the tcp read errors are labeled as initial for the first calls.
+
+30 May 2024: Wouter
+ - Fix #1079: tags from tagged rpz zones are no longer honored after
+ upgrade from 1.19.3 to 1.20.0.
+ - Fix for #1079: fix RPZ taglist in iterator callback that no client
+ info is like no taglist intersection.
+
+29 May 2024: Wouter
+ - Merge #1078: Only check old pid if no username.
+
+27 May 2024: Wouter
+ - Fix to enable that SERVFAIL is cached, for a short period, for more
+ cases. In the cases where limits are exceeded.
+ - Fix spelling of tcp-idle-timeout docs, from Michael Tokarev.
+
+27 May 2024: Yorgos
+ - Fix unused variable warning on compilation with no thread support.
+ - unbound-control-setup: check openssl availability before doing
+ anything, patch from Michael Tokarev.
+ - Update patch to remove 'command' shell builtin and update error
+ text.
+
+24 May 2024: Wouter
+ - Fix #1064: Unbound 1.20 Cachedb broken?
+
+24 May 2024: Yorgos
+ - Fix #1059: Intermittent DNS blocking failure with local-zone and
+ always_nxdomain. Addition of local_zones dynamically via
+ unbound-control was not finding the zone's parent correctly.
+
+21 May 2024: Wouter
+ - Merge #1073: fix null pointer dereference issue in function
+ ub_ctx_set_fwd.
+ - Fix to print a parse error when config is read with no name for
+ a forward-zone, stub-zone or view.
+ - Fix for parse end of forward-zone, stub-zone and view.
+ - Fix for #1064: Fix that cachedb expired messages are considered
+ insecure, and thus can be served to clients when dnssec is enabled.
+
+17 May 2024: Yorgos
+ - Merge #1069: Fix unbound-control stdin commands for multi-process
+ Unbounds.
+ - Fix unbound-control commands that read stdin in multi-process
+ operation (local_zones_remove, local_zones, local_datas_remove,
+ local_datas, view_local_datas_remove, view_local_datas). They will
+ be properly distributed to all processes. dump_cache and load_cache
+ are no longer supported in multi-process operation.
+ - Remove testdata/remote-threaded.tdir. testdata/09-unbound-control.tdir
+ now checks both single and multi process/thread operation.
+
+16 May 2024: Yorgos
+ - Merge #1070: Fix rtt assignement for low values of
+ infra-cache-max-rtt.
+
+16 May 2024: Wouter
+ - Fix #1071: [FR] Clear both in-memory and cachedb module cache with
+ `unbound-control flush*` commands.
+
+15 May 2024: Yorgos
+ - Add missing common functions to tdir tests.
+
+10 May 2024: Wouter
+ - Fix when the mesh jostle is exceeded that nameserver targets are
+ marked as resolved, so that the lookup is not stuck on the
+ requestlist.
+
+8 May 2024: Wouter
+ - Fix to squelch udp connect errors in the log at low verbosity about
+ invalid argument for IPv6 link local addresses.
+
+7 May 2024: Wouter
+ - Merge #1062: Fix potential overflow bug while parsing port in
+ function cfg_mark_ports.
+ - Fix for #1062: declaration before statement, avoid print of null,
+ and redundant check for array size.
+
1 May 2024: Wouter
- Fix for the DNSBomb vulnerability CVE-2024-33655. Thanks to Xiang Li
from the Network and Information Security Lab of Tsinghua University
for reporting it.
- - Set version number to 1.20.0 for release.
+ - Set version number to 1.20.0 for release. This became the release
+ on 8 may 2024, the repository continues with version 1.20.1.
29 April 2024: Yorgos
- Cleanup unnecessary strdup calls for EDE strings.
-README for Unbound 1.20.0
+README for Unbound 1.21.0
Copyright 2007 NLnet Labs
http://unbound.net
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.20.0.
+# See unbound.conf(5) man page, version 1.21.0.
#
# this is a comment.
# the time to live (TTL) value lower bound, in seconds. Default 0.
# For negative responses in the cache. If disabled, default,
- # cache-min-tll applies if configured.
+ # cache-min-ttl applies if configured.
# cache-min-negative-ttl: 0
# the time to live (TTL) value for cached roundtrip times, lameness and
# example value "000102030405060708090a0b0c0d0e0f".
# cookie-secret: <128 bit random hex string>
+ # File with cookie secrets, the 'cookie-secret:' option is ignored
+ # and the file can be managed to have staging and active secrets
+ # with remote control commands. Disabled with "". Default is "".
+ # cookie-secret-file: "/usr/local/etc/unbound_cookiesecrets.txt"
+
# Enable to attach Extended DNS Error codes (RFC8914) to responses.
# ede: no
# dnstap-identity: ""
# # if "" it uses the package version.
# dnstap-version: ""
+# # log only 1/N messages, if 0 it is disabled. default 0.
+# dnstap-sample-rate: 0
# dnstap-log-resolver-query-messages: no
# dnstap-log-resolver-response-messages: no
# dnstap-log-client-query-messages: no
# dnstap-log-forwarder-response-messages: no
# Response Policy Zones
-# RPZ policies. Applied in order of configuration. QNAME, Response IP
+# RPZ policies. Applied in order of configuration. Any match from an earlier
+# RPZ zone will terminate the RPZ lookup. QNAME, Response IP
# Address, nsdname, nsip and clientip triggers are supported. Supported
# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only
# and drop. Policies can be loaded from a file, or using zone
-.TH "libunbound" "3" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "libunbound" "3" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
-\- Unbound DNS validating resolver 1.20.0 functions.
+\- Unbound DNS validating resolver 1.21.0 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
-.TH "unbound-anchor" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound-anchor" "8" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
-.TH "unbound-checkconf" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound-checkconf" "8" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
-.TH "unbound-control" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound-control" "8" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
line. For bulk removals.
.TP
.B dump_cache
-The contents of the cache is printed in a text format to stdout. You can
-redirect it to a file to store the cache in a file.
+The content of the cache is printed in a text format to stdout.
+You can redirect it to a file to store the cache in a file.
+Not supported in remote Unbounds in multi-process operation.
.TP
.B load_cache
-The contents of the cache is loaded from stdin. Uses the same format as
-dump_cache uses. Loading the cache with old, or wrong data can result
-in old or wrong data returned to clients. Loading data into the cache
-in this way is supported in order to aid with debugging.
+The content of the cache is loaded from stdin.
+Uses the same format as dump_cache uses.
+Loading the cache with old, or wrong data can result in old or wrong data
+returned to clients.
+Loading data into the cache in this way is supported in order to aid with
+debugging.
+Not supported in remote Unbounds in multi-process operation.
.TP
.B lookup \fIname
Print to stdout the name servers that would be used to look up the
name specified.
.TP
-.B flush \fIname
+.B flush \fR[\fI+c\fR] \fIname
Remove the name from the cache. Removes the types
A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR, SVCB and HTTPS.
Because that is fast to do. Other record types can be removed using
.B flush_type
or
.B flush_zone\fR.
+.IP
+The '+c' option removes the items also from the cachedb cache. If
+cachedb is in use.
.TP
-.B flush_type \fIname\fR \fItype
+.B flush_type \fR[\fI+c\fR] \fIname\fR \fItype
Remove the name, type information from the cache.
.TP
-.B flush_zone \fIname
+.B flush_zone \fR[\fI+c\fR] \fIname
Remove all information at or below the name from the cache.
The rrsets and key entries are removed so that new lookups will be performed.
This needs to walk and inspect the entire cache, and is a slow operation.
with serve\-expired enabled, it'll serve that information but schedule a
prefetch for new information).
.TP
-.B flush_bogus
+.B flush_bogus \fR[\fI+c\fR]
Remove all bogus data from the cache.
.TP
-.B flush_negative
+.B flush_negative \fR[\fI+c\fR]
Remove all negative data from the cache. This is nxdomain answers,
nodata answers and servfail answers. Also removes bad key entries
(which could be due to failed lookups) from the dnssec key cache, and
.TP
.B view_local_datas \fIview\fR
Add a list of \fIlocal_data\fR for given view from stdin. Like local_datas.
+.TP
+.B add_cookie_secret <secret>
+Add or replace a cookie secret persistently. <secret> needs to be an 128 bit
+hex string.
+.IP
+Cookie secrets can be either \fIactive\fR or \fIstaging\fR. \fIActive\fR cookie
+secrets are used to create DNS Cookies, but verification of a DNS Cookie
+succeeds with any of the \fIactive\fR or \fIstaging\fR cookie secrets. The
+state of the current cookie secrets can be printed with the
+\fBprint_cookie_secrets\fR command.
+.IP
+When there are no cookie secrets configured yet, the <secret> is added as
+\fIactive\fR. If there is already an \fIactive\fR cookie secret, the <secret>
+is added as \fIstaging\fR or replacing an existing \fIstaging\fR secret.
+.IP
+To "roll" a cookie secret used in an anycast set. The new secret has to be
+added as staging secret to \fBall\fR nodes in the anycast set. When \fBall\fR
+nodes can verify DNS Cookies with the new secret, the new secret can be
+activated with the \fBactivate_cookie_secret\fR command. After \fBall\fR nodes
+have the new secret \fIactive\fR for at least one hour, the previous secret can
+be dropped with the \fBdrop_cookie_secret\fR command.
+.IP
+Persistence is accomplished by writing to a file which if configured with the
+\fBcookie\-secret\-file\fR option in the server section of the config file.
+This is disabled by default, "".
+.TP
+.B drop_cookie_secret
+Drop the \fIstaging\fR cookie secret.
+.TP
+.B activate_cookie_secret
+Make the current \fIstaging\fR cookie secret \fIactive\fR, and the current
+\fIactive\fR cookie secret \fIstaging\fR.
+.TP
+.B print_cookie_secrets
+Show the current configured cookie secrets with their status.
.SH "EXIT CODE"
The unbound\-control program exits with status code 1 on error, 0 on success.
.SH "SET UP"
-.TH "unbound\-host" "1" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound\-host" "1" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
-.TH "unbound" "8" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound" "8" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound.8 -- unbound manual
.\"
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.20.0.
+\- Unbound DNS validating resolver 1.21.0.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
-.TH "unbound.conf" "5" "May 8, 2024" "NLnet Labs" "unbound 1.20.0"
+.TH "unbound.conf" "5" "Aug 15, 2024" "NLnet Labs" "unbound 1.21.0"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
total number configured, and finally to 0 if the number of free buffers
falls below 20% of the total number configured. A minimum timeout of
200 milliseconds is observed regardless of the option value used.
-It will be overriden by \fBedns\-tcp\-keepalive\-timeout\fR if
+It will be overridden by \fBedns\-tcp\-keepalive\-timeout\fR if
\fBedns\-tcp\-keepalive\fR is enabled.
.TP
.B tcp-reuse-timeout: \fI<msec>\fR
UDP queries without a DNS Cookie receive REFUSED responses with the TC flag set,
that may trigger fall back to TCP for those clients.
.IP
-By default only localhost is \fIallow\fRed, the rest is \fIrefuse\fRd.
+By default only localhost (the 127.0.0.0/8 IP netblock, not the loopback
+interface) is implicitly \fIallow\fRed, the rest is \fIrefuse\fRd.
The default is \fIrefuse\fRd, because that is protocol\-friendly. The DNS
protocol is not designed to handle dropped packets due to policy, and
dropping may result in (possibly excessive) retried queries.
.IP
The action is the same as the ones defined under \fBaccess\-control:\fR.
Interfaces are \fIrefuse\fRd by default.
-By default only localhost (the IP netblock, not the loopback interface) is
-\fIallow\fRed through the default \fBaccess\-control:\fR behavior.
+By default only localhost (the 127.0.0.0/8 IP netblock, not the loopback
+interface) is implicitly \fIallow\fRed through the default
+\fBaccess\-control:\fR behavior.
+This also means that any attempt to use the \fBinterface-*:\fR options for the
+loopback interface will not work as they will be overridden by the implicit
+default "\fBaccess\-control:\fR 127.0.0.0/8 allow" option.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
share the secret in order to verify each other's Server Cookies.
An example hex string would be "000102030405060708090a0b0c0d0e0f".
Default is a 128 bits random secret generated at startup time.
+This option is ignored if a \fBcookie\-secret\-file\fR is
+present. In that case the secrets from that file are used in DNS Cookie
+calculations.
+.TP 5
+.B cookie\-secret\-file: \fI<filename>
+File from which the secrets are read used in DNS Cookie calculations. When this
+file exists, the secrets in this file are used and the secret specified by the
+\fBcookie-secret\fR option is ignored.
+Enable it by setting a filename, like "/usr/local/etc/unbound_cookiesecrets.txt".
+The content of this file must be manipulated with the \fBadd_cookie_secret\fR,
+\fBdrop_cookie_secret\fR and \fBactivate_cookie_secret\fR commands to the
+\fIunbound\-control\fR(8) tool. Please see that manpage on how to perform a
+safe cookie secret rollover.
+Default is "" (disabled).
.TP 5
.B edns\-client\-string: \fI<IP netblock> <string>
Include an EDNS0 option containing configured ascii string in queries with
The version to send with messages, if "" the package version is used.
Default is "".
.TP
+.B dnstap-sample-rate: \fI<number>
+The sample rate for log of messages, it logs only 1/N messages. With 0 it
+is disabled. Default is 0. This is useful in a high volume environment,
+where log functionality would otherwise not be reliable. For example 10
+would spend only 1/10th time on logging, and 100 would only spend a
+hundredth of the time on logging.
+.TP
.B dnstap-log-resolver-query-messages: \fI<yes or no>
Enable to log resolver query messages. Default is no.
These are messages from Unbound to upstream servers.
.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.:
+\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 and
+any match from an earlier RPZ zone will terminate the RPZ lookup. Note that a
+PASSTHRU action is still considered a match.
+The \fBrespip\fR module needs to be added to the \fBmodule-config\fR, e.g.:
\fBmodule-config: "respip validator iterator"\fR.
.P
QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
and drop. RPZ QNAME triggers are applied after \fBlocal\-zones\fR and
before \fBauth\-zones\fR.
.P
-The rpz zone is formatted with a SOA start record as usual. The items in
-the zone are entries, that specify what to act on (the trigger) and what to
-do (the action). The trigger to act on is recorded in the name, the action
-to do is recorded as the resource record. The names all end in the zone
-name, so you could type the trigger names without a trailing dot in the
-zonefile.
+The RPZ zone is a regular DNS zone formatted with a SOA start record as usual.
+The items in the zone are entries, that specify what to act on (the trigger)
+and what to do (the action).
+The trigger to act on is recorded in the name, the action to do is recorded as
+the resource record.
+The names all end in the zone name, so you could type the trigger names without
+a trailing dot in the zonefile.
.P
An example RPZ record, that answers example.com with NXDOMAIN
.nf
If enabled the zone is authoritatively answered for and queries for the RPZ
zone information are answered to downstream clients. This is useful for
monitoring scripts, that can then access the SOA information to check if
-the rpz information is up to date. Default is no.
+the RPZ information is up to date. Default is no.
.TP
.B tags: \fI<list of tags>
Limit the policies from this RPZ clause to clients with a matching tag. Tags
* The module function block
*/
static struct module_func_block subnetmod_block = {
- "subnetcache", &subnetmod_init, &subnetmod_deinit, &subnetmod_operate,
+ "subnetcache",
+ NULL, NULL, &subnetmod_init, &subnetmod_deinit, &subnetmod_operate,
&subnetmod_inform_super, &subnetmod_clear, &subnetmod_get_mem
};
*/
static struct module_func_block ipsecmod_block = {
"ipsecmod",
- &ipsecmod_init, &ipsecmod_deinit, &ipsecmod_operate,
+ NULL, NULL, &ipsecmod_init, &ipsecmod_deinit, &ipsecmod_operate,
&ipsecmod_inform_super, &ipsecmod_clear, &ipsecmod_get_mem
};
default:
errno = EAFNOSUPPORT;
return -1;
- }
+}
addr.pfra_af = af;
if (ioctl(dev, DIOCRADDADDRS, &io) == -1) {
if (!env || !env->modinfo[id]) {
return;
}
- ipset_env = (struct ipset_env*)env->modinfo[id];
+ ipset_env = (struct ipset_env *)env->modinfo[id];
dev = (filter_dev)ipset_env->dev;
if (dev) {
return 0;
}
+/** Shorten RRset */
+static void
+shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
+{
+ /* The too large NS RRset is shortened. This is so that too large
+ * content does not overwhelm the cache. It may make the rrset
+ * bogus if it was signed, and then the domain is not resolved any
+ * more, that is okay, the NS RRset was too large. During a referral
+ * it can be shortened and then the first part of the list could
+ * be used to resolve. The scrub continues to disallow glue for the
+ * removed nameserver RRs and removes that too. Because the glue
+ * is not marked as okay, since the RRs have been removed here. */
+ int i;
+ struct rr_parse* rr = rrset->rr_first, *prev = NULL;
+ if(!rr)
+ return;
+ for(i=0; i<count; i++) {
+ prev = rr;
+ rr = rr->next;
+ if(!rr)
+ return; /* The RRset is already short. */
+ }
+ if(verbosity >= VERB_QUERY
+ && rrset->dname_len <= LDNS_MAX_DOMAINLEN) {
+ uint8_t buf[LDNS_MAX_DOMAINLEN+1];
+ dname_pkt_copy(pkt, buf, rrset->dname);
+ log_nametypeclass(VERB_QUERY, "normalize: shorten RRset:", buf,
+ rrset->type, ntohs(rrset->rrset_class));
+ }
+ /* remove further rrs */
+ rrset->rr_last = prev;
+ rrset->rr_count = count;
+ while(rr) {
+ rrset->size -= rr->size;
+ rr = rr->next;
+ }
+ if(rrset->rr_last)
+ rrset->rr_last->next = NULL;
+ else rrset->rr_first = NULL;
+}
+
/**
* This routine normalizes a response. This includes removing "irrelevant"
* records from the answer and additional sections and (re)synthesizing
uint8_t* sname = qinfo->qname;
size_t snamelen = qinfo->qname_len;
struct rrset_parse* rrset, *prev, *nsset=NULL;
+ int cname_length = 0; /* number of CNAMEs, or DNAMEs */
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN)
prev = NULL;
rrset = msg->rrset_first;
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
+ if(cname_length > 11 /* env->cfg.iter_scrub_cname */) {
+ /* Too many CNAMEs, or DNAMEs, from the authority
+ * server, scrub down the length to something
+ * shorter. This deletes everything after the limit
+ * is reached. The iterator is going to look up
+ * the content one by one anyway. */
+ remove_rrset("normalize: removing because too many cnames:",
+ pkt, msg, prev, &rrset);
+ continue;
+ }
if(rrset->type == LDNS_RR_TYPE_DNAME &&
pkt_strict_sub(pkt, sname, rrset->dname)) {
/* check if next rrset is correct CNAME. else,
"too long");
return 0;
}
+ cname_length++;
if(nx && nx->type == LDNS_RR_TYPE_CNAME &&
dname_pkt_compare(pkt, sname, nx->dname) == 0) {
/* check next cname */
if(rrset->type == LDNS_RR_TYPE_CNAME) {
struct rrset_parse* nx = rrset->rrset_all_next;
uint8_t* oldsname = sname;
+ cname_length++;
/* see if the next one is a DNAME, if so, swap them */
if(nx && nx->section == LDNS_SECTION_ANSWER &&
nx->type == LDNS_RR_TYPE_DNAME &&
LDNS_SECTION_ANSWER &&
dname_pkt_compare(pkt, oldsname,
rrset->dname) == 0) {
+ if(rrset->type == LDNS_RR_TYPE_NS &&
+ rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
+ shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ }
prev = rrset;
rrset = rrset->rrset_all_next;
}
continue;
}
+ if(rrset->type == LDNS_RR_TYPE_NS &&
+ rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
+ shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ }
+
/* Mark the additional names from relevant rrset as OK. */
/* only for RRsets that match the query name, other ones
* will be removed by sanitize, so no additional for them */
"RRset:", pkt, msg, prev, &rrset);
continue;
}
+ if(rrset->rr_count > 20 /* env->cfg->iter_scrub_ns */) {
+ /* If this is not a referral, and the NS RRset
+ * is signed, then remove it entirely, so
+ * that when it becomes bogus it does not
+ * make the message that is otherwise fine
+ * into a bogus message. */
+ if(!(msg->an_rrsets == 0 &&
+ FLAGS_GET_RCODE(msg->flags) ==
+ LDNS_RCODE_NOERROR &&
+ !soa_in_auth(msg) &&
+ !(msg->flags & BIT_AA)) &&
+ rrset->rrsig_count != 0) {
+ remove_rrset("normalize: removing too large NS "
+ "RRset:", pkt, msg, prev, &rrset);
+ continue;
+ } else {
+ shorten_rrset(pkt, rrset, 20 /* env->cfg->iter_scrub_ns */);
+ }
+ }
}
/* if this is type DS and we query for type DS we just got
* a referral answer for our type DS query, fix packet */
name, namelen, qtype, &lame, &dnsseclame, &reclame,
&rtt, now)) {
log_addr(VERB_ALGO, "servselect", &a->addr, a->addrlen);
- verbose(VERB_ALGO, " rtt=%d%s%s%s%s", rtt,
+ verbose(VERB_ALGO, " rtt=%d%s%s%s%s%s", rtt,
lame?" LAME":"",
dnsseclame?" DNSSEC_LAME":"",
+ a->dnsseclame?" ADDR_DNSSEC_LAME":"",
reclame?" REC_LAME":"",
a->lame?" ADDR_LAME":"");
if(lame)
iq->target_count[TARGET_COUNT_NX] += num;
}
+static void
+target_count_increase_global_quota(struct iter_qstate* iq, int num)
+{
+ target_count_create(iq);
+ if(iq->target_count)
+ iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
+}
+
/**
* Generate a subrequest.
* Generate a local request event. Local events are tied to this module, and
"restarts (eg. indirections)");
if(iq->qchase.qname)
errinf_dname(qstate, "stop at", iq->qchase.qname);
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* We enforce a maximum recursion/dependency depth -- in general,
errinf(qstate, "malloc failure for forward zone");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
+ if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
+ qstate->region, iq->dp)) {
+ errinf(qstate, "malloc failure, copy extra info into delegation point");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
if((qstate->query_flags&BIT_RD)==0) {
/* If the server accepts RD=0 queries and forwards
* with RD=1, then if the server is listed as an NS
if(!iq->dp) {
log_err("internal error: no hints dp");
errinf(qstate, "no hints for this class");
- return error_response(qstate, id,
+ return error_response_cache(qstate, id,
LDNS_RCODE_SERVFAIL);
}
iq->dp = delegpt_copy(iq->dp, qstate->region);
* if it is negative, there is no maximum number of targets.
* @param num: returns the number of queries generated and processed,
* which may be zero if there were no missing targets.
- * @return false on error.
+ * @return 0 on success, nonzero on error. 1 means temporary failure and
+ * 2 means the failure can be cached.
*/
static int
query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
else toget = maxtargets;
if(toget == 0) {
*num = 0;
- return 1;
+ return 0;
}
/* now that we are sure that a target query is going to be made,
* check the limits. */
if(iq->depth == ie->max_dependency_depth)
- return 0;
+ return 1;
if(iq->depth > 0 && iq->target_count &&
iq->target_count[TARGET_COUNT_QUERIES] > MAX_TARGET_COUNT) {
char s[LDNS_MAX_DOMAINLEN+1];
verbose(VERB_QUERY, "request %s has exceeded the maximum "
"number of glue fetches %d", s,
iq->target_count[TARGET_COUNT_QUERIES]);
- return 0;
+ return 2;
}
if(iq->dp_target_count > MAX_DP_TARGET_COUNT) {
char s[LDNS_MAX_DOMAINLEN+1];
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;
+ return 2;
}
/* select 'toget' items from the total of 'missing' items */
*num = query_count;
if(query_count > 0)
qstate->ext_state[id] = module_wait_subquery;
- return 0;
+ return 1;
}
query_count++;
/* If the mesh query list is full, exit the loop here.
* increase, because the spawned state uses cpu and a
* socket while this state waits for that spawned
* state. Next time we can look up further targets */
- if(mesh_jostle_exceeded(qstate->env->mesh))
+ if(mesh_jostle_exceeded(qstate->env->mesh)) {
+ /* If no ip4 query is possible, that makes
+ * this ns resolved. */
+ if(!((ie->supports_ipv4 || ie->use_nat64) &&
+ ((ns->lame && !ns->done_pside4) ||
+ (!ns->lame && !ns->got4)))) {
+ ns->resolved = 1;
+ }
break;
}
+ }
/* Send the A request. */
if((ie->supports_ipv4 || ie->use_nat64) &&
((ns->lame && !ns->done_pside4) ||
*num = query_count;
if(query_count > 0)
qstate->ext_state[id] = module_wait_subquery;
- return 0;
+ return 1;
}
query_count++;
/* If the mesh query list is full, exit the loop. */
- if(mesh_jostle_exceeded(qstate->env->mesh))
+ if(mesh_jostle_exceeded(qstate->env->mesh)) {
+ /* With the ip6 query already checked for,
+ * this makes the ns resolved. It is no longer
+ * a missing target. */
+ ns->resolved = 1;
break;
}
+ }
/* mark this target as in progress. */
ns->resolved = 1;
if(query_count > 0)
qstate->ext_state[id] = module_wait_subquery;
- return 1;
+ return 0;
}
/**
}
/* query for an extra name added by the parent-NS record */
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
- int qs = 0;
+ int qs = 0, ret;
verbose(VERB_ALGO, "try parent-side target name");
- if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) {
+ if((ret=query_for_targets(qstate, iq, ie, id, 1, &qs))!=0) {
errinf(qstate, "could not fetch nameserver");
errinf_dname(qstate, "at zone", iq->dp->name);
+ if(ret == 1)
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
target_count_increase(iq, qs);
verbose(VERB_QUERY, "request has exceeded the maximum "
"number of referrrals with %d", iq->referral_count);
errinf(qstate, "exceeded the maximum of referrals");
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(iq->sent_count > ie->max_sent_count) {
verbose(VERB_QUERY, "request has exceeded the maximum "
"number of sends with %d", iq->sent_count);
errinf(qstate, "exceeded the maximum number of sends");
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* Check if we reached MAX_TARGET_NX limit without a fallback activation. */
"already present for the delegation point, no "
"fallback possible");
errinf(qstate, "exceeded the maximum nameserver nxdomains");
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
verbose(VERB_ALGO, "initiating parent-side fallback for "
"nxdomain nameserver lookups");
"lookups (%d) with %d", MAX_TARGET_NX_FALLBACK,
iq->target_count[TARGET_COUNT_NX]);
errinf(qstate, "exceeded the maximum nameserver nxdomains");
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(!iq->dp->has_parent_side_NS) {
verbose(VERB_ALGO, "auth zone lookup failed, no fallback,"
" servfail");
errinf(qstate, "auth zone lookup failed, fallback is off");
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(iq->dp->auth_dp) {
/* we wanted to fallback, but had no delegpt, only the
/* if in 0x20 fallback get as many targets as possible */
if(iq->caps_fallback) {
- int extra = 0;
+ int extra = 0, ret;
size_t naddr, nres, navail;
- if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
+ if((ret=query_for_targets(qstate, iq, ie, id, -1, &extra))!=0) {
errinf(qstate, "could not fetch nameservers for 0x20 fallback");
+ if(ret == 1)
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
target_count_increase(iq, extra);
* to distinguish between generating (a) new target
* query, or failing. */
if(delegpt_count_missing_targets(iq->dp, NULL) > 0) {
- int qs = 0;
+ int qs = 0, ret;
verbose(VERB_ALGO, "querying for next "
"missing target");
- if(!query_for_targets(qstate, iq, ie, id,
- 1, &qs)) {
+ if((ret=query_for_targets(qstate, iq, ie, id,
+ 1, &qs))!=0) {
errinf(qstate, "could not fetch nameserver");
errinf_dname(qstate, "at zone", iq->dp->name);
+ if(ret == 1)
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id,
+ LDNS_RCODE_SERVFAIL);
}
if(qs == 0 &&
delegpt_count_missing_targets(iq->dp, NULL) == 0){
* so this is not a loop. */
return 1;
}
+ if(qs == 0) {
+ /* There should be targets now, and
+ * if there are not, it should not
+ * wait for no targets. Stop it from
+ * waiting forever, or looping to
+ * here, as a safeguard. */
+ errinf(qstate, "could not generate nameserver lookups");
+ errinf_dname(qstate, "at zone", iq->dp->name);
+ return error_response(qstate, id,
+ LDNS_RCODE_SERVFAIL);
+ }
iq->num_target_queries += qs;
target_count_increase(iq, qs);
}
}
}
+ target_count_increase_global_quota(iq, 1);
+ if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
+ > MAX_GLOBAL_QUOTA) {
+ char s[LDNS_MAX_DOMAINLEN+1];
+ dname_str(qstate->qinfo.qname, s);
+ verbose(VERB_QUERY, "request %s has exceeded the maximum "
+ "global quota on number of upstream queries %d", s,
+ iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+
/* Do not check ratelimit for forwarding queries or if we already got a
* pass. */
sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
qstate->was_ratelimited = 1;
errinf_dname(qstate, "exceeded ratelimit for zone",
iq->dp->name);
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
log_addr(VERB_QUERY, "error sending query to auth server",
&real_addr, real_addrlen);
iter_scrub_nxdomain(iq->response);
return final_state(iq);
}
- return error_response(qstate, id,
+ return error_response_cache(qstate, id,
LDNS_RCODE_SERVFAIL);
}
/* Best effort qname-minimisation.
" fallback possible, servfail");
errinf_dname(qstate, "response is bad, no fallback, "
"for auth zone", iq->dp->name);
- return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
verbose(VERB_ALGO, "auth zone response was bad, "
"fallback enabled");
if(iq->num_current_queries == 0) {
verbose(VERB_ALGO, "No root hints or fwds, giving up "
"on qclass ANY");
- return error_response(qstate, id, LDNS_RCODE_REFUSED);
+ return error_response_cache(qstate, id, LDNS_RCODE_REFUSED);
}
/* return false, wait for queries to return */
}
"getting different replies, failed");
outbound_list_remove(&iq->outlist, outbound);
errinf(qstate, "0x20 failed, then got different replies in fallback");
- (void)error_response(qstate, id,
+ (void)error_response_cache(qstate, id,
LDNS_RCODE_SERVFAIL);
return;
}
*/
static struct module_func_block iter_block = {
"iterator",
- &iter_init, &iter_deinit, &iter_operate, &iter_inform_super,
- &iter_clear, &iter_get_mem
+ NULL, NULL, &iter_init, &iter_deinit, &iter_operate,
+ &iter_inform_super, &iter_clear, &iter_get_mem
};
struct module_func_block*
/** max number of targets spawned for a query and its subqueries */
#define MAX_TARGET_COUNT 64
+/** max number of upstream queries for a query and its subqueries, it is
+ * never reset. */
+#define MAX_GLOBAL_QUOTA 128
/** 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
TARGET_COUNT_QUERIES,
/** Number of nxdomain responses encountered. */
TARGET_COUNT_NX,
+ /** Global quota on number of queries to upstream servers per
+ * client request, that is never reset. */
+ TARGET_COUNT_GLOBAL_QUOTA,
/** This should stay last here, it is used for the allocation */
TARGET_COUNT_MAX,
ctx->pipe_pid = getpid();
cfg_apply_local_port_policy(cfg, 65536);
config_apply(cfg);
- if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
+ if(!modstack_call_startup(&ctx->mods, cfg->module_conf, ctx->env))
+ return UB_INITFAIL;
+ if(!modstack_call_init(&ctx->mods, cfg->module_conf, ctx->env))
return UB_INITFAIL;
listen_setup_locks();
log_edns_known_options(VERB_ALGO, ctx->env);
int e = errno;
ub_randfree(ctx->seed_rnd);
config_delete(ctx->env->cfg);
- modstack_desetup(&ctx->mods, ctx->env);
+ modstack_call_deinit(&ctx->mods, ctx->env);
+ modstack_call_destartup(&ctx->mods, ctx->env);
+ modstack_free(&ctx->mods);
listen_desetup_locks();
edns_known_options_delete(ctx->env);
edns_strings_delete(ctx->env->edns_strings);
tube_delete(ctx->qq_pipe);
ub_randfree(ctx->seed_rnd);
config_delete(ctx->env->cfg);
- modstack_desetup(&ctx->mods, ctx->env);
+ modstack_call_deinit(&ctx->mods, ctx->env);
+ modstack_call_destartup(&ctx->mods, ctx->env);
+ modstack_free(&ctx->mods);
listen_desetup_locks();
edns_known_options_delete(ctx->env);
edns_strings_delete(ctx->env->edns_strings);
}
libworker_delete_event(ctx->event_worker);
- modstack_desetup(&ctx->mods, ctx->env);
+ modstack_call_deinit(&ctx->mods, ctx->env);
+ modstack_call_destartup(&ctx->mods, ctx->env);
+ modstack_free(&ctx->mods);
a = ctx->alloc_list;
while(a) {
na = a->super;
if(!addr) {
/* disable fwd mode - the root stub should be first. */
if(ctx->env->cfg->forwards &&
- strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
+ (ctx->env->cfg->forwards->name &&
+ strcmp(ctx->env->cfg->forwards->name, ".") == 0)) {
s = ctx->env->cfg->forwards;
ctx->env->cfg->forwards = s->next;
s->next = NULL;
/* it parses, add root stub in front of list */
lock_basic_lock(&ctx->cfglock);
if(!ctx->env->cfg->forwards ||
- strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
+ (ctx->env->cfg->forwards->name &&
+ strcmp(ctx->env->cfg->forwards->name, ".") != 0)) {
s = calloc(1, sizeof(*s));
if(!s) {
lock_basic_unlock(&ctx->cfglock);
ctx->env->cfg->forwards = s;
} else {
log_assert(ctx->env->cfg->forwards);
+ log_assert(ctx->env->cfg->forwards->name);
s = ctx->env->cfg->forwards;
}
dupl = strdup(addr);
log_err("unknown command for bg worker %d",
(int)context_serial_getcmd(msg, len));
/* and fall through to quit */
+ ATTR_FALLTHROUGH
/* fallthrough */
case UB_LIBCMD_QUIT:
free(msg);
*/
static struct module_func_block respip_block = {
"respip",
- &respip_init, &respip_deinit, &respip_operate, &respip_inform_super,
- &respip_clear, &respip_get_mem
+ NULL, NULL, &respip_init, &respip_deinit, &respip_operate,
+ &respip_inform_super, &respip_clear, &respip_get_mem
};
struct module_func_block*
static int zonemd_dnssec_verify_rrset(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* node,
- struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg)
+ struct auth_rrset* rrset, char** why_bogus, uint8_t* sigalg,
+ char* reasonbuf, size_t reasonlen)
{
struct ub_packed_rrset_key pk;
enum sec_status sec;
"zonemd: verify %s RRset with DNSKEY", typestr);
}
sec = dnskeyset_verify_rrset(env, ve, &pk, dnskey, sigalg, why_bogus, NULL,
- LDNS_SECTION_ANSWER, NULL, &verified);
+ LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf, reasonlen);
if(sec == sec_status_secure) {
return 1;
}
static int zonemd_check_dnssec_absence(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
- char** reason, char** why_bogus, uint8_t* sigalg)
+ char** reason, char** why_bogus, uint8_t* sigalg, char* reasonbuf,
+ size_t reasonlen)
{
struct auth_rrset* nsec = NULL;
if(!apex) {
struct ub_packed_rrset_key pk;
/* dnssec verify the NSEC */
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
- nsec, why_bogus, sigalg)) {
+ nsec, why_bogus, sigalg, reasonbuf, reasonlen)) {
*reason = "DNSSEC verify failed for NSEC RRset";
return 0;
}
}
/* dnssec verify the NSEC3 */
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, match,
- nsec3, why_bogus, sigalg)) {
+ nsec3, why_bogus, sigalg, reasonbuf, reasonlen)) {
*reason = "DNSSEC verify failed for NSEC3 RRset";
return 0;
}
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* dnskey, struct auth_data* apex,
struct auth_rrset* zonemd_rrset, char** reason, char** why_bogus,
- uint8_t* sigalg)
+ uint8_t* sigalg, char* reasonbuf, size_t reasonlen)
{
struct auth_rrset* soa;
if(!apex) {
return 0;
}
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex, soa,
- why_bogus, sigalg)) {
+ why_bogus, sigalg, reasonbuf, reasonlen)) {
*reason = "DNSSEC verify failed for SOA RRset";
return 0;
}
if(!zonemd_dnssec_verify_rrset(z, env, mods, dnskey, apex,
- zonemd_rrset, why_bogus, sigalg)) {
+ zonemd_rrset, why_bogus, sigalg, reasonbuf, reasonlen)) {
*reason = "DNSSEC verify failed for ZONEMD RRset";
return 0;
}
struct module_stack* mods, struct ub_packed_rrset_key* dnskey,
int is_insecure, char** result, uint8_t* sigalg)
{
+ char reasonbuf[256];
char* reason = NULL, *why_bogus = NULL;
struct auth_data* apex = NULL;
struct auth_rrset* zonemd_rrset = NULL;
} else if(!zonemd_rrset && dnskey && !is_insecure) {
/* fetch, DNSSEC verify, and check NSEC/NSEC3 */
if(!zonemd_check_dnssec_absence(z, env, mods, dnskey, apex,
- &reason, &why_bogus, sigalg)) {
+ &reason, &why_bogus, sigalg, reasonbuf,
+ sizeof(reasonbuf))) {
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
return;
}
} else if(zonemd_rrset && dnskey && !is_insecure) {
/* check DNSSEC verify of SOA and ZONEMD */
if(!zonemd_check_dnssec_soazonemd(z, env, mods, dnskey, apex,
- zonemd_rrset, &reason, &why_bogus, sigalg)) {
+ zonemd_rrset, &reason, &why_bogus, sigalg, reasonbuf,
+ sizeof(reasonbuf))) {
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
return;
}
* @param why_bogus: if the routine fails, returns the failure reason.
* @param keystorage: where to store the ub_packed_rrset_key that is created
* on success. A pointer to it is returned on success.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return the dnskey RRset, reference to zone data and keystorage, or
* NULL on failure.
*/
zonemd_get_dnskey_from_anchor(struct auth_zone* z, struct module_env* env,
struct module_stack* mods, struct trust_anchor* anchor,
int* is_insecure, char** why_bogus,
- struct ub_packed_rrset_key* keystorage)
+ struct ub_packed_rrset_key* keystorage, char* reasonbuf,
+ size_t reasonlen)
{
struct auth_data* apex;
struct auth_rrset* dnskey_rrset;
auth_zone_log(z->name, VERB_QUERY,
"zonemd: verify DNSKEY RRset with trust anchor");
sec = val_verify_DNSKEY_with_TA(env, ve, keystorage, anchor->ds_rrset,
- anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL);
+ anchor->dnskey_rrset, NULL, why_bogus, NULL, NULL, reasonbuf,
+ reasonlen);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
/* success */
auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
struct module_env* env, struct module_stack* mods,
struct ub_packed_rrset_key* ds, int* is_insecure, char** why_bogus,
- struct ub_packed_rrset_key* keystorage, uint8_t* sigalg)
+ struct ub_packed_rrset_key* keystorage, uint8_t* sigalg,
+ char* reasonbuf, size_t reasonlen)
{
struct auth_data* apex;
struct auth_rrset* dnskey_rrset;
keystorage->rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
- why_bogus, NULL, NULL);
+ why_bogus, NULL, NULL, reasonbuf, reasonlen);
regional_free_all(env->scratch);
if(sec == sec_status_secure) {
/* success */
{
struct auth_zone* z = (struct auth_zone*)arg;
struct module_env* env;
+ char reasonbuf[256];
char* reason = NULL, *ds_bogus = NULL, *typestr="DNSKEY";
struct ub_packed_rrset_key* dnskey = NULL, *ds = NULL;
int is_insecure = 0, downprot;
if(!reason && !is_insecure && !dnskey && ds) {
dnskey = auth_zone_verify_zonemd_key_with_ds(z, env,
&env->mesh->mods, ds, &is_insecure, &ds_bogus,
- &keystorage, downprot?sigalg:NULL);
+ &keystorage, downprot?sigalg:NULL, reasonbuf,
+ sizeof(reasonbuf));
if(!dnskey && !is_insecure && !reason)
reason = "DNSKEY verify with DS failed";
}
if(reason) {
auth_zone_zonemd_fail(z, env, reason, ds_bogus, NULL);
lock_rw_unlock(&z->lock);
+ regional_free_all(env->scratch);
return;
}
void auth_zone_verify_zonemd(struct auth_zone* z, struct module_env* env,
struct module_stack* mods, char** result, int offline, int only_online)
{
+ char reasonbuf[256];
char* reason = NULL, *why_bogus = NULL;
struct trust_anchor* anchor = NULL;
struct ub_packed_rrset_key* dnskey = NULL;
}
/* equal to trustanchor, no need for online lookups */
dnskey = zonemd_get_dnskey_from_anchor(z, env, mods, anchor,
- &is_insecure, &why_bogus, &keystorage);
+ &is_insecure, &why_bogus, &keystorage, reasonbuf,
+ sizeof(reasonbuf));
lock_basic_unlock(&anchor->lock);
if(!dnskey && !reason && !is_insecure) {
reason = "verify DNSKEY RRset with trust anchor failed";
if(reason) {
auth_zone_zonemd_fail(z, env, reason, why_bogus, result);
+ regional_free_all(env->scratch);
return;
}
struct ub_packed_rrset_key* ck;
lock_rw_rdlock(&rep->ref[i].key->entry.lock);
/* if deleted rrset, do not copy it */
- if(rep->ref[i].key->id == 0)
+ if(rep->ref[i].key->id == 0 ||
+ rep->ref[i].id != rep->ref[i].key->id)
ck = NULL;
else ck = packed_rrset_copy_region(
rep->ref[i].key, region, now);
/* no break: also copy key item */
/* the line below is matched by gcc regex and silences
* the fallthrough warning */
+ ATTR_FALLTHROUGH
/* fallthrough */
case 1: /* ref updated, item inserted */
rep->rrsets[i] = rep->ref[i].key;
- }
- /* if ref was updated make sure the message ttl is updated to
- * the minimum of the current rrsets. */
- ttl = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)->ttl;
+ /* ref was updated; make sure the message ttl is
+ * updated to the minimum of the current rrsets. */
+ lock_rw_rdlock(&rep->ref[i].key->entry.lock);
+ /* if deleted, skip ttl update. */
+ if(rep->ref[i].key->id != 0 &&
+ rep->ref[i].id == rep->ref[i].key->id) {
+ ttl = ((struct packed_rrset_data*)
+ rep->rrsets[i]->entry.data)->ttl;
if(ttl < min_ttl) min_ttl = ttl;
+ }
+ lock_rw_unlock(&rep->ref[i].key->entry.lock);
+ }
}
if(min_ttl < rep->ttl) {
rep->ttl = min_ttl;
* not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
+ /* Because recursion for lookup uses BIT_CD, check
+ * for that so it stops the recursion lookup, if a
+ * negative answer is cached. Because the cache uses
+ * the CD flag for type AAAA. */
+ if(!neg)
+ neg = msg_cache_lookup(env, ns->name, ns->namelen,
+ LDNS_RR_TYPE_AAAA, qclass, BIT_CD, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
* not use dns64 translation */
neg = msg_cache_lookup(env, ns->name, ns->namelen,
LDNS_RR_TYPE_AAAA, qclass, 0, now, 0);
+ /* Because recursion for lookup uses BIT_CD, check
+ * for that so it stops the recursion lookup, if a
+ * negative answer is cached. Because the cache uses
+ * the CD flag for type AAAA. */
+ if(!neg)
+ neg = msg_cache_lookup(env, ns->name, ns->namelen,
+ LDNS_RR_TYPE_AAAA, qclass, BIT_CD, now, 0);
if(neg) {
delegpt_add_neg_msg(dp, neg);
lock_rw_unlock(&neg->entry.lock);
* can do this number of packets (until those all timeout too) */
#define TIMEOUT_COUNT_MAX 3
+/** Minus 1000 because that is outside of the RTTBAND, so
+ * blacklisted servers stay blacklisted if this is chosen.
+ * If USEFUL_SERVER_TOP_TIMEOUT is below 1000 (configured via RTT_MAX_TIMEOUT,
+ * infra-cache-max-rtt) change it to just above the RTT_BAND. */
+#define STILL_USEFUL_TIMEOUT ( \
+ USEFUL_SERVER_TOP_TIMEOUT < 1000 || \
+ USEFUL_SERVER_TOP_TIMEOUT - 1000 <= RTT_BAND \
+ ?RTT_BAND + 1 \
+ :USEFUL_SERVER_TOP_TIMEOUT - 1000)
+
/** ratelimit value for delegation point */
int infra_dp_ratelimit = 0;
return NULL;
}
infra_ip_ratelimit = cfg->ip_ratelimit;
+ infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie;
infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
&ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL);
infra->infra_keep_probing = cfg->infra_keep_probing;
infra_dp_ratelimit = cfg->ratelimit;
infra_ip_ratelimit = cfg->ip_ratelimit;
+ infra_ip_ratelimit_cookie = cfg->ip_ratelimit_cookie;
maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
sizeof(struct infra_data)+INFRA_BYTES_NAME);
/* divide cachesize by slabs and multiply by slabs, because if the
if(data->rtt.rto >= RTT_MAX_TIMEOUT)
/* do not disqualify this server altogether, it is better
* than nothing */
- data->rtt.rto = RTT_MAX_TIMEOUT-1000;
+ data->rtt.rto = STILL_USEFUL_TIMEOUT;
lock_rw_unlock(&e->lock);
}
&& infra->infra_keep_probing) {
/* single probe, keep probing */
if(*rtt >= USEFUL_SERVER_TOP_TIMEOUT)
- *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ *rtt = STILL_USEFUL_TIMEOUT;
} else if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay
&& rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) {
/* single probe for this domain, and we are not probing */
if(qtype == LDNS_RR_TYPE_A) {
if(host->timeout_A >= TIMEOUT_COUNT_MAX)
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
- else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ else *rtt = STILL_USEFUL_TIMEOUT;
} else if(qtype == LDNS_RR_TYPE_AAAA) {
if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX)
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
- else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ else *rtt = STILL_USEFUL_TIMEOUT;
} else {
if(host->timeout_other >= TIMEOUT_COUNT_MAX)
*rtt = USEFUL_SERVER_TOP_TIMEOUT;
- else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ else *rtt = STILL_USEFUL_TIMEOUT;
}
}
/* expired entry */
if(timenow > host->ttl) {
-
/* see if this can be a re-probe of an unresponsive server */
- /* minus 1000 because that is outside of the RTTBAND, so
- * blacklisted servers stay blacklisted if this is chosen */
if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
lock_rw_unlock(&e->lock);
- *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
+ *rtt = STILL_USEFUL_TIMEOUT;
*lame = 0;
*dnsseclame = 0;
*reclame = 0;
struct config_file* cfg);
/**
- * Plain find infra data function (used by the the other functions)
+ * Plain find infra data function (used by the other functions)
* @param infra: infrastructure cache.
* @param addr: host address.
* @param addrlen: length of addr.
int* reuseport, int transparent, int mss, int nodelay, int freebind,
int use_systemd, int dscp)
{
- int s;
+ int s = -1;
char* err;
#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined(SO_BINDANY)
int on = 1;
}
/** enter a new zone */
-static struct local_zone*
+struct local_zone*
lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
uint16_t dclass)
{
return 1;
}
-/** setup parent pointers, so that a lookup can be done for closest match */
-static void
-init_parents(struct local_zones* zones)
+/* return closest parent in the tree, NULL if none */
+static struct local_zone* find_closest_parent(struct local_zone* curr,
+ struct local_zone* prev)
{
- struct local_zone* node, *prev = NULL, *p;
+ struct local_zone* p;
int m;
- lock_rw_wrlock(&zones->lock);
- RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
- lock_rw_wrlock(&node->lock);
- node->parent = NULL;
- if(!prev || prev->dclass != node->dclass) {
- prev = node;
- lock_rw_unlock(&node->lock);
- continue;
- }
- (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
- node->namelabs, &m); /* we know prev is smaller */
+ if(!prev || prev->dclass != curr->dclass) return NULL;
+ (void)dname_lab_cmp(prev->name, prev->namelabs, curr->name,
+ curr->namelabs, &m); /* we know prev is smaller */
/* sort order like: . com. bla.com. zwb.com. net. */
/* find the previous, or parent-parent-parent */
- for(p = prev; p; p = p->parent)
+ for(p = prev; p; p = p->parent) {
/* looking for name with few labels, a parent */
if(p->namelabs <= m) {
/* ==: since prev matched m, this is closest*/
/* <: prev matches more, but is not a parent,
* this one is a (grand)parent */
- node->parent = p;
- break;
+ return p;
+ }
+ }
+ return NULL;
}
- prev = node;
+/** setup parent pointers, so that a lookup can be done for closest match */
+void
+lz_init_parents(struct local_zones* zones)
+{
+ struct local_zone* node, *prev = NULL;
+ lock_rw_wrlock(&zones->lock);
+ RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
+ lock_rw_wrlock(&node->lock);
+ node->parent = find_closest_parent(node, prev);
+ prev = node;
if(node->override_tree)
addr_tree_init_parents(node->override_tree);
lock_rw_unlock(&node->lock);
int nmlabs = 0;
int match = 0; /* number of labels match count */
- init_parents(zones); /* to enable local_zones_lookup() */
+ lz_init_parents(zones); /* to enable local_zones_lookup() */
for(p = cfg->local_data; p; p = p->next) {
uint8_t* rr_name;
uint16_t rr_class, rr_type;
}
/* setup parent ptrs for lookup during data entry */
- init_parents(zones);
+ lz_init_parents(zones);
/* insert local zone tags */
if(!lz_enter_zone_tags(zones, cfg)) {
return 0;
uint8_t* name, size_t len, int labs, uint16_t dclass,
enum localzone_type tp)
{
+ int exact;
/* create */
+ struct local_zone *prev;
struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
if(!z) {
free(name);
lock_rw_wrlock(&z->lock);
/* find the closest parent */
- z->parent = local_zones_find(zones, name, len, labs, dclass);
+ prev = local_zones_find_le(zones, name, len, labs, dclass, &exact);
+ if(!exact)
+ z->parent = find_closest_parent(z, prev);
/* insert into the tree */
- if(!rbtree_insert(&zones->ztree, &z->node)) {
+ if(exact||!rbtree_insert(&zones->ztree, &z->node)) {
/* duplicate entry! */
lock_rw_unlock(&z->lock);
local_zone_delete(z);
*/
struct local_data*
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs);
+
+/** Enter a new zone; returns with WRlock
+ * Made public for unit testing
+ * @param zones: the local zones tree
+ * @param name: name of the zone
+ * @param type: type of the zone
+ * @param dclass: class of the zone
+ * @return local_zone (or duplicate), NULL on parse and malloc failures
+ */
+struct local_zone*
+lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
+ uint16_t dclass);
+
+/** Setup parent pointers, so that a lookup can be done for closest match
+ * Made public for unit testing
+ * @param zones: the local zones tree
+ */
+void
+lz_init_parents(struct local_zones* zones);
#endif /* SERVICES_LOCALZONE_H */
int timeout = mesh->env->cfg->serve_expired?
mesh->env->cfg->serve_expired_client_timeout:0;
struct sldns_buffer* r_buffer = rep->c->buffer;
+ uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
if(rep->c->tcp_req_info) {
r_buffer = rep->c->tcp_req_info->spool_buffer;
}
return;
}
if(!unique)
- s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_area_find(mesh, cinfo, qinfo, mesh_flags, 0, 0);
/* does this create a new reply state? */
if(!s || s->list_select == mesh_no_list) {
if(!mesh_make_new_space(mesh, rep->c->buffer)) {
struct rbnode_type* n;
#endif
s = mesh_state_create(mesh->env, qinfo, cinfo,
- qflags&(BIT_RD|BIT_CD), 0, 0);
+ mesh_flags, 0, 0);
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
+ if(rep->c->use_h2)
+ http2_stream_remove_mesh_state(rep->c->h2_stream);
comm_point_send_reply(rep);
if(added)
mesh_state_delete(&s->s);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
+ uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
if(!unique)
- s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0);
/* there are no limits on the number of callbacks */
struct rbnode_type* n;
#endif
s = mesh_state_create(mesh->env, qinfo, NULL,
- qflags&(BIT_RD|BIT_CD), 0, 0);
+ mesh_flags, 0, 0);
if(!s) {
return 0;
}
struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
int rpz_passthru)
{
+ /* Explicitly set the BIT_RD regardless of the client's flags. This is
+ * for a prefetch query (no client attached) but it needs to be treated
+ * as a recursion query. */
+ uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD);
struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
- qflags&(BIT_RD|BIT_CD), 0, 0);
+ mesh_flags, 0, 0);
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
return;
}
- s = mesh_state_create(mesh->env, qinfo, NULL,
- qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0);
if(!s) {
log_err("prefetch mesh_state_create: out of memory");
return;
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
+ /* Explicitly set the BIT_RD regardless of the client's flags. This is
+ * for a prefetch query (no client attached) but it needs to be treated
+ * as a recursion query. */
+ uint16_t mesh_flags = BIT_RD|(qflags&BIT_CD);
if(!mesh_make_new_space(mesh, NULL)) {
verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
mesh->stats_dropped ++;
return;
}
- s = mesh_state_create(mesh->env, qinfo, NULL,
- qflags&(BIT_RD|BIT_CD), 0, 0);
+ s = mesh_state_create(mesh->env, qinfo, NULL, mesh_flags, 0, 0);
if(!s) {
log_err("prefetch_subnet mesh_state_create: out of memory");
return;
for(; rep; rep=rep->next) {
infra_wait_limit_dec(mesh->env->infra_cache,
&rep->query_reply, mesh->env->cfg);
+ if(rep->query_reply.c->use_h2)
+ http2_stream_remove_mesh_state(rep->h2_stream);
comm_point_drop_reply(&rep->query_reply);
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--;
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
+ if(r->query_reply.c->use_h2)
+ http2_stream_remove_mesh_state(r->h2_stream);
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
mstate->s.env->mesh->stats_dropped++;
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
+ if(r->query_reply.c->use_h2) {
+ http2_stream_remove_mesh_state(r->h2_stream);
+ }
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
} else {
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
r_buffer = NULL;
}
+ /* mesh_send_reply removed mesh state from
+ * http2_stream. */
prev = r;
prev_buffer = r_buffer;
}
return 0;
if(rep->c->use_h2)
r->h2_stream = rep->c->h2_stream;
+ else r->h2_stream = NULL;
/* Data related to local alias stored in 'qinfo' (if any) is ephemeral
* and can be different for different original queries (even if the
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
+ if(r->query_reply.c->use_h2)
+ http2_stream_remove_mesh_state(r->h2_stream);
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
mstate->s.env->mesh->stats_dropped++;
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);
+ /* mesh_send_reply removed mesh state from http2_stream. */
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
prev = r;
stack->mod = NULL;
}
+void
+modstack_free(struct module_stack* stack)
+{
+ if(!stack)
+ return;
+ stack->num = 0;
+ free(stack->mod);
+ stack->mod = NULL;
+}
+
int
modstack_config(struct module_stack* stack, const char* module_conf)
{
}
int
-modstack_setup(struct module_stack* stack, const char* module_conf,
+modstack_call_startup(struct module_stack* stack, const char* module_conf,
struct module_env* env)
{
int i;
if(stack->num != 0)
- modstack_desetup(stack, env);
+ fatal_exit("unexpected already initialised modules");
/* fixed setup of the modules */
if(!modstack_config(stack, module_conf)) {
return 0;
}
+ for(i=0; i<stack->num; i++) {
+ if(stack->mod[i]->startup == NULL)
+ continue;
+ verbose(VERB_OPS, "startup module %d: %s",
+ i, stack->mod[i]->name);
+ fptr_ok(fptr_whitelist_mod_startup(stack->mod[i]->startup));
+ if(!(*stack->mod[i]->startup)(env, i)) {
+ log_err("module startup for module %s failed",
+ stack->mod[i]->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int
+modstack_call_init(struct module_stack* stack, const char* module_conf,
+ struct module_env* env)
+{
+ int i, changed = 0;
env->need_to_validate = 0; /* set by module init below */
+ for(i=0; i<stack->num; i++) {
+ while(*module_conf && isspace(*module_conf))
+ module_conf++;
+ if(strncmp(stack->mod[i]->name, module_conf,
+ strlen(stack->mod[i]->name))) {
+ if(stack->mod[i]->startup || stack->mod[i]->destartup) {
+ log_err("changed module ordering during reload not supported, for module that needs startup");
+ return 0;
+ } else {
+ changed = 1;
+ }
+ }
+ module_conf += strlen(stack->mod[i]->name);
+ }
+ if(changed) {
+ modstack_free(stack);
+ if(!modstack_config(stack, module_conf)) {
+ return 0;
+ }
+ }
+
for(i=0; i<stack->num; i++) {
verbose(VERB_OPS, "init module %d: %s",
i, stack->mod[i]->name);
}
void
-modstack_desetup(struct module_stack* stack, struct module_env* env)
+modstack_call_deinit(struct module_stack* stack, struct module_env* env)
{
int i;
for(i=0; i<stack->num; i++) {
fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit));
(*stack->mod[i]->deinit)(env, i);
}
- stack->num = 0;
- free(stack->mod);
- stack->mod = NULL;
+}
+
+void
+modstack_call_destartup(struct module_stack* stack, struct module_env* env)
+{
+ int i;
+ for(i=0; i<stack->num; i++) {
+ if(stack->mod[i]->destartup == NULL)
+ continue;
+ fptr_ok(fptr_whitelist_mod_destartup(stack->mod[i]->destartup));
+ (*stack->mod[i]->destartup)(env, i);
+ }
}
int
*/
void modstack_init(struct module_stack* stack);
+/**
+ * Free the stack of modules
+ * @param stack: stack that frees up memory.
+ */
+void modstack_free(struct module_stack* stack);
+
+/**
+ * Initialises modules and assignes ids. Calls module_startup().
+ * @param stack: Expected empty, filled according to module_conf
+ * @param module_conf: string what modules to initialize
+ * @param env: module environment which is inited by the modules.
+ * environment should have a superalloc, cfg,
+ * @return on false a module init failed.
+ */
+int modstack_call_startup(struct module_stack* stack, const char* module_conf,
+ struct module_env* env);
+
/**
* Read config file module settings and set up the modfunc block
* @param stack: the stack of modules (empty before call).
const char** module_list_avail(void);
/**
- * Setup modules. Assigns ids and calls module_init.
- * @param stack: if not empty beforehand, it will be desetup()ed.
- * It is then modstack_configged().
- * @param module_conf: string what modules to insert.
+ * Init modules. Calls module_init().
+ * @param stack: It is modstack_setupped().
+ * @param module_conf: module ordering to check against the ordering in stack.
+ * fails on changed ordering.
* @param env: module environment which is inited by the modules.
* environment should have a superalloc, cfg,
* env.need_to_validate is set by the modules.
* @return on false a module init failed.
*/
-int modstack_setup(struct module_stack* stack, const char* module_conf,
+int modstack_call_init(struct module_stack* stack, const char* module_conf,
struct module_env* env);
/**
- * Desetup the modules, deinit, delete.
+ * Deinit the modules.
* @param stack: made empty.
* @param env: module env for module deinit() calls.
*/
-void modstack_desetup(struct module_stack* stack, struct module_env* env);
+void modstack_call_deinit(struct module_stack* stack, struct module_env* env);
+
+/**
+ * Destartup the modules, close, delete.
+ * @param stack: made empty.
+ * @param env: module env for module destartup() calls.
+ */
+void modstack_call_destartup(struct module_stack* stack, struct module_env* env);
/**
* Find index of module by name.
}
/** return true is UDP connect error needs to be logged */
-static int udp_connect_needs_log(int err)
+static int udp_connect_needs_log(int err, struct sockaddr_storage* addr,
+ socklen_t addrlen)
{
switch(err) {
case ECONNREFUSED:
if(verbosity >= VERB_ALGO)
return 1;
return 0;
+ case EINVAL:
+ /* Stop 'Invalid argument for fe80::/10' addresses appearing
+ * in the logs, at low verbosity. They cannot be sent to. */
+ if(addr_is_ip6linklocal(addr, addrlen)) {
+ if(verbosity >= VERB_ALGO)
+ return 1;
+ return 0;
+ }
+ break;
default:
break;
}
/* connect() to the destination */
if(connect(fd, (struct sockaddr*)&pend->addr,
pend->addrlen) < 0) {
- if(udp_connect_needs_log(errno)) {
+ if(udp_connect_needs_log(errno,
+ &pend->addr, pend->addrlen)) {
log_err_addr("udp connect failed",
strerror(errno), &pend->addr,
pend->addrlen);
timenow = *env->now;
if(!infra_ratelimit_inc(env->infra_cache, zone,
zonelen, timenow, env->cfg->ratelimit_backoff,
- &qstate->qinfo, qstate->reply)) {
+ &qstate->qinfo,
+ qstate->mesh_info->reply_list
+ ?&qstate->mesh_info->reply_list->query_reply
+ :NULL)) {
/* Can we pass through with slip factor? */
if(env->cfg->ratelimit_factor == 0 ||
ub_random_max(env->rnd,
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimiter
- * \param[in] data_limit maximum size the the data buffer
+ * \param[in] data_limit maximum size the data buffer
* \return the number of character read
*/
ssize_t sldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimiter
- * \param[in] data_limit maximum size the the data buffer
+ * \param[in] data_limit maximum size the data buffer
* \param[in] line_nr pointer to an integer containing the current line number (for
debugging purposes)
* \return the number of character read
* \param[in] k_del keyword delimiter
* \param[out] data the data found
* \param[in] d_del the data delimiter
- * \param[in] data_limit maximum size the the data buffer
+ * \param[in] data_limit maximum size the data buffer
* \return the number of character read
*/
ssize_t sldns_bget_keyword_data(struct sldns_buffer *b, const char *keyword, const char *k_del, char *data, const char *d_del, size_t data_limit);
/* ........ ........ ....4444 4....... ........ */
c = src[3] >> 7 ;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 3: dst[4] = b32[(src[2] & 0x0f) << 1 | c];
/* ........ .......3 3333.... ........ ........ */
c = src[2] >> 4 ;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 2: dst[3] = b32[(src[1] & 0x01) << 4 | c];
/* .....111 11...... ........ ........ ........ */
c = src[1] >> 6 ;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 1: dst[1] = b32[(src[0] & 0x07) << 2 | c];
switch (src_sz) {
case 1: dst[2] = '=';
dst[3] = '=';
+ ATTR_FALLTHROUGH
/* fallthrough */
case 2: dst[4] = '=';
+ ATTR_FALLTHROUGH
/* fallthrough */
case 3: dst[5] = '=';
dst[6] = '=';
+ ATTR_FALLTHROUGH
/* fallthrough */
case 4: dst[7] = '=';
}
/* ........ ........ ........ .55555.. ........ */
/* ........ ........ ....4444 4....... ........ */
dst[3] = buf[4] << 7 | buf[5] << 2 | buf[6] >> 3;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 5: /* ........ ........ ....4444 4....... ........ */
/* ........ .......3 3333.... ........ ........ */
dst[2] = buf[3] << 4 | buf[4] >> 1;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 4: /* ........ .......3 3333.... ........ ........ */
/* ........ ..22222. ........ ........ ........ */
/* .....111 11...... ........ ........ ........ */
dst[1] = buf[1] << 6 | buf[2] << 1 | buf[3] >> 4;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 2: /* .....111 11...... ........ ........ ........ */
LDNS_EDE_NO_REACHABLE_AUTHORITY = 22,
LDNS_EDE_NETWORK_ERROR = 23,
LDNS_EDE_INVALID_DATA = 24,
+ LDNS_EDE_SIGNATURE_EXPIRED_BEFORE_VALID = 25,
+ LDNS_EDE_TOO_EARLY = 26,
+ LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS = 27,
+ LDNS_EDE_BADPROXYPOLICY = 28,
+ LDNS_EDE_SYNTHESIZED = 29
};
typedef enum sldns_enum_ede_code sldns_ede_code;
{ LDNS_EDE_NO_REACHABLE_AUTHORITY, "No Reachable Authority" },
{ LDNS_EDE_NETWORK_ERROR, "Network Error" },
{ LDNS_EDE_INVALID_DATA, "Invalid Data" },
+ { LDNS_EDE_SIGNATURE_EXPIRED_BEFORE_VALID, "Signature Expired Before Valid" },
+ { LDNS_EDE_TOO_EARLY, "Non-Replayable Transactions Received in 0-RTT Data" },
+ { LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS, "Unsupported NSEC3 Iterations Value" },
+ { LDNS_EDE_BADPROXYPOLICY, "Unable to Conform to Policy" },
+ { LDNS_EDE_SYNTHESIZED, "Synthesized Answer" },
{ 0, NULL}
};
sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data;
r = sldns_wire2str_svcparam_ech2str(s, slen, data_len, *d);
break;
case SVCB_KEY_DOHPATH:
+ ATTR_FALLTHROUGH
/* fallthrough */
default:
r = sldns_str_print(s, slen, "=\"");
#define HTTPS_PORT 443
#ifdef USE_WINSOCK
-/* sneakily reuse the the wsa_strerror function, on windows */
+/* sneakily reuse the wsa_strerror function, on windows */
char* wsa_strerror(int err);
#endif
/* The anchors must start on a new line with ". IN DS and end with \n"[;]
* because the makedist script greps on the source here */
/* anchor 20326 is from 2017 */
-". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n";
+". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n"
+ /* anchor 38696 is from 2024 */
+". IN DS 38696 8 2 683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16\n";
/** verbosity for this application */
static int verb = 0;
}
/* wants to be called again */
}
+#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
+ x = SSL_get1_peer_certificate(ssl);
+#else
x = SSL_get_peer_certificate(ssl);
+#endif
if(!x) {
if(verb) printf("Server presented no peer certificate\n");
SSL_free(ssl);
fatal_exit("out of memory");
if(!edns_known_options_init(&env))
fatal_exit("out of memory");
- if(!(*fb->init)(&env, 0)) {
- fatal_exit("bad config for %s module", fb->name);
- }
+ if(fb->startup && !(*fb->startup)(&env, 0))
+ fatal_exit("bad config during startup for %s module", fb->name);
+ if(!(*fb->init)(&env, 0))
+ fatal_exit("bad config during init for %s module", fb->name);
(*fb->deinit)(&env, 0);
+ if(fb->destartup)
+ (*fb->destartup)(&env, 0);
sldns_buffer_free(env.scratch_buffer);
regional_destroy(env.scratch);
edns_known_options_delete(&env);
done
shift $((OPTIND - 1))
+if ! openssl >/dev/null 2>&1; then
+ echo "$0 requires openssl to be installed for keys/certificates generation." >&2
+ exit 1
+fi
echo "setup in directory $DESTDIR"
cd "$DESTDIR"
printf(" local_data <RR data...> add local data, for example\n");
printf(" local_data www.example.com A 192.0.2.1\n");
printf(" local_data_remove <name> remove local RR data from name\n");
- printf(" local_zones, local_zones_remove, local_datas, local_datas_remove\n");
- printf(" same, but read list from stdin\n");
+ printf(" local_zones,\n");
+ printf(" local_zones_remove,\n");
+ printf(" local_datas,\n");
+ printf(" local_datas_remove same, but read list from stdin\n");
printf(" (one entry per line).\n");
printf(" dump_cache print cache to stdout\n");
+ printf(" (not supported in remote unbounds in\n");
+ printf(" multi-process operation)\n");
printf(" load_cache load cache from stdin\n");
+ printf(" (not supported in remote unbounds in\n");
+ printf(" multi-process operation)\n");
printf(" lookup <name> print nameservers for name\n");
- printf(" flush <name> flushes common types for name from cache\n");
+ printf(" flush [+c] <name> flushes common types for name from cache\n");
printf(" types: A, AAAA, MX, PTR, NS,\n");
printf(" SOA, CNAME, DNAME, SRV, NAPTR\n");
- printf(" flush_type <name> <type> flush name, type from cache\n");
- printf(" flush_zone <name> flush everything at or under name\n");
+ printf(" flush_type [+c] <name> <type> flush name, type from cache\n");
+ printf(" +c remove from cachedb too\n");
+ printf(" flush_zone [+c] <name> flush everything at or under name\n");
printf(" from rr and dnssec caches\n");
- printf(" flush_bogus flush all bogus data\n");
- printf(" flush_negative flush all negative data\n");
+ printf(" flush_bogus [+c] flush all bogus data\n");
+ printf(" flush_negative [+c] flush all negative data\n");
printf(" flush_stats flush statistics, make zero\n");
printf(" flush_requestlist drop queries that are worked on\n");
printf(" dump_requestlist show what is worked on by first thread\n");
printf(" rpz_enable zone Enable the RPZ zone if it had previously\n");
printf(" been disabled\n");
printf(" rpz_disable zone Disable the RPZ zone\n");
+ printf(" add_cookie_secret <secret> add (or replace) a new cookie secret <secret>\n");
+ printf(" drop_cookie_secret drop a staging cookie secret\n");
+ printf(" activate_cookie_secret make a staging cookie secret active\n");
+ printf(" print_cookie_secrets show all cookie secrets with their status\n");
printf("Version %s\n", PACKAGE_VERSION);
printf("BSD licensed, see LICENSE in source package for details.\n");
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
/* check authenticity of server */
if(SSL_get_verify_result(ssl) != X509_V_OK)
ssl_err("SSL verification failed");
+#ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
+ x = SSL_get1_peer_certificate(ssl);
+#else
x = SSL_get_peer_certificate(ssl);
+#endif
if(!x)
ssl_err("Server presented no peer certificate");
X509_free(x);
struct query_info* qinfo)
{
enum sec_status sec;
+ char reasonbuf[256];
char* reason = NULL;
uint8_t sigalg[ALGO_NEEDS_MAX+1];
int verified = 0;
}
setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */
/* ok to give null as qstate here, won't be used for answer section. */
- sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason, NULL,
- LDNS_SECTION_ANSWER, NULL, &verified);
+ sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason,
+ NULL, LDNS_SECTION_ANSWER, NULL, &verified, reasonbuf,
+ sizeof(reasonbuf));
if(vsig) {
printf("verify outcome is: %s %s\n", sec_status_to_string(sec),
reason?reason:"");
memcpy(res+8, &mem_special, sizeof(mem_special));
return res+16;
}
+/** strdup with stats */
+char *unbound_stat_strdup(const char* s)
+{
+ size_t len;
+ char* res;
+ if(!s) return NULL;
+ len = strlen(s);
+ res = unbound_stat_malloc(len+1);
+ if(!res) return NULL;
+ memmove(res, s, len+1);
+ return res;
+}
/** log to file where alloc was done */
void *unbound_stat_malloc_log(size_t size, const char* file, int line,
return unbound_stat_realloc(ptr, size);
}
+/** log to file where strdup was done */
+char *unbound_stat_strdup_log(const char *s, const char* file, int line,
+ const char* func)
+{
+ log_info("%s:%d %s strdup size %u", file, line, func,
+ (s?(unsigned)strlen(s)+1:0));
+ return unbound_stat_strdup(s);
+}
+
#endif /* UNBOUND_ALLOC_STATS */
#ifdef UNBOUND_ALLOC_LITE
#undef malloc
#include "config.h"
#include <ctype.h>
#include <stdarg.h>
+#include <errno.h>
#ifdef HAVE_TIME_H
#include <time.h>
#endif
memset(cfg->cookie_secret, 0, sizeof(cfg->cookie_secret));
cfg->cookie_secret_len = 16;
init_cookie_secret(cfg->cookie_secret, cfg->cookie_secret_len);
+ cfg->cookie_secret_file = NULL;
#ifdef USE_CACHEDB
if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
else S_YNO("dnstap-send-version:", dnstap_send_version)
else S_STR("dnstap-identity:", dnstap_identity)
else S_STR("dnstap-version:", dnstap_version)
+ else S_NUMBER_OR_ZERO("dnstap-sample-rate:", dnstap_sample_rate)
else S_YNO("dnstap-log-resolver-query-messages:",
dnstap_log_resolver_query_messages)
else S_YNO("dnstap-log-resolver-response-messages:",
{ IS_NUMBER_OR_ZERO; cfg->ipsecmod_max_ttl = atoi(val); }
else S_YNO("ipsecmod-strict:", ipsecmod_strict)
#endif
+ else S_YNO("answer-cookie:", do_answer_cookie)
+ else S_STR("cookie-secret-file:", cookie_secret_file)
#ifdef USE_CACHEDB
else S_YNO("cachedb-no-store:", cachedb_no_store)
else S_YNO("cachedb-check-when-serve-expired:", cachedb_check_when_serve_expired)
else O_YNO(opt, "dnstap-send-version", dnstap_send_version)
else O_STR(opt, "dnstap-identity", dnstap_identity)
else O_STR(opt, "dnstap-version", dnstap_version)
+ else O_UNS(opt, "dnstap-sample-rate", dnstap_sample_rate)
else O_YNO(opt, "dnstap-log-resolver-query-messages",
dnstap_log_resolver_query_messages)
else O_YNO(opt, "dnstap-log-resolver-response-messages",
else O_LST(opt, "ipsecmod-whitelist", ipsecmod_whitelist)
else O_YNO(opt, "ipsecmod-strict", ipsecmod_strict)
#endif
+ else O_YNO(opt, "answer-cookie", do_answer_cookie)
+ else O_STR(opt, "cookie-secret-file", cookie_secret_file)
#ifdef USE_CACHEDB
else O_STR(opt, "backend", cachedb_backend)
else O_STR(opt, "secret-seed", cachedb_secret)
free(cfg->ipsecmod_hook);
config_delstrlist(cfg->ipsecmod_whitelist);
#endif
+ free(cfg->cookie_secret_file);
#ifdef USE_CACHEDB
free(cfg->cachedb_backend);
free(cfg->cachedb_secret);
}
}
+static int
+extract_port_from_str(const char* str, int max_port) {
+ char* endptr;
+ long int value;
+ if (str == NULL || *str == '\0') {
+ log_err("str: '%s' is invalid", (str?str:"NULL"));
+ return -1;
+ }
+
+ value = strtol(str, &endptr, 10);
+ if ((endptr == str) || (*endptr != '\0')) {
+ log_err("cannot parse port number '%s'", str);
+ return -1;
+ }
+
+ if (errno == ERANGE) {
+ log_err("overflow occurred when parsing '%s'", str);
+ return -1;
+ }
+
+ if (value == 0 && strcmp(str, "0") != 0) {
+ log_err("cannot parse port number '%s'", str);
+ return -1;
+ }
+
+ if (value < 0 || value >= max_port) {
+ log_err(" '%s' is out of bounds [0, %d)", str, max_port);
+ return -1;
+ }
+
+ return (int)value;
+}
+
int
cfg_mark_ports(const char* str, int allow, int* avail, int num)
{
"options");
#endif
if(!mid) {
- int port = atoi(str);
+ int port = extract_port_from_str(str, num);
if(port < 0) {
- log_err("port number is negative: %d", port);
- return 0;
- }
- if(port == 0 && strcmp(str, "0") != 0) {
- log_err("cannot parse port number '%s'", str);
+ log_err("Failed to parse the port number");
return 0;
}
if(port < num)
avail[port] = (allow?port:0);
} else {
- int i, low, high = atoi(mid+1);
char buf[16];
+ int i, low;
+ int high = extract_port_from_str(mid+1, num);
if(high < 0) {
- log_err("port number is negative: %d", high);
- return 0;
- }
- if(high == 0 && strcmp(mid+1, "0") != 0) {
- log_err("cannot parse port number '%s'", mid+1);
+ log_err("Failed to parse the port number");
return 0;
}
+
if( (int)(mid-str)+1 >= (int)sizeof(buf) ) {
log_err("cannot parse port number '%s'", str);
return 0;
}
+
if(mid > str)
memcpy(buf, str, (size_t)(mid-str));
buf[mid-str] = 0;
- low = atoi(buf);
+ low = extract_port_from_str(buf, num);
if(low < 0) {
- log_err("port number is negative: %d", low);
+ log_err("Failed to parse the port number");
return 0;
}
- if(low == 0 && strcmp(buf, "0") != 0) {
- log_err("cannot parse port number '%s'", buf);
+
+ if (low > high) {
+ log_err("Low value is greater than high value");
return 0;
}
- if(high > num) {
- /* Stop very high values from taking a long time. */
- high = num;
- }
+
for(i=low; i<=high; i++) {
if(i < num)
avail[i] = (allow?i:0);
}
- return 1;
}
return 1;
}
char* dnstap_identity;
/** dnstap "version", package version is used if "". */
char* dnstap_version;
+ /** dnstap sample rate */
+ int dnstap_sample_rate;
/** true to log dnstap RESOLVER_QUERY message events */
int dnstap_log_resolver_query_messages;
uint8_t cookie_secret[40];
/** cookie secret length */
size_t cookie_secret_len;
+ /** path to cookie secret store */
+ char* cookie_secret_file;
/* ipset module */
#ifdef USE_IPSET
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
dnstap-log-forwarder-response-messages{COLON} {
YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
+dnstap-sample-rate { YDVAR(1, VAR_DNSTAP_SAMPLE_RATE) }
disable-dnssec-lame-check{COLON} { YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) }
ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) }
ip-ratelimit-cookie{COLON} { YDVAR(1, VAR_IP_RATELIMIT_COOKIE) }
tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
answer-cookie{COLON} { YDVAR(1, VAR_ANSWER_COOKIE ) }
cookie-secret{COLON} { YDVAR(1, VAR_COOKIE_SECRET) }
+cookie-secret-file{COLON} { YDVAR(1, VAR_COOKIE_SECRET_FILE) }
edns-client-string{COLON} { YDVAR(2, VAR_EDNS_CLIENT_STRING) }
edns-client-string-opcode{COLON} { YDVAR(1, VAR_EDNS_CLIENT_STRING_OPCODE) }
nsid{COLON} { YDVAR(1, VAR_NSID ) }
%token VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES
%token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES
%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
+%token VAR_DNSTAP_SAMPLE_RATE
%token VAR_RESPONSE_IP_TAG VAR_RESPONSE_IP VAR_RESPONSE_IP_DATA
%token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT
%token VAR_IP_DSCP
%token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO
%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE
%token VAR_LOG_DESTADDR VAR_CACHEDB_CHECK_WHEN_SERVE_EXPIRED
+%token VAR_COOKIE_SECRET_FILE
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_interface_automatic_ports | server_ede |
server_proxy_protocol_port | server_statistics_inhibit_zero |
server_harden_unknown_additional | server_disable_edns_do |
- server_log_destaddr
+ server_log_destaddr | server_cookie_secret_file
;
stubstart: VAR_STUB_ZONE
{
}
}
;
-contents_stub: contents_stub content_stub
- | ;
+contents_stub: content_stub contents_stub
+ |
+ {
+ /* stub end */
+ if(cfg_parser->cfg->stubs &&
+ !cfg_parser->cfg->stubs->name)
+ yyerror("stub-zone without name");
+ };
content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first |
stub_no_cache | stub_ssl_upstream | stub_tcp_upstream
;
}
}
;
-contents_forward: contents_forward content_forward
- | ;
+contents_forward: content_forward contents_forward
+ |
+ {
+ /* forward end */
+ if(cfg_parser->cfg->forwards &&
+ !cfg_parser->cfg->forwards->name)
+ yyerror("forward-zone without name");
+ };
content_forward: forward_name | forward_host | forward_addr | forward_first |
forward_no_cache | forward_ssl_upstream | forward_tcp_upstream
;
s = (struct config_view*)calloc(1, sizeof(struct config_view));
if(s) {
s->next = cfg_parser->cfg->views;
- if(s->next && !s->next->name)
- yyerror("view without name");
cfg_parser->cfg->views = s;
} else {
yyerror("out of memory");
}
}
;
-contents_view: contents_view content_view
- | ;
+contents_view: content_view contents_view
+ |
+ {
+ /* view end */
+ if(cfg_parser->cfg->views &&
+ !cfg_parser->cfg->views->name)
+ yyerror("view without name");
+ };
content_view: view_name | view_local_zone | view_local_data | view_first |
view_response_ip | view_response_ip_data | view_local_data_ptr
;
dt_dnstap_log_client_query_messages |
dt_dnstap_log_client_response_messages |
dt_dnstap_log_forwarder_query_messages |
- dt_dnstap_log_forwarder_response_messages
+ dt_dnstap_log_forwarder_response_messages |
+ dt_dnstap_sample_rate
;
dt_dnstap_enable: VAR_DNSTAP_ENABLE STRING_ARG
{
free($2);
}
;
+dt_dnstap_sample_rate: VAR_DNSTAP_SAMPLE_RATE STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_sample_rate:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else if(atoi($2) < 0)
+ yyerror("dnstap sample rate too small");
+ else cfg_parser->cfg->dnstap_sample_rate = atoi($2);
+ free($2);
+ }
+ ;
pythonstart: VAR_PYTHON
{
OUTYY(("\nP(python:)\n"));
free($2);
}
;
+server_cookie_secret_file: VAR_COOKIE_SECRET_FILE STRING_ARG
+ {
+ OUTYY(("P(cookie_secret_file:%s)\n", $2));
+ free(cfg_parser->cfg->cookie_secret_file);
+ cfg_parser->cfg->cookie_secret_file = $2;
+ }
+ ;
ipsetstart: VAR_IPSET
{
OUTYY(("\nP(ipset:)\n"));
int dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2);
/**
- * Counts labels. Tests is d1 is a subdomain of d2.
+ * Counts labels. Tests if d1 is a subdomain of d2.
* @param d1: domain name, uncompressed wireformat
* @param d2: domain name, uncompressed wireformat
* @return true if d1 is a subdomain of d2.
static int
parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len,
struct edns_data* edns, struct config_file* cfg, struct comm_point* c,
- struct comm_reply* repinfo, uint32_t now, struct regional* region)
+ struct comm_reply* repinfo, uint32_t now, struct regional* region,
+ struct cookie_secrets* cookie_secrets)
{
/* To respond with a Keepalive option, the client connection must have
* received one message with a TCP Keepalive EDNS option, and that
&((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16);
}
+ if(cfg->cookie_secret_file &&
+ cfg->cookie_secret_file[0]) {
+ /* Loop over the active and staging cookies. */
+ cookie_val_status =
+ cookie_secrets_server_validate(
+ rdata_ptr, opt_len, cookie_secrets,
+ cookie_is_v4, server_cookie, now);
+ } else {
+ /* Use the cookie option value to validate. */
cookie_val_status = edns_cookie_server_validate(
rdata_ptr, opt_len, cfg->cookie_secret,
cfg->cookie_secret_len, cookie_is_v4,
server_cookie, now);
+ }
+ if(cookie_val_status == COOKIE_STATUS_VALID_RENEW)
+ edns->cookie_valid = 1;
switch(cookie_val_status) {
case COOKIE_STATUS_VALID:
- case COOKIE_STATUS_VALID_RENEW:
edns->cookie_valid = 1;
/* Reuse cookie */
if(!edns_opt_list_append(
break;
case COOKIE_STATUS_CLIENT_ONLY:
edns->cookie_client = 1;
+ ATTR_FALLTHROUGH
/* fallthrough */
+ case COOKIE_STATUS_VALID_RENEW:
case COOKIE_STATUS_FUTURE:
case COOKIE_STATUS_EXPIRED:
case COOKIE_STATUS_INVALID:
default:
+ if(cfg->cookie_secret_file &&
+ cfg->cookie_secret_file[0]) {
+ if(!cookie_secrets)
+ break;
+ lock_basic_lock(&cookie_secrets->lock);
+ if(cookie_secrets->cookie_count < 1) {
+ lock_basic_unlock(&cookie_secrets->lock);
+ break;
+ }
+ edns_cookie_server_write(server_cookie,
+ cookie_secrets->cookie_secrets[0].cookie_secret,
+ cookie_is_v4, now);
+ lock_basic_unlock(&cookie_secrets->lock);
+ } else {
edns_cookie_server_write(server_cookie,
cfg->cookie_secret, cookie_is_v4, now);
+ }
if(!edns_opt_list_append(&edns->opt_list_out,
LDNS_EDNS_COOKIE, 24, server_cookie,
region)) {
int
parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns,
struct config_file* cfg, struct comm_point* c,
- struct comm_reply* repinfo, time_t now, struct regional* region)
+ struct comm_reply* repinfo, time_t now, struct regional* region,
+ struct cookie_secrets* cookie_secrets)
{
size_t rdata_len;
uint8_t* rdata_ptr;
rdata_ptr = sldns_buffer_current(pkt);
/* ignore rrsigs */
return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg,
- c, repinfo, now, region);
+ c, repinfo, now, region, cookie_secrets);
}
void
struct config_file;
struct comm_point;
struct comm_reply;
+struct cookie_secrets;
/** number of buckets in parse rrset hash table. Must be power of 2. */
#define PARSE_TABLE_SIZE 32
* @param repinfo: commreply to determine the client address
* @param now: current time
* @param region: region to alloc results in (edns option contents)
+ * @param cookie_secrets: the cookie secrets for EDNS COOKIE validation.
* @return: 0 on success, or an RCODE on error.
* RCODE formerr if OPT is badly formatted and so on.
*/
int parse_edns_from_query_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
struct config_file* cfg, struct comm_point* c,
- struct comm_reply* repinfo, time_t now, struct regional* region);
+ struct comm_reply* repinfo, time_t now, struct regional* region,
+ struct cookie_secrets* cookie_secrets);
/**
* Calculate hash value for rrset in packet.
return 0;
}
+int
+fptr_whitelist_mod_startup(int (*fptr)(struct module_env* env, int id))
+{
+#ifdef USE_IPSET
+ if(fptr == &ipset_startup) return 1;
+#else
+ (void)fptr;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_destartup(void (*fptr)(struct module_env* env, int id))
+{
+#ifdef USE_IPSET
+ if(fptr == &ipset_destartup) return 1;
+#else
+ (void)fptr;
+#endif
+ return 0;
+}
+
int
fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate,
enum module_ev event, int id, struct outbound_entry* outbound))
*/
int fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id));
+/**
+ * Check function pointer whitelist for module startup call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_startup(int (*fptr)(struct module_env* env, int id));
+
+/**
+ * Check function pointer whitelist for module destartup call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_destartup(void (*fptr)(struct module_env* env, int id));
+
/**
* Check function pointer whitelist for module operate call values.
*
* also contain an rcode that is nonzero, but in this case additional
* information (query, additional) can be passed along.
*
- * The rcode and dns_msg are used to pass the result from the the rightmost
+ * The rcode and dns_msg are used to pass the result from the rightmost
* module towards the leftmost modules and then towards the user.
*
* If you want to avoid recursion-cycles where queries need other queries
const char* name;
/**
- * init the module. Called once for the global state.
+ * Set up the module for start. This is called only once at startup.
+ * Privileged operations like opening device files may be done here.
+ * The function ptr can be NULL, if it is not used.
+ * @param env: module environment.
+ * @param id: module id number.
+ * return: 0 on error
+ */
+ int (*startup)(struct module_env* env, int id);
+
+ /**
+ * Close down the module for stop. This is called only once before
+ * shutdown to free resources allocated during startup().
+ * Closing privileged ports or files must be done here.
+ * The function ptr can be NULL, if it is not used.
+ * @param env: module environment.
+ * @param id: module id number.
+ */
+ void (*destartup)(struct module_env* env, int id);
+
+ /**
+ * Initialise the module. Called when restarting or reloading the
+ * daemon.
* This is the place to apply settings from the config file.
* @param env: module environment.
* @param id: module id number.
int (*init)(struct module_env* env, int id);
/**
- * de-init, delete, the module. Called once for the global state.
+ * Deinitialise the module, undo stuff done during init().
+ * Called before reloading the daemon.
* @param env: module environment.
* @param id: module id number.
*/
#ifdef HAVE_NETIOAPI_H
#include <netioapi.h>
#endif
+#include <ctype.h>
#include "util/net_help.h"
#include "util/log.h"
#include "util/data/dname.h"
return (memcmp(s, map_prefix, 12) == 0);
}
+int addr_is_ip6linklocal(struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ const uint8_t prefix[2] = {0xfe, 0x80};
+ int af = (int)((struct sockaddr_in6*)addr)->sin6_family;
+ void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ uint8_t start[2];
+ if(af != AF_INET6 || addrlen<(socklen_t)sizeof(struct sockaddr_in6))
+ return 0;
+ /* Put the first 10 bits of sin6addr in start, match fe80::/10. */
+ memmove(start, sin6addr, 2);
+ start[1] &= 0xc0;
+ return memcmp(start, prefix, 2) == 0;
+}
+
int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen)
{
int af = (int)((struct sockaddr_in*)addr)->sin_family;
if(!SSL_CTX_set_ecdh_auto(ctx,1)) {
log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE");
}
-#elif defined(USE_ECDSA)
+#elif defined(USE_ECDSA) && defined(HAVE_SSL_CTX_SET_TMP_ECDH)
if(1) {
EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
if (!ecdh) {
closesocket(socket);
}
# endif /* USE_WINSOCK */
+
+ssize_t
+hex_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize)
+{
+ static char hexdigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+ size_t i;
+
+ if (targsize < srclength * 2 + 1) {
+ return -1;
+ }
+
+ for (i = 0; i < srclength; ++i) {
+ *target++ = hexdigits[src[i] >> 4U];
+ *target++ = hexdigits[src[i] & 0xfU];
+ }
+ *target = '\0';
+ return 2 * srclength;
+}
+
+ssize_t
+hex_pton(const char* src, uint8_t* target, size_t targsize)
+{
+ uint8_t *t = target;
+ if(strlen(src) % 2 != 0 || strlen(src)/2 > targsize) {
+ return -1;
+ }
+ while(*src) {
+ if(!isxdigit((unsigned char)src[0]) ||
+ !isxdigit((unsigned char)src[1]))
+ return -1;
+ *t++ = sldns_hexdigit_to_int(src[0]) * 16 +
+ sldns_hexdigit_to_int(src[1]) ;
+ src += 2;
+ }
+ return t-target;
+}
*/
int addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen);
+/**
+ * See if sockaddr is an ipv6 fe80::/10 link local address.
+ * @param addr: address
+ * @param addrlen: length of address
+ * @return true if so
+ */
+int addr_is_ip6linklocal(struct sockaddr_storage* addr, socklen_t addrlen);
+
/**
* See if sockaddr is 255.255.255.255.
* @param addr: address
/** close the socket with close, or wsa closesocket */
void sock_close(int socket);
+/**
+ * Convert binary data to a string of hexadecimal characters.
+ */
+ssize_t hex_ntop(uint8_t const *src, size_t srclength, char *target,
+ size_t targsize);
+
+/** Convert hexadecimal data to binary. */
+ssize_t hex_pton(const char* src, uint8_t* target, size_t targsize);
+
#endif /* NET_HELP_H */
case EACCES:
if(verbosity < VERB_ALGO)
return 0;
+ break;
default:
break;
}
#ifndef USE_WINSOCK
if(errno == EINTR || errno == EAGAIN)
return 1;
- if(recv_initial) {
#ifdef ECONNRESET
if(errno == ECONNRESET && verbosity < 2)
return 0; /* silence reset by peer */
#endif
+ if(recv_initial) {
#ifdef ECONNREFUSED
if(errno == ECONNREFUSED && verbosity < 2)
return 0; /* silence reset by peer */
#endif
#ifdef ENOTCONN
if(errno == ENOTCONN) {
- log_err_addr("read (in tcp s) failed and this "
+ log_err_addr("read (in tcp initial) failed and this "
"could be because TCP Fast Open is "
"enabled [--disable-tfo-client "
"--disable-tfo-server] but does not "
return 1;
}
#endif
- log_err_addr("read (in tcp s)", sock_strerror(errno),
- &c->repinfo.remote_addr, c->repinfo.remote_addrlen);
+ log_err_addr((recv_initial?"read (in tcp initial)":"read (in tcp)"),
+ sock_strerror(errno), &c->repinfo.remote_addr,
+ c->repinfo.remote_addrlen);
return 0;
}
h2_stream->mesh_state = m;
}
+void http2_stream_remove_mesh_state(struct http2_stream* h2_stream)
+{
+ if(!h2_stream)
+ return;
+ h2_stream->mesh_state = NULL;
+}
+
/** delete http2 session server. After closing connection. */
static void http2_session_server_delete(struct http2_session* h2_session)
{
void http2_stream_add_meshstate(struct http2_stream* h2_stream,
struct mesh_area* mesh, struct mesh_state* m);
+/** Remove mesh state from stream. When the mesh state has been removed. */
+void http2_stream_remove_mesh_state(struct http2_stream* h2_stream);
+
/**
* This routine is published for checks and tests, and is only used internally.
* handle libevent callback for timer comm.
switch(length) /* all the case statements fall through */
{
case 3 : c+=k[2];
+ ATTR_FALLTHROUGH
/* fallthrough */
case 2 : b+=k[1];
+ ATTR_FALLTHROUGH
/* fallthrough */
case 1 : a+=k[0];
final(a,b,c);
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 0: /* case 0: nothing left to add */
break;
}
switch(length) /* all the case statements fall through */
{
case 3 : c+=k[2];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 2 : b+=k[1];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=k[0];
final(a,b,c);
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 0: /* case 0: nothing left to add */
break;
}
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
- case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
- case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
- case 9 : c+=k8[8]; /* fall through */
+ case 11: c+=((uint32_t)k8[10])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 10: c+=((uint32_t)k8[9])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 9 : c+=k8[8];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[1]; a+=k[0]; break;
- case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
- case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
- case 5 : b+=k8[4]; /* fall through */
+ case 7 : b+=((uint32_t)k8[6])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 6 : b+=((uint32_t)k8[5])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 5 : b+=k8[4];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[0]; break;
- case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
- case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 3 : a+=((uint32_t)k8[2])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 2 : a+=((uint32_t)k8[1])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 11: c+=((uint32_t)k8[10])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 9 : c+=k8[8]; /* fall through */
+ case 9 : c+=k8[8];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 7 : b+=((uint32_t)k8[6])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 5 : b+=k8[4]; /* fall through */
+ case 5 : b+=k8[4];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 3 : a+=((uint32_t)k8[2])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 11: c+=((uint32_t)k[10])<<16;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 10: c+=((uint32_t)k[9])<<8;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 9 : c+=k[8];
+ ATTR_FALLTHROUGH
/* fallthrough */
case 8 : b+=((uint32_t)k[7])<<24;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 7 : b+=((uint32_t)k[6])<<16;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 6 : b+=((uint32_t)k[5])<<8;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 5 : b+=k[4];
+ ATTR_FALLTHROUGH
/* fallthrough */
case 4 : a+=((uint32_t)k[3])<<24;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 3 : a+=((uint32_t)k[2])<<16;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 2 : a+=((uint32_t)k[1])<<8;
+ ATTR_FALLTHROUGH
/* fallthrough */
case 1 : a+=k[0];
break;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
- case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
- case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
- case 9 : c+=k8[8]; /* fall through */
+ case 11: c+=((uint32_t)k8[10])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 10: c+=((uint32_t)k8[9])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 9 : c+=k8[8];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[1]; a+=k[0]; break;
- case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
- case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
- case 5 : b+=k8[4]; /* fall through */
+ case 7 : b+=((uint32_t)k8[6])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 6 : b+=((uint32_t)k8[5])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 5 : b+=k8[4];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[0]; break;
- case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
- case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 3 : a+=((uint32_t)k8[2])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 2 : a+=((uint32_t)k8[1])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=k8[0]; break;
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
}
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 11: c+=((uint32_t)k8[10])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 9 : c+=k8[8]; /* fall through */
+ case 9 : c+=k8[8];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 7 : b+=((uint32_t)k8[6])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 5 : b+=k8[4]; /* fall through */
+ case 5 : b+=k8[4];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
- case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 3 : a+=((uint32_t)k8[2])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 11: c+=((uint32_t)k[10])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 10: c+=((uint32_t)k[9])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 9 : c+=k[8];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=((uint32_t)k[7])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 7 : b+=((uint32_t)k[6])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 6 : b+=((uint32_t)k[5])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 5 : b+=k[4];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=((uint32_t)k[3])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 3 : a+=((uint32_t)k[2])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 2 : a+=((uint32_t)k[1])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=k[0];
break;
case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
switch(length) /* all the case statements fall through */
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
- case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
- case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
- case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
+ case 11: c+=((uint32_t)k8[10])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 10: c+=((uint32_t)k8[9])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 9 : c+=((uint32_t)k8[8])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[1]; a+=k[0]; break;
- case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
- case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
- case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
+ case 7 : b+=((uint32_t)k8[6])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 6 : b+=((uint32_t)k8[5])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 5 : b+=((uint32_t)k8[4])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[0]; break;
- case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
- case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
+ case 3 : a+=((uint32_t)k8[2])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
+ case 2 : a+=((uint32_t)k8[1])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=((uint32_t)k8[0])<<24; break;
case 0 : return c;
}
switch(length) /* all the case statements fall through */
{
case 12: c+=k[11];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 11: c+=((uint32_t)k[10])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 10: c+=((uint32_t)k[9])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 9 : c+=((uint32_t)k[8])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 8 : b+=k[7];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 7 : b+=((uint32_t)k[6])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 6 : b+=((uint32_t)k[5])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 5 : b+=((uint32_t)k[4])<<24;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 4 : a+=k[3];
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 3 : a+=((uint32_t)k[2])<<8;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 2 : a+=((uint32_t)k[1])<<16;
+ ATTR_FALLTHROUGH
+ /* fallthrough */
case 1 : a+=((uint32_t)k[0])<<24;
break;
case 0 : return c;
struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
struct module_qstate* qstate)
{
+ char reasonbuf[256];
char* reason = NULL;
uint8_t sigalg[ALGO_NEEDS_MAX+1];
int downprot = env->cfg->harden_algo_downgrade;
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
- NULL, qstate);
+ NULL, qstate, reasonbuf, sizeof(reasonbuf));
/* sigalg is ignored, it returns algorithms signalled to exist, but
* in 5011 there are no other rrsets to check. if downprot is
* enabled, then it checks that the DNSKEY is signed with all
nsec_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey,
char** reason, sldns_ede_code* reason_bogus,
- struct module_qstate* qstate)
+ struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
nsec->entry.data;
if(d->security == sec_status_secure)
return 1;
d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason,
- reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified);
+ reason_bogus, LDNS_SECTION_AUTHORITY, qstate, &verified,
+ reasonbuf, reasonlen);
if(d->security == sec_status_secure) {
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
return 1;
val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
struct query_info* qinfo, struct reply_info* rep,
struct key_entry_key* kkey, time_t* proof_ttl, char** reason,
- sldns_ede_code* reason_bogus, struct module_qstate* qstate)
+ sldns_ede_code* reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen)
{
struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
* 2) this is not a delegation point */
if(nsec) {
if(!nsec_verify_rrset(env, ve, nsec, kkey, reason,
- reason_bogus, qstate)) {
+ reason_bogus, qstate, reasonbuf, reasonlen)) {
verbose(VERB_ALGO, "NSEC RRset for the "
"referral did not verify.");
return sec_status_bogus;
if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
continue;
if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason,
- reason_bogus, qstate)) {
+ reason_bogus, qstate, reasonbuf, reasonlen)) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"did not verify.");
*reason = "NSEC for empty non-terminal "
* @param reason: string explaining why bogus.
* @param reason_bogus: relevant EDE code for validation failure.
* @param qstate: qstate with region.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return security status.
* SECURE: proved absence of DS.
* INSECURE: proved that this was not a delegation point.
struct val_env* ve, struct query_info* qinfo,
struct reply_info* rep, struct key_entry_key* kkey,
time_t* proof_ttl, char** reason, sldns_ede_code* reason_bogus,
- struct module_qstate* qstate);
+ struct module_qstate* qstate, char* reasonbuf, size_t reasonlen);
/**
* nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
list_is_secure(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
- struct module_qstate* qstate)
+ struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
{
struct packed_rrset_data* d;
size_t i;
continue;
d->security = val_verify_rrset_entry(env, ve, list[i], kkey,
reason, reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
- &verified);
+ &verified, reasonbuf, reasonlen);
if(d->security != sec_status_secure) {
verbose(VERB_ALGO, "NSEC3 did not verify");
return 0;
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
- struct nsec3_cache_table* ct)
+ struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen)
{
struct nsec3_filter flt;
struct ce_response ce;
*reason = "no valid NSEC3s";
return sec_status_bogus; /* no valid NSEC3s, bogus */
}
- if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus, qstate)) {
+ if(!list_is_secure(env, ve, list, num, kkey, reason, reason_bogus,
+ qstate, reasonbuf, reasonlen)) {
*reason = "not all NSEC3 records secure";
return sec_status_bogus; /* not all NSEC3 records secure */
}
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
* @param ct: cached hashes table.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey, char** reason,
sldns_ede_code* reason_bogus, struct module_qstate* qstate,
- struct nsec3_cache_table* ct);
+ struct nsec3_cache_table* ct, char* reasonbuf, size_t reasonlen);
/**
* Prove NXDOMAIN or NODATA.
if(!dsasig) return 0;
#ifdef HAVE_DSA_SIG_SET0
- if(!DSA_SIG_set0(dsasig, R, S)) return 0;
+ if(!DSA_SIG_set0(dsasig, R, S)) {
+ DSA_SIG_free(dsasig);
+ return 0;
+ }
#else
# ifndef S_SPLINT_S
dsasig->r = R;
digest_size = (digest_size ? digest_size : SHA1_DIGEST_SIZE);
#endif
/* double fallthrough annotation to please gcc parser */
+ ATTR_FALLTHROUGH
/* fallthrough */
#ifdef USE_SHA2
/* fallthrough */
case LDNS_RSASHA256:
digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
+ ATTR_FALLTHROUGH
/* fallthrough */
case LDNS_RSASHA512:
digest_size = (digest_size ? digest_size : SHA512_DIGEST_SIZE);
#ifdef USE_ECDSA
case LDNS_ECDSAP256SHA256:
digest_size = (digest_size ? digest_size : SHA256_DIGEST_SIZE);
+ ATTR_FALLTHROUGH
/* fallthrough */
case LDNS_ECDSAP384SHA384:
digest_size = (digest_size ? digest_size : SHA384_DIGEST_SIZE);
dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
- sldns_pkt_section section, struct module_qstate* qstate, int* verified)
+ sldns_pkt_section section, struct module_qstate* qstate, int* verified,
+ char* reasonbuf, size_t reasonlen)
{
enum sec_status sec;
size_t i, num;
verbose(VERB_ALGO, "rrset failed to verify: "
"no valid signatures for %d algorithms",
(int)algo_needs_num_missing(&needs));
- algo_needs_reason(env, alg, reason, "no signatures");
+ algo_needs_reason(alg, reason, "no signatures", reasonbuf,
+ reasonlen);
} else {
verbose(VERB_ALGO, "rrset failed to verify: "
"no valid signatures");
return sec_status_bogus;
}
-void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s)
+void algo_needs_reason(int alg, char** reason, char* s, char* reasonbuf,
+ size_t reasonlen)
{
- char buf[256];
sldns_lookup_table *t = sldns_lookup_by_id(sldns_algorithms, alg);
if(t&&t->name)
- snprintf(buf, sizeof(buf), "%s with algorithm %s", s, t->name);
- else snprintf(buf, sizeof(buf), "%s with algorithm ALG%u", s,
+ snprintf(reasonbuf, reasonlen, "%s with algorithm %s", s,
+ t->name);
+ else snprintf(reasonbuf, reasonlen, "%s with algorithm ALG%u", s,
(unsigned)alg);
- *reason = regional_strdup(env->scratch, buf);
- if(!*reason)
- *reason = s;
+ *reason = reasonbuf;
}
enum sec_status
/**
* Format error reason for algorithm missing.
- * @param env: module env with scratch for temp storage of string.
* @param alg: DNSKEY-algorithm missing.
* @param reason: destination.
* @param s: string, appended with 'with algorithm ..'.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
*/
-void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s);
+void algo_needs_reason(int alg, char** reason, char* s, char* reasonbuf,
+ size_t reasonlen);
/**
* Check if dnskey matches a DS digest
* @param section: section of packet where this rrset comes from.
* @param qstate: qstate with region.
* @param verified: if not NULL the number of RRSIG validations is returned.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return SECURE if one key in the set verifies one rrsig.
* UNCHECKED on allocation errors, unsupported algorithms, malformed data,
* and BOGUS on verification failures (no keys match any signatures).
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg,
char** reason, sldns_ede_code *reason_bogus,
- sldns_pkt_section section, struct module_qstate* qstate, int* verified);
-
+ sldns_pkt_section section, struct module_qstate* qstate, int* verified,
+ char* reasonbuf, size_t reasonlen);
/**
* verify rrset against one specific dnskey (from rrset)
}
}
+/** Detect if the, unsigned, CNAME is under a previous DNAME RR in the
+ * message, and thus it was generated from that previous DNAME.
+ */
+static int
+cname_under_previous_dname(struct reply_info* rep, size_t cname_idx,
+ size_t* ret)
+{
+ size_t i;
+ for(i=0; i<cname_idx; i++) {
+ if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNAME &&
+ dname_strict_subdomain_c(rep->rrsets[cname_idx]->
+ rk.dname, rep->rrsets[i]->rk.dname)) {
+ *ret = i;
+ return 1;
+ }
+ }
+ *ret = 0;
+ return 0;
+}
+
void
val_find_signer(enum val_classification subtype, struct query_info* qinf,
struct reply_info* rep, size_t skip, uint8_t** signer_name,
*signer_name = NULL;
*signer_len = 0;
} else if(subtype == VAL_CLASS_CNAME) {
+ size_t j;
/* check for the first signed cname/dname rrset */
for(i=skip; i<rep->an_numrrsets; i++) {
val_find_rrset_signer(rep->rrsets[i],
signer_name, signer_len);
if(*signer_name)
return;
+ if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME
+ && cname_under_previous_dname(rep, i, &j)) {
+ val_find_rrset_signer(rep->rrsets[j],
+ signer_name, signer_len);
+ return;
+ }
if(ntohs(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_DNAME)
break; /* only check CNAME after a DNAME */
}
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
uint8_t* sigalg, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate,
- int *verified)
+ int *verified, char* reasonbuf, size_t reasonlen)
{
enum sec_status sec;
struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
log_nametypeclass(VERB_ALGO, "verify rrset", rrset->rk.dname,
ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
sec = dnskeyset_verify_rrset(env, ve, rrset, keys, sigalg, reason,
- reason_bogus, section, qstate, verified);
+ reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
verbose(VERB_ALGO, "verify result: %s", sec_status_to_string(sec));
regional_free_all(env->scratch);
struct ub_packed_rrset_key* rrset, struct key_entry_key* kkey,
char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate,
- int* verified)
+ int* verified, char* reasonbuf, size_t reasonlen)
{
/* temporary dnskey rrset-key */
struct ub_packed_rrset_key dnskey;
dnskey.entry.key = &dnskey;
dnskey.entry.data = kd->rrset_data;
sec = val_verify_rrset(env, ve, rrset, &dnskey, kd->algo, reason,
- reason_bogus, section, qstate, verified);
+ reason_bogus, section, qstate, verified, reasonbuf, reasonlen);
return sec;
}
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx, char** reason,
sldns_ede_code *reason_bogus, struct module_qstate* qstate,
- int *nonechecked)
+ int *nonechecked, char* reasonbuf, size_t reasonlen)
{
enum sec_status sec = sec_status_bogus;
size_t i, num, numchecked = 0, numhashok = 0, numsizesupp = 0;
return sec_status_insecure;
}
if(numchecked == 0) {
- algo_needs_reason(env, ds_get_key_algo(ds_rrset, ds_idx),
- reason, "no keys have a DS");
+ algo_needs_reason(ds_get_key_algo(ds_rrset, ds_idx),
+ reason, "no keys have a DS", reasonbuf, reasonlen);
*nonechecked = 1;
} else if(numhashok == 0) {
*reason = "DS hash mismatches key";
val_verify_DNSKEY_with_DS(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate)
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen)
{
/* as long as this is false, we can consider this DS rrset to be
* equivalent to no DS rrset. */
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
ds_rrset, i, reason, reason_bogus, qstate,
- &nonechecked);
+ &nonechecked, reasonbuf, reasonlen);
if(sec == sec_status_insecure) {
/* DNSKEY too large unsupported or algo refused by
* crypto lib. */
/* If any were understandable, then it is bad. */
verbose(VERB_QUERY, "Failed to match any usable DS to a DNSKEY.");
if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
- algo_needs_reason(env, alg, reason, "missing verification of "
- "DNSKEY signature");
+ algo_needs_reason(alg, reason, "missing verification of "
+ "DNSKEY signature", reasonbuf, reasonlen);
}
return sec_status_bogus;
}
val_verify_new_DNSKEYs(struct regional* region, struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate)
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_DS(env, ve,
dnskey_rrset, ds_rrset, downprot?sigalg:NULL, reason,
- reason_bogus, qstate);
+ reason_bogus, qstate, reasonbuf, reasonlen);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate)
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen)
{
/* as long as this is false, we can consider this anchor to be
* equivalent to no anchor. */
continue;
sec = verify_dnskeys_with_ds_rr(env, ve, dnskey_rrset,
- ta_ds, i, reason, reason_bogus, qstate, &nonechecked);
+ ta_ds, i, reason, reason_bogus, qstate, &nonechecked,
+ reasonbuf, reasonlen);
if(sec == sec_status_insecure) {
has_algo_refusal = 1;
continue;
/* If any were understandable, then it is bad. */
verbose(VERB_QUERY, "Failed to match any usable anchor to a DNSKEY.");
if(sigalg && (alg=algo_needs_missing(&needs)) != 0) {
- algo_needs_reason(env, alg, reason, "missing verification of "
- "DNSKEY signature");
+ algo_needs_reason(alg, reason, "missing verification of "
+ "DNSKEY signature", reasonbuf, reasonlen);
}
return sec_status_bogus;
}
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
- char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate)
+ char** reason, sldns_ede_code *reason_bogus,
+ struct module_qstate* qstate, char* reasonbuf, size_t reasonlen)
{
uint8_t sigalg[ALGO_NEEDS_MAX+1];
enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve,
dnskey_rrset, ta_ds_rrset, ta_dnskey_rrset,
- downprot?sigalg:NULL, reason, reason_bogus, qstate);
+ downprot?sigalg:NULL, reason, reason_bogus, qstate,
+ reasonbuf, reasonlen);
if(sec == sec_status_secure) {
return key_entry_create_rrset(region,
val_fill_reply(struct reply_info* chase, struct reply_info* orig,
size_t skip, uint8_t* name, size_t len, uint8_t* signer)
{
- size_t i;
+ size_t i, j;
int seen_dname = 0;
chase->rrset_count = 0;
chase->an_numrrsets = 0;
LDNS_RR_TYPE_DNAME) {
seen_dname = 1;
}
+ } else if(ntohs(orig->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME
+ && ((struct packed_rrset_data*)orig->rrsets[i]->
+ entry.data)->rrsig_count == 0 &&
+ cname_under_previous_dname(orig, i, &j) &&
+ rrset_has_signer(orig->rrsets[j], name, len)) {
+ chase->rrsets[chase->an_numrrsets++] = orig->rrsets[j];
+ chase->rrsets[chase->an_numrrsets++] = orig->rrsets[i];
}
}
/* AUTHORITY section */
* @param section: section of packet where this rrset comes from.
* @param qstate: qstate with region.
* @param verified: if not NULL, the number of RRSIG validations is returned.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return security status of verification.
*/
enum sec_status val_verify_rrset_entry(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct key_entry_key* kkey, char** reason, sldns_ede_code *reason_bogus,
sldns_pkt_section section, struct module_qstate* qstate,
- int* verified);
+ int* verified, char* reasonbuf, size_t reasonlen);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return: sec_status_secure if a DS matches.
* sec_status_insecure if end of trust (i.e., unknown algorithms).
* sec_status_bogus if it fails.
enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate);
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen);
/**
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return: sec_status_secure if a DS matches.
* sec_status_insecure if end of trust (i.e., unknown algorithms).
* sec_status_bogus if it fails.
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate);
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return a KeyEntry. This will either contain the now trusted
* dnskey_rrset, a "null" key entry indicating that this DS
* rrset/DNSKEY pair indicate an secure end to the island of trust
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason,
- sldns_ede_code *reason_bogus, struct module_qstate* qstate);
+ sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen);
/**
* Verify rrset with trust anchor: DS and DNSKEY rrset.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @param reason_bogus: EDE (RFC8914) code paired with the reason of failure.
* @param qstate: qstate with region.
+ * @param reasonbuf: buffer to use for fail reason string print.
+ * @param reasonlen: length of reasonbuf.
* @return a KeyEntry. This will either contain the now trusted
* dnskey_rrset, a "null" key entry indicating that this DS
* rrset/DNSKEY pair indicate an secure end to the island of trust
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset, int downprot,
- char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate);
+ char** reason, sldns_ede_code *reason_bogus, struct module_qstate* qstate,
+ char* reasonbuf, size_t reasonlen);
/**
* Determine if DS rrset is usable for validator or not.
/* forward decl for cache response and normal super inform calls of a DS */
static void process_ds_response(struct module_qstate* qstate,
struct val_qstate* vq, int id, int rcode, struct dns_msg* msg,
- struct query_info* qinfo, struct sock_list* origin, int* suspend);
+ struct query_info* qinfo, struct sock_list* origin, int* suspend,
+ struct module_qstate* sub_qstate);
/* Updates the suplied EDE (RFC8914) code selectively so we don't lose
return NULL;
if(vq->orig_msg->rep->rrset_count > RR_COUNT_MAX)
return NULL; /* protect against integer overflow */
- vq->chase_reply->rrsets = regional_alloc_init(qstate->region,
- vq->orig_msg->rep->rrsets, sizeof(struct ub_packed_rrset_key*)
- * vq->orig_msg->rep->rrset_count);
+ /* Over allocate (+an_numrrsets) in case we need to put extra DNAME
+ * records for unsigned CNAME repetitions */
+ vq->chase_reply->rrsets = regional_alloc(qstate->region,
+ sizeof(struct ub_packed_rrset_key*) *
+ (vq->orig_msg->rep->rrset_count
+ + vq->orig_msg->rep->an_numrrsets));
if(!vq->chase_reply->rrsets)
return NULL;
+ memmove(vq->chase_reply->rrsets, vq->orig_msg->rep->rrsets,
+ sizeof(struct ub_packed_rrset_key*) *
+ vq->orig_msg->rep->rrset_count);
vq->rrset_skip = 0;
return vq;
}
struct ub_packed_rrset_key* s;
enum sec_status sec;
int num_verifies = 0, verified, have_state = 0;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
*suspend = 0;
/* Verify the answer rrset */
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
- &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
+ &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified,
+ reasonbuf, sizeof(reasonbuf));
/* If the (answer) rrset failed to validate, then this
* message is BAD. */
if(sec != sec_status_secure) {
s = chase_reply->rrsets[i];
sec = val_verify_rrset_entry(env, ve, s, key_entry, &reason,
&reason_bogus, LDNS_SECTION_AUTHORITY, qstate,
- &verified);
+ &verified, reasonbuf, sizeof(reasonbuf));
/* If anything in the authority section fails to be secure,
* we have a bad message. */
if(sec != sec_status_secure) {
if(sname && query_dname_compare(sname, key_entry->name)==0)
(void)val_verify_rrset_entry(env, ve, s, key_entry,
&reason, NULL, LDNS_SECTION_ADDITIONAL, qstate,
- &verified);
+ &verified, reasonbuf, sizeof(reasonbuf));
/* the additional section can fail to be secure,
* it is optional, check signature in case we need
* to clean the additional section later. */
verbose(VERB_ALGO, "Process suspended sub DS response");
msg = vq->sub_ds_msg;
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
- msg, &msg->qinfo, NULL, &suspend);
+ msg, &msg->qinfo, NULL, &suspend, NULL);
if(suspend) {
/* we'll come back here later to continue */
if(!validate_suspend_setup_timer(qstate, vq,
vq->key_entry->name)) ) {
verbose(VERB_ALGO, "Process cached DS response");
process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
- msg, &msg->qinfo, NULL, &suspend);
+ msg, &msg->qinfo, NULL, &suspend, NULL);
if(suspend) {
/* we'll come back here later to continue */
if(!validate_suspend_setup_timer(qstate, vq,
* @param ta: trust anchor.
* @param qstate: qstate that needs key.
* @param id: module id.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
* @return new key entry or NULL on allocation failure.
* The key entry will either contain a validated DNSKEY rrset, or
* represent a Null key (query failed, but validation did not), or a
*/
static struct key_entry_key*
primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
- struct trust_anchor* ta, struct module_qstate* qstate, int id)
+ struct trust_anchor* ta, struct module_qstate* qstate, int id,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* kkey = NULL;
enum sec_status sec = sec_status_unchecked;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
int downprot = qstate->env->cfg->harden_algo_downgrade;
if(!dnskey_rrset) {
+ char* err = errinf_to_str_misc(sub_qstate);
+ char rstr[1024];
log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
"could not fetch DNSKEY rrset",
ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
reason_bogus = LDNS_EDE_DNSKEY_MISSING;
- reason = "no DNSKEY rrset";
+ if(!err) {
+ snprintf(rstr, sizeof(rstr), "no DNSKEY rrset");
+ } else {
+ snprintf(rstr, sizeof(rstr), "no DNSKEY rrset "
+ "[%s]", err);
+ }
if(qstate->env->cfg->harden_dnssec_stripped) {
- errinf_ede(qstate, reason, reason_bogus);
+ errinf_ede(qstate, rstr, reason_bogus);
kkey = key_entry_create_bad(qstate->region, ta->name,
ta->namelen, ta->dclass, BOGUS_KEY_TTL,
- reason_bogus, reason,
- *qstate->env->now);
+ reason_bogus, rstr, *qstate->env->now);
} else kkey = key_entry_create_null(qstate->region, ta->name,
ta->namelen, ta->dclass, NULL_KEY_TTL,
- reason_bogus, reason,
- *qstate->env->now);
+ reason_bogus, rstr, *qstate->env->now);
if(!kkey) {
log_err("out of memory: allocate fail prime key");
return NULL;
/* attempt to verify with trust anchor DS and DNSKEY */
kkey = val_verify_new_DNSKEYs_with_ta(qstate->region, qstate->env, ve,
dnskey_rrset, ta->ds_rrset, ta->dnskey_rrset, downprot,
- &reason, &reason_bogus, qstate);
+ &reason, &reason_bogus, qstate, reasonbuf, sizeof(reasonbuf));
if(!kkey) {
log_err("out of memory: verifying prime TA");
return NULL;
* DS response indicated an end to secure space, is_good if the DS
* validated. It returns ke=NULL if the DS response indicated that the
* request wasn't a delegation point.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
+ * Can be NULL.
* @return
* 0 on success,
* 1 on servfail error (malloc failure),
static int
ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct key_entry_key** ke)
+ struct key_entry_key** ke, struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
enum val_classification subtype;
verbose(VERB_DETAIL, "DS response was error, thus bogus");
errinf(qstate, rc);
reason = "no DS";
+ if(sub_qstate) {
+ char* err = errinf_to_str_misc(sub_qstate);
+ if(err) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "[%s]", err);
+ errinf(qstate, buf);
+ }
+ }
reason_bogus = LDNS_EDE_NETWORK_ERROR;
errinf_ede(qstate, reason, reason_bogus);
goto return_bogus;
/* Verify only returns BOGUS or SECURE. If the rrset is
* bogus, then we are done. */
sec = val_verify_rrset_entry(qstate->env, ve, ds,
- vq->key_entry, &reason, &reason_bogus, LDNS_SECTION_ANSWER, qstate, &verified);
+ vq->key_entry, &reason, &reason_bogus,
+ LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
+ sizeof(reasonbuf));
if(sec != sec_status_secure) {
verbose(VERB_DETAIL, "DS rrset in DS response did "
"not verify");
/* Try to prove absence of the DS with NSEC */
sec = val_nsec_prove_nodata_dsreply(
qstate->env, ve, qinfo, msg->rep, vq->key_entry,
- &proof_ttl, &reason, &reason_bogus, qstate);
+ &proof_ttl, &reason, &reason_bogus, qstate,
+ reasonbuf, sizeof(reasonbuf));
switch(sec) {
case sec_status_secure:
verbose(VERB_DETAIL, "NSEC RRset for the "
sec = nsec3_prove_nods(qstate->env, ve,
msg->rep->rrsets + msg->rep->an_numrrsets,
msg->rep->ns_numrrsets, qinfo, vq->key_entry, &reason,
- &reason_bogus, qstate, &vq->nsec3_cache_table);
+ &reason_bogus, qstate, &vq->nsec3_cache_table,
+ reasonbuf, sizeof(reasonbuf));
switch(sec) {
case sec_status_insecure:
/* case insecure also continues to unsigned
}
sec = val_verify_rrset_entry(qstate->env, ve, cname,
vq->key_entry, &reason, &reason_bogus,
- LDNS_SECTION_ANSWER, qstate, &verified);
+ LDNS_SECTION_ANSWER, qstate, &verified, reasonbuf,
+ sizeof(reasonbuf));
if(sec == sec_status_secure) {
verbose(VERB_ALGO, "CNAME validated, "
"proof that DS does not exist");
* @param origin: the origin of msg.
* @param suspend: returned true if the task takes too long and needs to
* suspend to continue the effort later.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
+ * Can be NULL.
*/
static void
process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin, int* suspend)
+ struct sock_list* origin, int* suspend,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* dske = NULL;
int ret;
*suspend = 0;
vq->empty_DS_name = NULL;
- ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske);
+ ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske,
+ sub_qstate);
if(ret != 0) {
switch(ret) {
case 1:
* @param msg: result message (if rcode is OK).
* @param qinfo: from the sub query state, query info.
* @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
*/
static void
process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
- struct sock_list* origin)
+ struct sock_list* origin, struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct key_entry_key* old = vq->key_entry;
struct ub_packed_rrset_key* dnskey = NULL;
int downprot;
+ char reasonbuf[256];
char* reason = NULL;
sldns_ede_code reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
dnskey = reply_find_answer_rrset(qinfo, msg->rep);
if(dnskey == NULL) {
+ char* err;
+ char rstr[1024];
/* bad response */
verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
"DNSKEY query.");
vq->restart_count++;
return;
}
- reason = "No DNSKEY record";
+ err = errinf_to_str_misc(sub_qstate);
+ if(!err) {
+ snprintf(rstr, sizeof(rstr), "No DNSKEY record");
+ } else {
+ snprintf(rstr, sizeof(rstr), "No DNSKEY record "
+ "[%s]", err);
+ }
reason_bogus = LDNS_EDE_DNSKEY_MISSING;
vq->key_entry = key_entry_create_bad(qstate->region,
qinfo->qname, qinfo->qname_len, qinfo->qclass,
- BOGUS_KEY_TTL, reason_bogus, reason,
- *qstate->env->now);
+ BOGUS_KEY_TTL, reason_bogus, rstr, *qstate->env->now);
if(!vq->key_entry) {
log_err("alloc failure in missing dnskey response");
/* key_entry is NULL for failure in Validate */
}
- errinf_ede(qstate, reason, reason_bogus);
+ errinf_ede(qstate, rstr, reason_bogus);
errinf_origin(qstate, origin);
errinf_dname(qstate, "for key", qinfo->qname);
vq->state = VAL_VALIDATE_STATE;
}
downprot = qstate->env->cfg->harden_algo_downgrade;
vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env,
- ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus, qstate);
+ ve, dnskey, vq->ds_rrset, downprot, &reason, &reason_bogus,
+ qstate, reasonbuf, sizeof(reasonbuf));
if(!vq->key_entry) {
log_err("out of memory in verify new DNSKEYs");
* @param rcode: rcode result value.
* @param msg: result message (if rcode is OK).
* @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ * the trust anchor data, it contains error information for the answer.
*/
static void
process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
- int id, int rcode, struct dns_msg* msg, struct sock_list* origin)
+ int id, int rcode, struct dns_msg* msg, struct sock_list* origin,
+ struct module_qstate* sub_qstate)
{
struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
struct ub_packed_rrset_key* dnskey_rrset = NULL;
return;
}
}
- vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id);
+ vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id,
+ sub_qstate);
lock_basic_unlock(&ta->lock);
if(vq->key_entry) {
if(key_entry_isbad(vq->key_entry)
if(vq->wait_prime_ta) {
vq->wait_prime_ta = 0;
process_prime_response(super, vq, id, qstate->return_rcode,
- qstate->return_msg, qstate->reply_origin);
+ qstate->return_msg, qstate->reply_origin, qstate);
return;
}
if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
int suspend;
process_ds_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin, &suspend);
+ qstate->reply_origin, &suspend, qstate);
/* If NSEC3 was needed during validation, NULL the NSEC3 cache;
* it will be re-initiated if needed later on.
* Validation (and the cache table) are happening/allocated in
} else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
process_dnskey_response(super, vq, id, qstate->return_rcode,
qstate->return_msg, &qstate->qinfo,
- qstate->reply_origin);
+ qstate->reply_origin, qstate);
return;
}
log_err("internal error in validator: no inform_supers possible");
*/
static struct module_func_block val_block = {
"validator",
- &val_init, &val_deinit, &val_operate, &val_inform_super, &val_clear,
- &val_get_mem
+ NULL, NULL, &val_init, &val_deinit, &val_operate, &val_inform_super,
+ &val_clear, &val_get_mem
};
struct module_func_block*