diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2018-09-20 23:15:41 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2018-09-20 23:15:41 +0000 |
commit | a2bd89bb699c1bac497a4aee78301d580453cc51 (patch) | |
tree | 782f1469c7219a9ad0893b665d225c53b1e5297b | |
parent | 5b5391b5131c860f1cf5cda909cbf0919289f747 (diff) |
merge unbound 1.8.0
74 files changed, 2287 insertions, 642 deletions
diff --git a/usr.sbin/unbound/Makefile.in b/usr.sbin/unbound/Makefile.in index 409cce049ab..20aff3e4ec9 100644 --- a/usr.sbin/unbound/Makefile.in +++ b/usr.sbin/unbound/Makefile.in @@ -57,7 +57,7 @@ STRIP=@STRIP@ CC=@CC@ CPPFLAGS=-I. @CPPFLAGS@ PYTHON_CPPFLAGS=-I. @PYTHON_CPPFLAGS@ -CFLAGS=@CFLAGS@ +CFLAGS=-DSRCDIR=$(srcdir) @CFLAGS@ LDFLAGS=@LDFLAGS@ LIBS=@LIBS@ LIBOBJS=@LIBOBJS@ @@ -83,7 +83,7 @@ LINTFLAGS+=@NETBSD_LINTFLAGS@ # 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 @@ -115,8 +115,9 @@ util/config_file.c util/configlexer.c util/configparser.c \ 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 \ @@ -131,9 +132,10 @@ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \ iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \ iter_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) \ @@ -170,7 +172,8 @@ UNITTEST_OBJ_LINK=$(UNITTEST_OBJ) worker_cb.lo $(COMMON_OBJ) $(SLDNS_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@ @@ -190,7 +193,8 @@ UBANCHOR_OBJ=unbound-anchor.lo 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 \ @@ -306,10 +310,11 @@ longcheck: longtest 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 @@ -588,7 +593,7 @@ iana_update: 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 @@ -596,7 +601,8 @@ DEPEND_TARGET2=Makefile.in # 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' | \ @@ -764,7 +770,7 @@ mesh.lo mesh.o: $(srcdir)/services/mesh.c config.h $(srcdir)/services/mesh.h $(s $(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 \ @@ -794,10 +800,11 @@ outside_network.lo outside_network.o: $(srcdir)/services/outside_network.c confi $(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 \ @@ -881,10 +888,11 @@ module.lo module.o: $(srcdir)/util/module.c config.h $(srcdir)/util/module.h $(s $(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 \ \ @@ -903,7 +911,15 @@ rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcd $(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 @@ -917,6 +933,12 @@ lruhash.lo lruhash.o: $(srcdir)/util/storage/lruhash.c config.h $(srcdir)/util/s $(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 \ @@ -1031,7 +1053,8 @@ dns64.lo dns64.o: $(srcdir)/dns64/dns64.c config.h $(srcdir)/dns64/dns64.h $(src $(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 \ @@ -1112,12 +1135,13 @@ unitmain.lo unitmain.o: $(srcdir)/testcode/unitmain.c config.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 \ @@ -1195,10 +1219,10 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.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 \ @@ -1257,10 +1281,10 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr $(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 \ @@ -1291,10 +1315,10 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr $(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 \ @@ -1312,10 +1336,10 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.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 \ diff --git a/usr.sbin/unbound/cachedb/cachedb.c b/usr.sbin/unbound/cachedb/cachedb.c index a6a609dcb68..5a179a2bb41 100644 --- a/usr.sbin/unbound/cachedb/cachedb.c +++ b/usr.sbin/unbound/cachedb/cachedb.c @@ -446,6 +446,7 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust) 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-> diff --git a/usr.sbin/unbound/configure b/usr.sbin/unbound/configure index cf54a87a558..92fe4dbf16c 100644 --- a/usr.sbin/unbound/configure +++ b/usr.sbin/unbound/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for unbound 1.7.3. +# Generated by GNU Autoconf 2.69 for unbound 1.8.0. # # Report bugs to <unbound-bugs@nlnetlabs.nl>. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.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='' @@ -670,9 +670,6 @@ SYSTEMD_DAEMON_LIBS SYSTEMD_DAEMON_CFLAGS SYSTEMD_LIBS SYSTEMD_CFLAGS -PKG_CONFIG_LIBDIR -PKG_CONFIG_PATH -PKG_CONFIG staticexe PC_LIBEVENT_DEPENDENCY UNBOUND_EVENT_UNINSTALL @@ -697,6 +694,9 @@ swig SWIG_LIB SWIG PC_PY_DEPENDENCY +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG PY_MAJOR_VERSION PYTHON_SITE_PKG PYTHON_LDFLAGS @@ -1440,7 +1440,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.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]... @@ -1505,7 +1505,7 @@ fi 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 @@ -1722,7 +1722,7 @@ fi 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. @@ -2431,7 +2431,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.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 $@ @@ -2781,14 +2781,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu 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 @@ -2850,6 +2850,7 @@ LIBUNBOUND_AGE=5 # 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 @@ -6273,6 +6274,8 @@ fi + + for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. @@ -6432,6 +6435,7 @@ fi 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; } @@ -6442,8 +6446,27 @@ $as_echo "#define LEX_HAS_YYLEX_DESTROY 1" >>confdefs.h { $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. @@ -16929,7 +16952,136 @@ $as_echo "#define HAVE_PYTHON 1" >>confdefs.h 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 @@ -18870,10 +19022,10 @@ else 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 @@ -18959,126 +19111,6 @@ else 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 : @@ -21045,7 +21077,7 @@ _ACEOF -version=1.7.3 +version=1.8.0 date=`date +'%b %e, %Y'` @@ -21564,7 +21596,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.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 @@ -21630,7 +21662,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -unbound config.status 1.7.3 +unbound config.status 1.8.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/unbound/configure.ac b/usr.sbin/unbound/configure.ac index 685dcb39871..b4b65728bda 100644 --- a/usr.sbin/unbound/configure.ac +++ b/usr.sbin/unbound/configure.ac @@ -10,16 +10,16 @@ sinclude(dnscrypt/dnscrypt.m4) # 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 @@ -81,6 +81,7 @@ LIBUNBOUND_AGE=5 # 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 @@ -323,11 +324,30 @@ AC_DEFUN([ACX_YYLEX_DESTROY], [ 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) @@ -585,7 +605,10 @@ if test x_$ub_test_python != x_no; then 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 @@ -1177,9 +1200,9 @@ AC_CHECK_DECLS([XML_StopParser], [], [], [AC_INCLUDES_DEFAULT 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 diff --git a/usr.sbin/unbound/daemon/cachedump.c b/usr.sbin/unbound/daemon/cachedump.c index 5a72e9d1106..b1ce53b596b 100644 --- a/usr.sbin/unbound/daemon/cachedump.c +++ b/usr.sbin/unbound/daemon/cachedump.c @@ -653,6 +653,7 @@ load_msg(RES* ssl, sldns_buffer* buf, struct worker* worker) 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"); diff --git a/usr.sbin/unbound/daemon/daemon.c b/usr.sbin/unbound/daemon/daemon.c index 6820e118145..a6bfe390271 100644 --- a/usr.sbin/unbound/daemon/daemon.c +++ b/usr.sbin/unbound/daemon/daemon.c @@ -76,6 +76,7 @@ #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" @@ -104,10 +105,8 @@ static int sig_record_reload = 0; /** 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. @@ -182,15 +181,8 @@ static void 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); @@ -279,11 +271,20 @@ daemon_init(void) 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); @@ -584,6 +585,8 @@ daemon_fork(struct daemon* 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(); @@ -657,12 +660,18 @@ daemon_fork(struct daemon* daemon) /* 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); @@ -738,6 +747,7 @@ daemon_delete(struct daemon* daemon) 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); @@ -746,10 +756,8 @@ daemon_delete(struct daemon* daemon) 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) @@ -800,9 +808,8 @@ void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg) { 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, diff --git a/usr.sbin/unbound/daemon/daemon.h b/usr.sbin/unbound/daemon/daemon.h index 031e05da343..5749dbef8fb 100644 --- a/usr.sbin/unbound/daemon/daemon.h +++ b/usr.sbin/unbound/daemon/daemon.h @@ -113,6 +113,8 @@ struct daemon { 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 */ diff --git a/usr.sbin/unbound/daemon/remote.c b/usr.sbin/unbound/daemon/remote.c index 011c55e659f..91e5609f50f 100644 --- a/usr.sbin/unbound/daemon/remote.c +++ b/usr.sbin/unbound/daemon/remote.c @@ -966,6 +966,8 @@ print_ext(RES* ssl, struct ub_stats_info* s) (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 */ @@ -1050,6 +1052,12 @@ print_ext(RES* ssl, struct ub_stats_info* s) (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; } @@ -1625,6 +1633,7 @@ zone_del_msg(struct lruhash_entry* e, void* arg) if(d->ttl > inf->expired) { d->ttl = inf->expired; d->prefetch_ttl = inf->expired; + d->serve_expired_ttl = inf->expired; inf->num_msgs++; } } @@ -1948,6 +1957,11 @@ parse_delegpt(RES* ssl, char* args, uint8_t* nm, int allow_names) 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)) { @@ -2416,6 +2430,57 @@ do_log_reopen(RES* ssl, struct worker* worker) 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) @@ -2806,6 +2871,12 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, } 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); diff --git a/usr.sbin/unbound/daemon/stats.c b/usr.sbin/unbound/daemon/stats.c index 6f4feaaad9d..cff01d90342 100644 --- a/usr.sbin/unbound/daemon/stats.c +++ b/usr.sbin/unbound/daemon/stats.c @@ -63,6 +63,9 @@ #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 @@ -124,6 +127,33 @@ void server_stats_log(struct ub_server_stats* stats, struct worker* worker, (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, @@ -301,6 +331,13 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset) /* 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; @@ -374,6 +411,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a) 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; @@ -428,8 +466,11 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c, 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) ) diff --git a/usr.sbin/unbound/daemon/unbound.c b/usr.sbin/unbound/daemon/unbound.c index 13831101351..3f0f75a560c 100644 --- a/usr.sbin/unbound/daemon/unbound.c +++ b/usr.sbin/unbound/daemon/unbound.c @@ -101,6 +101,7 @@ static void usage(void) 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"); @@ -626,8 +627,10 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* 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); diff --git a/usr.sbin/unbound/daemon/worker.c b/usr.sbin/unbound/daemon/worker.c index 44a989a4e94..9551c60f4a6 100644 --- a/usr.sbin/unbound/daemon/worker.c +++ b/usr.sbin/unbound/daemon/worker.c @@ -66,6 +66,7 @@ #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" @@ -477,6 +478,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, * 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; @@ -509,7 +511,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, 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); @@ -534,19 +536,22 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, } } /* 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); @@ -614,6 +619,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, 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; @@ -623,7 +629,9 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, && 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 @@ -667,7 +675,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, 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); @@ -695,12 +703,13 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, } } 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 && @@ -728,11 +737,13 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, 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); @@ -779,10 +790,11 @@ reply_and_prefetch(struct worker* worker, struct query_info* qinfo, * @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)); @@ -815,7 +827,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, 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)) @@ -825,9 +837,9 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* 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); } /** @@ -835,9 +847,11 @@ chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns, * @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 */ @@ -848,7 +862,7 @@ chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w) 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; } @@ -882,7 +896,7 @@ chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w) } 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); } @@ -891,12 +905,13 @@ chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w) * @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) @@ -912,13 +927,13 @@ answer_chaos(struct worker* w, struct query_info* qinfo, 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, @@ -929,8 +944,8 @@ answer_chaos(struct worker* w, struct query_info* qinfo, 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, @@ -938,7 +953,7 @@ answer_chaos(struct worker* w, struct query_info* qinfo, { if(cfg->hide_trustanchor) return 0; - chaos_trustanchor(pkt, edns, w); + chaos_trustanchor(pkt, edns, w, repinfo); return 1; } @@ -1246,29 +1261,52 @@ worker_handle_request(struct comm_point* c, void* arg, int error, 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) { @@ -1298,7 +1336,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, 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; @@ -1325,7 +1363,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } 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); @@ -1708,9 +1746,13 @@ worker_init(struct worker* worker, struct config_file *cfg, 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); @@ -1972,22 +2014,22 @@ void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), } 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); } @@ -2000,13 +2042,13 @@ int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 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; } diff --git a/usr.sbin/unbound/dns64/dns64.c b/usr.sbin/unbound/dns64/dns64.c index 7889d72e229..eadfabb08c8 100644 --- a/usr.sbin/unbound/dns64/dns64.c +++ b/usr.sbin/unbound/dns64/dns64.c @@ -48,6 +48,9 @@ #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" /****************************************************************************** * * @@ -111,6 +114,11 @@ struct dns64_env { * 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; }; @@ -285,6 +293,40 @@ synthesize_aaaa(const uint8_t prefix_addr[16], int prefix_net, ******************************************************************************/ /** + * 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 * prefix (a.k.a. Pref64) is configurable. @@ -295,6 +337,7 @@ synthesize_aaaa(const uint8_t prefix_addr[16], int prefix_net, 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, @@ -311,6 +354,11 @@ dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg) 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; } @@ -329,7 +377,8 @@ dns64_init(struct module_env* env, int id) 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; @@ -337,6 +386,16 @@ dns64_init(struct module_env* env, int id) 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. * @@ -346,8 +405,14 @@ dns64_init(struct module_env* env, int id) 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; } @@ -441,6 +506,25 @@ generate_type_A_query(struct module_qstate* qstate, int id) } /** + * 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 * another module, in which case we don't want to do any special processing @@ -468,6 +552,14 @@ handle_event_pass(struct module_qstate* qstate, int id) && 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; @@ -501,17 +593,29 @@ handle_event_moddone(struct module_qstate* qstate, int id) * 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; } /** @@ -677,8 +781,9 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate * 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; @@ -705,6 +810,12 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate 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, diff --git a/usr.sbin/unbound/doc/Changelog b/usr.sbin/unbound/doc/Changelog index 3d05ae53a1a..7e81304f930 100644 --- a/usr.sbin/unbound/doc/Changelog +++ b/usr.sbin/unbound/doc/Changelog @@ -1,14 +1,263 @@ +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 diff --git a/usr.sbin/unbound/doc/README b/usr.sbin/unbound/doc/README index 5bd23fac67b..ae90773412f 100644 --- a/usr.sbin/unbound/doc/README +++ b/usr.sbin/unbound/doc/README @@ -1,4 +1,4 @@ -README for Unbound 1.7.3 +README for Unbound 1.8.0 Copyright 2007 NLnet Labs http://unbound.net @@ -76,6 +76,8 @@ The DNSTAP code has BSD license in dnstap/dnstap.c. 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. diff --git a/usr.sbin/unbound/doc/example.conf.in b/usr.sbin/unbound/doc/example.conf.in index d1f21482088..993a08d620d 100644 --- a/usr.sbin/unbound/doc/example.conf.in +++ b/usr.sbin/unbound/doc/example.conf.in @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.7.3. +# See unbound.conf(5) man page, version 1.8.0. # # this is a comment. @@ -103,7 +103,7 @@ server: # 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 @@ -212,6 +212,15 @@ server: # 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 @@ -309,6 +318,13 @@ server: # 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@" @@ -357,7 +373,7 @@ server: # 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). @@ -438,7 +454,7 @@ server: # 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 @@ -527,6 +543,16 @@ server: # 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. @@ -692,6 +718,9 @@ server: # 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. @@ -725,6 +754,9 @@ server: # 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 @@ -814,6 +846,7 @@ remote-control: # stub-prime: no # stub-first: no # stub-tls-upstream: no +# stub-no-cache: no # stub-zone: # name: "example.org" # stub-host: ns.example.com. @@ -830,6 +863,7 @@ remote-control: # 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 diff --git a/usr.sbin/unbound/doc/libunbound.3.in b/usr.sbin/unbound/doc/libunbound.3.in index d4b0efd69a9..9a2fff83560 100644 --- a/usr.sbin/unbound/doc/libunbound.3.in +++ b/usr.sbin/unbound/doc/libunbound.3.in @@ -1,4 +1,4 @@ -.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 .\" @@ -43,7 +43,7 @@ .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 diff --git a/usr.sbin/unbound/doc/unbound-anchor.8.in b/usr.sbin/unbound/doc/unbound-anchor.8.in index ca7cafa060a..ece844deff3 100644 --- a/usr.sbin/unbound/doc/unbound-anchor.8.in +++ b/usr.sbin/unbound/doc/unbound-anchor.8.in @@ -1,4 +1,4 @@ -.TH "unbound-anchor" "8" "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 .\" @@ -109,6 +109,11 @@ It does so, because the tool when used for bootstrapping the recursive 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 diff --git a/usr.sbin/unbound/doc/unbound-checkconf.8.in b/usr.sbin/unbound/doc/unbound-checkconf.8.in index 9d35e64dbe0..1fa91d35d3c 100644 --- a/usr.sbin/unbound/doc/unbound-checkconf.8.in +++ b/usr.sbin/unbound/doc/unbound-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "unbound-checkconf" "8" "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 .\" diff --git a/usr.sbin/unbound/doc/unbound-control.8.in b/usr.sbin/unbound/doc/unbound-control.8.in index f3d9669f816..596138470e5 100644 --- a/usr.sbin/unbound/doc/unbound-control.8.in +++ b/usr.sbin/unbound/doc/unbound-control.8.in @@ -1,4 +1,4 @@ -.TH "unbound-control" "8" "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 .\" @@ -293,6 +293,18 @@ ips are dropped before checking the cache. 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 @@ -515,6 +527,10 @@ Number of queries that were made using TCP towards the unbound server. 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 @@ -625,6 +641,14 @@ answered using cached data. 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@ diff --git a/usr.sbin/unbound/doc/unbound-host.1.in b/usr.sbin/unbound/doc/unbound-host.1.in index ea95bd77e07..dacee3d1342 100644 --- a/usr.sbin/unbound/doc/unbound-host.1.in +++ b/usr.sbin/unbound/doc/unbound-host.1.in @@ -1,4 +1,4 @@ -.TH "unbound\-host" "1" "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 .\" @@ -12,20 +12,20 @@ \- 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 @@ -86,6 +86,8 @@ are read. .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 diff --git a/usr.sbin/unbound/doc/unbound.8.in b/usr.sbin/unbound/doc/unbound.8.in index 5613ce30b20..7062fb07eac 100644 --- a/usr.sbin/unbound/doc/unbound.8.in +++ b/usr.sbin/unbound/doc/unbound.8.in @@ -1,4 +1,4 @@ -.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 .\" @@ -9,7 +9,7 @@ .\" .SH "NAME" .B unbound -\- Unbound DNS validating resolver 1.7.3. +\- Unbound DNS validating resolver 1.8.0. .SH "SYNOPSIS" .B unbound .RB [ \-h ] diff --git a/usr.sbin/unbound/doc/unbound.conf.5.in b/usr.sbin/unbound/doc/unbound.conf.5.in index c4b812763d6..3fc16dc2b53 100644 --- a/usr.sbin/unbound/doc/unbound.conf.5.in +++ b/usr.sbin/unbound/doc/unbound.conf.5.in @@ -1,4 +1,4 @@ -.TH "unbound.conf" "5" "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 .\" @@ -85,7 +85,7 @@ interface and port number), if not specified the default port (from \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 @@ -242,9 +242,9 @@ to so\-rcvbuf. .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. @@ -353,6 +353,37 @@ Note that not all platform supports socket option to set MSS (TCP_MAXSEG). 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. @@ -367,7 +398,7 @@ Enabled or disable whether the upstream queries use TLS only for transport. 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> @@ -430,6 +461,11 @@ Enable or disable whether the unbound server forks into the background as 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, @@ -521,8 +557,9 @@ to chroot and dropping permissions. This allows the pidfile to be 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 @@ -582,6 +619,16 @@ Default is no. Note that it takes time to print these 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 @@ -655,7 +702,7 @@ noerror for empty nonterminals, hence this is possible. Very old software 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> @@ -769,9 +816,11 @@ from the query ID, for speed and thread safety). Default is 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 @@ -919,6 +968,17 @@ If enabled, unbound attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish. 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 @@ -967,7 +1027,7 @@ Number of bytes size of the aggressive negative cache. Default is 1 megabyte. 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, @@ -978,7 +1038,7 @@ as a (DHCP-) DNS network resolver for a group of machines, where such 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. @@ -1425,6 +1485,10 @@ Default is no. .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 @@ -1459,6 +1523,7 @@ the '@' and '#', the '@' comes first. 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. @@ -1469,11 +1534,15 @@ The default is no. .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 @@ -1608,6 +1677,12 @@ It must be /96 or shorter. The default prefix is 64:ff9b::/96. .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 diff --git a/usr.sbin/unbound/edns-subnet/subnetmod.c b/usr.sbin/unbound/edns-subnet/subnetmod.c index ae2523b86c2..1a5044e427c 100644 --- a/usr.sbin/unbound/edns-subnet/subnetmod.c +++ b/usr.sbin/unbound/edns-subnet/subnetmod.c @@ -464,7 +464,12 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) 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) { @@ -511,6 +516,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) lock_rw_wrlock(&sne->biglock); update_cache(qstate, id); + sne->num_msg_nocache++; lock_rw_unlock(&sne->biglock); if (sq->subnet_downstream) { @@ -693,6 +699,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, 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; @@ -741,7 +748,8 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event, /* 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); } diff --git a/usr.sbin/unbound/edns-subnet/subnetmod.h b/usr.sbin/unbound/edns-subnet/subnetmod.h index c7f56327f9d..f417a64a45b 100644 --- a/usr.sbin/unbound/edns-subnet/subnetmod.h +++ b/usr.sbin/unbound/edns-subnet/subnetmod.h @@ -61,6 +61,10 @@ struct subnet_env { /** 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 { diff --git a/usr.sbin/unbound/ipsecmod/ipsecmod.c b/usr.sbin/unbound/ipsecmod/ipsecmod.c index 3e4ee6a5350..c8400c6333e 100644 --- a/usr.sbin/unbound/ipsecmod/ipsecmod.c +++ b/usr.sbin/unbound/ipsecmod/ipsecmod.c @@ -341,6 +341,8 @@ ipsecmod_handle_query(struct module_qstate* qstate, qstate->env->cfg->ipsecmod_max_ttl; qstate->return_msg->rep->prefetch_ttl = PREFETCH_TTL_CALC( qstate->return_msg->rep->ttl); + qstate->return_msg->rep->serve_expired_ttl = qstate->return_msg->rep->ttl + + qstate->env->cfg->serve_expired_ttl; } } } diff --git a/usr.sbin/unbound/iterator/iter_delegpt.h b/usr.sbin/unbound/iterator/iter_delegpt.h index 354bd617738..6c088264588 100644 --- a/usr.sbin/unbound/iterator/iter_delegpt.h +++ b/usr.sbin/unbound/iterator/iter_delegpt.h @@ -85,6 +85,8 @@ struct delegpt { uint8_t ssl_upstream; /** delegpt from authoritative zone that is locally hosted */ uint8_t auth_dp; + /*** no cache */ + int no_cache; }; /** diff --git a/usr.sbin/unbound/iterator/iter_fwd.c b/usr.sbin/unbound/iterator/iter_fwd.c index a44f54386dc..4eb0eb71860 100644 --- a/usr.sbin/unbound/iterator/iter_fwd.c +++ b/usr.sbin/unbound/iterator/iter_fwd.c @@ -239,6 +239,11 @@ read_fwds_addr(struct config_stub* s, struct delegpt* dp) 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"); @@ -267,6 +272,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg) * 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:"); diff --git a/usr.sbin/unbound/iterator/iter_hints.c b/usr.sbin/unbound/iterator/iter_hints.c index e8d09338e97..0b35a9d9e24 100644 --- a/usr.sbin/unbound/iterator/iter_hints.c +++ b/usr.sbin/unbound/iterator/iter_hints.c @@ -252,6 +252,11 @@ read_stubs_addr(struct config_stub* s, struct delegpt* dp) 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"); @@ -278,6 +283,8 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg) * 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); diff --git a/usr.sbin/unbound/iterator/iter_utils.c b/usr.sbin/unbound/iterator/iter_utils.c index 0a8f7700fcf..90c8cf114e3 100644 --- a/usr.sbin/unbound/iterator/iter_utils.c +++ b/usr.sbin/unbound/iterator/iter_utils.c @@ -375,11 +375,34 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, 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) { @@ -401,6 +424,9 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, 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; diff --git a/usr.sbin/unbound/iterator/iterator.c b/usr.sbin/unbound/iterator/iterator.c index 58a9bff6634..e99a559fae4 100644 --- a/usr.sbin/unbound/iterator/iterator.c +++ b/usr.sbin/unbound/iterator/iterator.c @@ -230,11 +230,12 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) 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 */ @@ -303,8 +304,20 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode) 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); } @@ -318,6 +331,7 @@ error_response_cache(struct module_qstate* qstate, int id, int 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"); @@ -789,6 +803,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, 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 */ } @@ -807,6 +822,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, 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 */ } @@ -822,6 +838,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, 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 */ } @@ -905,6 +922,7 @@ auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq, return 1; /* just fallback */ } lock_rw_unlock(&z->lock); + errinf(qstate, "malloc failure"); return 0; } dp->name = regional_alloc_init(qstate->region, @@ -916,6 +934,7 @@ auth_zone_delegpt(struct module_qstate* qstate, struct iter_qstate* iq, return 1; /* just fallback */ } lock_rw_unlock(&z->lock); + errinf(qstate, "malloc failure"); return 0; } dp->namelen = z->namelen; @@ -1125,6 +1144,53 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq) 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 @@ -1159,6 +1225,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1170,6 +1240,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1196,7 +1268,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* 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"); @@ -1240,9 +1318,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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 @@ -1260,6 +1341,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* 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; @@ -1271,6 +1354,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, { 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; @@ -1290,6 +1374,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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; @@ -1349,12 +1434,14 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1398,6 +1485,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } } @@ -1427,6 +1517,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1435,6 +1526,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1454,6 +1548,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1508,6 +1603,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, 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 @@ -1798,6 +1894,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -1857,6 +1955,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, 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; @@ -1868,6 +1968,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, } 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 && @@ -1876,6 +1977,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, 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 */ @@ -1901,9 +2003,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* 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++; } @@ -1911,9 +2015,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* 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++; } @@ -1934,6 +2040,8 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, 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. */ @@ -1967,6 +2075,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id) } /* 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); } @@ -1987,6 +2096,7 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id) 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); } @@ -2032,11 +2142,13 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, 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); } @@ -2044,6 +2156,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * 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) @@ -2203,6 +2316,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, * 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) { @@ -2228,6 +2342,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, 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; @@ -2308,6 +2423,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, "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); } @@ -2378,6 +2495,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, 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); } } @@ -2542,6 +2662,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* 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 */ @@ -2690,11 +2819,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, 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); @@ -2756,8 +2889,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, } /* 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). */ @@ -2858,6 +2993,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, 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, " @@ -2948,6 +3085,8 @@ processPrimeResponse(struct module_qstate* qstate, int id) 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; } @@ -3091,6 +3230,7 @@ processDSNSResponse(struct module_qstate* qstate, int id, 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) */ @@ -3191,6 +3331,8 @@ processClassResponse(struct module_qstate* qstate, int id, 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 --; @@ -3229,6 +3371,8 @@ processCollectClass(struct module_qstate* qstate, int id) 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); } @@ -3275,6 +3419,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, (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); } @@ -3445,6 +3590,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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 @@ -3459,6 +3605,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, || !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; } @@ -3511,6 +3658,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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"); @@ -3530,15 +3678,30 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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"); @@ -3570,6 +3733,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, 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; @@ -3608,6 +3772,7 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, 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; } @@ -3625,11 +3790,13 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id, } 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); } diff --git a/usr.sbin/unbound/iterator/iterator.h b/usr.sbin/unbound/iterator/iterator.h index 67ffeb14763..57cb7c4c474 100644 --- a/usr.sbin/unbound/iterator/iterator.h +++ b/usr.sbin/unbound/iterator/iterator.h @@ -371,6 +371,9 @@ struct iter_qstate { /** 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. diff --git a/usr.sbin/unbound/libunbound/context.c b/usr.sbin/unbound/libunbound/context.c index 6ac8086bf67..9a35ce56f30 100644 --- a/usr.sbin/unbound/libunbound/context.c +++ b/usr.sbin/unbound/libunbound/context.c @@ -71,9 +71,8 @@ context_finalize(struct ub_ctx* ctx) 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, @@ -294,26 +293,29 @@ context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, * 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; } @@ -322,21 +324,23 @@ struct ctx_query* 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; @@ -345,9 +349,9 @@ context_deserialize_answer(struct ub_ctx* ctx, } 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 */ diff --git a/usr.sbin/unbound/libunbound/libworker.c b/usr.sbin/unbound/libunbound/libworker.c index 3dcaa7818f7..05006a0ec44 100644 --- a/usr.sbin/unbound/libunbound/libworker.c +++ b/usr.sbin/unbound/libunbound/libworker.c @@ -521,8 +521,9 @@ libworker_enter_result(struct ub_result* res, sldns_buffer* buf, /** 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) { @@ -546,13 +547,13 @@ libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, 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 */ @@ -603,16 +604,16 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) 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; @@ -634,7 +635,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) 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; @@ -657,7 +658,7 @@ libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, 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); } } @@ -684,15 +685,15 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, 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 */ @@ -710,7 +711,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, /** 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; @@ -724,19 +725,23 @@ add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 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--; @@ -755,7 +760,7 @@ add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 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; @@ -773,12 +778,13 @@ libworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, 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); } @@ -803,7 +809,7 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len) 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; @@ -816,15 +822,15 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len) 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; } @@ -832,7 +838,7 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len) /* 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); } diff --git a/usr.sbin/unbound/libunbound/unbound-event.h b/usr.sbin/unbound/libunbound/unbound-event.h index d5f0b1a36fe..4d694b8b4c5 100644 --- a/usr.sbin/unbound/libunbound/unbound-event.h +++ b/usr.sbin/unbound/libunbound/unbound-event.h @@ -170,7 +170,7 @@ struct ub_event { 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. diff --git a/usr.sbin/unbound/libunbound/unbound.h b/usr.sbin/unbound/libunbound/unbound.h index fbd69cab0e7..90766b06236 100644 --- a/usr.sbin/unbound/libunbound/unbound.h +++ b/usr.sbin/unbound/libunbound/unbound.h @@ -204,6 +204,12 @@ struct ub_result { 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. */ @@ -674,6 +680,8 @@ struct ub_server_stats { 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 */ @@ -757,6 +765,11 @@ struct ub_server_stats { /** 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; }; /** diff --git a/usr.sbin/unbound/libunbound/worker.h b/usr.sbin/unbound/libunbound/worker.h index 7d2ede04ed0..fe1d51878a8 100644 --- a/usr.sbin/unbound/libunbound/worker.h +++ b/usr.sbin/unbound/libunbound/worker.h @@ -89,15 +89,15 @@ void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len, /** 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. diff --git a/usr.sbin/unbound/respip/respip.c b/usr.sbin/unbound/respip/respip.c index 2e9313f271b..135c45fe53c 100644 --- a/usr.sbin/unbound/respip/respip.c +++ b/usr.sbin/unbound/respip/respip.c @@ -611,8 +611,9 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region, * EDNS0 OPT RR in the additional section appended on sending it out), * so the total number of RRsets is an_numrrsets. */ new_rep = construct_reply_info_base(region, rep->flags, - rep->qdcount, rep->ttl, rep->prefetch_ttl, an_numrrsets, - 0, 0, an_numrrsets, sec_status_insecure); + rep->qdcount, rep->ttl, rep->prefetch_ttl, + rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets, + sec_status_insecure); if(!new_rep) return NULL; if(!reply_info_alloc_rrset_keys(new_rep, NULL, region)) diff --git a/usr.sbin/unbound/services/authzone.c b/usr.sbin/unbound/services/authzone.c index f1ca2a2b055..fe56c9f81b6 100644 --- a/usr.sbin/unbound/services/authzone.c +++ b/usr.sbin/unbound/services/authzone.c @@ -185,11 +185,13 @@ msg_ttl(struct dns_msg* msg) 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; } } @@ -1014,7 +1016,8 @@ rrset_moveover_rrsigs(struct auth_data* node, uint16_t rr_type, } /* 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)); @@ -2284,6 +2287,7 @@ az_add_negative_soa(struct auth_zone* z, struct regional* region, 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; } @@ -3168,8 +3172,8 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo, /** 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; @@ -3179,7 +3183,7 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env, 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), @@ -3194,8 +3198,8 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env, /** 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; @@ -3203,7 +3207,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, 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), @@ -3211,8 +3215,8 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, } 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; @@ -3260,9 +3264,9 @@ int auth_zones_answer(struct auth_zones* az, struct module_env* env, /* 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; } @@ -3470,6 +3474,23 @@ int auth_zones_notify(struct auth_zones* az, struct module_env* env, 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, @@ -5073,7 +5094,8 @@ xfr_transfer_nexttarget_or_end(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); } @@ -5132,7 +5154,8 @@ xfr_master_add_addrs(struct auth_master* m, struct ub_packed_rrset_key* rrset, /** 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; @@ -5530,7 +5553,8 @@ process_list_end_transfer(struct auth_xfer* xfr, 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; @@ -5871,29 +5895,35 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, 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; @@ -5996,7 +6026,8 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) /* 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; } @@ -6012,18 +6043,31 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env) 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; @@ -6151,6 +6195,8 @@ xfr_start_probe(struct auth_xfer* xfr, 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 */ diff --git a/usr.sbin/unbound/services/authzone.h b/usr.sbin/unbound/services/authzone.h index 4e06c0654d9..8c636eaa446 100644 --- a/usr.sbin/unbound/services/authzone.h +++ b/usr.sbin/unbound/services/authzone.h @@ -309,6 +309,9 @@ struct auth_probe { /** 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 */ @@ -509,12 +512,13 @@ int auth_zones_lookup(struct auth_zones* az, struct query_info* qinfo, * @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. @@ -588,6 +592,12 @@ int auth_zones_notify(struct auth_zones* az, struct module_env* env, * 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); @@ -637,10 +647,12 @@ int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err, 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 diff --git a/usr.sbin/unbound/services/cache/dns.c b/usr.sbin/unbound/services/cache/dns.c index 35adc35b57e..01c9a8c5c10 100644 --- a/usr.sbin/unbound/services/cache/dns.c +++ b/usr.sbin/unbound/services/cache/dns.c @@ -109,7 +109,7 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, } /** 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) { @@ -547,6 +547,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, 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; @@ -601,6 +602,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 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; @@ -638,6 +640,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 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; @@ -696,6 +699,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 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 ++; diff --git a/usr.sbin/unbound/services/cache/dns.h b/usr.sbin/unbound/services/cache/dns.h index 78f81e79952..19d0d9f992d 100644 --- a/usr.sbin/unbound/services/cache/dns.h +++ b/usr.sbin/unbound/services/cache/dns.h @@ -238,4 +238,16 @@ struct msgreply_entry* msg_cache_lookup(struct module_env* env, 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 */ diff --git a/usr.sbin/unbound/services/cache/infra.c b/usr.sbin/unbound/services/cache/infra.c index f4320306daa..6f8fea6ad82 100644 --- a/usr.sbin/unbound/services/cache/infra.c +++ b/usr.sbin/unbound/services/cache/infra.c @@ -215,6 +215,18 @@ static int infra_ratelimit_cfg_insert(struct infra_cache* infra, 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) { @@ -230,7 +242,6 @@ 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, @@ -241,11 +252,10 @@ infra_create(struct config_file* cfg) 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, @@ -285,12 +295,28 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg) 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; } diff --git a/usr.sbin/unbound/services/cache/rrset.c b/usr.sbin/unbound/services/cache/rrset.c index 26c1aeb91c6..8c0251bcb93 100644 --- a/usr.sbin/unbound/services/cache/rrset.c +++ b/usr.sbin/unbound/services/cache/rrset.c @@ -81,8 +81,8 @@ void rrset_cache_delete(struct rrset_cache* r) 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); diff --git a/usr.sbin/unbound/services/listen_dnsport.c b/usr.sbin/unbound/services/listen_dnsport.c index 70284168e1d..458bf6f513f 100644 --- a/usr.sbin/unbound/services/listen_dnsport.c +++ b/usr.sbin/unbound/services/listen_dnsport.c @@ -167,7 +167,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, 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 @@ -564,7 +564,8 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, /* 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); } @@ -572,7 +573,8 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, 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); @@ -1216,7 +1218,8 @@ listen_cp_insert(struct comm_point* c, struct listen_dnsport* front) 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*) @@ -1243,10 +1246,12 @@ listen_create(struct comm_base* base, struct listen_port* ports, 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) diff --git a/usr.sbin/unbound/services/listen_dnsport.h b/usr.sbin/unbound/services/listen_dnsport.h index fac0f797092..46b432d4b93 100644 --- a/usr.sbin/unbound/services/listen_dnsport.h +++ b/usr.sbin/unbound/services/listen_dnsport.h @@ -47,6 +47,7 @@ struct listen_list; struct config_file; struct addrinfo; struct sldns_buffer; +struct tcl_list; /** * Listening for queries structure. @@ -137,6 +138,8 @@ void listening_ports_free(struct listen_port* list); * @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 @@ -145,9 +148,10 @@ void listening_ports_free(struct listen_port* list); * @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 diff --git a/usr.sbin/unbound/services/localzone.c b/usr.sbin/unbound/services/localzone.c index 0f608170c85..902a29f21d4 100644 --- a/usr.sbin/unbound/services/localzone.c +++ b/usr.sbin/unbound/services/localzone.c @@ -1146,8 +1146,9 @@ void local_zones_print(struct local_zones* zones) /** 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; @@ -1165,23 +1166,22 @@ local_encode(struct query_info* qinfo, struct module_env* env, 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; @@ -1189,7 +1189,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, 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); @@ -1310,7 +1310,8 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list, /** 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) @@ -1339,7 +1340,7 @@ local_data_answer(struct local_zone* z, struct module_env* env, * 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); } } @@ -1374,29 +1375,60 @@ local_data_answer(struct local_zone* z, struct module_env* env, 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. */ @@ -1405,7 +1437,7 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, 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 || @@ -1421,9 +1453,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, 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 @@ -1438,9 +1470,9 @@ lz_zone_answer(struct local_zone* z, struct module_env* env, 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; } @@ -1459,7 +1491,7 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo, 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); } @@ -1543,10 +1575,6 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, (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; } @@ -1554,10 +1582,24 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, 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) { @@ -1570,27 +1612,33 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, 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 */ } diff --git a/usr.sbin/unbound/services/mesh.c b/usr.sbin/unbound/services/mesh.c index 41aba74ab26..c6bb9ef2bc6 100644 --- a/usr.sbin/unbound/services/mesh.c +++ b/usr.sbin/unbound/services/mesh.c @@ -55,6 +55,7 @@ #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" @@ -385,7 +386,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, 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); @@ -401,7 +402,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, 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); @@ -429,7 +430,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, 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); @@ -631,8 +632,8 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, 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) { @@ -693,6 +694,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo, 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++) { @@ -740,7 +742,7 @@ mesh_state_cleanup(struct mesh_state* mstate) 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--; } } @@ -968,7 +970,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, { 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; @@ -977,22 +980,23 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, 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); @@ -1002,7 +1006,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, 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, @@ -1010,11 +1014,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, { 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); @@ -1080,11 +1084,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, 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, @@ -1099,14 +1103,17 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, 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, @@ -1148,6 +1155,15 @@ void mesh_query_done(struct mesh_state* mstate) 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. */ @@ -1197,6 +1213,8 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate) 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); } } diff --git a/usr.sbin/unbound/services/mesh.h b/usr.sbin/unbound/services/mesh.h index 67749accb35..b4ce03e7e2a 100644 --- a/usr.sbin/unbound/services/mesh.h +++ b/usr.sbin/unbound/services/mesh.h @@ -223,10 +223,11 @@ struct mesh_reply { /** * 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 @@ -242,9 +243,8 @@ struct mesh_cb { 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 */ diff --git a/usr.sbin/unbound/services/outside_network.c b/usr.sbin/unbound/services/outside_network.c index 5700ef8a95e..87c88349b3f 100644 --- a/usr.sbin/unbound/services/outside_network.c +++ b/usr.sbin/unbound/services/outside_network.c @@ -48,6 +48,7 @@ #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" @@ -1036,6 +1037,8 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, 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); @@ -1882,7 +1885,7 @@ serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff) 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; @@ -2190,39 +2193,48 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, { 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); diff --git a/usr.sbin/unbound/sldns/rrdef.c b/usr.sbin/unbound/sldns/rrdef.c index 644762f59f4..b365a4a8ec3 100644 --- a/usr.sbin/unbound/sldns/rrdef.c +++ b/usr.sbin/unbound/sldns/rrdef.c @@ -341,12 +341,9 @@ static sldns_rr_descriptor rdata_field_descriptors[] = { {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. diff --git a/usr.sbin/unbound/sldns/rrdef.h b/usr.sbin/unbound/sldns/rrdef.h index 0446687bd33..4e7fef5745f 100644 --- a/usr.sbin/unbound/sldns/rrdef.h +++ b/usr.sbin/unbound/sldns/rrdef.h @@ -182,9 +182,7 @@ enum sldns_enum_rr_type 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 */ diff --git a/usr.sbin/unbound/smallapp/unbound-anchor.c b/usr.sbin/unbound/smallapp/unbound-anchor.c index b3009108800..f398509018d 100644 --- a/usr.sbin/unbound/smallapp/unbound-anchor.c +++ b/usr.sbin/unbound/smallapp/unbound-anchor.c @@ -192,9 +192,10 @@ usage(void) 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"); @@ -1920,8 +1921,7 @@ static int 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; @@ -1961,7 +1961,6 @@ do_certupdate(const char* root_anchor_file, const char* root_cert_file, #ifndef S_SPLINT_S sk_X509_pop_free(cert, X509_free); #endif - ub_resolve_free(dnskey); ip_list_free(ip_list); return 1; } @@ -2199,16 +2198,33 @@ probe_date_allows_certupdate(const char* root_anchor_file) 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' */ @@ -2217,12 +2233,22 @@ do_root_update_work(const char* root_anchor_file, const char* root_cert_file, /* 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"); @@ -2230,18 +2256,18 @@ do_root_update_work(const char* root_anchor_file, const char* root_cert_file, 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; } @@ -2264,8 +2290,9 @@ int main(int argc, char* argv[]) 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; @@ -2300,6 +2327,9 @@ int main(int argc, char* argv[]) case 'r': root_hints = optarg; break; + case 'R': + res_conf_fallback = 1; + break; case 'C': debugconf = optarg; break; @@ -2346,5 +2376,5 @@ int main(int argc, char* argv[]) 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); } diff --git a/usr.sbin/unbound/smallapp/unbound-checkconf.c b/usr.sbin/unbound/smallapp/unbound-checkconf.c index 37ba9eab31a..ea46479172c 100644 --- a/usr.sbin/unbound/smallapp/unbound-checkconf.c +++ b/usr.sbin/unbound/smallapp/unbound-checkconf.c @@ -43,6 +43,7 @@ */ #include "config.h" +#include <ctype.h> #include "util/log.h" #include "util/config_file.h" #include "util/module.h" @@ -252,6 +253,23 @@ aclchecks(struct config_file* cfg) } } +/** 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) @@ -373,6 +391,44 @@ ecs_conf_checks(struct config_file* cfg) } #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) @@ -381,6 +437,7 @@ 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"); @@ -465,6 +522,9 @@ morechecks(struct config_file* cfg, const char* fname) 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 @@ -511,7 +571,6 @@ morechecks(struct config_file* cfg, const char* fname) #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 diff --git a/usr.sbin/unbound/smallapp/unbound-control.c b/usr.sbin/unbound/smallapp/unbound-control.c index d1654177919..9e4c006f3b5 100644 --- a/usr.sbin/unbound/smallapp/unbound-control.c +++ b/usr.sbin/unbound/smallapp/unbound-control.c @@ -143,6 +143,8 @@ usage(void) 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"); @@ -319,6 +321,7 @@ static void print_extended(struct ub_stats_info* s) /* 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 */ @@ -371,6 +374,10 @@ static void print_extended(struct ub_stats_info* s) #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 */ @@ -444,6 +451,22 @@ static void ssl_err(const char* s) 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) @@ -467,12 +490,15 @@ 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); diff --git a/usr.sbin/unbound/smallapp/unbound-host.c b/usr.sbin/unbound/smallapp/unbound-host.c index cd1ffe3351d..f02511fe561 100644 --- a/usr.sbin/unbound/smallapp/unbound-host.c +++ b/usr.sbin/unbound/smallapp/unbound-host.c @@ -82,9 +82,8 @@ static int verb = 0; 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"); @@ -98,6 +97,8 @@ usage(void) 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"); @@ -339,6 +340,7 @@ pretty_output(char* q, int t, int c, struct ub_result* result, int docname) exit(1); } printf("%s\n", s); + free(s); } else printf(" has no %s record", tstr); printf(" %s\n", secstatus); } diff --git a/usr.sbin/unbound/smallapp/worker_cb.c b/usr.sbin/unbound/smallapp/worker_cb.c index dda94cc670c..6c3bd004908 100644 --- a/usr.sbin/unbound/smallapp/worker_cb.c +++ b/usr.sbin/unbound/smallapp/worker_cb.c @@ -168,21 +168,21 @@ void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), 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); } diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c index 5513144da9a..55ac97af4f3 100644 --- a/usr.sbin/unbound/util/config_file.c +++ b/usr.sbin/unbound/util/config_file.c @@ -104,6 +104,9 @@ config_create(void) 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; @@ -115,6 +118,8 @@ config_create(void) 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 */ @@ -172,7 +177,7 @@ config_create(void) 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; @@ -192,11 +197,12 @@ config_create(void) #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; @@ -228,6 +234,8 @@ config_create(void) 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 */ @@ -248,7 +256,7 @@ config_create(void) 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"))) @@ -338,6 +346,7 @@ struct config_file* config_create_forlib(void) 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; } @@ -455,6 +464,9 @@ int config_set_option(struct config_file* cfg, const char* opt, 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) @@ -540,10 +552,15 @@ int config_set_option(struct config_file* cfg, const char* opt, 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) @@ -878,6 +895,9 @@ config_get_option(struct config_file* cfg, const char* opt, 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) @@ -893,6 +913,8 @@ config_get_option(struct config_file* cfg, const char* opt, 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) @@ -920,6 +942,8 @@ config_get_option(struct config_file* cfg, const char* opt, 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) @@ -936,6 +960,7 @@ config_get_option(struct config_file* cfg, const char* opt, 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) @@ -1338,6 +1363,7 @@ config_delete(struct config_file* cfg) 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); @@ -1355,6 +1381,7 @@ config_delete(struct config_file* cfg) 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); @@ -1840,6 +1867,7 @@ config_apply(struct config_file* config) { 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; @@ -2178,7 +2206,7 @@ void w_config_adjust_directory(struct config_file* cfg) 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) { @@ -2203,7 +2231,7 @@ void errinf(struct module_qstate* qstate, const char* str) 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]; @@ -2220,7 +2248,7 @@ void errinf_origin(struct module_qstate* qstate, struct sock_list *origin) } } -char* errinf_to_str(struct module_qstate* qstate) +char* errinf_to_str_bogus(struct module_qstate* qstate) { char buf[20480]; char* p = buf; @@ -2245,12 +2273,37 @@ char* errinf_to_str(struct module_qstate* qstate) 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)); @@ -2263,7 +2316,7 @@ void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname) { 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); diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h index 4206eb9a2a5..d1bce1b69be 100644 --- a/usr.sbin/unbound/util/config_file.h +++ b/usr.sbin/unbound/util/config_file.h @@ -99,6 +99,12 @@ struct config_file { 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; @@ -214,6 +220,9 @@ struct config_file { /** 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 */ @@ -268,6 +277,10 @@ struct config_file { 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; @@ -326,6 +339,10 @@ struct config_file { 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 */ @@ -419,6 +436,8 @@ struct config_file { /* 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; @@ -561,6 +580,8 @@ struct config_stub { int isfirst; /** use SSL for queries to this stub */ int ssl_upstream; + /*** no cache */ + int no_cache; }; /** @@ -1065,12 +1086,20 @@ void errinf_dname(struct module_qstate* qstate, const char* str, 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 diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex index 6124e32bd24..75796048491 100644 --- a/usr.sbin/unbound/util/configlexer.lex +++ b/usr.sbin/unbound/util/configlexer.lex @@ -228,6 +228,9 @@ do-tcp{COLON} { YDVAR(1, VAR_DO_TCP) } 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) } @@ -299,12 +302,14 @@ stub-addr{COLON} { YDVAR(1, VAR_STUB_ADDR) } stub-host{COLON} { YDVAR(1, VAR_STUB_HOST) } stub-prime{COLON} { YDVAR(1, VAR_STUB_PRIME) } stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) } +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) } @@ -349,6 +354,8 @@ val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) } 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) } @@ -366,6 +373,8 @@ log-identity{COLON} { YDVAR(1, VAR_LOG_IDENTITY) } 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) } @@ -393,6 +402,7 @@ rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) } max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) } dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } +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) } @@ -462,6 +472,7 @@ redis-server-host{COLON} { YDVAR(1, VAR_CACHEDB_REDISHOST) } 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 */ diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y index e34665aded0..24c5b2d1e95 100644 --- a/usr.sbin/unbound/util/configparser.y +++ b/usr.sbin/unbound/util/configparser.y @@ -72,7 +72,8 @@ extern struct config_parser_state* cfg_parser; %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 @@ -106,7 +107,7 @@ extern struct config_parser_state* cfg_parser; %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 @@ -114,7 +115,7 @@ extern struct config_parser_state* cfg_parser; %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 @@ -139,7 +140,8 @@ extern struct config_parser_state* cfg_parser; %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 @@ -157,7 +159,8 @@ extern struct config_parser_state* cfg_parser; %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 ; @@ -180,7 +183,8 @@ content_server: server_num_threads | server_verbosity | server_port | 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 | @@ -217,11 +221,12 @@ content_server: server_num_threads | server_verbosity | server_port | server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_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 | @@ -239,6 +244,7 @@ content_server: server_num_threads | server_verbosity | server_port | 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 | @@ -249,7 +255,8 @@ content_server: server_num_threads | server_verbosity | server_port | 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 { @@ -266,7 +273,7 @@ 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 { @@ -283,7 +290,7 @@ 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 { @@ -631,6 +638,41 @@ server_outgoing_tcp_mss: VAR_OUTGOING_TCP_MSS STRING_ARG 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)); @@ -764,6 +806,24 @@ server_log_replies: VAR_LOG_REPLIES STRING_ARG 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)); @@ -1462,6 +1522,24 @@ server_serve_expired: VAR_SERVE_EXPIRED STRING_ARG 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)); @@ -1663,6 +1741,14 @@ server_dns64_synthall: VAR_DNS64_SYNTHALL STRING_ARG 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; @@ -2031,6 +2117,15 @@ stub_first: VAR_STUB_FIRST STRING_ARG 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)); @@ -2084,6 +2179,15 @@ forward_first: VAR_FORWARD_FIRST STRING_ARG 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)); @@ -2681,6 +2785,17 @@ redis_timeout: VAR_CACHEDB_REDISTIMEOUT STRING_ARG 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 */ diff --git a/usr.sbin/unbound/util/data/msgparse.h b/usr.sbin/unbound/util/data/msgparse.h index e21f8504ea7..c0c6ff5fd09 100644 --- a/usr.sbin/unbound/util/data/msgparse.h +++ b/usr.sbin/unbound/util/data/msgparse.h @@ -79,6 +79,8 @@ extern time_t MAX_TTL; 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 */ diff --git a/usr.sbin/unbound/util/data/msgreply.c b/usr.sbin/unbound/util/data/msgreply.c index 772f5d1f102..540d7d4b3de 100644 --- a/usr.sbin/unbound/util/data/msgreply.c +++ b/usr.sbin/unbound/util/data/msgreply.c @@ -61,6 +61,8 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */ 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 @@ -85,8 +87,8 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, /** 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. */ @@ -103,6 +105,7 @@ construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, 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; @@ -126,7 +129,7 @@ parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, 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; @@ -424,6 +427,7 @@ parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, pset = pset->rrset_all_next; } rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); + rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL; return 1; } @@ -502,6 +506,7 @@ reply_info_set_ttls(struct reply_info* rep, time_t timenow) 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; @@ -687,9 +692,9 @@ reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, { 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 */ @@ -913,8 +918,9 @@ parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, } 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; } @@ -1013,7 +1019,7 @@ static int inplace_cb_reply_call_generic( 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; @@ -1026,7 +1032,7 @@ static int inplace_cb_reply_call_generic( 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; @@ -1034,44 +1040,45 @@ static int inplace_cb_reply_call_generic( 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, diff --git a/usr.sbin/unbound/util/data/msgreply.h b/usr.sbin/unbound/util/data/msgreply.h index 60e6438a84a..a455c4d2b37 100644 --- a/usr.sbin/unbound/util/data/msgreply.h +++ b/usr.sbin/unbound/util/data/msgreply.h @@ -156,6 +156,12 @@ struct reply_info { */ 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. */ @@ -222,6 +228,7 @@ struct msgreply_entry { * @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 @@ -232,8 +239,8 @@ struct msgreply_entry { */ 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. @@ -545,12 +552,13 @@ struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code); * @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. @@ -561,13 +569,14 @@ int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, * @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. @@ -578,13 +587,14 @@ int inplace_cb_reply_cache_call(struct module_env* env, * @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. @@ -596,13 +606,14 @@ int inplace_cb_reply_local_call(struct module_env* env, * @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. diff --git a/usr.sbin/unbound/util/iana_ports.inc b/usr.sbin/unbound/util/iana_ports.inc index b35cf7d29b0..55d041e4084 100644 --- a/usr.sbin/unbound/util/iana_ports.inc +++ b/usr.sbin/unbound/util/iana_ports.inc @@ -4741,6 +4741,7 @@ 8020, 8021, 8022, +8023, 8025, 8026, 8032, @@ -4917,6 +4918,7 @@ 9104, 9105, 9106, +9111, 9119, 9131, 9160, diff --git a/usr.sbin/unbound/util/module.c b/usr.sbin/unbound/util/module.c index f4b715d141b..f16583183bf 100644 --- a/usr.sbin/unbound/util/module.c +++ b/usr.sbin/unbound/util/module.c @@ -236,3 +236,13 @@ log_edns_known_options(enum verbosity_value level, struct module_env* env) } } } + +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; + } +} diff --git a/usr.sbin/unbound/util/module.h b/usr.sbin/unbound/util/module.h index c6e5164de6d..1b9aed216c7 100644 --- a/usr.sbin/unbound/util/module.h +++ b/usr.sbin/unbound/util/module.h @@ -236,8 +236,8 @@ struct inplace_cb { /** * 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 @@ -247,18 +247,23 @@ struct inplace_cb { * 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. @@ -270,6 +275,7 @@ typedef int inplace_cb_reply_func_type(struct query_info* qinfo, * 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, @@ -279,10 +285,10 @@ 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, @@ -290,11 +296,11 @@ 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, @@ -621,6 +627,8 @@ struct module_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 @@ -819,4 +827,14 @@ int unique_mesh_state(struct edns_option* list, struct module_env* env); 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 */ diff --git a/usr.sbin/unbound/util/net_help.c b/usr.sbin/unbound/util/net_help.c index a5059b0addc..91368c84759 100644 --- a/usr.sbin/unbound/util/net_help.c +++ b/usr.sbin/unbound/util/net_help.c @@ -410,7 +410,7 @@ void log_err_addr(const char* str, const char* err, 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 diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c index 5cc8606fad3..37353804142 100644 --- a/usr.sbin/unbound/util/netevent.c +++ b/usr.sbin/unbound/util/netevent.c @@ -43,6 +43,7 @@ #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" @@ -82,10 +83,11 @@ # 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 */ @@ -728,6 +730,7 @@ comm_point_udp_callback(int fd, short event, void* arg) 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); @@ -737,13 +740,29 @@ setup_tcp_handler(struct comm_point* c, int fd, int cur, int max) #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), @@ -832,6 +851,16 @@ int comm_point_perform_accept(struct comm_point* c, #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 @@ -2525,6 +2554,10 @@ comm_point_create_tcp_handler(struct comm_base *base, 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; @@ -2565,7 +2598,8 @@ comm_point_create_tcp_handler(struct comm_base *base, } 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, @@ -2587,6 +2621,10 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, 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; @@ -2665,6 +2703,10 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, 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; @@ -2906,6 +2948,7 @@ comm_point_close(struct comm_point* c) 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) { diff --git a/usr.sbin/unbound/util/netevent.h b/usr.sbin/unbound/util/netevent.h index 6819f57f8d9..f6b6af688b9 100644 --- a/usr.sbin/unbound/util/netevent.h +++ b/usr.sbin/unbound/util/netevent.h @@ -65,6 +65,7 @@ struct sldns_buffer; struct comm_point; struct comm_reply; +struct tcl_list; struct ub_event_base; /* internal event notification data storage structure. */ @@ -256,9 +257,17 @@ struct comm_point { /** 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; @@ -443,6 +452,8 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, * @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. @@ -452,8 +463,8 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, * 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. diff --git a/usr.sbin/unbound/util/storage/slabhash.c b/usr.sbin/unbound/util/storage/slabhash.c index ae63b97727e..a6c3d0fa649 100644 --- a/usr.sbin/unbound/util/storage/slabhash.c +++ b/usr.sbin/unbound/util/storage/slabhash.c @@ -153,6 +153,19 @@ size_t slabhash_get_size(struct slabhash* sl) 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); diff --git a/usr.sbin/unbound/util/storage/slabhash.h b/usr.sbin/unbound/util/storage/slabhash.h index 2ecf6fe719a..4ecb6042167 100644 --- a/usr.sbin/unbound/util/storage/slabhash.h +++ b/usr.sbin/unbound/util/storage/slabhash.h @@ -153,6 +153,15 @@ void slabhash_status(struct slabhash* table, const char* id, int extended); 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. * @return memory in use. diff --git a/usr.sbin/unbound/validator/autotrust.c b/usr.sbin/unbound/validator/autotrust.c index 7bc5577f4f6..a34a7c96c81 100644 --- a/usr.sbin/unbound/validator/autotrust.c +++ b/usr.sbin/unbound/validator/autotrust.c @@ -2306,7 +2306,7 @@ autr_debug_print(struct val_anchors* anchors) 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 diff --git a/usr.sbin/unbound/validator/autotrust.h b/usr.sbin/unbound/validator/autotrust.h index c549798f0e3..057f2b68aed 100644 --- a/usr.sbin/unbound/validator/autotrust.h +++ b/usr.sbin/unbound/validator/autotrust.h @@ -206,6 +206,6 @@ void autr_debug_print(struct val_anchors* anchors); /** 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 */ diff --git a/usr.sbin/unbound/validator/validator.c b/usr.sbin/unbound/validator/validator.c index 5777b2932cb..fa8d5419a80 100644 --- a/usr.sbin/unbound/validator/validator.c +++ b/usr.sbin/unbound/validator/validator.c @@ -388,6 +388,14 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, 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( @@ -467,7 +475,7 @@ generate_keytag_query(struct module_qstate* qstate, int id, 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; } @@ -524,12 +532,12 @@ prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq, 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 @@ -1673,7 +1681,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) 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; @@ -1745,7 +1753,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) 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; @@ -1774,7 +1782,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) 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; @@ -1784,7 +1792,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id) 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); } @@ -2227,13 +2235,17 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, 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); } @@ -2332,6 +2344,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, 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; @@ -2367,7 +2380,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, 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; |