CC=@CC@
CPPFLAGS=-I. @CPPFLAGS@
PYTHON_CPPFLAGS=-I. @PYTHON_CPPFLAGS@
-CFLAGS=@CFLAGS@
+CFLAGS=-DSRCDIR=$(srcdir) @CFLAGS@
LDFLAGS=@LDFLAGS@
LIBS=@LIBS@
LIBOBJS=@LIBOBJS@
# compat with OpenBSD
LINTFLAGS+="-Dsigset_t=long"
# FreeBSD
-LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=int" "-D__va_list=va_list" "-D__uint32_t=uint32_t"
+LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=int" "-D__va_list=va_list" "-D__uint32_t=uint32_t" "-D_Alignof(x)=x" "-D__aligned(x)=" "-D__requires_exclusive(x)=" "-D__requires_unlocked(x)=" "-D__locks_exclusive(x)=" "-D__trylocks_exclusive(x)=" "-D__unlocks(x)=" "-D__locks_shared(x)=" "-D__trylocks_shared(x)="
INSTALL=$(SHELL) $(srcdir)/install-sh
util/shm_side/shm_main.c services/authzone.c \
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
-util/rtt.c util/storage/dnstree.c util/storage/lookup3.c \
-util/storage/lruhash.c util/storage/slabhash.c util/timehist.c util/tube.c \
+util/rtt.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
+util/storage/lruhash.c util/storage/slabhash.c util/tcp_conn_limit.c \
+util/timehist.c util/tube.c \
util/ub_event.c util/ub_event_pluggable.c util/winsock_event.c \
validator/autotrust.c validator/val_anchor.c validator/validator.c \
validator/val_kcache.c validator/val_kentry.c validator/val_neg.c \
iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \
iter_scrub.lo iter_utils.lo localzone.lo mesh.lo modstack.lo view.lo \
outbound_list.lo alloc.lo config_file.lo configlexer.lo configparser.lo \
-fptr_wlist.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
+fptr_wlist.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \
-slabhash.lo timehist.lo tube.lo winsock_event.lo autotrust.lo val_anchor.lo \
+slabhash.lo tcp_conn_limit.lo timehist.lo tube.lo winsock_event.lo \
+autotrust.lo val_anchor.lo \
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo redis.lo authzone.lo \
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
$(COMPAT_OBJ)
DAEMON_SRC=daemon/acl_list.c daemon/cachedump.c daemon/daemon.c \
daemon/remote.c daemon/stats.c daemon/unbound.c daemon/worker.c @WIN_DAEMON_SRC@
-DAEMON_OBJ=acl_list.lo cachedump.lo daemon.lo shm_main.lo remote.lo stats.lo unbound.lo \
+DAEMON_OBJ=acl_list.lo cachedump.lo daemon.lo \
+shm_main.lo remote.lo stats.lo unbound.lo \
worker.lo @WIN_DAEMON_OBJ@
DAEMON_OBJ_LINK=$(DAEMON_OBJ) $(COMMON_OBJ_ALL_SYMBOLS) $(SLDNS_OBJ) \
$(COMPAT_OBJ) @WIN_DAEMON_OBJ_LINK@
UBANCHOR_OBJ_LINK=$(UBANCHOR_OBJ) parseutil.lo \
$(COMPAT_OBJ_WITHOUT_CTIME) @WIN_UBANCHOR_OBJ_LINK@
TESTBOUND_SRC=testcode/testbound.c testcode/testpkts.c \
-daemon/worker.c daemon/acl_list.c daemon/daemon.c daemon/stats.c \
+daemon/worker.c daemon/acl_list.c \
+daemon/daemon.c daemon/stats.c \
testcode/replay.c testcode/fake_event.c
TESTBOUND_OBJ=testbound.lo replay.lo fake_event.lo
TESTBOUND_OBJ_LINK=$(TESTBOUND_OBJ) testpkts.lo worker.lo acl_list.lo \
test: unittest$(EXEEXT) testbound$(EXEEXT)
./unittest$(EXEEXT)
./testbound$(EXEEXT) -s
- for x in testdata/*.rpl; do echo -n "$$x "; if ./testbound$(EXEEXT) -p $$x >/dev/null 2>&1; then echo OK; else echo failed; exit 1; fi done
+ for x in $(srcdir)/testdata/*.rpl; do echo -n "$$x "; if ./testbound$(EXEEXT) -p $$x >/dev/null 2>&1; then echo OK; else echo failed; exit 1; fi done
@echo test OK
longtest: tests
+ if test ! $(srcdir)/testdata -ef ./testdata; then rm -rf testcode testdata; mkdir testcode testdata; cp -R $(srcdir)/testdata/*.sh $(srcdir)/testdata/*.tdir $(srcdir)/testdata/*.rpl $(srcdir)/testdata/*.crpl testdata; cp $(srcdir)/testcode/*.sh testcode; if test ! -d util; then mkdir util; fi; cp $(srcdir)/util/iana_ports.inc util; fi
if test -x "`which bash`"; then bash testcode/do-tests.sh; else sh testcode/do-tests.sh; fi
lib: libunbound.la unbound.h
DEPEND_TMP=depend1073.tmp
DEPEND_TMP2=depend1074.tmp
DEPEND_TARGET=Makefile
-DEPEND_TARGET2=Makefile.in
+DEPEND_TARGET2=$(srcdir)/Makefile.in
# actions: generate deplines from gcc,
# then, filter out home/xx, /usr/xx and /opt/xx lines (some cc already do this)
# then, remove empty " \" lines
# then, remove srcdir from the (generated) parser and lexer.
# and mention the .lo
depend:
- (cd $(srcdir) ; $(CC) $(DEPFLAG) $(CPPFLAGS) $(CFLAGS) @PTHREAD_CFLAGS_ONLY@ $(ALL_SRC) $(COMPAT_SRC)) | \
+ (BUILDDIR=$$PWD; cd $(srcdir) ; $(CC) $(DEPFLAG) $(CPPFLAGS) $(CFLAGS) -I$$BUILDDIR @PTHREAD_CFLAGS_ONLY@ $(ALL_SRC) $(COMPAT_SRC)) | \
+ sed -e 's?'$$PWD'/config.h?config.h?g' | \
sed -e 's!'$$HOME'[^ ]* !!g' -e 's!'$$HOME'[^ ]*$$!!g' \
-e 's!/usr[^ ]* !!g' -e 's!/usr[^ ]*$$!!g' \
-e 's!/opt[^ ]* !!g' -e 's!/opt[^ ]*$$!!g' | \
$(srcdir)/services/modstack.h $(srcdir)/services/outbound_list.h $(srcdir)/services/cache/dns.h \
$(srcdir)/util/net_help.h $(srcdir)/util/regional.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/timehist.h \
$(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/alloc.h $(srcdir)/util/config_file.h \
- $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h $(srcdir)/services/localzone.h \
+ $(srcdir)/util/edns.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h $(srcdir)/services/localzone.h \
$(srcdir)/util/storage/dnstree.h $(srcdir)/services/view.h $(srcdir)/util/data/dname.h $(srcdir)/respip/respip.h
modstack.lo modstack.o: $(srcdir)/services/modstack.c config.h $(srcdir)/services/modstack.h \
$(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h \
$(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/util/storage/dnstree.h $(srcdir)/util/rtt.h $(srcdir)/util/data/msgreply.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h $(srcdir)/util/net_help.h \
- $(srcdir)/util/random.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/module.h $(srcdir)/util/tube.h \
- $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h $(srcdir)/sldns/sbuffer.h $(srcdir)/dnstap/dnstap.h \
+ $(srcdir)/util/data/packed_rrset.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
+ $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
+ $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h $(srcdir)/util/net_help.h $(srcdir)/util/random.h \
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h \
+ $(srcdir)/sldns/sbuffer.h $(srcdir)/dnstap/dnstap.h \
alloc.lo alloc.o: $(srcdir)/util/alloc.c config.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/testcode/checklocks.h $(srcdir)/util/regional.h $(srcdir)/util/data/packed_rrset.h \
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
$(srcdir)/dnscrypt/cert.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
- $(srcdir)/testcode/checklocks.h $(srcdir)/util/ub_event.h $(srcdir)/util/net_help.h $(srcdir)/util/fptr_wlist.h \
- $(srcdir)/util/storage/lruhash.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \
- $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \
- $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/testcode/checklocks.h $(srcdir)/util/ub_event.h $(srcdir)/util/net_help.h \
+ $(srcdir)/util/tcp_conn_limit.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/module.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \
+ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \
$(srcdir)/services/modstack.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h $(srcdir)/dnstap/dnstap.h \
\
$(srcdir)/sldns/rrdef.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
$(srcdir)/services/modstack.h
regional.lo regional.o: $(srcdir)/util/regional.c config.h $(srcdir)/util/log.h $(srcdir)/util/regional.h
-rtt.lo rtt.o: $(srcdir)/util/rtt.c config.h $(srcdir)/util/rtt.h
+rtt.lo rtt.o: $(srcdir)/util/rtt.c config.h $(srcdir)/util/rtt.h $(srcdir)/iterator/iterator.h \
+ $(srcdir)/services/outbound_list.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h $(srcdir)/util/data/packed_rrset.h \
+ $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h
+edns.lo edns.o: $(srcdir)/util/edns.c config.h $(srcdir)/util/config_file.h $(srcdir)/util/netevent.h \
+ $(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/dnscrypt/cert.h \
+ $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/data/msgparse.h $(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h
dnstree.lo dnstree.o: $(srcdir)/util/storage/dnstree.c config.h $(srcdir)/util/storage/dnstree.h \
$(srcdir)/util/rbtree.h $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \
$(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h $(srcdir)/util/net_help.h
$(srcdir)/services/modstack.h
slabhash.lo slabhash.o: $(srcdir)/util/storage/slabhash.c config.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h
+tcp_conn_limit.lo tcp_conn_limit.o: $(srcdir)/util/tcp_conn_limit.c config.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/log.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/tcp_conn_limit.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/testcode/checklocks.h \
+ $(srcdir)/services/localzone.h $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \
+ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/services/view.h $(srcdir)/sldns/str2wire.h
timehist.lo timehist.o: $(srcdir)/util/timehist.c config.h $(srcdir)/util/timehist.h $(srcdir)/util/log.h
tube.lo tube.o: $(srcdir)/util/tube.c config.h $(srcdir)/util/tube.h $(srcdir)/util/log.h $(srcdir)/util/net_help.h \
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
$(srcdir)/util/storage/slabhash.h $(srcdir)/util/config_file.h $(srcdir)/util/fptr_wlist.h \
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
$(srcdir)/dnscrypt/cert.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \
- $(srcdir)/services/modstack.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h
+ $(srcdir)/services/modstack.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h \
+ $(srcdir)/util/storage/dnstree.h $(srcdir)/util/data/dname.h $(srcdir)/sldns/str2wire.h
edns-subnet.lo edns-subnet.o: $(srcdir)/edns-subnet/edns-subnet.c config.h \
$(srcdir)/edns-subnet/edns-subnet.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h
subnetmod.lo subnetmod.o: $(srcdir)/edns-subnet/subnetmod.c config.h $(srcdir)/edns-subnet/subnetmod.h \
$(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \
$(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h $(srcdir)/util/alloc.h $(srcdir)/util/locks.h \
$(srcdir)/testcode/checklocks.h $(srcdir)/util/net_help.h $(srcdir)/util/config_file.h $(srcdir)/util/rtt.h \
- $(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/services/cache/infra.h \
- $(srcdir)/util/storage/lruhash.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
+ $(srcdir)/util/timehist.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \
+ $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/packed_rrset.h \
+ $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/libunbound/unbound.h \
+ $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \
$(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
- $(srcdir)/dnscrypt/cert.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \
- $(srcdir)/util/random.h $(srcdir)/respip/respip.h $(srcdir)/util/module.h $(srcdir)/util/data/msgparse.h \
- $(srcdir)/sldns/pkthdr.h $(srcdir)/services/localzone.h $(srcdir)/services/view.h
+ $(srcdir)/dnscrypt/cert.h $(srcdir)/util/random.h $(srcdir)/respip/respip.h $(srcdir)/services/localzone.h \
+ $(srcdir)/services/view.h
unitmsgparse.lo unitmsgparse.o: $(srcdir)/testcode/unitmsgparse.c config.h $(srcdir)/util/log.h \
$(srcdir)/testcode/unitmain.h $(srcdir)/util/data/msgparse.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/util/locks.h $(srcdir)/testcode/checklocks.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \
$(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h \
$(srcdir)/util/config_file.h $(srcdir)/util/shm_side/shm_main.h $(srcdir)/util/storage/lookup3.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \
- $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/util/random.h $(srcdir)/util/tube.h \
- $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/respip/respip.h
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/util/tcp_conn_limit.h $(srcdir)/services/listen_dnsport.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/localzone.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/util/random.h \
+ $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/respip/respip.h
remote.lo remote.o: $(srcdir)/daemon/remote.c config.h \
$(srcdir)/daemon/remote.h \
$(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/services/outbound_list.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
$(srcdir)/util/rtt.h $(srcdir)/services/cache/dns.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h \
$(srcdir)/services/localzone.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h \
- $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
- $(srcdir)/validator/autotrust.h $(srcdir)/validator/val_anchor.h $(srcdir)/respip/respip.h \
- $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/libunbound/libworker.h \
- $(srcdir)/sldns/wire2str.h $(srcdir)/util/shm_side/shm_main.h
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/edns.h $(srcdir)/iterator/iter_fwd.h \
+ $(srcdir)/iterator/iter_hints.h $(srcdir)/validator/autotrust.h $(srcdir)/validator/val_anchor.h \
+ $(srcdir)/respip/respip.h $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound-event.h \
+ $(srcdir)/libunbound/libworker.h $(srcdir)/sldns/wire2str.h $(srcdir)/util/shm_side/shm_main.h
testbound.lo testbound.o: $(srcdir)/testcode/testbound.c config.h $(srcdir)/testcode/testpkts.h \
$(srcdir)/testcode/replay.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
$(srcdir)/dnscrypt/cert.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/services/outbound_list.h $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h \
$(srcdir)/util/rtt.h $(srcdir)/services/cache/dns.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h \
$(srcdir)/services/localzone.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/dname.h \
- $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \
- $(srcdir)/validator/autotrust.h $(srcdir)/validator/val_anchor.h $(srcdir)/respip/respip.h \
- $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/libunbound/libworker.h \
- $(srcdir)/sldns/wire2str.h $(srcdir)/util/shm_side/shm_main.h
+ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/edns.h $(srcdir)/iterator/iter_fwd.h \
+ $(srcdir)/iterator/iter_hints.h $(srcdir)/validator/autotrust.h $(srcdir)/validator/val_anchor.h \
+ $(srcdir)/respip/respip.h $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound-event.h \
+ $(srcdir)/libunbound/libworker.h $(srcdir)/sldns/wire2str.h $(srcdir)/util/shm_side/shm_main.h
acl_list.lo acl_list.o: $(srcdir)/daemon/acl_list.c config.h $(srcdir)/daemon/acl_list.h \
$(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/locks.h \
$(srcdir)/util/log.h $(srcdir)/testcode/checklocks.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h \
$(srcdir)/daemon/remote.h \
$(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h \
$(srcdir)/util/config_file.h $(srcdir)/util/shm_side/shm_main.h $(srcdir)/util/storage/lookup3.h \
- $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \
- $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \
- $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/util/random.h $(srcdir)/util/tube.h \
- $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/respip/respip.h
+ $(srcdir)/util/storage/slabhash.h $(srcdir)/util/tcp_conn_limit.h $(srcdir)/services/listen_dnsport.h \
+ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \
+ $(srcdir)/services/localzone.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/util/random.h \
+ $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/respip/respip.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 \
msg->rep->ttl -= adjust;
else msg->rep->ttl = 0;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
for(i=0; i<msg->rep->rrset_count; i++) {
packed_rrset_ttl_subtract((struct packed_rrset_data*)msg->
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for unbound 1.7.3.
+# Generated by GNU Autoconf 2.69 for unbound 1.8.0.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl>.
#
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
-PACKAGE_VERSION='1.7.3'
-PACKAGE_STRING='unbound 1.7.3'
+PACKAGE_VERSION='1.8.0'
+PACKAGE_STRING='unbound 1.8.0'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl'
PACKAGE_URL=''
SYSTEMD_DAEMON_CFLAGS
SYSTEMD_LIBS
SYSTEMD_CFLAGS
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
staticexe
PC_LIBEVENT_DEPENDENCY
UNBOUND_EVENT_UNINSTALL
SWIG_LIB
SWIG
PC_PY_DEPENDENCY
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
PY_MAJOR_VERSION
PYTHON_SITE_PKG
PYTHON_LDFLAGS
# 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.7.3 to adapt to many kinds of systems.
+\`configure' configures unbound 1.8.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.7.3:";;
+ short | recursive ) echo "Configuration of unbound 1.8.0:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-unbound configure 1.7.3
+unbound configure 1.8.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 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.7.3, which was
+It was created by unbound $as_me 1.8.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
UNBOUND_VERSION_MAJOR=1
-UNBOUND_VERSION_MINOR=7
+UNBOUND_VERSION_MINOR=8
-UNBOUND_VERSION_MICRO=3
+UNBOUND_VERSION_MICRO=0
-LIBUNBOUND_CURRENT=7
-LIBUNBOUND_REVISION=11
-LIBUNBOUND_AGE=5
+LIBUNBOUND_CURRENT=8
+LIBUNBOUND_REVISION=0
+LIBUNBOUND_AGE=0
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
# 1.0.2 had 0:14:0
# 1.7.1 had 7:9:5
# 1.7.2 had 7:10:5
# 1.7.3 had 7:11:5
+# 1.7.4 had 8:0:0 # changes the event callback function signature
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
+
+
for ac_prog in flex lex
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
rm -f conftest.l $LEX_OUTPUT_ROOT.c
fi
+if test "$LEX" != "" -a "$LEX" != ":"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for yylex_destroy" >&5
$as_echo_n "checking for yylex_destroy... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }; fi
+$as_echo "no" >&6; };
+ LEX=":"
+ fi
+
+fi
+if test "$LEX" != "" -a "$LEX" != ":"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lex %option" >&5
+$as_echo_n "checking for lex %option... " >&6; }
+ if cat <<EOF | $LEX -t 2>&1 | grep yy_delete_buffer >/dev/null 2>&1; then
+%option nounput
+%%
+EOF
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+ LEX=":"
+ fi
+fi
for ac_prog in 'bison -y' byacc
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
CPPFLAGS="$PYTHON_CPPFLAGS"
fi
ub_have_python=yes
- PC_PY_DEPENDENCY="python"
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+fi
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\"python\${PY_MAJOR_VERSION}\"\""; } >&5
+ ($PKG_CONFIG --exists --print-errors ""python${PY_MAJOR_VERSION}"") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ PC_PY_DEPENDENCY="python${PY_MAJOR_VERSION}"
+else
+ PC_PY_DEPENDENCY="python"
+fi
# Check for SWIG
withval="no"
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libhiredis" >&5
-$as_echo_n "checking for libhiredis... " >&6; }
found_libhiredis="no"
if test x_$withval = x_yes -o x_$withval != x_no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libhiredis" >&5
+$as_echo_n "checking for libhiredis... " >&6; }
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
fi
fi
have_systemd=no
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $PKG_CONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
- ac_pt_PKG_CONFIG=$PKG_CONFIG
- # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $ac_pt_PKG_CONFIG in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
- if test "x$ac_pt_PKG_CONFIG" = x; then
- PKG_CONFIG=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- PKG_CONFIG=$ac_pt_PKG_CONFIG
- fi
-else
- PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
-fi
-
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=0.9.0
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
- else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
- PKG_CONFIG=""
- fi
-fi
if test "x$enable_systemd" != xno; then :
-version=1.7.3
+version=1.8.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.7.3, which was
+This file was extended by unbound $as_me 1.8.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-unbound config.status 1.7.3
+unbound config.status 1.8.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
-m4_define([VERSION_MINOR],[7])
-m4_define([VERSION_MICRO],[3])
+m4_define([VERSION_MINOR],[8])
+m4_define([VERSION_MICRO],[0])
AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl, unbound)
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
-LIBUNBOUND_CURRENT=7
-LIBUNBOUND_REVISION=11
-LIBUNBOUND_AGE=5
+LIBUNBOUND_CURRENT=8
+LIBUNBOUND_REVISION=0
+LIBUNBOUND_AGE=0
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
# 1.0.2 had 0:14:0
# 1.7.1 had 7:9:5
# 1.7.2 had 7:10:5
# 1.7.3 had 7:11:5
+# 1.7.4 had 8:0:0 # changes the event callback function signature
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
if echo %% | $LEX -t 2>&1 | grep yylex_destroy >/dev/null 2>&1; then
AC_DEFINE(LEX_HAS_YYLEX_DESTROY, 1, [if lex has yylex_destroy])
AC_MSG_RESULT(yes)
- else AC_MSG_RESULT(no); fi
+ else AC_MSG_RESULT(no);
+ LEX=":"
+ fi
+])
+
+AC_DEFUN([ACX_YYLEX_OPTION], [
+ AC_MSG_CHECKING([for lex %option])
+ if cat <<EOF | $LEX -t 2>&1 | grep yy_delete_buffer >/dev/null 2>&1; then
+%option nounput
+%%
+EOF
+ AC_MSG_RESULT(yes)
+ else AC_MSG_RESULT(no);
+ LEX=":"
+ fi
])
AC_PROG_LEX
+if test "$LEX" != "" -a "$LEX" != ":"; then
ACX_YYLEX_DESTROY
+fi
+if test "$LEX" != "" -a "$LEX" != ":"; then
+ACX_YYLEX_OPTION
+fi
AC_PROG_YACC
AC_CHECK_PROG(doxygen, doxygen, doxygen)
AC_CHECK_TOOL(STRIP, strip)
CPPFLAGS="$PYTHON_CPPFLAGS"
fi
ub_have_python=yes
- PC_PY_DEPENDENCY="python"
+ PKG_PROG_PKG_CONFIG
+ PKG_CHECK_EXISTS(["python${PY_MAJOR_VERSION}"],
+ [PC_PY_DEPENDENCY="python${PY_MAJOR_VERSION}"],
+ [PC_PY_DEPENDENCY="python"])
AC_SUBST(PC_PY_DEPENDENCY)
# Check for SWIG
AC_ARG_WITH(libhiredis, AC_HELP_STRING([--with-libhiredis=path],
[specify explicit path for libhiredis.]),
[ ],[ withval="no" ])
-AC_MSG_CHECKING(for libhiredis)
found_libhiredis="no"
if test x_$withval = x_yes -o x_$withval != x_no; then
+ AC_MSG_CHECKING(for libhiredis)
if test x_$withval = x_ -o x_$withval = x_yes; then
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
fi
rep.qdcount = (uint16_t)qdcount;
rep.ttl = (time_t)ttl;
rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
+ rep.serve_expired_ttl = rep.ttl + SERVE_EXPIRED_TTL;
rep.security = (enum sec_status)security;
if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
log_warn("error too many rrsets");
#include "util/shm_side/shm_main.h"
#include "util/storage/lookup3.h"
#include "util/storage/slabhash.h"
+#include "util/tcp_conn_limit.h"
#include "services/listen_dnsport.h"
#include "services/cache/rrset.h"
#include "services/cache/infra.h"
/** cleaner ssl memory freeup */
static void* comp_meth = NULL;
#endif
-#ifdef LEX_HAS_YYLEX_DESTROY
/** remove buffers for parsing and init */
int ub_c_lex_destroy(void);
-#endif
/** used when no other sighandling happens, so we don't die
* when multiple signals in quick succession are sent to us.
signal_handling_playback(struct worker* wrk)
{
#ifdef SIGHUP
- if(sig_record_reload) {
-# ifdef HAVE_SYSTEMD
- sd_notify(0, "RELOADING=1");
-# endif
+ if(sig_record_reload)
worker_sighandler(SIGHUP, wrk);
-# ifdef HAVE_SYSTEMD
- sd_notify(0, "READY=1");
-# endif
- }
#endif
if(sig_record_quit)
worker_sighandler(SIGTERM, wrk);
free(daemon);
return NULL;
}
+ daemon->tcl = tcl_list_create();
+ if(!daemon->tcl) {
+ acl_list_delete(daemon->acl);
+ edns_known_options_delete(daemon->env);
+ free(daemon->env);
+ free(daemon);
+ return NULL;
+ }
if(gettimeofday(&daemon->time_boot, NULL) < 0)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
if((daemon->env->auth_zones = auth_zones_create()) == 0) {
acl_list_delete(daemon->acl);
+ tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
free(daemon->env);
free(daemon);
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views))
fatal_exit("Could not setup access control list");
+ if(!tcl_list_apply_cfg(daemon->tcl, daemon->cfg))
+ fatal_exit("Could not setup TCP connection limits");
if(daemon->cfg->dnscrypt) {
#ifdef USE_DNSCRYPT
daemon->dnscenv = dnsc_create();
/* Start resolver service on main thread. */
#ifdef HAVE_SYSTEMD
- sd_notify(0, "READY=1");
+ if(daemon->cfg->use_systemd)
+ sd_notify(0, "READY=1");
#endif
log_info("start of service (%s).", PACKAGE_STRING);
worker_work(daemon->workers[0]);
#ifdef HAVE_SYSTEMD
- sd_notify(0, "STOPPING=1");
+ if(daemon->cfg->use_systemd) {
+ if (daemon->workers[0]->need_to_exit)
+ sd_notify(0, "STOPPING=1");
+ else
+ sd_notify(0, "RELOADING=1");
+ }
#endif
log_info("service stopped (%s).", PACKAGE_STRING);
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
+ tcl_list_delete(daemon->tcl);
free(daemon->chroot);
free(daemon->pidfile);
free(daemon->env);
SSL_CTX_free((SSL_CTX*)daemon->connect_sslctx);
#endif
free(daemon);
-#ifdef LEX_HAS_YYLEX_DESTROY
/* lex cleanup */
ub_c_lex_destroy();
-#endif
/* libcrypto cleanup */
#ifdef HAVE_SSL
# if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST)
{
daemon->cfg = cfg;
config_apply(cfg);
- if(!daemon->env->msg_cache ||
- cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) ||
- cfg->msg_cache_slabs != daemon->env->msg_cache->size) {
+ if(!slabhash_is_size(daemon->env->msg_cache, cfg->msg_cache_size,
+ cfg->msg_cache_slabs)) {
slabhash_delete(daemon->env->msg_cache);
daemon->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
struct module_stack mods;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
+ /** TCP connection limit, limit connections from client IPs */
+ struct tcl_list* tcl;
/** local authority zones */
struct local_zones* local_zones;
/** last time of statistics printout */
(unsigned long)s->svr.qtcp)) return 0;
if(!ssl_printf(ssl, "num.query.tcpout"SQ"%lu\n",
(unsigned long)s->svr.qtcp_outgoing)) return 0;
+ if(!ssl_printf(ssl, "num.query.tls"SQ"%lu\n",
+ (unsigned long)s->svr.qtls)) return 0;
if(!ssl_printf(ssl, "num.query.ipv6"SQ"%lu\n",
(unsigned long)s->svr.qipv6)) return 0;
/* flags */
(unsigned long)s->svr.num_query_authzone_up)) return 0;
if(!ssl_printf(ssl, "num.query.authzone.down"SQ"%lu\n",
(unsigned long)s->svr.num_query_authzone_down)) return 0;
+#ifdef CLIENT_SUBNET
+ if(!ssl_printf(ssl, "num.query.subnet"SQ"%lu\n",
+ (unsigned long)s->svr.num_query_subnet)) return 0;
+ if(!ssl_printf(ssl, "num.query.subnet_cache"SQ"%lu\n",
+ (unsigned long)s->svr.num_query_subnet_cache)) return 0;
+#endif /* CLIENT_SUBNET */
return 1;
}
if(d->ttl > inf->expired) {
d->ttl = inf->expired;
d->prefetch_ttl = inf->expired;
+ d->serve_expired_ttl = inf->expired;
inf->num_msgs++;
}
}
return NULL;
}
} else {
+#ifndef HAVE_SSL_SET1_HOST
+ if(auth_name)
+ log_err("no name verification functionality in "
+ "ssl library, ignored name for %s", todo);
+#endif
/* add address */
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
auth_name)) {
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
}
+/** do the auth_zone_reload command */
+static void
+do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
+{
+ size_t nmlen;
+ int nmlabs;
+ uint8_t* nm = NULL;
+ struct auth_zones* az = worker->env.auth_zones;
+ struct auth_zone* z = NULL;
+ if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
+ return;
+ if(az) {
+ lock_rw_rdlock(&az->lock);
+ z = auth_zone_find(az, nm, nmlen, LDNS_RR_CLASS_IN);
+ if(z) {
+ lock_rw_wrlock(&z->lock);
+ }
+ lock_rw_unlock(&az->lock);
+ }
+ free(nm);
+ if(!z) {
+ (void)ssl_printf(ssl, "error no auth-zone %s\n", arg);
+ return;
+ }
+ if(!auth_zone_read_zonefile(z)) {
+ lock_rw_unlock(&z->lock);
+ (void)ssl_printf(ssl, "error failed to read %s\n", arg);
+ return;
+ }
+ lock_rw_unlock(&z->lock);
+ send_ok(ssl);
+}
+
+/** do the auth_zone_transfer command */
+static void
+do_auth_zone_transfer(RES* ssl, struct worker* worker, char* arg)
+{
+ size_t nmlen;
+ int nmlabs;
+ uint8_t* nm = NULL;
+ struct auth_zones* az = worker->env.auth_zones;
+ if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
+ return;
+ if(!az || !auth_zones_startprobesequence(az, &worker->env, nm, nmlen,
+ LDNS_RR_CLASS_IN)) {
+ (void)ssl_printf(ssl, "error zone xfr task not found %s\n", arg);
+ return;
+ }
+ send_ok(ssl);
+}
+
/** do the set_option command */
static void
do_set_option(RES* ssl, struct worker* worker, char* arg)
} else if(cmdcmp(p, "list_auth_zones", 15)) {
do_list_auth_zones(ssl, worker->env.auth_zones);
return;
+ } else if(cmdcmp(p, "auth_zone_reload", 16)) {
+ do_auth_zone_reload(ssl, worker, skipwhite(p+16));
+ return;
+ } else if(cmdcmp(p, "auth_zone_transfer", 18)) {
+ do_auth_zone_transfer(ssl, worker, skipwhite(p+18));
+ return;
} else if(cmdcmp(p, "stub_add", 8)) {
/* must always distribute this cmd */
if(rc) distribute_cmd(rc, ssl, cmd);
#include "services/authzone.h"
#include "validator/val_kcache.h"
#include "validator/val_neg.h"
+#ifdef CLIENT_SUBNET
+#include "edns-subnet/subnetmod.h"
+#endif
/** add timers and the values do not overflow or become negative */
static void
(unsigned)worker->env.mesh->stats_jostled);
}
+
+#ifdef CLIENT_SUBNET
+/** Set the EDNS Subnet stats. */
+static void
+set_subnet_stats(struct worker* worker, struct ub_server_stats* svr,
+ int reset)
+{
+ int m = modstack_find(&worker->env.mesh->mods, "subnet");
+ struct subnet_env* sne;
+ if(m == -1)
+ return;
+ sne = (struct subnet_env*)worker->env.modinfo[m];
+ if(reset && !worker->env.cfg->stat_cumulative) {
+ lock_rw_wrlock(&sne->biglock);
+ } else {
+ lock_rw_rdlock(&sne->biglock);
+ }
+ svr->num_query_subnet = (long long)(sne->num_msg_nocache + sne->num_msg_cache);
+ svr->num_query_subnet_cache = (long long)sne->num_msg_cache;
+ if(reset && !worker->env.cfg->stat_cumulative) {
+ sne->num_msg_cache = 0;
+ sne->num_msg_nocache = 0;
+ }
+ lock_rw_unlock(&sne->biglock);
+}
+#endif /* CLIENT_SUBNET */
+
/** Set the neg cache stats. */
static void
set_neg_cache_stats(struct worker* worker, struct ub_server_stats* svr,
/* Set neg cache usage numbers */
set_neg_cache_stats(worker, &s->svr, reset);
+#ifdef CLIENT_SUBNET
+ /* EDNS Subnet usage numbers */
+ set_subnet_stats(worker, &s->svr, reset);
+#else
+ s->svr.num_query_subnet = 0;
+ s->svr.num_query_subnet_cache = 0;
+#endif
/* get tcp accept usage */
s->svr.tcp_accept_usage = 0;
total->svr.qclass_big += a->svr.qclass_big;
total->svr.qtcp += a->svr.qtcp;
total->svr.qtcp_outgoing += a->svr.qtcp_outgoing;
+ total->svr.qtls += a->svr.qtls;
total->svr.qipv6 += a->svr.qipv6;
total->svr.qbit_QR += a->svr.qbit_QR;
total->svr.qbit_AA += a->svr.qbit_AA;
stats->qclass[qclass]++;
else stats->qclass_big++;
stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++;
- if(c->type != comm_udp)
+ if(c->type != comm_udp) {
stats->qtcp++;
+ if(c->ssl != NULL)
+ stats->qtls++;
+ }
if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
stats->qipv6++;
if( (flags&BIT_QR) )
printf("-c file config file to read instead of %s\n", CONFIGFILE);
printf(" file format is described in unbound.conf(5).\n");
printf("-d do not fork into the background.\n");
+ printf("-p do not create a pidfile.\n");
printf("-v verbose (more times to increase verbosity)\n");
#ifdef UB_ON_WINDOWS
printf("-w opt windows option: \n");
fatal_exit("Could not alloc config defaults");
if(!config_read(cfg, cfgfile, daemon->chroot)) {
if(errno != ENOENT)
- fatal_exit("Could not read config file: %s",
- cfgfile);
+ fatal_exit("Could not read config file: %s."
+ " Maybe try unbound -dd, it stays on "
+ "the commandline to see more errors, "
+ "or unbound-checkconf", cfgfile);
log_warn("Continuing with default config settings");
}
apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity);
#include "util/data/dname.h"
#include "util/fptr_wlist.h"
#include "util/tube.h"
+#include "util/edns.h"
#include "iterator/iter_fwd.h"
#include "iterator/iter_hints.h"
#include "validator/autotrust.h"
* Then check if it needs validation, if so, this routine fails,
* so that iterator can prime and validator can verify rrsets.
*/
+ struct edns_data edns_bak;
uint16_t udpsize = edns->udp_size;
int secure = 0;
time_t timenow = *worker->env.now;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL,
- msg->rep, LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+ msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
return 0;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
}
}
/* return this delegation from the cache */
+ edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep,
- (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
return 0;
msg->rep->flags |= BIT_QR|BIT_RA;
- if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
+ if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
+ repinfo->c, worker->scratchpad) ||
+ !reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
repinfo->c->buffer, 0, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns)
{
+ struct edns_data edns_bak;
time_t timenow = *worker->env.now;
uint16_t udpsize = edns->udp_size;
struct reply_info* encode_rep = rep;
&& worker->env.need_to_validate;
*partial_repp = NULL; /* avoid accidental further pass */
if(worker->env.cfg->serve_expired) {
- /* always lock rrsets, rep->ttl is ignored */
+ if(worker->env.cfg->serve_expired_ttl &&
+ rep->serve_expired_ttl < timenow)
+ return 0;
if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
return 0;
/* below, rrsets with ttl before timenow become TTL 0 in
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
- LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
goto bail_out;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
}
} else secure = 0;
+ edns_bak = *edns;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep,
- (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad))
+ (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if(worker->daemon->use_response_ip && !partial_rep &&
if(!*partial_repp)
goto bail_out;
}
- } else if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
+ } else if(!apply_edns_options(edns, &edns_bak, worker->env.cfg,
+ repinfo->c, worker->scratchpad) ||
+ !reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
+ LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
* @param num: number of strings in array.
* @param edns: edns reply information.
* @param worker: worker with scratch region.
+ * @param repinfo: reply information for a communication point.
*/
static void
chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
- struct worker* worker)
+ struct worker* worker, struct comm_reply* repinfo)
{
int i;
unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
- LDNS_RCODE_NOERROR, edns, worker->scratchpad))
+ LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad))
edns->opt_list = NULL;
if(sldns_buffer_capacity(pkt) >=
sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
/** Reply with one string */
static void
chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns,
- struct worker* worker)
+ struct worker* worker, struct comm_reply* repinfo)
{
- chaos_replystr(pkt, (char**)&str, 1, edns, worker);
+ chaos_replystr(pkt, (char**)&str, 1, edns, worker, repinfo);
}
/**
* @param pkt: buffer
* @param edns: edns reply information.
* @param w: worker with scratch region.
+ * @param repinfo: reply information for a communication point.
*/
static void
-chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w)
+chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w,
+ struct comm_reply* repinfo)
{
#define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */
#define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */
if(!w->env.need_to_validate) {
/* no validator module, reply no trustanchors */
- chaos_replystr(pkt, NULL, 0, edns, w);
+ chaos_replystr(pkt, NULL, 0, edns, w, repinfo);
return;
}
}
lock_basic_unlock(&w->env.anchors->lock);
- chaos_replystr(pkt, str_array, num, edns, w);
+ chaos_replystr(pkt, str_array, num, edns, w, repinfo);
regional_free_all(w->scratchpad);
}
* @param w: worker
* @param qinfo: query info. Pointer into packet buffer.
* @param edns: edns info from query.
+ * @param repinfo: reply information for a communication point.
* @param pkt: packet buffer.
* @return: true if a reply is to be sent.
*/
static int
-answer_chaos(struct worker* w, struct query_info* qinfo,
- struct edns_data* edns, sldns_buffer* pkt)
+answer_chaos(struct worker* w, struct query_info* qinfo,
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* pkt)
{
struct config_file* cfg = w->env.cfg;
if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT)
char buf[MAXHOSTNAMELEN+1];
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
buf[MAXHOSTNAMELEN] = 0;
- chaos_replyonestr(pkt, buf, edns, w);
+ chaos_replyonestr(pkt, buf, edns, w, repinfo);
} else {
log_err("gethostname: %s", strerror(errno));
- chaos_replyonestr(pkt, "no hostname", edns, w);
+ chaos_replyonestr(pkt, "no hostname", edns, w, repinfo);
}
}
- else chaos_replyonestr(pkt, cfg->identity, edns, w);
+ else chaos_replyonestr(pkt, cfg->identity, edns, w, repinfo);
return 1;
}
if(query_dname_compare(qinfo->qname,
if(cfg->hide_version)
return 0;
if(cfg->version==NULL || cfg->version[0]==0)
- chaos_replyonestr(pkt, PACKAGE_STRING, edns, w);
- else chaos_replyonestr(pkt, cfg->version, edns, w);
+ chaos_replyonestr(pkt, PACKAGE_STRING, edns, w, repinfo);
+ else chaos_replyonestr(pkt, cfg->version, edns, w, repinfo);
return 1;
}
if(query_dname_compare(qinfo->qname,
{
if(cfg->hide_trustanchor)
return 0;
- chaos_trustanchor(pkt, edns, w);
+ chaos_trustanchor(pkt, edns, w, repinfo);
return 1;
}
server_stats_insrcode(&worker->stats, c->buffer);
goto send_reply;
}
- if(edns.edns_present && edns.edns_version != 0) {
- edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
- edns.edns_version = EDNS_ADVERTISED_VERSION;
- edns.udp_size = EDNS_ADVERTISED_SIZE;
- edns.bits &= EDNS_DO;
- edns.opt_list = NULL;
- verbose(VERB_ALGO, "query with bad edns version.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
- error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
- *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
- sldns_buffer_read_u16_at(c->buffer, 2), NULL);
- if(sldns_buffer_capacity(c->buffer) >=
- sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
- attach_edns_record(c->buffer, &edns);
- regional_free_all(worker->scratchpad);
- goto send_reply;
- }
- if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
- worker->daemon->cfg->harden_short_bufsize) {
- verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
- (int)edns.udp_size);
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
- edns.udp_size = NORMAL_UDP_SIZE;
+ if(edns.edns_present) {
+ struct edns_option* edns_opt;
+ if(edns.edns_version != 0) {
+ edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
+ edns.edns_version = EDNS_ADVERTISED_VERSION;
+ edns.udp_size = EDNS_ADVERTISED_SIZE;
+ edns.bits &= EDNS_DO;
+ edns.opt_list = NULL;
+ verbose(VERB_ALGO, "query with bad edns version.");
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
+ *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+ sldns_buffer_read_u16_at(c->buffer, 2), NULL);
+ if(sldns_buffer_capacity(c->buffer) >=
+ sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
+ attach_edns_record(c->buffer, &edns);
+ regional_free_all(worker->scratchpad);
+ goto send_reply;
+ }
+ if(edns.udp_size < NORMAL_UDP_SIZE &&
+ worker->daemon->cfg->harden_short_bufsize) {
+ verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
+ (int)edns.udp_size);
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ edns.udp_size = NORMAL_UDP_SIZE;
+ }
+ if(c->type != comm_udp) {
+ edns_opt = edns_opt_list_find(edns.opt_list, LDNS_EDNS_KEEPALIVE);
+ if(edns_opt && edns_opt->opt_len > 0) {
+ edns.ext_rcode = 0;
+ edns.edns_version = EDNS_ADVERTISED_VERSION;
+ edns.udp_size = EDNS_ADVERTISED_SIZE;
+ edns.bits &= EDNS_DO;
+ edns.opt_list = NULL;
+ verbose(VERB_ALGO, "query with bad edns keepalive.");
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo,
+ *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+ sldns_buffer_read_u16_at(c->buffer, 2), NULL);
+ if(sldns_buffer_capacity(c->buffer) >=
+ sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
+ attach_edns_record(c->buffer, &edns);
+ regional_free_all(worker->scratchpad);
+ goto send_reply;
+ }
+ }
}
if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
c->type == comm_udp) {
if(c->type != comm_udp)
edns.udp_size = 65535; /* max size for TCP replies */
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
- &edns, c->buffer)) {
+ &edns, repinfo, c->buffer)) {
server_stats_insrcode(&worker->stats, c->buffer);
regional_free_all(worker->scratchpad);
goto send_reply;
}
if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env,
- &qinfo, &edns, c->buffer, worker->scratchpad)) {
+ &qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
worker->comsig = NULL;
}
worker->front = listen_create(worker->base, ports,
- cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
- worker->daemon->listen_sslctx, dtenv, worker_handle_request,
- worker);
+ cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
+ cfg->do_tcp_keepalive
+ ? cfg->tcp_keepalive_timeout
+ : cfg->tcp_idle_timeout,
+ worker->daemon->tcl,
+ worker->daemon->listen_sslctx,
+ dtenv, worker_handle_request, worker);
if(!worker->front) {
log_err("could not create listening sockets");
worker_delete(worker);
}
void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
- sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
- sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
- sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
{
- log_assert(0);
- return 0;
+ log_assert(0);
+ return 0;
}
int codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
- log_assert(0);
- return 0;
+ log_assert(0);
+ return 0;
}
#include "util/fptr_wlist.h"
#include "util/net_help.h"
#include "util/regional.h"
+#include "util/storage/dnstree.h"
+#include "util/data/dname.h"
+#include "sldns/str2wire.h"
/******************************************************************************
* *
* This is the CIDR length of the prefix. It needs to be between 0 and 96.
*/
int prefix_net;
+
+ /**
+ * Tree of names for which AAAA is ignored. always synthesize from A.
+ */
+ rbtree_type ignore_aaaa;
};
* *
******************************************************************************/
+/**
+ * insert ignore_aaaa element into the tree
+ * @param dns64_env: module env.
+ * @param str: string with domain name.
+ * @return false on failure.
+ */
+static int
+dns64_insert_ignore_aaaa(struct dns64_env* dns64_env, char* str)
+{
+ /* parse and insert element */
+ struct name_tree_node* node;
+ node = (struct name_tree_node*)calloc(1, sizeof(*node));
+ if(!node) {
+ log_err("out of memory");
+ return 0;
+ }
+ node->name = sldns_str2wire_dname(str, &node->len);
+ if(!node->name) {
+ free(node);
+ log_err("cannot parse dns64-ignore-aaaa: %s", str);
+ return 0;
+ }
+ node->labs = dname_count_labels(node->name);
+ node->dclass = LDNS_RR_CLASS_IN;
+ if(!name_tree_insert(&dns64_env->ignore_aaaa, node,
+ node->name, node->len, node->labs, node->dclass)) {
+ /* ignore duplicate element */
+ free(node->name);
+ free(node);
+ return 1;
+ }
+ return 1;
+}
+
/**
* This function applies the configuration found in the parsed configuration
* file \a cfg to this instance of the dns64 module. Currently only the DNS64
static int
dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg)
{
+ struct config_strlist* s;
verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix);
if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix :
DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr,
cfg->dns64_prefix);
return 0;
}
+ for(s = cfg->dns64_ignore_aaaa; s; s = s->next) {
+ if(!dns64_insert_ignore_aaaa(dns64_env, s->str))
+ return 0;
+ }
+ name_tree_init_parents(&dns64_env->ignore_aaaa);
return 1;
}
log_err("malloc failure");
return 0;
}
- env->modinfo[id] = (void*)dns64_env;
+ env->modinfo[id] = (void*)dns64_env;
+ name_tree_init(&dns64_env->ignore_aaaa);
if (!dns64_apply_cfg(dns64_env, env->cfg)) {
log_err("dns64: could not apply configuration settings.");
return 0;
return 1;
}
+/** free ignore AAAA elements */
+static void
+free_ignore_aaaa_node(rbnode_type* node, void* ATTR_UNUSED(arg))
+{
+ struct name_tree_node* n = (struct name_tree_node*)node;
+ if(!n) return;
+ free(n->name);
+ free(n);
+}
+
/**
* Deinitializes this instance of the dns64 module.
*
void
dns64_deinit(struct module_env* env, int id)
{
+ struct dns64_env* dns64_env;
if (!env)
return;
+ dns64_env = (struct dns64_env*)env->modinfo[id];
+ if(dns64_env) {
+ traverse_postorder(&dns64_env->ignore_aaaa, free_ignore_aaaa_node,
+ NULL);
+ }
free(env->modinfo[id]);
env->modinfo[id] = NULL;
}
return module_wait_subquery;
}
+/**
+ * See if query name is in the always synth config.
+ * The ignore-aaaa list has names for which the AAAA for the domain is
+ * ignored and the A is always used to create the answer.
+ * @param qstate: query state.
+ * @param id: module id.
+ * @return true if the name is covered by ignore-aaaa.
+ */
+static int
+dns64_always_synth_for_qname(struct module_qstate* qstate, int id)
+{
+ struct dns64_env* dns64_env = (struct dns64_env*)qstate->env->modinfo[id];
+ int labs = dname_count_labels(qstate->qinfo.qname);
+ struct name_tree_node* node = name_tree_lookup(&dns64_env->ignore_aaaa,
+ qstate->qinfo.qname, qstate->qinfo.qname_len, labs,
+ qstate->qinfo.qclass);
+ return (node != NULL);
+}
+
/**
* Handles the "pass" event for a query. This event is received when a new query
* is received by this module. The query may have been generated internally by
&& qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)
return generate_type_A_query(qstate, id);
+ if(dns64_always_synth_for_qname(qstate, id) &&
+ (uintptr_t)qstate->minfo[id] == DNS64_NEW_QUERY
+ && !(qstate->query_flags & BIT_CD)
+ && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) {
+ verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
+ return generate_type_A_query(qstate, id);
+ }
+
/* We are finished when our sub-query is finished. */
if ((uintptr_t)qstate->minfo[id] == DNS64_SUBQUERY_FINISHED)
return module_finished;
* synthesize in (sec 5.1.2 of RFC6147).
* - A successful AAAA query with an answer.
*/
- if ( (enum dns64_qstate)qstate->minfo[id] == DNS64_INTERNAL_QUERY
- || qstate->qinfo.qtype != LDNS_RR_TYPE_AAAA
- || (qstate->query_flags & BIT_CD)
- || (qstate->return_msg &&
+ if((enum dns64_qstate)qstate->minfo[id] != DNS64_INTERNAL_QUERY
+ && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA
+ && !(qstate->query_flags & BIT_CD)
+ && !(qstate->return_msg &&
qstate->return_msg->rep &&
reply_find_answer_rrset(&qstate->qinfo,
qstate->return_msg->rep)))
- return module_finished;
+ /* not internal, type AAAA, not CD, and no answer RRset,
+ * So, this is a AAAA noerror/nodata answer */
+ return generate_type_A_query(qstate, id);
+
+ if((enum dns64_qstate)qstate->minfo[id] != DNS64_INTERNAL_QUERY
+ && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA
+ && !(qstate->query_flags & BIT_CD)
+ && dns64_always_synth_for_qname(qstate, id)) {
+ /* if it is not internal, AAAA, not CD and listed domain,
+ * generate from A record and ignore AAAA */
+ verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway");
+ return generate_type_A_query(qstate, id);
+ }
- /* So, this is a AAAA noerror/nodata answer */
- return generate_type_A_query(qstate, id);
+ /* do nothing */
+ return module_finished;
}
/**
* Build the actual reply.
*/
cp = construct_reply_info_base(super->region, rep->flags, rep->qdcount,
- rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, rep->ns_numrrsets,
- rep->ar_numrrsets, rep->rrset_count, rep->security);
+ rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl,
+ rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
+ rep->rrset_count, rep->security);
if(!cp)
return;
rrset_cache_remove(super->env->rrset_cache, dk->rk.dname,
dk->rk.dname_len, LDNS_RR_TYPE_AAAA,
LDNS_RR_CLASS_IN, 0);
+ /* Delete negative AAAA in msg cache for CNAMEs,
+ * stored by the iterator module */
+ if(i != 0) /* if not the first RR */
+ msg_cache_remove(super->env, dk->rk.dname,
+ dk->rk.dname_len, LDNS_RR_TYPE_AAAA,
+ LDNS_RR_CLASS_IN, 0);
} else {
dk->entry.hash = fk->entry.hash;
dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
+4 September 2018: Wouter
+ - Tag for 1.8.0rc1 release.
+
+31 August 2018: Wouter
+ - Disable minimal-responses in subnet unit tests.
+
+30 August 2018: Wouter
+ - Fix that a local-zone with a local-zone-type that is transparent
+ in a view with view-first, makes queries check for answers from the
+ local-zones defined outside of views.
+
+28 August 2018: Ralph
+ - Disable minimal-responses in ipsecmod unit tests.
+ - Added serve-expired-ttl and serve-expired-ttl-reset options.
+
+27 August 2018: Wouter
+ - Set defaults to yes for a number of options to increase speed and
+ resilience of the server. The so-reuseport, harden-below-nxdomain,
+ and minimal-responses options are enabled by default. They used
+ to be disabled by default, waiting to make sure they worked. They
+ are enabled by default now, and can be disabled explicitly by
+ setting them to "no" in the unbound.conf config file. The reuseport
+ and minimal options increases speed of the server, and should be
+ otherwise harmless. The harden-below-nxdomain option works well
+ together with the recently default enabled qname minimisation, this
+ causes more fetches to use information from the cache.
+ - next release is called 1.8.0.
+ - Fix lintflags for lint on FreeBSD.
+
+22 August 2018: George
+ - #4140: Expose repinfo (comm_reply) to the inplace_callbacks. This
+ gives access to reply information for the client's communication
+ point when the callback is called before the mesh state (modules).
+ Changes to C and Python's inplace_callback signatures were also
+ necessary.
+
+21 August 2018: Wouter
+ - log-local-actions: yes option for unbound.conf that logs all the
+ local zone actions, a patch from Saksham Manchanda (Secure64).
+ - #4146: num.query.subnet and num.query.subnet_cache counters.
+ - Fix only misc failure from log-servfail when val-log-level is not
+ enabled.
+
+17 August 2018: Ralph
+ - Fix classification for QTYPE=CNAME queries when QNAME minimisation is
+ enabled.
+
+17 August 2018: Wouter
+ - Set libunbound to increase current, because the libunbound change
+ to the event callback function signature. That needs programs,
+ that use it, to recompile against the new header definition.
+ - print servfail info to log as error.
+ - added more servfail printout statements, to the iterator.
+ - log-servfail: yes prints log lines that say why queries are
+ returning SERVFAIL to clients.
+
+16 August 2018: Wouter
+ - Fix warning on compile without threads.
+ - Fix contrib/fastrpz.patch.
+
+15 August 2018: Wouter
+ - Fix segfault in auth-zone read and reorder of RRSIGs.
+
+14 August 2018: Wouter
+ - Fix that printout of error for cycle targets is a verbosity 4
+ printout and does not wrongly print it is a memory error.
+ - Upgraded crosscompile script to include libunbound DLL in the
+ zipfile.
+
+10 August 2018: Wouter
+ - Fix #4144: dns64 module caches wrong (negative) information.
+
+9 August 2018: Wouter
+ - unbound-checkconf checks if modules exist and prints if they are
+ not compiled in the name of the wrong module.
+ - document --enable-subnet in doc/README.
+ - Patch for stub-no-cache and forward-no-cache options that disable
+ caching for the contents of that stub or forward, for when you
+ want immediate changes visible, from Bjoern A. Zeeb.
+
+7 August 2018: Ralph
+ - Make capsforid fallback QNAME minimisation aware.
+
+7 August 2018: Wouter
+ - Fix #4142: unbound.service.in: improvements and fixes.
+ Add unit dependency ordering (based on systemd-resolved).
+ Add 'CAP_SYS_RESOURCE' to 'CapabilityBoundingSet' (fixes warnings
+ about missing privileges during startup). Add 'AF_INET6' to
+ 'RestrictAddressFamilies' (without it IPV6 can't work). From
+ Guido Shanahan.
+ - Patch to implement tcp-connection-limit from Jim Hague (Sinodun).
+ This limits the number of simultaneous TCP client connections
+ from a nominated netblock.
+ - make depend, yacc, lex, doc, headers. And log the limit exceeded
+ message only on high verbosity, so as to not spam the logs when
+ it is busy.
+
+6 August 2018: Wouter
+ - Fix for #4136: Fix to unconditionally call destroy in daemon.c.
+
+3 August 2018: George
+ - Expose if a query (or a subquery) was ratelimited (not src IP
+ ratelimiting) to libunbound under 'ub_result.was_ratelimited'.
+ This also introduces a change to 'ub_event_callback_type' in
+ libunbound/unbound-event.h.
+ - Tidy pylib tests.
+
+3 August 2018: Wouter
+ - Revert previous change for #4136: because it introduces build
+ problems.
+ - New fix for #4136: This one ignores lex without without
+ yylex_destroy.
+
+1 August 2018: Wouter
+ - Fix to remove systemd sockaddr function check, that is not
+ always present. Make socket activation more lenient. But not
+ different when socket activation is not used.
+ - iana port list update.
+
+31 July 2018: Wouter
+ - Patches from Jim Hague (Sinodun) for EDNS KeepAlive.
+ - Sort out test runs when the build directory isn't the project
+ root directory.
+ - Add config tcp-idle-timeout (default 30s). This applies to
+ client connections only; the timeout on TCP connections upstream
+ is unaffected.
+ - Error if EDNS Keepalive received over UDP.
+ - Add edns-tcp-keepalive and edns-tcp-keepalive timeout options
+ and implement option in client responses.
+ - Correct and expand manual page entries for keepalive and idle timeout.
+ - Implement progressive backoff of TCP idle/keepalive timeout.
+ - Fix 'make depend' to work when build dir is not project root.
+ - Add delay parameter to streamtcp, -d secs.
+ To be used when testing idle timeout.
+ - From Wouter: make depend, the dependencies in the patches did not
+ apply cleanly. Also remade yacc and lex.
+ - Fix mesh.c incompatible pointer pass.
+ - Please doxygen so it passes.
+ - Fix #4139: Fix unbound-host leaks memory on ANY.
+
+30 July 2018: Wouter
+ - Fix #4136: insufficiency from mismatch of FLEX capability between
+ released tarball and build host.
+
+27 July 2018: Wouter
+ - Fix man page, say that chroot is enabled by default.
+
+26 July 2018: Wouter
+ - Fix #4135: 64-bit Windows Installer Creates Entries Under The
+ Wrong Registry Key, reported by Brian White.
+
+23 July 2018: Wouter
+ - Fix use-systemd readiness signalling, only when use-systemd is yes
+ and not in signal handler.
+
+20 July 2018: Wouter
+ - Fix #4130: print text describing -dd and unbound-checkconf on
+ config file read error at startup, the errors may have been moved
+ away by the startup process.
+ - Fix #4131: for solaris, error YY_CURRENT_BUFFER undeclared.
+
+19 July 2018: Wouter
+ - Fix #4129 unbound-control error message with wrong cert permissions
+ is too cryptic.
+
+17 July 2018: Wouter
+ - Fix #4127 unbound -h does not list -p help.
+ - Print error if SSL name verification configured but not available
+ in the ssl library.
+ - Fix that ratelimit and ip-ratelimit are applied after reload of
+ changed config file.
+ - Resize ratelimit and ip-ratelimit caches if changed on reload.
+
+16 July 2018: Wouter
+ - Fix qname minimisation NXDOMAIN validation lookup failures causing
+ error_supers assertion fails.
+ - Squelch can't bind socket errors with Permission denied unless
+ verbosity is 4 or higher, for UDP outgoing sockets.
+
+12 July 2018: Wouter
+ - Fix to improve systemd socket activation code file descriptor
+ assignment.
+ - Fix for 4126 that the #define for UNKNOWN_SERVER_NICENESS can be more
+ easily changed to adjust default rtt assumptions.
+
+10 July 2018: Wouter
+ - Note in documentation that the cert name match code needs
+ OpenSSL 1.1.0 or later to be enabled.
+
+6 July 2018: Wouter
+ - Fix documentation ambiguity for tls-win-cert in tls-upstream and
+ forward-tls-upstream docs.
+ - iana port update.
+ - Note RFC8162 support. SMIMEA record type can be read in by the
+ zone record parser.
+ - Fix round robin for failed addresses with prefer-ip6: yes
+
+4 July 2018: Wouter
+ - Fix #4112: Fix that unbound-anchor -f /etc/resolv.conf will not pass
+ if DNSSEC is not enabled. New option -R allows fallback from
+ resolv.conf to direct queries.
+
+3 July 2018: Wouter
+ - Better documentation for unblock-lan-zones and insecure-lan-zones
+ config statements.
+ - Fix permission denied printed for auth zone probe random port nrs.
+
+2 July 2018: Wouter
+ - Fix checking for libhiredis printout in configure output.
+ - Fix typo on man page in ip-address description.
+ - Update libunbound/python/examples/dnssec_test.py example code to
+ also set the 20326 trust anchor for the root in the example code.
+
+29 June 2018: Wouter
+ - dns64-ignore-aaaa: config option to list domain names for which the
+ existing AAAA is ignored and dns64 processing is used on the A
+ record.
+
+28 June 2018: Wouter
+ - num.queries.tls counter for queries over TLS.
+ - log port number with err_addr logs.
+
+27 June 2018: Wouter
+ - #4109: Fix that package config depends on python unconditionally.
+ - Patch, do not export python from pkg-config, from Petr MenÅ¡Ãk.
+
+26 June 2018: Wouter
+ - Partial fix for permission denied on IPv6 address on FreeBSD.
+ - Fix that auth-zone master reply with current SOA serial does not
+ stop scan of masters for an updated zone.
+ - Fix that auth-zone does not start the wait timer without checking
+ if the wait timer has already been started.
+
+21 June 2018: Wouter
+ - #4108: systemd reload hang fix.
+ - Fix usage printout for unbound-host, hostname has to be last
+ argument on BSDs and Windows.
+
19 June 2018: Wouter
- Fix for unbound-control on Windows and set TCP socket parameters
more closely.
+ This fix is part of 1.7.3.
+ - Windows example service.conf edited with more windows specific
+ configuration.
- Fix windows unbound-control no cert bad file descriptor error.
+ This fix is part of 1.7.3.
18 June 2018: Wouter
- Fix that control-use-cert: no works for 127.0.0.1 to disable certs.
+ This fix is part of 1.7.3rc2.
- Fix unbound-checkconf for control-use-cert.
+ This fix is part of 1.7.3.
15 June 2018: Wouter
- tag for 1.7.3rc1.
+ - trunk has 1.7.4.
+ - unbound-control auth_zone_reload _zone_ option rereads the zonefile.
+ - unbound-control auth_zone_transfer _zone_ option starts the probe
+ sequence for a master to transfer the zone from and transfers when
+ a new zone version is available.
14 June 2018: Wouter
- #4103: Fix that auth-zone does not insist on SOA record first in
-README for Unbound 1.7.3
+README for Unbound 1.8.0
Copyright 2007 NLnet Labs
http://unbound.net
Disable support for RSASHA256 and RSASHA512 crypto.
* --disable-gost
Disable support for GOST crypto, RFC 5933.
+ * --enable-subnet
+ Enable EDNS client subnet processing.
* 'make test' runs a series of self checks.
#
# Example configuration file.
#
-# See unbound.conf(5) man page, version 1.7.3.
+# See unbound.conf(5) man page, version 1.8.0.
#
# this is a comment.
# so-sndbuf: 0
# use SO_REUSEPORT to distribute queries over threads.
- # so-reuseport: no
+ # so-reuseport: yes
# use IP_TRANSPARENT so the interface: addresses can be non-local
# and you can config non-existing IPs that are going to work later on
# Default is 0, system default MSS.
# outgoing-tcp-mss: 0
+ # Idle TCP timeout, connection closed in milliseconds
+ # tcp-idle-timeout: 30000
+
+ # Enable EDNS TCP keepalive option.
+ # edns-tcp-keepalive: no
+
+ # Timeout for EDNS TCP keepalive, in msec.
+ # edns-tcp-keepalive-timeout: 120000
+
# Use systemd socket activation for UDP, TCP, and control sockets.
# use-systemd: no
# timetoresolve, fromcache and responsesize.
# log-replies: no
+ # log the local-zone actions, like local-zone type inform is enabled
+ # also for the other local zone types.
+ # log-local-actions: no
+
+ # print log lines that say why queries return SERVFAIL to clients.
+ # log-servfail: no
+
# the pid file. Can be an absolute path outside of chroot/work dir.
# pidfile: "@UNBOUND_PIDFILE@"
# harden-dnssec-stripped: yes
# Harden against queries that fall under dnssec-signed nxdomain names.
- # harden-below-nxdomain: no
+ # harden-below-nxdomain: yes
# Harden the referral path by performing additional queries for
# infrastructure data. Validates the replies (if possible).
# if yes, Unbound doesn't insert authority/additional sections
# into response messages when those sections are not required.
- # minimal-responses: no
+ # minimal-responses: yes
# true to disable DNSSEC lameness check in iterator.
# disable-dnssec-lame-check: no
# Serve expired responses from cache, with TTL 0 in the response,
# and then attempt to fetch the data afresh.
# serve-expired: no
+ #
+ # Limit serving of expired responses to configured seconds after
+ # expiration. 0 disables the limit.
+ # serve-expired-ttl: 0
+ #
+ # Set the TTL of expired records to the serve-expired-ttl value after a
+ # failed attempt to retrieve the record from upstream. This makes sure
+ # that the expired records will be served as long as there are queries
+ # for it.
+ # serve-expired-ttl-reset: no
# Have the validator log failed validations for your diagnosis.
# 0: off. 1: A line per failed user query. 2: With reason and bad IP.
# Enable dns64 in module-config. Used to synthesize IPv6 from IPv4.
# dns64-prefix: 64:ff9b::0/96
+ # DNS64 ignore AAAA records for these domains and use A instead.
+ # dns64-ignore-aaaa: "example.com"
+
# ratelimit for uncached, new queries, this limits recursion effort.
# ratelimiting is experimental, and may help against randomqueryflood.
# if 0(default) it is disabled, otherwise state qps allowed per zone.
# 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through
# ip-ratelimit-factor: 10
+ # Limit the number of connections simultaneous from a netblock
+ # tcp-connection-limit: 192.0.2.0/24 12
+
# what is considered a low rtt (ping time for upstream server), in msec
# low-rtt: 45
# select low rtt this many times out of 1000. 0 means the fast server
# stub-prime: no
# stub-first: no
# stub-tls-upstream: no
+# stub-no-cache: no
# stub-zone:
# name: "example.org"
# stub-host: ns.example.com.
# forward-addr: 192.0.2.73@5355 # forward to port 5355.
# forward-first: no
# forward-tls-upstream: no
+# forward-no-cache: no
# forward-zone:
# name: "example.org"
# forward-host: fwd.example.com
-.TH "libunbound" "3" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "libunbound" "3" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.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.7.3 functions.
+\- Unbound DNS validating resolver 1.8.0 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
-.TH "unbound-anchor" "8" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound-anchor" "8" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
resolver, cannot use that recursive resolver itself because it is bootstrapping
that server.
.TP
+.B \-R
+Allow fallback from \-f resolv.conf file to direct root servers query.
+It allows you to prefer local resolvers, but fallback automatically
+to direct root query if they do not respond or do not support DNSSEC.
+.TP
.B \-v
More verbose. Once prints informational messages, multiple times may enable
large debug amounts (such as full certificates or byte\-dumps of downloaded
-.TH "unbound-checkconf" "8" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound-checkconf" "8" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"
-.TH "unbound-control" "8" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound-control" "8" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound-control.8 -- unbound remote control manual
.\"
List the auth zones that are configured. Printed one per line with a
status, indicating if the zone is expired and current serial number.
.TP
+.B auth_zone_reload \fIzone\fR
+Reload the auth zone from zonefile. The zonefile is read in overwriting
+the current contents of the zone in memory. This changes the auth zone
+contents itself, not the cache contents. Such cache contents exists if
+you set unbound to validate with for-upstream yes and that can be cleared
+with \fBflush_zone\fR \fIzone\fR.
+.TP
+.B auth_zone_transfer \fIzone\fR
+Tranfer the auth zone from master. The auth zone probe sequence is started,
+where the masters are probed to see if they have an updated zone (with the SOA
+serial check). And then the zone is transferred for a newer zone version.
+.TP
.B view_list_local_zones \fIview\fR
\fIlist_local_zones\fR for given view.
.TP
Number of queries that the unbound server made using TCP outgoing towards
other servers.
.TP
+.I num.query.tls
+Number of queries that were made using TLS towards the unbound server.
+These are also counted in num.query.tcp, because TLS uses TCP.
+.TP
.I num.query.ipv6
Number of queries that were made using IPv6 towards the unbound server.
.TP
The number of queries answered using cached NSEC records with NXDOMAIN RCODE.
These queries would otherwise have been sent to the internet, but are now
answered using cached data.
+.TP
+.I num.query.subnet
+Number of queries that got an answer that contained EDNS client subnet data.
+.TP
+.I num.query.subnet_cache
+Number of queries answered from the edns client subnet cache. These are
+counted as cachemiss by the main counters, but hit the client subnet
+specific cache, after getting processed by the edns client subnet module.
.SH "FILES"
.TP
.I @ub_conf_file@
-.TH "unbound\-host" "1" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound\-host" "1" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"
\- unbound DNS lookup utility
.SH "SYNOPSIS"
.B unbound\-host
+.RB [ \-C
+.IR configfile ]
.RB [ \-vdhr46D ]
.RB [ \-c
.IR class ]
.RB [ \-t
.IR type ]
-.I hostname
.RB [ \-y
.IR key ]
.RB [ \-f
.IR keyfile ]
.RB [ \-F
.IR namedkeyfile ]
-.RB [ \-C
-.IR configfile ]
+.I hostname
.SH "DESCRIPTION"
.B Unbound\-host
uses the unbound validating resolver to query for the hostname and display
.B \-C \fIconfigfile
Uses the specified unbound.conf to prime
.IR libunbound (3).
+Pass it as first argument if you want to override some options from the
+config file with further arguments on the commandline.
.TP
.B \-r
Read /etc/resolv.conf, and use the forward DNS servers from there (those could
-.TH "unbound" "8" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound" "8" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound.8 -- unbound manual
.\"
.\"
.SH "NAME"
.B unbound
-\- Unbound DNS validating resolver 1.7.3.
+\- Unbound DNS validating resolver 1.8.0.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]
-.TH "unbound.conf" "5" "Jun 21, 2018" "NLnet Labs" "unbound 1.7.3"
+.TH "unbound.conf" "5" "Sep 10, 2018" "NLnet Labs" "unbound 1.8.0"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
\fBport\fR) is used.
.TP
.B ip\-address: \fI<ip address[@port]>
-Same as interface: (for easy of compatibility with nsd.conf).
+Same as interface: (for ease of compatibility with nsd.conf).
.TP
.B interface\-automatic: \fI<yes or no>
Detect source interface on UDP queries and copy them to replies. This
.B so\-reuseport: \fI<yes or no>
If yes, then open dedicated listening sockets for incoming queries for each
thread and try to set the SO_REUSEPORT socket option on each socket. May
-distribute incoming queries to threads more evenly. Default is no. On Linux
-it is supported in kernels >= 3.9. On other systems, FreeBSD, OSX it may
-also work. You can enable it (on any platform and kernel),
+distribute incoming queries to threads more evenly. Default is yes.
+On Linux it is supported in kernels >= 3.9. On other systems, FreeBSD, OSX
+it may also work. You can enable it (on any platform and kernel),
it then attempts to open the port and passes the option if it was available
at compile time, if that works it is used, if it fails, it continues
silently (unless verbosity 3) without the option.
Default is system default MSS determined by interface MTU and
negotiation between Unbound and other servers.
.TP
+.B tcp-idle-timeout: \fI<msec>\fR
+The period Unbound will wait for a query on a TCP connection.
+If this timeout expires Unbound closes the connection.
+This option defaults to 30000 milliseconds.
+When the number of free incoming TCP buffers falls below 50% of the
+total number configured, the option value used is progressively
+reduced, first to 1% of the configured value, then to 0.2% of the
+configured value if the number of free buffers falls below 35% of the
+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.
+.TP
+.B edns-tcp-keepalive: \fI<yes or no>\fR
+Enable or disable EDNS TCP Keepalive. Default is no.
+.TP
+.B edns-tcp-keepalive-timeout: \fI<msec>\fR
+The period Unbound will wait for a query on a TCP connection when
+EDNS TCP Keepalive is active. If this timeout expires Unbound closes
+the connection. If the client supports the EDNS TCP Keepalive option,
+Unbound sends the timeout value to the client to encourage it to
+close the connection before the server times out.
+This option defaults to 120000 milliseconds.
+When the number of free incoming TCP buffers falls below 50% of
+the total number configured, the advertised timeout is progressively
+reduced to 1% of the configured value, then to 0.2% of the configured
+value if the number of free buffers falls below 35% of the total number
+configured, and finally to 0 if the number of free buffers falls below
+20% of the total number configured.
+A minimum actual timeout of 200 milliseconds is observed regardless of the
+advertised timeout.
+.TP
.B tcp\-upstream: \fI<yes or no>
Enable or disable whether the upstream queries use TCP only for transport.
Default is no. Useful in tunneling scenarios.
Default is no. Useful in tunneling scenarios. The TLS contains plain DNS in
TCP wireformat. The other server must support this (see
\fBtls\-service\-key\fR).
-If you enable this, also configure a tls\-cert\-bundle or use tls\-win\cert to
+If you enable this, also configure a tls\-cert\-bundle or use tls\-win\-cert to
load CA certs, otherwise the connections cannot be authenticated.
.TP
.B ssl\-upstream: \fI<yes or no>
a daemon. Set the value to \fIno\fR when unbound runs as systemd service.
Default is yes.
.TP
+.B tcp\-connection\-limit: \fI<IP netblock> <limit>
+Allow up to \fIlimit\R simultaneous TCP connections from the given netblock.
+When at the limit, further connections are accepted but closed immediately.
+This option is experimental at this time.
+.TP
.B access\-control: \fI<IP netblock> <action>
The netblock is given as an IP4 or IP6 address with /size appended for a
classless network block. The action can be \fIdeny\fR, \fIrefuse\fR,
Additionally, unbound may need to access /dev/random (for entropy)
from inside the chroot.
.IP
-If given a chroot is done to the given directory. The default is
-"@UNBOUND_CHROOT_DIR@". If you give "" no chroot is performed.
+If given a chroot is done to the given directory. By default chroot is
+enabled and the default is "@UNBOUND_CHROOT_DIR@". If you give "" no
+chroot is performed.
.TP
.B username: \fI<name>
If given, after binding the port the user privileges are dropped. Default is
lines which makes the server (significantly) slower. Odd (nonprintable)
characters in names are printed as '?'.
.TP
+.B log\-local\-actions: \fI<yes or no>
+Print log lines to inform about local zone actions. These lines are like the
+local\-zone type inform prints out, but they are also printed for the other
+types of local zones.
+.TP
+.B log\-servfail: \fI<yes or no>
+Print log lines that say why queries return SERVFAIL to clients.
+This is separate from the verbosity debug logs, much smaller, and printed
+at the error level, not the info level of debug info from verbosity.
+.TP
.B pidfile: \fI<filename>
The process id is written to the file. Default is to not write to a file.
.TP
might return nxdomain for empty nonterminals (that usually happen for reverse
IP address lookups), and thus may be incompatible with this. To try to avoid
this only DNSSEC-secure nxdomains are used, because the old software does not
-have DNSSEC. Default is off.
+have DNSSEC. Default is on.
The nxdomain must be secure, this means nsec3 with optout is insufficient.
.TP
.B harden\-referral\-path: \fI<yes or no>
If yes, Unbound doesn't insert authority/additional sections into response
messages when those sections are not required. This reduces response
size significantly, and may avoid TCP fallback for some responses.
-This may cause a slight speedup. The default is no, because the DNS
+This may cause a slight speedup. The default is yes, even though the DNS
protocol RFCs mandate these sections, and the additional content could
-be of use and save roundtrips for clients.
+be of use and save roundtrips for clients. Because they are not used,
+and the saved roundtrips are easier saved with prefetch, whilst this is
+faster.
.TP
.B disable-dnssec-lame-check: \fI<yes or no>
If true, disables the DNSSEC lameness check in the iterator. This check
TTL of 0 in the response without waiting for the actual resolution to finish.
The actual resolution answer ends up in the cache later on. Default is "no".
.TP
+.B serve\-expired\-ttl: \fI<seconds>
+Limit serving of expired responses to configured seconds after expiration. 0
+disables the limit. This option only applies when \fBserve\-expired\fR is
+enabled. The default is 0.
+.TP
+.B serve\-expired\-ttl\-reset: \fI<yes or no>
+Set the TTL of expired records to the \fBserve\-expired\-ttl\fR value after a
+failed attempt to retrieve the record from upstream. This makes sure that the
+expired records will be served as long as there are queries for it. Default is
+"no".
+.TP
.B val\-nsec3\-keysize\-iterations: \fI<"list of values">
List of keysize and iteration count values, separated by spaces, surrounded
by quotes. Default is "1024 150 2048 500 4096 2500". This determines the
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
or gigabytes (1024*1024 bytes in a megabyte).
.TP
-.B unblock\-lan\-zones: \fI<yesno>
+.B unblock\-lan\-zones: \fI<yes or no>
Default is disabled. If enabled, then for private address space,
the reverse lookups are no longer filtered. This allows unbound when
running as dns service on a host where it provides service for that host,
lookups should be filtered (RFC compliance), this also stops potential
data leakage about the local network to the upstream DNS servers.
.TP
-.B insecure\-lan\-zones: \fI<yesno>
+.B insecure\-lan\-zones: \fI<yes or no>
Default is disabled. If enabled, then reverse lookups in private
address space are not validated. This is usually required whenever
\fIunblock\-lan\-zones\fR is used.
.TP
.B stub\-ssl\-upstream: \fI<yes or no>
Alternate syntax for \fBstub\-tls\-upstream\fR.
+.TP
+.B stub\-no\-cache: \fI<yes or no>
+Default is no. If enabled, data inside the stub is not cached. This is
+useful when you want immediate changes to be visible.
.SS "Forward Zone Options"
.LP
There may be multiple
At high verbosity it logs the TLS certificate, with TLS enabled.
If you leave out the '#' and auth name from the forward\-addr, any
name is accepted. The cert must also match a CA from the tls\-cert\-bundle.
+The cert name match code needs OpenSSL 1.1.0 or later to be enabled.
.TP
.B forward\-first: \fI<yes or no>
If enabled, a query is attempted without the forward clause if it fails.
.B forward\-tls\-upstream: \fI<yes or no>
Enabled or disable whether the queries to this forwarder use TLS for transport.
Default is no.
-If you enable this, also configure a tls\-cert\-bundle or use tls\-win\cert to
+If you enable this, also configure a tls\-cert\-bundle or use tls\-win\-cert to
load CA certs, otherwise the connections cannot be authenticated.
.TP
.B forward\-ssl\-upstream: \fI<yes or no>
Alternate syntax for \fBforward\-tls\-upstream\fR.
+.TP
+.B forward\-no\-cache: \fI<yes or no>
+Default is no. If enabled, data inside the forward is not cached. This is
+useful when you want immediate changes to be visible.
.SS "Authority Zone Options"
.LP
Authority zones are configured with \fBauth\-zone:\fR, and each one must
.B dns64\-synthall: \fI<yes or no>\fR
Debug option, default no. If enabled, synthesize all AAAA records
despite the presence of actual AAAA records.
+.TP
+.B dns64\-ignore\-aaaa: \fI<name>\fR
+List domain for which the AAAA records are ignored and the A record is
+used by dns64 processing instead. Can be entered multiple times, list a
+new domain for which it applies, one per line. Applies also to names
+underneath the name given.
.SS "DNSCrypt Options"
.LP
The
memset(c_out, 0, sizeof(*c_out));
- if (!qstate->return_msg) return module_error;
+ if (!qstate->return_msg) {
+ /* already an answer and its not a message, but retain
+ * the actual rcode, instead of module_error, so send
+ * module_finished */
+ return module_finished;
+ }
/* We have not asked for subnet data */
if (!sq->subnet_sent) {
lock_rw_wrlock(&sne->biglock);
update_cache(qstate, id);
+ sne->num_msg_nocache++;
lock_rw_unlock(&sne->biglock);
if (sq->subnet_downstream) {
lock_rw_wrlock(&sne->biglock);
if (lookup_and_reply(qstate, id, sq)) {
+ sne->num_msg_cache++;
lock_rw_unlock(&sne->biglock);
verbose(VERB_QUERY, "subnet: answered from cache");
qstate->ext_state[id] = module_finished;
/* Query handed back by next module, we have a 'final' answer */
if(sq && event == module_event_moddone) {
qstate->ext_state[id] = eval_response(qstate, id, sq);
- if(qstate->ext_state[id] == module_finished) {
+ if(qstate->ext_state[id] == module_finished &&
+ qstate->return_msg) {
ecs_opt_list_append(&sq->ecs_client_out,
&qstate->edns_opts_front_out, qstate);
}
/** allocation service */
struct alloc_cache alloc;
lock_rw_type biglock;
+ /** number of messages from cache */
+ size_t num_msg_cache;
+ /** number of messages not from cache */
+ size_t num_msg_nocache;
};
struct subnet_msg_cache_data {
uint8_t ssl_upstream;
/** delegpt from authoritative zone that is locally hosted */
uint8_t auth_dp;
+ /*** no cache */
+ int no_cache;
};
/**
s->name, p->str);
return 0;
}
+#ifndef HAVE_SSL_SET1_HOST
+ if(tls_auth_name)
+ log_err("no name verification functionality in "
+ "ssl library, ignored name for %s", p->str);
+#endif
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
tls_auth_name)) {
log_err("out of memory");
* last resort will ask for parent-side NS record and thus
* fallback to the internet name servers on a failure */
dp->has_parent_side_NS = (uint8_t)!s->isfirst;
+ /* Do not cache if set. */
+ dp->no_cache = s->no_cache;
/* use SSL for queries to this forwarder */
dp->ssl_upstream = (uint8_t)s->ssl_upstream;
verbose(VERB_QUERY, "Forward zone server list:");
s->name, p->str);
return 0;
}
+#ifndef HAVE_SSL_SET1_HOST
+ if(auth_name)
+ log_err("no name verification functionality in "
+ "ssl library, ignored name for %s", p->str);
+#endif
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
auth_name)) {
log_err("out of memory");
* last resort will ask for parent-side NS record and thus
* fallback to the internet name servers on a failure */
dp->has_parent_side_NS = (uint8_t)!s->isfirst;
+ /* Do not cache if set. */
+ dp->no_cache = s->no_cache;
/* ssl_upstream */
dp->ssl_upstream = (uint8_t)s->ssl_upstream;
delegpt_log(VERB_QUERY, dp);
int got_num6 = 0;
int low_rtt6 = 0;
int i;
+ int attempt = -1; /* filter to make sure addresses have
+ less attempts on them than the first, to force round
+ robin when all the IPv6 addresses fail */
+ int num4ok = 0; /* number ip4 at low attempt count */
+ int num4_lowrtt = 0;
prev = NULL;
a = dp->result_list;
for(i = 0; i < got_num; i++) {
swap_to_front = 0;
+ if(a->addr.ss_family != AF_INET6 && attempt == -1) {
+ /* if we only have ip4 at low attempt count,
+ * then ip6 is failing, and we need to
+ * select one of the remaining IPv4 addrs */
+ attempt = a->attempts;
+ num4ok++;
+ num4_lowrtt = a->sel_rtt;
+ } else if(a->addr.ss_family != AF_INET6 && attempt == a->attempts) {
+ num4ok++;
+ if(num4_lowrtt == 0 || a->sel_rtt < num4_lowrtt) {
+ num4_lowrtt = a->sel_rtt;
+ }
+ }
if(a->addr.ss_family == AF_INET6) {
+ if(attempt == -1) {
+ attempt = a->attempts;
+ } else if(a->attempts > attempt) {
+ break;
+ }
got_num6++;
swap_to_front = 1;
if(low_rtt6 == 0 || a->sel_rtt < low_rtt6) {
if(got_num6 > 0) {
got_num = got_num6;
*selected_rtt = low_rtt6;
+ } else if(num4ok > 0) {
+ got_num = num4ok;
+ *selected_rtt = num4_lowrtt;
}
}
return got_num;
qstate->qinfo.qname, qstate->qinfo.qname_len);
if(!dpns) {
/* not interested */
+ /* this can happen, for eg. qname minimisation asked
+ * for an NXDOMAIN to be validated, and used qtype
+ * A for that, and the error of that, the name, is
+ * not listed in super_iq->dp */
verbose(VERB_ALGO, "subq error, but not interested");
log_query_info(VERB_ALGO, "superq", &super->qinfo);
- if(super_iq->dp)
- delegpt_log(VERB_ALGO, super_iq->dp);
- log_assert(0);
return;
} else {
/* see if the failure did get (parent-lame) info */
if((msg=msg_cache_lookup(qstate->env,
qstate->qinfo.qname, qstate->qinfo.qname_len,
qstate->qinfo.qtype, qstate->qinfo.qclass,
- qstate->query_flags, 0, 0))
+ qstate->query_flags, 0,
+ qstate->env->cfg->serve_expired_ttl_reset))
!= NULL) {
+ if(qstate->env->cfg->serve_expired_ttl_reset) {
+ struct reply_info* rep =
+ (struct reply_info*)msg->entry.data;
+ if(rep && *qstate->env->now +
+ qstate->env->cfg->serve_expired_ttl >
+ rep->serve_expired_ttl) {
+ rep->serve_expired_ttl =
+ *qstate->env->now +
+ qstate->env->cfg->serve_expired_ttl;
+ }
+ }
lock_rw_unlock(&msg->entry.lock);
return error_response(qstate, id, rcode);
}
err.qdcount = 1;
err.ttl = NORR_TTL;
err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl);
+ err.serve_expired_ttl = NORR_TTL;
/* do not waste time trying to validate this servfail */
err.security = sec_status_indeterminate;
verbose(VERB_ALGO, "store error response in message cache");
iq->dp = delegpt_copy(stub_dp, qstate->region);
if(!iq->dp) {
log_err("out of memory priming stub");
+ errinf(qstate, "malloc failure, priming stub");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */
}
LDNS_RR_TYPE_NS, qclass, qstate, id, iq,
QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0)) {
verbose(VERB_ALGO, "could not prime stub");
+ errinf(qstate, "could not generate lookup for stub prime");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */
}
fptr_ok(fptr_whitelist_modenv_kill_sub(
qstate->env->kill_sub));
(*qstate->env->kill_sub)(subq);
+ errinf(qstate, "malloc failure, in stub prime");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return 1; /* return 1 to make module stop, with error */
}
return 1; /* just fallback */
}
lock_rw_unlock(&z->lock);
+ errinf(qstate, "malloc failure");
return 0;
}
dp->name = regional_alloc_init(qstate->region,
return 1; /* just fallback */
}
lock_rw_unlock(&z->lock);
+ errinf(qstate, "malloc failure");
return 0;
}
dp->namelen = z->namelen;
return 1;
}
+static int
+iter_stub_fwd_no_cache(struct module_qstate *qstate, struct iter_qstate *iq)
+{
+ struct iter_hints_stub *stub;
+ struct delegpt *dp;
+
+ /* Check for stub. */
+ stub = hints_lookup_stub(qstate->env->hints, iq->qchase.qname,
+ iq->qchase.qclass, iq->dp);
+ dp = forwards_lookup(qstate->env->fwds, iq->qchase.qname, iq->qchase.qclass);
+
+ /* see if forward or stub is more pertinent */
+ if(stub && stub->dp && dp) {
+ if(dname_strict_subdomain(dp->name, dp->namelabs,
+ stub->dp->name, stub->dp->namelabs)) {
+ stub = NULL; /* ignore stub, forward is lower */
+ } else {
+ dp = NULL; /* ignore forward, stub is lower */
+ }
+ }
+
+ /* check stub */
+ if (stub != NULL && stub->dp != NULL) {
+ if(stub->dp->no_cache) {
+ char qname[255+1];
+ char dpname[255+1];
+ dname_str(iq->qchase.qname, qname);
+ dname_str(stub->dp->name, dpname);
+ verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname);
+ }
+ return (stub->dp->no_cache);
+ }
+
+ /* Check for forward. */
+ if (dp) {
+ if(dp->no_cache) {
+ char qname[255+1];
+ char dpname[255+1];
+ dname_str(iq->qchase.qname, qname);
+ dname_str(dp->name, dpname);
+ verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname);
+ }
+ return (dp->no_cache);
+ }
+ return 0;
+}
+
/**
* Process the initial part of the request handling. This state roughly
* corresponds to resolver algorithms steps 1 (find answer in cache) and 2
if(iq->query_restart_count > MAX_RESTART_COUNT) {
verbose(VERB_QUERY, "request has exceeded the maximum number"
" of query restarts with %d", iq->query_restart_count);
+ errinf(qstate, "request has exceeded the maximum number "
+ "restarts (eg. indirections)");
+ if(iq->qchase.qname)
+ errinf_dname(qstate, "stop at", iq->qchase.qname);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(iq->depth > ie->max_dependency_depth) {
verbose(VERB_QUERY, "request has exceeded the maximum "
"dependency depth with depth of %d", iq->depth);
+ errinf(qstate, "request has exceeded the maximum dependency "
+ "depth (eg. nameserver lookup recursion)");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* This either results in a query restart (CNAME cache response), a
* terminating response (ANSWER), or a cache miss (null). */
- if(qstate->blacklist) {
+ if (iter_stub_fwd_no_cache(qstate, iq)) {
+ /* Asked to not query cache. */
+ verbose(VERB_ALGO, "no-cache set, going to the network");
+ qstate->no_cache_lookup = 1;
+ qstate->no_cache_store = 1;
+ msg = NULL;
+ } else if(qstate->blacklist) {
/* if cache, or anything else, was blacklisted then
* getting older results from cache is a bad idea, no cache */
verbose(VERB_ALGO, "cache blacklisted, going to the network");
verbose(VERB_ALGO, "returning CNAME response from "
"cache");
if(!handle_cname_response(qstate, iq, msg,
- &sname, &slen))
+ &sname, &slen)) {
+ errinf(qstate, "failed to prepend CNAME "
+ "components, malloc failure");
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
+ }
iq->qchase.qname = sname;
iq->qchase.qname_len = slen;
/* This *is* a query restart, even if it is a cheap
/* if from cache, NULL, else insert 'cache IP' len=0 */
if(qstate->reply_origin)
sock_list_insert(&qstate->reply_origin, NULL, 0, qstate->region);
+ if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_SERVFAIL)
+ errinf(qstate, "SERVFAIL in cache");
/* it is an answer, response, to final state */
verbose(VERB_ALGO, "returning answer from cache.");
iq->response = msg;
{
if(!iq->dp) {
log_err("alloc failure for forward dp");
+ errinf(qstate, "malloc failure for forward zone");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->refetch_glue = 0;
if(iq->refetch_glue) {
if(!iq->dp) {
log_err("internal or malloc fail: no dp for refetch");
+ errinf(qstate, "malloc failure, for delegation info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
delname = iq->dp->name;
iq->qchase.qclass);
if(!iq->dp) {
log_err("internal error: no hints dp");
+ errinf(qstate, "no hints for this class");
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
iq->dp = delegpt_copy(iq->dp, qstate->region);
if(!iq->dp) {
log_err("out of memory in safety belt");
+ errinf(qstate, "malloc failure, in safety belt");
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
log_nametypeclass(VERB_ALGO, "ratelimit exceeded with "
"delegation point", iq->dp->name,
LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
+ qstate->was_ratelimited = 1;
+ errinf(qstate, "query was ratelimited");
+ errinf_dname(qstate, "for zone", iq->dp->name);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
}
if(!iq->dp) {
log_err("out of memory in "
"stub/fwd fallback");
+ errinf(qstate, "malloc failure, for fallback to config");
return error_response(qstate,
id, LDNS_RCODE_SERVFAIL);
}
verbose(VERB_ALGO, "useless dp "
"but cannot go up, servfail");
delegpt_log(VERB_ALGO, iq->dp);
+ errinf(qstate, "no useful nameservers, "
+ "and cannot go up");
+ errinf_dname(qstate, "for zone", iq->dp->name);
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
iq->dp = delegpt_copy(iq->dp, qstate->region);
if(!iq->dp) {
log_err("out of memory in safety belt");
+ errinf(qstate, "malloc failure, in safety belt, for root");
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
struct iter_hints_stub* stub;
if(!iq->dp) {
log_err("internal or malloc fail: no dp for refetch");
+ errinf(qstate, "malloc failure, no delegation info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* Do not send queries above stub, do not set delname to dp if
iq->qchase.qclass, NULL)) {
/* fail -- no more targets, no more hope of targets, no hope
* of a response. */
+ errinf(qstate, "all the configured stub or forward servers failed,");
+ errinf_dname(qstate, "at zone", iq->dp->name);
verbose(VERB_QUERY, "configured stub or forward servers failed -- returning SERVFAIL");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
int qs = 0;
verbose(VERB_ALGO, "try parent-side target name");
if(!query_for_targets(qstate, iq, ie, id, 1, &qs)) {
+ errinf(qstate, "could not fetch nameserver");
+ errinf_dname(qstate, "at zone", iq->dp->name);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
}
if(iq->depth == ie->max_dependency_depth) {
verbose(VERB_QUERY, "maxdepth and need more nameservers, fail");
+ errinf(qstate, "cannot fetch more nameservers because at max dependency depth");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(iq->depth > 0 && iq->target_count &&
dname_str(qstate->qinfo.qname, s);
verbose(VERB_QUERY, "request %s has exceeded the maximum "
"number of glue fetches %d", s, iq->target_count[1]);
+ errinf(qstate, "exceeded the maximum number of glue fetches");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
/* mark cycle targets for parent-side lookups */
/* Send the AAAA request. */
if(!generate_parentside_target_query(qstate, iq, id,
ns->name, ns->namelen,
- LDNS_RR_TYPE_AAAA, iq->qchase.qclass))
+ LDNS_RR_TYPE_AAAA, iq->qchase.qclass)) {
+ errinf_dname(qstate, "could not generate nameserver AAAA lookup for", ns->name);
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
+ }
ns->done_pside6 = 1;
query_count++;
}
/* Send the A request. */
if(!generate_parentside_target_query(qstate, iq, id,
ns->name, ns->namelen,
- LDNS_RR_TYPE_A, iq->qchase.qclass))
+ LDNS_RR_TYPE_A, iq->qchase.qclass)) {
+ errinf_dname(qstate, "could not generate nameserver A lookup for", ns->name);
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
+ }
ns->done_pside4 = 1;
query_count++;
}
iq->deleg_msg?iq->deleg_msg->rep:
(iq->response?iq->response->rep:NULL));
+ errinf(qstate, "all servers for this domain failed,");
+ errinf_dname(qstate, "at zone", iq->dp->name);
verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL");
/* fail -- no more targets, no more hope of targets, no hope
* of a response. */
}
/* robustcheck for internal error: we are not underneath the dp */
if(!dname_subdomain_c(iq->dsns_point, iq->dp->name)) {
+ errinf_dname(qstate, "for DS query parent-child nameserver search the query is not under the zone", iq->dp->name);
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(!generate_sub_request(iq->dsns_point, iq->dsns_point_len,
LDNS_RR_TYPE_NS, iq->qchase.qclass, qstate, id, iq,
INIT_REQUEST_STATE, FINISHED_STATE, &subq, 0)) {
+ errinf_dname(qstate, "for DS query parent-child nameserver search, could not generate NS lookup for", iq->dsns_point);
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(iq->referral_count > MAX_REFERRAL_COUNT) {
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);
}
if(iq->sent_count > 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);
}
* or another failure occurred */
if(!iq->dp) {
verbose(VERB_QUERY, "Failed to get a delegation, giving up");
+ errinf(qstate, "failed to get a delegation (eg. prime failure)");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(!ie->supports_ipv6)
* no internet fallback */
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);
}
if(iq->dp && iq->dp->auth_dp) {
int extra = 0;
size_t naddr, nres, navail;
if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
+ errinf(qstate, "could not fetch nameservers for 0x20 fallback");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
"missing target");
if(!query_for_targets(qstate, iq, ie, id,
1, &qs)) {
+ errinf(qstate, "could not fetch nameserver");
+ errinf_dname(qstate, "at zone", iq->dp->name);
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
ie->num_queries_ratelimited++;
lock_basic_unlock(&ie->queries_ratelimit_lock);
verbose(VERB_ALGO, "query exceeded ratelimits");
+ qstate->was_ratelimited = 1;
+ errinf_dname(qstate, "exceeded ratelimit for zone",
+ iq->dp->name);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
}
/* DNAME to a subdomain loop; do not recurse */
type = RESPONSE_TYPE_ANSWER;
}
+ } else if(type == RESPONSE_TYPE_CNAME &&
+ iq->qchase.qtype == LDNS_RR_TYPE_CNAME &&
+ iq->minimisation_state == MINIMISE_STATE &&
+ query_dname_compare(iq->qchase.qname, iq->qinfo_out.qname) == 0) {
+ /* The minimised query for full QTYPE and hidden QTYPE can be
+ * classified as CNAME response type, even when the original
+ * QTYPE=CNAME. This should be treated as answer response type.
+ */
+ type = RESPONSE_TYPE_ANSWER;
}
/* handle each of the type cases */
iq->dp = delegpt_from_message(iq->response, qstate->region);
if (qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
- if(!iq->dp)
+ if(!iq->dp) {
+ errinf(qstate, "malloc failure, for delegation point");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
- qstate->region, iq->dp))
+ qstate->region, iq->dp)) {
+ errinf(qstate, "malloc failure, copy extra info into delegation point");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
if(iq->store_parent_NS && query_dname_compare(iq->dp->name,
iq->store_parent_NS->name) == 0)
iter_merge_retry_counts(iq->dp, iq->store_parent_NS);
}
/* Process the CNAME response. */
if(!handle_cname_response(qstate, iq, iq->response,
- &sname, &snamelen))
+ &sname, &snamelen)) {
+ errinf(qstate, "malloc failure, CNAME info");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
/* cache the CNAME response under the current query */
/* NOTE : set referral=1, so that rrsets get stored but not
* the partial query answer (CNAME only). */
iq->dp->name, iq->dp->namelen, qstate->qinfo.qclass)) {
verbose(VERB_ALGO, "auth zone response bad, and no"
" fallback possible, servfail");
+ errinf_dname(qstate, "reponse is bad, no fallback, "
+ "for auth zone", iq->dp->name);
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
verbose(VERB_ALGO, "auth zone response was bad, "
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = iq->response;
} else {
+ errinf(qstate, "prime response did not get an answer");
+ errinf_dname(qstate, "for", qstate->qinfo.qname);
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
qstate->return_msg = NULL;
}
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
if(!foriq->dp) {
log_err("out of memory in dsns dp alloc");
+ errinf(qstate, "malloc failure, in DS search");
return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */
}
/* success, go query the querytargets in the new dp (and go down) */
to->rep->ttl = from->rep->ttl;
if(from->rep->prefetch_ttl < to->rep->prefetch_ttl)
to->rep->prefetch_ttl = from->rep->prefetch_ttl;
+ if(from->rep->serve_expired_ttl < to->rep->serve_expired_ttl)
+ to->rep->serve_expired_ttl = from->rep->serve_expired_ttl;
}
/* are we done? */
foriq->num_current_queries --;
c, qstate, id, iq, INIT_REQUEST_STATE,
FINISHED_STATE, &subq,
(int)!(qstate->query_flags&BIT_CD))) {
+ errinf(qstate, "could not generate class ANY"
+ " lookup query");
return error_response(qstate, id,
LDNS_RCODE_SERVFAIL);
}
(iq->response?iq->response->rep:NULL));
if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail");
+ errinf(qstate, "(no response found at query finish)");
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->caps_server = 0;
iq->caps_reply = NULL;
iq->caps_response = NULL;
+ iq->caps_minimisation_state = DONOT_MINIMISE_STATE;
iq->state = QUERYTARGETS_STATE;
iq->num_current_queries--;
/* need fresh attempts for the 0x20 fallback, if
|| !qstate->reply) {
log_err("Bad event combined with response");
outbound_list_remove(&iq->outlist, outbound);
+ errinf(qstate, "module iterator received wrong internal event with a response message");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return;
}
iq->caps_server = 0;
iq->caps_reply = NULL;
iq->caps_response = NULL;
+ iq->caps_minimisation_state = DONOT_MINIMISE_STATE;
iq->state = QUERYTARGETS_STATE;
iq->num_current_queries--;
verbose(VERB_DETAIL, "Capsforid: scrub failed, starting fallback with no response");
iq->response->rep);
if(event == module_event_capsfail || iq->caps_fallback) {
+ if(qstate->env->cfg->qname_minimisation &&
+ iq->minimisation_state != DONOT_MINIMISE_STATE) {
+ /* Skip QNAME minimisation for next query, since that
+ * one has to match the current query. */
+ iq->minimisation_state = SKIP_MINIMISE_STATE;
+ }
/* for fallback we care about main answer, not additionals */
/* removing that makes comparison more likely to succeed */
caps_strip_reply(iq->response->rep);
+
+ if(iq->caps_fallback &&
+ iq->caps_minimisation_state != iq->minimisation_state) {
+ /* QNAME minimisation state has changed, restart caps
+ * fallback. */
+ iq->caps_fallback = 0;
+ }
+
if(!iq->caps_fallback) {
/* start fallback */
iq->caps_fallback = 1;
iq->caps_server = 0;
iq->caps_reply = iq->response->rep;
iq->caps_response = iq->response;
+ iq->caps_minimisation_state = iq->minimisation_state;
iq->state = QUERYTARGETS_STATE;
iq->num_current_queries--;
verbose(VERB_DETAIL, "Capsforid: starting fallback");
verbose(VERB_DETAIL, "Capsforid fallback: "
"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,
LDNS_RCODE_SERVFAIL);
return;
if((event == module_event_new || event == module_event_pass) &&
iq == NULL) {
if(!iter_new(qstate, id)) {
+ errinf(qstate, "malloc failure, new iterator module allocation");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return;
}
}
if(event == module_event_error) {
verbose(VERB_ALGO, "got called with event error, giving up");
+ errinf(qstate, "iterator module got the error event");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return;
}
log_err("bad event for iterator");
+ errinf(qstate, "iterator module received wrong event");
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
/** QNAME minimisation state, RFC7816 */
enum minimisation_state minimisation_state;
+ /** State for capsfail: QNAME minimisation state for comparisons. */
+ enum minimisation_state caps_minimisation_state;
+
/**
* The query info that is sent upstream. Will be a subset of qchase
* when qname minimisation is enabled.
return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1))
return UB_INITFAIL;
- if(!ctx->env->msg_cache ||
- cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) ||
- cfg->msg_cache_slabs != ctx->env->msg_cache->size) {
+ if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
+ cfg->msg_cache_slabs)) {
slabhash_delete(ctx->env->msg_cache);
ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
* o uint32 id
* o uint32 error_code
* o uint32 msg_security
+ * o uint32 was_ratelimited
* o uint32 length of why_bogus string (+1 for eos); 0 absent.
* o why_bogus_string
* o the remainder is the answer msg from resolver lookup.
* remainder can be length 0.
*/
+ size_t size_of_uint32s = 6 * sizeof(uint32_t);
size_t pkt_len = pkt?sldns_buffer_remaining(pkt):0;
size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
uint8_t* p;
- *len = sizeof(uint32_t)*5 + pkt_len + wlen;
+ *len = size_of_uint32s + pkt_len + wlen;
p = (uint8_t*)malloc(*len);
if(!p) return NULL;
sldns_write_uint32(p, UB_LIBCMD_ANSWER);
sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
- sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen);
+ sldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)q->res->was_ratelimited);
+ sldns_write_uint32(p+5*sizeof(uint32_t), (uint32_t)wlen);
if(wlen > 0)
- memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen);
+ memmove(p+size_of_uint32s, q->res->why_bogus, wlen);
if(pkt_len > 0)
- memmove(p+5*sizeof(uint32_t)+wlen,
+ memmove(p+size_of_uint32s+wlen,
sldns_buffer_begin(pkt), pkt_len);
return p;
}
context_deserialize_answer(struct ub_ctx* ctx,
uint8_t* p, uint32_t len, int* err)
{
+ size_t size_of_uint32s = 6 * sizeof(uint32_t);
struct ctx_query* q = NULL ;
int id;
size_t wlen;
- if(len < 5*sizeof(uint32_t)) return NULL;
+ if(len < size_of_uint32s) return NULL;
log_assert( sldns_read_uint32(p) == UB_LIBCMD_ANSWER);
id = (int)sldns_read_uint32(p+sizeof(uint32_t));
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
if(!q) return NULL;
*err = (int)sldns_read_uint32(p+2*sizeof(uint32_t));
q->msg_security = sldns_read_uint32(p+3*sizeof(uint32_t));
- wlen = (size_t)sldns_read_uint32(p+4*sizeof(uint32_t));
- if(len > 5*sizeof(uint32_t) && wlen > 0) {
- if(len >= 5*sizeof(uint32_t)+wlen)
+ q->res->was_ratelimited = (int)sldns_read_uint32(p+4*sizeof(uint32_t));
+ wlen = (size_t)sldns_read_uint32(p+5*sizeof(uint32_t));
+ if(len > size_of_uint32s && wlen > 0) {
+ if(len >= size_of_uint32s+wlen)
q->res->why_bogus = (char*)memdup(
- p+5*sizeof(uint32_t), wlen);
+ p+size_of_uint32s, wlen);
if(!q->res->why_bogus) {
/* pass malloc failure to the user callback */
q->msg_len = 0;
}
q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
}
- if(len > 5*sizeof(uint32_t)+wlen) {
- q->msg_len = len - 5*sizeof(uint32_t) - wlen;
- q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen,
+ if(len > size_of_uint32s+wlen) {
+ q->msg_len = len - size_of_uint32s - wlen;
+ q->msg = (uint8_t*)memdup(p+size_of_uint32s+wlen,
q->msg_len);
if(!q->msg) {
/* pass malloc failure to the user callback */
/** fillup fg results */
static void
libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
- enum sec_status s, char* why_bogus)
+ enum sec_status s, char* why_bogus, int was_ratelimited)
{
+ q->res->was_ratelimited = was_ratelimited;
if(why_bogus)
q->res->why_bogus = strdup(why_bogus);
if(rcode != 0) {
void
libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
- char* why_bogus)
+ char* why_bogus, int was_ratelimited)
{
struct ctx_query* q = (struct ctx_query*)arg;
/* fg query is done; exit comm base */
comm_base_exit(q->w->base);
- libworker_fillup_fg(q, rcode, buf, s, why_bogus);
+ libworker_fillup_fg(q, rcode, buf, s, why_bogus, was_ratelimited);
}
/** setup qinfo and edns */
NULL, 0, NULL, 0, NULL)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
- w->back->udp_buff, sec_status_insecure, NULL);
+ w->back->udp_buff, sec_status_insecure, NULL, 0);
libworker_delete(w);
free(qinfo.qname);
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
- w->back->udp_buff, sec_status_insecure, NULL);
+ w->back->udp_buff, sec_status_insecure, NULL, 0);
libworker_delete(w);
free(qinfo.qname);
return UB_NOERROR;
void
libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
- enum sec_status s, char* why_bogus)
+ enum sec_status s, char* why_bogus, int was_ratelimited)
{
struct ctx_query* q = (struct ctx_query*)arg;
ub_event_callback_type cb = q->cb_event;
else if(s == sec_status_secure)
sec = 2;
(*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf),
- (int)sldns_buffer_limit(buf), sec, why_bogus);
+ (int)sldns_buffer_limit(buf), sec, why_bogus, was_ratelimited);
}
}
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
- w->back->udp_buff, sec_status_insecure, NULL);
+ w->back->udp_buff, sec_status_insecure, NULL, 0);
return UB_NOERROR;
}
if(ctx->env->auth_zones && auth_zones_answer(ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
- w->back->udp_buff, sec_status_insecure, NULL);
+ w->back->udp_buff, sec_status_insecure, NULL, 0);
return UB_NOERROR;
}
/* process new query */
/** add result to the bg worker result queue */
static void
add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
- int err, char* reason)
+ int err, char* reason, int was_ratelimited)
{
uint8_t* msg = NULL;
uint32_t len = 0;
lock_basic_lock(&w->ctx->cfglock);
if(reason)
q->res->why_bogus = strdup(reason);
+ q->res->was_ratelimited = was_ratelimited;
if(pkt) {
q->msg_len = sldns_buffer_remaining(pkt);
q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
- if(!q->msg)
- msg = context_serialize_answer(q, UB_NOMEM,
- NULL, &len);
- else msg = context_serialize_answer(q, err,
- NULL, &len);
- } else msg = context_serialize_answer(q, err, NULL, &len);
+ if(!q->msg) {
+ msg = context_serialize_answer(q, UB_NOMEM, NULL, &len);
+ } else {
+ msg = context_serialize_answer(q, err, NULL, &len);
+ }
+ } else {
+ msg = context_serialize_answer(q, err, NULL, &len);
+ }
lock_basic_unlock(&w->ctx->cfglock);
} else {
if(reason)
q->res->why_bogus = strdup(reason);
+ q->res->was_ratelimited = was_ratelimited;
msg = context_serialize_answer(q, err, pkt, &len);
(void)rbtree_delete(&w->ctx->queries, q->node.key);
w->ctx->num_async--;
void
libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
- char* why_bogus)
+ char* why_bogus, int was_ratelimited)
{
struct ctx_query* q = (struct ctx_query*)arg;
return;
}
q->msg_security = s;
- if(!buf)
+ if(!buf) {
buf = q->w->env->scratch_buffer;
+ }
if(rcode != 0) {
error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
}
- add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
+ add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus, was_ratelimited);
}
return;
}
if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
- add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
+ add_bg_result(w, q, NULL, UB_SYNTAX, NULL, 0);
return;
}
qid = 0;
NULL, 0, NULL, 0, NULL)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
- add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
+ add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
free(qinfo.qname);
return;
}
if(w->ctx->env->auth_zones && auth_zones_answer(w->ctx->env->auth_zones,
- w->env, &qinfo, &edns, w->back->udp_buff, w->env->scratch)) {
+ w->env, &qinfo, &edns, NULL, w->back->udp_buff, w->env->scratch)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
- add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
+ add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL, 0);
free(qinfo.qname);
return;
}
/* process new query */
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
- add_bg_result(w, q, NULL, UB_NOMEM, NULL);
+ add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
}
free(qinfo.qname);
}
struct ub_event_vmt* vmt;
};
-typedef void (*ub_event_callback_type)(void*, int, void*, int, int, char*);
+typedef void (*ub_event_callback_type)(void*, int, void*, int, int, char*, int);
/**
* Create a resolving and validation context.
*/
char* why_bogus;
+ /**
+ * If the query or one of its subqueries was ratelimited. Useful if
+ * ratelimiting is enabled and answer is SERVFAIL.
+ */
+ int was_ratelimited;
+
/**
* TTL for the result, in seconds. If the security is bogus, then
* you also cannot trust this value.
long long qtcp;
/** number of outgoing queries over TCP */
long long qtcp_outgoing;
+ /** number of queries over (DNS over) TLS */
+ long long qtls;
/** number of queries over IPv6 */
long long qipv6;
/** number of queries with QR bit */
/** number of times neg cache records were used to generate NXDOMAIN
* responses. */
long long num_neg_cache_nxdomain;
+ /** number of queries answered from edns-subnet specific data */
+ long long num_query_subnet;
+ /** number of queries answered from edns-subnet specific data, and
+ * the answer was from the edns-subnet cache. */
+ long long num_query_subnet_cache;
};
/**
/** mesh callback with fg results */
void libworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf,
- enum sec_status s, char* why_bogus);
+ enum sec_status s, char* why_bogus, int was_ratelimited);
/** mesh callback with bg results */
void libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf,
- enum sec_status s, char* why_bogus);
+ enum sec_status s, char* why_bogus, int was_ratelimited);
/** mesh callback with event results */
void libworker_event_done_cb(void* arg, int rcode, struct sldns_buffer* buf,
- enum sec_status s, char* why_bogus);
+ enum sec_status s, char* why_bogus, int was_ratelimited);
/**
* Worker signal handler function. User argument is the worker itself.
if(msg->rep->rrset_count == 1) {
msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]);
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
} else if(get_rrset_ttl(msg->rep->rrsets[msg->rep->rrset_count-1]) <
msg->rep->ttl) {
msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[
msg->rep->rrset_count-1]);
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
}
}
}
/* copy base values */
memcpy(sigd, sigold, sizeof(struct packed_rrset_data));
- sigd->rrsig_count -= sigs;
+ /* in sigd the RRSIGs are stored in the base of the RR, in count */
+ sigd->count -= sigs;
/* setup rr_len */
sigd->rr_len = (size_t*)((uint8_t*)sigd +
sizeof(struct packed_rrset_data));
d->rr_ttl[0] = (time_t)minimum;
msg->rep->ttl = get_rrset_ttl(msg->rep->rrsets[0]);
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
return 1;
}
/** encode auth answer */
static void
auth_answer_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- struct dns_msg* msg)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct dns_msg* msg)
{
uint16_t udpsize;
udpsize = edns->udp_size;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, msg->rep,
- (int)FLAGS_GET_RCODE(msg->rep->flags), edns, temp)
+ (int)FLAGS_GET_RCODE(msg->rep->flags), edns, repinfo, temp)
|| !reply_info_answer_encode(qinfo, msg->rep,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
/** encode auth error answer */
static void
auth_error_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- int rcode)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, int rcode)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, temp))
+ rcode, edns, repinfo, temp))
edns->opt_list = NULL;
error_encode(buf, rcode|BIT_AA, qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
}
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf,
- struct regional* temp)
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp)
{
struct dns_msg* msg = NULL;
struct auth_zone* z;
/* encode answer */
if(!r)
- auth_error_encode(qinfo, env, edns, buf, temp,
+ auth_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_SERVFAIL);
- else auth_answer_encode(qinfo, env, edns, buf, temp, msg);
+ else auth_answer_encode(qinfo, env, edns, repinfo, buf, temp, msg);
return 1;
}
return 1;
}
+int auth_zones_startprobesequence(struct auth_zones* az,
+ struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass)
+{
+ struct auth_xfer* xfr;
+ lock_rw_rdlock(&az->lock);
+ xfr = auth_xfer_find(az, nm, nmlen, dclass);
+ if(!xfr) {
+ lock_rw_unlock(&az->lock);
+ return 0;
+ }
+ lock_basic_lock(&xfr->lock);
+ lock_rw_unlock(&az->lock);
+
+ xfr_process_notify(xfr, env, 0, 0, NULL);
+ return 1;
+}
+
/** set a zone expired */
static void
auth_xfer_set_expired(struct auth_xfer* xfr, struct module_env* env,
xfr_transfer_disown(xfr);
/* pick up the nextprobe task and wait */
- xfr_set_timeout(xfr, env, 1, 0);
+ if(xfr->task_nextprobe->worker == NULL)
+ xfr_set_timeout(xfr, env, 1, 0);
lock_basic_unlock(&xfr->lock);
}
/** callback for task_transfer lookup of host name, of A or AAAA */
void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
- enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus))
+ enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
+ int ATTR_UNUSED(was_ratelimited))
{
struct auth_xfer* xfr = (struct auth_xfer*)arg;
struct module_env* env;
return;
} else {
/* pick up the nextprobe task and wait (normail wait time) */
- xfr_set_timeout(xfr, env, 0, 0);
+ if(xfr->task_nextprobe->worker == NULL)
+ xfr_set_timeout(xfr, env, 0, 0);
}
lock_basic_unlock(&xfr->lock);
return;
return 0;
}
+ /* other tasks are running, we don't do this anymore */
+ xfr_probe_disown(xfr);
+ lock_basic_unlock(&xfr->lock);
+ /* return, we don't sent a reply to this udp packet,
+ * and we setup the tasks to do next */
+ return 0;
} else {
- /* if zone not updated, start the wait timer again */
- verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait");
- if(xfr->have_zone)
- xfr->lease_time = *env->now;
- if(xfr->task_nextprobe->worker == NULL)
- xfr_set_timeout(xfr, env, 0, 0);
+ verbose(VERB_ALGO, "auth_zone master reports unchanged soa serial");
+ /* we if cannot find updates amongst the
+ * masters, this means we then have a new lease
+ * on the zone */
+ xfr->task_probe->have_new_lease = 1;
+ }
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char buf[256];
+ dname_str(xfr->name, buf);
+ verbose(VERB_ALGO, "auth zone %s: bad reply to soa probe", buf);
}
- /* other tasks are running, we don't do this anymore */
- xfr_probe_disown(xfr);
- lock_basic_unlock(&xfr->lock);
- /* return, we don't sent a reply to this udp packet,
- * and we setup the tasks to do next */
- return 0;
}
- }
- if(verbosity >= VERB_ALGO) {
- char buf[256];
- dname_str(xfr->name, buf);
- verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf);
+ } else {
+ if(verbosity >= VERB_ALGO) {
+ char buf[256];
+ dname_str(xfr->name, buf);
+ verbose(VERB_ALGO, "auth zone %s: soa probe failed", buf);
+ }
}
- /* failed lookup */
+ /* failed lookup or not an update */
/* delete commpoint so a new one is created, with a fresh port nr */
comm_point_delete(xfr->task_probe->cp);
xfr->task_probe->cp = NULL;
/* only wanted lookups for copy, stop probe and start wait */
xfr->task_probe->only_lookup = 0;
xfr_probe_disown(xfr);
- xfr_set_timeout(xfr, env, 0, 0);
+ if(xfr->task_nextprobe->worker == NULL)
+ xfr_set_timeout(xfr, env, 0, 0);
lock_basic_unlock(&xfr->lock);
return;
}
xfr_probe_nextmaster(xfr);
}
- /* we failed to send this as well, move to the wait task,
- * use the shorter retry timeout */
- xfr_probe_disown(xfr);
+ /* done with probe sequence, wait */
+ if(xfr->task_probe->have_new_lease) {
+ /* if zone not updated, start the wait timer again */
+ verbose(VERB_ALGO, "auth_zone unchanged, new lease, wait");
+ xfr_probe_disown(xfr);
+ if(xfr->have_zone)
+ xfr->lease_time = *env->now;
+ if(xfr->task_nextprobe->worker == NULL)
+ xfr_set_timeout(xfr, env, 0, 0);
+ } else {
+ /* we failed to send this as well, move to the wait task,
+ * use the shorter retry timeout */
+ xfr_probe_disown(xfr);
+ /* pick up the nextprobe task and wait */
+ if(xfr->task_nextprobe->worker == NULL)
+ xfr_set_timeout(xfr, env, 1, 0);
+ }
- /* pick up the nextprobe task and wait */
- xfr_set_timeout(xfr, env, 1, 0);
lock_basic_unlock(&xfr->lock);
}
/** callback for task_probe lookup of host name, of A or AAAA */
void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
- enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus))
+ enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
+ int ATTR_UNUSED(was_ratelimited))
{
struct auth_xfer* xfr = (struct auth_xfer*)arg;
struct module_env* env;
xfr->task_probe->cp = NULL;
/* start the task */
+ /* have not seen a new lease yet, this scan */
+ xfr->task_probe->have_new_lease = 0;
/* if this was a timeout, no specific first master to scan */
/* otherwise, spec is nonNULL the notified master, scan
* first and also transfer first from it */
/** we only want to do lookups for making config work (for notify),
* don't proceed with UDP SOA probe queries */
int only_lookup;
+ /** we have seen a new lease this scan, because one of the masters
+ * replied with the current SOA serial version */
+ int have_new_lease;
/** once notified, or the timeout has been reached. a scan starts. */
/** the scan specific target (notify source), or NULL if none */
* @param qinfo: query info (parsed).
* @param edns: edns info (parsed).
* @param buf: buffer with query ID and flags, also for reply.
+ * @param repinfo: reply information for a communication point.
* @param temp: temporary storage region.
* @return false if not answered
*/
int auth_zones_answer(struct auth_zones* az, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf,
- struct regional* temp);
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, struct sldns_buffer* buf, struct regional* temp);
/**
* Find the auth zone that is above the given qname.
* returns 0 if no soa record in the notify */
int auth_zone_parse_notify_serial(struct sldns_buffer* pkt, uint32_t *serial);
+/** for the zone and if not already going, starts the probe sequence.
+ * false if zone cannot be found. This is like a notify arrived and was
+ * accepted for that zone. */
+int auth_zones_startprobesequence(struct auth_zones* az,
+ struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass);
+
/** read auth zone from zonefile. caller must lock zone. false on failure */
int auth_zone_read_zonefile(struct auth_zone* z);
void auth_xfer_probe_timer_callback(void* arg);
/** mesh callback for task_probe on lookup of host names */
void auth_xfer_probe_lookup_callback(void* arg, int rcode,
- struct sldns_buffer* buf, enum sec_status sec, char* why_bogus);
+ struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
+ int was_ratelimited);
/** mesh callback for task_transfer on lookup of host names */
void auth_xfer_transfer_lookup_callback(void* arg, int rcode,
- struct sldns_buffer* buf, enum sec_status sec, char* why_bogus);
+ struct sldns_buffer* buf, enum sec_status sec, char* why_bogus,
+ int was_ratelimited);
/*
* Compares two 32-bit serial numbers as defined in RFC1982. Returns
}
/** delete message from message cache */
-static void
+void
msg_cache_remove(struct module_env* env, uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags)
{
if(r->prefetch_ttl > now)
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
else msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->security = r->security;
msg->rep->an_numrrsets = r->an_numrrsets;
msg->rep->ns_numrrsets = r->ns_numrrsets;
msg->rep->qdcount = 1;
msg->rep->ttl = d->ttl - now;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->security = sec_status_unchecked;
msg->rep->an_numrrsets = 1;
msg->rep->ns_numrrsets = 0;
msg->rep->qdcount = 1;
msg->rep->ttl = d->ttl - now;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->security = sec_status_unchecked;
msg->rep->an_numrrsets = 1;
msg->rep->ns_numrrsets = 0;
newd->rr_ttl[0] = newd->ttl;
msg->rep->ttl = newd->ttl;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(newd->ttl);
+ msg->rep->serve_expired_ttl = newd->ttl + SERVE_EXPIRED_TTL;
sldns_write_uint16(newd->rr_data[0], newlen);
memmove(newd->rr_data[0] + sizeof(uint16_t), newname, newlen);
msg->rep->an_numrrsets ++;
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, time_t now, int wr);
+/**
+ * Remove entry from the message cache. For unwanted entries.
+ * @param env: with message cache.
+ * @param qname: query name, in wireformat
+ * @param qnamelen: length of qname, including terminating 0.
+ * @param qtype: query type, host order.
+ * @param qclass: query class, host order.
+ * @param flags: flags
+ */
+void msg_cache_remove(struct module_env* env, uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags);
+
#endif /* SERVICES_CACHE_DNS_H */
return 1;
}
+/** setup domain limits tree (0 on failure) */
+static int
+setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
+{
+ name_tree_init(&infra->domain_limits);
+ if(!infra_ratelimit_cfg_insert(infra, cfg)) {
+ return 0;
+ }
+ name_tree_init_parents(&infra->domain_limits);
+ return 1;
+}
+
struct infra_cache*
infra_create(struct config_file* cfg)
{
return NULL;
}
infra->host_ttl = cfg->host_ttl;
- name_tree_init(&infra->domain_limits);
infra_dp_ratelimit = cfg->ratelimit;
infra->domain_rates = slabhash_create(cfg->ratelimit_slabs,
INFRA_HOST_STARTSIZE, cfg->ratelimit_size,
return NULL;
}
/* insert config data into ratelimits */
- if(!infra_ratelimit_cfg_insert(infra, cfg)) {
+ if(!setup_domain_limits(infra, cfg)) {
infra_delete(infra);
return NULL;
}
- name_tree_init_parents(&infra->domain_limits);
infra_ip_ratelimit = cfg->ip_ratelimit;
infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs,
INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc,
if(!infra)
return infra_create(cfg);
infra->host_ttl = cfg->host_ttl;
+ infra_dp_ratelimit = cfg->ratelimit;
+ infra_ip_ratelimit = cfg->ip_ratelimit;
maxmem = cfg->infra_cache_numhosts * (sizeof(struct infra_key)+
sizeof(struct infra_data)+INFRA_BYTES_NAME);
- if(maxmem != slabhash_get_size(infra->hosts) ||
- cfg->infra_cache_slabs != infra->hosts->size) {
+ /* divide cachesize by slabs and multiply by slabs, because if the
+ * cachesize is not an even multiple of slabs, that is the resulting
+ * size of the slabhash */
+ if(!slabhash_is_size(infra->hosts, maxmem, cfg->infra_cache_slabs) ||
+ !slabhash_is_size(infra->domain_rates, cfg->ratelimit_size,
+ cfg->ratelimit_slabs) ||
+ !slabhash_is_size(infra->client_ip_rates, cfg->ip_ratelimit_size,
+ cfg->ip_ratelimit_slabs)) {
infra_delete(infra);
infra = infra_create(cfg);
+ } else {
+ /* reapply domain limits */
+ traverse_postorder(&infra->domain_limits, domain_limit_free,
+ NULL);
+ if(!setup_domain_limits(infra, cfg)) {
+ infra_delete(infra);
+ return NULL;
+ }
}
return infra;
}
struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r,
struct config_file* cfg, struct alloc_cache* alloc)
{
- if(!r || !cfg || cfg->rrset_cache_slabs != r->table.size ||
- cfg->rrset_cache_size != slabhash_get_size(&r->table))
+ if(!r || !cfg || !slabhash_is_size(&r->table, cfg->rrset_cache_size,
+ cfg->rrset_cache_slabs))
{
rrset_cache_delete(r);
r = rrset_cache_create(cfg, alloc);
int freebind, int use_systemd)
{
int s;
-#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined(SO_BINDANY)
+#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined (SO_BINDANY)
int on=1;
#endif
#ifdef IPV6_MTU
/* detect freebsd jail with no ipv6 permission */
if(family==AF_INET6 && errno==EINVAL)
*noproto = 1;
- else if(errno != EADDRINUSE) {
+ else if(errno != EADDRINUSE &&
+ !(errno == EACCES && verbosity < 4 && !listen)) {
log_err_addr("can't bind socket", strerror(errno),
(struct sockaddr_storage*)addr, addrlen);
}
close(s);
#else /* USE_WINSOCK */
if(WSAGetLastError() != WSAEADDRINUSE &&
- WSAGetLastError() != WSAEADDRNOTAVAIL) {
+ WSAGetLastError() != WSAEADDRNOTAVAIL &&
+ !(WSAGetLastError() == WSAEACCES && verbosity < 4 && !listen)) {
log_err_addr("can't bind socket",
wsa_strerror(WSAGetLastError()),
(struct sockaddr_storage*)addr, addrlen);
struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ports,
- size_t bufsize, int tcp_accept_count, void* sslctx,
+ size_t bufsize, int tcp_accept_count, int tcp_idle_timeout,
+ struct tcl_list* tcp_conn_limit, void* sslctx,
struct dt_env* dtenv, comm_point_callback_type* cb, void *cb_arg)
{
struct listen_dnsport* front = (struct listen_dnsport*)
else if(ports->ftype == listen_type_tcp ||
ports->ftype == listen_type_tcp_dnscrypt)
cp = comm_point_create_tcp(base, ports->fd,
- tcp_accept_count, bufsize, cb, cb_arg);
+ tcp_accept_count, tcp_idle_timeout,
+ tcp_conn_limit, bufsize, cb, cb_arg);
else if(ports->ftype == listen_type_ssl) {
cp = comm_point_create_tcp(base, ports->fd,
- tcp_accept_count, bufsize, cb, cb_arg);
+ tcp_accept_count, tcp_idle_timeout,
+ tcp_conn_limit, bufsize, cb, cb_arg);
cp->ssl = sslctx;
} else if(ports->ftype == listen_type_udpancil ||
ports->ftype == listen_type_udpancil_dnscrypt)
struct config_file;
struct addrinfo;
struct sldns_buffer;
+struct tcl_list;
/**
* Listening for queries structure.
* @param bufsize: size of datagram buffer.
* @param tcp_accept_count: max number of simultaneous TCP connections
* from clients.
+ * @param tcp_idle_timeout: idle timeout for TCP connections in msec.
+ * @param tcp_conn_limit: TCP connection limit info.
* @param sslctx: nonNULL if ssl context.
* @param dtenv: nonNULL if dnstap enabled.
* @param cb: callback function when a request arrives. It is passed
* @return: the malloced listening structure, ready for use. NULL on error.
*/
struct listen_dnsport* listen_create(struct comm_base* base,
- struct listen_port* ports, size_t bufsize, int tcp_accept_count,
- void* sslctx, struct dt_env *dtenv, comm_point_callback_type* cb,
- void* cb_arg);
+ struct listen_port* ports, size_t bufsize,
+ int tcp_accept_count, int tcp_idle_timeout,
+ struct tcl_list* tcp_conn_limit, void* sslctx,
+ struct dt_env *dtenv, comm_point_callback_type* cb, void* cb_arg);
/**
* delete the listening structure
/** encode answer consisting of 1 rrset */
static int
local_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- struct ub_packed_rrset_key* rrset, int ansec, int rcode)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
+ int rcode)
{
struct reply_info rep;
uint16_t udpsize;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
- if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns, temp)
- || !reply_info_answer_encode(qinfo, &rep,
- *(uint16_t*)sldns_buffer_begin(buf),
- sldns_buffer_read_u16_at(buf, 2),
- buf, 0, 0, temp, udpsize, edns,
- (int)(edns->bits&EDNS_DO), 0))
+ if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
+ repinfo, temp) || !reply_info_answer_encode(qinfo, &rep,
+ *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
+ }
return 1;
}
/** encode local error answer */
static void
local_error_encode(struct query_info* qinfo, struct module_env* env,
- struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
- int rcode, int r)
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, int rcode, int r)
{
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
- rcode, edns, temp))
+ rcode, edns, repinfo, temp))
edns->opt_list = NULL;
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
/** answer local data match */
static int
local_data_answer(struct local_zone* z, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags)
* chain. */
if(qinfo->local_alias)
return 1;
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
&r, 1, LDNS_RCODE_NOERROR);
}
}
struct ub_packed_rrset_key r = *lr->rrset;
r.rk.dname = qinfo->qname;
r.rk.dname_len = qinfo->qname_len;
- return local_encode(qinfo, env, edns, buf, temp, &r, 1,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1,
LDNS_RCODE_NOERROR);
}
- return local_encode(qinfo, env, edns, buf, temp, lr->rrset, 1,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
LDNS_RCODE_NOERROR);
}
+/**
+ * See if the local zone does not cover the name, eg. the name is not
+ * in the zone and the zone is transparent */
+static int
+local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
+ int labs)
+{
+ struct local_data key;
+ struct local_data* ld = NULL;
+ struct local_rrset* lr = NULL;
+ if(z->type == local_zone_always_transparent)
+ return 1;
+ if(z->type != local_zone_transparent
+ && z->type != local_zone_typetransparent
+ && z->type != local_zone_inform)
+ return 0;
+ key.node.key = &key;
+ key.name = qinfo->qname;
+ key.namelen = qinfo->qname_len;
+ key.namelabs = labs;
+ ld = (struct local_data*)rbtree_search(&z->data, &key.node);
+ if(z->type == local_zone_transparent || z->type == local_zone_inform)
+ return (ld == NULL);
+ if(ld)
+ lr = local_data_find_type(ld, qinfo->qtype, 1);
+ /* local_zone_typetransparent */
+ return (lr == NULL);
+}
+
/**
- * answer in case where no exact match is found
- * @param z: zone for query
- * @param env: module environment
- * @param qinfo: query
- * @param edns: edns from query
+ * Answer in case where no exact match is found.
+ * @param z: zone for query.
+ * @param env: module environment.
+ * @param qinfo: query.
+ * @param edns: edns from query.
+ * @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
- * @param temp: temp region for encoding
+ * @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
- * @param lz_type: type of the local zone
+ * @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
static int
lz_zone_answer(struct local_zone* z, struct module_env* env,
- struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
- struct regional* temp, struct local_data* ld, enum localzone_type lz_type)
+ struct query_info* qinfo, struct edns_data* edns,
+ struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
+ struct local_data* ld, enum localzone_type lz_type)
{
if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) {
/** no reply at all, signal caller by clearing buffer. */
return 1;
} else if(lz_type == local_zone_refuse
|| lz_type == local_zone_always_refuse) {
- local_error_encode(qinfo, env, edns, buf, temp,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA));
return 1;
} else if(lz_type == local_zone_static ||
int rcode = (ld || lz_type == local_zone_redirect)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
if(z->soa)
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa, 0, rcode);
- local_error_encode(qinfo, env, edns, buf, temp, rcode,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
} else if(lz_type == local_zone_typetransparent
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
if(z->soa)
- return local_encode(qinfo, env, edns, buf, temp,
+ return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa, 0, rcode);
- local_error_encode(qinfo, env, edns, buf, temp, rcode,
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
(rcode|BIT_AA));
return 1;
}
uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
dname_str(z->name, zname);
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
- snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip,
+ snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip,
(unsigned)port);
log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
}
(z = local_zones_lookup(view->local_zones,
qinfo->qname, qinfo->qname_len, labs,
qinfo->qclass, qinfo->qtype))) {
- if(z->type != local_zone_noview)
- verbose(VERB_ALGO,
- "using localzone from view: %s",
- view->name);
lock_rw_rdlock(&z->lock);
lzt = z->type;
}
lock_rw_unlock(&z->lock);
z = NULL;
}
+ if(z && (lzt == local_zone_transparent ||
+ lzt == local_zone_typetransparent ||
+ lzt == local_zone_inform ||
+ lzt == local_zone_always_transparent) &&
+ local_zone_does_not_cover(z, qinfo, labs)) {
+ lock_rw_unlock(&z->lock);
+ z = NULL;
+ }
if(view->local_zones && !z && !view->isfirst){
lock_rw_unlock(&view->lock);
return 0;
}
+ if(z && verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(z->name, zname);
+ verbose(VERB_ALGO, "using localzone %s %s from view %s",
+ zname, local_zone_type2str(lzt), view->name);
+ }
lock_rw_unlock(&view->lock);
}
if(!z) {
return 0;
}
lock_rw_rdlock(&z->lock);
-
lzt = lz_type(taglist, taglen, z->taglist, z->taglen,
tagactions, tagactionssize, z->type, repinfo,
z->override_tree, &tag, tagname, num_tags);
lock_rw_unlock(&zones->lock);
+ if(z && verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(z->name, zname);
+ verbose(VERB_ALGO, "using localzone %s %s", zname,
+ local_zone_type2str(lzt));
+ }
}
- if((lzt == local_zone_inform || lzt == local_zone_inform_deny)
- && repinfo)
+ if((env->cfg->log_local_actions ||
+ lzt == local_zone_inform || lzt == local_zone_inform_deny)
+ && repinfo)
lz_inform_print(z, qinfo, repinfo);
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain
- && local_data_answer(z, env, qinfo, edns, buf, temp, labs, &ld, lzt,
- tag, tag_datas, tag_datas_size, tagname, num_tags)) {
+ && local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
+ &ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock);
/* We should tell the caller that encode is deferred if we found
* a local alias. */
return !qinfo->local_alias;
}
- r = lz_zone_answer(z, env, qinfo, edns, buf, temp, ld, lzt);
+ r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
lock_rw_unlock(&z->lock);
return r && !qinfo->local_alias; /* see above */
}
#include "util/fptr_wlist.h"
#include "util/alloc.h"
#include "util/config_file.h"
+#include "util/edns.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
#include "services/localzone.h"
if(!s) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
- LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch))
+ LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
if(!s->s.edns_opts_front_in) {
log_err("mesh_state_create: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL,
- NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
log_err("mesh_new_client: out of memory; SERVFAIL");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
- NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch))
+ NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
edns->opt_list = NULL;
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
mesh_run(mesh, e->qstate->mesh_info, event, e);
}
-struct mesh_state*
-mesh_state_create(struct module_env* env, struct query_info* qinfo,
+struct mesh_state*
+mesh_state_create(struct module_env* env, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags, int prime,
int valrec)
{
mstate->s.no_cache_lookup = 0;
mstate->s.no_cache_store = 0;
mstate->s.need_refetch = 0;
+ mstate->s.was_ratelimited = 0;
/* init modules */
for(i=0; i<env->mesh->mods.num; i++) {
mstate->cb_list = cb->next;
fptr_ok(fptr_whitelist_mesh_cb(cb->cb));
(*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL,
- sec_status_unchecked, NULL);
+ sec_status_unchecked, NULL, 0);
mesh->num_reply_addrs--;
}
}
{
int secure;
char* reason = NULL;
- /* bogus messages are not made into servfail, sec_status passed
+ int was_ratelimited = m->s.was_ratelimited;
+ /* bogus messages are not made into servfail, sec_status passed
* to the callback function */
if(rep && rep->security == sec_status_secure)
secure = 1;
rcode = LDNS_RCODE_SERVFAIL;
if(!rcode && (rep->security == sec_status_bogus ||
rep->security == sec_status_secure_sentinel_fail)) {
- if(!(reason = errinf_to_str(&m->s)))
+ if(!(reason = errinf_to_str_bogus(&m->s)))
rcode = LDNS_RCODE_SERVFAIL;
}
/* send the reply */
if(rcode) {
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, m->s.region))
+ &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
}
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
- (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL);
+ (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL,
+ was_ratelimited);
} else {
size_t udp_size = r->edns.udp_size;
sldns_buffer_clear(r->buf);
r->edns.bits &= EDNS_DO;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->buf, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
{
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
- sec_status_unchecked, NULL);
+ sec_status_unchecked, NULL, 0);
} else {
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf,
- rep->security, reason);
+ rep->security, reason, was_ratelimited);
}
}
free(reason);
m->s.qinfo.local_alias = r->local_alias;
if(rcode == LDNS_RCODE_SERVFAIL) {
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, rcode, &r->edns, m->s.region))
+ rep, rcode, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
- &r->edns, m->s.region))
+ &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
}
error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
m->s.qinfo.qname = r->qname;
m->s.qinfo.local_alias = r->local_alias;
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep,
- LDNS_RCODE_NOERROR, &r->edns, m->s.region) ||
+ LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region) ||
+ !apply_edns_options(&r->edns, &edns_bak,
+ m->s.env->cfg, r->query_reply.c,
+ m->s.region) ||
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->query_reply.c->buffer, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
(int)(r->edns.bits & EDNS_DO), secure))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
- rep, LDNS_RCODE_SERVFAIL, &r->edns, m->s.region))
+ rep, LDNS_RCODE_SERVFAIL, &r->edns, NULL, m->s.region))
r->edns.opt_list = NULL;
error_encode(r->query_reply.c->buffer,
LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid,
struct mesh_cb* c;
struct reply_info* rep = (mstate->s.return_msg?
mstate->s.return_msg->rep:NULL);
+ if((mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
+ (rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL))
+ && mstate->s.env->cfg->log_servfail
+ && !mstate->s.env->cfg->val_log_squelch) {
+ char* err = errinf_to_str_servfail(&mstate->s);
+ if(err)
+ log_err("%s", err);
+ free(err);
+ }
for(r = mstate->reply_list; r; r = r->next) {
/* if a response-ip address block has been stored the
* information should be logged for each client. */
mesh->mods.mod[ref->s->s.curmod]->inform_super));
(*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s,
ref->s->s.curmod, &ref->s->s);
+ /* copy state that is always relevant to super */
+ copy_state_to_super(&mstate->s, ref->s->s.curmod, &ref->s->s);
}
}
/**
* Mesh result callback func.
- * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus);
+ * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus,
+ * was_ratelimited);
*/
-typedef void (*mesh_cb_func_type)(void*, int, struct sldns_buffer*, enum sec_status,
- char*);
+typedef void (*mesh_cb_func_type)(void* cb_arg, int rcode, struct sldns_buffer*,
+ enum sec_status, char* why_bogus, int was_ratelimited);
/**
* Callback to result routine
uint16_t qflags;
/** buffer for reply */
struct sldns_buffer* buf;
-
/** callback routine for results. if rcode != 0 buf has message.
- * called as cb(cb_arg, rcode, buf, sec_state);
+ * called as cb(cb_arg, rcode, buf, sec_state, why_bogus, was_ratelimited);
*/
mesh_cb_func_type cb;
/** user arg for callback */
#include "services/outside_network.h"
#include "services/listen_dnsport.h"
#include "services/cache/infra.h"
+#include "iterator/iterator.h"
#include "util/data/msgparse.h"
#include "util/data/msgreply.h"
#include "util/data/msgencode.h"
int freebind = 0;
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
sa.sin6_port = (in_port_t)htons((uint16_t)port);
+ sa.sin6_flowinfo = 0;
+ sa.sin6_scope_id = 0;
if(pfxlen != 0) {
freebind = 1;
sai6_putrandom(&sa, pfxlen, rnd);
sq->last_sent_time = *sq->outnet->now_tv;
if(sq->tcp_upstream || sq->ssl_upstream) {
timeout = rtt;
- if(rtt >= 376 && rtt < TCP_AUTH_QUERY_TIMEOUT)
+ if(rtt >= UNKNOWN_SERVER_NICENESS && rtt < TCP_AUTH_QUERY_TIMEOUT)
timeout = TCP_AUTH_QUERY_TIMEOUT;
} else {
timeout = TCP_AUTH_QUERY_TIMEOUT;
{
struct sockaddr_storage* addr;
socklen_t addrlen;
- int i;
- int try;
-
- /* select interface */
- if(addr_is_ip6(to_addr, to_addrlen)) {
- if(outnet->num_ip6 == 0) {
- char to[64];
- addr_to_str(to_addr, to_addrlen, to, sizeof(to));
- verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to);
- return -1;
- }
- i = ub_random_max(outnet->rnd, outnet->num_ip6);
- addr = &outnet->ip6_ifs[i].addr;
- addrlen = outnet->ip6_ifs[i].addrlen;
- } else {
- if(outnet->num_ip4 == 0) {
- char to[64];
- addr_to_str(to_addr, to_addrlen, to, sizeof(to));
- verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to);
- return -1;
- }
- i = ub_random_max(outnet->rnd, outnet->num_ip4);
- addr = &outnet->ip4_ifs[i].addr;
- addrlen = outnet->ip4_ifs[i].addrlen;
- }
+ int i, try, pnum;
+ struct port_if* pif;
/* create fd */
for(try = 0; try<1000; try++) {
+ int port = 0;
int freebind = 0;
int noproto = 0;
int inuse = 0;
- int port = ub_random(outnet->rnd)&0xffff;
int fd = -1;
+
+ /* select interface */
+ if(addr_is_ip6(to_addr, to_addrlen)) {
+ if(outnet->num_ip6 == 0) {
+ char to[64];
+ addr_to_str(to_addr, to_addrlen, to, sizeof(to));
+ verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to);
+ return -1;
+ }
+ i = ub_random_max(outnet->rnd, outnet->num_ip6);
+ pif = &outnet->ip6_ifs[i];
+ } else {
+ if(outnet->num_ip4 == 0) {
+ char to[64];
+ addr_to_str(to_addr, to_addrlen, to, sizeof(to));
+ verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to);
+ return -1;
+ }
+ i = ub_random_max(outnet->rnd, outnet->num_ip4);
+ pif = &outnet->ip4_ifs[i];
+ }
+ addr = &pif->addr;
+ addrlen = pif->addrlen;
+ pnum = ub_random_max(outnet->rnd, pif->avail_total);
+ if(pnum < pif->inuse) {
+ /* port already open */
+ port = pif->out[pnum]->number;
+ } else {
+ /* unused ports in start part of array */
+ port = pif->avail_ports[pnum - pif->inuse];
+ }
+
if(addr_is_ip6(to_addr, to_addrlen)) {
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
sa.sin6_port = (in_port_t)htons((uint16_t)port);
{LDNS_RR_TYPE_NSEC3PARAM, "NSEC3PARAM", 4, 4, type_nsec3param_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
/* 52 */
{LDNS_RR_TYPE_TLSA, "TLSA", 4, 4, type_tlsa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
- /*53 */
-#ifdef DRAFT_RRTYPES
+ /* 53 */
{LDNS_RR_TYPE_SMIMEA, "SMIMEA", 4, 4, type_tlsa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
-#else
-{LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
-#endif
+ /* 54 */
{LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
/* 55
* Hip ends with 0 or more Rendezvous Servers represented as dname's.
LDNS_RR_TYPE_NSEC3PARAM = 51, /* RFC 5155 */
LDNS_RR_TYPE_NSEC3PARAMS = 51,
LDNS_RR_TYPE_TLSA = 52, /* RFC 6698 */
- LDNS_RR_TYPE_SMIMEA = 53, /* draft-ietf-dane-smime, TLSA-like but may
- be extended */
-
+ LDNS_RR_TYPE_SMIMEA = 53, /* RFC 8162 */
LDNS_RR_TYPE_HIP = 55, /* RFC 5205 */
/** draft-reid-dnsext-zs */
printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER);
printf("-4 work using IPv4 only\n");
printf("-6 work using IPv6 only\n");
- printf("-f resolv.conf use given resolv.conf to resolve -u name\n");
- printf("-r root.hints use given root.hints to resolve -u name\n"
+ printf("-f resolv.conf use given resolv.conf\n");
+ printf("-r root.hints use given root.hints\n"
" builtin root hints are used by default\n");
+ printf("-R fallback from -f to root query on error\n");
printf("-v more verbose\n");
printf("-C conf debug, read config\n");
printf("-P port use port for https connect, default 443\n");
do_certupdate(const char* root_anchor_file, const char* root_cert_file,
const char* urlname, const char* xmlname, const char* p7sname,
const char* p7signer, const char* res_conf, const char* root_hints,
- const char* debugconf, int ip4only, int ip6only, int port,
- struct ub_result* dnskey)
+ const char* debugconf, int ip4only, int ip6only, int port)
{
STACK_OF(X509)* cert;
BIO *xml, *p7s;
#ifndef S_SPLINT_S
sk_X509_pop_free(cert, X509_free);
#endif
- ub_resolve_free(dnskey);
ip_list_free(ip_list);
return 1;
}
return 0;
}
+static struct ub_result *
+fetch_root_key(const char* root_anchor_file, const char* res_conf,
+ const char* root_hints, const char* debugconf,
+ int ip4only, int ip6only)
+{
+ struct ub_ctx* ctx;
+ struct ub_result* dnskey;
+
+ ctx = create_unbound_context(res_conf, root_hints, debugconf,
+ ip4only, ip6only);
+ add_5011_probe_root(ctx, root_anchor_file);
+ dnskey = prime_root_key(ctx);
+ ub_ctx_delete(ctx);
+ return dnskey;
+}
+
/** perform the unbound-anchor work */
static int
do_root_update_work(const char* root_anchor_file, const char* root_cert_file,
const char* urlname, const char* xmlname, const char* p7sname,
const char* p7signer, const char* res_conf, const char* root_hints,
- const char* debugconf, int ip4only, int ip6only, int force, int port)
+ const char* debugconf, int ip4only, int ip6only, int force,
+ int res_conf_fallback, int port)
{
- struct ub_ctx* ctx;
struct ub_result* dnskey;
int used_builtin = 0;
+ int rcode;
/* see if builtin rootanchor needs to be provided, or if
* rootanchor is 'revoked-trust-point' */
/* make unbound context with 5011-probe for root anchor,
* and probe . DNSKEY */
- ctx = create_unbound_context(res_conf, root_hints, debugconf,
- ip4only, ip6only);
- add_5011_probe_root(ctx, root_anchor_file);
- dnskey = prime_root_key(ctx);
- ub_ctx_delete(ctx);
-
+ dnskey = fetch_root_key(root_anchor_file, res_conf,
+ root_hints, debugconf, ip4only, ip6only);
+ rcode = dnskey->rcode;
+
+ if (res_conf_fallback && res_conf && !dnskey->secure) {
+ if (verb) printf("%s failed, retrying direct\n", res_conf);
+ ub_resolve_free(dnskey);
+ /* try direct query without res_conf */
+ dnskey = fetch_root_key(root_anchor_file, NULL,
+ root_hints, debugconf, ip4only, ip6only);
+ if (rcode != 0 && dnskey->rcode == 0) {
+ res_conf = NULL;
+ rcode = 0;
+ }
+ }
+
/* if secure: exit */
if(dnskey->secure && !force) {
if(verb) printf("success: the anchor is ok\n");
return used_builtin;
}
if(force && verb) printf("debug cert update forced\n");
+ ub_resolve_free(dnskey);
/* if not (and NOERROR): check date and do certupdate */
- if((dnskey->rcode == 0 &&
+ if((rcode == 0 &&
probe_date_allows_certupdate(root_anchor_file)) || force) {
if(do_certupdate(root_anchor_file, root_cert_file, urlname,
xmlname, p7sname, p7signer, res_conf, root_hints,
- debugconf, ip4only, ip6only, port, dnskey))
+ debugconf, ip4only, ip6only, port))
return 1;
return used_builtin;
}
if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n");
- ub_resolve_free(dnskey);
return used_builtin;
}
const char* root_hints = NULL;
const char* debugconf = NULL;
int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT;
+ int res_conf_fallback = 0;
/* parse the options */
- while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) {
+ while( (c=getopt(argc, argv, "46C:FRP:a:c:f:hln:r:s:u:vx:")) != -1) {
switch(c) {
case 'l':
dolist = 1;
case 'r':
root_hints = optarg;
break;
+ case 'R':
+ res_conf_fallback = 1;
+ break;
case 'C':
debugconf = optarg;
break;
return do_root_update_work(root_anchor_file, root_cert_file, urlname,
xmlname, p7sname, p7signer, res_conf, root_hints, debugconf,
- ip4only, ip6only, force, port);
+ ip4only, ip6only, force, res_conf_fallback, port);
}
*/
#include "config.h"
+#include <ctype.h>
#include "util/log.h"
#include "util/config_file.h"
#include "util/module.h"
}
}
+/** check tcp connection limit ips */
+static void
+tcpconnlimitchecks(struct config_file* cfg)
+{
+ int d;
+ struct sockaddr_storage a;
+ socklen_t alen;
+ struct config_str2list* tcl;
+ for(tcl=cfg->tcp_connection_limits; tcl; tcl = tcl->next) {
+ if(!netblockstrtoaddr(tcl->str, UNBOUND_DNS_PORT, &a, &alen,
+ &d)) {
+ fatal_exit("cannot parse tcp connection limit address %s %s",
+ tcl->str, tcl->str2);
+ }
+ }
+}
+
/** true if fname is a file */
static int
is_file(const char* fname)
}
#endif /* CLIENT_SUBNET */
+/** check that the modules exist, are compiled in */
+static void
+check_modules_exist(const char* module_conf)
+{
+ const char** names = module_list_avail();
+ const char* s = module_conf;
+ while(*s) {
+ int i = 0;
+ int is_ok = 0;
+ while(*s && isspace((unsigned char)*s))
+ s++;
+ if(!*s) break;
+ while(names[i]) {
+ if(strncmp(names[i], s, strlen(names[i])) == 0) {
+ is_ok = 1;
+ break;
+ }
+ i++;
+ }
+ if(is_ok == 0) {
+ char n[64];
+ size_t j;
+ n[0]=0;
+ n[sizeof(n)-1]=0;
+ for(j=0; j<sizeof(n)-1; j++) {
+ if(!s[j] || isspace((unsigned char)s[j])) {
+ n[j] = 0;
+ break;
+ }
+ n[j] = s[j];
+ }
+ fatal_exit("module_conf lists module '%s' but that "
+ "module is not available.", n);
+ }
+ s += strlen(names[i]);
+ }
+}
+
/** check configuration for errors */
static void
morechecks(struct config_file* cfg, const char* fname)
warn_hosts("forward-host", cfg->forwards);
interfacechecks(cfg);
aclchecks(cfg);
+ tcpconnlimitchecks(cfg);
if(cfg->verbosity < 0)
fatal_exit("verbosity value < 0");
free(cfg->chrootdir);
cfg->chrootdir = NULL;
+ /* check that the modules listed in module_conf exist */
+ check_modules_exist(cfg->module_conf);
+
/* There should be no reason for 'respip' module not to work with
* dns64, but it's not explicitly confirmed, so the combination is
* excluded below. It's simply unknown yet for the combination of
#if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET)
&& strcmp(cfg->module_conf, "python subnetcache iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache python iterator") != 0
- && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0
&& strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0
printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n");
printf(" +a list all, also not ratelimited\n");
printf(" list_auth_zones list auth zones\n");
+ printf(" auth_zone_reload zone reload auth zone from zonefile\n");
+ printf(" auth_zone_transfer zone transfer auth zone from master\n");
printf(" view_list_local_zones view list local-zones in view\n");
printf(" view_list_local_data view list local-data RRs in view\n");
printf(" view_local_zone view name type add local-zone in view\n");
/* transport */
PR_UL("num.query.tcp", s->svr.qtcp);
PR_UL("num.query.tcpout", s->svr.qtcp_outgoing);
+ PR_UL("num.query.tls", s->svr.qtls);
PR_UL("num.query.ipv6", s->svr.qipv6);
/* flags */
#endif /* USE_DNSCRYPT */
PR_UL("num.query.authzone.up", s->svr.num_query_authzone_up);
PR_UL("num.query.authzone.down", s->svr.num_query_authzone_down);
+#ifdef CLIENT_SUBNET
+ PR_UL("num.query.subnet", s->svr.num_query_subnet);
+ PR_UL("num.query.subnet_cache", s->svr.num_query_subnet_cache);
+#endif
}
/** print statistics out of memory structures */
exit(1);
}
+/** exit with ssl error related to a file path */
+static void ssl_path_err(const char* s, const char *path)
+{
+ unsigned long err;
+ err = ERR_peek_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_SYS &&
+ (ERR_GET_FUNC(err) == SYS_F_FOPEN ||
+ ERR_GET_FUNC(err) == SYS_F_FREAD) ) {
+ fprintf(stderr, "error: %s\n%s: %s\n",
+ s, path, ERR_reason_error_string(err));
+ exit(1);
+ } else {
+ ssl_err(s);
+ }
+}
+
/** setup SSL context */
static SSL_CTX*
setup_ctx(struct config_file* cfg)
if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)
!= SSL_OP_NO_SSLv3)
ssl_err("could not set SSL_OP_NO_SSLv3");
- if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) ||
- !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
- || !SSL_CTX_check_private_key(ctx))
- ssl_err("Error setting up SSL_CTX client key and cert");
+ if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert))
+ ssl_path_err("Error setting up SSL_CTX client cert", c_cert);
+ if (!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM))
+ ssl_path_err("Error setting up SSL_CTX client key", c_key);
+ if (!SSL_CTX_check_private_key(ctx))
+ ssl_err("Error setting up SSL_CTX client key");
if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
- ssl_err("Error setting up SSL_CTX verify, server cert");
+ ssl_path_err("Error setting up SSL_CTX verify, server cert",
+ s_cert);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
free(s_cert);
static void
usage(void)
{
- printf("Usage: unbound-host [-vdhr46] [-c class] [-t type] hostname\n");
- printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n");
- printf(" [-C configfile]\n");
+ printf("Usage: unbound-host [-C configfile] [-vdhr46] [-c class] [-t type]\n");
+ printf(" [-y key] [-f keyfile] [-F namedkeyfile] hostname\n");
printf(" Queries the DNS for information.\n");
printf(" The hostname is looked up for IP4, IP6 and mail.\n");
printf(" If an ip-address is given a reverse lookup is done.\n");
printf(" -f keyfile read trust anchors from file, with lines as -y.\n");
printf(" -F keyfile read named.conf-style trust anchors.\n");
printf(" -C config use the specified unbound.conf (none read by default)\n");
+ printf(" pass as first argument if you want to override some\n");
+ printf(" options with further arguments\n");
printf(" -r read forwarder information from /etc/resolv.conf\n");
printf(" breaks validation if the forwarder does not do DNSSEC.\n");
printf(" -v be more verbose, shows nodata and security.\n");
exit(1);
}
printf("%s\n", s);
+ free(s);
} else printf(" has no %s record", tstr);
printf(" %s\n", secstatus);
}
void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
- char* ATTR_UNUSED(why_bogus))
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
log_assert(0);
}
cfg->udp_upstream_without_downstream = 0;
cfg->tcp_mss = 0;
cfg->outgoing_tcp_mss = 0;
+ cfg->tcp_idle_timeout = 30 * 1000; /* 30s in millisecs */
+ cfg->do_tcp_keepalive = 0;
+ cfg->tcp_keepalive_timeout = 120 * 1000; /* 120s in millisecs */
cfg->ssl_service_key = NULL;
cfg->ssl_service_pem = NULL;
cfg->ssl_port = UNBOUND_DNS_OVER_TLS_PORT;
cfg->log_time_ascii = 0;
cfg->log_queries = 0;
cfg->log_replies = 0;
+ cfg->log_local_actions = 0;
+ cfg->log_servfail = 0;
#ifndef USE_WINSOCK
# ifdef USE_MINI_EVENT
/* select max 1024 sockets */
cfg->if_automatic = 0;
cfg->so_rcvbuf = 0;
cfg->so_sndbuf = 0;
- cfg->so_reuseport = 0;
+ cfg->so_reuseport = 1;
cfg->ip_transparent = 0;
cfg->ip_freebind = 0;
cfg->num_ifs = 0;
#endif
cfg->views = NULL;
cfg->acls = NULL;
+ cfg->tcp_connection_limits = NULL;
cfg->harden_short_bufsize = 0;
cfg->harden_large_queries = 0;
cfg->harden_glue = 1;
cfg->harden_dnssec_stripped = 1;
- cfg->harden_below_nxdomain = 0;
+ cfg->harden_below_nxdomain = 1;
cfg->harden_referral_path = 0;
cfg->harden_algo_downgrade = 0;
cfg->use_caps_bits_for_id = 0;
cfg->aggressive_nsec = 0;
cfg->ignore_cd = 0;
cfg->serve_expired = 0;
+ cfg->serve_expired_ttl = 0;
+ cfg->serve_expired_ttl_reset = 0;
cfg->add_holddown = 30*24*3600;
cfg->del_holddown = 30*24*3600;
cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */
cfg->control_ifs.last = NULL;
cfg->control_port = UNBOUND_CONTROL_PORT;
cfg->control_use_cert = 1;
- cfg->minimal_responses = 0;
+ cfg->minimal_responses = 1;
cfg->rrset_roundrobin = 0;
cfg->max_udp_size = 4096;
if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key")))
forward nameserver running on localhost */
cfg->val_log_level = 2; /* to fill why_bogus with */
cfg->val_log_squelch = 1;
+ cfg->minimal_responses = 0;
return cfg;
}
udp_upstream_without_downstream)
else S_NUMBER_NONZERO("tcp-mss:", tcp_mss)
else S_NUMBER_NONZERO("outgoing-tcp-mss:", outgoing_tcp_mss)
+ else S_NUMBER_NONZERO("tcp-idle-timeout:", tcp_idle_timeout)
+ else S_YNO("edns-tcp-keepalive:", do_tcp_keepalive)
+ else S_NUMBER_NONZERO("edns-tcp-keepalive-timeout:", tcp_keepalive_timeout)
else S_YNO("ssl-upstream:", ssl_upstream)
else S_STR("ssl-service-key:", ssl_service_key)
else S_STR("ssl-service-pem:", ssl_service_pem)
else S_YNO("val-log-squelch:", val_log_squelch)
else S_YNO("log-queries:", log_queries)
else S_YNO("log-replies:", log_replies)
+ else S_YNO("log-local-actions:", log_local_actions)
+ else S_YNO("log-servfail:", log_servfail)
else S_YNO("val-permissive-mode:", val_permissive_mode)
else S_YNO("aggressive-nsec:", aggressive_nsec)
else S_YNO("ignore-cd-flag:", ignore_cd)
else S_YNO("serve-expired:", serve_expired)
+ else if(strcmp(opt, "serve_expired_ttl:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->serve_expired_ttl = atoi(val); SERVE_EXPIRED_TTL=(time_t)cfg->serve_expired_ttl;}
+ else S_YNO("serve-expired-ttl-reset:", serve_expired_ttl_reset)
else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown)
else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown)
else O_YNO(opt, "udp-upstream-without-downstream", udp_upstream_without_downstream)
else O_DEC(opt, "tcp-mss", tcp_mss)
else O_DEC(opt, "outgoing-tcp-mss", outgoing_tcp_mss)
+ else O_DEC(opt, "tcp-idle-timeout", tcp_idle_timeout)
+ else O_YNO(opt, "edns-tcp-keepalive", do_tcp_keepalive)
+ else O_DEC(opt, "edns-tcp-keepalive-timeout", tcp_keepalive_timeout)
else O_YNO(opt, "ssl-upstream", ssl_upstream)
else O_STR(opt, "ssl-service-key", ssl_service_key)
else O_STR(opt, "ssl-service-pem", ssl_service_pem)
else O_STR(opt, "logfile", logfile)
else O_YNO(opt, "log-queries", log_queries)
else O_YNO(opt, "log-replies", log_replies)
+ else O_YNO(opt, "log-local-actions", log_local_actions)
+ else O_YNO(opt, "log-servfail", log_servfail)
else O_STR(opt, "pidfile", pidfile)
else O_YNO(opt, "hide-identity", hide_identity)
else O_YNO(opt, "hide-version", hide_version)
else O_YNO(opt, "aggressive-nsec", aggressive_nsec)
else O_YNO(opt, "ignore-cd-flag", ignore_cd)
else O_YNO(opt, "serve-expired", serve_expired)
+ else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl)
+ else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset)
else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
else O_UNS(opt, "add-holddown", add_holddown)
else O_UNS(opt, "del-holddown", del_holddown)
else O_STR(opt, "control-cert-file", control_cert_file)
else O_LST(opt, "root-hints", root_hints)
else O_LS2(opt, "access-control", acls)
+ else O_LS2(opt, "tcp-connection-limit", tcp_connection_limits)
else O_LST(opt, "do-not-query-address", donotqueryaddrs)
else O_LST(opt, "private-address", private_address)
else O_LST(opt, "private-domain", private_domain)
free(cfg->dlv_anchor_file);
config_delstrlist(cfg->dlv_anchor_list);
config_deldblstrlist(cfg->acls);
+ config_deldblstrlist(cfg->tcp_connection_limits);
free(cfg->val_nsec3_key_iterations);
config_deldblstrlist(cfg->local_zones);
config_delstrlist(cfg->local_zones_nodefault);
free(cfg->control_key_file);
free(cfg->control_cert_file);
free(cfg->dns64_prefix);
+ config_delstrlist(cfg->dns64_ignore_aaaa);
free(cfg->dnstap_socket_path);
free(cfg->dnstap_identity);
free(cfg->dnstap_version);
{
MAX_TTL = (time_t)config->max_ttl;
MIN_TTL = (time_t)config->min_ttl;
+ SERVE_EXPIRED_TTL = (time_t)config->serve_expired_ttl;
MAX_NEG_TTL = (time_t)config->max_negative_ttl;
RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
void errinf(struct module_qstate* qstate, const char* str)
{
struct config_strlist* p;
- if(qstate->env->cfg->val_log_level < 2 || !str)
+ if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str)
return;
p = (struct config_strlist*)regional_alloc(qstate->region, sizeof(*p));
if(!p) {
void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
{
struct sock_list* p;
- if(qstate->env->cfg->val_log_level < 2)
+ if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
return;
for(p=origin; p; p=p->next) {
char buf[256];
}
}
-char* errinf_to_str(struct module_qstate* qstate)
+char* errinf_to_str_bogus(struct module_qstate* qstate)
{
char buf[20480];
char* p = buf;
return p;
}
+char* errinf_to_str_servfail(struct module_qstate* qstate)
+{
+ char buf[20480];
+ char* p = buf;
+ size_t left = sizeof(buf);
+ struct config_strlist* s;
+ char dname[LDNS_MAX_DOMAINLEN+1];
+ char t[16], c[16];
+ sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
+ sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
+ dname_str(qstate->qinfo.qname, dname);
+ snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c);
+ left -= strlen(p); p += strlen(p);
+ if(!qstate->errinf)
+ snprintf(p, left, " misc failure");
+ else for(s=qstate->errinf; s; s=s->next) {
+ snprintf(p, left, " %s", s->str);
+ left -= strlen(p); p += strlen(p);
+ }
+ p = strdup(buf);
+ if(!p)
+ log_err("malloc failure in errinf_to_str");
+ return p;
+}
+
void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
{
char buf[1024];
char dname[LDNS_MAX_DOMAINLEN+1];
char t[16], c[16];
- if(qstate->env->cfg->val_log_level < 2 || !rr)
+ if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr)
return;
sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t));
sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c));
{
char b[1024];
char buf[LDNS_MAX_DOMAINLEN+1];
- if(qstate->env->cfg->val_log_level < 2 || !str || !dname)
+ if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname)
return;
dname_str(dname, buf);
snprintf(b, sizeof(b), "%s %s", str, buf);
int tcp_mss;
/** maximum segment size of tcp socket for outgoing queries */
int outgoing_tcp_mss;
+ /** tcp idle timeout, in msec */
+ int tcp_idle_timeout;
+ /** do edns tcp keepalive */
+ int do_tcp_keepalive;
+ /** tcp keepalive timeout, in msec */
+ int tcp_keepalive_timeout;
/** private key file for dnstcp-ssl service (enabled if not NULL) */
char* ssl_service_key;
/** use default localhost donotqueryaddr entries */
int donotquery_localhost;
+ /** list of tcp connection limitss, linked list */
+ struct config_str2list* tcp_connection_limits;
+
/** harden against very small edns buffer sizes */
int harden_short_bufsize;
/** harden against very large query sizes */
int log_queries;
/** log replies with one line per reply */
int log_replies;
+ /** log every local-zone hit **/
+ int log_local_actions;
+ /** log servfails with a reason */
+ int log_servfail;
/** log identity to report */
char* log_identity;
int ignore_cd;
/** serve expired entries and prefetch them */
int serve_expired;
+ /** serve expired entries until TTL after expiration */
+ int serve_expired_ttl;
+ /** reset serve expired TTL after failed update attempt */
+ int serve_expired_ttl_reset;
/** nsec3 maximum iterations per key size, string */
char* val_nsec3_key_iterations;
/** autotrust add holddown time, in seconds */
/* Synthetize all AAAA record despite the presence of an authoritative one */
int dns64_synthall;
+ /** ignore AAAAs for these domain names and use A record anyway */
+ struct config_strlist* dns64_ignore_aaaa;
/** true to enable dnstap support */
int dnstap;
int isfirst;
/** use SSL for queries to this stub */
int ssl_upstream;
+ /*** no cache */
+ int no_cache;
};
/**
uint8_t* dname);
/**
- * Create error info in string
+ * Create error info in string. For validation failures.
+ * @param qstate: query state.
+ * @return string or NULL on malloc failure (already logged).
+ * This string is malloced and has to be freed by caller.
+ */
+char* errinf_to_str_bogus(struct module_qstate* qstate);
+
+/**
+ * Create error info in string. For other servfails.
* @param qstate: query state.
* @return string or NULL on malloc failure (already logged).
* This string is malloced and has to be freed by caller.
*/
-char* errinf_to_str(struct module_qstate* qstate);
+char* errinf_to_str_servfail(struct module_qstate* qstate);
/**
* Used during options parsing
tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) }
tcp-mss{COLON} { YDVAR(1, VAR_TCP_MSS) }
outgoing-tcp-mss{COLON} { YDVAR(1, VAR_OUTGOING_TCP_MSS) }
+tcp-idle-timeout{COLON} { YDVAR(1, VAR_TCP_IDLE_TIMEOUT) }
+edns-tcp-keepalive{COLON} { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE) }
+edns-tcp-keepalive-timeout{COLON} { YDVAR(1, VAR_EDNS_TCP_KEEPALIVE_TIMEOUT) }
ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
tls-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) }
stub-host{COLON} { YDVAR(1, VAR_STUB_HOST) }
stub-prime{COLON} { YDVAR(1, VAR_STUB_PRIME) }
stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) }
+stub-no-cache{COLON} { YDVAR(1, VAR_STUB_NO_CACHE) }
stub-ssl-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
stub-tls-upstream{COLON} { YDVAR(1, VAR_STUB_SSL_UPSTREAM) }
forward-zone{COLON} { YDVAR(0, VAR_FORWARD_ZONE) }
forward-addr{COLON} { YDVAR(1, VAR_FORWARD_ADDR) }
forward-host{COLON} { YDVAR(1, VAR_FORWARD_HOST) }
forward-first{COLON} { YDVAR(1, VAR_FORWARD_FIRST) }
+forward-no-cache{COLON} { YDVAR(1, VAR_FORWARD_NO_CACHE) }
forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) }
aggressive-nsec{COLON} { YDVAR(1, VAR_AGGRESSIVE_NSEC) }
ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) }
serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) }
+serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) }
+serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) }
fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) }
fake-sha1{COLON} { YDVAR(1, VAR_FAKE_SHA1) }
val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) }
log-time-ascii{COLON} { YDVAR(1, VAR_LOG_TIME_ASCII) }
log-queries{COLON} { YDVAR(1, VAR_LOG_QUERIES) }
log-replies{COLON} { YDVAR(1, VAR_LOG_REPLIES) }
+log-local-actions{COLON} { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) }
+log-servfail{COLON} { YDVAR(1, VAR_LOG_SERVFAIL) }
local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) }
local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) }
local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) }
max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) }
dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) }
dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) }
+dns64-ignore-aaaa{COLON} { YDVAR(1, VAR_DNS64_IGNORE_AAAA) }
define-tag{COLON} { YDVAR(1, VAR_DEFINE_TAG) }
local-zone-tag{COLON} { YDVAR(2, VAR_LOCAL_ZONE_TAG) }
access-control-tag{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_TAG) }
redis-server-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) }
redis-timeout{COLON} { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) }
udp-upstream-without-downstream{COLON} { YDVAR(1, VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM) }
+tcp-connection-limit{COLON} { YDVAR(2, VAR_TCP_CONNECTION_LIMIT) }
<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
/* Quoted strings. Strip leading and ending quotes */
%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT
%token VAR_OUTGOING_RANGE VAR_INTERFACE
%token VAR_DO_IP4 VAR_DO_IP6 VAR_PREFER_IP6 VAR_DO_UDP VAR_DO_TCP
-%token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS
+%token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_TCP_IDLE_TIMEOUT
+%token VAR_EDNS_TCP_KEEPALIVE VAR_EDNS_TCP_KEEPALIVE_TIMEOUT
%token VAR_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
%token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD
%token VAR_RRSET_CACHE_SIZE VAR_RRSET_CACHE_SLABS VAR_OUTGOING_NUM_TCP
%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT VAR_HARDEN_BELOW_NXDOMAIN
-%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES
+%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES VAR_LOG_LOCAL_ACTIONS
%token VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
%token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE
%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE
%token VAR_UNBLOCK_LAN_ZONES VAR_INSECURE_LAN_ZONES
%token VAR_INFRA_CACHE_MIN_RTT
-%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL
+%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL VAR_DNS64_IGNORE_AAAA
%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH
%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION
%token VAR_DNSTAP_IDENTITY VAR_DNSTAP_VERSION
%token VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG VAR_ACCESS_CONTROL_TAG
%token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
%token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
-%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1
+%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_SERVE_EXPIRED_TTL
+%token VAR_SERVE_EXPIRED_TTL_RESET VAR_FAKE_DSA VAR_FAKE_SHA1
%token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
%token VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
%token VAR_ROOT_KEY_SENTINEL
%token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM
%token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM
%token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL
-%token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT
+%token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT VAR_TCP_CONNECTION_LIMIT
+%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
server_outgoing_range | server_do_ip4 |
server_do_ip6 | server_prefer_ip6 |
server_do_udp | server_do_tcp |
- server_tcp_mss | server_outgoing_tcp_mss |
+ server_tcp_mss | server_outgoing_tcp_mss | server_tcp_idle_timeout |
+ server_tcp_keepalive | server_tcp_keepalive_timeout |
server_interface | server_chroot | server_username |
server_directory | server_logfile | server_pidfile |
server_msg_cache_size | server_msg_cache_slabs |
server_edns_buffer_size | server_prefetch | server_prefetch_key |
server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream |
+ server_log_local_actions |
server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
server_minimal_responses | server_rrset_roundrobin | server_max_udp_size |
server_so_reuseport | server_delay_close |
server_unblock_lan_zones | server_insecure_lan_zones |
- server_dns64_prefix | server_dns64_synthall |
+ server_dns64_prefix | server_dns64_synthall | server_dns64_ignore_aaaa |
server_infra_cache_min_rtt | server_harden_algo_downgrade |
server_ip_transparent | server_ip_ratelimit | server_ratelimit |
server_ip_ratelimit_slabs | server_ratelimit_slabs |
server_local_zone_override | server_access_control_tag_action |
server_access_control_tag_data | server_access_control_view |
server_qname_minimisation_strict | server_serve_expired |
+ server_serve_expired_ttl | server_serve_expired_ttl_reset |
server_fake_dsa | server_log_identity | server_use_systemd |
server_response_ip_tag | server_response_ip | server_response_ip_data |
server_shm_enable | server_shm_key | server_fake_sha1 |
server_ipsecmod_whitelist | server_ipsecmod_strict |
server_udp_upstream_without_downstream | server_aggressive_nsec |
server_tls_cert_bundle | server_tls_additional_port | server_low_rtt |
- server_low_rtt_permil | server_tls_win_cert
+ server_low_rtt_permil | server_tls_win_cert |
+ server_tcp_connection_limit | server_log_servfail
;
stubstart: VAR_STUB_ZONE
{
contents_stub: contents_stub content_stub
| ;
content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first |
- stub_ssl_upstream
+ stub_no_cache | stub_ssl_upstream
;
forwardstart: VAR_FORWARD_ZONE
{
contents_forward: contents_forward content_forward
| ;
content_forward: forward_name | forward_host | forward_addr | forward_first |
- forward_ssl_upstream
+ forward_no_cache | forward_ssl_upstream
;
viewstart: VAR_VIEW
{
free($2);
}
;
+server_tcp_idle_timeout: VAR_TCP_IDLE_TIMEOUT STRING_ARG
+ {
+ OUTYY(("P(server_tcp_idle_timeout:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else if (atoi($2) > 120000)
+ cfg_parser->cfg->tcp_idle_timeout = 120000;
+ else if (atoi($2) < 1)
+ cfg_parser->cfg->tcp_idle_timeout = 1;
+ else cfg_parser->cfg->tcp_idle_timeout = atoi($2);
+ free($2);
+ }
+ ;
+server_tcp_keepalive: VAR_EDNS_TCP_KEEPALIVE STRING_ARG
+ {
+ OUTYY(("P(server_tcp_keepalive:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_tcp_keepalive = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_tcp_keepalive_timeout: VAR_EDNS_TCP_KEEPALIVE_TIMEOUT STRING_ARG
+ {
+ OUTYY(("P(server_tcp_keepalive_timeout:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else if (atoi($2) > 6553500)
+ cfg_parser->cfg->tcp_keepalive_timeout = 6553500;
+ else if (atoi($2) < 1)
+ cfg_parser->cfg->tcp_keepalive_timeout = 0;
+ else cfg_parser->cfg->tcp_keepalive_timeout = atoi($2);
+ free($2);
+ }
+ ;
server_tcp_upstream: VAR_TCP_UPSTREAM STRING_ARG
{
OUTYY(("P(server_tcp_upstream:%s)\n", $2));
free($2);
}
;
+server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG
+ {
+ OUTYY(("P(server_log_servfail:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_servfail = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG
+ {
+ OUTYY(("P(server_log_local_actions:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_chroot: VAR_CHROOT STRING_ARG
{
OUTYY(("P(server_chroot:%s)\n", $2));
free($2);
}
;
+server_serve_expired_ttl: VAR_SERVE_EXPIRED_TTL STRING_ARG
+ {
+ OUTYY(("P(server_serve_expired_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->serve_expired_ttl = atoi($2);
+ free($2);
+ }
+ ;
+server_serve_expired_ttl_reset: VAR_SERVE_EXPIRED_TTL_RESET STRING_ARG
+ {
+ OUTYY(("P(server_serve_expired_ttl_reset:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->serve_expired_ttl_reset = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
server_fake_dsa: VAR_FAKE_DSA STRING_ARG
{
OUTYY(("P(server_fake_dsa:%s)\n", $2));
free($2);
}
;
+server_dns64_ignore_aaaa: VAR_DNS64_IGNORE_AAAA STRING_ARG
+ {
+ OUTYY(("P(dns64_ignore_aaaa:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dns64_ignore_aaaa,
+ $2))
+ fatal_exit("out of memory adding dns64-ignore-aaaa");
+ }
+ ;
server_define_tag: VAR_DEFINE_TAG STRING_ARG
{
char* p, *s = $2;
free($2);
}
;
+stub_no_cache: VAR_STUB_NO_CACHE STRING_ARG
+ {
+ OUTYY(("P(stub-no-cache:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->no_cache=(strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
stub_ssl_upstream: VAR_STUB_SSL_UPSTREAM STRING_ARG
{
OUTYY(("P(stub-ssl-upstream:%s)\n", $2));
free($2);
}
;
+forward_no_cache: VAR_FORWARD_NO_CACHE STRING_ARG
+ {
+ OUTYY(("P(forward-no-cache:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->forwards->no_cache=(strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG
{
OUTYY(("P(forward-ssl-upstream:%s)\n", $2));
free($2);
}
;
+server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_tcp_connection_limit:%s %s)\n", $2, $3));
+ if (atoi($3) < 0)
+ yyerror("positive number expected");
+ else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->tcp_connection_limits, $2, $3))
+ fatal_exit("out of memory adding tcp connection limit");
+ }
+ }
+ ;
%%
/* parse helper routines could be here */
extern time_t MIN_TTL;
/** Maximum Negative TTL that is allowed */
extern time_t MAX_NEG_TTL;
+/** Time to serve records after expiration */
+extern time_t SERVE_EXPIRED_TTL;
/** Negative cache time (for entries without any RRs.) */
#define NORR_TTL 5 /* seconds */
time_t MIN_TTL = 0;
/** MAX Negative TTL, for SOA records in authority section */
time_t MAX_NEG_TTL = 3600; /* one hour */
+/** Time to serve records after expiration */
+time_t SERVE_EXPIRED_TTL = 0;
/** allocate qinfo, return 0 on error */
static int
/** constructor for replyinfo */
struct reply_info*
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
- time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar,
- size_t total, enum sec_status sec)
+ time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
+ size_t ar, size_t total, enum sec_status sec)
{
struct reply_info* rep;
/* rrset_count-1 because the first ref is part of the struct. */
rep->qdcount = qd;
rep->ttl = ttl;
rep->prefetch_ttl = prettl;
+ rep->serve_expired_ttl = expttl;
rep->an_numrrsets = an;
rep->ns_numrrsets = ns;
rep->ar_numrrsets = ar;
struct regional* region)
{
*rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
- 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
+ 0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
msg->rrset_count, sec_status_unchecked);
if(!*rep)
return 0;
pset = pset->rrset_all_next;
}
rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
+ rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL;
return 1;
}
size_t i, j;
rep->ttl += timenow;
rep->prefetch_ttl += timenow;
+ rep->serve_expired_ttl += timenow;
for(i=0; i<rep->rrset_count; i++) {
struct packed_rrset_data* data = (struct packed_rrset_data*)
rep->ref[i].key->entry.data;
{
struct reply_info* cp;
cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
- rep->ttl, rep->prefetch_ttl, rep->an_numrrsets,
- rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count,
- rep->security);
+ rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl,
+ rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
+ rep->rrset_count, rep->security);
if(!cp)
return NULL;
/* allocate ub_key structures special or not */
}
memset(msg, 0, sizeof(*msg));
sldns_buffer_set_position(pkt, 0);
- if(parse_packet(pkt, msg, region) != 0)
+ if(parse_packet(pkt, msg, region) != 0){
return 0;
+ }
if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
return 0;
}
struct inplace_cb* callback_list, enum inplace_cb_list_type type,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
struct inplace_cb* cb;
struct edns_option* opt_list_out = NULL;
fptr_ok(fptr_whitelist_inplace_cb_reply_generic(
(inplace_cb_reply_func_type*)cb->cb, type));
(void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep,
- rcode, edns, &opt_list_out, region, cb->id, cb->cb_arg);
+ rcode, edns, &opt_list_out, repinfo, region, cb->id, cb->cb_arg);
}
edns->opt_list = opt_list_out;
return 1;
int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
- struct edns_data* edns, struct regional* region)
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo,
- qstate, rep, rcode, edns, region);
+ qstate, rep, rcode, edns, repinfo, region);
}
int inplace_cb_reply_cache_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache,
- qinfo, qstate, rep, rcode, edns, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region);
}
int inplace_cb_reply_local_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local,
- qinfo, qstate, rep, rcode, edns, region);
+ qinfo, qstate, rep, rcode, edns, repinfo, region);
}
int inplace_cb_reply_servfail_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region)
+ struct comm_reply* repinfo, struct regional* region)
{
/* We are going to servfail. Remove any potential edns options. */
if(qstate)
qstate->edns_opts_front_out = NULL;
return inplace_cb_reply_call_generic(
env->inplace_cb_lists[inplace_cb_reply_servfail],
- inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, region);
+ inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo,
+ region);
}
int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo,
*/
time_t prefetch_ttl;
+ /**
+ * Reply TTL extended with serve exipred TTL, to limit time to serve
+ * expired message.
+ */
+ time_t serve_expired_ttl;
+
/**
* The security status from DNSSEC validation of this message.
*/
* @param qd: qd count
* @param ttl: TTL of replyinfo
* @param prettl: prefetch ttl
+ * @param expttl: serve expired ttl
* @param an: an count
* @param ns: ns count
* @param ar: ar count
*/
struct reply_info*
construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
- time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar,
- size_t total, enum sec_status sec);
+ time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns,
+ size_t ar, size_t total, enum sec_status sec);
/**
* Parse wire query into a queryinfo structure, return 0 on parse error.
* @param rep: Reply info. Could be NULL.
* @param rcode: return code.
* @param edns: edns data of the reply.
+ * @param repinfo: comm_reply. NULL.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
- struct edns_data* edns, struct regional* region);
+ struct edns_data* edns, struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply_cache linked list.
* @param rep: Reply info.
* @param rcode: return code.
* @param edns: edns data of the reply. Edns input can be found here.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
int inplace_cb_reply_cache_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply_local linked list.
* @param rep: Reply info.
* @param rcode: return code.
* @param edns: edns data of the reply. Edns input can be found here.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
int inplace_cb_reply_local_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_reply linked list.
* @param rcode: return code. LDNS_RCODE_SERVFAIL.
* @param edns: edns data of the reply. Edns input can be found here if qstate
* is NULL.
+ * @param repinfo: comm_reply. Reply information for a communication point.
* @param region: region to store data.
* @return false on failure (a callback function returned an error).
*/
int inplace_cb_reply_servfail_call(struct module_env* env,
struct query_info* qinfo, struct module_qstate* qstate,
struct reply_info* rep, int rcode, struct edns_data* edns,
- struct regional* region);
+ struct comm_reply* repinfo, struct regional* region);
/**
* Call the registered functions in the inplace_cb_query linked list.
8020,
8021,
8022,
+8023,
8025,
8026,
8032,
9104,
9105,
9106,
+9111,
9119,
9131,
9160,
}
}
}
+
+void
+copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
+ struct module_qstate* super)
+{
+ /* Overwrite super's was_ratelimited only when it was not set */
+ if(!super->was_ratelimited) {
+ super->was_ratelimited = qstate->was_ratelimited;
+ }
+}
/**
* Inplace callback function called before replying.
- * Called as func(edns, qstate, opt_list_out, qinfo, reply_info, rcode,
- * region, python_callback)
+ * Called as func(qinfo, qstate, rep, rcode, edns, opt_list_out, repinfo,
+ * region, id, python_callback)
* Where:
* qinfo: the query info.
* qstate: the module state. NULL when calling before the query reaches the
* edns: the edns_data of the reply. When qstate is NULL, it is also used as
* the edns input.
* opt_list_out: the edns options list for the reply.
+ * repinfo: reply information for a communication point. NULL when calling
+ * during the mesh states; the same could be found from
+ * qstate->mesh_info->reply_list.
* region: region to store data.
+ * id: module id.
* python_callback: only used for registering a python callback function.
*/
typedef int inplace_cb_reply_func_type(struct query_info* qinfo,
struct module_qstate* qstate, struct reply_info* rep, int rcode,
- struct edns_data* edns, struct edns_option** opt_list_out,
- struct regional* region, int id, void* callback);
+ struct edns_data* edns, struct edns_option** opt_list_out,
+ struct comm_reply* repinfo, struct regional* region, int id,
+ void* callback);
/**
* Inplace callback function called before sending the query to a nameserver.
* Called as func(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region,
- * python_callback)
+ * id, python_callback)
* Where:
* qinfo: query info.
* flags: flags of the query.
* authoritative.
* zonelen: length of zone.
* region: region to store data.
+ * id: module id.
* python_callback: only used for registering a python callback function.
*/
typedef int inplace_cb_query_func_type(struct query_info* qinfo, uint16_t flags,
/**
* Inplace callback function called after parsing edns on query reply.
- * Called as func(qstate, cb_args)
+ * Called as func(qstate, id, cb_args)
* Where:
- * qstate: the query state
- * id: module id
+ * qstate: the query state.
+ * id: module id.
* cb_args: argument passed when registering callback.
*/
typedef int inplace_cb_edns_back_parsed_func_type(struct module_qstate* qstate,
/**
* Inplace callback function called after parsing query response.
- * Called as func(qstate, id, cb_args)
+ * Called as func(qstate, response, id, cb_args)
* Where:
- * qstate: the query state
- * response: query response
- * id: module id
+ * qstate: the query state.
+ * response: query response.
+ * id: module id.
* cb_args: argument passed when registering callback.
*/
typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate,
int no_cache_store;
/** whether to refetch a fresh answer on finishing this state*/
int need_refetch;
+ /** whether the query (or a subquery) was ratelimited */
+ int was_ratelimited;
/**
* Attributes of clients that share the qstate that may affect IP-based
void log_edns_known_options(enum verbosity_value level,
struct module_env* env);
+/**
+ * Copy state that may have happened in the subquery and is always relevant to
+ * the super.
+ * @param qstate: query state that finished.
+ * @param id: module id.
+ * @param super: the qstate to inform.
+ */
+void copy_state_to_super(struct module_qstate* qstate, int id,
+ struct module_qstate* super);
+
#endif /* UTIL_MODULE_H */
if(verbosity >= 4)
log_err("%s: %s for %s port %d (len %d)", str, err, dest,
(int)port, (int)addrlen);
- else log_err("%s: %s for %s", str, err, dest);
+ else log_err("%s: %s for %s port %d", str, err, dest, (int)port);
}
int
#include "util/ub_event.h"
#include "util/log.h"
#include "util/net_help.h"
+#include "util/tcp_conn_limit.h"
#include "util/fptr_wlist.h"
#include "sldns/pkthdr.h"
#include "sldns/sbuffer.h"
# endif
#endif
-/** The TCP reading or writing query timeout in milliseconds */
+/** The TCP writing query timeout in milliseconds */
#define TCP_QUERY_TIMEOUT 120000
-/** The TCP timeout in msec for fast queries, above half are used */
-#define TCP_QUERY_TIMEOUT_FAST 200
+/** The minimum actual TCP timeout to use, regardless of what we advertise,
+ * in msec */
+#define TCP_QUERY_TIMEOUT_MINIMUM 200
#ifndef NONBLOCKING_IS_BROKEN
/** number of UDP reads to perform per read indication from select */
static void
setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
{
+ int handler_usage;
log_assert(c->type == comm_tcp);
log_assert(c->fd == -1);
sldns_buffer_clear(c->buffer);
#endif
c->tcp_is_reading = 1;
c->tcp_byte_count = 0;
- c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
/* if more than half the tcp handlers are in use, use a shorter
* timeout for this TCP connection, we need to make space for
* other connections to be able to get attention */
- if(cur > max/2)
- c->tcp_timeout_msec = TCP_QUERY_TIMEOUT_FAST;
- comm_point_start_listening(c, fd, c->tcp_timeout_msec);
+ /* If > 50% TCP handler structures in use, set timeout to 1/100th
+ * configured value.
+ * If > 65%TCP handler structures in use, set to 1/500th configured
+ * value.
+ * If > 80% TCP handler structures in use, set to 0.
+ *
+ * If the timeout to use falls below 200 milliseconds, an actual
+ * timeout of 200ms is used.
+ */
+ handler_usage = (cur * 100) / max;
+ if(handler_usage > 50 && handler_usage <= 65)
+ c->tcp_timeout_msec /= 100;
+ else if (handler_usage > 65 && handler_usage <= 80)
+ c->tcp_timeout_msec /= 500;
+ else if (handler_usage > 80)
+ c->tcp_timeout_msec = 0;
+ comm_point_start_listening(c, fd,
+ c->tcp_timeout_msec < TCP_QUERY_TIMEOUT_MINIMUM
+ ? TCP_QUERY_TIMEOUT_MINIMUM
+ : c->tcp_timeout_msec);
}
void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
#endif
return -1;
}
+ if(c->tcp_conn_limit && c->type == comm_tcp_accept) {
+ c->tcl_addr = tcl_addr_lookup(c->tcp_conn_limit, addr, *addrlen);
+ if(!tcl_new_connection(c->tcl_addr)) {
+ if(verbosity >= 3)
+ log_err_addr("accept rejected",
+ "connection limit exceeded", addr, *addrlen);
+ close(new_fd);
+ return -1;
+ }
+ }
#ifndef HAVE_ACCEPT4
fd_set_nonblock(new_fd);
#endif
c->tcp_is_reading = 0;
c->tcp_byte_count = 0;
c->tcp_parent = parent;
+ c->tcp_timeout_msec = parent->tcp_timeout_msec;
+ c->tcp_conn_limit = parent->tcp_conn_limit;
+ c->tcl_addr = NULL;
+ c->tcp_keepalive = 0;
c->max_tcp_count = 0;
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
}
struct comm_point*
-comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
+comm_point_create_tcp(struct comm_base *base, int fd, int num,
+ int idle_timeout, struct tcl_list* tcp_conn_limit, size_t bufsize,
comm_point_callback_type* callback, void* callback_arg)
{
struct comm_point* c = (struct comm_point*)calloc(1,
c->timeout = NULL;
c->tcp_is_reading = 0;
c->tcp_byte_count = 0;
+ c->tcp_timeout_msec = idle_timeout;
+ c->tcp_conn_limit = tcp_conn_limit;
+ c->tcl_addr = NULL;
+ c->tcp_keepalive = 0;
c->tcp_parent = NULL;
c->max_tcp_count = num;
c->cur_tcp_count = 0;
c->timeout = NULL;
c->tcp_is_reading = 0;
c->tcp_byte_count = 0;
+ c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
+ c->tcp_conn_limit = NULL;
+ c->tcl_addr = NULL;
+ c->tcp_keepalive = 0;
c->tcp_parent = NULL;
c->max_tcp_count = 0;
c->cur_tcp_count = 0;
log_err("could not event_del on close");
}
}
+ tcl_close_connection(c->tcl_addr);
/* close fd after removing from event lists, or epoll.. is messed up */
if(c->fd != -1 && !c->do_not_close) {
if(c->type == comm_tcp || c->type == comm_http) {
struct sldns_buffer;
struct comm_point;
struct comm_reply;
+struct tcl_list;
struct ub_event_base;
/* internal event notification data storage structure. */
/** timeout in msec for TCP wait times for this connection */
int tcp_timeout_msec;
+ /** if set, tcp keepalive is enabled on this connection */
+ int tcp_keepalive;
+
/** if set, checks for pending error from nonblocking connect() call.*/
int tcp_check_nb_connect;
+ /** if set, check for connection limit on tcp accept. */
+ struct tcl_list* tcp_conn_limit;
+ /** the entry for the connection. */
+ struct tcl_addr* tcl_addr;
+
#ifdef USE_MSG_FASTOPEN
/** used to track if the sendto() call should be done when using TFO. */
int tcp_do_fastopen;
* @param fd: file descriptor of open TCP socket set to listen nonblocking.
* @param num: becomes max_tcp_count, the routine allocates that
* many tcp handler commpoints.
+ * @param idle_timeout: TCP idle timeout in ms.
+ * @param tcp_conn_limit: TCP connection limit info.
* @param bufsize: size of buffer to create for handlers.
* @param callback: callback function pointer for TCP handlers.
* @param callback_arg: will be passed to your callback function.
* Inits timeout to NULL. All handlers are on the free list.
*/
struct comm_point* comm_point_create_tcp(struct comm_base* base,
- int fd, int num, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg);
+ int fd, int num, int idle_timeout, struct tcl_list* tcp_conn_limit,
+ size_t bufsize, comm_point_callback_type* callback, void* callback_arg);
/**
* Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.
return total;
}
+int slabhash_is_size(struct slabhash* sl, size_t size, size_t slabs)
+{
+ /* divide by slabs and then multiply by the number of slabs,
+ * because if the size is not an even multiple of slabs, the
+ * uneven amount needs to be removed for comparison */
+ if(!sl) return 0;
+ if(sl->size != slabs) return 0;
+ if(slabs == 0) return 0;
+ if( (size/slabs)*slabs == slabhash_get_size(sl))
+ return 1;
+ return 0;
+}
+
size_t slabhash_get_mem(struct slabhash* sl)
{
size_t i, total = sizeof(*sl);
*/
size_t slabhash_get_size(struct slabhash* table);
+/**
+ * See if slabhash is of given (size, slabs) configuration.
+ * @param table: hash table
+ * @param size: max size to test for
+ * @param slabs: slab count to test for.
+ * @return true if equal
+ */
+int slabhash_is_size(struct slabhash* table, size_t size, size_t slabs);
+
/**
* Retrieve slab hash current memory use.
* @param table: hash table.
void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode),
sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec),
- char* ATTR_UNUSED(why_bogus))
+ char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
{
/* retry was set before the query was done,
* re-querytime is set when query succeeded, but that may not
/** callback for query answer to 5011 probe */
void probe_answer_cb(void* arg, int rcode, struct sldns_buffer* buf,
- enum sec_status sec, char* errinf);
+ enum sec_status sec, char* errinf, int was_ratelimited);
#endif /* VALIDATOR_AUTOTRUST_H */
if(qtype == LDNS_RR_TYPE_DLV)
valrec = 0;
else valrec = 1;
+
+ fptr_ok(fptr_whitelist_modenv_detect_cycle(qstate->env->detect_cycle));
+ if((*qstate->env->detect_cycle)(qstate, &ask,
+ (uint16_t)(BIT_RD|flags), 0, valrec)) {
+ verbose(VERB_ALGO, "Could not generate request: cycle detected");
+ return 0;
+ }
+
if(detached) {
struct mesh_state* sub = NULL;
fptr_ok(fptr_whitelist_modenv_add_sub(
LDNS_RR_TYPE_NULL, ta->dclass);
if(!generate_request(qstate, id, keytagdname, dnamebuf_len,
LDNS_RR_TYPE_NULL, ta->dclass, 0, &newq, 1)) {
- log_err("failed to generate key tag signaling request");
+ verbose(VERB_ALGO, "failed to generate key tag signaling request");
return 0;
}
if(newq && qstate->env->cfg->trust_anchor_signaling &&
!generate_keytag_query(qstate, id, toprime)) {
- log_err("keytag signaling query failed");
+ verbose(VERB_ALGO, "keytag signaling query failed");
return 0;
}
if(!ret) {
- log_err("Could not prime trust anchor: out of memory");
+ verbose(VERB_ALGO, "Could not prime trust anchor");
return 0;
}
/* ignore newq; validator does not need state created for that
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
vq->qchase.qclass, BIT_CD, &newq, 0)) {
- log_err("mem error generating DNSKEY request");
+ verbose(VERB_ALGO, "error generating DNSKEY request");
return val_error(qstate, id);
}
return 0;
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
vq->qchase.qclass, BIT_CD, &newq, 0)) {
- log_err("mem error generating DNSKEY request");
+ verbose(VERB_ALGO, "error generating DNSKEY request");
return val_error(qstate, id);
}
return 0;
if(!generate_request(qstate, id, target_key_name,
target_key_len, LDNS_RR_TYPE_DS, vq->qchase.qclass,
BIT_CD, &newq, 0)) {
- log_err("mem error generating DS request");
+ verbose(VERB_ALGO, "error generating DS request");
return val_error(qstate, id);
}
return 0;
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
vq->qchase.qclass, BIT_CD, &newq, 0)) {
- log_err("mem error generating DNSKEY request");
+ verbose(VERB_ALGO, "error generating DNSKEY request");
return val_error(qstate, id);
}
vq->orig_msg->rep->ttl = ve->bogus_ttl;
vq->orig_msg->rep->prefetch_ttl =
PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl);
- if(qstate->env->cfg->val_log_level >= 1 &&
+ vq->orig_msg->rep->serve_expired_ttl =
+ vq->orig_msg->rep->ttl + qstate->env->cfg->serve_expired_ttl;
+ if((qstate->env->cfg->val_log_level >= 1 ||
+ qstate->env->cfg->log_servfail) &&
!qstate->env->cfg->val_log_squelch) {
- if(qstate->env->cfg->val_log_level < 2)
+ if(qstate->env->cfg->val_log_level < 2 &&
+ !qstate->env->cfg->log_servfail)
log_query_info(0, "validation failure",
&qstate->qinfo);
else {
- char* err = errinf_to_str(qstate);
+ char* err = errinf_to_str_bogus(qstate);
if(err) log_info("%s", err);
free(err);
}
if(vq->dlv_status == dlv_error) {
verbose(VERB_QUERY, "failed DLV lookup");
+ errinf(qstate, "failed DLV lookup");
return val_error(qstate, id);
} else if(vq->dlv_status == dlv_success) {
uint8_t* nm;
if(!generate_request(qstate, id, vq->ds_rrset->rk.dname,
vq->ds_rrset->rk.dname_len, LDNS_RR_TYPE_DNSKEY,
vq->qchase.qclass, BIT_CD, &newq, 0)) {
- log_err("mem error generating DNSKEY request");
+ verbose(VERB_ALGO, "error generating DNSKEY request");
return val_error(qstate, id);
}
return 0;