diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2017-02-17 18:53:33 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2017-02-17 18:53:33 +0000 |
commit | 3d7e55155dd0acaba23dc19920091ee5580ad180 (patch) | |
tree | 128498ff1499e8cde628b28e9707636bd4d161a5 | |
parent | 57a7719d7ee152a16a7ac027d83bcce25a6a46ac (diff) |
Update to unbound-1.6.1rc3 - thanks millert@ and Brad for tests.
138 files changed, 8964 insertions, 2138 deletions
diff --git a/usr.sbin/unbound/Makefile.in b/usr.sbin/unbound/Makefile.in index acff9b6c44f..3c2de971cb9 100644 --- a/usr.sbin/unbound/Makefile.in +++ b/usr.sbin/unbound/Makefile.in @@ -81,7 +81,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" +LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=int" "-D__va_list=va_list" "-D__uint32_t=uint32_t" INSTALL=$(SHELL) $(srcdir)/install-sh @@ -101,7 +101,7 @@ util/data/msgreply.c util/data/packed_rrset.c iterator/iterator.c \ iterator/iter_delegpt.c iterator/iter_donotq.c iterator/iter_fwd.c \ iterator/iter_hints.c iterator/iter_priv.c iterator/iter_resptype.c \ iterator/iter_scrub.c iterator/iter_utils.c services/listen_dnsport.c \ -services/localzone.c services/mesh.c services/modstack.c \ +services/localzone.c services/mesh.c services/modstack.c services/view.c \ services/outbound_list.c services/outside_network.c util/alloc.c \ util/config_file.c util/configlexer.c util/configparser.c \ util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \ @@ -117,7 +117,7 @@ $(DNSTAP_SRC) COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \ 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 \ +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 \ random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \ @@ -228,7 +228,7 @@ SVCUNINST_OBJ_LINK=$(SVCUNINST_OBJ) w_inst.lo rsrc_svcuninst.o \ $(COMPAT_OBJ_WITHOUT_CTIMEARC4) ANCHORUPD_SRC=winrc/anchor-update.c ANCHORUPD_OBJ=anchor-update.lo -ANCHORUPD_OBJ_LINK=$(ANCHORUPD_OBJ) rsrc_anchorupd.o $(COMPAT_OBJ_WITHOUT_CTIMEARC4) +ANCHORUPD_OBJ_LINK=$(ANCHORUPD_OBJ) rsrc_anchorupd.o $(COMPAT_OBJ_WITHOUT_CTIMEARC4) wire2str.lo str2wire.lo parseutil.lo sbuffer.lo rrdef.lo keyraw.lo parse.lo RSRC_OBJ=rsrc_svcinst.o rsrc_svcuninst.o rsrc_anchorupd.o rsrc_unbound.o \ rsrc_unbound_host.o rsrc_unbound_anchor.o rsrc_unbound_control.o \ rsrc_unbound_checkconf.o @@ -626,7 +626,8 @@ msgencode.lo msgencode.o: $(srcdir)/util/data/msgencode.c config.h $(srcdir)/uti $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/dname.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h \ - $(srcdir)/sldns/sbuffer.h + $(srcdir)/sldns/sbuffer.h $(srcdir)/services/localzone.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/module.h $(srcdir)/services/view.h msgparse.lo msgparse.o: $(srcdir)/util/data/msgparse.c config.h $(srcdir)/util/data/msgparse.h \ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/sldns/pkthdr.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \ @@ -636,7 +637,9 @@ msgreply.lo msgreply.o: $(srcdir)/util/data/msgreply.c config.h $(srcdir)/util/d $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h \ $(srcdir)/util/storage/lookup3.h $(srcdir)/util/alloc.h $(srcdir)/util/netevent.h $(srcdir)/util/net_help.h \ $(srcdir)/util/data/dname.h $(srcdir)/util/regional.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \ - $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgencode.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h + $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgencode.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/wire2str.h \ + $(srcdir)/util/module.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/services/mesh.h \ + $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h packed_rrset.lo packed_rrset.o: $(srcdir)/util/data/packed_rrset.c config.h \ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/alloc.h $(srcdir)/util/regional.h \ @@ -705,25 +708,33 @@ listen_dnsport.lo listen_dnsport.o: $(srcdir)/services/listen_dnsport.c config.h $(srcdir)/util/rbtree.h $(srcdir)/util/log.h $(srcdir)/util/config_file.h \ $(srcdir)/util/net_help.h $(srcdir)/sldns/sbuffer.h localzone.lo localzone.o: $(srcdir)/services/localzone.c config.h $(srcdir)/services/localzone.h \ - $(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h \ - $(srcdir)/sldns/sbuffer.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/data/dname.h \ - $(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgencode.h \ - $(srcdir)/util/net_help.h $(srcdir)/util/netevent.h $(srcdir)/util/data/msgreply.h \ - $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/util/as112.h + $(srcdir)/util/rbtree.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/storage/dnstree.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 $(srcdir)/sldns/sbuffer.h \ + $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/data/dname.h \ + $(srcdir)/util/data/msgencode.h $(srcdir)/util/net_help.h $(srcdir)/util/netevent.h $(srcdir)/util/as112.h mesh.lo mesh.o: $(srcdir)/services/mesh.c config.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/netevent.h $(srcdir)/util/data/msgparse.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \ $(srcdir)/util/log.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/module.h \ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(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)/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/storage/dnstree.h \ + $(srcdir)/services/view.h $(srcdir)/util/data/dname.h modstack.lo modstack.o: $(srcdir)/services/modstack.c config.h $(srcdir)/services/modstack.h \ $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h \ $(srcdir)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/dns64/dns64.h \ $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/validator/validator.h \ - $(srcdir)/validator/val_utils.h $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h + $(srcdir)/validator/val_utils.h $(PYTHONMOD_HEADER) +view.lo view.o: $(srcdir)/services/view.c config.h $(srcdir)/services/view.h $(srcdir)/util/rbtree.h \ + $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.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)/util/config_file.h outbound_list.lo outbound_list.o: $(srcdir)/services/outbound_list.c config.h \ $(srcdir)/services/outbound_list.h $(srcdir)/services/outside_network.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/netevent.h @@ -760,15 +771,15 @@ fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/ $(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)/services/modstack.h $(srcdir)/util/mini_event.h \ $(srcdir)/util/rbtree.h $(srcdir)/services/outside_network.h \ - $(srcdir)/services/localzone.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \ - $(srcdir)/util/rtt.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/dns64/dns64.h \ - $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h \ - $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_anchor.h \ - $(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h \ - $(srcdir)/validator/val_neg.h $(srcdir)/validator/autotrust.h $(srcdir)/libunbound/libworker.h \ - $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound.h \ - $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h \ - $(PYTHONMOD_HEADER) $(srcdir)/cachedb/cachedb.h + $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h $(srcdir)/services/view.h \ + $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/cache/rrset.h \ + $(srcdir)/util/storage/slabhash.h $(srcdir)/dns64/dns64.h $(srcdir)/iterator/iterator.h \ + $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/validator/validator.h \ + $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_anchor.h $(srcdir)/validator/val_nsec3.h \ + $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h $(srcdir)/validator/val_neg.h \ + $(srcdir)/validator/autotrust.h $(srcdir)/libunbound/libworker.h $(srcdir)/libunbound/context.h \ + $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \ + $(srcdir)/util/config_file.h $(PYTHONMOD_HEADER) locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ @@ -778,7 +789,7 @@ mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/ $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h module.lo module.o: $(srcdir)/util/module.c config.h $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h \ $(srcdir)/util/locks.h $(srcdir)/util/log.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/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/netevent.h $(srcdir)/util/ub_event.h \ $(srcdir)/util/log.h $(srcdir)/util/net_help.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/storage/lruhash.h \ $(srcdir)/util/locks.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \ @@ -902,14 +913,7 @@ 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)/util/tube.h $(srcdir)/services/mesh.h $(srcdir)/util/rbtree.h \ $(srcdir)/services/modstack.h $(srcdir)/util/net_help.h $(srcdir)/util/regional.h -cachedb.lo cachedb.o: $(srcdir)/cachedb/cachedb.c config.h $(srcdir)/cachedb/cachedb.h $(srcdir)/util/module.h \ - $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.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/regional.h $(srcdir)/util/net_help.h $(srcdir)/util/config_file.h \ - $(srcdir)/util/data/msgencode.h $(srcdir)/services/cache/dns.h $(srcdir)/validator/val_neg.h \ - $(srcdir)/util/rbtree.h $(srcdir)/validator/val_secalgo.h $(srcdir)/iterator/iter_utils.h \ - $(srcdir)/iterator/iter_resptype.h $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h \ - $(srcdir)/sldns/sbuffer.h +cachedb.lo cachedb.o: $(srcdir)/cachedb/cachedb.c config.h checklocks.lo checklocks.o: $(srcdir)/testcode/checklocks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/testcode/checklocks.h unitanchor.lo unitanchor.o: $(srcdir)/testcode/unitanchor.c config.h $(srcdir)/util/log.h $(srcdir)/util/data/dname.h \ @@ -956,8 +960,11 @@ testpkts.lo testpkts.o: $(srcdir)/testcode/testpkts.c config.h $(srcdir)/testcod unitldns.lo unitldns.o: $(srcdir)/testcode/unitldns.c config.h $(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h \ $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.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)/util/regional.h $(srcdir)/util/log.h \ - $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/locks.h \ + $(srcdir)/util/log.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.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)/sldns/str2wire.h cachedump.lo cachedump.o: $(srcdir)/daemon/cachedump.c config.h $(srcdir)/daemon/cachedump.h \ $(srcdir)/daemon/remote.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 \ @@ -977,10 +984,10 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \ $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \ $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \ - $(srcdir)/util/config_file.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)/util/random.h $(srcdir)/util/tube.h \ - $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h + $(srcdir)/services/view.h $(srcdir)/util/config_file.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)/util/random.h \ + $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \ $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \ @@ -991,12 +998,12 @@ remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/util/net_help.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \ $(srcdir)/util/rbtree.h $(srcdir)/util/rtt.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \ - $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/data/dname.h $(srcdir)/validator/validator.h \ - $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_kcache.h $(srcdir)/validator/val_kentry.h \ - $(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \ - $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/iterator/iter_delegpt.h \ - $(srcdir)/services/outside_network.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/parseutil.h \ - $(srcdir)/sldns/wire2str.h + $(srcdir)/services/view.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/data/dname.h \ + $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h $(srcdir)/validator/val_kcache.h \ + $(srcdir)/validator/val_kentry.h $(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h \ + $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \ + $(srcdir)/iterator/iter_delegpt.h $(srcdir)/services/outside_network.h $(srcdir)/sldns/str2wire.h \ + $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.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 \ @@ -1024,8 +1031,8 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \ $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/daemon.h \ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h \ - $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/regional.h \ - $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \ + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/config_file.h \ + $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \ $(srcdir)/services/outside_network.h $(srcdir)/services/outbound_list.h \ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \ $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \ @@ -1053,8 +1060,8 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \ $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h $(srcdir)/daemon/daemon.h \ $(srcdir)/services/modstack.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h \ - $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/regional.h \ - $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \ + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/config_file.h \ + $(srcdir)/util/regional.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/listen_dnsport.h \ $(srcdir)/services/outside_network.h $(srcdir)/services/outbound_list.h \ $(srcdir)/services/cache/rrset.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \ $(srcdir)/services/cache/dns.h $(srcdir)/services/mesh.h $(srcdir)/services/localzone.h \ @@ -1063,8 +1070,11 @@ worker.lo worker.o: $(srcdir)/daemon/worker.c config.h $(srcdir)/util/log.h $(sr $(srcdir)/validator/val_anchor.h $(srcdir)/libunbound/context.h $(srcdir)/libunbound/unbound.h \ $(srcdir)/libunbound/libworker.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)/util/regional.h $(srcdir)/util/log.h \ - $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h $(srcdir)/services/view.h $(srcdir)/util/locks.h \ + $(srcdir)/util/log.h $(srcdir)/util/regional.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.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)/sldns/str2wire.h daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h \ $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \ $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \ @@ -1072,10 +1082,10 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h \ $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/util/module.h $(srcdir)/dnstap/dnstap.h \ $(srcdir)/daemon/remote.h $(srcdir)/daemon/acl_list.h $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rbtree.h \ - $(srcdir)/util/config_file.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)/util/random.h $(srcdir)/util/tube.h \ - $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h + $(srcdir)/services/view.h $(srcdir)/util/config_file.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)/util/random.h \ + $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.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 \ @@ -1123,7 +1133,7 @@ unbound-checkconf.lo unbound-checkconf.o: $(srcdir)/smallapp/unbound-checkconf.c $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h $(srcdir)/iterator/iter_fwd.h \ $(srcdir)/util/rbtree.h $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h \ $(srcdir)/validator/validator.h $(srcdir)/validator/val_utils.h $(srcdir)/services/localzone.h \ - $(srcdir)/sldns/sbuffer.h $(PYTHONMOD_HEADER) + $(srcdir)/services/view.h $(srcdir)/sldns/sbuffer.h $(PYTHONMOD_HEADER) worker_cb.lo worker_cb.o: $(srcdir)/smallapp/worker_cb.c config.h $(srcdir)/libunbound/context.h \ $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \ $(srcdir)/libunbound/unbound.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \ @@ -1135,8 +1145,9 @@ context.lo context.o: $(srcdir)/libunbound/context.c config.h $(srcdir)/libunbou $(srcdir)/libunbound/unbound.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h \ $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/services/localzone.h \ - $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h \ - $(srcdir)/util/storage/dnstree.h $(srcdir)/util/rtt.h $(srcdir)/sldns/sbuffer.h + $(srcdir)/util/storage/dnstree.h $(srcdir)/services/view.h $(srcdir)/services/cache/rrset.h \ + $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \ + $(srcdir)/sldns/sbuffer.h libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbound/unbound.h \ $(srcdir)/libunbound/unbound-event.h config.h $(srcdir)/libunbound/context.h $(srcdir)/util/locks.h \ $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \ @@ -1144,9 +1155,9 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou $(srcdir)/util/config_file.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \ $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/regional.h \ $(srcdir)/util/random.h $(srcdir)/util/net_help.h $(srcdir)/util/tube.h $(srcdir)/util/ub_event.h \ - $(srcdir)/services/localzone.h $(srcdir)/services/cache/infra.h $(srcdir)/util/storage/dnstree.h \ - $(srcdir)/util/rtt.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \ - $(srcdir)/sldns/sbuffer.h + $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h $(srcdir)/services/view.h \ + $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/cache/rrset.h \ + $(srcdir)/util/storage/slabhash.h $(srcdir)/sldns/sbuffer.h libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/libunbound/libworker.h \ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \ @@ -1154,11 +1165,12 @@ libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/li $(srcdir)/libunbound/unbound-event.h $(srcdir)/services/outside_network.h $(srcdir)/util/netevent.h \ $(srcdir)/services/mesh.h $(srcdir)/util/data/msgparse.h \ $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/module.h $(srcdir)/util/data/msgreply.h \ - $(srcdir)/services/localzone.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \ - $(srcdir)/services/outbound_list.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h \ - $(srcdir)/util/random.h $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h \ + $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h $(srcdir)/services/view.h \ + $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h \ + $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \ + $(srcdir)/util/config_file.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h \ $(srcdir)/util/data/dname.h $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h \ - $(srcdir)/iterator/iter_hints.h $(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h + $(srcdir)/iterator/iter_hints.h $(srcdir)/sldns/str2wire.h unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \ @@ -1226,7 +1238,6 @@ snprintf.lo snprintf.o: $(srcdir)/compat/snprintf.c config.h strlcat.lo strlcat.o: $(srcdir)/compat/strlcat.c config.h strlcpy.lo strlcpy.o: $(srcdir)/compat/strlcpy.c config.h strptime.lo strptime.o: $(srcdir)/compat/strptime.c config.h -strsep.lo strsep.o: $(srcdir)/compat/strsep.c config.h getentropy_linux.lo getentropy_linux.o: $(srcdir)/compat/getentropy_linux.c config.h getentropy_osx.lo getentropy_osx.o: $(srcdir)/compat/getentropy_osx.c config.h getentropy_solaris.lo getentropy_solaris.o: $(srcdir)/compat/getentropy_solaris.c config.h @@ -1238,3 +1249,4 @@ arc4_lock.lo arc4_lock.o: $(srcdir)/compat/arc4_lock.c config.h $(srcdir)/util/l sha512.lo sha512.o: $(srcdir)/compat/sha512.c config.h reallocarray.lo reallocarray.o: $(srcdir)/compat/reallocarray.c config.h isblank.lo isblank.o: $(srcdir)/compat/isblank.c config.h +strsep.lo strsep.o: $(srcdir)/compat/strsep.c config.h diff --git a/usr.sbin/unbound/aclocal.m4 b/usr.sbin/unbound/aclocal.m4 index ea5d6e9f868..f21da5394f7 100644 --- a/usr.sbin/unbound/aclocal.m4 +++ b/usr.sbin/unbound/aclocal.m4 @@ -9044,3 +9044,329 @@ m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) +dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +dnl serial 11 (pkg-config-0.29.1) +dnl +dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. +dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + diff --git a/usr.sbin/unbound/acx_python.m4 b/usr.sbin/unbound/acx_python.m4 index 6fa925af168..4e83d7764bc 100644 --- a/usr.sbin/unbound/acx_python.m4 +++ b/usr.sbin/unbound/acx_python.m4 @@ -14,58 +14,11 @@ AC_DEFUN([AC_PYTHON_DEVEL],[ fi if test -z "$PYTHON_VERSION"; then - PYTHON_VERSION=`$PYTHON -c "import sys, string; \ - print string.split(sys.version)[[0]]"` + PYTHON_VERSION=`$PYTHON -c "import sys; \ + print(sys.version.split()[[0]])"` fi # - # Check for a version of Python >= 2.1.0 - # - AC_MSG_CHECKING([for a version of Python >= '2.1.0']) - ac_supports_python_ver=`$PYTHON -c "import sys, string; \ - ver = string.split(sys.version)[[0]]; \ - print ver >= '2.1.0'"` - if test "$ac_supports_python_ver" != "True"; then - if test -z "$PYTHON_NOVERSIONCHECK"; then - AC_MSG_RESULT([no]) - AC_MSG_FAILURE([ -This version of the AC@&t@_PYTHON_DEVEL macro -doesn't work properly with versions of Python before -2.1.0. You may need to re-run configure, setting the -variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG, -PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand. -Moreover, to disable this check, set PYTHON_NOVERSIONCHECK -to something else than an empty string. -]) - else - AC_MSG_RESULT([skip at user request]) - fi - else - AC_MSG_RESULT([yes]) - fi - - # - # if the macro parameter ``version'' is set, honour it - # - if test -n "$1"; then - AC_MSG_CHECKING([for a version of Python $1]) - ac_supports_python_ver=`$PYTHON -c "import sys, string; \ - ver = string.split(sys.version)[[0]]; \ - print ver $1"` - if test "$ac_supports_python_ver" = "True"; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - AC_MSG_ERROR([this package requires Python $1. -If you have it installed, but it isn't the default Python -interpreter in your system path, please pass the PYTHON_VERSION -variable to configure. See ``configure --help'' for reference. -]) - PYTHON_VERSION="" - fi - fi - - # # Check if you have distutils, else fail # AC_MSG_CHECKING([for the distutils Python package]) @@ -86,7 +39,7 @@ $ac_distutils_result]) AC_MSG_CHECKING([for Python include path]) if test -z "$PYTHON_CPPFLAGS"; then python_path=`$PYTHON -c "import distutils.sysconfig; \ - print distutils.sysconfig.get_python_inc();"` + print(distutils.sysconfig.get_python_inc());"` if test -n "${python_path}"; then python_path="-I$python_path" fi @@ -100,25 +53,8 @@ $ac_distutils_result]) # AC_MSG_CHECKING([for Python library path]) if test -z "$PYTHON_LDFLAGS"; then - # (makes two attempts to ensure we've got a version number - # from the interpreter) - py_version=`$PYTHON -c "from distutils.sysconfig import *; \ - from string import join; \ - print join(get_config_vars('VERSION'))"` - if test "$py_version" = "[None]"; then - if test -n "$PYTHON_VERSION"; then - py_version=$PYTHON_VERSION - else - py_version=`$PYTHON -c "import sys; \ - print sys.version[[:3]]"` - fi - fi - PYTHON_LDFLAGS=`$PYTHON -c "from distutils.sysconfig import *; \ - from string import join; \ - print '-L' + get_python_lib(0,1), \ - '-L' + os.path.dirname(get_python_lib(0,1)), \ - '-lpython';"`$py_version + print('-L'+get_config_var('LIBDIR')+' -L'+get_config_var('LIBDEST')+' '+get_config_var('BLDLIBRARY'));"` fi AC_MSG_RESULT([$PYTHON_LDFLAGS]) AC_SUBST([PYTHON_LDFLAGS]) @@ -129,43 +65,22 @@ $ac_distutils_result]) AC_MSG_CHECKING([for Python site-packages path]) if test -z "$PYTHON_SITE_PKG"; then PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \ - print distutils.sysconfig.get_python_lib(1,0);"` + print(distutils.sysconfig.get_python_lib(1,0));"` fi AC_MSG_RESULT([$PYTHON_SITE_PKG]) AC_SUBST([PYTHON_SITE_PKG]) # - # libraries which must be linked in when embedding - # - AC_MSG_CHECKING(python extra libraries) - if test -z "$PYTHON_EXTRA_LIBS"; then - PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \ - conf = distutils.sysconfig.get_config_var; \ - print conf('LOCALMODLIBS'), conf('LIBS')"` - fi - AC_MSG_RESULT([$PYTHON_EXTRA_LIBS]) - AC_SUBST(PYTHON_EXTRA_LIBS) - - # - # linking flags needed when embedding - # - AC_MSG_CHECKING(python extra linking flags) - if test -z "$PYTHON_EXTRA_LDFLAGS"; then - PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \ - conf = distutils.sysconfig.get_config_var; \ - print conf('LINKFORSHARED')"` - fi - AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS]) - AC_SUBST(PYTHON_EXTRA_LDFLAGS) - - # # final check to see if everything compiles alright # AC_MSG_CHECKING([consistency of all components of python development environment]) AC_LANG_PUSH([C]) # save current global flags - LIBS="$ac_save_LIBS $PYTHON_LDFLAGS" - CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS" + ac_save_LIBS="$LIBS" + ac_save_CPPFLAGS="$CPPFLAGS" + + LIBS="$LIBS $PYTHON_LDFLAGS" + CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" AC_TRY_LINK([ #include <Python.h> ],[ diff --git a/usr.sbin/unbound/cachedb/cachedb.c b/usr.sbin/unbound/cachedb/cachedb.c index 76d9afa47c8..a326d6ef8db 100644 --- a/usr.sbin/unbound/cachedb/cachedb.c +++ b/usr.sbin/unbound/cachedb/cachedb.c @@ -547,8 +547,8 @@ cachedb_handle_query(struct module_qstate* qstate, return; } - if(qstate->blacklist) { - /* cache is blacklisted */ + if(qstate->blacklist || qstate->no_cache_lookup) { + /* cache is blacklisted or we are instructed from edns to not look */ /* pass request to next module */ qstate->ext_state[id] = module_wait_module; return; @@ -556,10 +556,15 @@ cachedb_handle_query(struct module_qstate* qstate, /* lookup inside unbound's internal cache */ if(cachedb_intcache_lookup(qstate)) { - if(verbosity >= VERB_ALGO) - log_dns_msg("cachedb internal cache lookup", - &qstate->return_msg->qinfo, - qstate->return_msg->rep); + if(verbosity >= VERB_ALGO) { + if(qstate->return_msg->rep) + log_dns_msg("cachedb internal cache lookup", + &qstate->return_msg->qinfo, + qstate->return_msg->rep); + else log_info("cachedb internal cache lookup: rcode %s", + sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)? + sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name:"??"); + } /* we are done with the query */ qstate->ext_state[id] = module_finished; return; @@ -595,8 +600,8 @@ static void cachedb_handle_response(struct module_qstate* qstate, struct cachedb_qstate* ATTR_UNUSED(iq), struct cachedb_env* ie, int id) { - /* check if we are enabled, and skip if not */ - if(!ie->enabled) { + /* check if we are not enabled or instructed to not cache, and skip */ + if(!ie->enabled || qstate->no_cache_store) { /* we are done with the query */ qstate->ext_state[id] = module_finished; return; @@ -649,6 +654,11 @@ cachedb_operate(struct module_qstate* qstate, enum module_ev event, int id, (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return; } + if(!iq && (event == module_event_moddone)) { + /* during priming, module done but we never started */ + qstate->ext_state[id] = module_finished; + return; + } log_err("bad event for cachedb"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); diff --git a/usr.sbin/unbound/config.h.in b/usr.sbin/unbound/config.h.in index b982629ea4d..3a4f47b5ca7 100644 --- a/usr.sbin/unbound/config.h.in +++ b/usr.sbin/unbound/config.h.in @@ -51,6 +51,9 @@ /* Define to 1 if you have the `chroot' function. */ #undef HAVE_CHROOT +/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */ +#undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA + /* Define to 1 if you have the `ctime_r' function. */ #undef HAVE_CTIME_R @@ -65,6 +68,14 @@ if you don't. */ #undef HAVE_DECL_ARC4RANDOM_UNIFORM +/* Define to 1 if you have the declaration of `inet_ntop', and to 0 if you + don't. */ +#undef HAVE_DECL_INET_NTOP + +/* Define to 1 if you have the declaration of `inet_pton', and to 0 if you + don't. */ +#undef HAVE_DECL_INET_PTON + /* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you don't. */ #undef HAVE_DECL_NID_SECP384R1 @@ -104,15 +115,27 @@ /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H +/* Define to 1 if you have the `DSA_SIG_set0' function. */ +#undef HAVE_DSA_SIG_SET0 + /* Define to 1 if you have the <endian.h> header file. */ #undef HAVE_ENDIAN_H /* Define to 1 if you have the `endprotoent' function. */ #undef HAVE_ENDPROTOENT +/* Define to 1 if you have the `endpwent' function. */ +#undef HAVE_ENDPWENT + /* Define to 1 if you have the `endservent' function. */ #undef HAVE_ENDSERVENT +/* Define to 1 if you have the `ERR_free_strings' function. */ +#undef HAVE_ERR_FREE_STRINGS + +/* Define to 1 if you have the `ERR_load_crypto_strings' function. */ +#undef HAVE_ERR_LOAD_CRYPTO_STRINGS + /* Define to 1 if you have the `event_base_free' function. */ #undef HAVE_EVENT_BASE_FREE @@ -128,6 +151,12 @@ /* Define to 1 if you have the <event.h> header file. */ #undef HAVE_EVENT_H +/* Define to 1 if you have the `EVP_cleanup' function. */ +#undef HAVE_EVP_CLEANUP + +/* Define to 1 if you have the `EVP_dss1' function. */ +#undef HAVE_EVP_DSS1 + /* Define to 1 if you have the `EVP_MD_CTX_new' function. */ #undef HAVE_EVP_MD_CTX_NEW @@ -254,24 +283,48 @@ /* Use libnettle for crypto */ #undef HAVE_NETTLE +/* Define to 1 if you have the <nettle/dsa-compat.h> header file. */ +#undef HAVE_NETTLE_DSA_COMPAT_H + /* Use libnss for crypto */ #undef HAVE_NSS +/* Define to 1 if you have the `OpenSSL_add_all_digests' function. */ +#undef HAVE_OPENSSL_ADD_ALL_DIGESTS + +/* Define to 1 if you have the <openssl/bn.h> header file. */ +#undef HAVE_OPENSSL_BN_H + /* Define to 1 if you have the `OPENSSL_config' function. */ #undef HAVE_OPENSSL_CONFIG /* Define to 1 if you have the <openssl/conf.h> header file. */ #undef HAVE_OPENSSL_CONF_H +/* Define to 1 if you have the <openssl/dh.h> header file. */ +#undef HAVE_OPENSSL_DH_H + +/* Define to 1 if you have the <openssl/dsa.h> header file. */ +#undef HAVE_OPENSSL_DSA_H + /* Define to 1 if you have the <openssl/engine.h> header file. */ #undef HAVE_OPENSSL_ENGINE_H /* Define to 1 if you have the <openssl/err.h> header file. */ #undef HAVE_OPENSSL_ERR_H +/* Define to 1 if you have the `OPENSSL_init_crypto' function. */ +#undef HAVE_OPENSSL_INIT_CRYPTO + +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ +#undef HAVE_OPENSSL_INIT_SSL + /* Define to 1 if you have the <openssl/rand.h> header file. */ #undef HAVE_OPENSSL_RAND_H +/* Define to 1 if you have the <openssl/rsa.h> header file. */ +#undef HAVE_OPENSSL_RSA_H + /* Define to 1 if you have the <openssl/ssl.h> header file. */ #undef HAVE_OPENSSL_SSL_H @@ -296,15 +349,15 @@ /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM +/* Define to 1 if you have the `RAND_cleanup' function. */ +#undef HAVE_RAND_CLEANUP + /* Define to 1 if you have the `reallocarray' function. */ #undef HAVE_REALLOCARRAY /* Define to 1 if you have the `recvmsg' function. */ #undef HAVE_RECVMSG -/* define if you have the sbrk() call */ -#undef HAVE_SBRK - /* Define to 1 if you have the `sendmsg' function. */ #undef HAVE_SENDMSG @@ -353,6 +406,9 @@ /* Define if you have the SSL libraries installed. */ #undef HAVE_SSL +/* Define to 1 if you have the `SSL_CTX_set_security_level' function. */ +#undef HAVE_SSL_CTX_SET_SECURITY_LEVEL + /* Define to 1 if you have the <stdarg.h> header file. */ #undef HAVE_STDARG_H @@ -398,6 +454,9 @@ /* Define to 1 if you have the <syslog.h> header file. */ #undef HAVE_SYSLOG_H +/* Define to 1 if systemd should be used */ +#undef HAVE_SYSTEMD + /* Define to 1 if you have the <sys/param.h> header file. */ #undef HAVE_SYS_PARAM_H @@ -610,6 +669,12 @@ /* Define if you want to use internal select based events */ #undef USE_MINI_EVENT +/* Define this to enable client TCP Fast Open. */ +#undef USE_MSG_FASTOPEN + +/* Define this to enable client TCP Fast Open. */ +#undef USE_OSX_MSG_FASTOPEN + /* Define this to enable SHA256 and SHA512 support. */ #undef USE_SHA2 @@ -635,6 +700,9 @@ #endif +/* Define this to enable server TCP Fast Open. */ +#undef USE_TCP_FASTOPEN + /* Whether the windows socket API is used */ #undef USE_WINSOCK @@ -1004,6 +1072,14 @@ char *strsep(char **stringp, const char *delim); int isblank(int c); #endif +#if defined(HAVE_INET_NTOP) && !HAVE_DECL_INET_NTOP +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +#endif + +#if defined(HAVE_INET_PTON) && !HAVE_DECL_INET_PTON +int inet_pton(int af, const char* src, void* dst); +#endif + #if !defined(HAVE_STRPTIME) || !defined(STRPTIME_WORKS) #define strptime unbound_strptime struct tm; diff --git a/usr.sbin/unbound/configure b/usr.sbin/unbound/configure index 5b65237ddc2..231a09bb32b 100644 --- a/usr.sbin/unbound/configure +++ b/usr.sbin/unbound/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for unbound 1.5.9. +# Generated by GNU Autoconf 2.69 for unbound 1.6.1rc3. # # Report bugs to <unbound-bugs@nlnetlabs.nl>. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.5.9' -PACKAGE_STRING='unbound 1.5.9' +PACKAGE_VERSION='1.6.1rc3' +PACKAGE_STRING='unbound 1.6.1rc3' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -658,7 +658,17 @@ WIN_DAEMON_SRC WINAPPS WINDRES CHECKLOCK_OBJ +USE_SYSTEMD_FALSE +USE_SYSTEMD_TRUE +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 UNBOUND_EVENT_INSTALL SSLLIB @@ -678,6 +688,7 @@ WITH_PYTHONMODULE swig SWIG_LIB SWIG +PC_PY_DEPENDENCY PY_MAJOR_VERSION PYTHON_SITE_PKG PYTHON_LDFLAGS @@ -834,9 +845,12 @@ enable_gost enable_ecdsa enable_dsa enable_event_api +enable_tfo_client +enable_tfo_server with_libevent with_libexpat enable_static_exe +enable_systemd enable_lock_checks enable_allsymbols enable_dnstap @@ -858,7 +872,14 @@ CPP YACC YFLAGS LT_SYS_LIBRARY_PATH -PYTHON_VERSION' +PYTHON_VERSION +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +SYSTEMD_CFLAGS +SYSTEMD_LIBS +SYSTEMD_DAEMON_CFLAGS +SYSTEMD_DAEMON_LIBS' # Initialize some variables set by options. @@ -1399,7 +1420,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.5.9 to adapt to many kinds of systems. +\`configure' configures unbound 1.6.1rc3 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1464,7 +1485,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.5.9:";; + short | recursive ) echo "Configuration of unbound 1.6.1rc3:";; esac cat <<\_ACEOF @@ -1500,8 +1521,11 @@ Optional Features: --disable-dsa Disable DSA support --enable-event-api Enable (experimental) pluggable event base libunbound API installed to unbound-event.h + --enable-tfo-client Enable TCP Fast Open for client mode + --enable-tfo-server Enable TCP Fast Open for server mode --enable-static-exe enable to compile executables statically against (event) libs, for debug purposes + --enable-systemd compile with systemd support --enable-lock-checks enable to check lock and unlock calls, for debug purposes --enable-allsymbols export all symbols from libunbound and link binaries @@ -1585,6 +1609,19 @@ Some influential environment variables: The installed Python version to use, for example '2.3'. This string will be appended to the Python interpreter canonical name. + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + SYSTEMD_CFLAGS + C compiler flags for SYSTEMD, overriding pkg-config + SYSTEMD_LIBS + linker flags for SYSTEMD, overriding pkg-config + SYSTEMD_DAEMON_CFLAGS + C compiler flags for SYSTEMD_DAEMON, overriding pkg-config + SYSTEMD_DAEMON_LIBS + linker flags for SYSTEMD_DAEMON, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1652,7 +1689,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.5.9 +unbound configure 1.6.1rc3 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2361,7 +2398,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.5.9, which was +It was created by unbound $as_me 1.6.1rc3, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2711,13 +2748,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu UNBOUND_VERSION_MAJOR=1 -UNBOUND_VERSION_MINOR=5 +UNBOUND_VERSION_MINOR=6 -UNBOUND_VERSION_MICRO=9 +UNBOUND_VERSION_MICRO=1rc3 LIBUNBOUND_CURRENT=6 -LIBUNBOUND_REVISION=1 +LIBUNBOUND_REVISION=4 LIBUNBOUND_AGE=4 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -2766,6 +2803,9 @@ LIBUNBOUND_AGE=4 # 1.5.7 had 5:10:3 # 1.5.8 had 6:0:4 # adds ub_ctx_set_stub # 1.5.9 had 6:1:4 +# 1.5.10 had 6:2:4 +# 1.6.0 had 6:3:4 +# 1.6.1 had 7:0:5 # ub_callback_t typedef renamed to ub_callback_type # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -4054,7 +4094,7 @@ esac # are we on MinGW? if uname -s 2>&1 | grep MINGW32 >/dev/null; then on_mingw="yes" else - if echo $target | grep mingw32 >/dev/null; then on_mingw="yes" + if echo $host $target | grep mingw32 >/dev/null; then on_mingw="yes" else on_mingw="no"; fi fi @@ -4064,7 +4104,7 @@ fi if test $on_mingw = "no"; then ub_conf_file=`eval echo "${sysconfdir}/unbound/unbound.conf"` else - ub_conf_file="C:\\Program Files\\Unbound\\service.conf" + ub_conf_file="C:\\Program Files (x86)\\Unbound\\service.conf" fi # Check whether --with-conf_file was given. @@ -4195,7 +4235,7 @@ else if test $on_mingw = no; then UNBOUND_ROOTKEY_FILE="$UNBOUND_RUN_DIR/root.key" else - UNBOUND_ROOTKEY_FILE="C:\\Program Files\\Unbound\\root.key" + UNBOUND_ROOTKEY_FILE="C:\\Program Files (x86)\\Unbound\\root.key" fi fi @@ -4217,7 +4257,7 @@ else if test $on_mingw = no; then UNBOUND_ROOTCERT_FILE="$UNBOUND_RUN_DIR/icannbundle.pem" else - UNBOUND_ROOTCERT_FILE="C:\\Program Files\\Unbound\\icannbundle.pem" + UNBOUND_ROOTCERT_FILE="C:\\Program Files (x86)\\Unbound\\icannbundle.pem" fi fi @@ -16714,7 +16754,7 @@ $as_echo "$PYTHON_CPPFLAGS" >&6; } $as_echo_n "checking for Python library path... " >&6; } if test -z "$PYTHON_LDFLAGS"; then PYTHON_LDFLAGS=`$PYTHON -c "from distutils.sysconfig import *; \ - print(get_config_var('BLDLIBRARY'));"` + print('-L'+get_config_var('LIBDIR')+' -L'+get_config_var('LIBDEST')+' '+get_config_var('BLDLIBRARY'));"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_LDFLAGS" >&5 $as_echo "$PYTHON_LDFLAGS" >&6; } @@ -16818,6 +16858,8 @@ $as_echo "#define HAVE_PYTHON 1" >>confdefs.h LIBS="$PYTHON_LDFLAGS $LIBS" CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" ub_have_python=yes + PC_PY_DEPENDENCY="python" + # Check for SWIG ub_have_swig=no @@ -17033,6 +17075,19 @@ if test "${with_nettle+set}" = set; then : $as_echo "#define HAVE_NETTLE 1" >>confdefs.h + for ac_header in nettle/dsa-compat.h +do : + ac_fn_c_check_header_compile "$LINENO" "nettle/dsa-compat.h" "ac_cv_header_nettle_dsa_compat_h" "$ac_includes_default +" +if test "x$ac_cv_header_nettle_dsa_compat_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_NETTLE_DSA_COMPAT_H 1 +_ACEOF + +fi + +done + if test "$withval" != "" -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval/include/nettle" LDFLAGS="$LDFLAGS -L$withval/lib" @@ -17397,6 +17452,47 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext SSLLIB="-lssl" + +# check if -lcrypt32 is needed because CAPIENG needs that. (on windows) +BAKLIBS="$LIBS" +LIBS="-lssl $LIBS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libssl needs -lcrypt32" >&5 +$as_echo_n "checking if libssl needs -lcrypt32... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char HMAC_Update (); +int +main () +{ +return HMAC_Update (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + LIBS="$BAKLIBS" + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + LIBS="$BAKLIBS" + LIBS="$LIBS -lcrypt32" + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5 $as_echo_n "checking for LibreSSL... " >&6; } if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then @@ -17462,33 +17558,37 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi -for ac_header in openssl/conf.h +for ac_header in openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h do : - ac_fn_c_check_header_compile "$LINENO" "openssl/conf.h" "ac_cv_header_openssl_conf_h" "$ac_includes_default + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " -if test "x$ac_cv_header_openssl_conf_h" = xyes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_OPENSSL_CONF_H 1 +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done -for ac_header in openssl/engine.h +for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 do : - ac_fn_c_check_header_compile "$LINENO" "openssl/engine.h" "ac_cv_header_openssl_engine_h" "$ac_includes_default -" -if test "x$ac_cv_header_openssl_engine_h" = xyes; then : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_OPENSSL_ENGINE_H 1 +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi - done -for ac_func in OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new + +# these check_funcs need -lssl +BAKLIBS="$LIBS" +LIBS="-lssl $LIBS" +for ac_func in OPENSSL_init_ssl SSL_CTX_set_security_level do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -17500,6 +17600,8 @@ _ACEOF fi done +LIBS="$BAKLIBS" + ac_fn_c_check_decl "$LINENO" "SSL_COMP_get_compression_methods" "ac_cv_have_decl_SSL_COMP_get_compression_methods" " $ac_includes_default #ifdef HAVE_OPENSSL_ERR_H @@ -17861,13 +17963,13 @@ if test "${enable_dsa+set}" = set; then : fi use_dsa="no" -case "$enable_ecdsa" in +case "$enable_dsa" in no) ;; *) # detect if DSA is supported, and turn it off if not. - ac_fn_c_check_func "$LINENO" "EVP_dss1" "ac_cv_func_EVP_dss1" -if test "x$ac_cv_func_EVP_dss1" = xyes; then : + ac_fn_c_check_func "$LINENO" "DSA_SIG_new" "ac_cv_func_DSA_SIG_new" +if test "x$ac_cv_func_DSA_SIG_new" = xyes; then : cat >>confdefs.h <<_ACEOF @@ -17900,6 +18002,82 @@ case "$enable_event_api" in ;; esac +# Check whether --enable-tfo-client was given. +if test "${enable_tfo_client+set}" = set; then : + enableval=$enable_tfo_client; +fi + +case "$enable_tfo_client" in + yes) + case `uname` in + Linux) ac_fn_c_check_decl "$LINENO" "MSG_FASTOPEN" "ac_cv_have_decl_MSG_FASTOPEN" "$ac_includes_default +#include <netinet/tcp.h> + +" +if test "x$ac_cv_have_decl_MSG_FASTOPEN" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&5 +$as_echo "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&2;} +else + as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 +fi + + +cat >>confdefs.h <<_ACEOF +#define USE_MSG_FASTOPEN 1 +_ACEOF + + ;; + Darwin) ac_fn_c_check_decl "$LINENO" "CONNECT_RESUME_ON_READ_WRITE" "ac_cv_have_decl_CONNECT_RESUME_ON_READ_WRITE" "$ac_includes_default +#include <sys/socket.h> + +" +if test "x$ac_cv_have_decl_CONNECT_RESUME_ON_READ_WRITE" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&5 +$as_echo "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO" >&2;} +else + as_fn_error $? "TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client" "$LINENO" 5 +fi + + +cat >>confdefs.h <<_ACEOF +#define USE_OSX_MSG_FASTOPEN 1 +_ACEOF + + ;; + esac + ;; + no|*) + ;; +esac + +# Check whether --enable-tfo-server was given. +if test "${enable_tfo_server+set}" = set; then : + enableval=$enable_tfo_server; +fi + +case "$enable_tfo_server" in + yes) + ac_fn_c_check_decl "$LINENO" "TCP_FASTOPEN" "ac_cv_have_decl_TCP_FASTOPEN" "$ac_includes_default +#include <netinet/tcp.h> + +" +if test "x$ac_cv_have_decl_TCP_FASTOPEN" = xyes; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO" >&5 +$as_echo "$as_me: WARNING: Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO" >&2;} +else + as_fn_error $? "TCP Fast Open is not available for server mode: please rerun without --enable-tfo-server" "$LINENO" 5 +fi + + +cat >>confdefs.h <<_ACEOF +#define USE_TCP_FASTOPEN 1 +_ACEOF + + ;; + no|*) + ;; +esac + # check for libevent # Check whether --with-libevent was given. @@ -18238,6 +18416,8 @@ _ACEOF fi done # only in libev. (tested on 4.00) + PC_LIBEVENT_DEPENDENCY="libevent" + if test -n "$BAK_LDFLAGS_SET"; then LDFLAGS="$BAK_LDFLAGS" fi @@ -18314,12 +18494,321 @@ if test x_$enable_static_exe = x_yes; then staticexe="-static" if test "$on_mingw" = yes; then staticexe="-all-static" - # for static crosscompile, include gdi32 and zlib here. - if test "`uname`" = "Linux"; then - LIBS="$LIBS -lgdi32 -lz" - fi + # for static compile, include gdi32 and zlib here. + LIBS="$LIBS -lgdi32 -lz" + fi +fi + +# Include systemd.m4 - begin +# macros for configuring systemd +# Copyright 2015, Sami Kerola, CloudFlare. +# BSD licensed. +# Check whether --enable-systemd was given. +if test "${enable_systemd+set}" = set; then : + enableval=$enable_systemd; +else + enable_systemd=no +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 : + + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5 +$as_echo_n "checking for SYSTEMD... " >&6; } + +if test -n "$SYSTEMD_CFLAGS"; then + pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SYSTEMD_LIBS"; then + pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "libsystemd" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd" 2>&1` + else + SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SYSTEMD_PKG_ERRORS" >&5 + + have_systemd=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_systemd=no +else + SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS + SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_systemd=yes +fi + if test "x$have_systemd" != "xyes"; then : + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD_DAEMON" >&5 +$as_echo_n "checking for SYSTEMD_DAEMON... " >&6; } + +if test -n "$SYSTEMD_DAEMON_CFLAGS"; then + pkg_cv_SYSTEMD_DAEMON_CFLAGS="$SYSTEMD_DAEMON_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd-daemon\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd-daemon") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_DAEMON_CFLAGS=`$PKG_CONFIG --cflags "libsystemd-daemon" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SYSTEMD_DAEMON_LIBS"; then + pkg_cv_SYSTEMD_DAEMON_LIBS="$SYSTEMD_DAEMON_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsystemd-daemon\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libsystemd-daemon") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SYSTEMD_DAEMON_LIBS=`$PKG_CONFIG --libs "libsystemd-daemon" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SYSTEMD_DAEMON_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsystemd-daemon" 2>&1` + else + SYSTEMD_DAEMON_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsystemd-daemon" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SYSTEMD_DAEMON_PKG_ERRORS" >&5 + + have_systemd_daemon=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + have_systemd_daemon=no +else + SYSTEMD_DAEMON_CFLAGS=$pkg_cv_SYSTEMD_DAEMON_CFLAGS + SYSTEMD_DAEMON_LIBS=$pkg_cv_SYSTEMD_DAEMON_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + have_systemd_daemon=yes +fi + if test "x$have_systemd_daemon" = "xyes"; then : + have_systemd=yes +fi + +fi + case $enable_systemd:$have_systemd in #( + yes:no) : + as_fn_error $? "systemd enabled but libsystemd not found" "$LINENO" 5 ;; #( + *:yes) : + +$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h + + LIBS="$LIBS $SYSTEMD_LIBS" + + ;; #( + *) : + ;; +esac + + +fi + if test "x$have_systemd" = xyes; then + USE_SYSTEMD_TRUE= + USE_SYSTEMD_FALSE='#' +else + USE_SYSTEMD_TRUE='#' + USE_SYSTEMD_FALSE= +fi + + +# Include systemd.m4 - end # set lock checking if requested # Check whether --enable-lock_checks was given. @@ -18762,7 +19251,7 @@ if test "$ac_res" != no; then : fi -for ac_func in tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync +for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -18821,39 +19310,77 @@ fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sbrk" >&5 -$as_echo_n "checking for sbrk... " >&6; } -# catch the warning of deprecated sbrk -old_cflags="$CFLAGS" -CFLAGS="$CFLAGS -Werror" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default +# check if setreuid en setregid fail, on MacOSX10.4(darwin8). +if echo $build_os | grep darwin8 > /dev/null; then -int main(void) { void* cur = sbrk(0); printf("%u\n", (unsigned)(size_t)((char*)cur - (char*)sbrk(0))); return 0; } +$as_echo "#define DARWIN_BROKEN_SETREUID 1" >>confdefs.h -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +fi +ac_fn_c_check_decl "$LINENO" "inet_pton" "ac_cv_have_decl_inet_pton" " +$ac_includes_default +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif -$as_echo "#define HAVE_SBRK 1" >>confdefs.h +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +" +if test "x$ac_cv_have_decl_inet_pton" = xyes; then : + ac_have_decl=1 else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + ac_have_decl=0 fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -CFLAGS="$old_cflags" -# check if setreuid en setregid fail, on MacOSX10.4(darwin8). -if echo $build_os | grep darwin8 > /dev/null; then +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_INET_PTON $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "inet_ntop" "ac_cv_have_decl_inet_ntop" " +$ac_includes_default +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif -$as_echo "#define DARWIN_BROKEN_SETREUID 1" >>confdefs.h +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +" +if test "x$ac_cv_have_decl_inet_ntop" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_INET_NTOP $ac_have_decl +_ACEOF + ac_fn_c_check_func "$LINENO" "inet_aton" "ac_cv_func_inet_aton" if test "x$ac_cv_func_inet_aton" = xyes; then : $as_echo "#define HAVE_INET_ATON 1" >>confdefs.h @@ -19098,8 +19625,8 @@ else esac else - case `uname` in - Darwin) + case "$host" in + Darwin|*darwin*) case " $LIBOBJS " in *" getentropy_osx.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getentropy_osx.$ac_objext" @@ -19107,7 +19634,7 @@ esac esac ;; - SunOS) + *solaris*|*sunos*|SunOS) case " $LIBOBJS " in *" getentropy_solaris.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getentropy_solaris.$ac_objext" @@ -19211,7 +19738,7 @@ if test "$ac_res" != no; then : fi ;; - Linux|*) + *linux*|Linux|*) case " $LIBOBJS " in *" getentropy_linux.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS getentropy_linux.$ac_objext" @@ -19801,7 +20328,7 @@ _ACEOF -version=1.5.9 +version=1.6.1rc3 date=`date +'%b %e, %Y'` @@ -19919,6 +20446,10 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs +if test -z "${USE_SYSTEMD_TRUE}" && test -z "${USE_SYSTEMD_FALSE}"; then + as_fn_error $? "conditional \"USE_SYSTEMD\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -20316,7 +20847,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.5.9, which was +This file was extended by unbound $as_me 1.6.1rc3, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -20382,7 +20913,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -unbound config.status 1.5.9 +unbound config.status 1.6.1rc3 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 37e3993e6f9..324fde3af59 100644 --- a/usr.sbin/unbound/configure.ac +++ b/usr.sbin/unbound/configure.ac @@ -9,15 +9,15 @@ sinclude(dnstap/dnstap.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) -m4_define([VERSION_MINOR],[5]) -m4_define([VERSION_MICRO],[9]) +m4_define([VERSION_MINOR],[6]) +m4_define([VERSION_MICRO],[1rc3]) 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=6 -LIBUNBOUND_REVISION=1 +LIBUNBOUND_REVISION=4 LIBUNBOUND_AGE=4 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -66,6 +66,9 @@ LIBUNBOUND_AGE=4 # 1.5.7 had 5:10:3 # 1.5.8 had 6:0:4 # adds ub_ctx_set_stub # 1.5.9 had 6:1:4 +# 1.5.10 had 6:2:4 +# 1.6.0 had 6:3:4 +# 1.6.1 had 7:0:5 # ub_callback_t typedef renamed to ub_callback_type # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -107,7 +110,7 @@ esac # are we on MinGW? if uname -s 2>&1 | grep MINGW32 >/dev/null; then on_mingw="yes" else - if echo $target | grep mingw32 >/dev/null; then on_mingw="yes" + if echo $host $target | grep mingw32 >/dev/null; then on_mingw="yes" else on_mingw="no"; fi fi @@ -117,7 +120,7 @@ fi if test $on_mingw = "no"; then ub_conf_file=`eval echo "${sysconfdir}/unbound/unbound.conf"` else - ub_conf_file="C:\\Program Files\\Unbound\\service.conf" + ub_conf_file="C:\\Program Files (x86)\\Unbound\\service.conf" fi AC_ARG_WITH([conf_file], AC_HELP_STRING([--with-conf-file=path], @@ -187,7 +190,7 @@ AC_ARG_WITH(rootkey-file, if test $on_mingw = no; then UNBOUND_ROOTKEY_FILE="$UNBOUND_RUN_DIR/root.key" else - UNBOUND_ROOTKEY_FILE="C:\\Program Files\\Unbound\\root.key" + UNBOUND_ROOTKEY_FILE="C:\\Program Files (x86)\\Unbound\\root.key" fi ) AC_SUBST(UNBOUND_ROOTKEY_FILE) @@ -201,7 +204,7 @@ AC_ARG_WITH(rootcert-file, if test $on_mingw = no; then UNBOUND_ROOTCERT_FILE="$UNBOUND_RUN_DIR/icannbundle.pem" else - UNBOUND_ROOTCERT_FILE="C:\\Program Files\\Unbound\\icannbundle.pem" + UNBOUND_ROOTCERT_FILE="C:\\Program Files (x86)\\Unbound\\icannbundle.pem" fi ) AC_SUBST(UNBOUND_ROOTCERT_FILE) @@ -542,6 +545,8 @@ if test x_$ub_test_python != x_no; then LIBS="$PYTHON_LDFLAGS $LIBS" CPPFLAGS="$CPPFLAGS $PYTHON_CPPFLAGS" ub_have_python=yes + PC_PY_DEPENDENCY="python" + AC_SUBST(PC_PY_DEPENDENCY) # Check for SWIG ub_have_swig=no @@ -629,6 +634,7 @@ AC_ARG_WITH([nettle], AC_HELP_STRING([--with-nettle=path], [ USE_NETTLE="yes" AC_DEFINE(HAVE_NETTLE, 1, [Use libnettle for crypto]) + AC_CHECK_HEADERS([nettle/dsa-compat.h],,, [AC_INCLUDES_DEFAULT]) if test "$withval" != "" -a "$withval" != "yes"; then CPPFLAGS="$CPPFLAGS -I$withval/include/nettle" LDFLAGS="$LDFLAGS -L$withval/lib" @@ -646,6 +652,20 @@ if test $USE_NSS = "no" -a $USE_NETTLE = "no"; then ACX_WITH_SSL ACX_LIB_SSL SSLLIB="-lssl" + +# check if -lcrypt32 is needed because CAPIENG needs that. (on windows) +BAKLIBS="$LIBS" +LIBS="-lssl $LIBS" +AC_MSG_CHECKING([if libssl needs -lcrypt32]) +AC_TRY_LINK_FUNC([HMAC_Update], [ + AC_MSG_RESULT([no]) + LIBS="$BAKLIBS" +], [ + AC_MSG_RESULT([yes]) + LIBS="$BAKLIBS" + LIBS="$LIBS -lcrypt32" +]) + AC_MSG_CHECKING([for LibreSSL]) if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then AC_MSG_RESULT([yes]) @@ -656,9 +676,15 @@ if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/ else AC_MSG_RESULT([no]) fi -AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new]) +AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h],,, [AC_INCLUDES_DEFAULT]) +AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1]) + +# these check_funcs need -lssl +BAKLIBS="$LIBS" +LIBS="-lssl $LIBS" +AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level]) +LIBS="$BAKLIBS" + AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H @@ -842,12 +868,12 @@ esac AC_ARG_ENABLE(dsa, AC_HELP_STRING([--disable-dsa], [Disable DSA support])) use_dsa="no" -case "$enable_ecdsa" in +case "$enable_dsa" in no) ;; *) # detect if DSA is supported, and turn it off if not. - AC_CHECK_FUNC(EVP_dss1, [ + AC_CHECK_FUNC(DSA_SIG_new, [ AC_DEFINE_UNQUOTED([USE_DSA], [1], [Define this to enable DSA support.]) ], [if test "x$enable_dsa" = "xyes"; then AC_MSG_ERROR([OpenSSL does not support DSA and you used --enable-dsa.]) fi ]) @@ -865,6 +891,42 @@ case "$enable_event_api" in ;; esac +AC_ARG_ENABLE(tfo-client, AC_HELP_STRING([--enable-tfo-client], [Enable TCP Fast Open for client mode])) +case "$enable_tfo_client" in + yes) + case `uname` in + Linux) AC_CHECK_DECL([MSG_FASTOPEN], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO])], + [AC_MSG_ERROR([TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client])], + [AC_INCLUDES_DEFAULT +#include <netinet/tcp.h> +]) + AC_DEFINE_UNQUOTED([USE_MSG_FASTOPEN], [1], [Define this to enable client TCP Fast Open.]) + ;; + Darwin) AC_CHECK_DECL([CONNECT_RESUME_ON_READ_WRITE], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support client mode TFO])], + [AC_MSG_ERROR([TCP Fast Open is not available for client mode: please rerun without --enable-tfo-client])], + [AC_INCLUDES_DEFAULT +#include <sys/socket.h> +]) + AC_DEFINE_UNQUOTED([USE_OSX_MSG_FASTOPEN], [1], [Define this to enable client TCP Fast Open.]) + ;; + esac + ;; + no|*) + ;; +esac + +AC_ARG_ENABLE(tfo-server, AC_HELP_STRING([--enable-tfo-server], [Enable TCP Fast Open for server mode])) +case "$enable_tfo_server" in + yes) + AC_CHECK_DECL([TCP_FASTOPEN], [AC_MSG_WARN([Check the platform specific TFO kernel parameters are correctly configured to support server mode TFO])], [AC_MSG_ERROR([TCP Fast Open is not available for server mode: please rerun without --enable-tfo-server])], [AC_INCLUDES_DEFAULT +#include <netinet/tcp.h> + ]) + AC_DEFINE_UNQUOTED([USE_TCP_FASTOPEN], [1], [Define this to enable server TCP Fast Open.]) + ;; + no|*) + ;; +esac + # check for libevent AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=pathname], [use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr or you can specify an explicit path). Slower, but allows use of large outgoing port ranges.]), @@ -942,6 +1004,8 @@ large outgoing port ranges. ]) AC_CHECK_FUNCS([event_base_get_method]) # only in libevent 1.4.3 and later AC_CHECK_FUNCS([ev_loop]) # only in libev. (tested on 3.51) AC_CHECK_FUNCS([ev_default_loop]) # only in libev. (tested on 4.00) + PC_LIBEVENT_DEPENDENCY="libevent" + AC_SUBST(PC_LIBEVENT_DEPENDENCY) if test -n "$BAK_LDFLAGS_SET"; then LDFLAGS="$BAK_LDFLAGS" fi @@ -985,13 +1049,15 @@ if test x_$enable_static_exe = x_yes; then staticexe="-static" if test "$on_mingw" = yes; then staticexe="-all-static" - # for static crosscompile, include gdi32 and zlib here. - if test "`uname`" = "Linux"; then - LIBS="$LIBS -lgdi32 -lz" - fi + # for static compile, include gdi32 and zlib here. + LIBS="$LIBS -lgdi32 -lz" fi fi +# Include systemd.m4 - begin +sinclude(systemd.m4) +# Include systemd.m4 - end + # set lock checking if requested AC_ARG_ENABLE(lock_checks, AC_HELP_STRING([--enable-lock-checks], [ enable to check lock and unlock calls, for debug purposes ]), @@ -1082,27 +1148,36 @@ AC_INCLUDES_DEFAULT #endif ]) AC_SEARCH_LIBS([setusercontext], [util]) -AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync]) +AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync]) AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])]) AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])]) -AC_MSG_CHECKING([for sbrk]) -# catch the warning of deprecated sbrk -old_cflags="$CFLAGS" -CFLAGS="$CFLAGS -Werror" -AC_COMPILE_IFELSE([AC_LANG_SOURCE(AC_INCLUDES_DEFAULT -[[ -int main(void) { void* cur = sbrk(0); printf("%u\n", (unsigned)(size_t)((char*)cur - (char*)sbrk(0))); return 0; } -]])], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_SBRK, 1, [define if you have the sbrk() call]) - ], [AC_MSG_RESULT(no)]) -CFLAGS="$old_cflags" - # check if setreuid en setregid fail, on MacOSX10.4(darwin8). if echo $build_os | grep darwin8 > /dev/null; then AC_DEFINE(DARWIN_BROKEN_SETREUID, 1, [Define this if on macOSX10.4-darwin8 and setreuid and setregid do not work]) fi +AC_CHECK_DECLS([inet_pton,inet_ntop], [], [], [ +AC_INCLUDES_DEFAULT +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif +]) AC_REPLACE_FUNCS(inet_aton) AC_REPLACE_FUNCS(inet_pton) AC_REPLACE_FUNCS(inet_ntop) @@ -1140,11 +1215,11 @@ if test "$USE_NSS" = "no"; then if test "$USE_WINSOCK" = 1; then AC_LIBOBJ(getentropy_win) else - case `uname` in - Darwin) + case "$host" in + Darwin|*darwin*) AC_LIBOBJ(getentropy_osx) ;; - SunOS) + *solaris*|*sunos*|SunOS) AC_LIBOBJ(getentropy_solaris) AC_CHECK_HEADERS([sys/sha2.h],, [ AC_CHECK_FUNCS([SHA512_Update],,[ @@ -1157,7 +1232,7 @@ if test "$USE_NSS" = "no"; then fi AC_SEARCH_LIBS([clock_gettime], [rt]) ;; - Linux|*) + *linux*|Linux|*) AC_LIBOBJ(getentropy_linux) AC_CHECK_FUNCS([SHA512_Update],,[ AC_DEFINE([COMPAT_SHA512], [1], [Do sha512 definitions in config.h]) @@ -1415,6 +1490,14 @@ char *strsep(char **stringp, const char *delim); int isblank(int c); #endif +#if defined(HAVE_INET_NTOP) && !HAVE_DECL_INET_NTOP +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +#endif + +#if defined(HAVE_INET_PTON) && !HAVE_DECL_INET_PTON +int inet_pton(int af, const char* src, void* dst); +#endif + #if !defined(HAVE_STRPTIME) || !defined(STRPTIME_WORKS) #define strptime unbound_strptime struct tm; diff --git a/usr.sbin/unbound/daemon/acl_list.c b/usr.sbin/unbound/daemon/acl_list.c index 48c8e0fe4db..f7d71b9fddb 100644 --- a/usr.sbin/unbound/daemon/acl_list.c +++ b/usr.sbin/unbound/daemon/acl_list.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -45,6 +45,8 @@ #include "util/log.h" #include "util/config_file.h" #include "util/net_help.h" +#include "services/localzone.h" +#include "sldns/str2wire.h" struct acl_list* acl_list_create(void) @@ -71,21 +73,21 @@ acl_list_delete(struct acl_list* acl) } /** insert new address into acl_list structure */ -static int +static struct acl_addr* acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr, socklen_t addrlen, int net, enum acl_access control, int complain_duplicates) { - struct acl_addr* node = regional_alloc(acl->region, + struct acl_addr* node = regional_alloc_zero(acl->region, sizeof(struct acl_addr)); if(!node) - return 0; + return NULL; node->control = control; if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) { if(complain_duplicates) verbose(VERB_QUERY, "duplicate acl address ignored."); } - return 1; + return node; } /** apply acl_list string */ @@ -103,6 +105,10 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2, control = acl_deny; else if(strcmp(s2, "refuse") == 0) control = acl_refuse; + else if(strcmp(s2, "deny_non_local") == 0) + control = acl_deny_non_local; + else if(strcmp(s2, "refuse_non_local") == 0) + control = acl_refuse_non_local; else if(strcmp(s2, "allow_snoop") == 0) control = acl_allow_snoop; else { @@ -121,6 +127,205 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2, return 1; } +/** find or create node (NULL on parse or error) */ +static struct acl_addr* +acl_find_or_create(struct acl_list* acl, const char* str) +{ + struct acl_addr* node; + struct sockaddr_storage addr; + int net; + socklen_t addrlen; + if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) { + log_err("cannot parse netblock: %s", str); + return NULL; + } + /* find or create node */ + if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr, + addrlen, net))) { + /* create node, type 'allow' since otherwise tags are + * pointless, can override with specific access-control: cfg */ + if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr, + addrlen, net, acl_allow, 1))) { + log_err("out of memory"); + return NULL; + } + } + return node; +} + +/** apply acl_tag string */ +static int +acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap, + size_t bitmaplen) +{ + struct acl_addr* node; + if(!(node=acl_find_or_create(acl, str))) + return 0; + node->taglen = bitmaplen; + node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen); + if(!node->taglist) { + log_err("out of memory"); + return 0; + } + return 1; +} + +/** apply acl_view string */ +static int +acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2, + struct views* vs) +{ + struct acl_addr* node; + if(!(node=acl_find_or_create(acl, str))) + return 0; + node->view = views_find_view(vs, str2, 0 /* get read lock*/); + if(!node->view) { + log_err("no view with name: %s", str2); + return 0; + } + lock_rw_unlock(&node->view->lock); + return 1; +} + +/** apply acl_tag_action string */ +static int +acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg, + const char* str, const char* tag, const char* action) +{ + struct acl_addr* node; + int tagid; + enum localzone_type t; + if(!(node=acl_find_or_create(acl, str))) + return 0; + /* allocate array if not yet */ + if(!node->tag_actions) { + node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region, + sizeof(*node->tag_actions)*cfg->num_tags); + if(!node->tag_actions) { + log_err("out of memory"); + return 0; + } + node->tag_actions_size = (size_t)cfg->num_tags; + } + /* parse tag */ + if((tagid=find_tag_id(cfg, tag)) == -1) { + log_err("cannot parse tag (define-tag it): %s %s", str, tag); + return 0; + } + if((size_t)tagid >= node->tag_actions_size) { + log_err("tagid too large for array %s %s", str, tag); + return 0; + } + if(!local_zone_str2type(action, &t)) { + log_err("cannot parse access control action type: %s %s %s", + str, tag, action); + return 0; + } + node->tag_actions[tagid] = (uint8_t)t; + return 1; +} + +/** check wire data parse */ +static int +check_data(const char* data, const struct config_strlist* head) +{ + char buf[65536]; + uint8_t rr[LDNS_RR_BUF_SIZE]; + size_t len = sizeof(rr); + int res; + /* '.' is sufficient for validation, and it makes the call to + * sldns_wirerr_get_type() simpler below. */ + snprintf(buf, sizeof(buf), "%s %s", ".", data); + res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0, + NULL, 0); + + /* Reject it if we would end up having CNAME and other data (including + * another CNAME) for the same tag. */ + if(res == 0 && head) { + const char* err_data = NULL; + + if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) { + /* adding CNAME while other data already exists. */ + err_data = data; + } else { + snprintf(buf, sizeof(buf), "%s %s", ".", head->str); + len = sizeof(rr); + res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, + NULL, 0, NULL, 0); + if(res != 0) { + /* This should be impossible here as head->str + * has been validated, but we check it just in + * case. */ + return 0; + } + if(sldns_wirerr_get_type(rr, len, 1) == + LDNS_RR_TYPE_CNAME) /* already have CNAME */ + err_data = head->str; + } + if(err_data) { + log_err("redirect tag data '%s' must not coexist with " + "other data.", err_data); + return 0; + } + } + if(res == 0) + return 1; + log_err("rr data [char %d] parse error %s", + (int)LDNS_WIREPARSE_OFFSET(res)-13, + sldns_get_errorstr_parse(res)); + return 0; +} + +/** apply acl_tag_data string */ +static int +acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg, + const char* str, const char* tag, const char* data) +{ + struct acl_addr* node; + int tagid; + char* dupdata; + if(!(node=acl_find_or_create(acl, str))) + return 0; + /* allocate array if not yet */ + if(!node->tag_datas) { + node->tag_datas = (struct config_strlist**)regional_alloc_zero( + acl->region, sizeof(*node->tag_datas)*cfg->num_tags); + if(!node->tag_datas) { + log_err("out of memory"); + return 0; + } + node->tag_datas_size = (size_t)cfg->num_tags; + } + /* parse tag */ + if((tagid=find_tag_id(cfg, tag)) == -1) { + log_err("cannot parse tag (define-tag it): %s %s", str, tag); + return 0; + } + if((size_t)tagid >= node->tag_datas_size) { + log_err("tagid too large for array %s %s", str, tag); + return 0; + } + + /* check data? */ + if(!check_data(data, node->tag_datas[tagid])) { + log_err("cannot parse access-control-tag data: %s %s '%s'", + str, tag, data); + return 0; + } + + dupdata = regional_strdup(acl->region, data); + if(!dupdata) { + log_err("out of memory"); + return 0; + } + if(!cfg_region_strlist_insert(acl->region, + &(node->tag_datas[tagid]), dupdata)) { + log_err("out of memory"); + return 0; + } + return 1; +} + /** read acl_list config */ static int read_acl_list(struct acl_list* acl, struct config_file* cfg) @@ -134,13 +339,114 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg) return 1; } +/** read acl tags config */ +static int +read_acl_tags(struct acl_list* acl, struct config_file* cfg) +{ + struct config_strbytelist* np, *p = cfg->acl_tags; + cfg->acl_tags = NULL; + while(p) { + log_assert(p->str && p->str2); + if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len)) { + config_del_strbytelist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p); + p = np; + } + return 1; +} + +/** read acl view config */ +static int +read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v) +{ + struct config_str2list* np, *p = cfg->acl_view; + cfg->acl_view = NULL; + while(p) { + log_assert(p->str && p->str2); + if(!acl_list_view_cfg(acl, p->str, p->str2, v)) { + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p); + p = np; + } + return 1; +} + +/** read acl tag actions config */ +static int +read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg) +{ + struct config_str3list* p, *np; + p = cfg->acl_tag_actions; + cfg->acl_tag_actions = NULL; + while(p) { + log_assert(p->str && p->str2 && p->str3); + if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2, + p->str3)) { + config_deltrplstrlist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p->str3); + free(p); + p = np; + } + return 1; +} + +/** read acl tag datas config */ +static int +read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg) +{ + struct config_str3list* p, *np; + p = cfg->acl_tag_datas; + cfg->acl_tag_datas = NULL; + while(p) { + log_assert(p->str && p->str2 && p->str3); + if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3)) { + config_deltrplstrlist(p); + return 0; + } + /* free the items as we go to free up memory */ + np = p->next; + free(p->str); + free(p->str2); + free(p->str3); + free(p); + p = np; + } + return 1; +} + int -acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg) +acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg, + struct views* v) { regional_free_all(acl->region); addr_tree_init(&acl->tree); if(!read_acl_list(acl, cfg)) return 0; + if(!read_acl_view(acl, cfg, v)) + return 0; + if(!read_acl_tags(acl, cfg)) + return 0; + if(!read_acl_tag_actions(acl, cfg)) + return 0; + if(!read_acl_tag_datas(acl, cfg)) + return 0; /* insert defaults, with '0' to ignore them if they are duplicates */ if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0)) return 0; @@ -159,13 +465,18 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg) } enum acl_access -acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr, +acl_get_control(struct acl_addr* acl) +{ + if(acl) return acl->control; + return acl_deny; +} + +struct acl_addr* +acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr, socklen_t addrlen) { - struct acl_addr* r = (struct acl_addr*)addr_tree_lookup(&acl->tree, + return (struct acl_addr*)addr_tree_lookup(&acl->tree, addr, addrlen); - if(r) return r->control; - return acl_deny; } size_t diff --git a/usr.sbin/unbound/daemon/acl_list.h b/usr.sbin/unbound/daemon/acl_list.h index 03ac301bf32..d0d42bfaebf 100644 --- a/usr.sbin/unbound/daemon/acl_list.h +++ b/usr.sbin/unbound/daemon/acl_list.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -43,6 +43,7 @@ #ifndef DAEMON_ACL_LIST_H #define DAEMON_ACL_LIST_H #include "util/storage/dnstree.h" +#include "services/view.h" struct config_file; struct regional; @@ -55,6 +56,10 @@ enum acl_access { acl_deny = 0, /** disallow access, send a polite 'REFUSED' reply */ acl_refuse, + /** disallow any access to zones that aren't local, drop it */ + acl_deny_non_local, + /** disallow access to zones that aren't local, 'REFUSED' reply */ + acl_refuse_non_local, /** allow full access for recursion (+RD) queries */ acl_allow, /** allow full access for all queries, recursion and cache snooping */ @@ -71,7 +76,7 @@ struct acl_list { * Tree of the addresses that are allowed/blocked. * contents of type acl_addr. */ - rbtree_t tree; + rbtree_type tree; }; /** @@ -83,6 +88,21 @@ struct acl_addr { struct addr_tree_node node; /** access control on this netblock */ enum acl_access control; + /** tag bitlist */ + uint8_t* taglist; + /** length of the taglist (in bytes) */ + size_t taglen; + /** array per tagnumber of localzonetype(in one byte). NULL if none. */ + uint8_t* tag_actions; + /** size of the tag_actions_array */ + size_t tag_actions_size; + /** array per tagnumber, with per tag a list of rdata strings. + * NULL if none. strings are like 'A 127.0.0.1' 'AAAA ::1' */ + struct config_strlist** tag_datas; + /** size of the tag_datas array */ + size_t tag_datas_size; + /* view element, NULL if none */ + struct view* view; }; /** @@ -101,19 +121,29 @@ void acl_list_delete(struct acl_list* acl); * Process access control config. * @param acl: where to store. * @param cfg: config options. + * @param v: views structure * @return 0 on error. */ -int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg); +int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg, + struct views* v); /** - * Lookup address to see its access control status. + * Lookup access control status for acl structure. + * @param acl: structure for acl storage. + * @return: what to do with message from this address. + */ +enum acl_access acl_get_control(struct acl_addr* acl); + +/** + * Lookup address to see its acl structure * @param acl: structure for address storage. * @param addr: address to check * @param addrlen: length of addr. - * @return: what to do with message from this address. + * @return: acl structure from this address. */ -enum acl_access acl_list_lookup(struct acl_list* acl, - struct sockaddr_storage* addr, socklen_t addrlen); +struct acl_addr* +acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr, + socklen_t addrlen); /** * Get memory used by acl structure. diff --git a/usr.sbin/unbound/daemon/cachedump.c b/usr.sbin/unbound/daemon/cachedump.c index 4b0a583a654..8992e6cb8f3 100644 --- a/usr.sbin/unbound/daemon/cachedump.c +++ b/usr.sbin/unbound/daemon/cachedump.c @@ -563,6 +563,7 @@ load_qinfo(char* str, struct query_info* qinfo, struct regional* region) qinfo->qclass = sldns_wirerr_get_class(rr, rr_len, dname_len); qinfo->qname_len = dname_len; qinfo->qname = (uint8_t*)regional_alloc_init(region, rr, dname_len); + qinfo->local_alias = NULL; if(!qinfo->qname) { log_warn("error out of memory"); return NULL; @@ -826,6 +827,7 @@ int print_deleg_lookup(SSL* ssl, struct worker* worker, uint8_t* nm, qinfo.qname_len = nmlen; qinfo.qtype = LDNS_RR_TYPE_A; qinfo.qclass = LDNS_RR_CLASS_IN; + qinfo.local_alias = NULL; dname_str(nm, b); if(!ssl_printf(ssl, "The following name servers are used for lookup " diff --git a/usr.sbin/unbound/daemon/daemon.c b/usr.sbin/unbound/daemon/daemon.c index 1036fcde200..4cae4380065 100644 --- a/usr.sbin/unbound/daemon/daemon.c +++ b/usr.sbin/unbound/daemon/daemon.c @@ -79,6 +79,7 @@ #include "services/cache/rrset.h" #include "services/cache/infra.h" #include "services/localzone.h" +#include "services/view.h" #include "services/modstack.h" #include "util/module.h" #include "util/random.h" @@ -87,6 +88,10 @@ #include "sldns/keyraw.h" #include <signal.h> +#ifdef HAVE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif + /** How many quit requests happened. */ static int sig_record_quit = 0; /** How many reload requests happened. */ @@ -174,8 +179,15 @@ static void signal_handling_playback(struct worker* wrk) { #ifdef SIGHUP - if(sig_record_reload) + if(sig_record_reload) { +# ifdef HAVE_SYSTEMD + sd_notify(0, "RELOADING=1"); +# endif worker_sighandler(SIGHUP, wrk); +# ifdef HAVE_SYSTEMD + sd_notify(0, "READY=1"); +# endif + } #endif if(sig_record_quit) worker_sighandler(SIGTERM, wrk); @@ -204,17 +216,29 @@ daemon_init(void) signal_handling_record(); checklock_start(); #ifdef HAVE_SSL +# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); +# endif ERR_load_SSL_strings(); # ifdef USE_GOST (void)sldns_key_EVP_load_gost_id(); # endif +# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); +# else + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS + | OPENSSL_INIT_ADD_ALL_DIGESTS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); +# endif # if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS /* grab the COMP method ptr because openssl leaks it */ comp_meth = (void*)SSL_COMP_get_compression_methods(); # endif +# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); +# else + (void)OPENSSL_init_ssl(0, NULL); +# endif # if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) if(!ub_openssl_lock_init()) fatal_exit("could not init openssl locks"); @@ -236,9 +260,16 @@ daemon_init(void) free(daemon); return NULL; } + /* init edns_known_options */ + if(!edns_known_options_init(daemon->env)) { + free(daemon->env); + free(daemon); + return NULL; + } alloc_init(&daemon->superalloc, NULL, 0); daemon->acl = acl_list_create(); if(!daemon->acl) { + edns_known_options_delete(daemon->env); free(daemon->env); free(daemon); return NULL; @@ -335,6 +366,7 @@ static void daemon_setup_modules(struct daemon* daemon) daemon->env)) { fatal_exit("failed to setup modules"); } + log_edns_known_options(VERB_ALGO, daemon->env); } /** @@ -404,6 +436,8 @@ daemon_create_workers(struct daemon* daemon) } daemon->workers = (struct worker**)calloc((size_t)daemon->num, sizeof(struct worker*)); + if(!daemon->workers) + fatal_exit("out of memory during daemon init"); if(daemon->cfg->dnstap) { #ifdef USE_DNSTAP daemon->dtenv = dt_create(daemon->cfg->dnstap_socket_path, @@ -528,8 +562,15 @@ void daemon_fork(struct daemon* daemon) { log_assert(daemon); - if(!acl_list_apply_cfg(daemon->acl, daemon->cfg)) + if(!(daemon->views = views_create())) + fatal_exit("Could not create views: out of memory"); + /* create individual views and their localzone/data trees */ + if(!views_apply_cfg(daemon->views, daemon->cfg)) + fatal_exit("Could not set up views"); + + if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views)) fatal_exit("Could not setup access control list"); + /* create global local_zones */ if(!(daemon->local_zones = local_zones_create())) fatal_exit("Could not create local zones: out of memory"); if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg)) @@ -565,8 +606,14 @@ daemon_fork(struct daemon* daemon) signal_handling_playback(daemon->workers[0]); /* Start resolver service on main thread. */ +#ifdef HAVE_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"); +#endif log_info("service stopped (%s).", PACKAGE_STRING); /* we exited! a signal happened! Stop other threads */ @@ -586,13 +633,14 @@ daemon_cleanup(struct daemon* daemon) log_thread_set(NULL); /* clean up caches because * a) RRset IDs will be recycled after a reload, causing collisions - * b) validation config can change, thus rrset, msg, keycache clear - * The infra cache is kept, the timing and edns info is still valid */ + * b) validation config can change, thus rrset, msg, keycache clear */ slabhash_clear(&daemon->env->rrset_cache->table); slabhash_clear(daemon->env->msg_cache); local_zones_delete(daemon->local_zones); daemon->local_zones = NULL; - /* key cache is cleared by module desetup during next daemon_init() */ + views_delete(daemon->views); + daemon->views = NULL; + /* key cache is cleared by module desetup during next daemon_fork() */ daemon_remote_clear(daemon->rc); for(i=0; i<daemon->num; i++) worker_delete(daemon->workers[i]); @@ -621,6 +669,8 @@ daemon_delete(struct daemon* daemon) slabhash_delete(daemon->env->msg_cache); rrset_cache_delete(daemon->env->rrset_cache); infra_delete(daemon->env->infra_cache); + edns_known_options_delete(daemon->env); + inplace_cb_lists_delete(daemon->env); } ub_randfree(daemon->rand); alloc_clear(&daemon->superalloc); @@ -656,8 +706,12 @@ daemon_delete(struct daemon* daemon) # endif CONF_modules_free(); # endif +# ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */ +# endif +# ifdef HAVE_ERR_FREE_STRINGS ERR_free_strings(); +# endif # if OPENSSL_VERSION_NUMBER < 0x10100000 RAND_cleanup(); # endif diff --git a/usr.sbin/unbound/daemon/daemon.h b/usr.sbin/unbound/daemon/daemon.h index 48c0b4f78a0..9177c0fd6bc 100644 --- a/usr.sbin/unbound/daemon/daemon.h +++ b/usr.sbin/unbound/daemon/daemon.h @@ -53,6 +53,7 @@ struct module_env; struct rrset_cache; struct acl_list; struct local_zones; +struct views; struct ub_randstate; struct daemon_remote; @@ -111,6 +112,8 @@ struct daemon { struct timeval time_last_stat; /** time when daemon started */ struct timeval time_boot; + /** views structure containing view tree */ + struct views* views; #ifdef USE_DNSTAP /** the dnstap environment master value, copied and changed by threads*/ struct dt_env* dtenv; diff --git a/usr.sbin/unbound/daemon/remote.c b/usr.sbin/unbound/daemon/remote.c index 7690ee8b187..681c57906a5 100644 --- a/usr.sbin/unbound/daemon/remote.c +++ b/usr.sbin/unbound/daemon/remote.c @@ -46,9 +46,12 @@ #ifdef HAVE_OPENSSL_ERR_H #include <openssl/err.h> #endif -#ifndef HEADER_DH_H +#ifdef HAVE_OPENSSL_DH_H #include <openssl/dh.h> #endif +#ifdef HAVE_OPENSSL_BN_H +#include <openssl/bn.h> +#endif #include <ctype.h> #include "daemon/remote.h" @@ -143,8 +146,9 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) * the command : "openssl dhparam -C 2048" * (some openssl versions reject DH that is 'too small', eg. 512). */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) #ifndef S_SPLINT_S -DH *get_dh2048() +static DH *get_dh2048(void) { static unsigned char dh2048_p[]={ 0xE7,0x36,0x28,0x3B,0xE4,0xC3,0x32,0x1C,0x01,0xC3,0x67,0xD6, @@ -173,16 +177,34 @@ DH *get_dh2048() static unsigned char dh2048_g[]={ 0x02, }; - DH *dh; - - if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL); - dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - { DH_free(dh); return(NULL); } - return(dh); + DH *dh = NULL; + BIGNUM *p = NULL, *g = NULL; + + dh = DH_new(); + p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL); + g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL); + if (!dh || !p || !g) + goto err; + +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) + dh->p = p; + dh->g = g; +#else + if (!DH_set0_pqg(dh, p, NULL, g)) + goto err; +#endif + return dh; +err: + if (p) + BN_free(p); + if (g) + BN_free(g); + if (dh) + DH_free(dh); + return NULL; } #endif /* SPLINT */ +#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */ struct daemon_remote* daemon_remote_create(struct config_file* cfg) @@ -223,18 +245,27 @@ daemon_remote_create(struct config_file* cfg) if (cfg->remote_control_use_cert == 0) { /* No certificates are requested */ - if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) { +#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL + SSL_CTX_set_security_level(rc->ctx, 0); +#endif + if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL, eNULL")) { log_crypto_err("Failed to set aNULL cipher list"); + daemon_remote_delete(rc); return NULL; } + /* in openssl 1.1, the securitylevel 0 allows eNULL, that + * does not need the DH */ +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) /* Since we have no certificates and hence no source of * DH params, let's generate and set them */ if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh2048())) { log_crypto_err("Wanted to set DH param, but failed"); + daemon_remote_delete(rc); return NULL; } +#endif return rc; } rc->use_cert = 1; @@ -350,7 +381,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if(ip[0] == '/') { /* This looks like a local socket */ - fd = create_local_accept_sock(ip, &noproto); + fd = create_local_accept_sock(ip, &noproto, cfg->use_systemd); /* * Change socket ownership and permissions so users other * than root can access it provided they are in the same @@ -359,8 +390,12 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, if(fd != -1) { #ifdef HAVE_CHOWN if (cfg->username && cfg->username[0] && - cfg_uid != (uid_t)-1) - chown(ip, cfg_uid, cfg_gid); + cfg_uid != (uid_t)-1) { + if(chown(ip, cfg_uid, cfg_gid) == -1) + log_err("cannot chown %u.%u %s: %s", + (unsigned)cfg_uid, (unsigned)cfg_gid, + ip, strerror(errno)); + } chmod(ip, (mode_t)(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); #else (void)cfg; @@ -389,7 +424,7 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err, /* open fd */ fd = create_tcp_accept_sock(res, 1, &noproto, 0, - cfg->ip_transparent, 0, cfg->ip_freebind); + cfg->ip_transparent, 0, cfg->ip_freebind, cfg->use_systemd); freeaddrinfo(res); } @@ -727,6 +762,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s) struct timeval avg; if(!ssl_printf(ssl, "%s.num.queries"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries)) return 0; + if(!ssl_printf(ssl, "%s.num.queries_ip_ratelimited"SQ"%lu\n", nm, + (unsigned long)s->svr.num_queries_ip_ratelimited)) return 0; if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm, (unsigned long)(s->svr.num_queries - s->svr.num_queries_missed_cache))) return 0; @@ -734,6 +771,8 @@ print_stats(SSL* ssl, const char* nm, struct stats_info* s) (unsigned long)s->svr.num_queries_missed_cache)) return 0; if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%lu\n", nm, (unsigned long)s->svr.num_queries_prefetch)) return 0; + if(!ssl_printf(ssl, "%s.num.zero_ttl"SQ"%lu\n", nm, + (unsigned long)s->svr.zero_ttl_responses)) return 0; if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%lu\n", nm, (unsigned long)s->mesh_replies_sent)) return 0; if(!ssl_printf(ssl, "%s.requestlist.avg"SQ"%g\n", nm, @@ -792,12 +831,6 @@ print_mem(SSL* ssl, struct worker* worker, struct daemon* daemon) { int m; size_t msg, rrset, val, iter; -#ifdef HAVE_SBRK - extern void* unbound_start_brk; - void* cur = sbrk(0); - if(!print_longnum(ssl, "mem.total.sbrk"SQ, - (size_t)((char*)cur - (char*)unbound_start_brk))) return 0; -#endif /* HAVE_SBRK */ msg = slabhash_get_mem(daemon->env->msg_cache); rrset = slabhash_get_mem(&daemon->env->rrset_cache->table); val=0; @@ -1097,8 +1130,8 @@ find_arg2(SSL* ssl, char* arg, char** arg2) } /** Add a new zone */ -static void -do_zone_add(SSL* ssl, struct worker* worker, char* arg) +static int +perform_zone_add(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; @@ -1107,83 +1140,266 @@ do_zone_add(SSL* ssl, struct worker* worker, char* arg) enum localzone_type t; struct local_zone* z; if(!find_arg2(ssl, arg, &arg2)) - return; + return 0; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; + return 0; if(!local_zone_str2type(arg2, &t)) { ssl_printf(ssl, "error not a zone type. %s\n", arg2); free(nm); - return; + return 0; } - lock_rw_wrlock(&worker->daemon->local_zones->lock); - if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, + lock_rw_wrlock(&zones->lock); + if((z=local_zones_find(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* already present in tree */ lock_rw_wrlock(&z->lock); z->type = t; /* update type anyway */ lock_rw_unlock(&z->lock); free(nm); - lock_rw_unlock(&worker->daemon->local_zones->lock); - send_ok(ssl); - return; + lock_rw_unlock(&zones->lock); + return 1; } - if(!local_zones_add_zone(worker->daemon->local_zones, nm, nmlen, + if(!local_zones_add_zone(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN, t)) { - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); ssl_printf(ssl, "error out of memory\n"); - return; + return 0; } - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); + return 1; +} + +/** Do the local_zone command */ +static void +do_zone_add(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_zone_add(ssl, zones, arg)) + return; send_ok(ssl); } -/** Remove a zone */ +/** Do the local_zones command */ static void -do_zone_remove(SSL* ssl, struct worker* worker, char* arg) +do_zones_add(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_zone_add(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "added %d zones\n", num); +} + +/** Remove a zone */ +static int +perform_zone_remove(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; size_t nmlen; struct local_zone* z; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - lock_rw_wrlock(&worker->daemon->local_zones->lock); - if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, + return 0; + lock_rw_wrlock(&zones->lock); + if((z=local_zones_find(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* present in tree */ - local_zones_del_zone(worker->daemon->local_zones, z); + local_zones_del_zone(zones, z); } - lock_rw_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&zones->lock); free(nm); + return 1; +} + +/** Do the local_zone_remove command */ +static void +do_zone_remove(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_zone_remove(ssl, zones, arg)) + return; send_ok(ssl); } -/** Add new RR data */ +/** Do the local_zones_remove command */ static void -do_data_add(SSL* ssl, struct worker* worker, char* arg) +do_zones_remove(SSL* ssl, struct local_zones* zones) { - if(!local_zones_add_RR(worker->daemon->local_zones, arg)) { + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_zone_remove(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "removed %d zones\n", num); +} + +/** Add new RR data */ +static int +perform_data_add(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!local_zones_add_RR(zones, arg)) { ssl_printf(ssl,"error in syntax or out of memory, %s\n", arg); - return; + return 0; } + return 1; +} + +/** Do the local_data command */ +static void +do_data_add(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_data_add(ssl, zones, arg)) + return; send_ok(ssl); } -/** Remove RR data */ +/** Do the local_datas command */ static void -do_data_remove(SSL* ssl, struct worker* worker, char* arg) +do_datas_add(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_data_add(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "added %d datas\n", num); +} + +/** Remove RR data */ +static int +perform_data_remove(SSL* ssl, struct local_zones* zones, char* arg) { uint8_t* nm; int nmlabs; size_t nmlen; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) - return; - local_zones_del_data(worker->daemon->local_zones, nm, + return 0; + local_zones_del_data(zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN); free(nm); + return 1; +} + +/** Do the local_data_remove command */ +static void +do_data_remove(SSL* ssl, struct local_zones* zones, char* arg) +{ + if(!perform_data_remove(ssl, zones, arg)) + return; send_ok(ssl); } +/** Do the local_datas_remove command */ +static void +do_datas_remove(SSL* ssl, struct local_zones* zones) +{ + char buf[2048]; + int num = 0; + while(ssl_read_line(ssl, buf, sizeof(buf))) { + if(buf[0] == 0x04 && buf[1] == 0) + break; /* end of transmission */ + if(!perform_data_remove(ssl, zones, buf)) { + if(!ssl_printf(ssl, "error for input line: %s\n", buf)) + return; + } + else + num++; + } + (void)ssl_printf(ssl, "removed %d datas\n", num); +} + +/** Add a new zone to view */ +static void +do_view_zone_add(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_zone_add(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Remove a zone from view */ +static void +do_view_zone_remove(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_zone_remove(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Add new RR data to view */ +static void +do_view_data_add(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_data_add(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + +/** Remove RR data from view */ +static void +do_view_data_remove(SSL* ssl, struct worker* worker, char* arg) +{ + char* arg2; + struct view* v; + if(!find_arg2(ssl, arg, &arg2)) + return; + v = views_find_view(worker->daemon->views, + arg, 1 /* get write lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_data_remove(ssl, v->local_zones, arg2); + lock_rw_unlock(&v->lock); +} + /** cache lookup of nameservers */ static void do_lookup(SSL* ssl, struct worker* worker, char* arg) @@ -1202,7 +1418,7 @@ static void do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, uint16_t t, uint16_t c) { - hashvalue_t h; + hashvalue_type h; struct query_info k; rrset_cache_remove(worker->env.rrset_cache, nm, nmlen, t, c, 0); if(t == LDNS_RR_TYPE_SOA) @@ -1212,6 +1428,7 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen, k.qname_len = nmlen; k.qtype = t; k.qclass = c; + k.local_alias = NULL; h = query_info_hash(&k, 0); slabhash_remove(worker->env.msg_cache, h, &k); if(t == LDNS_RR_TYPE_AAAA) { @@ -2157,6 +2374,14 @@ do_set_option(SSL* ssl, struct worker* worker, char* arg) (void)ssl_printf(ssl, "error setting option\n"); return; } + /* effectuate some arguments */ + if(strcmp(arg, "val-override-date:") == 0) { + int m = modstack_find(&worker->env.mesh->mods, "validator"); + struct val_env* val_env = NULL; + if(m != -1) val_env = (struct val_env*)worker->env.modinfo[m]; + if(val_env) + val_env->date_override = worker->env.cfg->val_date_override; + } send_ok(ssl); } @@ -2237,9 +2462,8 @@ do_list_stubs(SSL* ssl, struct worker* worker) /** do the list_local_zones command */ static void -do_list_local_zones(SSL* ssl, struct worker* worker) +do_list_local_zones(SSL* ssl, struct local_zones* zones) { - struct local_zones* zones = worker->daemon->local_zones; struct local_zone* z; char buf[257]; lock_rw_rdlock(&zones->lock); @@ -2260,9 +2484,8 @@ do_list_local_zones(SSL* ssl, struct worker* worker) /** do the list_local_data command */ static void -do_list_local_data(SSL* ssl, struct worker* worker) +do_list_local_data(SSL* ssl, struct worker* worker, struct local_zones* zones) { - struct local_zones* zones = worker->daemon->local_zones; struct local_zone* z; struct local_data* d; struct local_rrset* p; @@ -2298,6 +2521,34 @@ do_list_local_data(SSL* ssl, struct worker* worker) lock_rw_unlock(&zones->lock); } +/** do the view_list_local_zones command */ +static void +do_view_list_local_zones(SSL* ssl, struct worker* worker, char* arg) +{ + struct view* v = views_find_view(worker->daemon->views, + arg, 0 /* get read lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_list_local_zones(ssl, v->local_zones); + lock_rw_unlock(&v->lock); +} + +/** do the view_list_local_data command */ +static void +do_view_list_local_data(SSL* ssl, struct worker* worker, char* arg) +{ + struct view* v = views_find_view(worker->daemon->views, + arg, 0 /* get read lock*/); + if(!v) { + ssl_printf(ssl,"no view with name: %s\n", arg); + return; + } + do_list_local_data(ssl, worker, v->local_zones); + lock_rw_unlock(&v->lock); +} + /** struct for user arg ratelimit list */ struct ratelimit_list_arg { /** the infra cache */ @@ -2310,6 +2561,8 @@ struct ratelimit_list_arg { time_t now; }; +#define ip_ratelimit_list_arg ratelimit_list_arg + /** list items in the ratelimit table */ static void rate_list(struct lruhash_entry* e, void* arg) @@ -2328,6 +2581,24 @@ rate_list(struct lruhash_entry* e, void* arg) ssl_printf(a->ssl, "%s %d limit %d\n", buf, max, lim); } +/** list items in the ip_ratelimit table */ +static void +ip_rate_list(struct lruhash_entry* e, void* arg) +{ + char ip[128]; + struct ip_ratelimit_list_arg* a = (struct ip_ratelimit_list_arg*)arg; + struct ip_rate_key* k = (struct ip_rate_key*)e->key; + struct ip_rate_data* d = (struct ip_rate_data*)e->data; + int lim = infra_ip_ratelimit; + int max = infra_rate_max(d, a->now); + if(a->all == 0) { + if(max < lim) + return; + } + addr_to_str(&k->addr, k->addrlen, ip, sizeof(ip)); + ssl_printf(a->ssl, "%s %d limit %d\n", ip, max, lim); +} + /** do the ratelimit_list command */ static void do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) @@ -2346,6 +2617,24 @@ do_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) slabhash_traverse(a.infra->domain_rates, 0, rate_list, &a); } +/** do the ip_ratelimit_list command */ +static void +do_ip_ratelimit_list(SSL* ssl, struct worker* worker, char* arg) +{ + struct ip_ratelimit_list_arg a; + a.all = 0; + a.infra = worker->env.infra_cache; + a.now = *worker->env.now; + a.ssl = ssl; + arg = skipwhite(arg); + if(strcmp(arg, "+a") == 0) + a.all = 1; + if(a.infra->client_ip_rates==NULL || + (a.all == 0 && infra_ip_ratelimit == 0)) + return; + slabhash_traverse(a.infra->client_ip_rates, 0, ip_rate_list, &a); +} + /** tell other processes to execute the command */ static void distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) @@ -2410,14 +2699,23 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, do_insecure_list(ssl, worker); return; } else if(cmdcmp(p, "list_local_zones", 16)) { - do_list_local_zones(ssl, worker); + do_list_local_zones(ssl, worker->daemon->local_zones); return; } else if(cmdcmp(p, "list_local_data", 15)) { - do_list_local_data(ssl, worker); + do_list_local_data(ssl, worker, worker->daemon->local_zones); + return; + } else if(cmdcmp(p, "view_list_local_zones", 21)) { + do_view_list_local_zones(ssl, worker, skipwhite(p+21)); + return; + } else if(cmdcmp(p, "view_list_local_data", 20)) { + do_view_list_local_data(ssl, worker, skipwhite(p+20)); return; } else if(cmdcmp(p, "ratelimit_list", 14)) { do_ratelimit_list(ssl, worker, p+14); return; + } else if(cmdcmp(p, "ip_ratelimit_list", 17)) { + do_ip_ratelimit_list(ssl, worker, p+17); + return; } else if(cmdcmp(p, "stub_add", 8)) { /* must always distribute this cmd */ if(rc) distribute_cmd(rc, ssl, cmd); @@ -2479,13 +2777,29 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, if(cmdcmp(p, "verbosity", 9)) { do_verbosity(ssl, skipwhite(p+9)); } else if(cmdcmp(p, "local_zone_remove", 17)) { - do_zone_remove(ssl, worker, skipwhite(p+17)); + do_zone_remove(ssl, worker->daemon->local_zones, skipwhite(p+17)); + } else if(cmdcmp(p, "local_zones_remove", 18)) { + do_zones_remove(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_zone", 10)) { - do_zone_add(ssl, worker, skipwhite(p+10)); + do_zone_add(ssl, worker->daemon->local_zones, skipwhite(p+10)); + } else if(cmdcmp(p, "local_zones", 11)) { + do_zones_add(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_data_remove", 17)) { - do_data_remove(ssl, worker, skipwhite(p+17)); + do_data_remove(ssl, worker->daemon->local_zones, skipwhite(p+17)); + } else if(cmdcmp(p, "local_datas_remove", 18)) { + do_datas_remove(ssl, worker->daemon->local_zones); } else if(cmdcmp(p, "local_data", 10)) { - do_data_add(ssl, worker, skipwhite(p+10)); + do_data_add(ssl, worker->daemon->local_zones, skipwhite(p+10)); + } else if(cmdcmp(p, "local_datas", 11)) { + do_datas_add(ssl, worker->daemon->local_zones); + } else if(cmdcmp(p, "view_local_zone_remove", 22)) { + do_view_zone_remove(ssl, worker, skipwhite(p+22)); + } else if(cmdcmp(p, "view_local_zone", 15)) { + do_view_zone_add(ssl, worker, skipwhite(p+15)); + } else if(cmdcmp(p, "view_local_data_remove", 22)) { + do_view_data_remove(ssl, worker, skipwhite(p+22)); + } else if(cmdcmp(p, "view_local_data", 15)) { + do_view_data_add(ssl, worker, skipwhite(p+15)); } else if(cmdcmp(p, "flush_zone", 10)) { do_flush_zone(ssl, worker, skipwhite(p+10)); } else if(cmdcmp(p, "flush_type", 10)) { diff --git a/usr.sbin/unbound/daemon/remote.h b/usr.sbin/unbound/daemon/remote.h index b25bfb1af61..190286d474a 100644 --- a/usr.sbin/unbound/daemon/remote.h +++ b/usr.sbin/unbound/daemon/remote.h @@ -56,8 +56,8 @@ struct comm_reply; struct comm_point; struct daemon_remote; -/** number of seconds timeout on incoming remote control handshake */ -#define REMOTE_CONTROL_TCP_TIMEOUT 120 +/** number of milliseconds timeout on incoming remote control handshake */ +#define REMOTE_CONTROL_TCP_TIMEOUT 120000 /** * a busy control command connection, SSL state diff --git a/usr.sbin/unbound/daemon/stats.c b/usr.sbin/unbound/daemon/stats.c index 9a1a7d2617e..a3c3d738976 100644 --- a/usr.sbin/unbound/daemon/stats.c +++ b/usr.sbin/unbound/daemon/stats.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -40,17 +40,26 @@ * numbers. These 'statistics' may be of interest to the operator. */ #include "config.h" -#include <ldns/wire2host.h> +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#include <sys/time.h> +#include <sys/types.h> #include "daemon/stats.h" #include "daemon/worker.h" #include "daemon/daemon.h" #include "services/mesh.h" #include "services/outside_network.h" +#include "services/listen_dnsport.h" #include "util/config_file.h" #include "util/tube.h" #include "util/timehist.h" #include "util/net_help.h" #include "validator/validator.h" +#include "sldns/sbuffer.h" +#include "services/cache/rrset.h" +#include "services/cache/infra.h" +#include "validator/val_kcache.h" /** add timers and the values do not overflow or become negative */ static void @@ -93,12 +102,14 @@ void server_stats_log(struct server_stats* stats, struct worker* worker, int threadnum) { log_info("server stats for thread %d: %u queries, " - "%u answers from cache, %u recursions, %u prefetch", + "%u answers from cache, %u recursions, %u prefetch, %u rejected by " + "ip ratelimiting", threadnum, (unsigned)stats->num_queries, (unsigned)(stats->num_queries - stats->num_queries_missed_cache), (unsigned)stats->num_queries_missed_cache, - (unsigned)stats->num_queries_prefetch); + (unsigned)stats->num_queries_prefetch, + (unsigned)stats->num_queries_ip_ratelimited); log_info("server stats for thread %d: requestlist max %u avg %g " "exceeded %u jostled %u", threadnum, (unsigned)stats->max_query_list_size, @@ -132,6 +143,7 @@ void server_stats_compile(struct worker* worker, struct stats_info* s, int reset) { int i; + struct listen_list* lp; s->svr = worker->stats; s->mesh_num_states = worker->env.mesh->all.count; @@ -153,10 +165,26 @@ server_stats_compile(struct worker* worker, struct stats_info* s, int reset) NUM_BUCKETS_HIST); /* values from outside network */ s->svr.unwanted_replies = worker->back->unwanted_replies; + s->svr.qtcp_outgoing = worker->back->num_tcp_outgoing; /* get and reset validator rrset bogus number */ s->svr.rrset_bogus = get_rrset_bogus(worker); + /* get cache sizes */ + s->svr.msg_cache_count = count_slabhash_entries(worker->env.msg_cache); + s->svr.rrset_cache_count = count_slabhash_entries(&worker->env.rrset_cache->table); + s->svr.infra_cache_count = count_slabhash_entries(worker->env.infra_cache->hosts); + if(worker->env.key_cache) + s->svr.key_cache_count = count_slabhash_entries(worker->env.key_cache->slab); + else s->svr.key_cache_count = 0; + + /* get tcp accept usage */ + s->svr.tcp_accept_usage = 0; + for(lp = worker->front->cps; lp; lp = lp->next) { + if(lp->com->type == comm_tcp_accept) + s->svr.tcp_accept_usage += lp->com->cur_tcp_count; + } + if(reset && !worker->env.cfg->stat_cumulative) { worker_stats_clear(worker); } @@ -200,6 +228,7 @@ void server_stats_reply(struct worker* worker, int reset) void server_stats_add(struct stats_info* total, struct stats_info* a) { total->svr.num_queries += a->svr.num_queries; + total->svr.num_queries_ip_ratelimited += a->svr.num_queries_ip_ratelimited; total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache; total->svr.num_queries_prefetch += a->svr.num_queries_prefetch; total->svr.sum_query_list_size += a->svr.sum_query_list_size; @@ -212,6 +241,7 @@ void server_stats_add(struct stats_info* total, struct stats_info* a) total->svr.qtype_big += a->svr.qtype_big; total->svr.qclass_big += a->svr.qclass_big; total->svr.qtcp += a->svr.qtcp; + total->svr.qtcp_outgoing += a->svr.qtcp_outgoing; total->svr.qipv6 += a->svr.qipv6; total->svr.qbit_QR += a->svr.qbit_QR; total->svr.qbit_AA += a->svr.qbit_AA; @@ -224,11 +254,13 @@ void server_stats_add(struct stats_info* total, struct stats_info* a) total->svr.qEDNS += a->svr.qEDNS; total->svr.qEDNS_DO += a->svr.qEDNS_DO; total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata; + total->svr.zero_ttl_responses += a->svr.zero_ttl_responses; total->svr.ans_secure += a->svr.ans_secure; total->svr.ans_bogus += a->svr.ans_bogus; total->svr.rrset_bogus += a->svr.rrset_bogus; total->svr.unwanted_replies += a->svr.unwanted_replies; total->svr.unwanted_queries += a->svr.unwanted_queries; + total->svr.tcp_accept_usage += a->svr.tcp_accept_usage; for(i=0; i<STATS_QTYPE_NUM; i++) total->svr.qtype[i] += a->svr.qtype[i]; for(i=0; i<STATS_QCLASS_NUM; i++) @@ -257,14 +289,14 @@ void server_stats_insquery(struct server_stats* stats, struct comm_point* c, uint16_t qtype, uint16_t qclass, struct edns_data* edns, struct comm_reply* repinfo) { - uint16_t flags = ldns_buffer_read_u16_at(c->buffer, 2); + uint16_t flags = sldns_buffer_read_u16_at(c->buffer, 2); if(qtype < STATS_QTYPE_NUM) stats->qtype[qtype]++; else stats->qtype_big++; if(qclass < STATS_QCLASS_NUM) stats->qclass[qclass]++; else stats->qclass_big++; - stats->qopcode[ LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) ]++; + stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++; if(c->type != comm_udp) stats->qtcp++; if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen)) @@ -292,12 +324,12 @@ void server_stats_insquery(struct server_stats* stats, struct comm_point* c, } } -void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf) +void server_stats_insrcode(struct server_stats* stats, sldns_buffer* buf) { - if(stats->extended && ldns_buffer_limit(buf) != 0) { - int r = (int)LDNS_RCODE_WIRE( ldns_buffer_begin(buf) ); + if(stats->extended && sldns_buffer_limit(buf) != 0) { + int r = (int)LDNS_RCODE_WIRE( sldns_buffer_begin(buf) ); stats->ans_rcode[r] ++; - if(r == 0 && LDNS_ANCOUNT( ldns_buffer_begin(buf) ) == 0) + if(r == 0 && LDNS_ANCOUNT( sldns_buffer_begin(buf) ) == 0) stats->ans_rcode_nodata ++; } } diff --git a/usr.sbin/unbound/daemon/stats.h b/usr.sbin/unbound/daemon/stats.h index c0fc1cc1544..0b9d77b427d 100644 --- a/usr.sbin/unbound/daemon/stats.h +++ b/usr.sbin/unbound/daemon/stats.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -43,12 +43,12 @@ #ifndef DAEMON_STATS_H #define DAEMON_STATS_H #include "util/timehist.h" -#include <ldns/buffer.h> struct worker; struct config_file; struct comm_point; struct comm_reply; struct edns_data; +struct sldns_buffer; /** number of qtype that is stored for in array */ #define STATS_QTYPE_NUM 256 @@ -63,6 +63,8 @@ struct edns_data; struct server_stats { /** number of queries from clients received. */ size_t num_queries; + /** number of queries that have been dropped/ratelimited by ip. */ + size_t num_queries_ip_ratelimited; /** number of queries that had a cache-miss. */ size_t num_queries_missed_cache; /** number of prefetch queries - cachehits with prefetch */ @@ -91,6 +93,8 @@ struct server_stats { size_t qopcode[STATS_OPCODE_NUM]; /** number of queries over TCP */ size_t qtcp; + /** number of outgoing queries over TCP */ + size_t qtcp_outgoing; /** number of queries over IPv6 */ size_t qipv6; /** number of queries with QR bit */ @@ -127,12 +131,24 @@ struct server_stats { size_t unwanted_replies; /** unwanted traffic received on client-facing ports */ size_t unwanted_queries; - + /** usage of tcp accept list */ + size_t tcp_accept_usage; + /** answers served from expired cache */ + size_t zero_ttl_responses; /** histogram data exported to array * if the array is the same size, no data is lost, and * if all histograms are same size (is so by default) then * adding up works well. */ size_t hist[NUM_BUCKETS_HIST]; + + /** number of message cache entries */ + size_t msg_cache_count; + /** number of rrset cache entries */ + size_t rrset_cache_count; + /** number of infra cache entries */ + size_t infra_cache_count; + /** number of key cache entries */ + size_t key_cache_count; }; /** @@ -230,6 +246,6 @@ void server_stats_insquery(struct server_stats* stats, struct comm_point* c, * @param stats: the stats * @param buf: buffer with rcode. If buffer is length0: not counted. */ -void server_stats_insrcode(struct server_stats* stats, ldns_buffer* buf); +void server_stats_insrcode(struct server_stats* stats, struct sldns_buffer* buf); #endif /* DAEMON_STATS_H */ diff --git a/usr.sbin/unbound/daemon/unbound.c b/usr.sbin/unbound/daemon/unbound.c index 92a8ef7b94f..ba7337d8907 100644 --- a/usr.sbin/unbound/daemon/unbound.c +++ b/usr.sbin/unbound/daemon/unbound.c @@ -87,13 +87,8 @@ # include "nss.h" #endif -#ifdef HAVE_SBRK -/** global debug value to keep track of heap memory allocation */ -void* unbound_start_brk = 0; -#endif - /** print usage. */ -static void usage() +static void usage(void) { const char** m; const char *evnm="event", *evsys="", *evmethod=""; @@ -118,7 +113,11 @@ static void usage() printf("linked libs: %s %s (it uses %s), %s\n", evnm, evsys, evmethod, #ifdef HAVE_SSL +# ifdef SSLEAY_VERSION SSLeay_version(SSLEAY_VERSION) +# else + OpenSSL_version(OPENSSL_VERSION) +# endif #elif defined(HAVE_NSS) NSS_GetVersion() #elif defined(HAVE_NETTLE) @@ -240,19 +239,37 @@ checkrlimits(struct config_file* cfg) #endif /* S_SPLINT_S */ } +/** set default logfile identity based on value from argv[0] at startup **/ +static void +log_ident_set_fromdefault(struct config_file* cfg, + const char *log_default_identity) +{ + if(cfg->log_identity == NULL || cfg->log_identity[0] == 0) + log_ident_set(log_default_identity); + else + log_ident_set(cfg->log_identity); +} + /** set verbosity, check rlimits, cache settings */ static void apply_settings(struct daemon* daemon, struct config_file* cfg, - int cmdline_verbose, int debug_mode) + int cmdline_verbose, int debug_mode, const char* log_default_identity) { /* apply if they have changed */ verbosity = cmdline_verbose + cfg->verbosity; if (debug_mode > 1) { cfg->use_syslog = 0; + free(cfg->logfile); cfg->logfile = NULL; } daemon_apply_cfg(daemon, cfg); checkrlimits(cfg); + + if (cfg->use_systemd && cfg->do_daemonize) { + log_warn("use-systemd and do-daemonize should not be enabled at the same time"); + } + + log_ident_set_fromdefault(cfg, log_default_identity); } #ifdef HAVE_KILL @@ -544,7 +561,9 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, log_warn("unable to initgroups %s: %s", cfg->username, strerror(errno)); # endif /* HAVE_INITGROUPS */ +# ifdef HAVE_ENDPWENT endpwent(); +# endif #ifdef HAVE_SETRESGID if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0) @@ -580,9 +599,10 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, * @param cmdline_verbose: verbosity resulting from commandline -v. * These increase verbosity as specified in the config file. * @param debug_mode: if set, do not daemonize. + * @param log_default_identity: Default identity to report in logs */ static void -run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) +run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; @@ -604,7 +624,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) cfgfile); log_warn("Continuing with default config settings"); } - apply_settings(daemon, cfg, cmdline_verbose, debug_mode); + apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity); if(!done_setup) config_lookup_uid(cfg); @@ -612,7 +632,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) if(!daemon_open_shared_ports(daemon)) fatal_exit("could not open ports"); if(!done_setup) { - perform_setup(daemon, cfg, debug_mode, &cfgfile); + perform_setup(daemon, cfg, debug_mode, &cfgfile); done_setup = 1; } else { /* reopen log after HUP to facilitate log rotation */ @@ -659,19 +679,16 @@ main(int argc, char* argv[]) int c; const char* cfgfile = CONFIGFILE; const char* winopt = NULL; + const char* log_ident_default; int cmdline_verbose = 0; int debug_mode = 0; #ifdef UB_ON_WINDOWS int cmdline_cfg = 0; #endif -#ifdef HAVE_SBRK - /* take debug snapshot of heap */ - unbound_start_brk = sbrk(0); -#endif - log_init(NULL, 0, NULL); - log_ident_set(strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]); + log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]; + log_ident_set(log_ident_default); /* parse the options */ while( (c=getopt(argc, argv, "c:dhvw:")) != -1) { switch(c) { @@ -715,7 +732,7 @@ main(int argc, char* argv[]) return 1; } - run_daemon(cfgfile, cmdline_verbose, debug_mode); + run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default); log_init(NULL, 0, NULL); /* close logfile */ return 0; } diff --git a/usr.sbin/unbound/daemon/worker.c b/usr.sbin/unbound/daemon/worker.c index 33a6883f921..b23bbab95d9 100644 --- a/usr.sbin/unbound/daemon/worker.c +++ b/usr.sbin/unbound/daemon/worker.c @@ -101,57 +101,14 @@ */ #define PREFETCH_EXPIRY_ADD 60 -#ifdef UNBOUND_ALLOC_STATS -/** measure memory leakage */ -static void -debug_memleak(size_t accounted, size_t heap, - size_t total_alloc, size_t total_free) -{ - static int init = 0; - static size_t base_heap, base_accounted, base_alloc, base_free; - size_t base_af, cur_af, grow_af, grow_acc; - if(!init) { - init = 1; - base_heap = heap; - base_accounted = accounted; - base_alloc = total_alloc; - base_free = total_free; - } - base_af = base_alloc - base_free; - cur_af = total_alloc - total_free; - grow_af = cur_af - base_af; - grow_acc = accounted - base_accounted; - log_info("Leakage: %d leaked. growth: %u use, %u acc, %u heap", - (int)(grow_af - grow_acc), (unsigned)grow_af, - (unsigned)grow_acc, (unsigned)(heap - base_heap)); -} - -/** give debug heap size indication */ -static void -debug_total_mem(size_t calctotal) -{ -#ifdef HAVE_SBRK - extern void* unbound_start_brk; - extern size_t unbound_mem_alloc, unbound_mem_freed; - void* cur = sbrk(0); - int total = cur-unbound_start_brk; - log_info("Total heap memory estimate: %u total-alloc: %u " - "total-free: %u", (unsigned)total, - (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); - debug_memleak(calctotal, (size_t)total, - unbound_mem_alloc, unbound_mem_freed); -#else - (void)calctotal; -#endif /* HAVE_SBRK */ -} -#endif /* UNBOUND_ALLOC_STATS */ - /** Report on memory usage by this thread and global */ static void worker_mem_report(struct worker* ATTR_UNUSED(worker), struct serviced_query* ATTR_UNUSED(cur_serv)) { #ifdef UNBOUND_ALLOC_STATS + /* measure memory leakage */ + extern size_t unbound_mem_alloc, unbound_mem_freed; /* debug func in validator module */ size_t total, front, back, mesh, msg, rrset, infra, ac, superac; size_t me, iter, val, anch; @@ -199,7 +156,9 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker), (unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch, (unsigned)ac, (unsigned)superac, (unsigned)me); - debug_total_mem(total); + log_info("Total heap memory estimate: %u total-alloc: %u " + "total-free: %u", (unsigned)total, + (unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed); #else /* no UNBOUND_ALLOC_STATS */ size_t val = 0; int i; @@ -485,6 +444,10 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, if(!dp) { /* no delegation, need to reprime */ return 0; } + /* In case we have a local alias, copy it into the delegation message. + * Shallow copy should be fine, as we'll be done with msg in this + * function. */ + msg->qinfo.local_alias = qinfo->local_alias; if(must_validate) { switch(check_delegation_secure(msg->rep)) { case sec_status_unchecked: @@ -497,8 +460,9 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, worker->scratchpad)) - return 0; + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, + msg->rep, LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + return 0; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); if(worker->stats.extended) { @@ -526,12 +490,16 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, worker->scratchpad)) - return 0; + if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep, + (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad)) + return 0; msg->rep->flags |= BIT_QR|BIT_RA; if(!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)) + edns->opt_list = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); } @@ -553,17 +521,29 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, int secure; int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd) && worker->env.need_to_validate; - /* see if it is possible */ - if(rep->ttl < timenow) { - /* the rrsets may have been updated in the meantime. - * we will refetch the message format from the - * authoritative server - */ - return 0; + if(worker->env.cfg->serve_expired) { + /* always lock rrsets, rep->ttl is ignored */ + if(!rrset_array_lock(rep->ref, rep->rrset_count, 0)) + return 0; + /* below, rrsets with ttl before timenow become TTL 0 in + * the response */ + /* This response was served with zero TTL */ + if (timenow >= rep->ttl) { + worker->stats.zero_ttl_responses++; + } + } else { + /* see if it is possible */ + if(rep->ttl < timenow) { + /* the rrsets may have been updated in the meantime. + * we will refetch the message format from the + * authoritative server + */ + return 0; + } + if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) + return 0; + /* locked and ids and ttls are OK. */ } - if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow)) - return 0; - /* locked and ids and ttls are OK. */ /* check CNAME chain (if any) */ if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == @@ -584,8 +564,9 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, worker->scratchpad)) - return 0; + if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, + LDNS_RCODE_SERVFAIL, edns, worker->scratchpad)) + goto bail_out; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); rrset_array_unlock_touch(worker->env.rrset_cache, @@ -616,11 +597,15 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, worker->scratchpad)) - return 0; + if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep, + (int)(flags&LDNS_RCODE_MASK), edns, worker->scratchpad)) + goto bail_out; if(!reply_info_answer_encode(qinfo, 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)) + edns->opt_list = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); } @@ -692,8 +677,9 @@ chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns, edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, worker->scratchpad)) - edns->opt_list = NULL; + if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, + LDNS_RCODE_NOERROR, edns, worker->scratchpad)) + edns->opt_list = NULL; attach_edns_record(pkt, edns); } @@ -773,6 +759,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl, LDNS_QR_SET(sldns_buffer_begin(c->buffer)); LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), LDNS_RCODE_REFUSED); + sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); + sldns_buffer_flip(c->buffer); return 1; } @@ -799,11 +787,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error, { struct worker* worker = (struct worker*)arg; int ret; - hashvalue_t h; + hashvalue_type h; struct lruhash_entry* e; struct query_info qinfo; struct edns_data edns; enum acl_access acl; + struct acl_addr* acladdr; int rc = 0; if(error != NETEVENT_NOERROR) { @@ -816,8 +805,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error, dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif - acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, + acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr, repinfo->addrlen); + acl = acl_get_control(acladdr); if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1) { if(ret == 1) @@ -835,7 +825,29 @@ worker_handle_request(struct comm_point* c, void* arg, int error, comm_point_drop_reply(repinfo); return 0; } + worker->stats.num_queries++; + + /* check if this query should be dropped based on source ip rate limiting */ + if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo, + *worker->env.now)) { + /* See if we are passed through with slip factor */ + if(worker->env.cfg->ip_ratelimit_factor != 0 && + ub_random_max(worker->env.rnd, + worker->env.cfg->ip_ratelimit_factor) == 1) { + + char addrbuf[128]; + addr_to_str(&repinfo->addr, repinfo->addrlen, + addrbuf, sizeof(addrbuf)); + verbose(VERB_OPS, "ip_ratelimit allowed through for ip address %s ", + addrbuf); + } else { + worker->stats.num_queries_ip_ratelimited++; + comm_point_drop_reply(repinfo); + return 0; + } + } + /* see if query is in the cache */ if(!query_info_parse(&qinfo, c->buffer)) { verbose(VERB_ALGO, "worker parse request: formerror."); @@ -870,6 +882,28 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } + if(qinfo.qtype == LDNS_RR_TYPE_OPT || + qinfo.qtype == LDNS_RR_TYPE_TSIG || + qinfo.qtype == LDNS_RR_TYPE_TKEY || + qinfo.qtype == LDNS_RR_TYPE_MAILA || + qinfo.qtype == LDNS_RR_TYPE_MAILB || + (qinfo.qtype >= 128 && qinfo.qtype <= 248)) { + verbose(VERB_ALGO, "worker request: formerror for meta-type."); + log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); + if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) { + comm_point_drop_reply(repinfo); + return 0; + } + sldns_buffer_rewind(c->buffer); + LDNS_QR_SET(sldns_buffer_begin(c->buffer)); + LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), + LDNS_RCODE_FORMERR); + if(worker->stats.extended) { + worker->stats.qtype[qinfo.qtype]++; + server_stats_insrcode(&worker->stats, c->buffer); + } + goto send_reply; + } if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); @@ -940,8 +974,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error, regional_free_all(worker->scratchpad); goto send_reply; } - if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns, - c->buffer, worker->scratchpad, repinfo)) { + if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo, + &edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist, + acladdr->taglen, acladdr->tag_actions, + acladdr->tag_actions_size, acladdr->tag_datas, + acladdr->tag_datas_size, worker->daemon->cfg->tagname, + worker->daemon->cfg->num_tags, acladdr->view)) { regional_free_all(worker->scratchpad); if(sldns_buffer_limit(c->buffer) == 0) { comm_point_drop_reply(repinfo); @@ -978,44 +1016,70 @@ worker_handle_request(struct comm_point* c, void* arg, int error, &repinfo->addr, repinfo->addrlen); goto send_reply; } - h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); - if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { - /* answer from cache - we have acquired a readlock on it */ - if(answer_from_cache(worker, &qinfo, - (struct reply_info*)e->data, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), repinfo, - &edns)) { - /* prefetch it if the prefetch TTL expired */ - if(worker->env.cfg->prefetch && *worker->env.now >= - ((struct reply_info*)e->data)->prefetch_ttl) { - time_t leeway = ((struct reply_info*)e-> - data)->ttl - *worker->env.now; + + /* If we've found a local alias, replace the qname with the alias + * target before resolving it. */ + if(qinfo.local_alias) { + struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset; + struct packed_rrset_data* d = rrset->entry.data; + + /* Sanity check: our current implementation only supports + * a single CNAME RRset as a local alias. */ + if(qinfo.local_alias->next || + rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) || + d->count != 1) { + log_err("assumption failure: unexpected local alias"); + regional_free_all(worker->scratchpad); + return 0; /* drop it */ + } + qinfo.qname = d->rr_data[0] + 2; + qinfo.qname_len = d->rr_len[0] - 2; + } + + if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) { + h = query_info_hash(&qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); + if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { + /* answer from cache - we have acquired a readlock on it */ + if(answer_from_cache(worker, &qinfo, + (struct reply_info*)e->data, + *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), + sldns_buffer_read_u16_at(c->buffer, 2), repinfo, + &edns)) { + /* prefetch it if the prefetch TTL expired */ + if((worker->env.cfg->prefetch || worker->env.cfg->serve_expired) + && *worker->env.now >= + ((struct reply_info*)e->data)->prefetch_ttl) { + time_t leeway = ((struct reply_info*)e-> + data)->ttl - *worker->env.now; + if(((struct reply_info*)e->data)->ttl + < *worker->env.now) + leeway = 0; + lock_rw_unlock(&e->lock); + reply_and_prefetch(worker, &qinfo, + sldns_buffer_read_u16_at(c->buffer, 2), + repinfo, leeway); + rc = 0; + regional_free_all(worker->scratchpad); + goto send_reply_rc; + } lock_rw_unlock(&e->lock); - reply_and_prefetch(worker, &qinfo, - sldns_buffer_read_u16_at(c->buffer, 2), - repinfo, leeway); - rc = 0; regional_free_all(worker->scratchpad); - goto send_reply_rc; + goto send_reply; } + verbose(VERB_ALGO, "answer from the cache failed"); lock_rw_unlock(&e->lock); - regional_free_all(worker->scratchpad); - goto send_reply; } - verbose(VERB_ALGO, "answer from the cache failed"); - lock_rw_unlock(&e->lock); - } - if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { - if(answer_norec_from_cache(worker, &qinfo, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), repinfo, - &edns)) { - regional_free_all(worker->scratchpad); - goto send_reply; + if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) { + if(answer_norec_from_cache(worker, &qinfo, + *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), + sldns_buffer_read_u16_at(c->buffer, 2), repinfo, + &edns)) { + regional_free_all(worker->scratchpad); + goto send_reply; + } + verbose(VERB_ALGO, "answer norec from cache -- " + "need to validate or not primed"); } - verbose(VERB_ALGO, "answer norec from cache -- " - "need to validate or not primed"); } sldns_buffer_rewind(c->buffer); server_stats_querymiss(&worker->stats, worker); @@ -1044,6 +1108,12 @@ send_reply_rc: dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, c->type, c->buffer); #endif + if(worker->env.cfg->log_replies) + { + struct timeval tv = {0, 0}; + log_reply_info(0, &qinfo, &repinfo->addr, repinfo->addrlen, + tv, 1, c->buffer); + } return rc; } @@ -1369,11 +1439,10 @@ worker_delete(struct worker* worker) } struct outbound_entry* -worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, - uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec, - int nocaps, struct edns_option* opt_list, - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* q) +worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec, + int want_dnssec, int nocaps, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, int ssl_upstream, + struct module_qstate* q) { struct worker* worker = q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -1381,11 +1450,10 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype, if(!e) return NULL; e->qstate = q; - e->qsent = outnet_serviced_query(worker->back, qname, - qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, - q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list, - addr, addrlen, zone, zonelen, worker_handle_service_reply, e, - worker->back->udp_buff); + e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec, + want_dnssec, nocaps, q->env->cfg->tcp_upstream, + ssl_upstream, addr, addrlen, zone, zonelen, q, + worker_handle_service_reply, e, worker->back->udp_buff, q->env); if(!e->qsent) { return NULL; } @@ -1425,14 +1493,13 @@ void worker_stop_accept(void* arg) } /* --- fake callbacks for fptr_wlist to work --- */ -struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), - size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), - uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), - int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list), - struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) +struct outbound_entry* libworker_send_query( + struct query_info* ATTR_UNUSED(qinfo), + uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), + int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), + struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), + uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), + int ATTR_UNUSED(ssl_upstream), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); return 0; diff --git a/usr.sbin/unbound/daemon/worker.h b/usr.sbin/unbound/daemon/worker.h index 63613430b05..0d7ce952161 100644 --- a/usr.sbin/unbound/daemon/worker.h +++ b/usr.sbin/unbound/daemon/worker.h @@ -61,6 +61,7 @@ struct ub_randstate; struct regional; struct tube; struct daemon_remote; +struct query_info; /** worker commands */ enum worker_commands { @@ -84,7 +85,7 @@ struct worker { /** global shared daemon structure */ struct daemon* daemon; /** thread id */ - ub_thread_t thr_id; + ub_thread_type thr_id; /** pipe, for commands for this worker */ struct tube* cmd; /** the event base this worker works with */ diff --git a/usr.sbin/unbound/dns64/dns64.c b/usr.sbin/unbound/dns64/dns64.c index 2fde67841bb..befec864d6a 100644 --- a/usr.sbin/unbound/dns64/dns64.c +++ b/usr.sbin/unbound/dns64/dns64.c @@ -825,8 +825,9 @@ dns64_inform_super(struct module_qstate* qstate, int id, } /* Store the generated response in cache. */ - if (!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep, - 0, 0, 0, NULL, super->query_flags)) + if (!super->no_cache_store && + !dns_cache_store(super->env, &super->qinfo, super->return_msg->rep, + 0, 0, 0, NULL, super->query_flags)) log_err("out of memory"); } @@ -872,7 +873,7 @@ static struct module_func_block dns64_block = { * Function for returning the above function block. */ struct module_func_block * -dns64_get_funcblock() +dns64_get_funcblock(void) { return &dns64_block; } diff --git a/usr.sbin/unbound/dnstap/dnstap.c b/usr.sbin/unbound/dnstap/dnstap.c index 6df2fef3f31..5d0420f6fbb 100644 --- a/usr.sbin/unbound/dnstap/dnstap.c +++ b/usr.sbin/unbound/dnstap/dnstap.c @@ -121,7 +121,9 @@ dt_msg_init(const struct dt_env *env, struct dt_env * dt_create(const char *socket_path, unsigned num_workers) { +#ifdef UNBOUND_DEBUG fstrm_res res; +#endif struct dt_env *env; struct fstrm_iothr_options *fopt; struct fstrm_unix_writer_options *fuwopt; @@ -138,7 +140,12 @@ dt_create(const char *socket_path, unsigned num_workers) return NULL; fwopt = fstrm_writer_options_init(); - res = fstrm_writer_options_add_content_type(fwopt, +#ifdef UNBOUND_DEBUG + res = +#else + (void) +#endif + fstrm_writer_options_add_content_type(fwopt, DNSTAP_CONTENT_TYPE, sizeof(DNSTAP_CONTENT_TYPE) - 1); log_assert(res == fstrm_res_success); diff --git a/usr.sbin/unbound/doc/Changelog b/usr.sbin/unbound/doc/Changelog index 4b009400cf8..31c9e462752 100644 --- a/usr.sbin/unbound/doc/Changelog +++ b/usr.sbin/unbound/doc/Changelog @@ -1,3 +1,432 @@ +14 February 2017: Wouter + - tag 1.6.1rc3. + +13 February 2017: Wouter + - Fix autoconf of systemd check for lack of pkg-config. + +10 February 2017: Wouter + - Fix pythonmod for typedef changes. + - Fix dnstap for warning of set but not used. + - tag 1.6.1rc2. + +9 February 2017: Wouter + - tag 1.6.1rc1. + +8 February 2017: Wouter + - Fix for type name change and fix warning on windows compile. + +7 February 2017: Wouter + - Include root trust anchor id 20326 in unbound-anchor. + +6 February 2017: Wouter + - Fix compile on solaris of the fix to use $host detect. + +4 February 2017: Wouter + - fix root_anchor test for updated icannbundle.pem lower certificates. + +26 January 2017: Wouter + - Fix 1211: Fix can't enable interface-automatic if no IPv6 with + more helpful error message. + +20 January 2017: Wouter + - Increase MAX_MODULE to 16. + +19 January 2017: Wouter + - Fix to Rename ub_callback_t to ub_callback_type, because POSIX + reserves _t typedefs. + - Fix to rename internally used types from _t to _type, because _t + type names are reserved by POSIX. + - iana portlist update + +12 January 2017: Wouter + - Fix to also block meta types 128 through to 248 with formerr. + - Fix #1206: Some view-related commands are missing from 'unbound-control -h' + +9 January 2017: Wouter + - Fix #1202: Fix code comment that packed_rrset_data is not always + 'packed'. + +6 January 2017: Wouter + - Fix #1201: Fix missing unlock in answer_from_cache error condition. + +5 January 2017: Wouter + - Fix to return formerr for queries for meta-types, to avoid + packet amplification if this meta-type is sent on to upstream. + - Fix #1184: Log DNS replies. This includes the same logging + information that DNS queries and response code and response size, + patch from Larissa Feng. + - Fix #1185: Source IP rate limiting, patch from Larissa Feng. + +3 January 2017: Wouter + - configure --enable-systemd and lets unbound use systemd sockets if + you enable use-systemd: yes in unbound.conf. + Also there are contrib/unbound.socket and contrib/unbound.service: + systemd files for unbound, install them in /usr/lib/systemd/system. + Contributed by Sami Kerola and Pavel Odintsov. + - Fix reload chdir failure when also chrooted to that directory. + +2 January 2017: Wouter + - Fix #1194: Cross build fails when $host isn't `uname` for getentropy. + +23 December 2016: Ralph + - Fix #1190: Do not echo back EDNS options in local-zone error response. + - iana portlist update + +21 December 2016: Ralph + - Fix #1188: Unresolved symbol 'fake_dsa' in libunbound.so when built + with Nettle + +19 December 2016: Ralph + - Fix #1191: remove comment about view deletion. + +15 December 2016: Wouter + - iana portlist update + - 64bit is default for windows builds. + - Fix inet_ntop and inet_pton warnings in windows compile. + +14 December 2016: Wouter + - Fix #1178: attempt to fix setup error at end, pop result values + at end of install. + +13 December 2016: Wouter + - Fix #1182: Fix Resource leak (socket), at startup. + - Fix unbound-control and ipv6 only. + +9 December 2016: Wouter + - Fix #1176: stack size too small for Alpine Linux. + +8 December 2016: Wouter + - Fix downcast warnings from visual studio in sldns code. + - tag 1.6.0rc1 which became 1.6.0 on 15 dec, and trunk is 1.6.1. + +7 December 2016: Ralph + - Add DSA support for OpenSSL 1.1.0 + - Fix remote control without cert for LibreSSL + +6 December 2016: George + - Added generic EDNS code for registering known EDNS option codes, + bypassing the cache response stage and uniquifying mesh states. Four EDNS + option lists were added to module_qstate (module_qstate.edns_opts_*) to + store EDNS options from/to front/back side. + - Added two flags to module_qstate (no_cache_lookup, no_cache_store) that + control the modules' cache interactions. + - Added code for registering inplace callback functions. The registered + functions can be called just before replying with local data or Chaos, + replying from cache, replying with SERVFAIL, replying with a resolved + query, sending a query to a nameserver. The functions can inspect the + available data and maybe change response/query related data (i.e. append + EDNS options). + - Updated Python module for the above. + - Updated Python documentation. + +5 December 2016: Ralph + - Fix #1173: differ local-zone type deny from unset + tag_actions element. + +5 December 2016: Wouter + - Fix #1170: document that 'inform' local-zone uses local-data. + +1 December 2016: Ralph + - hyphen as minus fix, by Andreas Schulze + +30 November 2016: Ralph + - Added local-zones and local-data bulk addition and removal + functionality in unbound-control (local_zones, local_zones_remove, + local_datas and local_datas_remove). + - iana portlist update + +29 November 2016: Wouter + - version 1.6.0 is in the development branch. + - braces in view.c around lock statements. + +28 November 2016: Wouter + - new install-sh. + +25 November 2016: Wouter + - Fix that with openssl 1.1 control-use-cert: no uses less cpu, by + using no encryption over the unix socket. + +22 Novenber 2016: Ralph + - Make access-control-tag-data RDATA absolute. This makes the RDATA + origin consistent between local-data and access-control-tag-data. + - Fix NSEC ENT wildcard check. Matching wildcard does not have to be a + subdomain of the NSEC owner. + - QNAME minimisation uses QTYPE=A, therefore always check cache for + this type in harden-below-nxdomain functionality. + - Added unit test for QNAME minimisation + harden below nxdomain + synergy. + +22 November 2016: Wouter + - iana portlist update. + - Fix unit tests for DS hash processing for fake-dsa test option. + - patch from Dag-Erling Smorgrav that removes code that relies + on sbrk(). + +21 November 2016: Wouter + - Fix #1158: reference RFC 8020 "NXDOMAIN: There Really Is Nothing + Underneath" for the harden-below-nxdomain option. + +10 November 2016: Ralph + - Fix #1155: test status code of unbound-control in 04-checkconf, + not the status code from the tee command. + +4 November 2016: Ralph + - Added stub-ssl-upstream and forward-ssl-upstream options. + +4 November 2016: Wouter + - configure detects ssl security level API function in the autoconf + manner. Every function on its own, so that other libraries (eg. + LibreSSL) can develop their API without hindrance. + - Fix #1154: segfault when reading config with duplicate zones. + - Note that for harden-below-nxdomain the nxdomain must be secure, + this means nsec3 with optout is insufficient. + +3 November 2016: Ralph + - Set OpenSSL security level to 0 when using aNULL ciphers. + +3 November 2016: Wouter + - .gitattributes line for githubs code language display. + - log-identity: config option to set sys log identity, patch from + "Robin H. Johnson" <robbat2@gentoo.org> + +2 November 2016: Wouter + - iana portlist update. + +31 October 2016: Wouter + - Fix failure to build on arm64 with no sbrk. + - iana portlist update. + +28 October 2016: Wouter + - Patch for server.num.zero_ttl stats for count of expired replies, + from Pavel Odintsov. + +26 October 2016: Wouter + - Fix unit tests for openssl 1.1, with no DSA, by faking DSA, enabled + with the undocumented switch 'fake-dsa'. It logs a warning. + +25 October 2016: Wouter + - Fix #1134: unbound-control set_option -- val-override-date: -1 works + immediately to ignore datetime, or back to 0 to enable it again. + The -- is to ignore the '-1' as an option flag. + +24 October 2016: Wouter + - serve-expired config option: serve expired responses with TTL 0. + - g.root-servers.net has AAAA address. + +21 October 2016: Wouter + - Ported tests for local_cname unit test to testbound framework. + +20 October 2016: Wouter + - suppress compile warning in lex files. + - init lzt variable, for older gcc compiler warnings. + - fix --enable-dsa to work, instead of copying ecdsa enable. + - Fix DNSSEC validation of query type ANY with DNAME answers. + - Fixup query_info local_alias init. + +19 October 2016: Wouter + - Fix #1130: whitespace in example.conf.in more consistent. + +18 October 2016: Wouter + - Patch that resolves CNAMEs entered in local-data conf statements that + point to data on the internet, from Jinmei Tatuya (Infoblox). + - Removed patch comments from acllist.c and msgencode.c + - Added documentation doc/CNAME-basedRedirectionDesignNotes.pdf, + from Jinmei Tatuya (Infoblox). + - Fix #1125: unbound could reuse an answer packet incorrectly for + clients with different EDNS parameters, from Jinmei Tatuya. + - Fix #1118: libunbound.pc sets strange Libs, Libs.private values. + - Added Requires line to libunbound.pc + - Please doxygen by modifying mesh.h + +17 October 2016: Wouter + - Re-fix #839 from view commit overwrite. + - Fixup const void cast warning. + +12 October 2016: Ralph + - Free view config elements. + +11 October 2016: Ralph + - Added qname-minimisation-strict config option. + - iana portlist update. + - fix memoryleak logfile when in debug mode. + +5 October 2016: Ralph + - Added views functionality. + - Fix #1117: spelling errors, from Robert Edmonds. + +30 September 2016: Wouter + - Fix Nits for 1.5.10 reported by Dag-Erling Smorgrav. + +29 September 2016: Wouter + - Fix #838: 1.5.10 cannot be built on Solaris, undefined PATH_MAX. + - Fix #839: Memory grows unexpectedly with large RPZ files. + - Fix #840: infinite loop in unbound_munin_ plugin on unowned lockfile. + - Fix #841: big local-zone's make it consume large amounts of memory. + +27 September 2016: Wouter + - tag for 1.5.10 release + - trunk contains 1.5.11 in development. + - Fix dnstap relaying "random" messages instead of resolver/forwarder + responses, from Nikolay Edigaryev. + - Fix #836: unbound could echo back EDNS options in an error response. + +20 September 2016: Wouter + - iana portlist update. + - Fix #835: fix --disable-dsa with nettle verify. + - tag for 1.5.10rc1 release. + +15 September 2016: Wouter + - Fix 883: error for duplicate local zone entry. + - Test for openssl init_crypto and init_ssl functions. + +15 September 2016: Ralph + - fix potential memory leak in daemon/remote.c and nullpointer + dereference in validator/autotrust. + - iana portlist update. + +13 September 2016: Wouter + - Silenced flex-generated sign-unsigned warning print with gcc + diagnostic pragma. + - Fix for new splint on FreeBSD. Fix cast for sockaddr_un.sun_len. + +9 September 2016: Wouter + - Fix #831: workaround for spurious fread_chk warning against petal.c + +5 September 2016: Ralph + - Take configured minimum TTL into consideration when reducing TTL + to original TTL from RRSIG. + +5 September 2016: Wouter + - Fix #829: doc of sldns_wire2str_rdata_buf() return value has an + off-by-one typo, from Jinmei Tatuya (Infoblox). + - Fix incomplete prototypes reported by Dag-Erling Smørgrav. + - Fix #828: missing type in access-control-tag-action redirect results + in NXDOMAIN. + +2 September 2016: Wouter + - Fix compile with openssl 1.1.0 with api=1.1.0. + +1 September 2016: Wouter + - RFC 7958 is now out, updated docs for unbound-anchor. + - Fix for compile without warnings with openssl 1.1.0. + - Fix #826: Fix refuse_non_local could result in a broken response. + - iana portlist update. + +29 August 2016: Wouter + - Fix #777: OpenSSL 1.1.0 compatibility, patch from Sebastian A. + Siewior. + - Add default root hints for IPv6 E.ROOT-SERVERS.NET, 2001:500:a8::e. + +25 August 2016: Ralph + - Clarify local-zone-override entry in unbound.conf.5 + +25 August 2016: Wouter + - 64bit build option for makedist windows compile, -w64. + +24 August 2016: Ralph + - Fix #820: set sldns_str2wire_rr_buf() dual meaning len parameter + in each iteration in find_tag_datas(). + - unbound.conf.5 entries for define-tag, access-control-tag, + access-control-tag-action, access-control-tag-data, local-zone-tag, + and local-zone-override. + +23 August 2016: Wouter + - Fix #804: unbound stops responding after outage. Fixes queries + that attempt to wait for an empty list of subqueries. + - Fix #804: lower num_target_queries for iterator also for failed + lookups. + +8 August 2016: Wouter + - Note that OPENPGPKEY type is RFC 7929. + +4 August 2016: Wouter + - Fix #807: workaround for possible some "unused" function parameters + in test code, from Jinmei Tatuya. + +3 August 2016: Wouter + - use sendmsg instead of sendto for TFO. + +28 July 2016: Wouter + - Fix #806: wrong comment removed. + +26 July 2016: Wouter + - nicer ratelimit-below-domain explanation. + +22 July 2016: Wouter + - Fix #801: missing error condition handling in + daemon_create_workers(). + - Fix #802: workaround for function parameters that are "unused" + without log_assert. + - Fix #803: confusing (and incorrect) code comment in daemon_cleanup(). + +20 July 2016: Wouter + - Fix typo in unbound.conf. + +18 July 2016: Wouter + - Fix #798: Client-side TCP fast open fails (Linux). + +14 July 2016: Wouter + - TCP Fast open patch from Sara Dickinson. + - Fixed unbound.doxygen for 1.8.11. + +7 July 2016: Wouter + - access-control-tag-data implemented. verbose(4) prints tag debug. + +5 July 2016: Wouter + - Fix dynamic link of anchor-update.exe on windows. + - Fix detect of mingw for MXE package build. + - Fixes for 64bit windows compile. + - Fix #788 for nettle 3.0: Failed to build with Nettle >= 3.0 and + --with-libunbound-only --with-nettle. + +4 July 2016: Wouter + - For #787: prefer-ip6 option for unbound.conf prefers to send + upstream queries to ipv6 servers. + - Fix #787: outgoing-interface netblock/64 ipv6 option to use linux + freebind to use 64bits of entropy for every query with random local + part. + +30 June 2016: Wouter + - Document always_transparent, always_refuse, always_nxdomain types. + +29 June 2016: Wouter + - Fix static compile on windows missing gdi32. + +28 June 2016: Wouter + - Create a pkg-config file for libunbound in contrib. + +27 June 2016: Wouter + - Fix #784: Build configure assumess that having getpwnam means there + is endpwent function available. + - Updated repository with newer flex and bison output. + +24 June 2016: Ralph + - Possibility to specify local-zone type for an acl/tag pair + - Possibility to specify (override) local-zone type for a source address + block +16 June 2016: Ralph + - Decrease dp attempts at each QNAME minimisation iteration + +16 June 2016: Wouter + - Fix tcp timeouts in tv.usec. + +15 June 2016: Wouter + - TCP_TIMEOUT is specified in milliseconds. + - If more than half of tcp connections are in use, a shorter timeout + is used (200 msec, vs 2 minutes) to pressure tcp for new connects. + +14 June 2016: Ralph + - QNAME minimisation unit test for dropped QTYPE=A queries. + +14 June 2016: Wouter + - Fix 775: unbound-host and unbound-anchor crash on windows, ignore + null delete for wsaevent. + - Fix spelling in freebind option man page text. + - Fix windows link of ssl with crypt32. + - Fix 779: Union casting is non-portable. + - Fix 780: MAP_ANON not defined in HP-UX 11.31. + - Fix 781: prealloc() is an HP-UX system library call. + 13 June 2016: Ralph - Use QTYPE=A for QNAME minimisation. - Keep track of number of time-outs when performing QNAME minimisation. @@ -6,12 +435,57 @@ 13 June 2016: Wouter - Fix #778: unbound 1.5.9: -h segfault (null deref). + - Fix directory: fix for unbound-checkconf, it restores cwd. + +10 June 2016: Wouter + - And delete service.conf.shipped on uninstall. + - In unbound.conf directory: dir immediately changes to that directory, + so that include: file below that is relative to that directory. + With chroot, make the directory an absolute path inside chroot. + - keep debug symbols in windows build. + - do not delete service.conf on windows uninstall. + - document directory immediate fix and allow EXECUTABLE syntax in it + on windows. + +9 June 2016: Wouter + - Trunk is called 1.5.10 (with previous fixes already in there to 2 + june). + - Revert fix for NetworkService account on windows due to breakage + it causes. + - Fix that windows install will not overwrite existing service.conf + file (and ignore gui config choices if it exists). + +7 June 2016: Ralph + - Lookup localzones by taglist from acl. + - Possibility to lookup local_zone, regardless the taglist. + - Added local_zone/taglist/acl unit test. + +7 June 2016: Wouter + - Fix #773: Non-standard Python location build failure with pyunbound. + - Improve threadsafety for openssl 0.9.8 ecdsa dnssec signatures. + +6 June 2016: Wouter + - Better help text from -h (from Ray Griffith). + - access-control-tag config directive. + - local-zone-override config directive. + - access-control-tag-action and access-control-tag-data config + directives. + - free acl-tags, acltag-action and acltag-data config lists during + initialisation to free up memory for more entries. + +3 June 2016: Wouter + - Fix to not ignore return value of chown() in daemon startup. 2 June 2016: Wouter - Fix libubound for edns optlist feature. - Fix distinction between free and CRYPTO_free in dsa and ecdsa alloc. - Fix #752: retry resource temporarily unavailable on control pipe. - un-document localzone tags. + - tag for release 1.5.9rc1. + And this also became release 1.5.9. + - Fix (for 1.5.10): Fix unbound-anchor.exe file location defaults to + Program Files with (x86) appended. + - re-documented localzone tags in example.conf. 31 May 2016: Wouter - Fix windows service to be created run with limited rights, as a diff --git a/usr.sbin/unbound/doc/README b/usr.sbin/unbound/doc/README index 7d0dd3712bc..a00c611949a 100644 --- a/usr.sbin/unbound/doc/README +++ b/usr.sbin/unbound/doc/README @@ -1,4 +1,4 @@ -README for Unbound 1.5.9 +README for Unbound 1.6.1rc3 Copyright 2007 NLnet Labs http://unbound.net diff --git a/usr.sbin/unbound/doc/example.conf.in b/usr.sbin/unbound/doc/example.conf.in index 6e00bdf69de..ab5560a07e1 100644 --- a/usr.sbin/unbound/doc/example.conf.in +++ b/usr.sbin/unbound/doc/example.conf.in @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.5.9. +# See unbound.conf(5) man page, version 1.6.1rc3. # # this is a comment. @@ -53,6 +53,15 @@ server: # outgoing-interface: 2001:DB8::5 # outgoing-interface: 2001:DB8::6 + # Specify a netblock to use remainder 64 bits as random bits for + # upstream queries. Uses freebind option (Linux). + # outgoing-interface: 2001:DB8::/64 + # Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo + # And: ip -6 route add local 2001:db8::/64 dev lo + # And set prefer-ip6: yes to use the ip6 randomness from a netblock. + # Set this to yes to prefer ipv6 upstream servers over ipv4. + # prefer-ip6: no + # number of ports to allocate per thread, determines the size of the # port range that can be open simultaneously. About double the # num-queries-per-thread, or, use as many as the OS will allow you. @@ -163,6 +172,10 @@ server: # the maximum number of hosts that are cached (roundtrip, EDNS, lame). # infra-cache-numhosts: 10000 + # define a number of tags here, use with local-zone, access-control. + # repeat the define-tag statement to add additional tags. + # define-tag: "tag1 tag2 tag3" + # Enable IPv4, "yes" or "no". # do-ip4: yes @@ -187,7 +200,11 @@ server: # Default is 0, system default MSS. # outgoing-tcp-mss: 0 + # Use systemd socket activation for UDP, TCP, and control sockets. + # use-systemd: no + # Detach from the terminal, run in background, "yes" or "no". + # Set the value to "no" when unbound runs as systemd service. # do-daemonize: yes # control which clients are allowed to make (recursive) queries @@ -203,6 +220,23 @@ server: # access-control: ::1 allow # access-control: ::ffff:127.0.0.1 allow + # tag access-control with list of tags (in "" with spaces between) + # Clients using this access control element use localzones that + # are tagged with one of these tags. + # access-control-tag: 192.0.2.0/24 "tag2 tag3" + + # set action for particular tag for given access control element + # if you have multiple tag values, the tag used to lookup the action + # is the first tag match between access-control-tag and local-zone-tag + # where "first" comes from the order of the define-tag values. + # access-control-tag-action: 192.0.2.0/24 tag3 refuse + + # set redirect data for particular tag for access control element + # access-control-tag-data: 192.0.2.0/24 tag2 "A 127.0.0.1" + + # Set view for access control element + # access-control-view: 192.0.2.0/24 viewname + # if given, a chroot(2) is done to the given directory. # i.e. you can chroot to the working directory, for example, # for extra security, but make sure all files are in that directory. @@ -236,6 +270,8 @@ server: # the working directory. The relative files in this config are # relative to this directory. If you give "" the working directory # is not changed. + # If you give a server: directory: dir before include: file statements + # then those includes can be relative to the working directory. # directory: "@UNBOUND_RUN_DIR@" # the log file, "" means log to stderr. @@ -243,15 +279,23 @@ server: # logfile: "" # Log to syslog(3) if yes. The log facility LOG_DAEMON is used to - # log to, with identity "unbound". If yes, it overrides the logfile. + # log to. If yes, it overrides the logfile. # use-syslog: yes + # Log identity to report. if empty, defaults to the name of argv[0] + # (usually "unbound"). + # log-identity: "" + # print UTC timestamp in ascii to logfile, default is epoch in seconds. # log-time-ascii: no # print one line with time, IP, name, type, class for every query. # log-queries: no + # print one line per reply, with time, IP, name, type, class, rcode, + # timetoresolve, fromcache and responsesize. + # log-replies: no + # the pid file. Can be an absolute path outside of chroot/work dir. # pidfile: "@UNBOUND_PIDFILE@" @@ -299,7 +343,7 @@ server: # Harden against queries that fall under dnssec-signed nxdomain names. # harden-below-nxdomain: no - # Harden the referral path by performing additional queries for + # Harden the referral path by performing additional queries for # infrastructure data. Validates the replies (if possible). # Default off, because the lookups burden the server. Experimental # implementation of draft-wijngaards-dnsext-resolver-side-mitigation. @@ -315,6 +359,12 @@ server: # to NS when possible. # qname-minimisation: no + # QNAME minimisation in strict mode. Do not fall-back to sending full + # QNAME to potentially broken nameservers. A lot of domains will not be + # resolvable when this option in enabled. + # This option only has effect when qname-minimisation is enabled. + # qname-minimisation-strict: no + # Use 0x20-encoded random bits in the query to foil spoof attempts. # This feature is an experimental implementation of draft dns-0x20. # use-caps-for-id: no @@ -322,6 +372,7 @@ server: # Domains (and domains in them) without support for dns-0x20 and # the fallback fails because they keep sending different answers. # caps-whitelist: "licdn.com" + # caps-whitelist: "senderbase.org" # Enforce privacy of these addresses. Strips them away from answers. # It may cause DNSSEC validation to additionally mark it as bogus. @@ -447,6 +498,10 @@ server: # that set CD but cannot validate themselves. # ignore-cd-flag: no + # Serve expired reponses from cache, with TTL 0 in the response, + # and then attempt to fetch the data afresh. + # serve-expired: 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. # val-log-level: 0 @@ -548,8 +603,10 @@ server: # o redirect serves the zone data for any subdomain in the zone. # o nodefault can be used to normally resolve AS112 zones. # o typetransparent resolves normally for other types and other names - # o inform resolves normally, but logs client IP address + # o inform acts like transparent, but logs client IP address # o inform_deny drops queries and logs client IP address + # o always_transparent, always_refuse, always_nxdomain, resolve in + # that way but ignore local data for that name. # # defaults are localhost address, reverse for 127.0.0.1 and ::1 # and nxdomain for AS112 zones. If you configure one of these zones @@ -576,6 +633,12 @@ server: # you need to do the reverse notation yourself. # local-data-ptr: "192.0.2.3 www.example.com" + # tag a localzone with a list of tag names (in "" with spaces between) + # local-zone-tag: "example.com" "tag2 tag3" + + # add a netblock specific override to a localzone, with zone type + # local-zone-override: "example.com" 192.0.2.0/24 refuse + # service clients over SSL (on the TCP sockets), with plain DNS inside # the SSL stream. Give the certificate to use and private key. # default is "" (disabled). requires restart to take effect. @@ -609,7 +672,21 @@ server: # ratelimit-for-domain: example.com 1000 # override the ratelimits for all domains below a domain name # can give this multiple times, the name closest to the zone is used. - # ratelimit-below-domain: example 1000 + # ratelimit-below-domain: com 1000 + + # global query ratelimit for all ip addresses. + # feature is experimental. + # if 0(default) it is disabled, otherwise states qps allowed per ip address + # ip-ratelimit: 0 + + # ip ratelimits are tracked in a cache, size in bytes of cache (or k,m). + # ip-ratelimit-size: 4m + # ip ratelimit cache slabs, reduces lock contention if equal to cpucount. + # ip-ratelimit-slabs: 4 + + # 0 blocks when ip is ratelimited, otherwise let 1/xth traffic through + # ip-ratelimit-factor: 10 + # Python config section. To enable: # o use --with-pythonmodule to configure before compiling. @@ -662,6 +739,7 @@ remote-control: # stub-addr: 192.0.2.68 # stub-prime: no # stub-first: no +# stub-ssl-upstream: no # stub-zone: # name: "example.org" # stub-host: ns.example.com. @@ -677,6 +755,23 @@ remote-control: # forward-addr: 192.0.2.68 # forward-addr: 192.0.2.73@5355 # forward to port 5355. # forward-first: no +# forward-ssl-upstream: no # forward-zone: # name: "example.org" # forward-host: fwd.example.com + +# Views +# Create named views. Name must be unique. Map views to requests using +# the access-control-view option. Views can contain zero or more local-zone +# and local-data options. Options from matching views will override global +# options. Global options will be used if no matching view is found. +# With view-first yes, it will try to answer using the global local-zone and +# local-data elements if there is no view specific match. +# view: +# name: "viewname" +# local-zone: "example.com" redirect +# local-data: "example.com A 192.0.2.3" +# view-first: no +# view: +# name: "anotherview" +# local-zone: "example.com" refuse diff --git a/usr.sbin/unbound/doc/libunbound.3.in b/usr.sbin/unbound/doc/libunbound.3.in index 163a6fa44d0..0b419f59934 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "libunbound" "3" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" libunbound.3 -- unbound library functions manual .\" @@ -12,7 +12,7 @@ .B unbound.h, .B ub_ctx, .B ub_result, -.B ub_callback_t, +.B ub_callback_type, .B ub_ctx_create, .B ub_ctx_delete, .B ub_ctx_set_option, @@ -43,7 +43,7 @@ .B ub_ctx_zone_remove, .B ub_ctx_data_add, .B ub_ctx_data_remove -\- Unbound DNS validating resolver 1.5.9 functions. +\- Unbound DNS validating resolver 1.6.1rc3 functions. .SH "SYNOPSIS" .B #include <unbound.h> .LP @@ -120,7 +120,7 @@ .br \fIint\fR rrtype, \fIint\fR rrclass, \fIvoid*\fR mydata, .br - \fIub_callback_t\fR callback, \fIint*\fR async_id); + \fIub_callback_type\fR callback, \fIint*\fR async_id); .LP \fIint\fR \fBub_cancel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR async_id); @@ -180,7 +180,7 @@ and .B ub_ctx_hosts to read them. Before you call this, use the openssl functions CRYPTO_set_id_callback and -CRYPTO_set_locking_callback to set up asyncronous operation if you use +CRYPTO_set_locking_callback to set up asynchronous operation if you use lib openssl (the application calls these functions once for initialisation). Openssl 1.0.0 or later uses the CRYPTO_THREADID_set_callback function. .TP diff --git a/usr.sbin/unbound/doc/unbound-anchor.8.in b/usr.sbin/unbound/doc/unbound-anchor.8.in index 1dabc725fa5..f094cd1c939 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound-anchor" "8" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" unbound-anchor.8 -- unbound anchor maintenance utility manual .\" @@ -16,6 +16,8 @@ .SH "DESCRIPTION" .B Unbound\-anchor performs setup or update of the root trust anchor for DNSSEC validation. +The program fetches the trust anchor with the method from RFC7958 when +regular RFC5011 update fails to bring it up to date. It can be run (as root) from the commandline, or run as part of startup scripts. Before you start the \fIunbound\fR(8) DNS server. .P @@ -39,8 +41,8 @@ update certificate files. .P It tests if the root anchor file works, and if not, and an update is possible, attempts to update the root anchor using the root update certificate. -It performs a https fetch of root-anchors.xml and checks the results, if -all checks are successful, it updates the root anchor file. Otherwise +It performs a https fetch of root-anchors.xml and checks the results (RFC7958), +if all checks are successful, it updates the root anchor file. Otherwise the root anchor file is unchanged. It performs RFC5011 tracking if the DNSSEC information available via the DNS makes that possible. .P @@ -65,7 +67,7 @@ List the builtin root key and builtin root update certificate on stdout. .B \-u \fIname The server name, it connects to https://name. Specify without https:// prefix. The default is "data.iana.org". It connects to the port specified with \-P. -You can pass an IPv4 addres or IPv6 address (no brackets) if you want. +You can pass an IPv4 address or IPv6 address (no brackets) if you want. .TP .B \-x \fIpath The pathname to the root\-anchors.xml file on the server. (forms URL with \-u). diff --git a/usr.sbin/unbound/doc/unbound-checkconf.8.in b/usr.sbin/unbound/doc/unbound-checkconf.8.in index a4cdf3b9ea9..275ea309e4c 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound-checkconf" "8" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" 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 3b24b1fa9a8..5b680a556e3 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound-control" "8" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" unbound-control.8 -- unbound remote control manual .\" @@ -99,6 +99,22 @@ but if the name has become an empty nonterminal (there is still data in domain names below the removed name), NOERROR nodata answers are the result for that name. .TP +.B local_zones +Add local zones read from stdin of unbound\-control. Input is read per line, +with name space type on a line. For bulk additions. +.TP +.B local_zones_remove +Remove local zones read from stdin of unbound\-control. Input is one name per +line. For bulk removals. +.TP +.B local_datas +Add local data RRs read from stdin of unbound\-control. Input is one RR per +line. For bulk additions. +.TP +.B local_datas_remove +Remove local data RRs read from stdin of unbound\-control. Input is one name per +line. For bulk removals. +.TP .B dump_cache The contents of the cache is printed in a text format to stdout. You can redirect it to a file to store the cache in a file. @@ -178,7 +194,7 @@ harden\-referral\-path, prefetch, prefetch\-key, log\-queries, hide\-identity, hide\-version, identity, version, val\-log\-level, val\-log\-squelch, ignore\-cd\-flag, add\-holddown, del\-holddown, keep\-missing, tcp\-upstream, ssl\-upstream, max\-udp\-size, ratelimit, -cache\-max\-ttl, cache\-min\-ttl, cache\-max\-negative\-ttl. +ip\-ratelimit, cache\-max\-ttl, cache\-min\-ttl, cache\-max\-negative\-ttl. .TP .B get_option \fIopt Get the value of the option. Give the option name without a trailing ':'. @@ -263,6 +279,30 @@ estimated qps and qps limit from config. With +a it prints all domains, not just the ratelimited domains, with their estimated qps. The ratelimited domains return an error for uncached (new) queries, but cached queries work as normal. +.TP +.B ip_ratelimit_list \fR[\fI+a\fR] +List the ip addresses that are ratelimited. Printed one per line with current +estimated qps and qps limit from config. With +a it prints all ips, not +just the ratelimited ips, with their estimated qps. The ratelimited +ips are dropped before checking the cache. +.TP +.B view_list_local_zones \fIview\fR +\fIlist_local_zones\fR for given view. +.TP +.B view_local_zone \fIview\fR \fIname\fR \fItype +\fIlocal_zone\fR for given view. +.TP +.B view_local_zone_remove \fIview\fR \fIname +\fIlocal_zone_remove\fR for given view. +.TP +.B view_list_local_data \fIview\fR +\fIlist_local_data\fR for given view. +.TP +.B view_local_data \fIview\fR \fIRR data... +\fIlocal_data\fR for given view. +.TP +.B view_local_data_remove \fIview\fR \fIname +\fIlocal_data_remove\fR for given view. .SH "EXIT CODE" The unbound\-control program exits with status code 1 on error, 0 on success. .SH "SET UP" @@ -288,6 +328,9 @@ The \fIstats\fR command shows a number of statistic counters. .I threadX.num.queries number of queries received by thread .TP +.I threadX.num.queries_ip_ratelimited +number of queries rate limited by thread +.TP .I threadX.num.cachehits number of queries that were successfully answered using a cache lookup .TP @@ -301,6 +344,9 @@ and resulted in recursive processing, taking a slot in the requestlist. Not part of the recursivereplies (or the histogram thereof) or cachemiss, as a cache response was sent. .TP +.I threadX.num.zero_ttl +number of replies with ttl zero, because they served an expired cache entry. +.TP .I threadX.num.recursivereplies The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries. .TP @@ -350,6 +396,9 @@ summed over threads. .I total.num.prefetch summed over threads. .TP +.I total.num.zero_ttl +summed over threads. +.TP .I total.num.recursivereplies summed over threads. .TP @@ -384,9 +433,6 @@ uptime since server boot in seconds. time since last statistics printout, in seconds. .SH EXTENDED STATISTICS .TP -.I mem.total.sbrk -If sbrk(2) is available, an estimate of the heap size of the program in number of bytes. Close to the total memory used by the program, as reported by top and ps. Could be wrong if the OS allocates memory non\-contiguously. -.TP .I mem.cache.rrset Memory in bytes in use by the RRset cache. .TP diff --git a/usr.sbin/unbound/doc/unbound-host.1.in b/usr.sbin/unbound/doc/unbound-host.1.in index 700382eb9f1..2acd006f740 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound\-host" "1" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" unbound-host.1 -- unbound DNS lookup utility .\" diff --git a/usr.sbin/unbound/doc/unbound.8.in b/usr.sbin/unbound/doc/unbound.8.in index 35385b9f1a0..7efdf466123 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound" "8" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" unbound.8 -- unbound manual .\" @@ -9,7 +9,7 @@ .\" .SH "NAME" .B unbound -\- Unbound DNS validating resolver 1.5.9. +\- Unbound DNS validating resolver 1.6.1rc3. .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 dcd10de5aa0..79781d29531 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 9, 2016" "NLnet Labs" "unbound 1.5.9" +.TH "unbound.conf" "5" "Feb 14, 2017" "NLnet Labs" "unbound 1.6.1rc3" .\" .\" unbound.conf.5 -- unbound.conf manual .\" @@ -36,7 +36,8 @@ Processing continues as if the text from the included file was copied into the config file at that point. If also using chroot, using full path names for the included files works, relative pathnames for the included names work if the directory where the daemon is started equals its chroot/working -directory. Wildcards can be used to include multiple files, see \fIglob\fR(7). +directory or is specified before the include statement with directory: dir. +Wildcards can be used to include multiple files, see \fIglob\fR(7). .SS "Server Options" These options are part of the .B server: @@ -90,7 +91,7 @@ Detect source interface on UDP queries and copy them to replies. This feature is experimental, and needs support in your OS for particular socket options. Default value is no. .TP -.B outgoing\-interface: \fI<ip address> +.B outgoing\-interface: \fI<ip address or ip6 netblock> Interface to use to connect to the network. This interface is used to send queries to authoritative servers and receive their replies. Can be given multiple times to work on several interfaces. If none are given the @@ -100,12 +101,28 @@ and .B outgoing\-interface: lines, the interfaces are then used for both purposes. Outgoing queries are sent via a random outgoing interface to counter spoofing. +.IP +If an IPv6 netblock is specified instead of an individual IPv6 address, +outgoing UDP queries will use a randomised source address taken from the +netblock to counter spoofing. Requires the IPv6 netblock to be routed to the +host running unbound, and requires OS support for unprivileged non-local binds +(currently only supported on Linux). Several netblocks may be specified with +multiple +.B outgoing\-interface: +options, but do not specify both an individual IPv6 address and an IPv6 +netblock, or the randomisation will be compromised. Consider combining with +.B prefer\-ip6: yes +to increase the likelihood of IPv6 nameservers being selected for queries. +On Linux you need these two commands to be able to use the freebind socket +option to receive traffic for the ip6 netblock: +ip \-6 addr add mynetblock/64 dev lo && +ip \-6 route add local mynetblock/64 dev lo .TP .B outgoing\-range: \fI<number> Number of ports to open. This number of file descriptors can be opened per thread. Must be at least 1. Default depends on compile options. Larger numbers need extra resources from the operating system. For performance a -a very large value is best, use libevent to make this possible. +very large value is best, use libevent to make this possible. .TP .B outgoing\-port\-permit: \fI<port number or range> Permit unbound to open this port or range of ports for use to send queries. @@ -245,7 +262,7 @@ permissions on some systems. The option uses IP_BINDANY on FreeBSD systems. If yes, then use IP_FREEBIND socket option on sockets where unbound is listening to incoming traffic. Default no. Allows you to bind to IP addresses that are nonlocal or do not exist, like when the network -interface or IP adress is down. Exists only on Linux, where the similar +interface or IP address is down. Exists only on Linux, where the similar ip\-transparent option is also available. .TP .B rrset\-cache\-size: \fI<number> @@ -293,6 +310,10 @@ Lower limit for dynamic retransmit timeout calculation in infrastructure cache. Default is 50 milliseconds. Increase this value if using forwarders needing more time to do recursive name resolution. .TP +.B define\-tag: \fI<"list of tags"> +Define the tags that can be used with local\-zone and access\-control. +Enclose the list between quotes ("") and put spaces between tags. +.TP .B do\-ip4: \fI<yes or no> Enable or disable whether ip4 queries are answered or issued. Default is yes. .TP @@ -303,6 +324,10 @@ IPv6 to the internet nameservers. With this option you can disable the ipv6 transport for sending DNS traffic, it does not impact the contents of the DNS traffic, which may have ip4 and ip6 addresses in it. .TP +.B prefer\-ip6: \fI<yes or no> +If enabled, prefer IPv6 transport for sending DNS queries to internet +nameservers. Default is no. +.TP .B do\-udp: \fI<yes or no> Enable or disable whether UDP queries are answered or issued. Default is yes. .TP @@ -352,9 +377,14 @@ turned off. The port number on which to provide TCP SSL service, default 853, only interfaces configured with that port number as @number get the SSL service. .TP +.B use\-systemd: \fI<yes or no> +Enable or disable systemd socket activation. +Default is no. +.TP .B do\-daemonize: \fI<yes or no> Enable or disable whether the unbound server forks into the background as -a daemon. Default is yes. +a daemon. Set the value to \fIno\fR when unbound runs as systemd service. +Default is yes. .TP .B access\-control: \fI<IP netblock> <action> The netblock is given as an IP4 or IP6 address with /size appended for a @@ -396,6 +426,26 @@ allowed full recursion but only the static data. With deny_non_local, messages that are disallowed are dropped, with refuse_non_local they receive error code REFUSED. .TP +.B access\-control\-tag: \fI<IP netblock> <"list of tags"> +Assign tags to access-control elements. Clients using this access control +element use localzones that are tagged with one of these tags. Tags must be +defined in \fIdefine\-tags\fR. Enclose list of tags in quotes ("") and put +spaces between tags. If access\-control\-tag is configured for a netblock that +does not have an access\-control, an access\-control element with action +\fIallow\fR is configured for this netblock. +.TP +.B access\-control\-tag\-action: \fI<IP netblock> <tag> <action> +Set action for particular tag for given access control element. If you have +multiple tag values, the tag used to lookup the action is the first tag match +between access\-control\-tag and local\-zone\-tag where "first" comes from the +order of the define-tag values. +.TP +.B access\-control\-tag\-data: \fI<IP netblock> <tag> <"resource record string"> +Set redirect data for particular tag for given access control element. +.TP +.B access\-control\-view: \fI<IP netblock> <view name> +Set view for given access control element. +.TP .B chroot: \fI<directory> If chroot is enabled, you should pass the configfile (from the commandline) as a full path from the original root. After the @@ -431,6 +481,10 @@ requires privileges, then a reload will fail; a restart is needed. .TP .B directory: \fI<directory> Sets the working directory for the program. Default is "@UNBOUND_RUN_DIR@". +On Windows the string "%EXECUTABLE%" tries to change to the directory +that unbound.exe resides in. +If you give a server: directory: dir before include: file statements +then those includes can be relative to the working directory. .TP .B logfile: \fI<filename> If "" is given, logging goes to stderr, or nowhere once daemonized. @@ -449,6 +503,13 @@ The log facility LOG_DAEMON is used, with identity "unbound". The logfile setting is overridden when use\-syslog is turned on. The default is to log to syslog. .TP +.B log\-identity: \fI<string> +If "" is given (default), then the name of the executable, usually "unbound" +is used to report to the log. Enter a string to override it +with that, which is useful on systems that run more than one instance of +unbound, with different configurations, so that the logs can be easily +distinguished against. +.TP .B log\-time\-ascii: \fI<yes or no> Sets logfile lines to use a timestamp in UTC ascii. Default is no, which prints the seconds since 1970 in brackets. No effect if using syslog, in @@ -460,6 +521,13 @@ name, type and class. 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\-replies: \fI<yes or no> +Prints one line per reply to the log, with the log timestamp and IP address, +name, type, class, return code, time to resolve, from cache and response size. +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 pidfile: \fI<filename> The process id is written to the file. Default is to not write to a file. .TP @@ -523,14 +591,15 @@ unsigned to badly signed often. If turned off you run the risk of a downgrade attack that disables security for a zone. Default is on. .TP .B harden\-below\-nxdomain: \fI<yes or no> -From draft\-vixie\-dnsext\-resimprove, returns nxdomain to queries for a name +From RFC 8020 (with title "NXDOMAIN: There Really Is Nothing Underneath"), +returns nxdomain to queries for a name below another name that is already known to be nxdomain. DNSSEC mandates 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. -Currently, draft\-ietf\-dnsop\-nxdomain\-cut promotes this technique. +The nxdomain must be secure, this means nsec3 with optout is insufficient. .TP .B harden\-referral\-path: \fI<yes or no> Harden the referral path by performing additional queries for @@ -567,8 +636,15 @@ Can be given multiple times, for different domains. .B qname\-minimisation: \fI<yes or no> Send minimum amount of information to upstream servers to enhance privacy. Only sent minimum required labels of the QNAME and set QTYPE to NS when -possible. Best effort approach, full QNAME and original QTYPE will be sent when -upstream replies with a RCODE other than NOERROR. Default is off. +possible. Best effort approach; full QNAME and original QTYPE will be sent when +upstream replies with a RCODE other than NOERROR, except when receiving +NXDOMAIN from a DNSSEC signed zone. Default is off. +.TP +.B qname\-minimisation\-strict: \fI<yes or no> +QNAME minimisation in strict mode. Do not fall-back to sending full QNAME to +potentially broken nameservers. A lot of domains will not be resolvable when +this option in enabled. Only use if you know what you are doing. +This option only has effect when qname-minimisation is enabled. Default is off. .TP .B private\-address: \fI<IP address or subnet> Give IPv4 of IPv6 addresses or classless subnets. These are addresses @@ -768,6 +844,11 @@ servers that set the CD flag but cannot validate DNSSEC themselves are the clients, and then unbound provides them with DNSSEC protection. The default value is "no". .TP +.B serve\-expired: \fI<yes or no> +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 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 @@ -836,6 +917,7 @@ address space are not validated. This is usually required whenever Configure a local zone. The type determines the answer to give if there is no match from local\-data. The types are deny, refuse, static, transparent, redirect, nodefault, typetransparent, inform, inform_deny, +always_transparent, always_refuse, always_nxdomain, and are explained below. After that the default settings are listed. Use local\-data: to enter data into the local zone. Answers for local zones are authoritative DNS answers. By default the zones are class IN. @@ -886,16 +968,25 @@ queries for www.example.com and www.foo.example.com are redirected, so that users with web browsers cannot access sites with suffix example.com. .TP 10 \h'5'\fIinform\fR -The query is answered normally. The client IP address (@portnumber) -is printed to the logfile. The log message is: timestamp, unbound-pid, -info: zonename inform IP@port queryname type class. This option can be -used for normal resolution, but machines looking up infected names are -logged, eg. to run antivirus on them. +The query is answered normally, same as transparent. The client IP +address (@portnumber) is printed to the logfile. The log message is: +timestamp, unbound-pid, info: zonename inform IP@port queryname type +class. This option can be used for normal resolution, but machines +looking up infected names are logged, eg. to run antivirus on them. .TP 10 \h'5'\fIinform_deny\fR The query is dropped, like 'deny', and logged, like 'inform'. Ie. find infected machines without answering the queries. .TP 10 +\h'5'\fIalways_transparent\fR +Like transparent, but ignores local data and resolves normally. +.TP 10 +\h'5'\fIalways_refuse\fR +Like refuse, but ignores local data and refuses the query. +.TP 10 +\h'5'\fIalways_nxdomain\fR +Like static, but ignores local data and returns nxdomain for the query. +.TP 10 \h'5'\fInodefault\fR Used to turn off default contents for AS112 zones. The other types also turn off default contents for the zone. The 'nodefault' option @@ -1013,6 +1104,18 @@ Configure local data shorthand for a PTR record with the reversed IPv4 or IPv6 address and the host name. For example "192.0.2.4 www.example.com". TTL can be inserted like this: "2001:DB8::4 7200 www.example.com" .TP 5 +.B local\-zone\-tag: \fI<zone> <"list of tags"> +Assign tags to localzones. Tagged localzones will only be applied when the +used access-control element has a matching tag. Tags must be defined in +\fIdefine\-tags\fR. Enclose list of tags in quotes ("") and put spaces between +tags. +.TP 5 +.B local\-zone\-override: \fI<zone> <IP netblock> <type> +Override the localzone type for queries from addresses matching netblock. +Use this localzone type, regardless the type configured for the local-zone +(both tagged and untagged) and regardless the type configured using +access\-control\-tag\-action. +.TP 5 .B ratelimit: \fI<number or 0> Enable ratelimiting of queries sent to nameserver for performing recursion. If 0, the default, it is disabled. This option is experimental at this time. @@ -1057,6 +1160,34 @@ in different parts of the namespace. The closest matching suffix is used to determine the qps limit. The rate for the exact matching domain name is not changed, use ratelimit\-for\-domain to set that, you might want to use different settings for a top\-level\-domain and subdomains. +.TP 5 +.B ip\-ratelimit: \fI<number or 0> +Enable global ratelimiting of queries accepted per ip address. +If 0, the default, it is disabled. This option is experimental at this time. +The ratelimit is in queries per second that are allowed. More queries are +completely dropped and will not receive a reply, SERVFAIL or otherwise. +IP ratelimiting happens before looking in the cache. This may be useful for +mitigating amplification attacks. +.TP 5 +.B ip\-ratelimit\-size: \fI<memory size> +Give the size of the data structure in which the current ongoing rates are +kept track in. Default 4m. In bytes or use m(mega), k(kilo), g(giga). +The ip ratelimit structure is small, so this data structure likely does +not need to be large. +.TP 5 +.B ip\-ratelimit\-slabs: \fI<number> +Give power of 2 number of slabs, this is used to reduce lock contention +in the ip ratelimit tracking data structure. Close to the number of cpus is +a fairly good setting. +.TP 5 +.B ip\-ratelimit\-factor: \fI<number> +Set the amount of queries to rate limit when the limit is exceeded. +If set to 0, all queries are dropped for addresses where the limit is +exceeded. If set to another value, 1 in that number is allowed through +to complete. Default is 10, allowing 1/10 traffic to flow normally. +This can make ordinary queries complete (if repeatedly queried for), +and enter the cache, whilst also mitigating the traffic flow by the +factor given. .SS "Remote Control Options" In the .B remote\-control: @@ -1167,6 +1298,10 @@ If enabled, a query is attempted without the stub clause if it fails. The data could not be retrieved and would have caused SERVFAIL because the servers are unreachable, instead it is tried without this clause. The default is no. +.TP +.B stub\-ssl\-upstream: \fI<yes or no> +Enabled or disable whether the queries to this stub use SSL for transport. +Default is no. .SS "Forward Zone Options" .LP There may be multiple @@ -1197,6 +1332,36 @@ If enabled, a query is attempted without the forward clause if it fails. The data could not be retrieved and would have caused SERVFAIL because the servers are unreachable, instead it is tried without this clause. The default is no. +.TP +.B forward\-ssl\-upstream: \fI<yes or no> +Enabled or disable whether the queries to this forwarder use SSL for transport. +Default is no. +.SS "View Options" +.LP +There may be multiple +.B view: +clauses. Each with a \fBname:\fR and zero or more \fBlocal\-zone\fR and +\fBlocal\-data\fR elements. View can be mapped to requests by specifying the view +name in an \fBaccess\-control\-view\fR element. Options from matching views will +override global options. Global options will be used if no matching view +is found. +.TP +.B name: \fI<view name> +Name of the view. Must be unique. This name is used in access\-control\-view +elements. +.TP +.B local\-zone: \fI<zone> <type> +View specific local\-zone elements. Has the same types and behaviour as the +global local\-zone elements. +.TP +.B local\-data: \fI"<resource record string>" +View specific local\-data elements. Has the same behaviour as the global +local\-data elements. +.TP +.B view\-first: \fI<yes or no> +If enabled, it attempts to use the global local\-zone and local\-data if there +is no match in the view specific options. +The default is no. .SS "Python Module Options" .LP The @@ -1206,9 +1371,15 @@ acts like the iterator and validator modules do, on queries and answers. To enable the script module it has to be compiled into the daemon, and the word "python" has to be put in the \fBmodule\-config:\fR option (usually first, or between the validator and iterator). +.LP +If the \fBchroot:\fR option is enabled, you should make sure Python's +library directory structure is bind mounted in the new root environment, see +\fImount\fR(8). Also the \fBpython\-script:\fR path should be specified as an +absolute path relative to the new root, or as a relative path to the working +directory. .TP .B python\-script: \fI<python file>\fR -The script file to load. +The script file to load. .SS "DNS64 Module Options" .LP The dns64 module must be configured in the \fBmodule\-config:\fR "dns64 diff --git a/usr.sbin/unbound/doc/unbound.doxygen b/usr.sbin/unbound/doc/unbound.doxygen index b32316b72a4..fe39876816b 100644 --- a/usr.sbin/unbound/doc/unbound.doxygen +++ b/usr.sbin/unbound/doc/unbound.doxygen @@ -287,7 +287,7 @@ TYPEDEF_HIDES_STRUCT = NO # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols -SYMBOL_CACHE_SIZE = 0 +#SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options @@ -487,7 +487,7 @@ SHOW_USED_FILES = YES # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. -SHOW_DIRECTORIES = YES +#SHOW_DIRECTORIES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the @@ -623,7 +623,9 @@ EXCLUDE = ./build \ pythonmod/examples/resip.py \ libunbound/python/unbound.py \ libunbound/python/libunbound_wrap.c \ - ./ldns-src + ./ldns-src \ + doc/control_proto_spec.txt \ + doc/requirements.txt # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded @@ -862,7 +864,7 @@ HTML_TIMESTAMP = YES # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. -HTML_ALIGN_MEMBERS = YES +#HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the @@ -1047,7 +1049,7 @@ GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. -USE_INLINE_TREES = NO +#USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree @@ -1272,13 +1274,13 @@ XML_OUTPUT = xml # which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +#XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +#XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting @@ -1497,7 +1499,7 @@ HAVE_DOT = NO # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. -DOT_FONTNAME = FreeSans.ttf +#DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. diff --git a/usr.sbin/unbound/iterator/iter_delegpt.c b/usr.sbin/unbound/iterator/iter_delegpt.c index f49048d5c26..ecf88b293da 100644 --- a/usr.sbin/unbound/iterator/iter_delegpt.c +++ b/usr.sbin/unbound/iterator/iter_delegpt.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -47,6 +47,8 @@ #include "util/data/packed_rrset.h" #include "util/data/msgreply.h" #include "util/net_help.h" +#include "sldns/rrdef.h" +#include "sldns/sbuffer.h" struct delegpt* delegpt_create(struct regional* region) @@ -70,8 +72,9 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) return NULL; copy->bogus = dp->bogus; copy->has_parent_side_NS = dp->has_parent_side_NS; + copy->ssl_upstream = dp->ssl_upstream; for(ns = dp->nslist; ns; ns = ns->next) { - if(!delegpt_add_ns(copy, region, ns->name, (int)ns->lame)) + if(!delegpt_add_ns(copy, region, ns->name, ns->lame)) return NULL; copy->nslist->resolved = ns->resolved; copy->nslist->got4 = ns->got4; @@ -90,6 +93,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region) int delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name) { + log_assert(!dp->dp_type_mlc); dp->namelabs = dname_count_size_labels(name, &dp->namelen); dp->name = regional_alloc_init(region, name, dp->namelen); return dp->name != 0; @@ -97,11 +101,12 @@ delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name) int delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, - int lame) + uint8_t lame) { struct delegpt_ns* ns; size_t len; (void)dname_count_size_labels(name, &len); + log_assert(!dp->dp_type_mlc); /* slow check for duplicates to avoid counting failures when * adding the same server as a dependency twice */ if(delegpt_find_ns(dp, name, len)) @@ -117,10 +122,10 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name, ns->resolved = 0; ns->got4 = 0; ns->got6 = 0; - ns->lame = (uint8_t)lame; + ns->lame = lame; ns->done_pside4 = 0; ns->done_pside6 = 0; - return 1; + return ns->name != 0; } struct delegpt_ns* @@ -143,7 +148,9 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, { struct delegpt_addr* p = dp->target_list; while(p) { - if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0) { + if(sockaddr_cmp_addr(addr, addrlen, &p->addr, p->addrlen)==0 + && ((struct sockaddr_in*)addr)->sin_port == + ((struct sockaddr_in*)&p->addr)->sin_port) { return p; } p = p->next_target; @@ -154,9 +161,10 @@ delegpt_find_addr(struct delegpt* dp, struct sockaddr_storage* addr, int delegpt_add_target(struct delegpt* dp, struct regional* region, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, int bogus, int lame) + socklen_t addrlen, uint8_t bogus, uint8_t lame) { struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); + log_assert(!dp->dp_type_mlc); if(!ns) { /* ignore it */ return 1; @@ -173,10 +181,11 @@ delegpt_add_target(struct delegpt* dp, struct regional* region, int delegpt_add_addr(struct delegpt* dp, struct regional* region, - struct sockaddr_storage* addr, socklen_t addrlen, int bogus, - int lame) + struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, + uint8_t lame) { struct delegpt_addr* a; + log_assert(!dp->dp_type_mlc); /* check for duplicates */ if((a = delegpt_find_addr(dp, addr, addrlen))) { if(bogus) @@ -200,6 +209,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region, a->attempts = 0; a->bogus = bogus; a->lame = lame; + a->dnsseclame = 0; return 1; } @@ -372,17 +382,18 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region) int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ns_rrset, int lame) + struct ub_packed_rrset_key* ns_rrset, uint8_t lame) { struct packed_rrset_data* nsdata = (struct packed_rrset_data*) ns_rrset->entry.data; size_t i; + log_assert(!dp->dp_type_mlc); if(nsdata->security == sec_status_bogus) dp->bogus = 1; for(i=0; i<nsdata->count; i++) { if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != - (size_t)ldns_read_uint16(nsdata->rr_data[i])) + (size_t)sldns_read_uint16(nsdata->rr_data[i])) continue; /* bad format */ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame)) @@ -393,12 +404,13 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, int lame) + struct ub_packed_rrset_key* ak, uint8_t lame) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; struct sockaddr_in sa; socklen_t len = (socklen_t)sizeof(sa); + log_assert(!dp->dp_type_mlc); memset(&sa, 0, len); sa.sin_family = AF_INET; sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT); @@ -416,12 +428,13 @@ delegpt_add_rrset_A(struct delegpt* dp, struct regional* region, int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* ak, int lame) + struct ub_packed_rrset_key* ak, uint8_t lame) { struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data; size_t i; struct sockaddr_in6 sa; socklen_t len = (socklen_t)sizeof(sa); + log_assert(!dp->dp_type_mlc); memset(&sa, 0, len); sa.sin6_family = AF_INET6; sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT); @@ -439,7 +452,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region, int delegpt_add_rrset(struct delegpt* dp, struct regional* region, - struct ub_packed_rrset_key* rrset, int lame) + struct ub_packed_rrset_key* rrset, uint8_t lame) { if(!rrset) return 1; @@ -492,3 +505,144 @@ void delegpt_no_ipv4(struct delegpt* dp) ns->resolved = 1; } } + +struct delegpt* delegpt_create_mlc(uint8_t* name) +{ + struct delegpt* dp=(struct delegpt*)calloc(1, sizeof(*dp)); + if(!dp) + return NULL; + dp->dp_type_mlc = 1; + if(name) { + dp->namelabs = dname_count_size_labels(name, &dp->namelen); + dp->name = memdup(name, dp->namelen); + if(!dp->name) { + free(dp); + return NULL; + } + } + return dp; +} + +void delegpt_free_mlc(struct delegpt* dp) +{ + struct delegpt_ns* n, *nn; + struct delegpt_addr* a, *na; + if(!dp) return; + log_assert(dp->dp_type_mlc); + n = dp->nslist; + while(n) { + nn = n->next; + free(n->name); + free(n); + n = nn; + } + a = dp->target_list; + while(a) { + na = a->next_target; + free(a); + a = na; + } + free(dp->name); + free(dp); +} + +int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name) +{ + log_assert(dp->dp_type_mlc); + dp->namelabs = dname_count_size_labels(name, &dp->namelen); + dp->name = memdup(name, dp->namelen); + return (dp->name != NULL); +} + +int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame) +{ + struct delegpt_ns* ns; + size_t len; + (void)dname_count_size_labels(name, &len); + log_assert(dp->dp_type_mlc); + /* slow check for duplicates to avoid counting failures when + * adding the same server as a dependency twice */ + if(delegpt_find_ns(dp, name, len)) + return 1; + ns = (struct delegpt_ns*)malloc(sizeof(struct delegpt_ns)); + if(!ns) + return 0; + ns->namelen = len; + ns->name = memdup(name, ns->namelen); + if(!ns->name) { + free(ns); + return 0; + } + ns->next = dp->nslist; + dp->nslist = ns; + ns->resolved = 0; + ns->got4 = 0; + ns->got6 = 0; + ns->lame = (uint8_t)lame; + ns->done_pside4 = 0; + ns->done_pside6 = 0; + return 1; +} + +int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t bogus, uint8_t lame) +{ + struct delegpt_addr* a; + log_assert(dp->dp_type_mlc); + /* check for duplicates */ + if((a = delegpt_find_addr(dp, addr, addrlen))) { + if(bogus) + a->bogus = bogus; + if(!lame) + a->lame = 0; + return 1; + } + + a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr)); + if(!a) + return 0; + a->next_target = dp->target_list; + dp->target_list = a; + a->next_result = 0; + a->next_usable = dp->usable_list; + dp->usable_list = a; + memcpy(&a->addr, addr, addrlen); + a->addrlen = addrlen; + a->attempts = 0; + a->bogus = bogus; + a->lame = lame; + a->dnsseclame = 0; + return 1; +} + +int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, + struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, + uint8_t lame) +{ + struct delegpt_ns* ns = delegpt_find_ns(dp, name, namelen); + log_assert(dp->dp_type_mlc); + if(!ns) { + /* ignore it */ + return 1; + } + if(!lame) { + if(addr_is_ip6(addr, addrlen)) + ns->got6 = 1; + else ns->got4 = 1; + if(ns->got4 && ns->got6) + ns->resolved = 1; + } + return delegpt_add_addr_mlc(dp, addr, addrlen, bogus, lame); +} + +size_t delegpt_get_mem(struct delegpt* dp) +{ + struct delegpt_ns* ns; + size_t s; + if(!dp) return 0; + s = sizeof(*dp) + dp->namelen + + delegpt_count_targets(dp)*sizeof(struct delegpt_addr); + for(ns=dp->nslist; ns; ns=ns->next) + s += sizeof(*ns)+ns->namelen; + return s; +} diff --git a/usr.sbin/unbound/iterator/iter_delegpt.h b/usr.sbin/unbound/iterator/iter_delegpt.h index c4ca62dc44d..4bd79c81af0 100644 --- a/usr.sbin/unbound/iterator/iter_delegpt.h +++ b/usr.sbin/unbound/iterator/iter_delegpt.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -79,6 +79,10 @@ struct delegpt { * Also true if the delegationpoint was created from a delegation * message and thus contains the parent-side-info already. */ uint8_t has_parent_side_NS; + /** for assertions on type of delegpt */ + uint8_t dp_type_mlc; + /** use SSL for upstream query */ + uint8_t ssl_upstream; }; /** @@ -138,9 +142,13 @@ struct delegpt_addr { int sel_rtt; /** if true, the A or AAAA RR was bogus, so this address is bad. * Also check the dp->bogus to see if everything is bogus. */ - int bogus; + uint8_t bogus; /** if true, this address is dispreferred: it is a lame IP address */ - int lame; + uint8_t lame; + /** if the address is dnsseclame, but this cannot be cached, this + * option is useful to mark the address dnsseclame. + * This value is not copied in addr-copy and dp-copy. */ + uint8_t dnsseclame; }; /** @@ -177,7 +185,7 @@ int delegpt_set_name(struct delegpt* dp, struct regional* regional, * @return false on error. */ int delegpt_add_ns(struct delegpt* dp, struct regional* regional, - uint8_t* name, int lame); + uint8_t* name, uint8_t lame); /** * Add NS rrset; calls add_ns repeatedly. @@ -188,7 +196,7 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional, * @return 0 on alloc error. */ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* ns_rrset, int lame); + struct ub_packed_rrset_key* ns_rrset, uint8_t lame); /** * Add target address to the delegation point. @@ -205,7 +213,7 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional, */ int delegpt_add_target(struct delegpt* dp, struct regional* regional, uint8_t* name, size_t namelen, struct sockaddr_storage* addr, - socklen_t addrlen, int bogus, int lame); + socklen_t addrlen, uint8_t bogus, uint8_t lame); /** * Add A RRset to delegpt. @@ -216,7 +224,7 @@ int delegpt_add_target(struct delegpt* dp, struct regional* regional, * @return 0 on alloc error. */ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, int lame); + struct ub_packed_rrset_key* rrset, uint8_t lame); /** * Add AAAA RRset to delegpt. @@ -227,7 +235,7 @@ int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional, * @return 0 on alloc error. */ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, int lame); + struct ub_packed_rrset_key* rrset, uint8_t lame); /** * Add any RRset to delegpt. @@ -239,7 +247,7 @@ int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional, * @return 0 on alloc error. */ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, - struct ub_packed_rrset_key* rrset, int lame); + struct ub_packed_rrset_key* rrset, uint8_t lame); /** * Add address to the delegation point. No servername is associated or checked. @@ -252,7 +260,8 @@ int delegpt_add_rrset(struct delegpt* dp, struct regional* regional, * @return false on error. */ int delegpt_add_addr(struct delegpt* dp, struct regional* regional, - struct sockaddr_storage* addr, socklen_t addrlen, int bogus, int lame); + struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t bogus, uint8_t lame); /** * Find NS record in name list of delegation point. @@ -346,4 +355,65 @@ void delegpt_no_ipv6(struct delegpt* dp); */ void delegpt_no_ipv4(struct delegpt* dp); +/** + * create malloced delegation point, with the given name + * @param name: uncompressed wireformat of delegpt name. + * @return NULL on alloc failure + */ +struct delegpt* delegpt_create_mlc(uint8_t* name); + +/** + * free malloced delegation point. + * @param dp: must have been created with delegpt_create_mlc, free'd. + */ +void delegpt_free_mlc(struct delegpt* dp); + +/** + * Set name of delegation point. + * @param dp: delegation point. malloced. + * @param name: name to use. + * @return false on error. + */ +int delegpt_set_name_mlc(struct delegpt* dp, uint8_t* name); + +/** + * add a name to malloced delegation point. + * @param dp: must have been created with delegpt_create_mlc. + * @param name: the name to add. + * @param lame: the name is lame, disprefer. + * @return false on error. + */ +int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame); + +/** + * add an address to a malloced delegation point. + * @param dp: must have been created with delegpt_create_mlc. + * @param addr: the address. + * @param addrlen: the length of addr. + * @param bogus: if address is bogus. + * @param lame: if address is lame. + * @return false on error. + */ +int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t bogus, uint8_t lame); + +/** + * Add target address to the delegation point. + * @param dp: must have been created with delegpt_create_mlc. + * @param name: name for which target was found (must be in nslist). + * This name is marked resolved. + * @param namelen: length of name. + * @param addr: the address. + * @param addrlen: the length of addr. + * @param bogus: security status for the address, pass true if bogus. + * @param lame: address is lame. + * @return false on error. + */ +int delegpt_add_target_mlc(struct delegpt* dp, uint8_t* name, size_t namelen, + struct sockaddr_storage* addr, socklen_t addrlen, uint8_t bogus, + uint8_t lame); + +/** get memory in use by dp */ +size_t delegpt_get_mem(struct delegpt* dp); + #endif /* ITERATOR_ITER_DELEGPT_H */ diff --git a/usr.sbin/unbound/iterator/iter_donotq.h b/usr.sbin/unbound/iterator/iter_donotq.h index 4c4fcb289dc..14105073aa3 100644 --- a/usr.sbin/unbound/iterator/iter_donotq.h +++ b/usr.sbin/unbound/iterator/iter_donotq.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -58,7 +58,7 @@ struct iter_donotq { * contents of type addr_tree_node. Each node is an address span * that must not be used to send queries to. */ - rbtree_t tree; + rbtree_type tree; }; /** diff --git a/usr.sbin/unbound/iterator/iter_fwd.c b/usr.sbin/unbound/iterator/iter_fwd.c index 3e580ca3551..0ba6c6ddfa9 100644 --- a/usr.sbin/unbound/iterator/iter_fwd.c +++ b/usr.sbin/unbound/iterator/iter_fwd.c @@ -82,7 +82,7 @@ static void fwd_zone_free(struct iter_forward_zone* n) free(n); } -static void delfwdnode(rbnode_t* n, void* ATTR_UNUSED(arg)) +static void delfwdnode(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct iter_forward_zone* node = (struct iter_forward_zone*)n; fwd_zone_free(node); @@ -265,6 +265,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; + /* use SSL for queries to this forwarder */ + dp->ssl_upstream = (uint8_t)s->ssl_upstream; verbose(VERB_QUERY, "Forward zone server list:"); delegpt_log(VERB_QUERY, dp); if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp)) @@ -330,7 +332,7 @@ forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg) struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) { - rbnode_t* res = NULL; + rbnode_type* res = NULL; struct iter_forward_zone key; key.node.key = &key; key.dclass = qclass; @@ -345,7 +347,7 @@ struct delegpt* forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass) { /* lookup the forward zone in the tree */ - rbnode_t* res = NULL; + rbnode_type* res = NULL; struct iter_forward_zone *result; struct iter_forward_zone key; key.node.key = &key; @@ -386,7 +388,7 @@ int forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass) { struct iter_forward_zone key; - rbnode_t* n; + rbnode_type* n; struct iter_forward_zone* p; if(*dclass == 0) { /* first root item is first item in tree */ diff --git a/usr.sbin/unbound/iterator/iter_fwd.h b/usr.sbin/unbound/iterator/iter_fwd.h index 8f3bc1fa2f2..e90b74c16a5 100644 --- a/usr.sbin/unbound/iterator/iter_fwd.h +++ b/usr.sbin/unbound/iterator/iter_fwd.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -45,14 +45,11 @@ #include "util/rbtree.h" struct config_file; struct delegpt; -struct regional; /** * Iterator forward zones structure */ struct iter_forwards { - /** regional where forward zone server addresses are allocated */ - struct regional* region; /** * Zones are stored in this tree. Sort order is specially chosen. * first sorted on qclass. Then on dname in nsec-like order, so that @@ -60,7 +57,7 @@ struct iter_forwards { * match which gives the ancestor needed. * contents of type iter_forward_zone. */ - rbtree_t* tree; + rbtree_type* tree; }; /** @@ -68,7 +65,7 @@ struct iter_forwards { */ struct iter_forward_zone { /** redblacktree node, key is this structure: class and name */ - rbnode_t node; + rbnode_type node; /** name */ uint8_t* name; /** length of name */ @@ -77,7 +74,9 @@ struct iter_forward_zone { int namelabs; /** delegation point with forward server information for this zone. * If NULL then this forward entry is used to indicate that a - * stub-zone with the same name exists, and should be used. */ + * stub-zone with the same name exists, and should be used. + * This delegation point is malloced. + */ struct delegpt* dp; /** pointer to parent in tree (or NULL if none) */ struct iter_forward_zone* parent; @@ -106,6 +105,16 @@ void forwards_delete(struct iter_forwards* fwd); int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg); /** + * Find forward zone exactly by name + * @param fwd: forward storage. + * @param qname: The qname of the query. + * @param qclass: The qclass of the query. + * @return: A delegation point or null. + */ +struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname, + uint16_t qclass); + +/** * Find forward zone information * For this qname/qclass find forward zone information, returns delegation * point with server names and addresses, or NULL if no forwarding is needed. @@ -152,9 +161,7 @@ int fwd_cmp(const void* k1, const void* k2); * @param fwd: the forward data structure * @param c: class of zone * @param dp: delegation point with name and target nameservers for new - * forward zone. This delegation point and all its data must be - * malloced in the fwd->region. (then it is freed when the fwd is - * deleted). + * forward zone. malloced. * @return false on failure (out of memory); */ int forwards_add_zone(struct iter_forwards* fwd, uint16_t c, @@ -162,12 +169,31 @@ int forwards_add_zone(struct iter_forwards* fwd, uint16_t c, /** * Remove zone from forward structure. For external use since it - * recalcs the tree parents. Does not actually release any memory, the region - * is unchanged. + * recalcs the tree parents. * @param fwd: the forward data structure * @param c: class of zone * @param nm: name of zone (in uncompressed wireformat). */ void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); +/** + * Add stub hole (empty entry in forward table, that makes resolution skip + * a forward-zone because the stub zone should override the forward zone). + * Does not add one if not necessary. + * @param fwd: the forward data structure + * @param c: class of zone + * @param nm: name of zone (in uncompressed wireformat). + * @return false on failure (out of memory); + */ +int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm); + +/** + * Remove stub hole, if one exists. + * @param fwd: the forward data structure + * @param c: class of zone + * @param nm: name of zone (in uncompressed wireformat). + */ +void forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, + uint8_t* nm); + #endif /* ITERATOR_ITER_FWD_H */ diff --git a/usr.sbin/unbound/iterator/iter_hints.c b/usr.sbin/unbound/iterator/iter_hints.c index 217dfa2578b..74869d35547 100644 --- a/usr.sbin/unbound/iterator/iter_hints.c +++ b/usr.sbin/unbound/iterator/iter_hints.c @@ -67,7 +67,7 @@ static void hints_stub_free(struct iter_hints_stub* s) free(s); } -static void delhintnode(rbnode_t* n, void* ATTR_UNUSED(arg)) +static void delhintnode(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct iter_hints_stub* node = (struct iter_hints_stub*)n; hints_stub_free(node); @@ -147,7 +147,9 @@ compile_time_root_prime(int do_ip4, int do_ip6) if(!ah(dp, "B.ROOT-SERVERS.NET.", "2001:500:84::b")) goto failed; if(!ah(dp, "C.ROOT-SERVERS.NET.", "2001:500:2::c")) goto failed; if(!ah(dp, "D.ROOT-SERVERS.NET.", "2001:500:2d::d")) goto failed; + if(!ah(dp, "E.ROOT-SERVERS.NET.", "2001:500:a8::e")) goto failed; if(!ah(dp, "F.ROOT-SERVERS.NET.", "2001:500:2f::f")) goto failed; + if(!ah(dp, "G.ROOT-SERVERS.NET.", "2001:500:12::d0d")) goto failed; if(!ah(dp, "H.ROOT-SERVERS.NET.", "2001:500:1::53")) goto failed; if(!ah(dp, "I.ROOT-SERVERS.NET.", "2001:7fe::53")) goto failed; if(!ah(dp, "J.ROOT-SERVERS.NET.", "2001:503:c27::2:30")) goto failed; @@ -274,6 +276,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; + /* ssl_upstream */ + dp->ssl_upstream = (uint8_t)s->ssl_upstream; delegpt_log(VERB_QUERY, dp); if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, !s->isprime)) return 0; diff --git a/usr.sbin/unbound/iterator/iter_hints.h b/usr.sbin/unbound/iterator/iter_hints.h index 4540971b0a4..06b4b9667d1 100644 --- a/usr.sbin/unbound/iterator/iter_hints.h +++ b/usr.sbin/unbound/iterator/iter_hints.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -46,14 +46,11 @@ struct iter_env; struct config_file; struct delegpt; -struct regional; /** * Iterator hints structure */ struct iter_hints { - /** regional where hints are allocated */ - struct regional* region; /** * Hints are stored in this tree. Sort order is specially chosen. * first sorted on qclass. Then on dname in nsec-like order, so that @@ -62,7 +59,7 @@ struct iter_hints { * contents of type iter_hints_stub. The class IN root is in here. * uses name_tree_node from dnstree.h. */ - rbtree_t tree; + rbtree_type tree; }; /** @@ -71,7 +68,7 @@ struct iter_hints { struct iter_hints_stub { /** tree sorted by name, class */ struct name_tree_node node; - /** delegation point with hint information for this stub. */ + /** delegation point with hint information for this stub. malloced. */ struct delegpt* dp; /** does the stub need to forego priming (like on other ports) */ uint8_t noprime; @@ -139,4 +136,26 @@ struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, */ size_t hints_get_mem(struct iter_hints* hints); +/** + * Add stub to hints structure. For external use since it recalcs + * the tree parents. + * @param hints: the hints data structure + * @param c: class of zone + * @param dp: delegation point with name and target nameservers for new + * hints stub. malloced. + * @param noprime: set noprime option to true or false on new hint stub. + * @return false on failure (out of memory); + */ +int hints_add_stub(struct iter_hints* hints, uint16_t c, struct delegpt* dp, + int noprime); + +/** + * Remove stub from hints structure. For external use since it + * recalcs the tree parents. + * @param hints: the hints data structure + * @param c: class of stub zone + * @param nm: name of stub zone (in uncompressed wireformat). + */ +void hints_delete_stub(struct iter_hints* hints, uint16_t c, uint8_t* nm); + #endif /* ITERATOR_ITER_HINTS_H */ diff --git a/usr.sbin/unbound/iterator/iter_priv.h b/usr.sbin/unbound/iterator/iter_priv.h index f6264f8d0c9..0430d57e3e3 100644 --- a/usr.sbin/unbound/iterator/iter_priv.h +++ b/usr.sbin/unbound/iterator/iter_priv.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -43,7 +43,7 @@ #ifndef ITERATOR_ITER_PRIV_H #define ITERATOR_ITER_PRIV_H #include "util/rbtree.h" -#include <ldns/buffer.h> +struct sldns_buffer; struct iter_env; struct config_file; struct regional; @@ -60,14 +60,14 @@ struct iter_priv { * contents of type addr_tree_node. * No further data need, only presence or absence. */ - rbtree_t a; + rbtree_type a; /** * Tree of the domains spans that are allowed to contain * the blocked address spans. * contents of type name_tree_node. * No further data need, only presence or absence. */ - rbtree_t n; + rbtree_type n; }; /** @@ -92,12 +92,14 @@ int priv_apply_cfg(struct iter_priv* priv, struct config_file* cfg); /** * See if rrset is bad. + * Will remove individual RRs that are bad (if possible) to + * sanitize the RRset without removing it completely. * @param priv: structure for private address storage. * @param pkt: packet to decompress rrset name in. * @param rrset: the rrset to examine, A or AAAA. * @return true if the rrset is bad and should be removed. */ -int priv_rrset_bad(struct iter_priv* priv, ldns_buffer* pkt, +int priv_rrset_bad(struct iter_priv* priv, struct sldns_buffer* pkt, struct rrset_parse* rrset); /** diff --git a/usr.sbin/unbound/iterator/iter_scrub.c b/usr.sbin/unbound/iterator/iter_scrub.c index 8a3fc170c05..1bee85c0b99 100644 --- a/usr.sbin/unbound/iterator/iter_scrub.c +++ b/usr.sbin/unbound/iterator/iter_scrub.c @@ -161,8 +161,8 @@ mark_additional_rrset(sldns_buffer* pkt, struct msg_parse* msg, for(rr = rrset->rr_first; rr; rr = rr->next) { if(get_additional_name(rrset, rr, &nm, &nmlen, pkt)) { /* mark A */ - hashvalue_t h = pkt_hash_rrset(pkt, nm, LDNS_RR_TYPE_A, - rrset->rrset_class, 0); + hashvalue_type h = pkt_hash_rrset(pkt, nm, + LDNS_RR_TYPE_A, rrset->rrset_class, 0); struct rrset_parse* r = msgparse_hashtable_lookup( msg, pkt, h, 0, nm, nmlen, LDNS_RR_TYPE_A, rrset->rrset_class); diff --git a/usr.sbin/unbound/iterator/iter_utils.c b/usr.sbin/unbound/iterator/iter_utils.c index a5aefa9602c..0b1b456113f 100644 --- a/usr.sbin/unbound/iterator/iter_utils.c +++ b/usr.sbin/unbound/iterator/iter_utils.c @@ -108,7 +108,7 @@ read_fetch_policy(struct iter_env* ie, const char* str) /** apply config caps whitelist items to name tree */ static int -caps_white_apply_cfg(rbtree_t* ntree, struct config_file* cfg) +caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg) { struct config_strlist* p; for(p=cfg->caps_whitelist; p; p=p->next) { @@ -360,6 +360,39 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env, } } *selected_rtt = low_rtt; + + if (env->cfg->prefer_ip6) { + int got_num6 = 0; + int low_rtt6 = 0; + int i; + prev = NULL; + a = dp->result_list; + for(i = 0; i < got_num; i++) { + swap_to_front = 0; + if(a->addr.ss_family == AF_INET6) { + got_num6++; + swap_to_front = 1; + if(low_rtt6 == 0 || a->sel_rtt < low_rtt6) { + low_rtt6 = a->sel_rtt; + } + } + /* swap to front if IPv6, or move to next result */ + if(swap_to_front && prev) { + n = a->next_result; + prev->next_result = n; + a->next_result = dp->result_list; + dp->result_list = a; + a = n; + } else { + prev = a; + a = a->next_result; + } + } + if(got_num6 > 0) { + got_num = got_num6; + *selected_rtt = low_rtt6; + } + } return got_num; } @@ -499,6 +532,7 @@ causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen, qinf.qname_len = namelen; qinf.qtype = t; qinf.qclass = c; + qinf.local_alias = NULL; fptr_ok(fptr_whitelist_modenv_detect_cycle( qstate->env->detect_cycle)); return (*qstate->env->detect_cycle)(qstate, &qinf, diff --git a/usr.sbin/unbound/iterator/iterator.c b/usr.sbin/unbound/iterator/iterator.c index 1f5132b8282..99ce96f384e 100644 --- a/usr.sbin/unbound/iterator/iterator.c +++ b/usr.sbin/unbound/iterator/iterator.c @@ -88,7 +88,7 @@ iter_init(struct module_env* env, int id) /** delete caps_whitelist element */ static void -caps_free(struct rbnode_t* n, void* ATTR_UNUSED(d)) +caps_free(struct rbnode_type* n, void* ATTR_UNUSED(d)) { if(n) { free(((struct name_tree_node*)n)->name); @@ -230,9 +230,8 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) return; } else { /* see if the failure did get (parent-lame) info */ - if(!cache_fill_missing(super->env, - super_iq->qchase.qclass, super->region, - super_iq->dp)) + if(!cache_fill_missing(super->env, super_iq->qchase.qclass, + super->region, super_iq->dp)) log_err("out of memory adding missing"); } dpns->resolved = 1; /* mark as failed */ @@ -278,27 +277,29 @@ error_response(struct module_qstate* qstate, int id, int rcode) static int error_response_cache(struct module_qstate* qstate, int id, int rcode) { - /* store in cache */ - struct reply_info err; - if(qstate->prefetch_leeway > NORR_TTL) { - verbose(VERB_ALGO, "error response for prefetch in cache"); - /* attempt to adjust the cache entry prefetch */ - if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo, - NORR_TTL, qstate->query_flags)) - return error_response(qstate, id, rcode); - /* if that fails (not in cache), fall through to store err */ - } - memset(&err, 0, sizeof(err)); - err.flags = (uint16_t)(BIT_QR | BIT_RA); - FLAGS_SET_RCODE(err.flags, rcode); - err.qdcount = 1; - err.ttl = NORR_TTL; - err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl); - /* do not waste time trying to validate this servfail */ - err.security = sec_status_indeterminate; - verbose(VERB_ALGO, "store error response in message cache"); - iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL, - qstate->query_flags); + if(!qstate->no_cache_store) { + /* store in cache */ + struct reply_info err; + if(qstate->prefetch_leeway > NORR_TTL) { + verbose(VERB_ALGO, "error response for prefetch in cache"); + /* attempt to adjust the cache entry prefetch */ + if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo, + NORR_TTL, qstate->query_flags)) + return error_response(qstate, id, rcode); + /* if that fails (not in cache), fall through to store err */ + } + memset(&err, 0, sizeof(err)); + err.flags = (uint16_t)(BIT_QR | BIT_RA); + FLAGS_SET_RCODE(err.flags, rcode); + err.qdcount = 1; + err.ttl = NORR_TTL; + err.prefetch_ttl = PREFETCH_TTL_CALC(err.ttl); + /* do not waste time trying to validate this servfail */ + err.security = sec_status_indeterminate; + verbose(VERB_ALGO, "store error response in message cache"); + iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL, + qstate->query_flags); + } return error_response(qstate, id, rcode); } @@ -551,6 +552,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype, qinf.qname_len = qnamelen; qinf.qtype = qtype; qinf.qclass = qclass; + qinf.local_alias = NULL; /* RD should be set only when sending the query back through the INIT * state. */ @@ -968,7 +970,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, { uint8_t* delname; size_t delnamelen; - struct dns_msg* msg; + struct dns_msg* msg = NULL; log_query_info(VERB_DETAIL, "resolving", &qstate->qinfo); /* check effort */ @@ -1008,13 +1010,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, * getting older results from cache is a bad idea, no cache */ verbose(VERB_ALGO, "cache blacklisted, going to the network"); msg = NULL; - } else { + } else if(!qstate->no_cache_lookup) { msg = dns_cache_lookup(qstate->env, iq->qchase.qname, iq->qchase.qname_len, iq->qchase.qtype, iq->qchase.qclass, qstate->query_flags, qstate->region, qstate->env->scratch); if(!msg && qstate->env->neg_cache) { - /* lookup in negative cache; may result in + /* lookup in negative cache; may result in * NOERROR/NODATA or NXDOMAIN answers that need validation */ msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase, qstate->region, qstate->env->rrset_cache, @@ -1700,10 +1702,11 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* if this was a parent-side glue query itself, then store that * failure in cache. */ - if(iq->query_for_pside_glue && !iq->pside_glue) - iter_store_parentside_neg(qstate->env, &qstate->qinfo, - iq->deleg_msg?iq->deleg_msg->rep: - (iq->response?iq->response->rep:NULL)); + if(!qstate->no_cache_store && iq->query_for_pside_glue + && !iq->pside_glue) + iter_store_parentside_neg(qstate->env, &qstate->qinfo, + iq->deleg_msg?iq->deleg_msg->rep: + (iq->response?iq->response->rep:NULL)); verbose(VERB_QUERY, "out of query targets -- returning SERVFAIL"); /* fail -- no more targets, no more hope of targets, no hope @@ -1787,8 +1790,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, int tf_policy; struct delegpt_addr* target; struct outbound_entry* outq; - /* EDNS options to set on outgoing packet */ - struct edns_option* opt_list = NULL; /* NOTE: a request will encounter this state for each target it * needs to send a query to. That is, at least one per referral, @@ -2011,6 +2012,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->qinfo_out.qname_len = iq->dp->namelen; iq->qinfo_out.qtype = LDNS_RR_TYPE_A; iq->qinfo_out.qclass = iq->qchase.qclass; + iq->qinfo_out.local_alias = NULL; iq->minimise_count = 0; } @@ -2026,6 +2028,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->minimise_count++; iq->minimise_timeout_count = 0; + iter_dec_attempts(iq->dp, 1); + /* Limit number of iterations for QNAMEs with more * than MAX_MINIMISE_COUNT labels. Send first MINIMISE_ONE_LAB * labels of QNAME always individually. @@ -2066,7 +2070,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, || iq->qchase.qtype == LDNS_RR_TYPE_A))) /* Stop minimising this query, resolve "as usual" */ iq->minimisation_state = DONOT_MINIMISE_STATE; - else { + else if(!qstate->no_cache_lookup) { struct dns_msg* msg = dns_cache_lookup(qstate->env, iq->qinfo_out.qname, iq->qinfo_out.qname_len, iq->qinfo_out.qtype, iq->qinfo_out.qclass, @@ -2086,7 +2090,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* Do not increment qname, continue incrementing next * iteration */ iq->minimisation_state = MINIMISE_STATE; - else + else if(!qstate->env->cfg->qname_minimisation_strict) /* Too many time-outs detected for this QNAME and QTYPE. * We give up, disable QNAME minimisation. */ iq->minimisation_state = DONOT_MINIMISE_STATE; @@ -2104,9 +2108,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->dnssec_lame_query?" but lame_query anyway": ""); } fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query)); - outq = (*qstate->env->send_query)( - iq->qinfo_out.qname, iq->qinfo_out.qname_len, - iq->qinfo_out.qtype, iq->qinfo_out.qclass, + outq = (*qstate->env->send_query)(&iq->qinfo_out, iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), /* unset CD if to forwarder(RD set) and not dnssec retry * (blacklist nonempty) and no trust-anchors are configured @@ -2115,8 +2117,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, !qstate->blacklist&&(!iter_indicates_dnssec_fwd(qstate->env, &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( - ie, iq), opt_list, &target->addr, target->addrlen, - iq->dp->name, iq->dp->namelen, qstate); + ie, iq), &target->addr, target->addrlen, + iq->dp->name, iq->dp->namelen, + (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream), qstate); if(!outq) { log_addr(VERB_DETAIL, "error sending query to auth server", &target->addr, target->addrlen); @@ -2257,10 +2260,11 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->num_target_queries = 0; return processDSNSFind(qstate, iq, id); } - iter_dns_store(qstate->env, &iq->response->qinfo, - iq->response->rep, 0, qstate->prefetch_leeway, - iq->dp&&iq->dp->has_parent_side_NS, - qstate->region, qstate->query_flags); + if(!qstate->no_cache_store) + iter_dns_store(qstate->env, &iq->response->qinfo, + iq->response->rep, 0, qstate->prefetch_leeway, + iq->dp&&iq->dp->has_parent_side_NS, + qstate->region, qstate->query_flags); /* close down outstanding requests to be discarded */ outbound_list_clear(&iq->outlist); iq->num_current_queries = 0; @@ -2273,12 +2277,15 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, &qstate->reply->addr, qstate->reply->addrlen, qstate->region); if(iq->minimisation_state != DONOT_MINIMISE_STATE) { - /* Best effort qname-minimisation. - * Stop minimising and send full query when RCODE - * is not NOERROR. */ if(FLAGS_GET_RCODE(iq->response->rep->flags) != - LDNS_RCODE_NOERROR) + LDNS_RCODE_NOERROR) { + if(qstate->env->cfg->qname_minimisation_strict) + return final_state(iq); + /* Best effort qname-minimisation. + * Stop minimising and send full query when + * RCODE is not NOERROR. */ iq->minimisation_state = DONOT_MINIMISE_STATE; + } if(FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_NXDOMAIN) { /* Stop resolving when NXDOMAIN is DNSSEC @@ -2325,7 +2332,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, } /* if hardened, only store referral if we asked for it */ - if(!qstate->env->cfg->harden_referral_path || + if(!qstate->no_cache_store && + (!qstate->env->cfg->harden_referral_path || ( qstate->qinfo.qtype == LDNS_RR_TYPE_NS && (qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD) @@ -2340,7 +2348,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->qchase.qname, iq->qchase.qname_len, LDNS_RR_TYPE_NS, iq->qchase.qclass) ) - )) { + ))) { /* Store the referral under the current query */ /* no prefetch-leeway, since its not the answer */ iter_dns_store(qstate->env, &iq->response->qinfo, @@ -2353,16 +2361,17 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, iq->response->rep, iq->dp->name); } /* store parent-side-in-zone-glue, if directly queried for */ - if(iq->query_for_pside_glue && !iq->pside_glue) { - iq->pside_glue = reply_find_rrset(iq->response->rep, - iq->qchase.qname, iq->qchase.qname_len, - iq->qchase.qtype, iq->qchase.qclass); - if(iq->pside_glue) { - log_rrset_key(VERB_ALGO, "found parent-side " - "glue", iq->pside_glue); - iter_store_parentside_rrset(qstate->env, - iq->pside_glue); - } + if(!qstate->no_cache_store && iq->query_for_pside_glue + && !iq->pside_glue) { + iq->pside_glue = reply_find_rrset(iq->response->rep, + iq->qchase.qname, iq->qchase.qname_len, + iq->qchase.qtype, iq->qchase.qclass); + if(iq->pside_glue) { + log_rrset_key(VERB_ALGO, "found parent-side " + "glue", iq->pside_glue); + iter_store_parentside_rrset(qstate->env, + iq->pside_glue); + } } /* Reset the event state, setting the current delegation @@ -2443,10 +2452,11 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* NOTE : set referral=1, so that rrsets get stored but not * the partial query answer (CNAME only). */ /* prefetchleeway applied because this updates answer parts */ - iter_dns_store(qstate->env, &iq->response->qinfo, - iq->response->rep, 1, qstate->prefetch_leeway, - iq->dp&&iq->dp->has_parent_side_NS, NULL, - qstate->query_flags); + if(!qstate->no_cache_store) + iter_dns_store(qstate->env, &iq->response->qinfo, + iq->response->rep, 1, qstate->prefetch_leeway, + iq->dp&&iq->dp->has_parent_side_NS, NULL, + qstate->query_flags); /* set the current request's qname to the new value. */ iq->qchase.qname = sname; iq->qchase.qname_len = snamelen; @@ -2525,7 +2535,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, /* LAME, THROWAWAY and "unknown" all end up here. * Recycle to the QUERYTARGETS state to hopefully try a * different target. */ - if (qstate->env->cfg->qname_minimisation) + if (qstate->env->cfg->qname_minimisation && + !qstate->env->cfg->qname_minimisation_strict) iq->minimisation_state = DONOT_MINIMISE_STATE; return next_state(iq, QUERYTARGETS_STATE); } @@ -2925,10 +2936,11 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, &qstate->qinfo); /* store negative cache element for parent side glue. */ - if(iq->query_for_pside_glue && !iq->pside_glue) - iter_store_parentside_neg(qstate->env, &qstate->qinfo, - iq->deleg_msg?iq->deleg_msg->rep: - (iq->response?iq->response->rep:NULL)); + if(!qstate->no_cache_store && iq->query_for_pside_glue + && !iq->pside_glue) + iter_store_parentside_neg(qstate->env, &qstate->qinfo, + iq->deleg_msg?iq->deleg_msg->rep: + (iq->response?iq->response->rep:NULL)); if(!iq->response) { verbose(VERB_ALGO, "No response is set, servfail"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); @@ -2964,7 +2976,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, /* store message with the finished prepended items, * but only if we did recursion. The nonrecursion referral * from cache does not need to be stored in the msg cache. */ - if(qstate->query_flags&BIT_RD) { + if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) { iter_dns_store(qstate->env, &qstate->qinfo, iq->response->rep, 0, qstate->prefetch_leeway, iq->dp&&iq->dp->has_parent_side_NS, @@ -3139,6 +3151,18 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, if(parse_extract_edns(prs, &edns, qstate->env->scratch) != LDNS_RCODE_NOERROR) goto handle_it; + + /* Copy the edns options we may got from the back end */ + if(edns.opt_list) { + qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list, + qstate->region); + if(!qstate->edns_opts_back_in) { + log_err("out of memory on incoming message"); + /* like packet got dropped */ + goto handle_it; + } + } + /* remove CD-bit, we asked for in case we handle validation ourself */ prs->flags &= ~BIT_CD; diff --git a/usr.sbin/unbound/iterator/iterator.h b/usr.sbin/unbound/iterator/iterator.h index 5585f578958..37b0ab0dc24 100644 --- a/usr.sbin/unbound/iterator/iterator.h +++ b/usr.sbin/unbound/iterator/iterator.h @@ -51,7 +51,7 @@ struct iter_forwards; struct iter_donotq; struct iter_prep_list; struct iter_priv; -struct rbtree_t; +struct rbtree_type; /** max number of targets spawned for a query and its subqueries */ #define MAX_TARGET_COUNT 64 @@ -115,7 +115,7 @@ struct iter_env { struct iter_priv* priv; /** whitelist for capsforid names */ - struct rbtree_t* caps_white; + struct rbtree_type* caps_white; /** The maximum dependency depth that this resolver will pursue. */ int max_dependency_depth; diff --git a/usr.sbin/unbound/libunbound/context.c b/usr.sbin/unbound/libunbound/context.c index f28307971b4..e203111b70d 100644 --- a/usr.sbin/unbound/libunbound/context.c +++ b/usr.sbin/unbound/libunbound/context.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -49,6 +49,7 @@ #include "services/cache/infra.h" #include "util/data/msgreply.h" #include "util/storage/slabhash.h" +#include "sldns/sbuffer.h" int context_finalize(struct ub_ctx* ctx) @@ -61,6 +62,7 @@ context_finalize(struct ub_ctx* ctx) config_apply(cfg); if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env)) return UB_INITFAIL; + log_edns_known_options(VERB_ALGO, ctx->env); ctx->local_zones = local_zones_create(); if(!ctx->local_zones) return UB_NOMEM; @@ -124,8 +126,8 @@ find_id(struct ub_ctx* ctx, int* id) } struct ctx_query* -context_new(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, - ub_callback_t cb, void* cbarg) +context_new(struct ub_ctx* ctx, const char* name, int rrtype, int rrclass, + ub_callback_type cb, void* cbarg) { struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q)); if(!q) return NULL; @@ -220,10 +222,10 @@ context_serialize_new_query(struct ctx_query* q, uint32_t* len) *len = sizeof(uint32_t)*4 + slen; p = (uint8_t*)malloc(*len); if(!p) return NULL; - ldns_write_uint32(p, UB_LIBCMD_NEWQUERY); - ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); - ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); - ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); + sldns_write_uint32(p, UB_LIBCMD_NEWQUERY); + sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); + sldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype); + sldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass); memmove(p+4*sizeof(uint32_t), q->res->qname, slen); return p; } @@ -237,8 +239,8 @@ context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) free(q); return NULL; } - log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); - q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t)); + log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); + q->querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); q->node.key = &q->querynum; q->async = 1; q->res = (struct ub_result*)calloc(1, sizeof(*q->res)); @@ -246,8 +248,8 @@ context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) free(q); return NULL; } - q->res->qtype = (int)ldns_read_uint32(p+2*sizeof(uint32_t)); - q->res->qclass = (int)ldns_read_uint32(p+3*sizeof(uint32_t)); + q->res->qtype = (int)sldns_read_uint32(p+2*sizeof(uint32_t)); + q->res->qclass = (int)sldns_read_uint32(p+3*sizeof(uint32_t)); q->res->qname = strdup((char*)(p+4*sizeof(uint32_t))); if(!q->res->qname) { free(q->res); @@ -269,8 +271,8 @@ context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) if(len < 4*sizeof(uint32_t)+1) { return NULL; } - log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); - querynum = (int)ldns_read_uint32(p+sizeof(uint32_t)); + log_assert( sldns_read_uint32(p) == UB_LIBCMD_NEWQUERY); + querynum = (int)sldns_read_uint32(p+sizeof(uint32_t)); q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum); if(!q) { return NULL; @@ -280,7 +282,7 @@ context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len) } uint8_t* -context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt, +context_serialize_answer(struct ctx_query* q, int err, sldns_buffer* pkt, uint32_t* len) { /* answer format @@ -293,22 +295,22 @@ context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt, * o the remainder is the answer msg from resolver lookup. * remainder can be length 0. */ - size_t pkt_len = pkt?ldns_buffer_remaining(pkt):0; + 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; p = (uint8_t*)malloc(*len); if(!p) return NULL; - ldns_write_uint32(p, UB_LIBCMD_ANSWER); - ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); - ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err); - ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security); - ldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen); + 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); if(wlen > 0) memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen); if(pkt_len > 0) memmove(p+5*sizeof(uint32_t)+wlen, - ldns_buffer_begin(pkt), pkt_len); + sldns_buffer_begin(pkt), pkt_len); return p; } @@ -320,13 +322,13 @@ context_deserialize_answer(struct ub_ctx* ctx, int id; size_t wlen; if(len < 5*sizeof(uint32_t)) return NULL; - log_assert( ldns_read_uint32(p) == UB_LIBCMD_ANSWER); - id = (int)ldns_read_uint32(p+sizeof(uint32_t)); + 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)ldns_read_uint32(p+2*sizeof(uint32_t)); - q->msg_security = ldns_read_uint32(p+3*sizeof(uint32_t)); - wlen = (size_t)ldns_read_uint32(p+4*sizeof(uint32_t)); + *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->why_bogus = (char*)memdup( @@ -359,11 +361,11 @@ context_serialize_cancel(struct ctx_query* q, uint32_t* len) /* format of cancel: * o uint32 cmd * o uint32 async-id */ - uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t)); + uint8_t* p = (uint8_t*)reallocarray(NULL, sizeof(uint32_t), 2); if(!p) return NULL; *len = 2*sizeof(uint32_t); - ldns_write_uint32(p, UB_LIBCMD_CANCEL); - ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); + sldns_write_uint32(p, UB_LIBCMD_CANCEL); + sldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum); return p; } @@ -373,8 +375,8 @@ struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx, struct ctx_query* q; int id; if(len != 2*sizeof(uint32_t)) return NULL; - log_assert( ldns_read_uint32(p) == UB_LIBCMD_CANCEL); - id = (int)ldns_read_uint32(p+sizeof(uint32_t)); + log_assert( sldns_read_uint32(p) == UB_LIBCMD_CANCEL); + id = (int)sldns_read_uint32(p+sizeof(uint32_t)); q = (struct ctx_query*)rbtree_search(&ctx->queries, &id); return q; } @@ -386,7 +388,7 @@ context_serialize_quit(uint32_t* len) if(!p) return NULL; *len = sizeof(uint32_t); - ldns_write_uint32(p, UB_LIBCMD_QUIT); + sldns_write_uint32(p, UB_LIBCMD_QUIT); return p; } @@ -395,6 +397,6 @@ enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len) uint32_t v; if((size_t)len < sizeof(v)) return UB_LIBCMD_QUIT; - v = ldns_read_uint32(p); + v = sldns_read_uint32(p); return v; } diff --git a/usr.sbin/unbound/libunbound/context.h b/usr.sbin/unbound/libunbound/context.h index d32c0b00aa0..1761c4d8721 100644 --- a/usr.sbin/unbound/libunbound/context.h +++ b/usr.sbin/unbound/libunbound/context.h @@ -61,17 +61,17 @@ struct ub_event_base; struct ub_ctx { /* --- pipes --- */ /** mutex on query write pipe */ - lock_basic_t qqpipe_lock; + lock_basic_type qqpipe_lock; /** the query write pipe */ struct tube* qq_pipe; /** mutex on result read pipe */ - lock_basic_t rrpipe_lock; + lock_basic_type rrpipe_lock; /** the result read pipe */ struct tube* rr_pipe; /* --- shared data --- */ /** mutex for access to env.cfg, finalized and dothread */ - lock_basic_t cfglock; + lock_basic_type cfglock; /** * The context has been finalized * This is after config when the first resolve is done. @@ -84,7 +84,7 @@ struct ub_ctx { /** pid of bg worker process */ pid_t bg_pid; /** tid of bg worker thread */ - ub_thread_t bg_tid; + ub_thread_type bg_tid; /** do threading (instead of forking) for async resolution */ int dothread; @@ -129,7 +129,7 @@ struct ub_ctx { * Used to see if querynum is free for use. * Content of type ctx_query. */ - rbtree_t queries; + rbtree_type queries; }; /** @@ -140,7 +140,7 @@ struct ub_ctx { */ struct ctx_query { /** node in rbtree, must be first entry, key is ptr to the querynum */ - struct rbnode_t node; + struct rbnode_type node; /** query id number, key for node */ int querynum; /** was this an async query? */ @@ -149,7 +149,7 @@ struct ctx_query { int cancelled; /** for async query, the callback function */ - ub_callback_t cb; + ub_callback_type cb; /** for async query, the callback user arg */ void* cb_arg; @@ -242,7 +242,7 @@ void context_query_delete(struct ctx_query* q); * @return new ctx_query or NULL for malloc failure. */ struct ctx_query* context_new(struct ub_ctx* ctx, const char* name, int rrtype, - int rrclass, ub_callback_t cb, void* cbarg); + int rrclass, ub_callback_type cb, void* cbarg); /** * Get a new alloc. Creates a new one or uses a cached one. diff --git a/usr.sbin/unbound/libunbound/libunbound.c b/usr.sbin/unbound/libunbound/libunbound.c index 69ccb08f45c..727b2752201 100644 --- a/usr.sbin/unbound/libunbound/libunbound.c +++ b/usr.sbin/unbound/libunbound/libunbound.c @@ -132,6 +132,15 @@ static struct ub_ctx* ub_ctx_create_nopipe(void) errno = ENOMEM; return NULL; } + /* init edns_known_options */ + if(!edns_known_options_init(ctx->env)) { + config_delete(ctx->env->cfg); + free(ctx->env); + ub_randfree(ctx->seed_rnd); + free(ctx); + errno = ENOMEM; + return NULL; + } ctx->env->alloc = &ctx->superalloc; ctx->env->worker = NULL; ctx->env->need_to_validate = 0; @@ -151,6 +160,7 @@ ub_ctx_create(void) ub_randfree(ctx->seed_rnd); config_delete(ctx->env->cfg); modstack_desetup(&ctx->mods, ctx->env); + edns_known_options_delete(ctx->env); free(ctx->env); free(ctx); errno = e; @@ -162,6 +172,7 @@ ub_ctx_create(void) ub_randfree(ctx->seed_rnd); config_delete(ctx->env->cfg); modstack_desetup(&ctx->mods, ctx->env); + edns_known_options_delete(ctx->env); free(ctx->env); free(ctx); errno = e; @@ -204,7 +215,7 @@ ub_ctx_create_event(struct event_base* eb) /** delete q */ static void -delq(rbnode_t* n, void* ATTR_UNUSED(arg)) +delq(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct ctx_query* q = (struct ctx_query*)n; context_query_delete(q); @@ -298,6 +309,8 @@ ub_ctx_delete(struct ub_ctx* ctx) rrset_cache_delete(ctx->env->rrset_cache); infra_delete(ctx->env->infra_cache); config_delete(ctx->env->cfg); + edns_known_options_delete(ctx->env); + inplace_cb_lists_delete(ctx->env); free(ctx->env); } ub_randfree(ctx->seed_rnd); @@ -487,7 +500,7 @@ ub_fd(struct ub_ctx* ctx) /** process answer from bg worker */ static int process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len, - ub_callback_t* cb, void** cbarg, int* err, + ub_callback_type* cb, void** cbarg, int* err, struct ub_result** res) { struct ctx_query* q; @@ -554,7 +567,7 @@ static int process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len) { int err; - ub_callback_t cb; + ub_callback_type cb; void* cbarg; struct ub_result* res; int r; @@ -597,7 +610,7 @@ int ub_wait(struct ub_ctx* ctx) { int err; - ub_callback_t cb; + ub_callback_type cb; void* cbarg; struct ub_result* res; int r; @@ -693,7 +706,8 @@ ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, int ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, - int rrclass, void* mydata, ub_event_callback_t callback, int* async_id) + int rrclass, void* mydata, ub_event_callback_type callback, + int* async_id) { struct ctx_query* q; int r; @@ -721,7 +735,7 @@ ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, ub_comm_base_now(ctx->event_worker->base); /* create new ctx_query and attempt to add to the list */ - q = context_new(ctx, name, rrtype, rrclass, (ub_callback_t)callback, + q = context_new(ctx, name, rrtype, rrclass, (ub_callback_type)callback, mydata); if(!q) return UB_NOMEM; @@ -735,7 +749,7 @@ ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, - int rrclass, void* mydata, ub_callback_t callback, int* async_id) + int rrclass, void* mydata, ub_callback_type callback, int* async_id) { struct ctx_query* q; uint8_t* msg = NULL; diff --git a/usr.sbin/unbound/libunbound/libworker.c b/usr.sbin/unbound/libunbound/libworker.c index 2af392706b6..b42ba0bd8e7 100644 --- a/usr.sbin/unbound/libunbound/libworker.c +++ b/usr.sbin/unbound/libunbound/libworker.c @@ -573,10 +573,12 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q, { qinfo->qtype = (uint16_t)q->res->qtype; qinfo->qclass = (uint16_t)q->res->qclass; + qinfo->local_alias = NULL; qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len); if(!qinfo->qname) { return 0; } + qinfo->local_alias = NULL; edns->edns_present = 1; edns->ext_rcode = 0; edns->edns_version = 0; @@ -607,8 +609,9 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q) /* see if there is a fixed answer */ sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); - if(local_zones_answer(ctx->local_zones, &qinfo, &edns, - w->back->udp_buff, w->env->scratch, NULL)) { + if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns, + w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0, + 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); @@ -636,7 +639,7 @@ libworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s, char* why_bogus) { struct ctx_query* q = (struct ctx_query*)arg; - ub_event_callback_t cb = (ub_event_callback_t)q->cb; + ub_event_callback_type cb = (ub_event_callback_type)q->cb; void* cb_arg = q->cb_arg; int cancelled = q->cancelled; @@ -677,8 +680,9 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q, /* see if there is a fixed answer */ sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); - if(local_zones_answer(ctx->local_zones, &qinfo, &edns, - w->back->udp_buff, w->env->scratch, NULL)) { + if(local_zones_answer(ctx->local_zones, w->env, &qinfo, &edns, + w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL)) { regional_free_all(w->env->scratch); free(qinfo.qname); libworker_event_done_cb(q, LDNS_RCODE_NOERROR, @@ -797,8 +801,9 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len) /* see if there is a fixed answer */ sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid); sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags); - if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns, - w->back->udp_buff, w->env->scratch, NULL)) { + if(local_zones_answer(w->ctx->local_zones, w->env, &qinfo, &edns, + w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0, + NULL, 0, NULL, 0, NULL)) { regional_free_all(w->env->scratch); q->msg_security = sec_status_insecure; add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL); @@ -821,11 +826,10 @@ void libworker_alloc_cleanup(void* arg) slabhash_clear(w->env->msg_cache); } -struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, - uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, int nocaps, struct edns_option* opt_list, +struct outbound_entry* libworker_send_query(struct query_info* qinfo, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* q) + size_t zonelen, int ssl_upstream, struct module_qstate* q) { struct libworker* w = (struct libworker*)q->env->worker; struct outbound_entry* e = (struct outbound_entry*)regional_alloc( @@ -833,11 +837,10 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, if(!e) return NULL; e->qstate = q; - e->qsent = outnet_serviced_query(w->back, qname, - qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps, - q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, opt_list, - addr, addrlen, zone, zonelen, libworker_handle_service_reply, - e, w->back->udp_buff); + e->qsent = outnet_serviced_query(w->back, qinfo, flags, dnssec, + want_dnssec, nocaps, q->env->cfg->tcp_upstream, ssl_upstream, + addr, addrlen, zone, zonelen, q, libworker_handle_service_reply, + e, w->back->udp_buff, q->env); if(!e->qsent) { return NULL; } @@ -952,14 +955,12 @@ void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) log_assert(0); } -struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), - size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), - uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), - int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list), - struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) +struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo), + uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), + int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), + struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), + uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), + int ATTR_UNUSED(ssl_upstream), struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); return 0; diff --git a/usr.sbin/unbound/libunbound/libworker.h b/usr.sbin/unbound/libunbound/libworker.h index 00143475bbc..b546e89f2ca 100644 --- a/usr.sbin/unbound/libunbound/libworker.h +++ b/usr.sbin/unbound/libunbound/libworker.h @@ -1,5 +1,5 @@ /* - * libunbound/worker.h - worker thread or process that resolves + * libunbound/libworker.h - worker thread or process that resolves * * Copyright (c) 2007, NLnet Labs. All rights reserved. * @@ -59,6 +59,7 @@ struct regional; struct tube; struct sldns_buffer; struct ub_event_base; +struct query_info; /** * The library-worker status structure diff --git a/usr.sbin/unbound/libunbound/unbound-event.h b/usr.sbin/unbound/libunbound/unbound-event.h index 432750d7749..d5f0b1a36fe 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_t)(void*, int, void*, int, int, char*); +typedef void (*ub_event_callback_type)(void*, int, void*, int, int, char*); /** * Create a resolving and validation context. @@ -254,7 +254,8 @@ int ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base); * @return 0 if OK, else error. */ int ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype, - int rrclass, void* mydata, ub_event_callback_t callback, int* async_id); + int rrclass, void* mydata, ub_event_callback_type callback, + int* async_id); #ifdef __cplusplus } diff --git a/usr.sbin/unbound/libunbound/unbound.h b/usr.sbin/unbound/libunbound/unbound.h index 9c828fc292b..9a076927f9a 100644 --- a/usr.sbin/unbound/libunbound/unbound.h +++ b/usr.sbin/unbound/libunbound/unbound.h @@ -223,7 +223,7 @@ struct ub_result { * This structure is allocated on the heap and needs to be * freed with ub_resolve_free(result); */ -typedef void (*ub_callback_t)(void*, int, struct ub_result*); +typedef void (*ub_callback_type)(void*, int, struct ub_result*); /** * Create a resolving and validation context. @@ -519,7 +519,7 @@ int ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype, * @return 0 if OK, else error. */ int ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype, - int rrclass, void* mydata, ub_callback_t callback, int* async_id); + int rrclass, void* mydata, ub_callback_type callback, int* async_id); /** * Cancel an async query in progress. diff --git a/usr.sbin/unbound/libunbound/worker.h b/usr.sbin/unbound/libunbound/worker.h index b8d8dd88a8d..88e1cf799d4 100644 --- a/usr.sbin/unbound/libunbound/worker.h +++ b/usr.sbin/unbound/libunbound/worker.h @@ -49,31 +49,28 @@ struct comm_point; struct module_qstate; struct tube; struct edns_option; +struct query_info; /** * Worker service routine to send serviced queries to authoritative servers. - * @param qname: query name. (host order) - * @param qnamelen: length in bytes of qname, including trailing 0. - * @param qtype: query type. (host order) - * @param qclass: query class. (host order) + * @param qinfo: query info. * @param flags: host order flags word, with opcode and CD bit. * @param dnssec: if set, EDNS record will have DO bit set. * @param want_dnssec: signatures needed. * @param nocaps: ignore capsforid(if in config), do not perturb qname. - * @param opt_list: EDNS options on outgoing packet. * @param addr: where to. * @param addrlen: length of addr. * @param zone: delegation point name. * @param zonelen: length of zone name wireformat dname. + * @param ssl_upstream: use SSL for upstream queries. * @param q: wich query state to reactivate upon return. * @return: false on failure (memory or socket related). no query was * sent. */ -struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, - uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, int nocaps, struct edns_option* opt_list, +struct outbound_entry* libworker_send_query(struct query_info* qinfo, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* q); + size_t zonelen, int ssl_upstream, struct module_qstate* q); /** process incoming replies from the network */ int libworker_handle_reply(struct comm_point* c, void* arg, int error, @@ -108,28 +105,24 @@ void worker_sighandler(int sig, void* arg); /** * Worker service routine to send serviced queries to authoritative servers. - * @param qname: query name. (host order) - * @param qnamelen: length in bytes of qname, including trailing 0. - * @param qtype: query type. (host order) - * @param qclass: query class. (host order) + * @param qinfo: query info. * @param flags: host order flags word, with opcode and CD bit. * @param dnssec: if set, EDNS record will have DO bit set. * @param want_dnssec: signatures needed. * @param nocaps: ignore capsforid(if in config), do not perturb qname. - * @param opt_list: EDNS options on outgoing packet. * @param addr: where to. * @param addrlen: length of addr. * @param zone: wireformat dname of the zone. * @param zonelen: length of zone name. + * @param ssl_upstream: use SSL for upstream queries. * @param q: wich query state to reactivate upon return. * @return: false on failure (memory or socket related). no query was * sent. */ -struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen, - uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, int nocaps, struct edns_option* opt_list, +struct outbound_entry* worker_send_query(struct query_info* qinfo, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* q); + size_t zonelen, int ssl_upstream, struct module_qstate* q); /** * process control messages from the main thread. Frees the control diff --git a/usr.sbin/unbound/services/cache/dns.c b/usr.sbin/unbound/services/cache/dns.c index 84db7a77884..7beb7616498 100644 --- a/usr.sbin/unbound/services/cache/dns.c +++ b/usr.sbin/unbound/services/cache/dns.c @@ -106,7 +106,7 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, - hashvalue_t hash, struct reply_info* rep, time_t leeway, int pside, + hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside, struct reply_info* qrep, struct regional* region) { struct msgreply_entry* e; @@ -188,12 +188,13 @@ msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen, { struct lruhash_entry* e; struct query_info k; - hashvalue_t h; + hashvalue_type h; k.qname = qname; k.qname_len = qnamelen; k.qtype = qtype; k.qclass = qclass; + k.local_alias = NULL; h = query_info_hash(&k, flags); e = slabhash_lookup(env->msg_cache, h, &k, wr); @@ -361,6 +362,7 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype, msg->qinfo.qname_len = qnamelen; msg->qinfo.qtype = qtype; msg->qinfo.qclass = qclass; + msg->qinfo.local_alias = NULL; /* non-packed reply_info, because it needs to grow the array */ msg->rep = (struct reply_info*)regional_alloc_zero(region, sizeof(struct reply_info)-sizeof(struct rrset_ref)); @@ -707,7 +709,7 @@ dns_cache_lookup(struct module_env* env, { struct lruhash_entry* e; struct query_info k; - hashvalue_t h; + hashvalue_type h; time_t now = *env->now; struct ub_packed_rrset_key* rrset; @@ -716,6 +718,7 @@ dns_cache_lookup(struct module_env* env, k.qname_len = qnamelen; k.qtype = qtype; k.qclass = qclass; + k.local_alias = NULL; h = query_info_hash(&k, flags); e = slabhash_lookup(env->msg_cache, h, &k, 0); if(e) { @@ -795,9 +798,9 @@ dns_cache_lookup(struct module_env* env, dname_remove_label(&k.qname, &k.qname_len); h = query_info_hash(&k, flags); e = slabhash_lookup(env->msg_cache, h, &k, 0); - if(!e && k.qtype != LDNS_RR_TYPE_NS && + if(!e && k.qtype != LDNS_RR_TYPE_A && env->cfg->qname_minimisation) { - k.qtype = LDNS_RR_TYPE_NS; + k.qtype = LDNS_RR_TYPE_A; h = query_info_hash(&k, flags); e = slabhash_lookup(env->msg_cache, h, &k, 0); } @@ -817,7 +820,7 @@ dns_cache_lookup(struct module_env* env, lock_rw_unlock(&e->lock); } k.qtype = qtype; - } + } /* fill common RR types for ANY response to avoid requery */ if(qtype == LDNS_RR_TYPE_ANY) { @@ -862,7 +865,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, } else { /* store msg, and rrsets */ struct query_info qinf; - hashvalue_t h; + hashvalue_type h; qinf = *msgqinf; qinf.qname = memdup(msgqinf->qname, msgqinf->qname_len); diff --git a/usr.sbin/unbound/services/cache/dns.h b/usr.sbin/unbound/services/cache/dns.h index 69796c2eb20..15a4a236b02 100644 --- a/usr.sbin/unbound/services/cache/dns.h +++ b/usr.sbin/unbound/services/cache/dns.h @@ -106,7 +106,7 @@ int dns_cache_store(struct module_env* env, struct query_info* qinf, * @param region: to allocate into for qmsg. */ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, - hashvalue_t hash, struct reply_info* rep, time_t leeway, int pside, + hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside, struct reply_info* qrep, struct regional* region); /** diff --git a/usr.sbin/unbound/services/cache/infra.c b/usr.sbin/unbound/services/cache/infra.c index 8a83528b5f7..314c85ef511 100644 --- a/usr.sbin/unbound/services/cache/infra.c +++ b/usr.sbin/unbound/services/cache/infra.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -39,7 +39,8 @@ * This file contains the infrastructure cache. */ #include "config.h" -#include <ldns/rr.h> +#include "sldns/rrdef.h" +#include "sldns/str2wire.h" #include "services/cache/infra.h" #include "util/storage/slabhash.h" #include "util/storage/lookup3.h" @@ -52,6 +53,18 @@ /** Timeout when only a single probe query per IP is allowed. */ #define PROBE_MAXRTO 12000 /* in msec */ +/** number of timeouts for a type when the domain can be blocked ; + * even if another type has completely rtt maxed it, the different type + * can do this number of packets (until those all timeout too) */ +#define TIMEOUT_COUNT_MAX 3 + +/** ratelimit value for delegation point */ +int infra_dp_ratelimit = 0; + +/** ratelimit value for client ip addresses, + * in queries per second. */ +int infra_ip_ratelimit = 0; + size_t infra_sizefunc(void* k, void* ATTR_UNUSED(d)) { @@ -94,6 +107,114 @@ infra_deldatafunc(void* d, void* ATTR_UNUSED(arg)) free(data); } +size_t +rate_sizefunc(void* k, void* ATTR_UNUSED(d)) +{ + struct rate_key* key = (struct rate_key*)k; + return sizeof(*key) + sizeof(struct rate_data) + key->namelen + + lock_get_mem(&key->entry.lock); +} + +int +rate_compfunc(void* key1, void* key2) +{ + struct rate_key* k1 = (struct rate_key*)key1; + struct rate_key* k2 = (struct rate_key*)key2; + if(k1->namelen != k2->namelen) { + if(k1->namelen < k2->namelen) + return -1; + return 1; + } + return query_dname_compare(k1->name, k2->name); +} + +void +rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) +{ + struct rate_key* key = (struct rate_key*)k; + if(!key) + return; + lock_rw_destroy(&key->entry.lock); + free(key->name); + free(key); +} + +void +rate_deldatafunc(void* d, void* ATTR_UNUSED(arg)) +{ + struct rate_data* data = (struct rate_data*)d; + free(data); +} + +/** find or create element in domainlimit tree */ +static struct domain_limit_data* domain_limit_findcreate( + struct infra_cache* infra, char* name) +{ + uint8_t* nm; + int labs; + size_t nmlen; + struct domain_limit_data* d; + + /* parse name */ + nm = sldns_str2wire_dname(name, &nmlen); + if(!nm) { + log_err("could not parse %s", name); + return NULL; + } + labs = dname_count_labels(nm); + + /* can we find it? */ + d = (struct domain_limit_data*)name_tree_find(&infra->domain_limits, + nm, nmlen, labs, LDNS_RR_CLASS_IN); + if(d) { + free(nm); + return d; + } + + /* create it */ + d = (struct domain_limit_data*)calloc(1, sizeof(*d)); + if(!d) { + free(nm); + return NULL; + } + d->node.node.key = &d->node; + d->node.name = nm; + d->node.len = nmlen; + d->node.labs = labs; + d->node.dclass = LDNS_RR_CLASS_IN; + d->lim = -1; + d->below = -1; + if(!name_tree_insert(&infra->domain_limits, &d->node, nm, nmlen, + labs, LDNS_RR_CLASS_IN)) { + log_err("duplicate element in domainlimit tree"); + free(nm); + free(d); + return NULL; + } + return d; +} + +/** insert rate limit configuration into lookup tree */ +static int infra_ratelimit_cfg_insert(struct infra_cache* infra, + struct config_file* cfg) +{ + struct config_str2list* p; + struct domain_limit_data* d; + for(p = cfg->ratelimit_for_domain; p; p = p->next) { + d = domain_limit_findcreate(infra, p->str); + if(!d) + return 0; + d->lim = atoi(p->str2); + } + for(p = cfg->ratelimit_below_domain; p; p = p->next) { + d = domain_limit_findcreate(infra, p->str); + if(!d) + return 0; + d->below = atoi(p->str2); + } + return 1; +} + struct infra_cache* infra_create(struct config_file* cfg) { @@ -109,15 +230,53 @@ 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; + if(cfg->ratelimit != 0) { + infra->domain_rates = slabhash_create(cfg->ratelimit_slabs, + INFRA_HOST_STARTSIZE, cfg->ratelimit_size, + &rate_sizefunc, &rate_compfunc, &rate_delkeyfunc, + &rate_deldatafunc, NULL); + if(!infra->domain_rates) { + infra_delete(infra); + return NULL; + } + /* insert config data into ratelimits */ + if(!infra_ratelimit_cfg_insert(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->ratelimit_slabs, + INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc, + &ip_rate_compfunc, &ip_rate_delkeyfunc, &ip_rate_deldatafunc, NULL); + if(!infra->client_ip_rates) { + infra_delete(infra); + return NULL; + } return infra; } +/** delete domain_limit entries */ +static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg)) +{ + if(n) { + free(((struct domain_limit_data*)n)->node.name); + free(n); + } +} + void infra_delete(struct infra_cache* infra) { if(!infra) return; slabhash_delete(infra->hosts); + slabhash_delete(infra->domain_rates); + traverse_postorder(&infra->domain_limits, domain_limit_free, NULL); + slabhash_delete(infra->client_ip_rates); free(infra); } @@ -138,31 +297,38 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg) return infra; } -/** calculate the hash value for a host key */ -static hashvalue_t -hash_addr(struct sockaddr_storage* addr, socklen_t addrlen) +/** calculate the hash value for a host key + * set use_port to a non-0 number to use the port in + * the hash calculation; 0 to ignore the port.*/ +static hashvalue_type +hash_addr(struct sockaddr_storage* addr, socklen_t addrlen, + int use_port) { - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; /* select the pieces to hash, some OS have changing data inside */ if(addr_is_ip6(addr, addrlen)) { struct sockaddr_in6* in6 = (struct sockaddr_in6*)addr; h = hashlittle(&in6->sin6_family, sizeof(in6->sin6_family), h); - h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h); + if(use_port){ + h = hashlittle(&in6->sin6_port, sizeof(in6->sin6_port), h); + } h = hashlittle(&in6->sin6_addr, INET6_SIZE, h); } else { struct sockaddr_in* in = (struct sockaddr_in*)addr; h = hashlittle(&in->sin_family, sizeof(in->sin_family), h); - h = hashlittle(&in->sin_port, sizeof(in->sin_port), h); + if(use_port){ + h = hashlittle(&in->sin_port, sizeof(in->sin_port), h); + } h = hashlittle(&in->sin_addr, INET_SIZE, h); } return h; } /** calculate infra hash for a key */ -static hashvalue_t +static hashvalue_type hash_infra(struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name) { - return dname_query_hash(name, hash_addr(addr, addrlen)); + return dname_query_hash(name, hash_addr(addr, addrlen, 1)); } /** lookup version that does not check host ttl (you check it) */ @@ -184,7 +350,7 @@ infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr, /** init the data elements */ static void data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, - uint32_t timenow) + time_t timenow) { struct infra_data* data = (struct infra_data*)e->data; data->ttl = timenow + infra->host_ttl; @@ -196,6 +362,9 @@ data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, data->rec_lame = 0; data->lame_type_A = 0; data->lame_other = 0; + data->timeout_A = 0; + data->timeout_AAAA = 0; + data->timeout_other = 0; } /** @@ -210,7 +379,7 @@ data_entry_init(struct infra_cache* infra, struct lruhash_entry* e, */ static struct lruhash_entry* new_entry(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* name, size_t namelen, uint32_t tm) + socklen_t addrlen, uint8_t* name, size_t namelen, time_t tm) { struct infra_data* data; struct infra_key* key = (struct infra_key*)malloc(sizeof(*key)); @@ -240,7 +409,7 @@ new_entry(struct infra_cache* infra, struct sockaddr_storage* addr, int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, + socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, @@ -250,6 +419,9 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, if(e && ((struct infra_data*)e->data)->ttl < timenow) { /* it expired, try to reuse existing entry */ int old = ((struct infra_data*)e->data)->rtt.rto; + uint8_t tA = ((struct infra_data*)e->data)->timeout_A; + uint8_t tAAAA = ((struct infra_data*)e->data)->timeout_AAAA; + uint8_t tother = ((struct infra_data*)e->data)->timeout_other; lock_rw_unlock(&e->lock); e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); if(e) { @@ -259,9 +431,13 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, data_entry_init(infra, e, timenow); wr = 1; /* TOP_TIMEOUT remains on reuse */ - if(old >= USEFUL_SERVER_TOP_TIMEOUT) + if(old >= USEFUL_SERVER_TOP_TIMEOUT) { ((struct infra_data*)e->data)->rtt.rto = USEFUL_SERVER_TOP_TIMEOUT; + ((struct infra_data*)e->data)->timeout_A = tA; + ((struct infra_data*)e->data)->timeout_AAAA = tAAAA; + ((struct infra_data*)e->data)->timeout_other = tother; + } } } if(!e) { @@ -302,7 +478,7 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* nm, size_t nmlen, uint32_t timenow, + socklen_t addrlen, uint8_t* nm, size_t nmlen, time_t timenow, int dnsseclame, int reclame, uint16_t qtype) { struct infra_data* data; @@ -358,8 +534,8 @@ infra_update_tcp_works(struct infra_cache* infra, int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* nm, size_t nmlen, int roundtrip, - int orig_rtt, uint32_t timenow) + socklen_t addrlen, uint8_t* nm, size_t nmlen, int qtype, + int roundtrip, int orig_rtt, time_t timenow) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); @@ -377,9 +553,29 @@ infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, data = (struct infra_data*)e->data; if(roundtrip == -1) { rtt_lost(&data->rtt, orig_rtt); + if(qtype == LDNS_RR_TYPE_A) { + if(data->timeout_A < TIMEOUT_COUNT_MAX) + data->timeout_A++; + } else if(qtype == LDNS_RR_TYPE_AAAA) { + if(data->timeout_AAAA < TIMEOUT_COUNT_MAX) + data->timeout_AAAA++; + } else { + if(data->timeout_other < TIMEOUT_COUNT_MAX) + data->timeout_other++; + } } else { + /* if we got a reply, but the old timeout was above server + * selection height, delete the timeout so the server is + * fully available again */ + if(rtt_unclamped(&data->rtt) >= USEFUL_SERVER_TOP_TIMEOUT) + rtt_init(&data->rtt); rtt_update(&data->rtt, roundtrip); data->probedelay = 0; + if(qtype == LDNS_RR_TYPE_A) + data->timeout_A = 0; + else if(qtype == LDNS_RR_TYPE_AAAA) + data->timeout_AAAA = 0; + else data->timeout_other = 0; } if(data->rtt.rto > 0) rto = data->rtt.rto; @@ -390,23 +586,27 @@ infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, return rto; } -int infra_get_host_rto(struct infra_cache* infra, +long long infra_get_host_rto(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, - size_t nmlen, struct rtt_info* rtt, int* delay, uint32_t timenow) + size_t nmlen, struct rtt_info* rtt, int* delay, time_t timenow, + int* tA, int* tAAAA, int* tother) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 0); struct infra_data* data; - int ttl = -2; + long long ttl = -2; if(!e) return -1; data = (struct infra_data*)e->data; if(data->ttl >= timenow) { - ttl = (int)(data->ttl - timenow); + ttl = (long long)(data->ttl - timenow); memmove(rtt, &data->rtt, sizeof(*rtt)); if(timenow < data->probedelay) *delay = (int)(data->probedelay - timenow); else *delay = 0; } + *tA = (int)data->timeout_A; + *tAAAA = (int)data->timeout_AAAA; + *tother = (int)data->timeout_other; lock_rw_unlock(&e->lock); return ttl; } @@ -414,7 +614,7 @@ int infra_get_host_rto(struct infra_cache* infra, int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* nm, size_t nmlen, int edns_version, - uint32_t timenow) + time_t timenow) { struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, nm, nmlen, 1); @@ -446,7 +646,7 @@ int infra_get_lame_rtt(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, uint16_t qtype, - int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow) + int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow) { struct infra_data* host; struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, @@ -456,20 +656,34 @@ infra_get_lame_rtt(struct infra_cache* infra, host = (struct infra_data*)e->data; *rtt = rtt_unclamped(&host->rtt); if(host->rtt.rto >= PROBE_MAXRTO && timenow < host->probedelay - && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) + && rtt_notimeout(&host->rtt)*4 <= host->rtt.rto) { /* single probe for this domain, and we are not probing */ - *rtt = USEFUL_SERVER_TOP_TIMEOUT; + /* unless the query type allows a probe to happen */ + if(qtype == LDNS_RR_TYPE_A) { + if(host->timeout_A >= TIMEOUT_COUNT_MAX) + *rtt = USEFUL_SERVER_TOP_TIMEOUT; + else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; + } else if(qtype == LDNS_RR_TYPE_AAAA) { + if(host->timeout_AAAA >= TIMEOUT_COUNT_MAX) + *rtt = USEFUL_SERVER_TOP_TIMEOUT; + else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; + } else { + if(host->timeout_other >= TIMEOUT_COUNT_MAX) + *rtt = USEFUL_SERVER_TOP_TIMEOUT; + else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; + } + } if(timenow > host->ttl) { /* expired entry */ /* see if this can be a re-probe of an unresponsive server */ /* minus 1000 because that is outside of the RTTBAND, so * blacklisted servers stay blacklisted if this is chosen */ if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) { + lock_rw_unlock(&e->lock); *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000; *lame = 0; *dnsseclame = 0; *reclame = 0; - lock_rw_unlock(&e->lock); return 1; } lock_rw_unlock(&e->lock); @@ -509,8 +723,275 @@ infra_get_lame_rtt(struct infra_cache* infra, return 1; } +int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, + size_t namelen) +{ + int labs = dname_count_labels(name); + struct domain_limit_data* d = (struct domain_limit_data*) + name_tree_lookup(&infra->domain_limits, name, namelen, labs, + LDNS_RR_CLASS_IN); + if(!d) return infra_dp_ratelimit; + + if(d->node.labs == labs && d->lim != -1) + return d->lim; /* exact match */ + + /* find 'below match' */ + if(d->node.labs == labs) + d = (struct domain_limit_data*)d->node.parent; + while(d) { + if(d->below != -1) + return d->below; + d = (struct domain_limit_data*)d->node.parent; + } + return infra_dp_ratelimit; +} + +size_t ip_rate_sizefunc(void* k, void* ATTR_UNUSED(d)) +{ + struct ip_rate_key* key = (struct ip_rate_key*)k; + return sizeof(*key) + sizeof(struct ip_rate_data) + + lock_get_mem(&key->entry.lock); +} + +int ip_rate_compfunc(void* key1, void* key2) +{ + struct ip_rate_key* k1 = (struct ip_rate_key*)key1; + struct ip_rate_key* k2 = (struct ip_rate_key*)key2; + return sockaddr_cmp_addr(&k1->addr, k1->addrlen, + &k2->addr, k2->addrlen); +} + +void ip_rate_delkeyfunc(void* k, void* ATTR_UNUSED(arg)) +{ + struct ip_rate_key* key = (struct ip_rate_key*)k; + if(!key) + return; + lock_rw_destroy(&key->entry.lock); + free(key); +} + +/** find data item in array, for write access, caller unlocks */ +static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra, + uint8_t* name, size_t namelen, int wr) +{ + struct rate_key key; + hashvalue_type h = dname_query_hash(name, 0xab); + memset(&key, 0, sizeof(key)); + key.name = name; + key.namelen = namelen; + key.entry.hash = h; + return slabhash_lookup(infra->domain_rates, h, &key, wr); +} + +/** find data item in array for ip addresses */ +struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra, + struct comm_reply* repinfo, int wr) +{ + struct ip_rate_key key; + hashvalue_type h = hash_addr(&(repinfo->addr), + repinfo->addrlen, 0); + memset(&key, 0, sizeof(key)); + key.addr = repinfo->addr; + key.addrlen = repinfo->addrlen; + key.entry.hash = h; + return slabhash_lookup(infra->client_ip_rates, h, &key, wr); +} + +/** create rate data item for name, number 1 in now */ +static void infra_create_ratedata(struct infra_cache* infra, + uint8_t* name, size_t namelen, time_t timenow) +{ + hashvalue_type h = dname_query_hash(name, 0xab); + struct rate_key* k = (struct rate_key*)calloc(1, sizeof(*k)); + struct rate_data* d = (struct rate_data*)calloc(1, sizeof(*d)); + if(!k || !d) { + free(k); + free(d); + return; /* alloc failure */ + } + k->namelen = namelen; + k->name = memdup(name, namelen); + if(!k->name) { + free(k); + free(d); + return; /* alloc failure */ + } + lock_rw_init(&k->entry.lock); + k->entry.hash = h; + k->entry.key = k; + k->entry.data = d; + d->qps[0] = 1; + d->timestamp[0] = timenow; + slabhash_insert(infra->domain_rates, h, &k->entry, d, NULL); +} + +/** create rate data item for ip address */ +static void infra_ip_create_ratedata(struct infra_cache* infra, + struct comm_reply* repinfo, time_t timenow) +{ + hashvalue_type h = hash_addr(&(repinfo->addr), + repinfo->addrlen, 0); + struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k)); + struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d)); + if(!k || !d) { + free(k); + free(d); + return; /* alloc failure */ + } + k->addr = repinfo->addr; + k->addrlen = repinfo->addrlen; + lock_rw_init(&k->entry.lock); + k->entry.hash = h; + k->entry.key = k; + k->entry.data = d; + d->qps[0] = 1; + d->timestamp[0] = timenow; + slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL); +} + +/** find the second and return its rate counter, if none, remove oldest */ +static int* infra_rate_find_second(void* data, time_t t) +{ + struct rate_data* d = (struct rate_data*)data; + int i, oldest; + for(i=0; i<RATE_WINDOW; i++) { + if(d->timestamp[i] == t) + return &(d->qps[i]); + } + /* remove oldest timestamp, and insert it at t with 0 qps */ + oldest = 0; + for(i=0; i<RATE_WINDOW; i++) { + if(d->timestamp[i] < d->timestamp[oldest]) + oldest = i; + } + d->timestamp[oldest] = t; + d->qps[oldest] = 0; + return &(d->qps[oldest]); +} + +int infra_rate_max(void* data, time_t now) +{ + struct rate_data* d = (struct rate_data*)data; + int i, max = 0; + for(i=0; i<RATE_WINDOW; i++) { + if(now-d->timestamp[i] <= RATE_WINDOW) { + if(d->qps[i] > max) + max = d->qps[i]; + } + } + return max; +} + +int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow) +{ + int lim, max; + struct lruhash_entry* entry; + + if(!infra_dp_ratelimit) + return 1; /* not enabled */ + + /* find ratelimit */ + lim = infra_find_ratelimit(infra, name, namelen); + + /* find or insert ratedata */ + entry = infra_find_ratedata(infra, name, namelen, 1); + if(entry) { + int premax = infra_rate_max(entry->data, timenow); + int* cur = infra_rate_find_second(entry->data, timenow); + (*cur)++; + max = infra_rate_max(entry->data, timenow); + lock_rw_unlock(&entry->lock); + + if(premax < lim && max >= lim) { + char buf[257]; + dname_str(name, buf); + verbose(VERB_OPS, "ratelimit exceeded %s %d", buf, lim); + } + return (max < lim); + } + + /* create */ + infra_create_ratedata(infra, name, namelen, timenow); + return (1 < lim); +} + +void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow) +{ + struct lruhash_entry* entry; + int* cur; + if(!infra_dp_ratelimit) + return; /* not enabled */ + entry = infra_find_ratedata(infra, name, namelen, 1); + if(!entry) return; /* not cached */ + cur = infra_rate_find_second(entry->data, timenow); + if((*cur) > 0) + (*cur)--; + lock_rw_unlock(&entry->lock); +} + +int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow) +{ + struct lruhash_entry* entry; + int lim, max; + if(!infra_dp_ratelimit) + return 0; /* not enabled */ + + /* find ratelimit */ + lim = infra_find_ratelimit(infra, name, namelen); + + /* find current rate */ + entry = infra_find_ratedata(infra, name, namelen, 0); + if(!entry) + return 0; /* not cached */ + max = infra_rate_max(entry->data, timenow); + lock_rw_unlock(&entry->lock); + + return (max >= lim); +} + size_t infra_get_mem(struct infra_cache* infra) { - return sizeof(*infra) + slabhash_get_mem(infra->hosts); + size_t s = sizeof(*infra) + slabhash_get_mem(infra->hosts); + if(infra->domain_rates) s += slabhash_get_mem(infra->domain_rates); + if(infra->client_ip_rates) s += slabhash_get_mem(infra->client_ip_rates); + /* ignore domain_limits because walk through tree is big */ + return s; +} + +int infra_ip_ratelimit_inc(struct infra_cache* infra, + struct comm_reply* repinfo, time_t timenow) +{ + int max; + struct lruhash_entry* entry; + + /* not enabled */ + if(!infra_ip_ratelimit) { + return 1; + } + /* find or insert ratedata */ + entry = infra_find_ip_ratedata(infra, repinfo, 1); + if(entry) { + int premax = infra_rate_max(entry->data, timenow); + int* cur = infra_rate_find_second(entry->data, timenow); + (*cur)++; + max = infra_rate_max(entry->data, timenow); + lock_rw_unlock(&entry->lock); + + if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) { + char client_ip[128]; + addr_to_str((struct sockaddr_storage *)&repinfo->addr, + repinfo->addrlen, client_ip, sizeof(client_ip)); + verbose(VERB_OPS, "ratelimit exceeded %s %d", client_ip, + infra_ip_ratelimit); + } + return (max <= infra_ip_ratelimit); + } + + /* create */ + infra_ip_create_ratedata(infra, repinfo, timenow); + return 1; } diff --git a/usr.sbin/unbound/services/cache/infra.h b/usr.sbin/unbound/services/cache/infra.h index 3a3508eac40..6f9471a3941 100644 --- a/usr.sbin/unbound/services/cache/infra.h +++ b/usr.sbin/unbound/services/cache/infra.h @@ -21,28 +21,34 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file * - * This file contains the infrastructure cache. + * This file contains the infrastructure cache, as well as rate limiting. + * Note that there are two sorts of rate-limiting here: + * - Pre-cache, per-query rate limiting (query ratelimits) + * - Post-cache, per-domain name rate limiting (infra-ratelimits) */ #ifndef SERVICES_CACHE_INFRA_H #define SERVICES_CACHE_INFRA_H #include "util/storage/lruhash.h" +#include "util/storage/dnstree.h" #include "util/rtt.h" +#include "util/netevent.h" +#include "util/data/msgreply.h" struct slabhash; struct config_file; @@ -68,10 +74,10 @@ struct infra_key { */ struct infra_data { /** TTL value for this entry. absolute time. */ - uint32_t ttl; + time_t ttl; /** time in seconds (absolute) when probing re-commences, 0 disabled */ - uint32_t probedelay; + time_t probedelay; /** round trip times for timeout calculation */ struct rtt_info rtt; @@ -91,6 +97,13 @@ struct infra_data { uint8_t lame_type_A; /** the host is lame (not authoritative) for other query types */ uint8_t lame_other; + + /** timeouts counter for type A */ + uint8_t timeout_A; + /** timeouts counter for type AAAA */ + uint8_t timeout_AAAA; + /** timeouts counter for others */ + uint8_t timeout_other; }; /** @@ -101,8 +114,76 @@ struct infra_cache { struct slabhash* hosts; /** TTL value for host information, in seconds */ int host_ttl; + /** hash table with query rates per name: rate_key, rate_data */ + struct slabhash* domain_rates; + /** ratelimit settings for domains, struct domain_limit_data */ + rbtree_type domain_limits; + /** hash table with query rates per client ip: ip_rate_key, ip_rate_data */ + struct slabhash* client_ip_rates; +}; + +/** ratelimit, unless overridden by domain_limits, 0 is off */ +extern int infra_dp_ratelimit; + +/** + * ratelimit settings for domains + */ +struct domain_limit_data { + /** key for rbtree, must be first in struct, name of domain */ + struct name_tree_node node; + /** ratelimit for exact match with this name, -1 if not set */ + int lim; + /** ratelimit for names below this name, -1 if not set */ + int below; +}; + +/** + * key for ratelimit lookups, a domain name + */ +struct rate_key { + /** lruhash key entry */ + struct lruhash_entry entry; + /** domain name in uncompressed wireformat */ + uint8_t* name; + /** length of name */ + size_t namelen; +}; + +/** ip ratelimit, 0 is off */ +extern int infra_ip_ratelimit; + +/** + * key for ip_ratelimit lookups, a source IP. + */ +struct ip_rate_key { + /** lruhash key entry */ + struct lruhash_entry entry; + /** client ip information */ + struct sockaddr_storage addr; + /** length of address */ + socklen_t addrlen; }; +/** number of seconds to track qps rate */ +#define RATE_WINDOW 2 + +/** + * Data for ratelimits per domain name + * It is incremented when a non-cache-lookup happens for that domain name. + * The name is the delegation point we have for the name. + * If a new delegation point is found (a referral reply), the previous + * delegation point is decremented, and the new one is charged with the query. + */ +struct rate_data { + /** queries counted, for that second. 0 if not in use. */ + int qps[RATE_WINDOW]; + /** what the timestamp is of the qps array members, counter is + * valid for that timestamp. Usually now and now-1. */ + time_t timestamp[RATE_WINDOW]; +}; + +#define ip_rate_data rate_data + /** infra host cache default hash lookup size */ #define INFRA_HOST_STARTSIZE 32 /** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */ @@ -166,7 +247,7 @@ struct lruhash_entry* infra_lookup_nottl(struct infra_cache* infra, */ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, - uint32_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to); + time_t timenow, int* edns_vs, uint8_t* edns_lame_known, int* to); /** * Set a host to be lame for the given zone. @@ -185,7 +266,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr, */ int infra_set_lame(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame, + uint8_t* name, size_t namelen, time_t timenow, int dnsseclame, int reclame, uint16_t qtype); /** @@ -195,6 +276,7 @@ int infra_set_lame(struct infra_cache* infra, * @param addrlen: length of addr. * @param name: zone name * @param namelen: zone name length + * @param qtype: query type. * @param roundtrip: estimate of roundtrip time in milliseconds or -1 for * timeout. * @param orig_rtt: original rtt for the query that timed out (roundtrip==-1). @@ -203,8 +285,8 @@ int infra_set_lame(struct infra_cache* infra, * @return: 0 on error. new rto otherwise. */ int infra_rtt_update(struct infra_cache* infra, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* name, size_t namelen, - int roundtrip, int orig_rtt, uint32_t timenow); + socklen_t addrlen, uint8_t* name, size_t namelen, int qtype, + int roundtrip, int orig_rtt, time_t timenow); /** * Update information for the host, store that a TCP transaction works. @@ -232,7 +314,7 @@ void infra_update_tcp_works(struct infra_cache* infra, */ int infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* name, size_t namelen, int edns_version, uint32_t timenow); + uint8_t* name, size_t namelen, int edns_version, time_t timenow); /** * Get Lameness information and average RTT if host is in the cache. @@ -255,7 +337,7 @@ int infra_edns_update(struct infra_cache* infra, int infra_get_lame_rtt(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, size_t namelen, uint16_t qtype, - int* lame, int* dnsseclame, int* reclame, int* rtt, uint32_t timenow); + int* lame, int* dnsseclame, int* reclame, int* rtt, time_t timenow); /** * Get additional (debug) info on timing. @@ -267,12 +349,71 @@ int infra_get_lame_rtt(struct infra_cache* infra, * @param rtt: the rtt_info is copied into here (caller alloced return struct). * @param delay: probe delay (if any). * @param timenow: what time it is now. + * @param tA: timeout counter on type A. + * @param tAAAA: timeout counter on type AAAA. + * @param tother: timeout counter on type other. * @return TTL the infra host element is valid for. If -1: not found in cache. * TTL -2: found but expired. */ -int infra_get_host_rto(struct infra_cache* infra, +long long infra_get_host_rto(struct infra_cache* infra, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* name, - size_t namelen, struct rtt_info* rtt, int* delay, uint32_t timenow); + size_t namelen, struct rtt_info* rtt, int* delay, time_t timenow, + int* tA, int* tAAAA, int* tother); + +/** + * Increment the query rate counter for a delegation point. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + * @return 1 if it could be incremented. 0 if the increment overshot the + * ratelimit or if in the previous second the ratelimit was exceeded. + * Failures like alloc failures are not returned (probably as 1). + */ +int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** + * Decrement the query rate counter for a delegation point. + * Because the reply received for the delegation point was pleasant, + * we do not charge this delegation point with it (i.e. it was a referral). + * Should call it with same second as when inc() was called. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + */ +void infra_ratelimit_dec(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** + * See if the query rate counter for a delegation point is exceeded. + * So, no queries are going to be allowed. + * @param infra: infra cache. + * @param name: zone name + * @param namelen: zone name length + * @param timenow: what time it is now. + * @return true if exceeded. + */ +int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name, + size_t namelen, time_t timenow); + +/** find the maximum rate stored, not too old. 0 if no information. */ +int infra_rate_max(void* data, time_t now); + +/** find the ratelimit in qps for a domain */ +int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name, + size_t namelen); + +/** Update query ratelimit hash and decide + * whether or not a query should be dropped. + * @param infra: infra cache + * @param repinfo: information about client + * @param timenow: what time it is now. + * @return 1 if it could be incremented. 0 if the increment overshot the + * ratelimit and the query should be dropped. */ +int infra_ip_ratelimit_inc(struct infra_cache* infra, + struct comm_reply* repinfo, time_t timenow); /** * Get memory used by the infra cache. @@ -294,4 +435,28 @@ void infra_delkeyfunc(void* k, void* arg); /** delete data and destroy the lameness hashtable */ void infra_deldatafunc(void* d, void* arg); +/** calculate size for the hashtable */ +size_t rate_sizefunc(void* k, void* d); + +/** compare two names, returns -1, 0, or +1 */ +int rate_compfunc(void* key1, void* key2); + +/** delete key, and destroy the lock */ +void rate_delkeyfunc(void* k, void* arg); + +/** delete data */ +void rate_deldatafunc(void* d, void* arg); + +/* calculate size for the client ip hashtable */ +size_t ip_rate_sizefunc(void* k, void* d); + +/* compare two addresses */ +int ip_rate_compfunc(void* key1, void* key2); + +/* delete key, and destroy the lock */ +void ip_rate_delkeyfunc(void* d, void* arg); + +/* delete data */ +#define ip_rate_deldatafunc rate_deldatafunc + #endif /* SERVICES_CACHE_INFRA_H */ diff --git a/usr.sbin/unbound/services/cache/rrset.c b/usr.sbin/unbound/services/cache/rrset.c index 2f6a1b50671..7e5732b760f 100644 --- a/usr.sbin/unbound/services/cache/rrset.c +++ b/usr.sbin/unbound/services/cache/rrset.c @@ -91,7 +91,7 @@ struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r, void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, - hashvalue_t hash, rrset_id_t id) + hashvalue_type hash, rrset_id_type id) { struct lruhash* table = slabhash_gettable(&r->table, hash); /* @@ -186,7 +186,7 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, { struct lruhash_entry* e; struct ub_packed_rrset_key* k = ref->key; - hashvalue_t h = k->entry.hash; + hashvalue_type h = k->entry.hash; uint16_t rrset_type = ntohs(k->rk.type); int equal = 0; log_assert(ref->id != 0 && k->id != 0); @@ -303,10 +303,10 @@ void rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, struct rrset_ref* ref, size_t count) { - hashvalue_t* h; + hashvalue_type* h; size_t i; - if(count > RR_COUNT_MAX || !(h = (hashvalue_t*)regional_alloc(scratch, - sizeof(hashvalue_t)*count))) { + if(count > RR_COUNT_MAX || !(h = (hashvalue_type*)regional_alloc( + scratch, sizeof(hashvalue_type)*count))) { log_warn("rrset LRU: memory allocation failed"); h = NULL; } else /* store hash values */ diff --git a/usr.sbin/unbound/services/cache/rrset.h b/usr.sbin/unbound/services/cache/rrset.h index 22d36719eaf..d5439ef085b 100644 --- a/usr.sbin/unbound/services/cache/rrset.h +++ b/usr.sbin/unbound/services/cache/rrset.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -102,7 +102,7 @@ struct rrset_cache* rrset_cache_adjust(struct rrset_cache* r, * @param id: used to check that the item is unchanged and not deleted. */ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, - hashvalue_t hash, rrset_id_t id); + hashvalue_type hash, rrset_id_type id); /** * Update an rrset in the rrset cache. Stores the information for later use. @@ -131,7 +131,7 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key, * also the rdata is equal (but other parameters in cache are superior). */ int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, - struct alloc_cache* alloc, uint32_t timenow); + struct alloc_cache* alloc, time_t timenow); /** * Lookup rrset. You obtain read/write lock. You must unlock before lookup @@ -149,7 +149,7 @@ int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref, */ struct ub_packed_rrset_key* rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, - uint32_t flags, uint32_t timenow, int wr); + uint32_t flags, time_t timenow, int wr); /** * Obtain readlock on a (sorted) list of rrset references. @@ -163,7 +163,7 @@ struct ub_packed_rrset_key* rrset_cache_lookup(struct rrset_cache* r, * RRsets have been purged from the cache. * If true, you hold readlocks on all the ref items. */ -int rrset_array_lock(struct rrset_ref* ref, size_t count, uint32_t timenow); +int rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow); /** * Unlock array (sorted) of rrset references. @@ -199,7 +199,7 @@ void rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch, * @param now: current time. */ void rrset_update_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset, uint32_t now); + struct ub_packed_rrset_key* rrset, time_t now); /** * Looks up security status of an rrset. Looks up the rrset. @@ -211,7 +211,7 @@ void rrset_update_sec_status(struct rrset_cache* r, * @param now: current time. */ void rrset_check_sec_status(struct rrset_cache* r, - struct ub_packed_rrset_key* rrset, uint32_t now); + struct ub_packed_rrset_key* rrset, time_t now); /** * Remove an rrset from the cache, by name and type and flags diff --git a/usr.sbin/unbound/services/listen_dnsport.c b/usr.sbin/unbound/services/listen_dnsport.c index b0d2d71d947..0132ce45f78 100644 --- a/usr.sbin/unbound/services/listen_dnsport.c +++ b/usr.sbin/unbound/services/listen_dnsport.c @@ -43,6 +43,9 @@ # include <sys/types.h> #endif #include <sys/time.h> +#ifdef USE_TCP_FASTOPEN +#include <netinet/tcp.h> +#endif #include "services/listen_dnsport.h" #include "services/outside_network.h" #include "util/netevent.h" @@ -60,6 +63,10 @@ #include <sys/un.h> #endif +#ifdef HAVE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif + /** number of queued TCP connections for listen() */ #define TCP_BACKLOG 256 @@ -93,11 +100,71 @@ verbose_print_addr(struct addrinfo *addr) } } +#ifdef HAVE_SYSTEMD +static int +systemd_get_activated(int family, int socktype, int listen, + struct sockaddr *addr, socklen_t addrlen, + const char *path) +{ + int i = 0; + int r = 0; + int s = -1; + const char* listen_pid, *listen_fds; + + /* We should use "listen" option only for stream protocols. For UDP it should be -1 */ + + if((r = sd_booted()) < 1) { + if(r == 0) + log_warn("systemd is not running"); + else + log_err("systemd sd_booted(): %s", strerror(-r)); + return -1; + } + + listen_pid = getenv("LISTEN_PID"); + listen_fds = getenv("LISTEN_FDS"); + + if (!listen_pid) { + log_warn("Systemd mandatory ENV variable is not defined: LISTEN_PID"); + return -1; + } + + if (!listen_fds) { + log_warn("Systemd mandatory ENV variable is not defined: LISTEN_FDS"); + return -1; + } + + if((r = sd_listen_fds(0)) < 1) { + if(r == 0) + log_warn("systemd: did not return socket, check unit configuration"); + else + log_err("systemd sd_listen_fds(): %s", strerror(-r)); + return -1; + } + + for(i = 0; i < r; i++) { + if(sd_is_socket(SD_LISTEN_FDS_START + i, family, socktype, listen)) { + s = SD_LISTEN_FDS_START + i; + break; + } + } + if (s == -1) { + if (addr) + log_err_addr("systemd sd_listen_fds()", + "no such socket", + (struct sockaddr_storage *)addr, addrlen); + else + log_err("systemd sd_listen_fds(): %s", path); + } + return s; +} +#endif + int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, int snd, int listen, int* reuseport, int transparent, - int freebind) + 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) @@ -121,6 +188,16 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, #if !defined(IP_FREEBIND) (void)freebind; #endif +#ifdef HAVE_SYSTEMD + int got_fd_from_systemd = 0; + + if (!use_systemd + || (use_systemd + && (s = systemd_get_activated(family, socktype, -1, addr, + addrlen, NULL)) == -1)) { +#else + (void)use_systemd; +#endif if((s = socket(family, socktype, 0)) == -1) { *inuse = 0; #ifndef USE_WINSOCK @@ -141,6 +218,11 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, *noproto = 0; return -1; } +#ifdef HAVE_SYSTEMD + } else { + got_fd_from_systemd = 1; + } +#endif if(listen) { #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, @@ -184,14 +266,6 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, #else (void)reuseport; #endif /* defined(SO_REUSEPORT) */ -#ifdef IP_FREEBIND - if (freebind && - setsockopt(s, IPPROTO_IP, IP_FREEBIND, (void*)&on, - (socklen_t)sizeof(on)) < 0) { - log_warn("setsockopt(.. IP_FREEBIND ..) failed: %s", - strerror(errno)); - } -#endif /* IP_FREEBIND */ #ifdef IP_TRANSPARENT if (transparent && setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on, @@ -209,6 +283,14 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, } #endif /* IP_TRANSPARENT || IP_BINDANY */ } +#ifdef IP_FREEBIND + if(freebind && + setsockopt(s, IPPROTO_IP, IP_FREEBIND, (void*)&on, + (socklen_t)sizeof(on)) < 0) { + log_warn("setsockopt(.. IP_FREEBIND ..) failed: %s", + strerror(errno)); + } +#endif /* IP_FREEBIND */ if(rcv) { #ifdef SO_RCVBUF int got; @@ -462,7 +544,11 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, } # endif /* IPv4 MTU */ } - if(bind(s, (struct sockaddr*)addr, addrlen) != 0) { + if( +#ifdef HAVE_SYSTEMD + !got_fd_from_systemd && +#endif + bind(s, (struct sockaddr*)addr, addrlen) != 0) { *noproto = 0; *inuse = 0; #ifndef USE_WINSOCK @@ -485,7 +571,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, (struct sockaddr_storage*)addr, addrlen); } closesocket(s); -#endif +#endif /* USE_WINSOCK */ return -1; } if(!fd_set_nonblock(s)) { @@ -503,12 +589,18 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind) + int* reuseport, int transparent, int mss, int freebind, int use_systemd) { int s; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) int on = 1; #endif +#ifdef HAVE_SYSTEMD + int got_fd_from_systemd = 0; +#endif +#ifdef USE_TCP_FASTOPEN + int qlen; +#endif #if !defined(IP_TRANSPARENT) && !defined(IP_BINDANY) (void)transparent; #endif @@ -517,6 +609,15 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, #endif verbose_print_addr(addr); *noproto = 0; +#ifdef HAVE_SYSTEMD + if (!use_systemd || + (use_systemd + && (s = systemd_get_activated(addr->ai_family, addr->ai_socktype, 1, + addr->ai_addr, addr->ai_addrlen, + NULL)) == -1)) { +#else + (void)use_systemd; +#endif if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #ifndef USE_WINSOCK if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { @@ -554,6 +655,11 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, log_warn(" setsockopt(TCP_MAXSEG) unsupported"); #endif /* defined(IPPROTO_TCP) && defined(TCP_MAXSEG) */ } +#ifdef HAVE_SYSTEMD + } else { + got_fd_from_systemd = 1; + } +#endif #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) { @@ -631,7 +737,11 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, (addr->ai_family==AF_INET6?"V6":""), strerror(errno)); } #endif /* IP_TRANSPARENT || IP_BINDANY */ - if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { + if( +#ifdef HAVE_SYSTEMD + !got_fd_from_systemd && +#endif + bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { #ifndef USE_WINSOCK /* detect freebsd jail with no ipv6 permission */ if(addr->ai_family==AF_INET6 && errno==EINVAL) @@ -669,20 +779,46 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, #endif return -1; } +#ifdef USE_TCP_FASTOPEN + /* qlen specifies how many outstanding TFO requests to allow. Limit is a defense + against IP spoofing attacks as suggested in RFC7413 */ +#ifdef __APPLE__ + /* OS X implementation only supports qlen of 1 via this call. Actual + value is configured by the net.inet.tcp.fastopen_backlog kernel parm. */ + qlen = 1; +#else + /* 5 is recommended on linux */ + qlen = 5; +#endif + if ((setsockopt(s, IPPROTO_TCP, TCP_FASTOPEN, &qlen, + sizeof(qlen))) == -1 ) { + log_err("Setting TCP Fast Open as server failed: %s", strerror(errno)); + } +#endif return s; } int -create_local_accept_sock(const char *path, int* noproto) +create_local_accept_sock(const char *path, int* noproto, int use_systemd) { +#ifdef HAVE_SYSTEMD + int ret; + + if (use_systemd && (ret = systemd_get_activated(AF_LOCAL, SOCK_STREAM, 1, NULL, 0, path)) != -1) + return ret; + else { +#endif #ifdef HAVE_SYS_UN_H int s; struct sockaddr_un usock; +#ifndef HAVE_SYSTEMD + (void)use_systemd; +#endif verbose(VERB_ALGO, "creating unix socket %s", path); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN /* this member exists on BSDs, not Linux */ - usock.sun_len = (socklen_t)sizeof(usock); + usock.sun_len = (unsigned)sizeof(usock); #endif usock.sun_family = AF_LOCAL; /* length is 92-108, 104 on FreeBSD */ @@ -729,7 +865,11 @@ err: #endif return -1; +#ifdef HAVE_SYSTEMD + } +#endif #else + (void)use_systemd; (void)path; log_err("Local sockets are not supported"); *noproto = 1; @@ -744,7 +884,7 @@ err: static int make_sock(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) { struct addrinfo *res = NULL; int r, s, inuse, noproto; @@ -772,7 +912,7 @@ make_sock(int stype, const char* ifname, const char* port, s = create_udp_sock(res->ai_family, res->ai_socktype, (struct sockaddr*)res->ai_addr, res->ai_addrlen, v6only, &inuse, &noproto, (int)rcv, (int)snd, 1, - reuseport, transparent, freebind); + reuseport, transparent, freebind, use_systemd); if(s == -1 && inuse) { log_err("bind: address already in use"); } else if(s == -1 && noproto && hints->ai_family == AF_INET6){ @@ -780,7 +920,7 @@ make_sock(int stype, const char* ifname, const char* port, } } else { s = create_tcp_accept_sock(res, v6only, &noproto, reuseport, - transparent, tcp_mss, freebind); + transparent, tcp_mss, freebind, use_systemd); if(s == -1 && noproto && hints->ai_family == AF_INET6){ *noip6 = 1; } @@ -793,7 +933,7 @@ make_sock(int stype, const char* ifname, const char* port, static int make_sock_port(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) { char* s = strchr(ifname, '@'); if(s) { @@ -815,10 +955,10 @@ make_sock_port(int stype, const char* ifname, const char* port, (void)strlcpy(p, s+1, sizeof(p)); p[strlen(s+1)]=0; return make_sock(stype, newif, p, hints, v6only, noip6, - rcv, snd, reuseport, transparent, tcp_mss, freebind); + rcv, snd, reuseport, transparent, tcp_mss, freebind, use_systemd); } return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd, - reuseport, transparent, tcp_mss, freebind); + reuseport, transparent, tcp_mss, freebind, use_systemd); } /** @@ -868,7 +1008,7 @@ set_recvpktinfo(int s, int family) } # else log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please " - "disable interface-automatic in config"); + "disable interface-automatic or do-ip6 in config"); return 0; # endif /* defined IPV6_RECVPKTINFO */ @@ -889,7 +1029,7 @@ set_recvpktinfo(int s, int family) } # else log_err("no IP_SENDSRCADDR or IP_PKTINFO option, please disable " - "interface-automatic in config"); + "interface-automatic or do-ip4 in config"); return 0; # endif /* IP_PKTINFO */ @@ -915,13 +1055,14 @@ set_recvpktinfo(int s, int family) * @param transparent: set IP_TRANSPARENT socket option. * @param tcp_mss: maximum segment size of tcp socket. default if zero. * @param freebind: set IP_FREEBIND socket option. + * @param use_systemd: if true, fetch sockets from systemd. * @return: returns false on error. */ static int ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, struct addrinfo *hints, const char* port, struct listen_port** list, size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent, - int tcp_mss, int freebind) + int tcp_mss, int freebind, int use_systemd) { int s, noip6=0; if(!do_udp && !do_tcp) @@ -929,7 +1070,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if(do_auto) { if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind)) == -1) { + tcp_mss, freebind, use_systemd)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -957,7 +1098,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, /* regular udp socket */ if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind)) == -1) { + tcp_mss, freebind, use_systemd)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -979,7 +1120,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, (!strchr(ifname, '@') && atoi(port) == ssl_port)); if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, &noip6, 0, 0, reuseport, transparent, tcp_mss, - freebind)) == -1) { + freebind, use_systemd)) == -1) { if(noip6) { /*log_warn("IPv6 protocol not available");*/ return 1; @@ -1023,7 +1164,7 @@ 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, - struct dt_env* dtenv, comm_point_callback_t* cb, void *cb_arg) + struct dt_env* dtenv, comm_point_callback_type* cb, void *cb_arg) { struct listen_dnsport* front = (struct listen_dnsport*) malloc(sizeof(struct listen_dnsport)); @@ -1137,7 +1278,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, reuseport, cfg->ip_transparent, - cfg->tcp_mss, cfg->ip_freebind)) { + cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) { listening_ports_free(list); return NULL; } @@ -1150,7 +1291,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, reuseport, cfg->ip_transparent, - cfg->tcp_mss, cfg->ip_freebind)) { + cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) { listening_ports_free(list); return NULL; } @@ -1165,7 +1306,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, reuseport, cfg->ip_transparent, - cfg->tcp_mss, cfg->ip_freebind)) { + cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) { listening_ports_free(list); return NULL; } @@ -1178,7 +1319,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, reuseport, cfg->ip_transparent, - cfg->tcp_mss, cfg->ip_freebind)) { + cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd)) { listening_ports_free(list); return NULL; } diff --git a/usr.sbin/unbound/services/listen_dnsport.h b/usr.sbin/unbound/services/listen_dnsport.h index fbaa48321d0..93d2ef7148e 100644 --- a/usr.sbin/unbound/services/listen_dnsport.h +++ b/usr.sbin/unbound/services/listen_dnsport.h @@ -137,7 +137,7 @@ void listening_ports_free(struct listen_port* list); */ 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_t* cb, + void* sslctx, struct dt_env *dtenv, comm_point_callback_type* cb, void* cb_arg); /** @@ -191,11 +191,12 @@ void listen_start_accept(struct listen_dnsport* listen); * listening UDP port. Set to false on return if it failed to do so. * @param transparent: set IP_TRANSPARENT socket option. * @param freebind: set IP_FREEBIND socket option. + * @param use_systemd: if true, fetch sockets from systemd. * @return: the socket. -1 on error. */ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, - int snd, int listen, int* reuseport, int transparent, int freebind); + int snd, int listen, int* reuseport, int transparent, int freebind, int use_systemd); /** * Create and bind TCP listening socket @@ -207,18 +208,20 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, * @param transparent: set IP_TRANSPARENT socket option. * @param mss: maximum segment size of the socket. if zero, leaves the default. * @param freebind: set IP_FREEBIND socket option. + * @param use_systemd: if true, fetch sockets from systemd. * @return: the socket. -1 on error. */ int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind); + int* reuseport, int transparent, int mss, int freebind, int use_systemd); /** * Create and bind local listening socket * @param path: path to the socket. * @param noproto: on error, this is set true if cause is that local sockets * are not supported. + * @param use_systemd: if true, fetch sockets from systemd. * @return: the socket. -1 on error. */ -int create_local_accept_sock(const char* path, int* noproto); +int create_local_accept_sock(const char* path, int* noproto, int use_systemd); #endif /* LISTEN_DNSPORT_H */ diff --git a/usr.sbin/unbound/services/localzone.c b/usr.sbin/unbound/services/localzone.c index fcf6e8dfd7e..d813ab58617 100644 --- a/usr.sbin/unbound/services/localzone.c +++ b/usr.sbin/unbound/services/localzone.c @@ -52,6 +52,11 @@ #include "util/data/msgreply.h" #include "util/data/msgparse.h" #include "util/as112.h" +#include "util/config_file.h" + +/* maximum RRs in an RRset, to cap possible 'endless' list RRs. + * with 16 bytes for an A record, a 64K packet has about 4000 max */ +#define LOCALZONE_RRSET_COUNT_MAX 4096 struct local_zones* local_zones_create(void) @@ -69,7 +74,7 @@ local_zones_create(void) /** helper traverse to delete zones */ static void -lzdel(rbnode_t* n, void* ATTR_UNUSED(arg)) +lzdel(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct local_zone* z = (struct local_zone*)n->key; local_zone_delete(z); @@ -154,13 +159,13 @@ local_zone_create(uint8_t* nm, size_t len, int labs, z->namelen = len; z->namelabs = labs; lock_rw_init(&z->lock); - z->region = regional_create(); + z->region = regional_create_custom(sizeof(struct regional)); if(!z->region) { free(z); return NULL; } rbtree_init(&z->data, &local_data_cmp); - lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_t)); + lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_type)); /* also the zones->lock protects node, parent, name*, class */ return z; } @@ -181,11 +186,18 @@ lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len, lock_rw_wrlock(&zones->lock); lock_rw_wrlock(&z->lock); if(!rbtree_insert(&zones->ztree, &z->node)) { + struct local_zone* oldz; log_warn("duplicate local-zone"); lock_rw_unlock(&z->lock); - local_zone_delete(z); + /* save zone name locally before deallocation, + * otherwise, nm is gone if we zone_delete now. */ + oldz = z; + /* find the correct zone, so not an error for duplicate */ + z = local_zones_find(zones, nm, len, labs, c); + lock_rw_wrlock(&z->lock); lock_rw_unlock(&zones->lock); - return NULL; + local_zone_delete(oldz); + return z; } lock_rw_unlock(&zones->lock); return z; @@ -272,16 +284,20 @@ get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass) * Find an rrset in local data structure. * @param data: local data domain name structure. * @param type: type to look for (host order). + * @param alias_ok: 1 if matching a non-exact, alias type such as CNAME is + * allowed. otherwise 0. * @return rrset pointer or NULL if not found. */ static struct local_rrset* -local_data_find_type(struct local_data* data, uint16_t type) +local_data_find_type(struct local_data* data, uint16_t type, int alias_ok) { struct local_rrset* p; type = htons(type); for(p = data->rrsets; p; p = p->next) { if(p->rrset->rk.type == type) return p; + if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) + return p; } return NULL; } @@ -339,13 +355,18 @@ new_local_rrset(struct regional* region, struct local_data* node, /** insert RR into RRset data structure; Wastes a couple of bytes */ static int insert_rr(struct regional* region, struct packed_rrset_data* pd, - uint8_t* rdata, size_t rdata_len, time_t ttl) + uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr) { size_t* oldlen = pd->rr_len; time_t* oldttl = pd->rr_ttl; uint8_t** olddata = pd->rr_data; /* add RR to rrset */ + if(pd->count > LOCALZONE_RRSET_COUNT_MAX) { + log_warn("RRset '%s' has more than %d records, record ignored", + rrstr, LOCALZONE_RRSET_COUNT_MAX); + return 1; + } pd->count++; pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count); pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count); @@ -456,7 +477,23 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) log_assert(node); free(nm); - rrset = local_data_find_type(node, rrtype); + /* Reject it if we would end up having CNAME and other data (including + * another CNAME) for a redirect zone. */ + if(z->type == local_zone_redirect && node->rrsets) { + const char* othertype = NULL; + if (rrtype == LDNS_RR_TYPE_CNAME) + othertype = "other"; + else if (node->rrsets->rrset->rk.type == + htons(LDNS_RR_TYPE_CNAME)) { + othertype = "CNAME"; + } + if(othertype) { + log_err("local-data '%s' in redirect zone must not " + "coexist with %s local-data", rrstr, othertype); + return 0; + } + } + rrset = local_data_find_type(node, rrtype, 0); if(!rrset) { rrset = new_local_rrset(z->region, node, rrtype, rrclass); if(!rrset) @@ -476,7 +513,7 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr); return 1; } - return insert_rr(z->region, pd, rdata, rdata_len, ttl); + return insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr); } /** enter a data RR into auth data; a zone for it must exist */ @@ -525,7 +562,7 @@ lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list, dname_labs = dname_count_labels(dname); lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, dname, dname_len, dname_labs, rr_class); + z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class); if(!z) { lock_rw_unlock(&zones->lock); log_err("no local-zone for tag %s", zname); @@ -542,6 +579,89 @@ lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list, return r; } +/** enter override into zone */ +static int +lz_enter_override(struct local_zones* zones, char* zname, char* netblock, + char* type, uint16_t rr_class) +{ + uint8_t dname[LDNS_MAX_DOMAINLEN+1]; + size_t dname_len = sizeof(dname); + int dname_labs; + struct sockaddr_storage addr; + int net; + socklen_t addrlen; + struct local_zone* z; + enum localzone_type t; + + /* parse zone name */ + if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) { + log_err("cannot parse zone name in local-zone-override: %s %s", + zname, netblock); + return 0; + } + dname_labs = dname_count_labels(dname); + + /* parse netblock */ + if(!netblockstrtoaddr(netblock, UNBOUND_DNS_PORT, &addr, &addrlen, + &net)) { + log_err("cannot parse netblock in local-zone-override: %s %s", + zname, netblock); + return 0; + } + + /* parse zone type */ + if(!local_zone_str2type(type, &t)) { + log_err("cannot parse type in local-zone-override: %s %s %s", + zname, netblock, type); + return 0; + } + + /* find localzone entry */ + lock_rw_rdlock(&zones->lock); + z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class); + if(!z) { + lock_rw_unlock(&zones->lock); + log_err("no local-zone for local-zone-override %s", zname); + return 0; + } + lock_rw_wrlock(&z->lock); + lock_rw_unlock(&zones->lock); + + /* create netblock addr_tree if not present yet */ + if(!z->override_tree) { + z->override_tree = (struct rbtree_type*)regional_alloc_zero( + z->region, sizeof(*z->override_tree)); + if(!z->override_tree) { + lock_rw_unlock(&z->lock); + log_err("out of memory"); + return 0; + } + addr_tree_init(z->override_tree); + } + /* add new elem to tree */ + if(z->override_tree) { + struct local_zone_override* n; + n = (struct local_zone_override*)regional_alloc_zero( + z->region, sizeof(*n)); + if(!n) { + lock_rw_unlock(&z->lock); + log_err("out of memory"); + return 0; + } + n->type = t; + if(!addr_tree_insert(z->override_tree, + (struct addr_tree_node*)n, &addr, addrlen, net)) { + lock_rw_unlock(&z->lock); + log_err("duplicate local-zone-override %s %s", + zname, netblock); + return 1; + } + } + + lock_rw_unlock(&z->lock); + return 1; +} + /** parse local-zone: statements */ static int lz_enter_zones(struct local_zones* zones, struct config_file* cfg) @@ -720,6 +840,19 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg) return 1; } +/** parse local-zone-override: statements */ +static int +lz_enter_overrides(struct local_zones* zones, struct config_file* cfg) +{ + struct config_str3list* p; + for(p = cfg->local_zone_overrides; p; p = p->next) { + if(!lz_enter_override(zones, p->str, p->str2, p->str3, + LDNS_RR_CLASS_IN)) + return 0; + } + return 1; +} + /** setup parent pointers, so that a lookup can be done for closest match */ static void init_parents(struct local_zones* zones) @@ -749,6 +882,9 @@ init_parents(struct local_zones* zones) break; } prev = node; + + if(node->override_tree) + addr_tree_init_parents(node->override_tree); lock_rw_unlock(&node->lock); } lock_rw_unlock(&zones->lock); @@ -887,6 +1023,10 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg) if(!lz_enter_defaults(zones, cfg)) { return 0; } + /* enter local zone overrides */ + if(!lz_enter_overrides(zones, cfg)) { + return 0; + } /* create implicit transparent zone from data. */ if(!lz_setup_implicit(zones, cfg)) { return 0; @@ -911,33 +1051,41 @@ struct local_zone* local_zones_lookup(struct local_zones* zones, uint8_t* name, size_t len, int labs, uint16_t dclass) { - rbnode_t* res = NULL; + return local_zones_tags_lookup(zones, name, len, labs, + dclass, NULL, 0, 1); +} + +struct local_zone* +local_zones_tags_lookup(struct local_zones* zones, + uint8_t* name, size_t len, int labs, uint16_t dclass, + uint8_t* taglist, size_t taglen, int ignoretags) +{ + rbnode_type* res = NULL; struct local_zone *result; struct local_zone key; + int m; key.node.key = &key; key.dclass = dclass; key.name = name; key.namelen = len; key.namelabs = labs; - if(rbtree_find_less_equal(&zones->ztree, &key, &res)) { - /* exact */ - return (struct local_zone*)res; - } else { - /* smaller element (or no element) */ - int m; - result = (struct local_zone*)res; - if(!result || result->dclass != dclass) - return NULL; - /* count number of labels matched */ - (void)dname_lab_cmp(result->name, result->namelabs, key.name, - key.namelabs, &m); - while(result) { /* go up until qname is subdomain of zone */ - if(result->namelabs <= m) - break; - result = result->parent; - } - return result; - } + rbtree_find_less_equal(&zones->ztree, &key, &res); + result = (struct local_zone*)res; + /* exact or smaller element (or no element) */ + if(!result || result->dclass != dclass) + return NULL; + /* count number of labels matched */ + (void)dname_lab_cmp(result->name, result->namelabs, key.name, + key.namelabs, &m); + while(result) { /* go up until qname is zone or subdomain of zone */ + if(result->namelabs <= m) + if(ignoretags || !result->taglist || + taglist_intersect(result->taglist, + result->taglen, taglist, taglen)) + break; + result = result->parent; + } + return result; } struct local_zone* @@ -1009,6 +1157,18 @@ void local_zones_print(struct local_zones* zones) log_nametypeclass(0, "inform_deny zone", z->name, 0, z->dclass); break; + case local_zone_always_transparent: + log_nametypeclass(0, "always_transparent zone", + z->name, 0, z->dclass); + break; + case local_zone_always_refuse: + log_nametypeclass(0, "always_refuse zone", + z->name, 0, z->dclass); + break; + case local_zone_always_nxdomain: + log_nametypeclass(0, "always_nxdomain zone", + z->name, 0, z->dclass); + break; default: log_nametypeclass(0, "badtyped zone", z->name, 0, z->dclass); @@ -1022,8 +1182,8 @@ void local_zones_print(struct local_zones* zones) /** encode answer consisting of 1 rrset */ static int -local_encode(struct query_info* qinfo, struct edns_data* edns, - sldns_buffer* buf, struct regional* temp, +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 reply_info rep; @@ -1042,23 +1202,145 @@ local_encode(struct query_info* qinfo, struct edns_data* edns, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - if(!edns_opt_inplace_reply(edns, temp) || - !reply_info_answer_encode(qinfo, &rep, + 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, + 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); + 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) +{ + edns->edns_version = EDNS_ADVERTISED_VERSION; + edns->udp_size = EDNS_ADVERTISED_SIZE; + edns->ext_rcode = 0; + edns->bits &= EDNS_DO; + + if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, + rcode, edns, temp)) + edns->opt_list = NULL; + error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), + sldns_buffer_read_u16_at(buf, 2), edns); +} + +/** find local data tag string match for the given type in the list */ +static int +find_tag_datas(struct query_info* qinfo, struct config_strlist* list, + struct ub_packed_rrset_key* r, struct regional* temp) +{ + struct config_strlist* p; + char buf[65536]; + uint8_t rr[LDNS_RR_BUF_SIZE]; + size_t len; + int res; + struct packed_rrset_data* d; + for(p=list; p; p=p->next) { + uint16_t rdr_type; + + len = sizeof(rr); + /* does this element match the type? */ + snprintf(buf, sizeof(buf), ". %s", p->str); + res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, + NULL, 0, NULL, 0); + if(res != 0) + /* parse errors are already checked before, in + * acllist check_data, skip this for robustness */ + continue; + if(len < 1 /* . */ + 8 /* typeclassttl*/ + 2 /*rdatalen*/) + continue; + rdr_type = sldns_wirerr_get_type(rr, len, 1); + if(rdr_type != qinfo->qtype && rdr_type != LDNS_RR_TYPE_CNAME) + continue; + + /* do we have entries already? if not setup key */ + if(r->rk.dname == NULL) { + r->entry.key = r; + r->rk.dname = qinfo->qname; + r->rk.dname_len = qinfo->qname_len; + r->rk.type = htons(rdr_type); + r->rk.rrset_class = htons(qinfo->qclass); + r->rk.flags = 0; + d = (struct packed_rrset_data*)regional_alloc_zero( + temp, sizeof(struct packed_rrset_data) + + sizeof(size_t) + sizeof(uint8_t*) + + sizeof(time_t)); + if(!d) return 0; /* out of memory */ + r->entry.data = d; + d->ttl = sldns_wirerr_get_ttl(rr, len, 1); + d->rr_len = (size_t*)((uint8_t*)d + + sizeof(struct packed_rrset_data)); + d->rr_data = (uint8_t**)&(d->rr_len[1]); + d->rr_ttl = (time_t*)&(d->rr_data[1]); + } + d = (struct packed_rrset_data*)r->entry.data; + /* add entry to the data */ + if(d->count != 0) { + size_t* oldlen = d->rr_len; + uint8_t** olddata = d->rr_data; + time_t* oldttl = d->rr_ttl; + /* increase arrays for lookup */ + /* this is of course slow for very many records, + * but most redirects are expected with few records */ + d->rr_len = (size_t*)regional_alloc_zero(temp, + (d->count+1)*sizeof(size_t)); + d->rr_data = (uint8_t**)regional_alloc_zero(temp, + (d->count+1)*sizeof(uint8_t*)); + d->rr_ttl = (time_t*)regional_alloc_zero(temp, + (d->count+1)*sizeof(time_t)); + if(!d->rr_len || !d->rr_data || !d->rr_ttl) + return 0; /* out of memory */ + /* first one was allocated after struct d, but new + * ones get their own array increment alloc, so + * copy old content */ + memmove(d->rr_len, oldlen, d->count*sizeof(size_t)); + memmove(d->rr_data, olddata, d->count*sizeof(uint8_t*)); + memmove(d->rr_ttl, oldttl, d->count*sizeof(time_t)); + } + + d->rr_len[d->count] = sldns_wirerr_get_rdatalen(rr, len, 1)+2; + d->rr_ttl[d->count] = sldns_wirerr_get_ttl(rr, len, 1); + d->rr_data[d->count] = regional_alloc_init(temp, + sldns_wirerr_get_rdatawl(rr, len, 1), + d->rr_len[d->count]); + if(!d->rr_data[d->count]) + if(!d) return 0; /* out of memory */ + d->count++; + } + /* If we've found a non-exact alias type of local data, make a shallow + * copy of the RRset and remember it in qinfo to complete the alias + * chain later. */ + if(r->rk.dname && qinfo->qtype != LDNS_RR_TYPE_CNAME && + r->rk.type == htons(LDNS_RR_TYPE_CNAME)) { + qinfo->local_alias = + regional_alloc_zero(temp, sizeof(struct local_rrset)); + if(!qinfo->local_alias) + return 0; /* out of memory */ + qinfo->local_alias->rrset = + regional_alloc_init(temp, r, sizeof(*r)); + if(!qinfo->local_alias->rrset) + return 0; /* out of memory */ + } + if(r->rk.dname) + return 1; + return 0; +} + /** answer local data match */ static int -local_data_answer(struct local_zone* z, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - int labs, struct local_data** ldp) +local_data_answer(struct local_zone* z, struct module_env* env, + struct query_info* qinfo, struct edns_data* edns, 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) { struct local_data key; struct local_data* ld; @@ -1067,58 +1349,95 @@ local_data_answer(struct local_zone* z, struct query_info* qinfo, key.name = qinfo->qname; key.namelen = qinfo->qname_len; key.namelabs = labs; - if(z->type == local_zone_redirect) { + if(lz_type == local_zone_redirect) { key.name = z->name; key.namelen = z->namelen; key.namelabs = z->namelabs; + if(tag != -1 && (size_t)tag<tag_datas_size && tag_datas[tag]) { + struct ub_packed_rrset_key r; + memset(&r, 0, sizeof(r)); + if(find_tag_datas(qinfo, tag_datas[tag], &r, temp)) { + verbose(VERB_ALGO, "redirect with tag data [%d] %s", + tag, (tag<num_tags?tagname[tag]:"null")); + + /* If we found a matching alias, we should + * use it as part of the answer, but we can't + * encode it until we complete the alias + * chain. */ + if(qinfo->local_alias) + return 1; + return local_encode(qinfo, env, edns, buf, temp, + &r, 1, LDNS_RCODE_NOERROR); + } + } } ld = (struct local_data*)rbtree_search(&z->data, &key.node); *ldp = ld; if(!ld) { return 0; } - lr = local_data_find_type(ld, qinfo->qtype); + lr = local_data_find_type(ld, qinfo->qtype, 1); if(!lr) return 0; - if(z->type == local_zone_redirect) { + + /* Special case for alias matching. See local_data_answer(). */ + if(lz_type == local_zone_redirect && + qinfo->qtype != LDNS_RR_TYPE_CNAME && + lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) { + qinfo->local_alias = + regional_alloc_zero(temp, sizeof(struct local_rrset)); + if(!qinfo->local_alias) + return 0; /* out of memory */ + qinfo->local_alias->rrset = + regional_alloc_init(temp, lr->rrset, sizeof(*lr->rrset)); + if(!qinfo->local_alias->rrset) + return 0; /* out of memory */ + qinfo->local_alias->rrset->rk.dname = qinfo->qname; + qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len; + return 1; + } + if(lz_type == local_zone_redirect) { /* convert rrset name to query name; like a wildcard */ struct ub_packed_rrset_key r = *lr->rrset; r.rk.dname = qinfo->qname; r.rk.dname_len = qinfo->qname_len; - return local_encode(qinfo, edns, buf, temp, &r, 1, + return local_encode(qinfo, env, edns, buf, temp, &r, 1, LDNS_RCODE_NOERROR); } - return local_encode(qinfo, edns, buf, temp, lr->rrset, 1, + return local_encode(qinfo, env, edns, buf, temp, lr->rrset, 1, LDNS_RCODE_NOERROR); } /** * 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 buf: buffer for answer. * @param temp: temp region for encoding * @param ld: local data, if NULL, no such name exists in localdata. + * @param lz_type: type of the local zone * @return 1 if a reply is to be sent, 0 if not. */ static int -lz_zone_answer(struct local_zone* z, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - struct local_data* ld) +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) { - if(z->type == local_zone_deny || z->type == local_zone_inform_deny) { + if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { /** no reply at all, signal caller by clearing buffer. */ sldns_buffer_clear(buf); sldns_buffer_flip(buf); return 1; - } else if(z->type == local_zone_refuse) { - error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo, - *(uint16_t*)sldns_buffer_begin(buf), - sldns_buffer_read_u16_at(buf, 2), edns); + } else if(lz_type == local_zone_refuse + || lz_type == local_zone_always_refuse) { + local_error_encode(qinfo, env, edns, buf, temp, + LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA)); return 1; - } else if(z->type == local_zone_static || - z->type == local_zone_redirect) { + } else if(lz_type == local_zone_static || + lz_type == local_zone_redirect || + lz_type == local_zone_always_nxdomain) { /* for static, reply nodata or nxdomain * for redirect, reply nodata */ /* no additional section processing, @@ -1126,30 +1445,30 @@ lz_zone_answer(struct local_zone* z, struct query_info* qinfo, * or using closest match for NSEC. * or using closest match for returning delegation downwards */ - int rcode = ld?LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; + int rcode = (ld || lz_type == local_zone_redirect)? + LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; if(z->soa) - return local_encode(qinfo, edns, buf, temp, + return local_encode(qinfo, env, edns, buf, temp, z->soa, 0, rcode); - error_encode(buf, (rcode|BIT_AA), qinfo, - *(uint16_t*)sldns_buffer_begin(buf), - sldns_buffer_read_u16_at(buf, 2), edns); + local_error_encode(qinfo, env, edns, buf, temp, rcode, + (rcode|BIT_AA)); return 1; - } else if(z->type == local_zone_typetransparent) { + } else if(lz_type == local_zone_typetransparent + || lz_type == local_zone_always_transparent) { /* no NODATA or NXDOMAINS for this zone type */ return 0; } - /* else z->type == local_zone_transparent */ + /* else lz_type == local_zone_transparent */ /* if the zone is transparent and the name exists, but the type * does not, then we should make this noerror/nodata */ if(ld && ld->rrsets) { int rcode = LDNS_RCODE_NOERROR; if(z->soa) - return local_encode(qinfo, edns, buf, temp, + return local_encode(qinfo, env, edns, buf, temp, z->soa, 0, rcode); - error_encode(buf, (rcode|BIT_AA), qinfo, - *(uint16_t*)sldns_buffer_begin(buf), - sldns_buffer_read_u16_at(buf, 2), edns); + local_error_encode(qinfo, env, edns, buf, temp, rcode, + (rcode|BIT_AA)); return 1; } @@ -1172,44 +1491,125 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo, log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); } +static enum localzone_type +lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2, + uint8_t *tagactions, size_t tagactionssize, enum localzone_type lzt, + struct comm_reply* repinfo, struct rbtree_type* override_tree, + int* tag, char** tagname, int num_tags) +{ + size_t i, j; + uint8_t tagmatch; + struct local_zone_override* lzo; + if(repinfo && override_tree) { + lzo = (struct local_zone_override*)addr_tree_lookup( + override_tree, &repinfo->addr, repinfo->addrlen); + if(lzo && lzo->type) { + verbose(VERB_ALGO, "local zone override to type %s", + local_zone_type2str(lzo->type)); + return lzo->type; + } + } + if(!taglist || !taglist2) + return lzt; + for(i=0; i<taglen && i<taglen2; i++) { + tagmatch = (taglist[i] & taglist2[i]); + for(j=0; j<8 && tagmatch>0; j++) { + if((tagmatch & 0x1)) { + *tag = (int)(i*8+j); + verbose(VERB_ALGO, "matched tag [%d] %s", + *tag, (*tag<num_tags?tagname[*tag]:"null")); + /* does this tag have a tag action? */ + if(i*8+j < tagactionssize && tagactions + && tagactions[i*8+j] != 0) { + verbose(VERB_ALGO, "tag action [%d] %s to type %s", + *tag, (*tag<num_tags?tagname[*tag]:"null"), + local_zone_type2str( + (enum localzone_type) + tagactions[i*8+j])); + return (enum localzone_type)tagactions[i*8+j]; + } + return lzt; + } + tagmatch >>= 1; + } + } + return lzt; +} + int -local_zones_answer(struct local_zones* zones, struct query_info* qinfo, - struct edns_data* edns, sldns_buffer* buf, struct regional* temp, - struct comm_reply* repinfo) +local_zones_answer(struct local_zones* zones, struct module_env* env, + struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, + struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, + size_t taglen, uint8_t* tagactions, size_t tagactionssize, + struct config_strlist** tag_datas, size_t tag_datas_size, + char** tagname, int num_tags, struct view* view) { /* see if query is covered by a zone, * if so: - try to match (exact) local data * - look at zone type for negative response. */ int labs = dname_count_labels(qinfo->qname); - struct local_data* ld; - struct local_zone* z; - int r; - lock_rw_rdlock(&zones->lock); - z = local_zones_lookup(zones, qinfo->qname, - qinfo->qname_len, labs, qinfo->qclass); + struct local_data* ld = NULL; + struct local_zone* z = NULL; + enum localzone_type lzt = local_zone_transparent; + int r, tag = -1; + + if(view) { + lock_rw_rdlock(&view->lock); + if(view->local_zones && + (z = local_zones_lookup(view->local_zones, + qinfo->qname, qinfo->qname_len, labs, + qinfo->qclass))) { + verbose(VERB_ALGO, + "using localzone from view: %s", + view->name); + lock_rw_rdlock(&z->lock); + lzt = z->type; + } + if(!z && !view->isfirst){ + lock_rw_unlock(&view->lock); + return 0; + } + lock_rw_unlock(&view->lock); + } if(!z) { + /* try global local_zones tree */ + lock_rw_rdlock(&zones->lock); + if(!(z = local_zones_tags_lookup(zones, qinfo->qname, + qinfo->qname_len, labs, qinfo->qclass, taglist, + taglen, 0))) { + lock_rw_unlock(&zones->lock); + 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); - return 0; } - lock_rw_rdlock(&z->lock); - lock_rw_unlock(&zones->lock); - - if((z->type == local_zone_inform || z->type == local_zone_inform_deny) + if((lzt == local_zone_inform || lzt == local_zone_inform_deny) && repinfo) lz_inform_print(z, qinfo, repinfo); - if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) { + 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)) { lock_rw_unlock(&z->lock); - return 1; + /* We should tell the caller that encode is deferred if we found + * a local alias. */ + return !qinfo->local_alias; } - r = lz_zone_answer(z, qinfo, edns, buf, temp, ld); + r = lz_zone_answer(z, env, qinfo, edns, buf, temp, ld, lzt); lock_rw_unlock(&z->lock); - return r; + return r && !qinfo->local_alias; /* see above */ } const char* local_zone_type2str(enum localzone_type t) { switch(t) { + case local_zone_unset: return "unset"; case local_zone_deny: return "deny"; case local_zone_refuse: return "refuse"; case local_zone_redirect: return "redirect"; @@ -1219,6 +1619,9 @@ const char* local_zone_type2str(enum localzone_type t) case local_zone_nodefault: return "nodefault"; case local_zone_inform: return "inform"; case local_zone_inform_deny: return "inform_deny"; + case local_zone_always_transparent: return "always_transparent"; + case local_zone_always_refuse: return "always_refuse"; + case local_zone_always_nxdomain: return "always_nxdomain"; } return "badtyped"; } @@ -1241,6 +1644,12 @@ int local_zone_str2type(const char* type, enum localzone_type* t) *t = local_zone_inform; else if(strcmp(type, "inform_deny") == 0) *t = local_zone_inform_deny; + else if(strcmp(type, "always_transparent") == 0) + *t = local_zone_always_transparent; + else if(strcmp(type, "always_refuse") == 0) + *t = local_zone_always_refuse; + else if(strcmp(type, "always_nxdomain") == 0) + *t = local_zone_always_nxdomain; else return 0; return 1; } diff --git a/usr.sbin/unbound/services/localzone.h b/usr.sbin/unbound/services/localzone.h index 964df19383c..bf9c9bf489c 100644 --- a/usr.sbin/unbound/services/localzone.h +++ b/usr.sbin/unbound/services/localzone.h @@ -43,6 +43,9 @@ #define SERVICES_LOCALZONE_H #include "util/rbtree.h" #include "util/locks.h" +#include "util/storage/dnstree.h" +#include "util/module.h" +#include "services/view.h" struct ub_packed_rrset_key; struct regional; struct config_file; @@ -50,6 +53,7 @@ struct edns_data; struct query_info; struct sldns_buffer; struct comm_reply; +struct config_strlist; /** * Local zone type @@ -57,8 +61,10 @@ struct comm_reply; * local-data directly. */ enum localzone_type { + /** unset type, used for unset tag_action elements */ + local_zone_unset = 0, /** drop query */ - local_zone_deny = 0, + local_zone_deny, /** answer with error */ local_zone_refuse, /** answer nxdomain or nodata */ @@ -75,7 +81,13 @@ enum localzone_type { /** log client address, but no block (transparent) */ local_zone_inform, /** log client address, and block (drop) */ - local_zone_inform_deny + local_zone_inform_deny, + /** resolve normally, even when there is local data */ + local_zone_always_transparent, + /** answer with error, even when there is local data */ + local_zone_always_refuse, + /** answer with nxdomain, even when there is local data */ + local_zone_always_nxdomain }; /** @@ -83,9 +95,9 @@ enum localzone_type { */ struct local_zones { /** lock on the localzone tree */ - lock_rw_t lock; + lock_rw_type lock; /** rbtree of struct local_zone */ - rbtree_t ztree; + rbtree_type ztree; }; /** @@ -93,7 +105,7 @@ struct local_zones { */ struct local_zone { /** rbtree node, key is name and class */ - rbnode_t node; + rbnode_type node; /** parent zone, if any. */ struct local_zone* parent; @@ -111,7 +123,7 @@ struct local_zone { * For the node, parent, name, namelen, namelabs, dclass, you * need to also hold the zones_tree lock to change them (or to * delete this zone) */ - lock_rw_t lock; + lock_rw_type lock; /** how to process zone */ enum localzone_type type; @@ -119,13 +131,16 @@ struct local_zone { uint8_t* taglist; /** length of the taglist (in bytes) */ size_t taglen; + /** netblock addr_tree with struct local_zone_override information + * or NULL if there are no override elements */ + struct rbtree_type* override_tree; /** in this region the zone's data is allocated. * the struct local_zone itself is malloced. */ struct regional* region; /** local data for this zone * rbtree of struct local_data */ - rbtree_t data; + rbtree_type data; /** if data contains zone apex SOA data, this is a ptr to it. */ struct ub_packed_rrset_key* soa; }; @@ -135,7 +150,7 @@ struct local_zone { */ struct local_data { /** rbtree node, key is name only */ - rbnode_t node; + rbnode_type node; /** domain name */ uint8_t* name; /** length of name */ @@ -158,6 +173,16 @@ struct local_rrset { }; /** + * Local zone override information + */ +struct local_zone_override { + /** node in addrtree */ + struct addr_tree_node node; + /** override for local zone type */ + enum localzone_type type; +}; + +/** * Create local zones storage * @return new struct or NULL on error. */ @@ -202,6 +227,24 @@ int local_data_cmp(const void* d1, const void* d2); void local_zone_delete(struct local_zone* z); /** + * Lookup zone that contains the given name, class and taglist. + * User must lock the tree or result zone. + * @param zones: the zones tree + * @param name: dname to lookup + * @param len: length of name. + * @param labs: labelcount of name. + * @param dclass: class to lookup. + * @param taglist: taglist to lookup. + * @param taglen: lenth of taglist. + * @param ignoretags: lookup zone by name and class, regardless the + * local-zone's tags. + * @return closest local_zone or NULL if no covering zone is found. + */ +struct local_zone* local_zones_tags_lookup(struct local_zones* zones, + uint8_t* name, size_t len, int labs, uint16_t dclass, + uint8_t* taglist, size_t taglen, int ignoretags); + +/** * Lookup zone that contains the given name, class. * User must lock the tree or result zone. * @param zones: the zones tree @@ -225,18 +268,39 @@ void local_zones_print(struct local_zones* zones); * Answer authoritatively for local zones. * Takes care of locking. * @param zones: the stored zones (shared, read only). + * @param env: the module environment. * @param qinfo: query info (parsed). * @param edns: edns info (parsed). * @param buf: buffer with query ID and flags, also for reply. * @param temp: temporary storage region. * @param repinfo: source address for checks. may be NULL. + * @param taglist: taglist for checks. May be NULL. + * @param taglen: length of the taglist. + * @param tagactions: local zone actions for tags. May be NULL. + * @param tagactionssize: length of the tagactions. + * @param tag_datas: array per tag of strlist with rdata strings. or NULL. + * @param tag_datas_size: size of tag_datas array. + * @param tagname: array of tag name strings (for debug output). + * @param num_tags: number of items in tagname array. + * @param view: answer using this view. May be NULL. * @return true if answer is in buffer. false if query is not answered * by authority data. If the reply should be dropped altogether, the return * value is true, but the buffer is cleared (empty). + * It can also return true if a non-exact alias answer is found. In this + * case qinfo->local_alias points to the corresponding alias RRset but the + * answer is NOT encoded in buffer. It's the caller's responsibility to + * complete the alias chain (if needed) and encode the final set of answer. + * Data pointed to by qinfo->local_alias is allocated in 'temp' or refers to + * configuration data. So the caller will need to make a deep copy of it + * if it needs to keep it beyond the lifetime of 'temp' or a dynamic update + * to local zone data. */ -int local_zones_answer(struct local_zones* zones, struct query_info* qinfo, - struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp, - struct comm_reply* repinfo); +int local_zones_answer(struct local_zones* zones, struct module_env* env, + struct query_info* qinfo, struct edns_data* edns, struct sldns_buffer* buf, + struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, + size_t taglen, uint8_t* tagactions, size_t tagactionssize, + struct config_strlist** tag_datas, size_t tag_datas_size, + char** tagname, int num_tags, struct view* view); /** * Parse the string into localzone type. diff --git a/usr.sbin/unbound/services/mesh.c b/usr.sbin/unbound/services/mesh.c index b0434b3ff0c..f5a193ac2d4 100644 --- a/usr.sbin/unbound/services/mesh.c +++ b/usr.sbin/unbound/services/mesh.c @@ -56,6 +56,9 @@ #include "util/alloc.h" #include "util/config_file.h" #include "sldns/sbuffer.h" +#include "sldns/wire2str.h" +#include "services/localzone.h" +#include "util/data/dname.h" /** subtract timers and the values do not overflow or become negative */ static void @@ -127,6 +130,11 @@ mesh_state_compare(const void* ap, const void* bp) struct mesh_state* a = (struct mesh_state*)ap; struct mesh_state* b = (struct mesh_state*)bp; + if(a->unique < b->unique) + return -1; + if(a->unique > b->unique) + return 1; + if(a->s.is_priming && !b->s.is_priming) return -1; if(!a->s.is_priming && b->s.is_priming) @@ -195,7 +203,7 @@ mesh_create(struct module_stack* stack, struct module_env* env) /** help mesh delete delete mesh states */ static void -mesh_delete_helper(rbnode_t* n) +mesh_delete_helper(rbnode_type* n) { struct mesh_state* mstate = (struct mesh_state*)n->key; /* perform a full delete, not only 'cleanup' routine, @@ -282,10 +290,13 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, uint16_t qid) { - struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); + struct mesh_state* s = NULL; + int unique = edns_unique_mesh_state(edns->opt_list, mesh->env); int was_detached = 0; int was_noreply = 0; int added = 0; + if(!unique) + s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); /* does this create a new reply state? */ if(!s || s->list_select == mesh_no_list) { if(!mesh_make_new_space(mesh, rep->c->buffer)) { @@ -310,18 +321,37 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, /* see if it already exists, if not, create one */ if(!s) { #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); if(!s) { log_err("mesh_state_create: out of memory; SERVFAIL"); - if(!edns_opt_inplace_reply(edns, mesh->env->scratch)) - edns->opt_list = NULL; + if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, + LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch)) + edns->opt_list = NULL; error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); return; } + if(unique) + mesh_state_make_unique(s); + /* copy the edns options we got from the front */ + if(edns->opt_list) { + s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list, + s->s.region); + 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)) + edns->opt_list = NULL; + error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, + qinfo, qid, qflags, edns); + comm_point_send_reply(rep); + return; + } + } + #ifdef UNBOUND_DEBUG n = #else @@ -338,10 +368,11 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, if(!s->reply_list && !s->cb_list) was_noreply = 1; /* add reply to s */ - if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) { + if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) { log_err("mesh_new_client: out of memory; SERVFAIL"); - if(!edns_opt_inplace_reply(edns, mesh->env->scratch)) - edns->opt_list = NULL; + if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s, + NULL, LDNS_RCODE_SERVFAIL, edns, mesh->env->scratch)) + edns->opt_list = NULL; error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -378,23 +409,35 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, - uint16_t qid, mesh_cb_func_t cb, void* cb_arg) + uint16_t qid, mesh_cb_func_type cb, void* cb_arg) { - struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); + struct mesh_state* s = NULL; + int unique = edns_unique_mesh_state(edns->opt_list, mesh->env); int was_detached = 0; int was_noreply = 0; int added = 0; + if(!unique) + s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); /* there are no limits on the number of callbacks */ /* see if it already exists, if not, create one */ if(!s) { #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); if(!s) { return 0; } + if(unique) + mesh_state_make_unique(s); + if(edns->opt_list) { + s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list, + s->s.region); + if(!s->s.edns_opts_front_in) { + return 0; + } + } #ifdef UNBOUND_DEBUG n = #else @@ -433,9 +476,10 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, time_t leeway) { - struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); + struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&(BIT_RD|BIT_CD), + 0, 0); #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif /* already exists, and for a different purpose perhaps. * if mesh_no_list, keep it that way. */ @@ -452,6 +496,7 @@ void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo, mesh->stats_dropped ++; return; } + s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); if(!s) { log_err("prefetch mesh_state_create: out of memory"); @@ -525,9 +570,11 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo, rbtree_init(&mstate->super_set, &mesh_state_ref_compare); rbtree_init(&mstate->sub_set, &mesh_state_ref_compare); mstate->num_activated = 0; + mstate->unique = NULL; /* init module qstate */ mstate->s.qinfo.qtype = qinfo->qtype; mstate->s.qinfo.qclass = qinfo->qclass; + mstate->s.qinfo.local_alias = NULL; mstate->s.qinfo.qname_len = qinfo->qname_len; mstate->s.qinfo.qname = regional_alloc_init(region, qinfo->qname, qinfo->qname_len); @@ -547,14 +594,34 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo, mstate->s.env = env; mstate->s.mesh_info = mstate; mstate->s.prefetch_leeway = 0; + mstate->s.no_cache_lookup = 0; + mstate->s.no_cache_store = 0; /* init modules */ for(i=0; i<env->mesh->mods.num; i++) { mstate->s.minfo[i] = NULL; mstate->s.ext_state[i] = module_state_initial; } + /* init edns option lists */ + mstate->s.edns_opts_front_in = NULL; + mstate->s.edns_opts_back_out = NULL; + mstate->s.edns_opts_back_in = NULL; + mstate->s.edns_opts_front_out = NULL; + return mstate; } +int +mesh_state_is_unique(struct mesh_state* mstate) +{ + return mstate->unique != NULL; +} + +void +mesh_state_make_unique(struct mesh_state* mstate) +{ + mstate->unique = mstate; +} + void mesh_state_cleanup(struct mesh_state* mstate) { @@ -662,7 +729,7 @@ void mesh_detach_subs(struct module_qstate* qstate) struct mesh_area* mesh = qstate->env->mesh; struct mesh_state_ref* ref, lookup; #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif lookup.node.key = &lookup; lookup.s = qstate->mesh_info; @@ -689,8 +756,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, { /* find it, if not, create it */ struct mesh_area* mesh = qstate->env->mesh; - struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime, - valrec); + struct mesh_state* sub = mesh_area_find(mesh, qinfo, qflags, prime, valrec); int was_detached; if(mesh_detect_cycle_found(qstate, sub)) { verbose(VERB_ALGO, "attach failed, cycle detected"); @@ -698,11 +764,10 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, } if(!sub) { #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif /* create a new one */ - sub = mesh_state_create(qstate->env, qinfo, qflags, prime, - valrec); + sub = mesh_state_create(qstate->env, qinfo, qflags, prime, valrec); if(!sub) { log_err("mesh_attach_sub: out of memory"); return 0; @@ -744,7 +809,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub) { #ifdef UNBOUND_DEBUG - struct rbnode_t* n; + struct rbnode_type* n; #endif struct mesh_state_ref* subref; /* points to sub, inserted in super */ struct mesh_state_ref* superref; /* points to super, inserted in sub */ @@ -804,6 +869,15 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, } /* 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)) + 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.opt_list = NULL; + } fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL); } else { @@ -813,8 +887,10 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.udp_size = EDNS_ADVERTISED_SIZE; r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; - if(!edns_opt_inplace_reply(&r->edns, m->s.region) || - !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, + + if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, + LDNS_RCODE_NOERROR, &r->edns, 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, (int)(r->edns.bits & EDNS_DO), secure)) @@ -847,6 +923,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, struct timeval end_time; struct timeval duration; int secure; + /* Copy the client's EDNS for later restore, to make sure the edns + * compare is with the correct edns options. */ + struct edns_data edns_bak = r->edns; /* examine security status */ if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) || m->s.env->cfg->ignore_cd) && rep && @@ -861,7 +940,13 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, if(!rep && rcode == LDNS_RCODE_NOERROR) rcode = LDNS_RCODE_SERVFAIL; /* send the reply */ + /* We don't reuse the encoded answer if either the previous or current + * response has a local alias. We could compare the alias records + * and still reuse the previous answer if they are the same, but that + * would be complicated and error prone for the relatively minor case. + * So we err on the side of safety. */ if(prev && prev->qflags == r->qflags && + !prev->local_alias && !r->local_alias && prev->edns.edns_present == r->edns.edns_present && prev->edns.bits == r->edns.bits && prev->edns.udp_size == r->edns.udp_size && @@ -878,6 +963,16 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, comm_point_send_reply(&r->query_reply); } else if(rcode) { m->s.qinfo.qname = r->qname; + 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)) + 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.opt_list = NULL; + } error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); comm_point_send_reply(&r->query_reply); @@ -888,16 +983,22 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; m->s.qinfo.qname = r->qname; - if(!edns_opt_inplace_reply(&r->edns, m->s.region) || - !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, + 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) || + !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)) + r->edns.opt_list = NULL; error_encode(r->query_reply.c->buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } + r->edns = edns_bak; comm_point_send_reply(&r->query_reply); } /* account */ @@ -918,6 +1019,12 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, query_reply.c->buffer)) == 0) m->s.env->mesh->ans_nodata++; } + /* Log reply sent */ + if(m->s.env->cfg->log_replies) { + log_reply_info(0, &m->s.qinfo, &r->query_reply.addr, + r->query_reply.addrlen, duration, 0, + r->query_reply.c->buffer); + } } void mesh_query_done(struct mesh_state* mstate) @@ -963,13 +1070,17 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh, key.s.is_valrec = valrec; key.s.qinfo = *qinfo; key.s.query_flags = qflags; + /* We are searching for a similar mesh state when we DO want to + * aggregate the state. Thus unique is set to NULL. (default when we + * desire aggregation).*/ + key.unique = NULL; result = (struct mesh_state*)rbtree_search(&mesh->all, &key); return result; } int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, - sldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg, + sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, uint16_t qid, uint16_t qflags) { struct mesh_cb* r = regional_alloc(s->s.region, @@ -996,7 +1107,8 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, } int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, - struct comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname) + struct comm_reply* rep, uint16_t qid, uint16_t qflags, + const struct query_info* qinfo) { struct mesh_reply* r = regional_alloc(s->s.region, sizeof(struct mesh_reply)); @@ -1014,10 +1126,62 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, r->qflags = qflags; r->start_time = *s->s.env->now_tv; r->next = s->reply_list; - r->qname = regional_alloc_init(s->s.region, qname, + r->qname = regional_alloc_init(s->s.region, qinfo->qname, s->s.qinfo.qname_len); if(!r->qname) return 0; + + /* Data related to local alias stored in 'qinfo' (if any) is ephemeral + * and can be different for different original queries (even if the + * replaced query name is the same). So we need to make a deep copy + * and store the copy for each reply info. */ + if(qinfo->local_alias) { + struct packed_rrset_data* d; + struct packed_rrset_data* dsrc; + r->local_alias = regional_alloc_zero(s->s.region, + sizeof(*qinfo->local_alias)); + if(!r->local_alias) + return 0; + r->local_alias->rrset = regional_alloc_init(s->s.region, + qinfo->local_alias->rrset, + sizeof(*qinfo->local_alias->rrset)); + if(!r->local_alias->rrset) + return 0; + dsrc = qinfo->local_alias->rrset->entry.data; + + /* In the current implementation, a local alias must be + * a single CNAME RR (see worker_handle_request()). */ + log_assert(!qinfo->local_alias->next && dsrc->count == 1 && + qinfo->local_alias->rrset->rk.type == + htons(LDNS_RR_TYPE_CNAME)); + /* Technically, we should make a local copy for the owner + * name of the RRset, but in the case of the first (and + * currently only) local alias RRset, the owner name should + * point to the qname of the corresponding query, which should + * be valid throughout the lifetime of this mesh_reply. So + * we can skip copying. */ + log_assert(qinfo->local_alias->rrset->rk.dname == + sldns_buffer_at(rep->c->buffer, LDNS_HEADER_SIZE)); + + d = regional_alloc_init(s->s.region, dsrc, + sizeof(struct packed_rrset_data) + + sizeof(size_t) + sizeof(uint8_t*) + sizeof(time_t)); + if(!d) + return 0; + r->local_alias->rrset->entry.data = d; + d->rr_len = (size_t*)((uint8_t*)d + + sizeof(struct packed_rrset_data)); + d->rr_data = (uint8_t**)&(d->rr_len[1]); + d->rr_ttl = (time_t*)&(d->rr_data[1]); + d->rr_len[0] = dsrc->rr_len[0]; + d->rr_ttl[0] = dsrc->rr_ttl[0]; + d->rr_data[0] = regional_alloc_init(s->s.region, + dsrc->rr_data[0], d->rr_len[0]); + if(!d->rr_data[0]) + return 0; + } else + r->local_alias = NULL; + s->reply_list = r; return 1; } @@ -1212,8 +1376,9 @@ mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo, uint16_t flags, int prime, int valrec) { struct mesh_area* mesh = qstate->env->mesh; - struct mesh_state* dep_m = mesh_area_find(mesh, qinfo, flags, prime, - valrec); + struct mesh_state* dep_m = NULL; + if(!mesh_state_is_unique(qstate->mesh_info)) + dep_m = mesh_area_find(mesh, qinfo, flags, prime, valrec); return mesh_detect_cycle_found(qstate, dep_m); } diff --git a/usr.sbin/unbound/services/mesh.h b/usr.sbin/unbound/services/mesh.h index 086e39094e8..435f89c689d 100644 --- a/usr.sbin/unbound/services/mesh.h +++ b/usr.sbin/unbound/services/mesh.h @@ -83,9 +83,9 @@ struct mesh_area { struct module_env* env; /** set of runnable queries (mesh_state.run_node) */ - rbtree_t run; + rbtree_type run; /** rbtree of all current queries (mesh_state.node)*/ - rbtree_t all; + rbtree_type all; /** count of the total number of mesh_reply entries */ size_t num_reply_addrs; @@ -154,9 +154,9 @@ struct mesh_area { */ struct mesh_state { /** node in mesh_area all tree, key is this struct. Must be first. */ - rbnode_t node; + rbnode_type node; /** node in mesh_area runnable tree, key is this struct */ - rbnode_t run_node; + rbnode_type run_node; /** the query state. Note that the qinfo and query_flags * may not change. */ struct module_qstate s; @@ -166,10 +166,10 @@ struct mesh_state { struct mesh_cb* cb_list; /** set of superstates (that want this state's result) * contains struct mesh_state_ref* */ - rbtree_t super_set; + rbtree_type super_set; /** set of substates (that this state needs to continue) * contains struct mesh_state_ref* */ - rbtree_t sub_set; + rbtree_type sub_set; /** number of activations for the mesh state */ size_t num_activated; @@ -180,6 +180,8 @@ struct mesh_state { /** if this state is in the forever list, jostle list, or neither */ enum mesh_list_select { mesh_no_list, mesh_forever_list, mesh_jostle_list } list_select; + /** pointer to this state for uniqueness or NULL */ + struct mesh_state* unique; /** true if replies have been sent out (at end for alignment) */ uint8_t replies_sent; @@ -191,7 +193,7 @@ struct mesh_state { */ struct mesh_state_ref { /** node in rbtree for set, key is this structure */ - rbnode_t node; + rbnode_type node; /** the mesh state */ struct mesh_state* s; }; @@ -214,13 +216,15 @@ struct mesh_reply { uint16_t qflags; /** qname from this query. len same as mesh qinfo. */ uint8_t* qname; + /** same as that in query_info. */ + struct local_rrset* local_alias; }; /** * Mesh result callback func. * called as func(cb_arg, rcode, buffer_with_reply, security, why_bogus); */ -typedef void (*mesh_cb_func_t)(void*, int, struct sldns_buffer*, enum sec_status, +typedef void (*mesh_cb_func_type)(void*, int, struct sldns_buffer*, enum sec_status, char*); /** @@ -241,7 +245,7 @@ struct mesh_cb { /** callback routine for results. if rcode != 0 buf has message. * called as cb(cb_arg, rcode, buf, sec_state); */ - mesh_cb_func_t cb; + mesh_cb_func_type cb; /** user arg for callback */ void* cb_arg; }; @@ -296,7 +300,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, */ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, - uint16_t qid, mesh_cb_func_t cb, void* cb_arg); + uint16_t qid, mesh_cb_func_type cb, void* cb_arg); /** * New prefetch message. Create new query state if needed. @@ -415,6 +419,21 @@ struct mesh_state* mesh_state_create(struct module_env* env, struct query_info* qinfo, uint16_t qflags, int prime, int valrec); /** + * Check if the mesh state is unique. + * A unique mesh state uses it's unique member to point to itself, else NULL. + * @param mstate: mesh state to check. + * @return true if the mesh state is unique, false otherwise. + */ +int mesh_state_is_unique(struct mesh_state* mstate); + +/** + * Make a mesh state unique. + * A unique mesh state uses it's unique member to point to itself. + * @param mstate: mesh state to check. + */ +void mesh_state_make_unique(struct mesh_state* mstate); + +/** * Cleanup a mesh state and its query state. Does not do rbtree or * reference cleanup. * @param mstate: mesh state to cleanup. Its pointer may no longer be used @@ -459,11 +478,12 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub); * @param rep: comm point reply info. * @param qid: ID of reply. * @param qflags: original query flags. - * @param qname: original query name. + * @param qinfo: original query info. * @return: 0 on alloc error. */ -int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, - struct comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname); +int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, + struct comm_reply* rep, uint16_t qid, uint16_t qflags, + const struct query_info* qinfo); /** * Create new callback structure and attach it to a mesh state. @@ -478,8 +498,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, * @return: 0 on alloc error. */ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, - struct sldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg, uint16_t qid, - uint16_t qflags); + struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg, + uint16_t qid, uint16_t qflags); /** * Run the mesh. Run all runnable mesh states. Which can create new diff --git a/usr.sbin/unbound/services/outside_network.c b/usr.sbin/unbound/services/outside_network.c index d9e34f46999..88fc5a9168e 100644 --- a/usr.sbin/unbound/services/outside_network.c +++ b/usr.sbin/unbound/services/outside_network.c @@ -243,7 +243,33 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len) return 0; fd_set_nonblock(s); +#ifdef USE_OSX_MSG_FASTOPEN + /* API for fast open is different here. We use a connectx() function and + then writes can happen as normal even using SSL.*/ + /* connectx requires that the len be set in the sockaddr struct*/ + struct sockaddr_in *addr_in = (struct sockaddr_in *)&w->addr; + addr_in->sin_len = w->addrlen; + sa_endpoints_t endpoints; + endpoints.sae_srcif = 0; + endpoints.sae_srcaddr = NULL; + endpoints.sae_srcaddrlen = 0; + endpoints.sae_dstaddr = (struct sockaddr *)&w->addr; + endpoints.sae_dstaddrlen = w->addrlen; + if (connectx(s, &endpoints, SAE_ASSOCID_ANY, + CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE, + NULL, 0, NULL, NULL) == -1) { +#else /* USE_OSX_MSG_FASTOPEN*/ +#ifdef USE_MSG_FASTOPEN + pend->c->tcp_do_fastopen = 1; + /* Only do TFO for TCP in which case no connect() is required here. + Don't combine client TFO with SSL, since OpenSSL can't + currently support doing a handshake on fd that already isn't connected*/ + if (w->outnet->sslctx && w->ssl_upstream) { + if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) { +#else /* USE_MSG_FASTOPEN*/ if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) { +#endif /* USE_MSG_FASTOPEN*/ +#endif /* USE_OSX_MSG_FASTOPEN*/ #ifndef USE_WINSOCK #ifdef EINPROGRESS if(errno != EINPROGRESS) { @@ -263,6 +289,9 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len) return 0; } } +#ifdef USE_MSG_FASTOPEN + } +#endif /* USE_MSG_FASTOPEN */ if(w->outnet->sslctx && w->ssl_upstream) { pend->c->ssl = outgoing_ssl_fd(w->outnet->sslctx, s); if(!pend->c->ssl) { @@ -305,7 +334,7 @@ use_free_buffer(struct outside_network* outnet) if(outnet->tcp_wait_last == w) outnet->tcp_wait_last = NULL; if(!outnet_tcp_take_into_use(w, w->pkt, w->pkt_len)) { - comm_point_callback_t* cb = w->cb; + comm_point_callback_type* cb = w->cb; void* cb_arg = w->cb_arg; waiting_tcp_delete(w); fptr_ok(fptr_whitelist_pending_tcp(cb)); @@ -591,7 +620,9 @@ static int setup_if(struct port_if* pif, const char* addrstr, pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); if(!pif->avail_ports) return 0; - if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen)) + if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && + !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, + &pif->addr, &pif->addrlen, &pif->pfxlen)) return 0; pif->maxout = (int)numfd; pif->inuse = 0; @@ -744,7 +775,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, /** helper pending delete */ static void -pending_node_del(rbnode_t* node, void* arg) +pending_node_del(rbnode_type* node, void* arg) { struct pending* pend = (struct pending*)node; struct outside_network* outnet = (struct outside_network*)arg; @@ -753,7 +784,7 @@ pending_node_del(rbnode_t* node, void* arg) /** helper serviced delete */ static void -serviced_node_del(rbnode_t* node, void* ATTR_UNUSED(arg)) +serviced_node_del(rbnode_type* node, void* ATTR_UNUSED(arg)) { struct serviced_query* sq = (struct serviced_query*)node; struct service_callback* p = sq->cblist, *np; @@ -893,32 +924,55 @@ pending_delete(struct outside_network* outnet, struct pending* p) free(p); } +static void +sai6_putrandom(struct sockaddr_in6 *sa, int pfxlen, struct ub_randstate *rnd) +{ + int i, last; + if(!(pfxlen > 0 && pfxlen < 128)) + return; + for(i = 0; i < (128 - pfxlen) / 8; i++) { + sa->sin6_addr.s6_addr[15-i] = (uint8_t)ub_random_max(rnd, 256); + } + last = pfxlen & 7; + if(last != 0) { + sa->sin6_addr.s6_addr[15-i] |= + ((0xFF >> last) & ub_random_max(rnd, 256)); + } +} + /** * Try to open a UDP socket for outgoing communication. * Sets sockets options as needed. * @param addr: socket address. * @param addrlen: length of address. + * @param pfxlen: length of network prefix (for address randomisation). * @param port: port override for addr. * @param inuse: if -1 is returned, this bool means the port was in use. + * @param rnd: random state (for address randomisation). * @return fd or -1 */ static int -udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int port, - int* inuse) +udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, + int port, int* inuse, struct ub_randstate* rnd) { int fd, noproto; if(addr_is_ip6(addr, addrlen)) { - struct sockaddr_in6* sa = (struct sockaddr_in6*)addr; - sa->sin6_port = (in_port_t)htons((uint16_t)port); + int freebind = 0; + struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; + sa.sin6_port = (in_port_t)htons((uint16_t)port); + if(pfxlen != 0) { + freebind = 1; + sai6_putrandom(&sa, pfxlen, rnd); + } fd = create_udp_sock(AF_INET6, SOCK_DGRAM, - (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, 0); + (struct sockaddr*)&sa, addrlen, 1, inuse, &noproto, + 0, 0, 0, NULL, 0, freebind, 0); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, 0); + 0, 0, 0, NULL, 0, 0, 0); } return fd; } @@ -978,7 +1032,8 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* try to open new port, if fails, loop to try again */ log_assert(pif->inuse < pif->maxout); portno = pif->avail_ports[my_port - pif->inuse]; - fd = udp_sockport(&pif->addr, pif->addrlen, portno, &inuse); + fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, + portno, &inuse, outnet->rnd); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ return 0; @@ -1069,7 +1124,7 @@ randomize_and_send_udp(struct pending* pend, sldns_buffer* packet, int timeout) struct pending* pending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet, - int timeout, comm_point_callback_t* cb, void* cb_arg) + int timeout, comm_point_callback_type* cb, void* cb_arg) { struct pending* pend = (struct pending*)calloc(1, sizeof(*pend)); if(!pend) return NULL; @@ -1119,7 +1174,7 @@ outnet_tcptimer(void* arg) { struct waiting_tcp* w = (struct waiting_tcp*)arg; struct outside_network* outnet = w->outnet; - comm_point_callback_t* cb; + comm_point_callback_type* cb; void* cb_arg; if(w->pkt) { /* it is on the waiting list */ @@ -1142,7 +1197,7 @@ outnet_tcptimer(void* arg) struct waiting_tcp* pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, - int timeout, comm_point_callback_t* callback, void* callback_arg) + int timeout, comm_point_callback_type* callback, void* callback_arg) { struct pending_tcp* pend = sq->outnet->tcp_free; struct waiting_tcp* w; @@ -1246,7 +1301,7 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec, { struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq)); #ifdef UNBOUND_DEBUG - rbnode_t* ins; + rbnode_type* ins; #endif if(!sq) return NULL; @@ -1361,6 +1416,7 @@ serviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len) long int random = 0; int bits = 0; log_assert(len >= 10 + 5 /* offset qname, root, qtype, qclass */); + (void)len; lablen = *d++; while(lablen) { while(lablen--) { @@ -1531,7 +1587,7 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c, uint8_t *backup_p = NULL; size_t backlen = 0; #ifdef UNBOUND_DEBUG - rbnode_t* rem = + rbnode_type* rem = #else (void) #endif @@ -1823,7 +1879,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, return 0; } #ifdef USE_DNSTAP - if(outnet->dtenv && + if(error == NETEVENT_NOERROR && outnet->dtenv && (outnet->dtenv->log_resolver_response_messages || outnet->dtenv->log_forwarder_response_messages)) dt_msg_send_outside_response(outnet->dtenv, &sq->addr, c->type, @@ -1930,17 +1986,22 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, struct serviced_query* outnet_serviced_query(struct outside_network* outnet, - uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, - uint16_t flags, int dnssec, int want_dnssec, int nocaps, - int tcp_upstream, int ssl_upstream, struct edns_option* opt_list, + struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, + int nocaps, int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, comm_point_callback_t* callback, void* callback_arg, - sldns_buffer* buff) + size_t zonelen, struct module_qstate* qstate, + comm_point_callback_type* callback, void* callback_arg, sldns_buffer* buff, + struct module_env* env) { struct serviced_query* sq; struct service_callback* cb; - serviced_gen_query(buff, qname, qnamelen, qtype, qclass, flags); - sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen, opt_list); + if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, zone, zonelen, + qstate, qstate->region)) + return NULL; + serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype, + qinfo->qclass, flags); + sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen, + qstate->edns_opts_back_out); /* duplicate entries are included in the callback list, because * there is a counterpart registration by our caller that needs to * be doubly-removed (with callbacks perhaps). */ @@ -1950,7 +2011,7 @@ outnet_serviced_query(struct outside_network* outnet, /* make new serviced query entry */ sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps, tcp_upstream, ssl_upstream, addr, addrlen, zone, - zonelen, (int)qtype, opt_list); + zonelen, (int)qinfo->qtype, qstate->edns_opts_back_out); if(!sq) { free(cb); return NULL; diff --git a/usr.sbin/unbound/services/outside_network.h b/usr.sbin/unbound/services/outside_network.h index 9a3270ee19a..befd512f0da 100644 --- a/usr.sbin/unbound/services/outside_network.h +++ b/usr.sbin/unbound/services/outside_network.h @@ -59,6 +59,9 @@ struct sldns_buffer; struct serviced_query; struct dt_env; struct edns_option; +struct module_env; +struct module_qstate; +struct query_info; /** * Send queries to outside servers and wait for answers from servers. @@ -120,9 +123,9 @@ struct outside_network { struct pending* udp_wait_last; /** pending udp answers. sorted by id, addr */ - rbtree_t* pending; + rbtree_type* pending; /** serviced queries, sorted by qbuf, addr, dnssec */ - rbtree_t* serviced; + rbtree_type* serviced; /** host cache, pointer but not owned by outnet. */ struct infra_cache* infra; /** where to get random numbers */ @@ -165,6 +168,10 @@ struct port_if { /** length of addr field */ socklen_t addrlen; + /** prefix length of network address (in bits), for randomisation. + * if 0, no randomisation. */ + int pfxlen; + /** the available ports array. These are unused. * Only the first total-inuse part is filled. */ int* avail_ports; @@ -203,7 +210,7 @@ struct port_comm { */ struct pending { /** redblacktree entry, key is the pending struct(id, addr). */ - rbnode_t node; + rbnode_type node; /** the ID for the query. int so that a value out of range can * be used to signify a pending that is for certain not present in * the rbtree. (and for which deletion is safe). */ @@ -217,7 +224,7 @@ struct pending { /** timeout event */ struct comm_timer* timer; /** callback for the timeout, error or reply to the message */ - comm_point_callback_t* cb; + comm_point_callback_type* cb; /** callback user argument */ void* cb_arg; /** the outside network it is part of */ @@ -278,7 +285,7 @@ struct waiting_tcp { /** length of query packet. */ size_t pkt_len; /** callback for the timeout, error or reply to the message */ - comm_point_callback_t* cb; + comm_point_callback_type* cb; /** callback user argument */ void* cb_arg; /** if it uses ssl upstream */ @@ -292,7 +299,7 @@ struct service_callback { /** next in callback list */ struct service_callback* next; /** callback function */ - comm_point_callback_t* cb; + comm_point_callback_type* cb; /** user argument for callback function */ void* cb_arg; }; @@ -310,7 +317,7 @@ struct service_callback { */ struct serviced_query { /** The rbtree node, key is this record */ - rbnode_t node; + rbnode_type node; /** The query that needs to be answered. Starts with flags u16, * then qdcount, ..., including qname, qtype, qclass. Does not include * EDNS record. */ @@ -436,7 +443,7 @@ void outside_network_quit_prepare(struct outside_network* outnet); * @return: NULL on error for malloc or socket. Else the pending query object. */ struct pending* pending_udp_query(struct serviced_query* sq, - struct sldns_buffer* packet, int timeout, comm_point_callback_t* callback, + struct sldns_buffer* packet, int timeout, comm_point_callback_type* callback, void* callback_arg); /** @@ -452,7 +459,7 @@ struct pending* pending_udp_query(struct serviced_query* sq, * @return: false on error for malloc or socket. Else the pending TCP object. */ struct waiting_tcp* pending_tcp_query(struct serviced_query* sq, - struct sldns_buffer* packet, int timeout, comm_point_callback_t* callback, + struct sldns_buffer* packet, int timeout, comm_point_callback_type* callback, void* callback_arg); /** @@ -467,10 +474,7 @@ void pending_delete(struct outside_network* outnet, struct pending* p); * Perform a serviced query to the authoritative servers. * Duplicate efforts are detected, and EDNS, TCP and UDP retry is performed. * @param outnet: outside network, with rbtree of serviced queries. - * @param qname: what qname to query. - * @param qnamelen: length of qname in octets including 0 root label. - * @param qtype: rrset type to query (host format) - * @param qclass: query class. (host format) + * @param qinfo: query info. * @param flags: flags u16 (host format), includes opcode, CD bit. * @param dnssec: if set, DO bit is set in EDNS queries. * If the value includes BIT_CD, CD bit is set when in EDNS queries. @@ -480,27 +484,28 @@ void pending_delete(struct outside_network* outnet, struct pending* p); * @param nocaps: ignore use_caps_for_id and use unperturbed qname. * @param tcp_upstream: use TCP for upstream queries. * @param ssl_upstream: use SSL for upstream queries. - * @param opt_list: pass edns option list (deep copied into serviced query) - * these options are set on the outgoing packets. - * @param callback: callback function. - * @param callback_arg: user argument to callback function. * @param addr: to which server to send the query. * @param addrlen: length of addr. * @param zone: name of the zone of the delegation point. wireformat dname. This is the delegation point name for which the server is deemed authoritative. * @param zonelen: length of zone. + * @param qstate: module qstate. Mainly for inspecting the available + * edns_opts_lists. + * @param callback: callback function. + * @param callback_arg: user argument to callback function. * @param buff: scratch buffer to create query contents in. Empty on exit. + * @param env: the module environment. * @return 0 on error, or pointer to serviced query that is used to answer * this serviced query may be shared with other callbacks as well. */ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, - uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, - uint16_t flags, int dnssec, int want_dnssec, int nocaps, - int tcp_upstream, int ssl_upstream, struct edns_option* opt_list, + struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, + int nocaps, int tcp_upstream, int ssl_upstream, struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, comm_point_callback_t* callback, void* callback_arg, - struct sldns_buffer* buff); + size_t zonelen, struct module_qstate* qstate, + comm_point_callback_type* callback, void* callback_arg, + struct sldns_buffer* buff, struct module_env* env); /** * Remove service query callback. diff --git a/usr.sbin/unbound/services/view.c b/usr.sbin/unbound/services/view.c new file mode 100644 index 00000000000..c9dfc3c8738 --- /dev/null +++ b/usr.sbin/unbound/services/view.c @@ -0,0 +1,207 @@ +/* + * services/view.c - named views containing local zones authority service. + * + * Copyright (c) 2016, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions to enable named views that can hold local zone + * authority service. + */ +#include "config.h" +#include "services/view.h" +#include "services/localzone.h" +#include "util/config_file.h" + +int +view_cmp(const void* v1, const void* v2) +{ + struct view* a = (struct view*)v1; + struct view* b = (struct view*)v2; + + return strcmp(a->name, b->name); +} + +struct views* +views_create(void) +{ + struct views* v = (struct views*)calloc(1, + sizeof(*v)); + if(!v) + return NULL; + rbtree_init(&v->vtree, &view_cmp); + lock_rw_init(&v->lock); + lock_protect(&v->lock, &v->vtree, sizeof(v->vtree)); + return v; +} + +void +view_delete(struct view* v) +{ + if(!v) + return; + lock_rw_destroy(&v->lock); + local_zones_delete(v->local_zones); + free(v->name); + free(v); +} + +static void +delviewnode(rbnode_type* n, void* ATTR_UNUSED(arg)) +{ + struct view* v = (struct view*)n; + view_delete(v); +} + +void +views_delete(struct views* v) +{ + if(!v) + return; + lock_rw_destroy(&v->lock); + traverse_postorder(&v->vtree, delviewnode, NULL); + free(v); +} + +/** create a new view */ +static struct view* +view_create(char* name) +{ + struct view* v = (struct view*)calloc(1, sizeof(*v)); + if(!v) + return NULL; + v->node.key = v; + if(!(v->name = strdup(name))) { + free(v); + return NULL; + } + lock_rw_init(&v->lock); + lock_protect(&v->lock, &v->name, sizeof(*v)-sizeof(rbnode_type)); + return v; +} + +/** enter a new view returns with WRlock */ +static struct view* +views_enter_view_name(struct views* vs, char* name) +{ + struct view* v = view_create(name); + if(!v) { + log_err("out of memory"); + return NULL; + } + + /* add to rbtree */ + lock_rw_wrlock(&vs->lock); + lock_rw_wrlock(&v->lock); + if(!rbtree_insert(&vs->vtree, &v->node)) { + log_warn("duplicate view: %s", name); + lock_rw_unlock(&v->lock); + view_delete(v); + lock_rw_unlock(&vs->lock); + return NULL; + } + lock_rw_unlock(&vs->lock); + return v; +} + +int +views_apply_cfg(struct views* vs, struct config_file* cfg) +{ + struct config_view* cv; + struct view* v; + struct config_file lz_cfg; + /* Check existence of name in first view (last in config). Rest of + * views are already checked when parsing config. */ + if(cfg->views && !cfg->views->name) { + log_err("view without a name"); + return 0; + } + for(cv = cfg->views; cv; cv = cv->next) { + /* create and enter view */ + if(!(v = views_enter_view_name(vs, cv->name))) + return 0; + v->isfirst = cv->isfirst; + if(cv->local_zones || cv->local_data) { + if(!(v->local_zones = local_zones_create())){ + lock_rw_unlock(&v->lock); + return 0; + } + memset(&lz_cfg, 0, sizeof(lz_cfg)); + lz_cfg.local_zones = cv->local_zones; + lz_cfg.local_data = cv->local_data; + lz_cfg.local_zones_nodefault = + cv->local_zones_nodefault; + if(!local_zones_apply_cfg(v->local_zones, &lz_cfg)){ + lock_rw_unlock(&v->lock); + return 0; + } + /* local_zones, local_zones_nodefault and local_data + * are free'd from config_view by local_zones_apply_cfg. + * Set pointers to NULL. */ + cv->local_zones = NULL; + cv->local_data = NULL; + cv->local_zones_nodefault = NULL; + } + lock_rw_unlock(&v->lock); + } + return 1; +} + +/** find a view by name */ +struct view* +views_find_view(struct views* vs, const char* name, int write) +{ + struct view* v; + struct view key; + key.node.key = &v; + key.name = (char *)name; + lock_rw_rdlock(&vs->lock); + if(!(v = (struct view*)rbtree_search(&vs->vtree, &key.node))) { + lock_rw_unlock(&vs->lock); + return 0; + } + if(write) { + lock_rw_wrlock(&v->lock); + } else { + lock_rw_rdlock(&v->lock); + } + lock_rw_unlock(&vs->lock); + return v; +} + +void views_print(struct views* v) +{ + /* TODO implement print */ + (void)v; +} diff --git a/usr.sbin/unbound/services/view.h b/usr.sbin/unbound/services/view.h new file mode 100644 index 00000000000..ce4b69d6c51 --- /dev/null +++ b/usr.sbin/unbound/services/view.h @@ -0,0 +1,134 @@ +/* + * services/view.h - named views containing local zones authority service. + * + * Copyright (c) 2016, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions to enable named views that can hold local zone + * authority service. + */ + +#ifndef SERVICES_VIEW_H +#define SERVICES_VIEW_H +#include "util/rbtree.h" +#include "util/locks.h" +struct regional; +struct config_file; +struct config_view; + + +/** + * Views storage, shared. + */ +struct views { + /** lock on the view tree */ + lock_rw_type lock; + /** rbtree of struct view */ + rbtree_type vtree; +}; + +/** + * View. Named structure holding local authority zones. + */ +struct view { + /** rbtree node, key is name */ + rbnode_type node; + /** view name. + * Has to be right after rbnode_t due to pointer arithmatic in + * view_create's lock protect */ + char* name; + /** view specific local authority zones */ + struct local_zones* local_zones; + /** Fallback to global local_zones when there is no match in the view + * specific tree. 1 for yes, 0 for no */ + int isfirst; + /** lock on the data in the structure + * For the node and name you need to also hold the views_tree lock to + * change them. */ + lock_rw_type lock; +}; + + +/** + * Create views storage + * @return new struct or NULL on error. + */ +struct views* views_create(void); + +/** + * Delete views storage + * @param v: views to delete. + */ +void views_delete(struct views* v); + +/** + * Apply config settings; + * Takes care of locking. + * @param v: view is set up. + * @param cfg: config data. + * @return false on error. + */ +int views_apply_cfg(struct views* v, struct config_file* cfg); + +/** + * Compare two view entries in rbtree. Sort canonical. + * @param v1: view 1 + * @param v2: view 2 + * @return: negative, positive or 0 comparison value. + */ +int view_cmp(const void* v1, const void* v2); + +/** + * Delete one view + * @param v: view to delete. + */ +void view_delete(struct view* v); + +/** + * Debug helper. Print all views + * Takes care of locking. + * @param v: the views tree + */ +void views_print(struct views* v); + +/* Find a view by name. + * @param vs: views + * @param name: name of the view we are looking for + * @param write: 1 for obtaining write lock on found view, 0 for read lock + * @return: locked view or NULL. + */ +struct view* views_find_view(struct views* vs, const char* name, int write); + +#endif /* SERVICES_VIEW_H */ diff --git a/usr.sbin/unbound/sldns/keyraw.c b/usr.sbin/unbound/sldns/keyraw.c index 8d28bf40ab3..e8f2da089d6 100644 --- a/usr.sbin/unbound/sldns/keyraw.c +++ b/usr.sbin/unbound/sldns/keyraw.c @@ -23,6 +23,15 @@ #ifdef HAVE_OPENSSL_ENGINE_H # include <openssl/engine.h> #endif +#ifdef HAVE_OPENSSL_BN_H +#include <openssl/bn.h> +#endif +#ifdef HAVE_OPENSSL_RSA_H +#include <openssl/rsa.h> +#endif +#ifdef HAVE_OPENSSL_DSA_H +#include <openssl/dsa.h> +#endif #endif /* HAVE_SSL */ size_t @@ -215,6 +224,7 @@ sldns_key_buf2dsa_raw(unsigned char* key, size_t len) BN_free(Y); return NULL; } +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) #ifndef S_SPLINT_S dsa->p = P; dsa->q = Q; @@ -222,6 +232,25 @@ sldns_key_buf2dsa_raw(unsigned char* key, size_t len) dsa->pub_key = Y; #endif /* splint */ +#else /* OPENSSL_VERSION_NUMBER */ + if (!DSA_set0_pqg(dsa, P, Q, G)) { + /* QPG not yet attached, need to free */ + BN_free(Q); + BN_free(P); + BN_free(G); + + DSA_free(dsa); + BN_free(Y); + return NULL; + } + if (!DSA_set0_key(dsa, Y, NULL)) { + /* QPG attached, cleaned up by DSA_fre() */ + DSA_free(dsa); + BN_free(Y); + return NULL; + } +#endif + return dsa; } @@ -273,11 +302,21 @@ sldns_key_buf2rsa_raw(unsigned char* key, size_t len) BN_free(modulus); return NULL; } +#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) #ifndef S_SPLINT_S rsa->n = modulus; rsa->e = exponent; #endif /* splint */ +#else /* OPENSSL_VERSION_NUMBER */ + if (!RSA_set0_key(rsa, modulus, exponent, NULL)) { + BN_free(exponent); + BN_free(modulus); + RSA_free(rsa); + return NULL; + } +#endif + return rsa; } diff --git a/usr.sbin/unbound/sldns/rrdef.h b/usr.sbin/unbound/sldns/rrdef.h index 3365f15fa05..00c01e63a40 100644 --- a/usr.sbin/unbound/sldns/rrdef.h +++ b/usr.sbin/unbound/sldns/rrdef.h @@ -195,7 +195,7 @@ enum sldns_enum_rr_type LDNS_RR_TYPE_TALINK = 58, LDNS_RR_TYPE_CDS = 59, /** RFC 7344 */ LDNS_RR_TYPE_CDNSKEY = 60, /** RFC 7344 */ - LDNS_RR_TYPE_OPENPGPKEY = 61, /* draft-ietf-dane-openpgpkey */ + LDNS_RR_TYPE_OPENPGPKEY = 61, /* RFC 7929 */ LDNS_RR_TYPE_CSYNC = 62, /* RFC 7477 */ LDNS_RR_TYPE_SPF = 99, /* RFC 4408 */ diff --git a/usr.sbin/unbound/sldns/str2wire.c b/usr.sbin/unbound/sldns/str2wire.c index e624e269e33..75c5d71b1ac 100644 --- a/usr.sbin/unbound/sldns/str2wire.c +++ b/usr.sbin/unbound/sldns/str2wire.c @@ -328,7 +328,7 @@ rrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len, /** find delimiters for type */ static const char* -rrinternal_get_delims(sldns_rdf_type rdftype, uint16_t r_cnt, uint16_t r_max) +rrinternal_get_delims(sldns_rdf_type rdftype, size_t r_cnt, size_t r_max) { switch(rdftype) { case LDNS_RDF_TYPE_B64 : @@ -463,7 +463,7 @@ rrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len, static int rrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len, uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype, - uint16_t rr_type, uint16_t r_cnt, uint16_t r_max, size_t dname_len, + uint16_t rr_type, size_t r_cnt, size_t r_max, size_t dname_len, uint8_t* origin, size_t origin_len) { size_t len; @@ -613,7 +613,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, uint8_t* origin, size_t origin_len) { const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type); - uint16_t r_cnt, r_min, r_max; + size_t r_cnt, r_min, r_max; size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen; int was_unknown_rr_format = 0, parens = 0, status, quoted; const char* delimiters; @@ -693,7 +693,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, sldns_buffer_position(strbuf)); } /* write rdata length */ - sldns_write_uint16(rr+dname_len+8, rr_cur_len-dname_len-10); + sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10)); *rr_len = rr_cur_len; return LDNS_WIREPARSE_ERR_OK; } @@ -1369,7 +1369,7 @@ int sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len) if (tm.tm_sec < 0 || tm.tm_sec > 59) return LDNS_WIREPARSE_ERR_SYNTAX_TIME; - sldns_write_uint32(rd, sldns_mktime_from_utc(&tm)); + sldns_write_uint32(rd, (uint32_t)sldns_mktime_from_utc(&tm)); } else { /* handle it as 32 bits timestamp */ char *end; @@ -1932,7 +1932,7 @@ int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len) if(!isalnum((unsigned char)*ptr)) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str); } - rd[0] = slen; + rd[0] = (uint8_t)slen; memmove(rd+1, str, slen); *len = slen+1; return LDNS_WIREPARSE_ERR_OK; @@ -2000,7 +2000,7 @@ int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len) return RET_ERR_SHIFT(e, s-(char*)str); if(pklen > 65535) return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535); - sldns_write_uint16(rd+2, pklen); + sldns_write_uint16(rd+2, (uint16_t)pklen); *len = 4 + hitlen + pklen; return LDNS_WIREPARSE_ERR_OK; diff --git a/usr.sbin/unbound/sldns/wire2str.c b/usr.sbin/unbound/sldns/wire2str.c index 639f56fae72..0efa65f7566 100644 --- a/usr.sbin/unbound/sldns/wire2str.c +++ b/usr.sbin/unbound/sldns/wire2str.c @@ -667,7 +667,7 @@ int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s, uint8_t* origd = *d; char* origs = *s; size_t origdlen = *dlen, origslen = *slen; - uint16_t r_cnt, r_max; + size_t r_cnt, r_max; sldns_rdf_type rdftype; int w = 0, n; @@ -788,8 +788,9 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, } /* spool label characters, end with '.' */ - if(in_buf && *dlen < labellen) labellen = *dlen; - else if(!in_buf && pos+labellen > pkt+pktlen) + if(in_buf && *dlen < (size_t)labellen) + labellen = (uint8_t)*dlen; + else if(!in_buf && pos+(size_t)labellen > pkt+pktlen) labellen = (uint8_t)(pkt + pktlen - pos); for(i=0; i<(unsigned)labellen; i++) { w += dname_char_print(s, slen, *pos++); @@ -1960,10 +1961,10 @@ int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str, w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize); if(rdatalen) { - if(*data_len < rdatalen) { + if((size_t)*data_len < rdatalen) { w += sldns_str_print(str, str_len, " ; Error EDNS rdata too short; "); - rdatalen = *data_len; + rdatalen = (uint16_t)*data_len; } w += print_edns_opts(str, str_len, *data, rdatalen); (*data) += rdatalen; diff --git a/usr.sbin/unbound/sldns/wire2str.h b/usr.sbin/unbound/sldns/wire2str.h index 67f54356626..c477f06610d 100644 --- a/usr.sbin/unbound/sldns/wire2str.h +++ b/usr.sbin/unbound/sldns/wire2str.h @@ -118,7 +118,7 @@ int sldns_str_print(char** str, size_t* slen, const char* format, ...) * @param str_len: the size of the string buffer. If more is needed, it'll * silently truncate the output to fit in the buffer. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_pkt_buf(uint8_t* data, size_t data_len, char* str, size_t str_len); @@ -351,7 +351,7 @@ int sldns_wire2str_edns_option_code_print(char** str, size_t* str_len, * @param str_len: the size of the string buffer. If more is needed, it'll * silently truncate the output to fit in the buffer. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str, size_t str_len); @@ -369,7 +369,7 @@ int sldns_wire2str_rr_buf(uint8_t* rr, size_t rr_len, char* str, * @param str_len: the size of the string buffer. If more is needed, it'll * silently truncate the output to fit in the buffer. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_rr_unknown_buf(uint8_t* rr, size_t rr_len, char* str, size_t str_len); @@ -389,7 +389,7 @@ int sldns_wire2str_rr_unknown_buf(uint8_t* rr, size_t rr_len, char* str, * @param str_len: the size of the string buffer. If more is needed, it'll * silently truncate the output to fit in the buffer. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rr_len, size_t dname_len, char* str, size_t str_len); @@ -406,7 +406,7 @@ int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rr_len, size_t dname_len, * silently truncate the output to fit in the buffer. * @param rrtype: rr type of the data * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str, size_t str_len, uint16_t rrtype); @@ -417,7 +417,7 @@ int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str, * @param str: the string to write to. * @param len: length of str. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_type_buf(uint16_t rrtype, char* str, size_t len); @@ -427,7 +427,7 @@ int sldns_wire2str_type_buf(uint16_t rrtype, char* str, size_t len); * @param str: the string to write to. * @param len: length of str. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_class_buf(uint16_t rrclass, char* str, size_t len); @@ -437,7 +437,7 @@ int sldns_wire2str_class_buf(uint16_t rrclass, char* str, size_t len); * @param str: the string to write to. * @param len: length of str. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_rcode_buf(int rcode, char* str, size_t len); @@ -448,7 +448,7 @@ int sldns_wire2str_rcode_buf(int rcode, char* str, size_t len); * @param str: the string to write to. * @param len: length of string. * @return the number of characters for this element, excluding zerobyte. - * Is larger than str_len if output was truncated. + * Is larger or equal than str_len if output was truncated. */ int sldns_wire2str_dname_buf(uint8_t* dname, size_t dname_len, char* str, size_t len); diff --git a/usr.sbin/unbound/smallapp/unbound-anchor.c b/usr.sbin/unbound/smallapp/unbound-anchor.c index 81bb896f717..2828088d9fd 100644 --- a/usr.sbin/unbound/smallapp/unbound-anchor.c +++ b/usr.sbin/unbound/smallapp/unbound-anchor.c @@ -37,7 +37,8 @@ * \file * * This file checks to see that the current 5011 keys work to prime the - * current root anchor. If not a certificate is used to update the anchor. + * current root anchor. If not a certificate is used to update the anchor, + * with RFC7958 https xml fetch. * * This is a concept solution for distribution of the DNSSEC root * trust anchor. It is a small tool, called "unbound-anchor", that @@ -47,7 +48,7 @@ * Management-Abstract: * * first run: fill root.key file with hardcoded DS record. * * mostly: use RFC5011 tracking, quick . DNSKEY UDP query. - * * failover: use builtin certificate, do https and update. + * * failover: use RFC7958 builtin certificate, do https and update. * Special considerations: * * 30-days RFC5011 timer saves a lot of https traffic. * * DNSKEY probe must be NOERROR, saves a lot of https traffic. @@ -77,7 +78,7 @@ * the file contains a list of normal DNSKEY/DS records, and uses that to * bootstrap 5011 (the KSK is made VALID). * - * The certificate update is done by fetching root-anchors.xml and + * The certificate RFC7958 update is done by fetching root-anchors.xml and * root-anchors.p7s via SSL. The HTTPS certificate can be logged but is * not validated (https for channel security; the security comes from the * certificate). The 'data.iana.org' domain name A and AAAA are resolved @@ -171,7 +172,7 @@ struct ip_list { /** Give unbound-anchor usage, and exit (1). */ static void -usage() +usage(void) { printf("Usage: unbound-anchor [opts]\n"); printf(" Setup or update root anchor. " @@ -240,7 +241,10 @@ static const char* get_builtin_ds(void) { return -". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n"; +/* anchor 19036 is from 2010 */ +/* anchor 20326 is from 2017 */ +". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n" +". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n"; } /** print hex data */ @@ -419,8 +423,14 @@ read_builtin_cert(void) { const char* builtin_cert = get_builtin_cert(); STACK_OF(X509)* sk; - BIO *bio = BIO_new_mem_buf((void*)builtin_cert, - (int)strlen(builtin_cert)); + BIO *bio; + char* d = strdup(builtin_cert); /* to avoid const warnings in the + changed prototype of BIO_new_mem_buf */ + if(!d) { + if(verb) printf("out of memory\n"); + exit(0); + } + bio = BIO_new_mem_buf(d, (int)strlen(d)); if(!bio) { if(verb) printf("out of memory\n"); exit(0); @@ -431,6 +441,7 @@ read_builtin_cert(void) exit(0); } BIO_free(bio); + free(d); return sk; } @@ -1836,7 +1847,7 @@ write_unsigned_root(const char* root_anchor_file) #ifdef HAVE_FSYNC fsync(fileno(out)); #else - FlushFileBuffers((HANDLE)_fileno(out)); + FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); #endif fclose(out); } @@ -1868,7 +1879,7 @@ write_root_anchor(const char* root_anchor_file, BIO* ds) #ifdef HAVE_FSYNC fsync(fileno(out)); #else - FlushFileBuffers((HANDLE)_fileno(out)); + FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); #endif fclose(out); } @@ -2310,10 +2321,22 @@ int main(int argc, char* argv[]) if(argc != 0) usage(); +#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); +#endif ERR_load_SSL_strings(); +#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); +#else + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS + | OPENSSL_INIT_ADD_ALL_DIGESTS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); +#else + (void)OPENSSL_init_ssl(0, NULL); +#endif if(dolist) do_list_builtin(); diff --git a/usr.sbin/unbound/smallapp/unbound-checkconf.c b/usr.sbin/unbound/smallapp/unbound-checkconf.c index b1c70f50787..eebc0e76ee8 100644 --- a/usr.sbin/unbound/smallapp/unbound-checkconf.c +++ b/usr.sbin/unbound/smallapp/unbound-checkconf.c @@ -72,7 +72,7 @@ /** Give checkconf usage, and exit (1). */ static void -usage() +usage(void) { printf("Usage: unbound-checkconf [file]\n"); printf(" Checks unbound configuration file for errors.\n"); @@ -97,7 +97,10 @@ static void print_option(struct config_file* cfg, const char* opt, int final) { if(strcmp(opt, "pidfile") == 0 && final) { - printf("%s\n", fname_after_chroot(cfg->pidfile, cfg, 1)); + char *p = fname_after_chroot(cfg->pidfile, cfg, 1); + if(!p) fatal_exit("out of memory"); + printf("%s\n", p); + free(p); return; } if(!config_get_option(cfg, opt, config_print_func, stdout)) @@ -115,12 +118,15 @@ check_mod(struct config_file* cfg, struct module_func_block* fb) env.scratch_buffer = sldns_buffer_new(BUFSIZ); if(!env.scratch || !env.scratch_buffer) fatal_exit("out of memory"); + if(!edns_known_options_init(&env)) + fatal_exit("out of memory"); if(!(*fb->init)(&env, 0)) { fatal_exit("bad config for %s module", fb->name); } (*fb->deinit)(&env, 0); sldns_buffer_free(env.scratch_buffer); regional_destroy(env.scratch); + edns_known_options_delete(&env); } /** check localzones */ @@ -161,6 +167,7 @@ warn_hosts(const char* typ, struct config_stub* list) static void interfacechecks(struct config_file* cfg) { + int d; struct sockaddr_storage a; socklen_t alen; int i, j; @@ -177,8 +184,8 @@ interfacechecks(struct config_file* cfg) } } for(i=0; i<cfg->num_out_ifs; i++) { - if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, - &a, &alen)) { + if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) && + !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) { fatal_exit("cannot parse outgoing-interface " "specified as '%s'", cfg->out_ifs[i]); } @@ -330,6 +337,8 @@ morechecks(struct config_file* cfg, const char* fname) fatal_exit("num_threads value weird"); if(!cfg->do_ip4 && !cfg->do_ip6) fatal_exit("ip4 and ip6 are both disabled, pointless"); + if(!cfg->do_ip6 && cfg->prefer_ip6) + fatal_exit("cannot prefer and disable ip6, pointless"); if(!cfg->do_udp && !cfg->do_tcp) fatal_exit("udp and tcp are both disabled, pointless"); if(cfg->edns_buffer_size > cfg->msg_buffer_size) @@ -436,7 +445,9 @@ morechecks(struct config_file* cfg, const char* fname) if(cfg->username && cfg->username[0]) { if(getpwnam(cfg->username) == NULL) fatal_exit("user '%s' does not exist.", cfg->username); +# ifdef HAVE_ENDPWENT endpwent(); +# endif } #endif if(cfg->remote_control_enable && cfg->remote_control_use_cert) { @@ -481,14 +492,22 @@ check_hints(struct config_file* cfg) static void checkconf(const char* cfgfile, const char* opt, int final) { + char oldwd[4096]; struct config_file* cfg = config_create(); if(!cfg) fatal_exit("out of memory"); + oldwd[0] = 0; + if(!getcwd(oldwd, sizeof(oldwd))) { + log_err("cannot getcwd: %s", strerror(errno)); + oldwd[0] = 0; + } if(!config_read(cfg, cfgfile, NULL)) { /* config_read prints messages to stderr */ config_delete(cfg); exit(1); } + if(oldwd[0] && chdir(oldwd) == -1) + log_err("cannot chdir(%s): %s", oldwd, strerror(errno)); if(opt) { print_option(cfg, opt, final); config_delete(cfg); diff --git a/usr.sbin/unbound/smallapp/unbound-control.c b/usr.sbin/unbound/smallapp/unbound-control.c index 23e265c7074..af4b45ee782 100644 --- a/usr.sbin/unbound/smallapp/unbound-control.c +++ b/usr.sbin/unbound/smallapp/unbound-control.c @@ -65,7 +65,7 @@ /** Give unbound-control usage, and exit (1). */ static void -usage() +usage(void) { printf("Usage: unbound-control [options] command\n"); printf(" Remote control utility for unbound server.\n"); @@ -124,7 +124,14 @@ usage() printf(" or off to turn off root forwarding\n"); printf(" or give list of ip addresses\n"); printf(" ratelimit_list [+a] list ratelimited domains\n"); + printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n"); printf(" +a list all, also not ratelimited\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"); + printf(" view_local_zone_remove view name remove local-zone in view\n"); + printf(" view_local_data view RR... add local-data in view\n"); + printf(" view_local_data_remove view name remove local-data in view\n"); printf("Version %s\n", PACKAGE_VERSION); printf("BSD licensed, see LICENSE in source package for details.\n"); printf("Report bugs to %s\n", PACKAGE_BUGREPORT); @@ -176,7 +183,10 @@ setup_ctx(struct config_file* cfg) free(c_cert); } else { /* Use ciphers that don't require authentication */ - if(!SSL_CTX_set_cipher_list(ctx, "aNULL")) +#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL + SSL_CTX_set_security_level(ctx, 0); +#endif + if(!SSL_CTX_set_cipher_list(ctx, "aNULL, eNULL")) ssl_err("Error setting NULL cipher!"); } return ctx; @@ -192,9 +202,13 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd) int fd; /* use svr or the first config entry */ if(!svr) { - if(cfg->control_ifs) + if(cfg->control_ifs) { svr = cfg->control_ifs->str; - else svr = "127.0.0.1"; + } else if(cfg->do_ip4) { + svr = "127.0.0.1"; + } else { + svr = "::1"; + } /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; @@ -212,7 +226,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd) struct sockaddr_un* usock = (struct sockaddr_un *) &addr; usock->sun_family = AF_LOCAL; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN - usock->sun_len = (socklen_t)sizeof(usock); + usock->sun_len = (unsigned)sizeof(usock); #endif (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); addrlen = (socklen_t)sizeof(struct sockaddr_un); @@ -300,6 +314,15 @@ send_file(SSL* ssl, FILE* in, char* buf, size_t sz) } } +/** send end-of-file marker to server */ +static void +send_eof(SSL* ssl) +{ + char e[] = {0x04, 0x0a}; + if(SSL_write(ssl, e, (int)sizeof(e)) <= 0) + ssl_err("could not SSL_write end-of-file marker"); +} + /** send command and display result */ static int go_cmd(SSL* ssl, int quiet, int argc, char* argv[]) @@ -325,6 +348,13 @@ go_cmd(SSL* ssl, int quiet, int argc, char* argv[]) if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { send_file(ssl, stdin, buf, sizeof(buf)); } + else if(argc == 1 && (strcmp(argv[0], "local_zones") == 0 || + strcmp(argv[0], "local_zones_remove") == 0 || + strcmp(argv[0], "local_datas") == 0 || + strcmp(argv[0], "local_datas_remove") == 0)) { + send_file(ssl, stdin, buf, sizeof(buf)); + send_eof(ssl); + } while(1) { ERR_clear_error(); @@ -418,10 +448,22 @@ int main(int argc, char* argv[]) cfgfile = CONFIGFILE; #endif +#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS ERR_load_crypto_strings(); +#endif ERR_load_SSL_strings(); +#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) OpenSSL_add_all_algorithms(); +#else + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS + | OPENSSL_INIT_ADD_ALL_DIGESTS + | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) (void)SSL_library_init(); +#else + (void)OPENSSL_init_ssl(0, NULL); +#endif if(!RAND_status()) { /* try to seed it */ diff --git a/usr.sbin/unbound/smallapp/unbound-host.c b/usr.sbin/unbound/smallapp/unbound-host.c index 095396749ff..d7a36a23193 100644 --- a/usr.sbin/unbound/smallapp/unbound-host.c +++ b/usr.sbin/unbound/smallapp/unbound-host.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -60,14 +60,19 @@ #define unbound_lite_wrapstr(s) s #endif #include "libunbound/unbound.h" -#include <ldns/ldns.h> +#include "sldns/rrdef.h" +#include "sldns/wire2str.h" +#ifdef HAVE_NSS +/* nss3 */ +#include "nss.h" +#endif /** verbosity for unbound-host app */ static int verb = 0; /** Give unbound-host usage, and exit (1). */ static void -usage() +usage(void) { printf("Usage: unbound-host [-vdhr46] [-c class] [-t type] hostname\n"); printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n"); @@ -80,11 +85,13 @@ usage() printf(" -c class what class to look for, if not class IN.\n"); printf(" -y 'keystring' specify trust anchor, DS or DNSKEY, like\n"); printf(" -y 'example.com DS 31560 5 1 1CFED8478...'\n"); + printf(" -D DNSSEC enable with default root anchor\n"); + printf(" from %s\n", ROOT_ANCHOR_FILE); 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(" -r read forwarder information from /etc/resolv.conf\n"); - printf(" breaks validation if the fwder does not do DNSSEC.\n"); + printf(" breaks validation if the forwarder does not do DNSSEC.\n"); printf(" -v be more verbose, shows nodata and security.\n"); printf(" -d debug, traces the action, -d -d shows more.\n"); printf(" -4 use ipv4 network, avoid ipv6.\n"); @@ -168,7 +175,7 @@ static int massage_type(const char* t, int reverse, int* multi) { if(t) { - int r = ldns_get_rr_type_by_name(t); + int r = sldns_get_rr_type_by_name(t); if(r == 0 && strcasecmp(t, "TYPE0") != 0 && strcmp(t, "") != 0) { fprintf(stderr, "error unknown type %s\n", t); @@ -187,7 +194,7 @@ static int massage_class(const char* c) { if(c) { - int r = ldns_get_rr_class_by_name(c); + int r = sldns_get_rr_class_by_name(c); if(r == 0 && strcasecmp(c, "CLASS0") != 0 && strcmp(c, "") != 0) { fprintf(stderr, "error unknown class %s\n", c); @@ -211,61 +218,36 @@ secure_str(struct ub_result* result) static void pretty_type(char* s, size_t len, int t) { - char* d = ldns_rr_type2str(t); + char d[16]; + sldns_wire2str_type_buf((uint16_t)t, d, sizeof(d)); snprintf(s, len, "%s", d); - free(d); } /** nice string for class */ static void pretty_class(char* s, size_t len, int c) { - char* d = ldns_rr_class2str(c); + char d[16]; + sldns_wire2str_class_buf((uint16_t)c, d, sizeof(d)); snprintf(s, len, "%s", d); - free(d); } /** nice string for rcode */ static void pretty_rcode(char* s, size_t len, int r) { - ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, r); - if(rcode) { - snprintf(s, len, "%s", rcode->name); - } else { - snprintf(s, len, "RCODE%d", r); - } + char d[16]; + sldns_wire2str_rcode_buf(r, d, sizeof(d)); + snprintf(s, len, "%s", d); } /** convert and print rdata */ static void print_rd(int t, char* data, size_t len) { - size_t i, pos = 0; - uint8_t* rd = (uint8_t*)malloc(len+2); - ldns_rr* rr = ldns_rr_new(); - ldns_status status; - if(!rd || !rr) { - fprintf(stderr, "out of memory"); - exit(1); - } - ldns_rr_set_type(rr, t); - ldns_write_uint16(rd, len); - memmove(rd+2, data, len); - ldns_rr_set_owner(rr, NULL); - status = ldns_wire2rdf(rr, rd, len+2, &pos); - if(status != LDNS_STATUS_OK) { - free(rd); - ldns_rr_free(rr); - printf("error_printing_data"); - return; - } - for(i=0; i<ldns_rr_rd_count(rr); i++) { - printf(" "); - ldns_rdf_print(stdout, ldns_rr_rdf(rr, i)); - } - ldns_rr_free(rr); - free(rd); + char s[65535]; + sldns_wire2str_rdata_buf((uint8_t*)data, len, s, sizeof(s), (uint16_t)t); + printf(" %s", s); } /** pretty line of RR data for results */ @@ -340,24 +322,14 @@ pretty_output(char* q, int t, int c, struct ub_result* result, int docname) else if(t == LDNS_RR_TYPE_MX) printf(" has no mail handler record"); else if(t == LDNS_RR_TYPE_ANY) { - ldns_pkt* p = NULL; - if(ldns_wire2pkt(&p, result->answer_packet, - (size_t)result->answer_len)==LDNS_STATUS_OK){ - if(ldns_rr_list_rr_count( - ldns_pkt_answer(p)) == 0) - printf(" has no records\n"); - else { - printf(" ANY:\n"); - ldns_rr_list_print(stdout, - ldns_pkt_answer(p)); - } - } else { - fprintf(stderr, "could not parse " - "reply packet to ANY query\n"); + char* s = sldns_wire2str_pkt( + result->answer_packet, + (size_t)result->answer_len); + if(!s) { + fprintf(stderr, "alloc failure\n"); exit(1); } - ldns_pkt_free(p); - + printf("%s\n", s); } else printf(" has no %s record", tstr); printf(" %s\n", secstatus); } @@ -437,7 +409,7 @@ extern int optind; /** getopt global, in case header files fail to declare it. */ extern char* optarg; -/** Main routine for checkconf */ +/** Main routine for unbound-host */ int main(int argc, char* argv[]) { int c; @@ -451,9 +423,11 @@ int main(int argc, char* argv[]) fprintf(stderr, "error: out of memory\n"); exit(1); } + /* no need to fetch additional targets, we only do few lookups */ + check_ub_res(ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0")); /* parse the options */ - while( (c=getopt(argc, argv, "46F:c:df:hrt:vy:C:")) != -1) { + while( (c=getopt(argc, argv, "46DF:c:df:hrt:vy:C:")) != -1) { switch(c) { case '4': check_ub_res(ub_ctx_set_option(ctx, "do-ip6:", "no")); @@ -467,6 +441,9 @@ int main(int argc, char* argv[]) case 'C': check_ub_res(ub_ctx_config(ctx, optarg)); break; + case 'D': + check_ub_res(ub_ctx_add_ta_file(ctx, ROOT_ANCHOR_FILE)); + break; case 'd': debuglevel++; if(debuglevel < 2) @@ -509,6 +486,12 @@ int main(int argc, char* argv[]) if(argc != 1) usage(); +#ifdef HAVE_NSS + if(NSS_NoDB_Init(".") != SECSuccess) { + fprintf(stderr, "could not init NSS\n"); + return 1; + } +#endif lookup(ctx, argv[0], qtype, qclass); return 0; } diff --git a/usr.sbin/unbound/smallapp/worker_cb.c b/usr.sbin/unbound/smallapp/worker_cb.c index 6ed95ac0107..e88e8c8d754 100644 --- a/usr.sbin/unbound/smallapp/worker_cb.c +++ b/usr.sbin/unbound/smallapp/worker_cb.c @@ -99,14 +99,13 @@ void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) log_assert(0); } -struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), - size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), - uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), +struct outbound_entry* worker_send_query( + struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) + size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream), + struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); return 0; @@ -132,14 +131,13 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg)) log_assert(0); } -struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), - size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), - uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), +struct outbound_entry* libworker_send_query( + struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct edns_option* ATTR_UNUSED(opt_list), - struct sockaddr_storage* ATTR_UNUSED(addr), + int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q)) + size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream), + struct module_qstate* ATTR_UNUSED(q)) { log_assert(0); return 0; @@ -225,8 +223,8 @@ struct order_id { int order_lock_cmp(const void* e1, const void* e2) { - struct order_id* o1 = (struct order_id*)e1; - struct order_id* o2 = (struct order_id*)e2; + const struct order_id* o1 = e1; + const struct order_id* o2 = e2; if(o1->thr < o2->thr) return -1; if(o1->thr > o2->thr) return 1; if(o1->instance < o2->instance) return -1; @@ -237,7 +235,7 @@ int order_lock_cmp(const void* e1, const void* e2) int codeline_cmp(const void* a, const void* b) { - return strcmp((const char*)a, (const char*)b); + return strcmp(a, b); } int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) diff --git a/usr.sbin/unbound/systemd.m4 b/usr.sbin/unbound/systemd.m4 new file mode 100644 index 00000000000..e5d4e27f6de --- /dev/null +++ b/usr.sbin/unbound/systemd.m4 @@ -0,0 +1,31 @@ +# macros for configuring systemd +# Copyright 2015, Sami Kerola, CloudFlare. +# BSD licensed. +AC_ARG_ENABLE([systemd], + [AS_HELP_STRING([--enable-systemd], [compile with systemd support])], + [], [enable_systemd=no]) +have_systemd=no +AS_IF([test "x$enable_systemd" != xno], [ + ifdef([PKG_CHECK_MODULES], [ + dnl systemd v209 or newer + PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [have_systemd=yes], [have_systemd=no]) + dnl old systemd library + AS_IF([test "x$have_systemd" != "xyes"], [ + PKG_CHECK_MODULES([SYSTEMD_DAEMON], [libsystemd-daemon], + [have_systemd_daemon=yes], [have_systemd_daemon=no]) + AS_IF([test "x$have_systemd_daemon" = "xyes"], + [have_systemd=yes]) + ]) + AS_CASE([$enable_systemd:$have_systemd], + [yes:no], + [AC_MSG_ERROR([systemd enabled but libsystemd not found])], + [*:yes], + [AC_DEFINE([HAVE_SYSTEMD], [1], [Define to 1 if systemd should be used]) + LIBS="$LIBS $SYSTEMD_LIBS" + ] + ) + ], [ + AC_MSG_ERROR([systemd enabled but need pkg-config to configure for it]) + ]) +]) +AM_CONDITIONAL([USE_SYSTEMD], [test "x$have_systemd" = xyes]) diff --git a/usr.sbin/unbound/util/alloc.c b/usr.sbin/unbound/util/alloc.c index b5ccd96b429..2c6e1a23f6c 100644 --- a/usr.sbin/unbound/util/alloc.c +++ b/usr.sbin/unbound/util/alloc.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -52,7 +52,7 @@ /** setup new special type */ static void -alloc_setup_special(alloc_special_t* t) +alloc_setup_special(alloc_special_type* t) { memset(t, 0, sizeof(*t)); lock_rw_init(&t->entry.lock); @@ -64,12 +64,13 @@ alloc_setup_special(alloc_special_t* t) * @param alloc: the structure to fill up. */ static void -prealloc(struct alloc_cache* alloc) +prealloc_setup(struct alloc_cache* alloc) { - alloc_special_t* p; + alloc_special_type* p; int i; for(i=0; i<ALLOC_SPECIAL_MAX; i++) { - if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) { + if(!(p = (alloc_special_type*)malloc( + sizeof(alloc_special_type)))) { log_err("prealloc: out of memory"); return; } @@ -128,7 +129,7 @@ alloc_init(struct alloc_cache* alloc, struct alloc_cache* super, void alloc_clear(struct alloc_cache* alloc) { - alloc_special_t* p, *np; + alloc_special_type* p, *np; struct regional* r, *nr; if(!alloc) return; @@ -187,10 +188,10 @@ alloc_get_id(struct alloc_cache* alloc) return id; } -alloc_special_t* +alloc_special_type* alloc_special_obtain(struct alloc_cache* alloc) { - alloc_special_t* p; + alloc_special_type* p; log_assert(alloc); /* see if in local cache */ if(alloc->quar) { @@ -216,8 +217,8 @@ alloc_special_obtain(struct alloc_cache* alloc) } } /* allocate new */ - prealloc(alloc); - if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) { + prealloc_setup(alloc); + if(!(p = (alloc_special_type*)malloc(sizeof(alloc_special_type)))) { log_err("alloc_special_obtain: out of memory"); return NULL; } @@ -228,10 +229,10 @@ alloc_special_obtain(struct alloc_cache* alloc) /** push mem and some more items to the super */ static void -pushintosuper(struct alloc_cache* alloc, alloc_special_t* mem) +pushintosuper(struct alloc_cache* alloc, alloc_special_type* mem) { int i; - alloc_special_t *p = alloc->quar; + alloc_special_type *p = alloc->quar; log_assert(p); log_assert(alloc && alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX); @@ -253,7 +254,7 @@ pushintosuper(struct alloc_cache* alloc, alloc_special_t* mem) } void -alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem) +alloc_special_release(struct alloc_cache* alloc, alloc_special_type* mem) { log_assert(alloc); if(!mem) @@ -286,12 +287,12 @@ alloc_stats(struct alloc_cache* alloc) size_t alloc_get_mem(struct alloc_cache* alloc) { - alloc_special_t* p; + alloc_special_type* p; size_t s = sizeof(*alloc); if(!alloc->super) { lock_quick_lock(&alloc->lock); /* superalloc needs locking */ } - s += sizeof(alloc_special_t) * alloc->num_quar; + s += sizeof(alloc_special_type) * alloc->num_quar; for(p = alloc->quar; p; p = alloc_special_next(p)) { s += lock_get_mem(&p->entry.lock); } @@ -364,11 +365,18 @@ void *unbound_stat_malloc(size_t size) #ifdef calloc #undef calloc #endif +#ifndef INT_MAX +#define INT_MAX (((int)-1)>>1) +#endif /** calloc with stats */ void *unbound_stat_calloc(size_t nmemb, size_t size) { - size_t s = (nmemb*size==0)?(size_t)1:nmemb*size; - void* res = calloc(1, s+16); + size_t s; + void* res; + if(nmemb != 0 && INT_MAX/nmemb < size) + return NULL; /* integer overflow check */ + s = (nmemb*size==0)?(size_t)1:nmemb*size; + res = calloc(1, s+16); if(!res) return NULL; log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, (unsigned)size); unbound_mem_alloc += s; @@ -503,8 +511,12 @@ void *unbound_stat_malloc_lite(size_t size, const char* file, int line, void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file, int line, const char* func) { - size_t req = nmemb * size; - void* res = malloc(req+lite_pad*2+sizeof(size_t)); + size_t req; + void* res; + if(nmemb != 0 && INT_MAX/nmemb < size) + return NULL; /* integer overflow check */ + req = nmemb * size; + res = malloc(req+lite_pad*2+sizeof(size_t)); if(!res) return NULL; memmove(res, lite_pre, lite_pad); memmove(res+lite_pad, &req, sizeof(size_t)); @@ -601,13 +613,13 @@ char* unbound_lite_wrapstr(char* s) return n; } -#undef ldns_pkt2wire -ldns_status unbound_lite_pkt2wire(uint8_t **dest, const ldns_pkt *p, +#undef sldns_pkt2wire +sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p, size_t *size) { uint8_t* md = NULL; size_t ms = 0; - ldns_status s = ldns_pkt2wire(&md, p, &ms); + sldns_status s = sldns_pkt2wire(&md, p, &ms); if(md) { *dest = unbound_stat_malloc_lite(ms, __FILE__, __LINE__, __func__); diff --git a/usr.sbin/unbound/util/alloc.h b/usr.sbin/unbound/util/alloc.h index 4ed0053e2b4..9839a455017 100644 --- a/usr.sbin/unbound/util/alloc.h +++ b/usr.sbin/unbound/util/alloc.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -53,11 +53,11 @@ struct ub_packed_rrset_key; struct regional; /** The special type, packed rrset. Not allowed to be used for other memory */ -typedef struct ub_packed_rrset_key alloc_special_t; +typedef struct ub_packed_rrset_key alloc_special_type; /** clean the special type. Pass pointer. */ #define alloc_special_clean(x) (x)->id = 0; /** access next pointer. (in available spot). Pass pointer. */ -#define alloc_special_next(x) ((alloc_special_t*)((x)->entry.overflow_next)) +#define alloc_special_next(x) ((alloc_special_type*)((x)->entry.overflow_next)) /** set next pointer. (in available spot). Pass pointers. */ #define alloc_set_special_next(x, y) \ ((x)->entry.overflow_next) = (struct lruhash_entry*)(y); @@ -71,11 +71,11 @@ typedef struct ub_packed_rrset_key alloc_special_t; */ struct alloc_cache { /** lock, only used for the super. */ - lock_quick_t lock; + lock_quick_type lock; /** global allocator above this one. NULL for none (malloc/free) */ struct alloc_cache* super; /** singly linked lists of special type. These are free for use. */ - alloc_special_t* quar; + alloc_special_type* quar; /** number of items in quarantine. */ size_t num_quar; /** thread number for id creation */ @@ -116,20 +116,20 @@ void alloc_init(struct alloc_cache* alloc, struct alloc_cache* super, void alloc_clear(struct alloc_cache* alloc); /** - * Get a new special_t element. + * Get a new special_type element. * @param alloc: where to alloc it. * @return: memory block. Will not return NULL (instead fatal_exit). * The block is zeroed. */ -alloc_special_t* alloc_special_obtain(struct alloc_cache* alloc); +alloc_special_type* alloc_special_obtain(struct alloc_cache* alloc); /** - * Return special_t back to pool. + * Return special_type back to pool. * The block is cleaned up (zeroed) which also invalidates the ID inside. * @param alloc: where to alloc it. * @param mem: block to free. */ -void alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem); +void alloc_special_release(struct alloc_cache* alloc, alloc_special_type* mem); /** * Set ID number of special type to a fresh new ID number. @@ -177,8 +177,11 @@ void alloc_set_id_cleanup(struct alloc_cache* alloc, void (*cleanup)(void*), void* arg); #ifdef UNBOUND_ALLOC_LITE -# include <ldns/packet.h> -# include <openssl/ssl.h> +# include <sldns/ldns.h> +# include <sldns/packet.h> +# ifdef HAVE_OPENSSL_SSL_H +# include <openssl/ssl.h> +# endif # define malloc(s) unbound_stat_malloc_lite(s, __FILE__, __LINE__, __func__) # define calloc(n,s) unbound_stat_calloc_lite(n, s, __FILE__, __LINE__, __func__) # define free(p) unbound_stat_free_lite(p, __FILE__, __LINE__, __func__) @@ -198,15 +201,15 @@ void *unbound_stat_realloc_lite(void *ptr, size_t size, const char* file, char* unbound_strdup_lite(const char* s, const char* file, int line, const char* func); char* unbound_lite_wrapstr(char* s); -# define ldns_rr2str(rr) unbound_lite_wrapstr(ldns_rr2str(rr)) -# define ldns_rdf2str(rdf) unbound_lite_wrapstr(ldns_rdf2str(rdf)) -# define ldns_rr_type2str(t) unbound_lite_wrapstr(ldns_rr_type2str(t)) -# define ldns_rr_class2str(c) unbound_lite_wrapstr(ldns_rr_class2str(c)) -# define ldns_rr_list2str(r) unbound_lite_wrapstr(ldns_rr_list2str(r)) -# define ldns_pkt2str(p) unbound_lite_wrapstr(ldns_pkt2str(p)) -# define ldns_pkt_rcode2str(r) unbound_lite_wrapstr(ldns_pkt_rcode2str(r)) -# define ldns_pkt2wire(a, r, s) unbound_lite_pkt2wire(a, r, s) -ldns_status unbound_lite_pkt2wire(uint8_t **dest, const ldns_pkt *p, size_t *size); +# define sldns_rr2str(rr) unbound_lite_wrapstr(sldns_rr2str(rr)) +# define sldns_rdf2str(rdf) unbound_lite_wrapstr(sldns_rdf2str(rdf)) +# define sldns_rr_type2str(t) unbound_lite_wrapstr(sldns_rr_type2str(t)) +# define sldns_rr_class2str(c) unbound_lite_wrapstr(sldns_rr_class2str(c)) +# define sldns_rr_list2str(r) unbound_lite_wrapstr(sldns_rr_list2str(r)) +# define sldns_pkt2str(p) unbound_lite_wrapstr(sldns_pkt2str(p)) +# define sldns_pkt_rcode2str(r) unbound_lite_wrapstr(sldns_pkt_rcode2str(r)) +# define sldns_pkt2wire(a, r, s) unbound_lite_pkt2wire(a, r, s) +sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p, size_t *size); # define i2d_DSA_SIG(d, s) unbound_lite_i2d_DSA_SIG(d, s) int unbound_lite_i2d_DSA_SIG(DSA_SIG* dsasig, unsigned char** sig); #endif /* UNBOUND_ALLOC_LITE */ diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c index 3e72bcad06b..1eba4af860c 100644 --- a/usr.sbin/unbound/util/config_file.c +++ b/usr.sbin/unbound/util/config_file.c @@ -105,8 +105,10 @@ config_create(void) cfg->ssl_port = 853; cfg->ssl_upstream = 0; cfg->use_syslog = 1; + cfg->log_identity = NULL; /* changed later with argv[0] */ cfg->log_time_ascii = 0; cfg->log_queries = 0; + cfg->log_replies = 0; #ifndef USE_WINSOCK # ifdef USE_MINI_EVENT /* select max 1024 sockets */ @@ -157,6 +159,7 @@ config_create(void) cfg->donotqueryaddrs = NULL; cfg->donotquery_localhost = 1; cfg->root_hints = NULL; + cfg->use_systemd = 0; cfg->do_daemonize = 1; cfg->if_automatic = 0; cfg->so_rcvbuf = 0; @@ -170,6 +173,7 @@ config_create(void) cfg->out_ifs = NULL; cfg->stubs = NULL; cfg->forwards = NULL; + cfg->views = NULL; cfg->acls = NULL; cfg->harden_short_bufsize = 0; cfg->harden_large_queries = 0; @@ -202,6 +206,7 @@ config_create(void) cfg->val_log_squelch = 0; cfg->val_permissive_mode = 0; cfg->ignore_cd = 0; + cfg->serve_expired = 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 */ @@ -212,6 +217,7 @@ config_create(void) cfg->local_zones = NULL; cfg->local_zones_nodefault = NULL; cfg->local_data = NULL; + cfg->local_zone_overrides = NULL; cfg->unblock_lan_zones = 0; cfg->insecure_lan_zones = 0; cfg->python_script = NULL; @@ -239,13 +245,18 @@ config_create(void) goto error_exit; #endif cfg->disable_dnssec_lame_check = 0; + cfg->ip_ratelimit = 0; cfg->ratelimit = 0; + cfg->ip_ratelimit_slabs = 4; cfg->ratelimit_slabs = 4; + cfg->ip_ratelimit_size = 4*1024*1024; cfg->ratelimit_size = 4*1024*1024; cfg->ratelimit_for_domain = NULL; cfg->ratelimit_below_domain = NULL; + cfg->ip_ratelimit_factor = 10; cfg->ratelimit_factor = 10; cfg->qname_minimisation = 0; + cfg->qname_minimisation_strict = 0; return cfg; error_exit: config_delete(cfg); @@ -366,6 +377,7 @@ int config_set_option(struct config_file* cfg, const char* opt, log_set_time_asc(cfg->log_time_ascii); } else S_SIZET_NONZERO("max-udp-size:", max_udp_size) else S_YNO("use-syslog:", use_syslog) + else S_STR("log-identity:", log_identity) else S_YNO("extended-statistics:", stat_extended) else S_YNO("statistics-cumulative:", stat_cumulative) else S_YNO("do-ip4:", do_ip4) @@ -380,6 +392,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_STR("ssl-service-pem:", ssl_service_pem) else S_NUMBER_NONZERO("ssl-port:", ssl_port) else S_YNO("interface-automatic:", if_automatic) + else S_YNO("use-systemd:", use_systemd) else S_YNO("do-daemonize:", do_daemonize) else S_NUMBER_NONZERO("port:", port) else S_NUMBER_NONZERO("outgoing-range:", outgoing_num_ports) @@ -450,8 +463,10 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_NUMBER_OR_ZERO("val-log-level:", val_log_level) 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("val-permissive-mode:", val_permissive_mode) else S_YNO("ignore-cd-flag:", ignore_cd) + else S_YNO("serve-expired:", serve_expired) 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) @@ -477,14 +492,22 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_STR("module-config:", module_conf) else S_STR("python-script:", python_script) else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check) + else if(strcmp(opt, "ip-ratelimit:") == 0) { + IS_NUMBER_OR_ZERO; cfg->ip_ratelimit = atoi(val); + infra_ip_ratelimit=cfg->ip_ratelimit; + } else if(strcmp(opt, "ratelimit:") == 0) { IS_NUMBER_OR_ZERO; cfg->ratelimit = atoi(val); infra_dp_ratelimit=cfg->ratelimit; } + else S_MEMSIZE("ip-ratelimit-size:", ip_ratelimit_size) else S_MEMSIZE("ratelimit-size:", ratelimit_size) + else S_POW2("ip-ratelimit-slabs:", ip_ratelimit_slabs) else S_POW2("ratelimit-slabs:", ratelimit_slabs) + else S_NUMBER_OR_ZERO("ip-ratelimit-factor:", ip_ratelimit_factor) else S_NUMBER_OR_ZERO("ratelimit-factor:", ratelimit_factor) else S_YNO("qname-minimisation:", qname_minimisation) + else S_YNO("qname-minimisation-strict:", qname_minimisation_strict) else if(strcmp(opt, "define-tag:") ==0) { return config_add_tag(cfg, val); /* val_sig_skew_min and max are copied into val_env during init, @@ -508,10 +531,11 @@ int config_set_option(struct config_file* cfg, const char* opt, /* unknown or unsupported (from the set_option interface): * interface, outgoing-interface, access-control, * stub-zone, name, stub-addr, stub-host, stub-prime - * forward-first, stub-first, - * forward-zone, name, forward-addr, forward-host, + * forward-first, stub-first, forward-ssl-upstream, + * stub-ssl-upstream, forward-zone, + * name, forward-addr, forward-host, * ratelimit-for-domain, ratelimit-below-domain, - * local-zone-tag */ + * local-zone-tag, access-control-view */ return 0; } return 1; @@ -640,6 +664,14 @@ config_collate_cat(struct config_strlist* list) func(buf, arg); \ } \ } +/** compare and print list option */ +#define O_LS3(opt, name, lst) if(strcmp(opt, name)==0) { \ + struct config_str3list* p = cfg->lst; \ + for(p = cfg->lst; p; p = p->next) { \ + snprintf(buf, len, "%s %s %s", p->str, p->str2, p->str3); \ + func(buf, arg); \ + } \ + } /** compare and print taglist option */ #define O_LTG(opt, name, lst) if(strcmp(opt, name)==0) { \ char* tmpstr = NULL; \ @@ -666,6 +698,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "statistics-cumulative", stat_cumulative) else O_YNO(opt, "extended-statistics", stat_extended) else O_YNO(opt, "use-syslog", use_syslog) + else O_STR(opt, "log-identity", log_identity) else O_YNO(opt, "log-time-ascii", log_time_ascii) else O_DEC(opt, "num-threads", num_threads) else O_IFC(opt, "interface", num_ifs, ifs) @@ -709,12 +742,14 @@ config_get_option(struct config_file* cfg, const char* opt, else O_STR(opt, "ssl-service-key", ssl_service_key) else O_STR(opt, "ssl-service-pem", ssl_service_pem) else O_DEC(opt, "ssl-port", ssl_port) + else O_YNO(opt, "use-systemd", use_systemd) else O_YNO(opt, "do-daemonize", do_daemonize) else O_STR(opt, "chroot", chrootdir) else O_STR(opt, "username", username) else O_STR(opt, "directory", directory) else O_STR(opt, "logfile", logfile) else O_YNO(opt, "log-queries", log_queries) + else O_YNO(opt, "log-replies", log_replies) else O_STR(opt, "pidfile", pidfile) else O_YNO(opt, "hide-identity", hide_identity) else O_YNO(opt, "hide-version", hide_version) @@ -739,6 +774,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_DEC(opt, "val-log-level", val_log_level) else O_YNO(opt, "val-permissive-mode", val_permissive_mode) else O_YNO(opt, "ignore-cd-flag", ignore_cd) + else O_YNO(opt, "serve-expired", serve_expired) 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) @@ -773,17 +809,27 @@ config_get_option(struct config_file* cfg, const char* opt, else O_DEC(opt, "max-udp-size", max_udp_size) else O_STR(opt, "python-script", python_script) else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check) + else O_DEC(opt, "ip-ratelimit", ip_ratelimit) else O_DEC(opt, "ratelimit", ratelimit) + else O_MEM(opt, "ip-ratelimit-size", ip_ratelimit_size) else O_MEM(opt, "ratelimit-size", ratelimit_size) + else O_DEC(opt, "ip-ratelimit-slabs", ip_ratelimit_slabs) else O_DEC(opt, "ratelimit-slabs", ratelimit_slabs) else O_LS2(opt, "ratelimit-for-domain", ratelimit_for_domain) else O_LS2(opt, "ratelimit-below-domain", ratelimit_below_domain) + else O_DEC(opt, "ip-ratelimit-factor", ip_ratelimit_factor) else O_DEC(opt, "ratelimit-factor", ratelimit_factor) else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min) else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max) else O_YNO(opt, "qname-minimisation", qname_minimisation) + else O_YNO(opt, "qname-minimisation-strict", qname_minimisation_strict) else O_IFC(opt, "define-tag", num_tags, tagname) else O_LTG(opt, "local-zone-tag", local_zone_tags) + else O_LTG(opt, "access-control-tag", acl_tags) + else O_LS3(opt, "local-zone-override", local_zone_overrides) + else O_LS3(opt, "access-control-tag-action", acl_tag_actions) + else O_LS3(opt, "access-control-tag-data", acl_tag_datas) + else O_LS2(opt, "access-control-view", acl_view) /* not here: * outgoing-permit, outgoing-avoid - have list of ports * local-zone - zones and nodefault variables @@ -936,6 +982,20 @@ config_deldblstrlist(struct config_str2list* p) } void +config_deltrplstrlist(struct config_str3list* p) +{ + struct config_str3list *np; + while(p) { + np = p->next; + free(p->str); + free(p->str2); + free(p->str3); + free(p); + p = np; + } +} + +void config_delstub(struct config_stub* p) { if(!p) return; @@ -956,6 +1016,27 @@ config_delstubs(struct config_stub* p) } } +void +config_delview(struct config_view* p) +{ + if(!p) return; + free(p->name); + config_deldblstrlist(p->local_zones); + config_delstrlist(p->local_zones_nodefault); + config_delstrlist(p->local_data); + free(p); +} + +void +config_delviews(struct config_view* p) +{ + struct config_view* np; + while(p) { + np = p->next; + config_delview(p); + p = np; + } +} /** delete string array */ static void config_del_strarray(char** array, int num) @@ -969,8 +1050,7 @@ config_del_strarray(char** array, int num) free(array); } -/** delete stringbytelist */ -static void +void config_del_strbytelist(struct config_strbytelist* p) { struct config_strbytelist* np; @@ -995,10 +1075,12 @@ config_delete(struct config_file* cfg) free(cfg->target_fetch_policy); free(cfg->ssl_service_key); free(cfg->ssl_service_pem); + free(cfg->log_identity); config_del_strarray(cfg->ifs, cfg->num_ifs); config_del_strarray(cfg->out_ifs, cfg->num_out_ifs); config_delstubs(cfg->stubs); config_delstubs(cfg->forwards); + config_delviews(cfg->views); config_delstrlist(cfg->donotqueryaddrs); config_delstrlist(cfg->root_hints); free(cfg->identity); @@ -1020,8 +1102,12 @@ config_delete(struct config_file* cfg) config_deldblstrlist(cfg->local_zones); config_delstrlist(cfg->local_zones_nodefault); config_delstrlist(cfg->local_data); + config_deltrplstrlist(cfg->local_zone_overrides); config_del_strarray(cfg->tagname, cfg->num_tags); config_del_strbytelist(cfg->local_zone_tags); + config_del_strbytelist(cfg->acl_tags); + config_deltrplstrlist(cfg->acl_tag_actions); + config_deltrplstrlist(cfg->acl_tag_datas); config_delstrlist(cfg->control_ifs); free(cfg->server_key_file); free(cfg->server_cert_file); @@ -1180,6 +1266,23 @@ int cfg_strlist_append(struct config_strlist_head* list, char* item) } int +cfg_region_strlist_insert(struct regional* region, + struct config_strlist** head, char* item) +{ + struct config_strlist *s; + if(!item || !head) + return 0; + s = (struct config_strlist*)regional_alloc_zero(region, + sizeof(struct config_strlist)); + if(!s) + return 0; + s->str = item; + s->next = *head; + *head = s; + return 1; +} + +int cfg_strlist_insert(struct config_strlist** head, char* item) { struct config_strlist *s; @@ -1210,6 +1313,24 @@ cfg_str2list_insert(struct config_str2list** head, char* item, char* i2) return 1; } +int +cfg_str3list_insert(struct config_str3list** head, char* item, char* i2, + char* i3) +{ + struct config_str3list *s; + if(!item || !i2 || !i3 || !head) + return 0; + s = (struct config_str3list*)calloc(1, sizeof(struct config_str3list)); + if(!s) + return 0; + s->str = item; + s->str2 = i2; + s->str3 = i3; + s->next = *head; + *head = s; + return 1; +} + int cfg_strbytelist_insert(struct config_strbytelist** head, char* item, uint8_t* i2, size_t i2len) @@ -1373,6 +1494,7 @@ cfg_set_bit(uint8_t* bitlist, size_t len, int id) { int pos = id/8; log_assert((size_t)pos < len); + (void)len; bitlist[pos] |= 1<<(id%8); } diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h index a51cdb464c0..d52c2f48104 100644 --- a/usr.sbin/unbound/util/config_file.h +++ b/usr.sbin/unbound/util/config_file.h @@ -42,12 +42,15 @@ #ifndef UTIL_CONFIG_FILE_H #define UTIL_CONFIG_FILE_H struct config_stub; +struct config_view; struct config_strlist; struct config_str2list; +struct config_str3list; struct config_strbytelist; struct module_qstate; struct sock_list; struct ub_packed_rrset_key; +struct regional; /** * The configuration options. @@ -73,6 +76,8 @@ struct config_file { int do_ip4; /** do ip6 query support. */ int do_ip6; + /** prefer ip6 upstream queries. */ + int prefer_ip6; /** do udp query support. */ int do_udp; /** do tcp query support. */ @@ -163,6 +168,8 @@ struct config_file { struct config_stub* stubs; /** the forward zone definitions, linked list */ struct config_stub* forwards; + /** the views definitions, linked list */ + struct config_view* views; /** list of donotquery addresses, linked list */ struct config_strlist* donotqueryaddrs; /** list of access control entries, linked list */ @@ -222,6 +229,10 @@ struct config_file { int log_time_ascii; /** log queries with one line per query */ int log_queries; + /** log replies with one line per reply */ + int log_replies; + /** log identity to report */ + char* log_identity; /** do not report identity (id.server, hostname.bind) */ int hide_identity; @@ -268,6 +279,8 @@ struct config_file { int val_permissive_mode; /** ignore the CD flag in incoming queries and refuse them bogus data */ int ignore_cd; + /** serve expired entries and prefetch them */ + int serve_expired; /** nsec3 maximum iterations per key size, string */ char* val_nsec3_key_iterations; /** autotrust add holddown time, in seconds */ @@ -292,12 +305,22 @@ struct config_file { struct config_strlist* local_zones_nodefault; /** local data RRs configured */ struct config_strlist* local_data; + /** local zone override types per netblock */ + struct config_str3list* local_zone_overrides; /** unblock lan zones (reverse lookups for AS112 zones) */ int unblock_lan_zones; /** insecure lan zones (don't validate AS112 zones) */ int insecure_lan_zones; /** list of zonename, tagbitlist */ struct config_strbytelist* local_zone_tags; + /** list of aclname, tagbitlist */ + struct config_strbytelist* acl_tags; + /** list of aclname, tagname, localzonetype */ + struct config_str3list* acl_tag_actions; + /** list of aclname, tagname, redirectdata */ + struct config_str3list* acl_tag_datas; + /** list of aclname, view*/ + struct config_str2list* acl_view; /** tag list, array with tagname[i] is malloced string */ char** tagname; /** number of items in the taglist */ @@ -323,6 +346,9 @@ struct config_file { /** Python script file */ char* python_script; + /** Use systemd socket activation. */ + int use_systemd; + /** daemonize, i.e. fork into the background. */ int do_daemonize; @@ -370,7 +396,16 @@ struct config_file { /** true to disable DNSSEC lameness check in iterator */ int disable_dnssec_lame_check; - /** ratelimit 0 is off, otherwise qps (unless overridden) */ + /** ratelimit for ip addresses. 0 is off, otherwise qps (unless overridden) */ + int ip_ratelimit; + /** number of slabs for ip_ratelimit cache */ + size_t ip_ratelimit_slabs; + /** memory size in bytes for ip_ratelimit cache */ + size_t ip_ratelimit_size; + /** ip_ratelimit factor, 0 blocks all, 10 allows 1/10 of traffic */ + int ip_ratelimit_factor; + + /** ratelimit for domains. 0 is off, otherwise qps (unless overridden) */ int ratelimit; /** number of slabs for ratelimit cache */ size_t ratelimit_slabs; @@ -384,6 +419,9 @@ struct config_file { int ratelimit_factor; /** minimise outgoing QNAME and hide original QTYPE if possible */ int qname_minimisation; + /** minimise QNAME in strict mode, minimise according to RFC. + * Do not apply fallback */ + int qname_minimisation_strict; }; /** from cfg username, after daemonise setup performed */ @@ -409,6 +447,27 @@ struct config_stub { int isprime; /** if forward-first is set (failover to without if fails) */ int isfirst; + /* use SSL for queries to this stub */ + int ssl_upstream; +}; + +/** + * View config options + */ +struct config_view { + /** next in list */ + struct config_view* next; + /** view name */ + char* name; + /** local zones */ + struct config_str2list* local_zones; + /** local data RRs */ + struct config_strlist* local_data; + /** local zones nodefault list */ + struct config_strlist* local_zones_nodefault; + /** Fallback to global local_zones when there is no match in the view + * view specific tree. 1 for yes, 0 for no */ + int isfirst; }; /** @@ -434,6 +493,21 @@ struct config_str2list { }; /** + * List of three strings for config options + */ +struct config_str3list { + /** next item in list */ + struct config_str3list* next; + /** first string */ + char* str; + /** second string */ + char* str2; + /** third string */ + char* str3; +}; + + +/** * List of string, bytestring for config options */ struct config_strbytelist { @@ -575,6 +649,10 @@ int cfg_strlist_append(struct config_strlist_head* list, char* item); */ int cfg_strlist_insert(struct config_strlist** head, char* item); +/** insert with region for allocation. */ +int cfg_region_strlist_insert(struct regional* region, + struct config_strlist** head, char* item); + /** * Insert string into str2list. * @param head: pointer to str2list head variable. @@ -585,8 +663,19 @@ int cfg_strlist_insert(struct config_strlist** head, char* item); int cfg_str2list_insert(struct config_str2list** head, char* item, char* i2); /** + * Insert string into str3list. + * @param head: pointer to str3list head variable. + * @param item: new item. malloced by caller. If NULL the insertion fails. + * @param i2: 2nd string, malloced by caller. If NULL the insertion fails. + * @param i3: 3rd string, malloced by caller. If NULL the insertion fails. + * @return: true on success. + */ +int cfg_str3list_insert(struct config_str3list** head, char* item, char* i2, + char* i3); + +/** * Insert string into strbytelist. - * @param head: pointer to str2list head variable. + * @param head: pointer to strbytelist head variable. * @param item: new item. malloced by caller. If NULL the insertion fails. * @param i2: 2nd string, malloced by caller. If NULL the insertion fails. * @param i2len: length of the i2 bytestring. @@ -619,6 +708,15 @@ void config_delstrlist(struct config_strlist* list); void config_deldblstrlist(struct config_str2list* list); /** + * Delete items in config triple string list. + * @param list: list. + */ +void config_deltrplstrlist(struct config_str3list* list); + +/** delete stringbytelist */ +void config_del_strbytelist(struct config_strbytelist* list); + +/** * Delete a stub item * @param p: stub item */ @@ -631,6 +729,18 @@ void config_delstub(struct config_stub* p); void config_delstubs(struct config_stub* list); /** + * Delete a view item + * @param p: view item + */ +void config_delview(struct config_view* p); + +/** + * Delete items in config view list. + * @param list: list. + */ +void config_delviews(struct config_view* list); + +/** * Convert 14digit to time value * @param str: string of 14 digits * @return time value or 0 for error. @@ -853,4 +963,7 @@ char* w_lookup_reg_str(const char* key, const char* name); void w_config_adjust_directory(struct config_file* cfg); #endif /* UB_ON_WINDOWS */ +/** debug option for unit tests. */ +extern int fake_dsa; + #endif /* UTIL_CONFIG_FILE_H */ diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex index 58d642c1da2..0e6037cd1b5 100644 --- a/usr.sbin/unbound/util/configlexer.lex +++ b/usr.sbin/unbound/util/configlexer.lex @@ -7,6 +7,12 @@ * See LICENSE for the license. * */ + +/* because flex keeps having sign-unsigned compare problems that are unfixed*/ +#if defined(__clang__)||(defined(__GNUC__)&&((__GNUC__ >4)||(defined(__GNUC_MINOR__)&&(__GNUC__ ==4)&&(__GNUC_MINOR__ >=2)))) +#pragma GCC diagnostic ignored "-Wsign-compare" +#endif + #include <ctype.h> #include <string.h> #include <strings.h> @@ -206,6 +212,7 @@ SQANY [^\'\n\r\\]|\\. LEXOUT(("comment(%s) ", yytext)); /* ignore */ } server{COLON} { YDVAR(0, VAR_SERVER) } qname-minimisation{COLON} { YDVAR(1, VAR_QNAME_MINIMISATION) } +qname-minimisation-strict{COLON} { YDVAR(1, VAR_QNAME_MINIMISATION_STRICT) } num-threads{COLON} { YDVAR(1, VAR_NUM_THREADS) } verbosity{COLON} { YDVAR(1, VAR_VERBOSITY) } port{COLON} { YDVAR(1, VAR_PORT) } @@ -216,6 +223,7 @@ outgoing-num-tcp{COLON} { YDVAR(1, VAR_OUTGOING_NUM_TCP) } incoming-num-tcp{COLON} { YDVAR(1, VAR_INCOMING_NUM_TCP) } do-ip4{COLON} { YDVAR(1, VAR_DO_IP4) } do-ip6{COLON} { YDVAR(1, VAR_DO_IP6) } +prefer-ip6{COLON} { YDVAR(1, VAR_PREFER_IP6) } do-udp{COLON} { YDVAR(1, VAR_DO_UDP) } do-tcp{COLON} { YDVAR(1, VAR_DO_TCP) } tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) } @@ -225,6 +233,7 @@ ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) } ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) } ssl-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) } ssl-port{COLON} { YDVAR(1, VAR_SSL_PORT) } +use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) } do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) } interface{COLON} { YDVAR(1, VAR_INTERFACE) } ip-address{COLON} { YDVAR(1, VAR_INTERFACE) } @@ -280,10 +289,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-ssl-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-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) } +view{COLON} { YDVAR(0, VAR_VIEW) } +view-first{COLON} { YDVAR(1, VAR_VIEW_FIRST) } do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) } do-not-query-localhost{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) } access-control{COLON} { YDVAR(2, VAR_ACCESS_CONTROL) } @@ -305,6 +318,8 @@ val-bogus-ttl{COLON} { YDVAR(1, VAR_BOGUS_TTL) } val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) } val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) } ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) } +serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) } +fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) } val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) } key-cache-size{COLON} { YDVAR(1, VAR_KEY_CACHE_SIZE) } key-cache-slabs{COLON} { YDVAR(1, VAR_KEY_CACHE_SLABS) } @@ -316,8 +331,10 @@ del-holddown{COLON} { YDVAR(1, VAR_DEL_HOLDDOWN) } keep-missing{COLON} { YDVAR(1, VAR_KEEP_MISSING) } permit-small-holddown{COLON} { YDVAR(1, VAR_PERMIT_SMALL_HOLDDOWN) } use-syslog{COLON} { YDVAR(1, VAR_USE_SYSLOG) } +log-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) } 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) } @@ -345,6 +362,11 @@ dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } 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) } +access-control-tag-action{COLON} { YDVAR(3, VAR_ACCESS_CONTROL_TAG_ACTION) } +access-control-tag-data{COLON} { YDVAR(3, VAR_ACCESS_CONTROL_TAG_DATA) } +access-control-view{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_VIEW) } +local-zone-override{COLON} { YDVAR(3, VAR_LOCAL_ZONE_OVERRIDE) } dnstap{COLON} { YDVAR(0, VAR_DNSTAP) } dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) } dnstap-socket-path{COLON} { YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } @@ -365,11 +387,15 @@ dnstap-log-forwarder-query-messages{COLON} { dnstap-log-forwarder-response-messages{COLON} { YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } disable-dnssec-lame-check{COLON} { YDVAR(1, VAR_DISABLE_DNSSEC_LAME_CHECK) } +ip-ratelimit{COLON} { YDVAR(1, VAR_IP_RATELIMIT) } ratelimit{COLON} { YDVAR(1, VAR_RATELIMIT) } +ip-ratelimit-slabs{COLON} { YDVAR(1, VAR_IP_RATELIMIT_SLABS) } ratelimit-slabs{COLON} { YDVAR(1, VAR_RATELIMIT_SLABS) } +ip-ratelimit-size{COLON} { YDVAR(1, VAR_IP_RATELIMIT_SIZE) } ratelimit-size{COLON} { YDVAR(1, VAR_RATELIMIT_SIZE) } ratelimit-for-domain{COLON} { YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } ratelimit-below-domain{COLON} { YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } +ip-ratelimit-factor{COLON} { YDVAR(1, VAR_IP_RATELIMIT_FACTOR) } ratelimit-factor{COLON} { YDVAR(1, VAR_RATELIMIT_FACTOR) } <INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; } diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y index 4ff18f0ce5c..e6e3fb4744f 100644 --- a/usr.sbin/unbound/util/configparser.y +++ b/usr.sbin/unbound/util/configparser.y @@ -69,7 +69,7 @@ extern struct config_parser_state* cfg_parser; %token <str> STRING_ARG %token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT %token VAR_OUTGOING_RANGE VAR_INTERFACE -%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP +%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_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE %token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD @@ -104,8 +104,10 @@ 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_TCP_UPSTREAM VAR_SSL_UPSTREAM +%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES +%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 %token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN %token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE %token VAR_UNBLOCK_LAN_ZONES VAR_INSECURE_LAN_ZONES @@ -122,16 +124,25 @@ extern struct config_parser_state* cfg_parser; %token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES %token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT %token VAR_DISABLE_DNSSEC_LAME_CHECK +%token VAR_IP_RATELIMIT VAR_IP_RATELIMIT_SLABS VAR_IP_RATELIMIT_SIZE %token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE -%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR +%token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN +%token VAR_IP_RATELIMIT_FACTOR VAR_RATELIMIT_FACTOR %token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN -%token VAR_QNAME_MINIMISATION VAR_IP_FREEBIND VAR_DEFINE_TAG VAR_LOCAL_ZONE_TAG +%token VAR_QNAME_MINIMISATION VAR_QNAME_MINIMISATION_STRICT VAR_IP_FREEBIND +%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 +%token VAR_LOG_IDENTITY +%token VAR_USE_SYSTEMD %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; toplevelvar: serverstart contents_server | stubstart contents_stub | forwardstart contents_forward | pythonstart contents_py | - rcstart contents_rc | dtstart contents_dt + rcstart contents_rc | dtstart contents_dt | viewstart + contents_view ; /* server: declaration */ @@ -144,7 +155,8 @@ contents_server: contents_server content_server | ; content_server: server_num_threads | server_verbosity | server_port | server_outgoing_range | server_do_ip4 | - server_do_ip6 | server_do_udp | server_do_tcp | + server_do_ip6 | server_prefer_ip6 | + server_do_udp | server_do_tcp | server_tcp_mss | server_outgoing_tcp_mss | server_interface | server_chroot | server_username | server_directory | server_logfile | server_pidfile | @@ -181,20 +193,27 @@ content_server: server_num_threads | server_verbosity | server_port | server_del_holddown | server_keep_missing | server_so_rcvbuf | server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | - server_log_queries | server_tcp_upstream | server_ssl_upstream | + server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream | 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_infra_cache_min_rtt | server_harden_algo_downgrade | - server_ip_transparent | server_ratelimit | server_ratelimit_slabs | - server_ratelimit_size | server_ratelimit_for_domain | + server_ip_transparent | server_ip_ratelimit | server_ratelimit | + server_ip_ratelimit_slabs | server_ratelimit_slabs | + server_ip_ratelimit_size | server_ratelimit_size | + server_ratelimit_for_domain | server_ratelimit_below_domain | server_ratelimit_factor | + server_ip_ratelimit_factor | server_caps_whitelist | server_cache_max_negative_ttl | server_permit_small_holddown | server_qname_minimisation | server_ip_freebind | server_define_tag | server_local_zone_tag | - server_disable_dnssec_lame_check + server_disable_dnssec_lame_check | server_access_control_tag | + 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_fake_dsa | server_log_identity | server_use_systemd ; stubstart: VAR_STUB_ZONE { @@ -210,7 +229,8 @@ stubstart: VAR_STUB_ZONE ; contents_stub: contents_stub content_stub | ; -content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first +content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first | + stub_ssl_upstream ; forwardstart: VAR_FORWARD_ZONE { @@ -226,7 +246,26 @@ forwardstart: VAR_FORWARD_ZONE ; contents_forward: contents_forward content_forward | ; -content_forward: forward_name | forward_host | forward_addr | forward_first +content_forward: forward_name | forward_host | forward_addr | forward_first | + forward_ssl_upstream + ; +viewstart: VAR_VIEW + { + struct config_view* s; + OUTYY(("\nP(view:)\n")); + s = (struct config_view*)calloc(1, sizeof(struct config_view)); + if(s) { + s->next = cfg_parser->cfg->views; + if(s->next && !s->next->name) + yyerror("view without name"); + cfg_parser->cfg->views = s; + } else + yyerror("out of memory"); + } + ; +contents_view: contents_view content_view + | ; +content_view: view_name | view_local_zone | view_local_data | view_first ; server_num_threads: VAR_NUM_THREADS STRING_ARG { @@ -402,6 +441,15 @@ server_do_tcp: VAR_DO_TCP STRING_ARG free($2); } ; +server_prefer_ip6: VAR_PREFER_IP6 STRING_ARG + { + OUTYY(("P(server_prefer_ip6:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->prefer_ip6 = (strcmp($2, "yes")==0); + free($2); + } + ; server_tcp_mss: VAR_TCP_MSS STRING_ARG { OUTYY(("P(server_tcp_mss:%s)\n", $2)); @@ -461,6 +509,15 @@ server_ssl_port: VAR_SSL_PORT STRING_ARG free($2); } ; +server_use_systemd: VAR_USE_SYSTEMD STRING_ARG + { + OUTYY(("P(server_use_systemd:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->use_systemd = (strcmp($2, "yes")==0); + free($2); + } + ; server_do_daemonize: VAR_DO_DAEMONIZE STRING_ARG { OUTYY(("P(server_do_daemonize:%s)\n", $2)); @@ -502,6 +559,15 @@ server_log_queries: VAR_LOG_QUERIES STRING_ARG free($2); } ; +server_log_replies: VAR_LOG_REPLIES STRING_ARG + { + OUTYY(("P(server_log_replies:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_replies = (strcmp($2, "yes")==0); + free($2); + } + ; server_chroot: VAR_CHROOT STRING_ARG { OUTYY(("P(server_chroot:%s)\n", $2)); @@ -521,6 +587,25 @@ server_directory: VAR_DIRECTORY STRING_ARG OUTYY(("P(server_directory:%s)\n", $2)); free(cfg_parser->cfg->directory); cfg_parser->cfg->directory = $2; + /* change there right away for includes relative to this */ + if($2[0]) { + char* d; +#ifdef UB_ON_WINDOWS + w_config_adjust_directory(cfg_parser->cfg); +#endif + d = cfg_parser->cfg->directory; + /* adjust directory if we have already chroot, + * like, we reread after sighup */ + if(cfg_parser->chroot && cfg_parser->chroot[0] && + strncmp(d, cfg_parser->chroot, strlen( + cfg_parser->chroot)) == 0) + d += strlen(cfg_parser->chroot); + if(d[0]) { + if(chdir(d)) + log_err("cannot chdir to directory: %s (%s)", + d, strerror(errno)); + } + } } ; server_logfile: VAR_LOGFILE STRING_ARG @@ -1129,6 +1214,28 @@ server_ignore_cd_flag: VAR_IGNORE_CD_FLAG STRING_ARG free($2); } ; +server_serve_expired: VAR_SERVE_EXPIRED STRING_ARG + { + OUTYY(("P(server_serve_expired:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->serve_expired = (strcmp($2, "yes")==0); + free($2); + } + ; +server_fake_dsa: VAR_FAKE_DSA STRING_ARG + { + OUTYY(("P(server_fake_dsa:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); +#ifdef HAVE_SSL + else fake_dsa = (strcmp($2, "yes")==0); + if(fake_dsa) + log_warn("test option fake_dsa is enabled"); +#endif + free($2); + } + ; server_val_log_level: VAR_VAL_LOG_LEVEL STRING_ARG { OUTYY(("P(server_val_log_level:%s)\n", $2)); @@ -1216,12 +1323,16 @@ server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 && strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0 - && strcmp($3, "typetransparent")!=0 && - strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0) + && strcmp($3, "typetransparent")!=0 + && strcmp($3, "always_transparent")!=0 + && strcmp($3, "always_refuse")!=0 + && strcmp($3, "always_nxdomain")!=0 + && strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0) yyerror("local-zone type: expected static, deny, " "refuse, redirect, transparent, " - "typetransparent, inform, inform_deny " - "or nodefault"); + "typetransparent, inform, inform_deny, " + "always_transparent, always_refuse, " + "always_nxdomain or nodefault"); else if(strcmp($3, "nodefault")==0) { if(!cfg_strlist_insert(&cfg_parser->cfg-> local_zones_nodefault, $2)) @@ -1332,6 +1443,82 @@ server_local_zone_tag: VAR_LOCAL_ZONE_TAG STRING_ARG STRING_ARG } } ; +server_access_control_tag: VAR_ACCESS_CONTROL_TAG STRING_ARG STRING_ARG + { + size_t len = 0; + uint8_t* bitlist = config_parse_taglist(cfg_parser->cfg, $3, + &len); + free($3); + OUTYY(("P(server_access_control_tag:%s)\n", $2)); + if(!bitlist) + yyerror("could not parse tags, (define-tag them first)"); + if(bitlist) { + if(!cfg_strbytelist_insert( + &cfg_parser->cfg->acl_tags, + $2, bitlist, len)) { + yyerror("out of memory"); + free($2); + } + } + } + ; +server_access_control_tag_action: VAR_ACCESS_CONTROL_TAG_ACTION STRING_ARG STRING_ARG STRING_ARG + { + OUTYY(("P(server_access_control_tag_action:%s %s %s)\n", $2, $3, $4)); + if(!cfg_str3list_insert(&cfg_parser->cfg->acl_tag_actions, + $2, $3, $4)) { + yyerror("out of memory"); + free($2); + free($3); + free($4); + } + } + ; +server_access_control_tag_data: VAR_ACCESS_CONTROL_TAG_DATA STRING_ARG STRING_ARG STRING_ARG + { + OUTYY(("P(server_access_control_tag_data:%s %s %s)\n", $2, $3, $4)); + if(!cfg_str3list_insert(&cfg_parser->cfg->acl_tag_datas, + $2, $3, $4)) { + yyerror("out of memory"); + free($2); + free($3); + free($4); + } + } + ; +server_local_zone_override: VAR_LOCAL_ZONE_OVERRIDE STRING_ARG STRING_ARG STRING_ARG + { + OUTYY(("P(server_local_zone_override:%s %s %s)\n", $2, $3, $4)); + if(!cfg_str3list_insert(&cfg_parser->cfg->local_zone_overrides, + $2, $3, $4)) { + yyerror("out of memory"); + free($2); + free($3); + free($4); + } + } + ; +server_access_control_view: VAR_ACCESS_CONTROL_VIEW STRING_ARG STRING_ARG + { + OUTYY(("P(server_access_control_view:%s %s)\n", $2, $3)); + if(!cfg_str2list_insert(&cfg_parser->cfg->acl_view, + $2, $3)) { + yyerror("out of memory"); + free($2); + free($3); + } + } + ; +server_ip_ratelimit: VAR_IP_RATELIMIT STRING_ARG + { + OUTYY(("P(server_ip_ratelimit:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->ip_ratelimit = atoi($2); + free($2); + } + ; + server_ratelimit: VAR_RATELIMIT STRING_ARG { OUTYY(("P(server_ratelimit:%s)\n", $2)); @@ -1341,6 +1528,14 @@ server_ratelimit: VAR_RATELIMIT STRING_ARG free($2); } ; +server_ip_ratelimit_size: VAR_IP_RATELIMIT_SIZE STRING_ARG + { + OUTYY(("P(server_ip_ratelimit_size:%s)\n", $2)); + if(!cfg_parse_memsize($2, &cfg_parser->cfg->ip_ratelimit_size)) + yyerror("memory size expected"); + free($2); + } + ; server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG { OUTYY(("P(server_ratelimit_size:%s)\n", $2)); @@ -1349,6 +1544,19 @@ server_ratelimit_size: VAR_RATELIMIT_SIZE STRING_ARG free($2); } ; +server_ip_ratelimit_slabs: VAR_IP_RATELIMIT_SLABS STRING_ARG + { + OUTYY(("P(server_ip_ratelimit_slabs:%s)\n", $2)); + if(atoi($2) == 0) + yyerror("number expected"); + else { + cfg_parser->cfg->ip_ratelimit_slabs = atoi($2); + if(!is_pow2(cfg_parser->cfg->ip_ratelimit_slabs)) + yyerror("must be a power of 2"); + } + free($2); + } + ; server_ratelimit_slabs: VAR_RATELIMIT_SLABS STRING_ARG { OUTYY(("P(server_ratelimit_slabs:%s)\n", $2)); @@ -1388,6 +1596,15 @@ server_ratelimit_below_domain: VAR_RATELIMIT_BELOW_DOMAIN STRING_ARG STRING_ARG } } ; +server_ip_ratelimit_factor: VAR_IP_RATELIMIT_FACTOR STRING_ARG + { + OUTYY(("P(server_ip_ratelimit_factor:%s)\n", $2)); + if(atoi($2) == 0 && strcmp($2, "0") != 0) + yyerror("number expected"); + else cfg_parser->cfg->ip_ratelimit_factor = atoi($2); + free($2); + } + ; server_ratelimit_factor: VAR_RATELIMIT_FACTOR STRING_ARG { OUTYY(("P(server_ratelimit_factor:%s)\n", $2)); @@ -1407,6 +1624,16 @@ server_qname_minimisation: VAR_QNAME_MINIMISATION STRING_ARG free($2); } ; +server_qname_minimisation_strict: VAR_QNAME_MINIMISATION_STRICT STRING_ARG + { + OUTYY(("P(server_qname_minimisation_strict:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->qname_minimisation_strict = + (strcmp($2, "yes")==0); + free($2); + } + ; stub_name: VAR_NAME STRING_ARG { OUTYY(("P(name:%s)\n", $2)); @@ -1440,6 +1667,16 @@ stub_first: VAR_STUB_FIRST STRING_ARG free($2); } ; +stub_ssl_upstream: VAR_STUB_SSL_UPSTREAM STRING_ARG + { + OUTYY(("P(stub-ssl-upstream:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->stubs->ssl_upstream = + (strcmp($2, "yes")==0); + free($2); + } + ; stub_prime: VAR_STUB_PRIME STRING_ARG { OUTYY(("P(stub-prime:%s)\n", $2)); @@ -1483,6 +1720,73 @@ forward_first: VAR_FORWARD_FIRST STRING_ARG free($2); } ; +forward_ssl_upstream: VAR_FORWARD_SSL_UPSTREAM STRING_ARG + { + OUTYY(("P(forward-ssl-upstream:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->forwards->ssl_upstream = + (strcmp($2, "yes")==0); + free($2); + } + ; +view_name: VAR_NAME STRING_ARG + { + OUTYY(("P(name:%s)\n", $2)); + if(cfg_parser->cfg->views->name) + yyerror("view name override, there must be one " + "name for one view"); + free(cfg_parser->cfg->views->name); + cfg_parser->cfg->views->name = $2; + } + ; +view_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG + { + OUTYY(("P(view_local_zone:%s %s)\n", $2, $3)); + if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 && + strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 && + strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0 + && strcmp($3, "typetransparent")!=0 + && strcmp($3, "always_transparent")!=0 + && strcmp($3, "always_refuse")!=0 + && strcmp($3, "always_nxdomain")!=0 + && strcmp($3, "inform")!=0 && strcmp($3, "inform_deny")!=0) + yyerror("local-zone type: expected static, deny, " + "refuse, redirect, transparent, " + "typetransparent, inform, inform_deny, " + "always_transparent, always_refuse, " + "always_nxdomain or nodefault"); + else if(strcmp($3, "nodefault")==0) { + if(!cfg_strlist_insert(&cfg_parser->cfg->views-> + local_zones_nodefault, $2)) + fatal_exit("out of memory adding local-zone"); + free($3); + } else { + if(!cfg_str2list_insert( + &cfg_parser->cfg->views->local_zones, + $2, $3)) + fatal_exit("out of memory adding local-zone"); + } + } + ; +view_local_data: VAR_LOCAL_DATA STRING_ARG + { + OUTYY(("P(view_local_data:%s)\n", $2)); + if(!cfg_strlist_insert(&cfg_parser->cfg->views->local_data, $2)) { + fatal_exit("out of memory adding local-data"); + free($2); + } + } + ; +view_first: VAR_VIEW_FIRST STRING_ARG + { + OUTYY(("P(view-first:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->views->isfirst=(strcmp($2, "yes")==0); + free($2); + } + ; rcstart: VAR_REMOTE_CONTROL { OUTYY(("\nP(remote-control:)\n")); @@ -1698,6 +2002,14 @@ server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG (strcmp($2, "yes")==0); free($2); } + ; +server_log_identity: VAR_LOG_IDENTITY STRING_ARG + { + OUTYY(("P(server_log_identity:%s)\n", $2)); + free(cfg_parser->cfg->log_identity); + cfg_parser->cfg->log_identity = $2; + } + ; %% /* parse helper routines could be here */ diff --git a/usr.sbin/unbound/util/data/dname.c b/usr.sbin/unbound/util/data/dname.c index 8fc475f7f3f..517af2843e2 100644 --- a/usr.sbin/unbound/util/data/dname.c +++ b/usr.sbin/unbound/util/data/dname.c @@ -270,8 +270,8 @@ dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) return 0; } -hashvalue_t -dname_query_hash(uint8_t* dname, hashvalue_t h) +hashvalue_type +dname_query_hash(uint8_t* dname, hashvalue_type h) { uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; @@ -294,8 +294,8 @@ dname_query_hash(uint8_t* dname, hashvalue_t h) return h; } -hashvalue_t -dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h) +hashvalue_type +dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h) { uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; diff --git a/usr.sbin/unbound/util/data/dname.h b/usr.sbin/unbound/util/data/dname.h index b942848a9dc..53b341bf7ef 100644 --- a/usr.sbin/unbound/util/data/dname.h +++ b/usr.sbin/unbound/util/data/dname.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -45,6 +45,7 @@ #ifndef UTIL_DATA_DNAME_H #define UTIL_DATA_DNAME_H #include "util/storage/lruhash.h" +struct sldns_buffer; /** max number of compression ptrs to follow */ #define MAX_COMPRESS_PTRS 256 @@ -55,7 +56,7 @@ * at end, position is at end of the dname. * @return: 0 on parse failure, or length including ending 0 of dname. */ -size_t query_dname_len(ldns_buffer* query); +size_t query_dname_len(struct sldns_buffer* query); /** * Determine if dname in memory is correct. no compression ptrs allowed. @@ -74,7 +75,7 @@ void query_dname_tolower(uint8_t* dname); * is unchanged. * @param dname: start of dname in packet. */ -void pkt_dname_tolower(ldns_buffer* pkt, uint8_t* dname); +void pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname); /** * Compare query dnames (uncompressed storage). The Dnames passed do not @@ -106,7 +107,7 @@ int query_dname_compare(uint8_t* d1, uint8_t* d2); * Compression pointers are followed and checked for loops. * The uncompressed wireformat length is returned. */ -size_t pkt_dname_len(ldns_buffer* pkt); +size_t pkt_dname_len(struct sldns_buffer* pkt); /** * Compare dnames in packet (compressed). Dnames must be valid. @@ -117,7 +118,7 @@ size_t pkt_dname_len(ldns_buffer* pkt); * @return: -1, 0, or +1 depending on comparison results. * Sort order is first difference found. not the canonical ordering. */ -int dname_pkt_compare(ldns_buffer* pkt, uint8_t* d1, uint8_t* d2); +int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2); /** * Hash dname, label by label, lowercasing, into hashvalue. @@ -126,7 +127,7 @@ int dname_pkt_compare(ldns_buffer* pkt, uint8_t* d1, uint8_t* d2); * @param h: initial hash value. * @return: result hash value. */ -hashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h); +hashvalue_type dname_query_hash(uint8_t* dname, hashvalue_type h); /** * Hash dname, label by label, lowercasing, into hashvalue. @@ -138,7 +139,8 @@ hashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h); * @return: result hash value. * Result is the same as dname_query_hash, even if compression is used. */ -hashvalue_t dname_pkt_hash(ldns_buffer* pkt, uint8_t* dname, hashvalue_t h); +hashvalue_type dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, + hashvalue_type h); /** * Copy over a valid dname and decompress it. @@ -146,7 +148,7 @@ hashvalue_t dname_pkt_hash(ldns_buffer* pkt, uint8_t* dname, hashvalue_t h); * @param to: buffer of size from pkt_len function to hold result. * @param dname: pointer into packet where dname starts. */ -void dname_pkt_copy(ldns_buffer* pkt, uint8_t* to, uint8_t* dname); +void dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname); /** * Copy over a valid dname to a packet. @@ -154,7 +156,7 @@ void dname_pkt_copy(ldns_buffer* pkt, uint8_t* to, uint8_t* dname); * @param dname: dname to copy. * @return: 0 if not enough space in buffer. */ -int dname_buffer_write(ldns_buffer* pkt, uint8_t* dname); +int dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname); /** * Count the number of labels in an uncompressed dname in memory. @@ -216,7 +218,7 @@ int dname_subdomain_c(uint8_t* d1, uint8_t* d2); * @param pkt: if not NULL, the packet for resolving compression ptrs. * @param dname: pointer to (start of) dname. */ -void dname_print(FILE* out, ldns_buffer* pkt, uint8_t* dname); +void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname); /** * Debug helper. Print dname to given string buffer (string buffer must diff --git a/usr.sbin/unbound/util/data/msgencode.c b/usr.sbin/unbound/util/data/msgencode.c index 034bb24bd6e..5d3a2476217 100644 --- a/usr.sbin/unbound/util/data/msgencode.c +++ b/usr.sbin/unbound/util/data/msgencode.c @@ -48,6 +48,7 @@ #include "util/regional.h" #include "util/net_help.h" #include "sldns/sbuffer.h" +#include "services/localzone.h" /** return code that means the function ran out of memory. negative so it does * not conflict with DNS rcodes. */ @@ -534,7 +535,11 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, { int r; size_t i, setstart; - *num_rrs = 0; + /* we now allow this function to be called multiple times for the + * same section, incrementally updating num_rrs. The caller is + * responsible for initializing it (which is the case in the current + * implementation). */ + if(s != LDNS_SECTION_ADDITIONAL) { if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) dnssec = 1; /* include all types in ANY answer */ @@ -581,17 +586,20 @@ static int insert_query(struct query_info* qinfo, struct compress_tree_node** tree, sldns_buffer* buffer, struct regional* region) { + uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_remaining(buffer) < qinfo->qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ - if(!compress_tree_store(qinfo->qname, - dname_count_labels(qinfo->qname), + if(!compress_tree_store(qname, dname_count_labels(qname), sldns_buffer_position(buffer), region, NULL, tree)) return RETVAL_OUTMEM; - if(sldns_buffer_current(buffer) == qinfo->qname) - sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len); - else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); + if(sldns_buffer_current(buffer) == qname) + sldns_buffer_skip(buffer, (ssize_t)qname_len); + else sldns_buffer_write(buffer, qname, qname_len); sldns_buffer_write_u16(buffer, qinfo->qtype); sldns_buffer_write_u16(buffer, qinfo->qclass); return RETVAL_OK; @@ -662,6 +670,33 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep, * for different roundrobins for sequential id client senders. */ rr_offset = RRSET_ROUNDROBIN?ntohs(id):0; + /* "prepend" any local alias records in the answer section if this + * response is supposed to be authoritative. Currently it should + * be a single CNAME record (sanity-checked in worker_handle_request()) + * but it can be extended if and when we support more variations of + * aliases. */ + if(qinfo->local_alias && (flags & BIT_AA)) { + struct reply_info arep; + time_t timezero = 0; /* to use the 'authoritative' TTL */ + memset(&arep, 0, sizeof(arep)); + arep.flags = rep->flags; + arep.an_numrrsets = 1; + arep.rrset_count = 1; + arep.rrsets = &qinfo->local_alias->rrset; + if((r=insert_section(&arep, 1, &ancount, buffer, 0, + timezero, region, &tree, LDNS_SECTION_ANSWER, + qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { + if(r == RETVAL_TRUNC) { + /* create truncated message */ + sldns_buffer_write_u16_at(buffer, 6, ancount); + LDNS_TC_SET(sldns_buffer_begin(buffer)); + sldns_buffer_flip(buffer); + return 1; + } + return 0; + } + } + /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, @@ -782,6 +817,15 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, } if(secure && (dnssec || (qflags&BIT_AD))) flags |= BIT_AD; + /* restore AA bit if we have a local alias and the response can be + * authoritative. Also clear AD bit if set as the local data is the + * primary answer. */ + if(qinf->local_alias && + (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || + FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) { + flags |= BIT_AA; + flags &= ~BIT_AD; + } log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ if(udpsize < LDNS_HEADER_SIZE) return 0; @@ -807,13 +851,17 @@ void qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ + const uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; sldns_buffer_clear(pkt); log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); sldns_buffer_skip(pkt, 2); /* id done later */ sldns_buffer_write_u16(pkt, flags); sldns_buffer_write_u16(pkt, 1); /* query count */ sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ - sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); + sldns_buffer_write(pkt, qname, qname_len); sldns_buffer_write_u16(pkt, qinfo->qtype); sldns_buffer_write_u16(pkt, qinfo->qclass); sldns_buffer_flip(pkt); @@ -838,9 +886,14 @@ error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { - if(sldns_buffer_current(buf) == qinfo->qname) - sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len); - else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len); + const uint8_t* qname = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname : qinfo->qname; + size_t qname_len = qinfo->local_alias ? + qinfo->local_alias->rrset->rk.dname_len : + qinfo->qname_len; + if(sldns_buffer_current(buf) == qname) + sldns_buffer_skip(buf, (ssize_t)qname_len); + else sldns_buffer_write(buf, qname, qname_len); sldns_buffer_write_u16(buf, qinfo->qtype); sldns_buffer_write_u16(buf, qinfo->qclass); } diff --git a/usr.sbin/unbound/util/data/msgparse.c b/usr.sbin/unbound/util/data/msgparse.c index 1d565c1ea28..5381500e152 100644 --- a/usr.sbin/unbound/util/data/msgparse.c +++ b/usr.sbin/unbound/util/data/msgparse.c @@ -71,7 +71,7 @@ smart_compare(sldns_buffer* pkt, uint8_t* dnow, */ static struct rrset_parse* new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass, hashvalue_t hash, + uint16_t type, uint16_t dclass, hashvalue_type hash, uint32_t rrset_flags, sldns_pkt_section section, struct regional* region) { @@ -159,13 +159,13 @@ pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec) return f; } -hashvalue_t +hashvalue_type pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, uint16_t dclass, uint32_t rrset_flags) { /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ /* this routine handles compressed names */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_pkt_hash(pkt, dname, h); h = hashlittle(&type, sizeof(type), h); /* host order */ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ @@ -174,25 +174,25 @@ pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, } /** create partial dname hash for rrset hash */ -static hashvalue_t +static hashvalue_type pkt_hash_rrset_first(sldns_buffer* pkt, uint8_t* dname) { /* works together with pkt_hash_rrset_rest */ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ /* this routine handles compressed names */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_pkt_hash(pkt, dname, h); return h; } /** create a rrset hash from a partial dname hash */ -static hashvalue_t -pkt_hash_rrset_rest(hashvalue_t dname_h, uint16_t type, uint16_t dclass, +static hashvalue_type +pkt_hash_rrset_rest(hashvalue_type dname_h, uint16_t type, uint16_t dclass, uint32_t rrset_flags) { /* works together with pkt_hash_rrset_first */ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ - hashvalue_t h; + hashvalue_type h; h = hashlittle(&type, sizeof(type), dname_h); /* host order */ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ h = hashlittle(&rrset_flags, sizeof(uint32_t), h); @@ -201,7 +201,7 @@ pkt_hash_rrset_rest(hashvalue_t dname_h, uint16_t type, uint16_t dclass, /** compare rrset_parse with data */ static int -rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_t h, +rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass) { @@ -215,8 +215,8 @@ rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_t h, struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, sldns_buffer* pkt, - hashvalue_t h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, - uint16_t type, uint16_t dclass) + hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, + size_t dnamelen, uint16_t type, uint16_t dclass) { struct rrset_parse* p = msg->hashtable[h & (PARSE_TABLE_SIZE-1)]; while(p) { @@ -388,7 +388,7 @@ change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, int hasother, sldns_pkt_section section, struct regional* region) { struct rrset_parse* dataset = sigset; - hashvalue_t hash = pkt_hash_rrset(pkt, sigset->dname, datatype, + hashvalue_type hash = pkt_hash_rrset(pkt, sigset->dname, datatype, sigset->rrset_class, rrset_flags); log_assert( sigset->type == LDNS_RR_TYPE_RRSIG ); log_assert( datatype != LDNS_RR_TYPE_RRSIG ); @@ -455,14 +455,14 @@ change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, */ static int find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname, - size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash, + size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_type* hash, uint32_t* rrset_flags, uint8_t** prev_dname_first, uint8_t** prev_dname_last, size_t* prev_dnamelen, uint16_t* prev_type, uint16_t* prev_dclass, struct rrset_parse** rrset_prev, sldns_pkt_section section, struct regional* region) { - hashvalue_t dname_h = pkt_hash_rrset_first(pkt, dname); + hashvalue_type dname_h = pkt_hash_rrset_first(pkt, dname); uint16_t covtype; if(*rrset_prev) { /* check if equal to previous item */ @@ -824,7 +824,7 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg, uint16_t type, prev_type = 0; uint16_t dclass, prev_dclass = 0; uint32_t rrset_flags = 0; - hashvalue_t hash = 0; + hashvalue_type hash = 0; struct rrset_parse* rrset = NULL; int r; @@ -1072,3 +1072,22 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, return 0; } + +void +log_edns_opt_list(enum verbosity_value level, const char* info_str, + struct edns_option* list) +{ + if(verbosity >= level && list) { + char str[128], *s; + size_t slen; + verbose(level, "%s", info_str); + while(list) { + s = str; + slen = sizeof(str); + (void)sldns_wire2str_edns_option_print(&s, &slen, list->opt_code, + list->opt_data, list->opt_len); + verbose(level, " %s", str); + list = list->next; + } + } +} diff --git a/usr.sbin/unbound/util/data/msgparse.h b/usr.sbin/unbound/util/data/msgparse.h index cae988ff995..e21f8504ea7 100644 --- a/usr.sbin/unbound/util/data/msgparse.h +++ b/usr.sbin/unbound/util/data/msgparse.h @@ -138,7 +138,7 @@ struct rrset_parse { /** next in list of all rrsets */ struct rrset_parse* rrset_all_next; /** hash value of rrset */ - hashvalue_t hash; + hashvalue_type hash; /** which section was it found in: one of * LDNS_SECTION_ANSWER, LDNS_SECTION_AUTHORITY, LDNS_SECTION_ADDITIONAL */ @@ -296,8 +296,8 @@ int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns, * @param rrset_flags: rrset flags (same as packed_rrset flags). * @return hash value */ -hashvalue_t pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, uint16_t type, - uint16_t dclass, uint32_t rrset_flags); +hashvalue_type pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, + uint16_t type, uint16_t dclass, uint32_t rrset_flags); /** * Lookup in msg hashtable to find a rrset. @@ -312,7 +312,7 @@ hashvalue_t pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, uint16_t ty * @return NULL or the rrset_parse if found. */ struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, - struct sldns_buffer* pkt, hashvalue_t h, uint32_t rrset_flags, + struct sldns_buffer* pkt, hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass); /** @@ -322,4 +322,13 @@ struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg, */ void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset); +/** + * Log the edns options in the edns option list. + * @param level: the verbosity level. + * @param info_str: the informational string to be printed before the options. + * @param list: the edns option list. + */ +void log_edns_opt_list(enum verbosity_value level, const char* info_str, + struct edns_option* list); + #endif /* UTIL_DATA_MSGPARSE_H */ diff --git a/usr.sbin/unbound/util/data/msgreply.c b/usr.sbin/unbound/util/data/msgreply.c index f8a24918dca..8869716b679 100644 --- a/usr.sbin/unbound/util/data/msgreply.c +++ b/usr.sbin/unbound/util/data/msgreply.c @@ -52,6 +52,8 @@ #include "util/data/msgencode.h" #include "sldns/sbuffer.h" #include "sldns/wire2str.h" +#include "util/module.h" +#include "util/fptr_wlist.h" /** MAX TTL default for messages and rrsets */ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */ @@ -76,6 +78,7 @@ parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, qinf->qname_len = msg->qname_len; qinf->qtype = msg->qtype; qinf->qclass = msg->qclass; + qinf->local_alias = NULL; return 1; } @@ -451,6 +454,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, int ret; qinf->qname = NULL; + qinf->local_alias = NULL; *rep = NULL; if(!(msg = regional_alloc(region, sizeof(*msg)))) { return LDNS_RCODE_SERVFAIL; @@ -542,6 +546,7 @@ query_info_parse(struct query_info* m, sldns_buffer* query) return 0; /* need qtype, qclass */ m->qtype = sldns_buffer_read_u16(query); m->qclass = sldns_buffer_read_u16(query); + m->local_alias = NULL; return 1; } @@ -603,10 +608,10 @@ reply_info_delete(void* d, void* ATTR_UNUSED(arg)) free(r); } -hashvalue_t +hashvalue_type query_info_hash(struct query_info *q, uint16_t flags) { - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = hashlittle(&q->qtype, sizeof(q->qtype), h); if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) h++; @@ -617,7 +622,7 @@ query_info_hash(struct query_info *q, uint16_t flags) struct msgreply_entry* query_info_entrysetup(struct query_info* q, struct reply_info* r, - hashvalue_t h) + hashvalue_type h) { struct msgreply_entry* e = (struct msgreply_entry*)malloc( sizeof(struct msgreply_entry)); @@ -814,7 +819,39 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) regional_destroy(region); } -void +void +log_reply_info(enum verbosity_value v, struct query_info *qinf, + struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, + int cached, struct sldns_buffer *rmsg) +{ + char qname_buf[LDNS_MAX_DOMAINLEN+1]; + char clientip_buf[128]; + char rcode_buf[16]; + char type_buf[16]; + char class_buf[16]; + size_t pktlen; + uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2)); + + if(verbosity < v) + return; + + sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf)); + addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); + if(rcode == LDNS_RCODE_FORMERR) + { + log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); + } else { + dname_str(qinf->qname, qname_buf); + pktlen = sldns_buffer_limit(rmsg); + sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); + sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); + log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", + clientip_buf, qname_buf, type_buf, class_buf, + rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); + } +} + +void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf) { @@ -871,9 +908,12 @@ int edns_opt_append(struct edns_data* edns, struct regional* region, opt->next = NULL; opt->opt_code = code; opt->opt_len = len; - opt->opt_data = regional_alloc_init(region, data, len); - if(!opt->opt_data) - return 0; + opt->opt_data = NULL; + if(len > 0) { + opt->opt_data = regional_alloc_init(region, data, len); + if(!opt->opt_data) + return 0; + } /* append at end of list */ prevp = &edns->opt_list; @@ -883,13 +923,138 @@ int edns_opt_append(struct edns_data* edns, struct regional* region, return 1; } -int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region) +int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, + uint8_t* data, struct regional* region) +{ + struct edns_option** prevp; + struct edns_option* opt; + + /* allocate new element */ + opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); + if(!opt) + return 0; + opt->next = NULL; + opt->opt_code = code; + opt->opt_len = len; + opt->opt_data = NULL; + if(len > 0) { + opt->opt_data = regional_alloc_init(region, data, len); + if(!opt->opt_data) + return 0; + } + + /* append at end of list */ + prevp = list; + while(*prevp != NULL) { + prevp = &((*prevp)->next); + } + *prevp = opt; + return 1; +} + +int edns_opt_list_remove(struct edns_option** list, uint16_t code) +{ + /* The list should already be allocated in a region. Freeing the + * allocated space in a region is not possible. We just unlink the + * required elements and they will be freed together with the region. */ + + struct edns_option* prev; + struct edns_option* curr; + if(!list || !(*list)) return 0; + + /* Unlink and repoint if the element(s) are first in list */ + while(list && *list && (*list)->opt_code == code) { + *list = (*list)->next; + } + + if(!list || !(*list)) return 1; + /* Unlink elements and reattach the list */ + prev = *list; + curr = (*list)->next; + while(curr != NULL) { + if(curr->opt_code == code) { + prev->next = curr->next; + curr = curr->next; + } else { + prev = curr; + curr = curr->next; + } + } + return 1; +} + +static int inplace_cb_reply_call_generic( + struct inplace_cb_reply* 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 inplace_cb_reply* cb; + struct edns_option* opt_list_out = NULL; + if(qstate) + opt_list_out = qstate->edns_opts_front_out; + for(cb=callback_list; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_reply_generic(cb->cb, type)); + (void)(*cb->cb)(qinfo, qstate, rep, rcode, edns, &opt_list_out, region, + cb->cb_arg); + } + edns->opt_list = opt_list_out; + return 1; +} + +int inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, + struct module_qstate* qstate, struct reply_info* rep, int rcode, + struct edns_data* edns, struct regional* region) { - (void)region; - /* remove all edns options from the reply, because only the - * options that we understand should be in the reply - * (sec 6.1.2 RFC 6891) */ - edns->opt_list = NULL; + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo, + qstate, rep, rcode, edns, 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) +{ + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache, + qinfo, qstate, rep, rcode, edns, 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) +{ + return inplace_cb_reply_call_generic( + env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local, + qinfo, qstate, rep, rcode, edns, 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) +{ + /* 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); +} + +int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, + uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, + struct regional* region) +{ + struct inplace_cb_query* cb = env->inplace_cb_lists[inplace_cb_query]; + for(; cb; cb=cb->next) { + fptr_ok(fptr_whitelist_inplace_cb_query(cb->cb)); + (void)(*cb->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen, + region, cb->cb_arg); + } return 1; } @@ -1000,7 +1165,7 @@ struct edns_option* edns_opt_copy_alloc(struct edns_option* list) return result; } -struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code) +struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code) { struct edns_option* p; for(p=list; p; p=p->next) { diff --git a/usr.sbin/unbound/util/data/msgreply.h b/usr.sbin/unbound/util/data/msgreply.h index b542b75e697..485d49afa87 100644 --- a/usr.sbin/unbound/util/data/msgreply.h +++ b/usr.sbin/unbound/util/data/msgreply.h @@ -49,8 +49,14 @@ struct alloc_cache; struct iovec; struct regional; struct edns_data; +struct edns_option; +struct inplace_cb_reply; +struct inplace_cb_query; +struct module_qstate; +struct module_env; struct msg_parse; struct rrset_parse; +struct local_rrset; /** calculate the prefetch TTL as 90% of original. Calculation * without numerical overflow (uin32_t) */ @@ -73,6 +79,23 @@ struct query_info { uint16_t qtype; /** qclass, host byte order */ uint16_t qclass; + /** + * Alias local answer(s) for the qname. If 'qname' is an alias defined + * in a local zone, this field will be set to the corresponding local + * RRset when the alias is determined. + * In the initial implementation this can only be a single CNAME RR + * (or NULL), but it could possibly be extended to be a DNAME or a + * chain of aliases. + * Users of this structure are responsible to initialize this field + * to be NULL; otherwise other part of query handling code may be + * confused. + * Users also have to be careful about the lifetime of data. On return + * from local zone lookup, it may point to data derived from + * configuration that may be dynamically invalidated or data allocated + * in an ephemeral regional allocator. A deep copy of the data may + * have to be generated if it has to be kept during iterative + * resolution. */ + struct local_rrset* local_alias; }; /** @@ -82,7 +105,7 @@ struct rrset_ref { /** the key with lock, and ptr to packed data. */ struct ub_packed_rrset_key* key; /** id needed */ - rrset_id_t id; + rrset_id_type id; }; /** @@ -307,7 +330,7 @@ void reply_info_delete(void* d, void* arg); /** calculate hash value of query_info, lowercases the qname, * uses CD flag for AAAA qtype */ -hashvalue_t query_info_hash(struct query_info *q, uint16_t flags); +hashvalue_type query_info_hash(struct query_info *q, uint16_t flags); /** * Setup query info entry @@ -317,7 +340,7 @@ hashvalue_t query_info_hash(struct query_info *q, uint16_t flags); * @return: newly allocated message reply cache item. */ struct msgreply_entry* query_info_entrysetup(struct query_info* q, - struct reply_info* r, hashvalue_t h); + struct reply_info* r, hashvalue_type h); /** * Copy reply_info and all rrsets in it and allocate. @@ -425,10 +448,27 @@ struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, * @param qinfo: query section. * @param rep: rest of message. */ -void log_dns_msg(const char* str, struct query_info* qinfo, +void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep); /** + * Print string with neat domain name, type, class, + * status code from, and size of a query response. + * + * @param v: at what verbosity level to print this. + * @param qinf: query section. + * @param addr: address of the client. + * @param addrlen: length of the client address. + * @param dur: how long it took to complete the query. + * @param cached: whether or not the reply is coming from + * the cache, or an outside network. + * @param rmsg: sldns buffer packet. + */ +void log_reply_info(enum verbosity_value v, struct query_info *qinf, + struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, + int cached, struct sldns_buffer *rmsg); + +/** * Print string with neat domain name, type, class from query info. * @param v: at what verbosity level to print this. * @param str: string of message. @@ -439,29 +479,133 @@ void log_query_info(enum verbosity_value v, const char* str, /** * Append edns option to edns data structure + * @param edns: the edns data structure to append the edns option to. + * @param region: region to allocate the new edns option. + * @param code: the edns option's code. + * @param len: the edns option's length. + * @param data: the edns option's data. + * @return false on failure. */ int edns_opt_append(struct edns_data* edns, struct regional* region, uint16_t code, size_t len, uint8_t* data); /** + * Append edns option to edns option list + * @param list: the edns option list to append the edns option to. + * @param code: the edns option's code. + * @param len: the edns option's length. + * @param data: the edns option's data. + * @param region: region to allocate the new edns option. + * @return false on failure. + */ +int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, + uint8_t* data, struct regional* region); + +/** + * Remove any option found on the edns option list that matches the code. + * @param list: the list of edns options. + * @param code: the opt code to remove. + * @return true when at least one edns option was removed, false otherwise. + */ +int edns_opt_list_remove(struct edns_option** list, uint16_t code); + +/** * Find edns option in edns list * @param list: list of edns options (eg. edns.opt_list) * @param code: opt code to find. * @return NULL or the edns_option element. */ -struct edns_option* edns_opt_find(struct edns_option* list, uint16_t code); +struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code); /** - * Transform edns data structure from query structure into reply structure. - * In place transform, for errors and cache replies. - * @param edns: on input contains the edns from the query. On output contains - * the edns for the answer. Add new options to the opt_list to put them - * in the answer (allocated in the region, with edns_opt_append). - * @param region: to allocate stuff in. - * @return false on failure (servfail to client, or for some error encodings, - * no EDNS options in the answer). - */ -int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region); + * Call the registered functions in the inplace_cb_reply linked list. + * This function is going to get called while answering with a resolved query. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. + * @param rep: Reply info. Could be NULL. + * @param rcode: return code. + * @param edns: edns data of the reply. + * @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); + +/** + * Call the registered functions in the inplace_cb_reply_cache linked list. + * This function is going to get called while answering from cache. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. NULL when replying from cache. + * @param rep: Reply info. + * @param rcode: return code. + * @param edns: edns data of the reply. Edns input can be found here. + * @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); + +/** + * Call the registered functions in the inplace_cb_reply_local linked list. + * This function is going to get called while answering with local data. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. NULL when replying from cache. + * @param rep: Reply info. + * @param rcode: return code. + * @param edns: edns data of the reply. Edns input can be found here. + * @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); + +/** + * Call the registered functions in the inplace_cb_reply linked list. + * This function is going to get called while answering with a servfail. + * @param env: module environment. + * @param qinfo: query info. + * @param qstate: module qstate. Contains the edns option lists. Could be NULL. + * @param rep: Reply info. NULL when servfail. + * @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 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); + +/** + * Call the registered functions in the inplace_cb_query linked list. + * This function is going to get called just before sending a query to a + * nameserver. + * @param env: module environment. + * @param qinfo: query info. + * @param flags: flags of the query. + * @param addr: to which server to send the query. + * @param addrlen: length of addr. + * @param zone: name of the zone of the delegation point. wireformat dname. + * This is the delegation point name for which the server is deemed + * authoritative. + * @param zonelen: length of zone. + * @param qstate: module qstate. + * @param region: region to store data. + * @return false on failure (a callback function returned an error). + */ +int inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, + uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, struct module_qstate* qstate, + struct regional* region); /** * Copy edns option list allocated to the new region diff --git a/usr.sbin/unbound/util/data/packed_rrset.c b/usr.sbin/unbound/util/data/packed_rrset.c index 66399085a65..9944087cbf5 100644 --- a/usr.sbin/unbound/util/data/packed_rrset.c +++ b/usr.sbin/unbound/util/data/packed_rrset.c @@ -158,14 +158,14 @@ rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2) return 1; } -hashvalue_t +hashvalue_type rrset_key_hash(struct packed_rrset_key* key) { /* type is hashed in host order */ uint16_t t = ntohs(key->type); /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */ /* this routine does not have a compressed name */ - hashvalue_t h = 0xab; + hashvalue_type h = 0xab; h = dname_query_hash(key->dname, h); h = hashlittle(&t, sizeof(t), h); h = hashlittle(&key->rrset_class, sizeof(uint16_t), h); diff --git a/usr.sbin/unbound/util/data/packed_rrset.h b/usr.sbin/unbound/util/data/packed_rrset.h index ad11a804226..a2f116afba4 100644 --- a/usr.sbin/unbound/util/data/packed_rrset.h +++ b/usr.sbin/unbound/util/data/packed_rrset.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -42,13 +42,12 @@ #ifndef UTIL_DATA_PACKED_RRSET_H #define UTIL_DATA_PACKED_RRSET_H #include "util/storage/lruhash.h" -#include <ldns/rr.h> struct alloc_cache; struct regional; /** type used to uniquely identify rrsets. Cannot be reused without * clearing the cache. */ -typedef uint64_t rrset_id_t; +typedef uint64_t rrset_id_type; /** this rrset is NSEC and is at zone apex (at child side of zonecut) */ #define PACKED_RRSET_NSEC_AT_APEX 0x1 @@ -59,6 +58,12 @@ typedef uint64_t rrset_id_t; * from the SOA in the answer section from a direct SOA query or ANY query. */ #define PACKED_RRSET_SOA_NEG 0x4 +/** number of rrs and rrsets for integer overflow protection. More than + * this is not really possible (64K packet has much less RRs and RRsets) in + * a message. And this is small enough that also multiplied there is no + * integer overflow. */ +#define RR_COUNT_MAX 0xffffff + /** * The identifying information for an RRset. */ @@ -109,7 +114,7 @@ struct ub_packed_rrset_key { * The other values in this struct may only be altered after changing * the id (which needs a writelock on entry.lock). */ - rrset_id_t id; + rrset_id_type id; /** key data: dname, type and class */ struct packed_rrset_key rk; }; @@ -186,11 +191,17 @@ enum sec_status { * RRset data. * * The data is packed, stored contiguously in memory. + * + * It is not always stored contiguously, in that case, an unpacked-packed + * rrset has the arrays separate. A bunch of routines work on that, but + * the packed rrset that is contiguous is for the rrset-cache and the + * cache-response routines in daemon/worker.c. + * * memory layout: * o base struct * o rr_len size_t array * o rr_data uint8_t* array - * o rr_ttl uint32_t array (after size_t and ptrs because those may be + * o rr_ttl time_t array (after size_t and ptrs because those may be * 64bit and this array before those would make them unaligned). * Since the stuff before is 32/64bit, rr_ttl is 32 bit aligned. * o rr_data rdata wireformats @@ -215,7 +226,7 @@ enum sec_status { struct packed_rrset_data { /** TTL (in seconds like time()) of the rrset. * Same for all RRs see rfc2181(5.2). */ - uint32_t ttl; + time_t ttl; /** number of rrs. */ size_t count; /** number of rrsigs, if 0 no rrsigs */ @@ -227,7 +238,7 @@ struct packed_rrset_data { /** length of every rr's rdata, rr_len[i] is size of rr_data[i]. */ size_t* rr_len; /** ttl of every rr. rr_ttl[i] ttl of rr i. */ - uint32_t *rr_ttl; + time_t *rr_ttl; /** * Array of pointers to every rr's rdata. * The rr_data[i] rdata is stored in uncompressed wireformat. @@ -281,7 +292,7 @@ size_t packed_rrset_sizeof(struct packed_rrset_data* data); * @param key: rrset key, with data to examine. * @return ttl value. */ -uint32_t ub_packed_rrset_ttl(struct ub_packed_rrset_key* key); +time_t ub_packed_rrset_ttl(struct ub_packed_rrset_key* key); /** * Calculate memory size of rrset entry. For hash table usage. @@ -329,7 +340,7 @@ void rrset_data_delete(void* data, void* userdata); * @param key: the rrset key with name, type, class, flags. * @return hash value. */ -hashvalue_t rrset_key_hash(struct packed_rrset_key* key); +hashvalue_type rrset_key_hash(struct packed_rrset_key* key); /** * Fixup pointers in fixed data packed_rrset_data blob. @@ -343,7 +354,7 @@ void packed_rrset_ptr_fixup(struct packed_rrset_data* data); * @param data: rrset data structure. Otherwise correctly filled in. * @param add: how many seconds to add, pass time(0) for example. */ -void packed_rrset_ttl_add(struct packed_rrset_data* data, uint32_t add); +void packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add); /** * Utility procedure to extract CNAME target name from its rdata. @@ -382,6 +393,27 @@ const char* sec_status_to_string(enum sec_status s); void log_rrset_key(enum verbosity_value v, const char* str, struct ub_packed_rrset_key* rrset); +/** + * Convert RR from RRset to string. + * @param rrset: structure with data. + * @param i: index of rr or RRSIG. + * @param now: time that is subtracted from ttl before printout. Can be 0. + * @param dest: destination string buffer. Must be nonNULL. + * @param dest_len: length of dest buffer (>0). + * @return false on failure. + */ +int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i, + time_t now, char* dest, size_t dest_len); + +/** + * Print the string with prefix, one rr per line. + * @param v: at what verbosity level to print this. + * @param str: string of message. + * @param rrset: with name, and rdata, and rrsigs. + */ +void log_packed_rrset(enum verbosity_value v, const char* str, + struct ub_packed_rrset_key* rrset); + /** * Allocate rrset in region - no more locks needed * @param key: a (just from rrset cache looked up) rrset key + valid, @@ -392,7 +424,7 @@ void log_rrset_key(enum verbosity_value v, const char* str, */ struct ub_packed_rrset_key* packed_rrset_copy_region( struct ub_packed_rrset_key* key, struct regional* region, - uint32_t now); + time_t now); /** * Allocate rrset with malloc (from region or you are holding the lock). @@ -403,32 +435,6 @@ struct ub_packed_rrset_key* packed_rrset_copy_region( */ struct ub_packed_rrset_key* packed_rrset_copy_alloc( struct ub_packed_rrset_key* key, struct alloc_cache* alloc, - uint32_t now); - -/** - * Create a ub_packed_rrset_key allocated on the heap. - * It therefore does not have the correct ID value, and cannot be used - * inside the cache. It can be used in storage outside of the cache. - * Keys for the cache have to be obtained from alloc.h . - * @param rrset: the ldns rr set. - * @return key allocated or NULL on failure. - */ -struct ub_packed_rrset_key* ub_packed_rrset_heap_key(ldns_rr_list* rrset); - -/** - * Create packed_rrset data on the heap. - * @param rrset: the ldns rr set with the data to copy. - * @return data allocated or NULL on failure. - */ -struct packed_rrset_data* packed_rrset_heap_data(ldns_rr_list* rrset); - -/** - * Convert packed rrset to ldns rr list. - * @param rrset: packed rrset. - * @param buf: scratch buffer. - * @return rr list or NULL on failure. - */ -ldns_rr_list* packed_rrset_to_rr_list(struct ub_packed_rrset_key* rrset, - ldns_buffer* buf); + time_t now); #endif /* UTIL_DATA_PACKED_RRSET_H */ diff --git a/usr.sbin/unbound/util/fptr_wlist.c b/usr.sbin/unbound/util/fptr_wlist.c index 80a23f20361..8bd7b973c2f 100644 --- a/usr.sbin/unbound/util/fptr_wlist.c +++ b/usr.sbin/unbound/util/fptr_wlist.c @@ -51,6 +51,7 @@ #include "services/localzone.h" #include "services/cache/infra.h" #include "services/cache/rrset.h" +#include "services/view.h" #include "dns64/dns64.h" #include "iterator/iterator.h" #include "iterator/iter_fwd.h" @@ -83,7 +84,7 @@ #endif int -fptr_whitelist_comm_point(comm_point_callback_t *fptr) +fptr_whitelist_comm_point(comm_point_callback_type *fptr) { if(fptr == &worker_handle_request) return 1; else if(fptr == &outnet_udp_cb) return 1; @@ -93,7 +94,7 @@ fptr_whitelist_comm_point(comm_point_callback_t *fptr) } int -fptr_whitelist_comm_point_raw(comm_point_callback_t *fptr) +fptr_whitelist_comm_point_raw(comm_point_callback_type *fptr) { if(fptr == &tube_handle_listen) return 1; else if(fptr == &tube_handle_write) return 1; @@ -155,7 +156,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *)) } int -fptr_whitelist_pending_udp(comm_point_callback_t *fptr) +fptr_whitelist_pending_udp(comm_point_callback_type *fptr) { if(fptr == &serviced_udp_callback) return 1; else if(fptr == &worker_handle_reply) return 1; @@ -164,7 +165,7 @@ fptr_whitelist_pending_udp(comm_point_callback_t *fptr) } int -fptr_whitelist_pending_tcp(comm_point_callback_t *fptr) +fptr_whitelist_pending_tcp(comm_point_callback_type *fptr) { if(fptr == &serviced_tcp_callback) return 1; else if(fptr == &worker_handle_reply) return 1; @@ -173,7 +174,7 @@ fptr_whitelist_pending_tcp(comm_point_callback_t *fptr) } int -fptr_whitelist_serviced_query(comm_point_callback_t *fptr) +fptr_whitelist_serviced_query(comm_point_callback_type *fptr) { if(fptr == &worker_handle_service_reply) return 1; else if(fptr == &libworker_handle_service_reply) return 1; @@ -203,47 +204,51 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)) else if(fptr == &val_neg_zone_compare) return 1; else if(fptr == &probetree_cmp) return 1; else if(fptr == &replay_var_compare) return 1; + else if(fptr == &view_cmp) return 1; return 0; } int -fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr) +fptr_whitelist_hash_sizefunc(lruhash_sizefunc_type fptr) { if(fptr == &msgreply_sizefunc) return 1; else if(fptr == &ub_rrset_sizefunc) return 1; else if(fptr == &infra_sizefunc) return 1; else if(fptr == &key_entry_sizefunc) return 1; else if(fptr == &rate_sizefunc) return 1; + else if(fptr == &ip_rate_sizefunc) return 1; else if(fptr == &test_slabhash_sizefunc) return 1; return 0; } int -fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr) +fptr_whitelist_hash_compfunc(lruhash_compfunc_type fptr) { if(fptr == &query_info_compare) return 1; else if(fptr == &ub_rrset_compare) return 1; else if(fptr == &infra_compfunc) return 1; else if(fptr == &key_entry_compfunc) return 1; else if(fptr == &rate_compfunc) return 1; + else if(fptr == &ip_rate_compfunc) return 1; else if(fptr == &test_slabhash_compfunc) return 1; return 0; } int -fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr) +fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_type fptr) { if(fptr == &query_entry_delete) return 1; else if(fptr == &ub_rrset_key_delete) return 1; else if(fptr == &infra_delkeyfunc) return 1; else if(fptr == &key_entry_delkeyfunc) return 1; else if(fptr == &rate_delkeyfunc) return 1; + else if(fptr == &ip_rate_delkeyfunc) return 1; else if(fptr == &test_slabhash_delkey) return 1; return 0; } int -fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr) +fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_type fptr) { if(fptr == &reply_info_delete) return 1; else if(fptr == &rrset_data_delete) return 1; @@ -255,7 +260,7 @@ fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr) } int -fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr) +fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr) { if(fptr == NULL) return 1; else if(fptr == &rrset_markdel) return 1; @@ -265,11 +270,9 @@ fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr) /** whitelist env->send_query callbacks */ int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)( - uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, - uint16_t flags, int dnssec, int want_dnssec, int nocaps, - struct edns_option* opt_list, struct sockaddr_storage* addr, - socklen_t addrlen, uint8_t* zone, size_t zonelen, - struct module_qstate* q)) + struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, + int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, int ssl_upstream, struct module_qstate* q)) { if(fptr == &worker_send_query) return 1; else if(fptr == &libworker_send_query) return 1; @@ -409,14 +412,14 @@ fptr_whitelist_alloc_cleanup(void (*fptr)(void*)) return 0; } -int fptr_whitelist_tube_listen(tube_callback_t* fptr) +int fptr_whitelist_tube_listen(tube_callback_type* fptr) { if(fptr == &worker_handle_control_cmd) return 1; else if(fptr == &libworker_handle_control_cmd) return 1; return 0; } -int fptr_whitelist_mesh_cb(mesh_cb_func_t fptr) +int fptr_whitelist_mesh_cb(mesh_cb_func_type fptr) { if(fptr == &libworker_fg_done_cb) return 1; else if(fptr == &libworker_bg_done_cb) return 1; @@ -432,3 +435,34 @@ int fptr_whitelist_print_func(void (*fptr)(char*,void*)) else if(fptr == &remote_get_opt_ssl) return 1; return 0; } + +int fptr_whitelist_inplace_cb_reply_generic(inplace_cb_reply_func_type* fptr, + enum inplace_cb_list_type type) +{ +#ifndef WITH_PYTHONMODULE + (void)fptr; +#endif + if(type == inplace_cb_reply) { +#ifdef WITH_PYTHONMODULE + if(fptr == &python_inplace_cb_reply_generic) return 1; +#endif + } else if(type == inplace_cb_reply_cache) { +#ifdef WITH_PYTHONMODULE + if(fptr == &python_inplace_cb_reply_generic) return 1; +#endif + } else if(type == inplace_cb_reply_local) { +#ifdef WITH_PYTHONMODULE + if(fptr == &python_inplace_cb_reply_generic) return 1; +#endif + } else if(type == inplace_cb_reply_servfail) { +#ifdef WITH_PYTHONMODULE + if(fptr == &python_inplace_cb_reply_generic) return 1; +#endif + } + return 0; +} + +int fptr_whitelist_inplace_cb_query(inplace_cb_query_func_type* ATTR_UNUSED(fptr)) +{ + return 0; +} diff --git a/usr.sbin/unbound/util/fptr_wlist.h b/usr.sbin/unbound/util/fptr_wlist.h index 98ca21bb967..5ab69f88758 100644 --- a/usr.sbin/unbound/util/fptr_wlist.h +++ b/usr.sbin/unbound/util/fptr_wlist.h @@ -80,7 +80,7 @@ * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_comm_point(comm_point_callback_t *fptr); +int fptr_whitelist_comm_point(comm_point_callback_type *fptr); /** * Check function pointer whitelist for raw comm_point callback values. @@ -88,7 +88,7 @@ int fptr_whitelist_comm_point(comm_point_callback_t *fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_comm_point_raw(comm_point_callback_t *fptr); +int fptr_whitelist_comm_point_raw(comm_point_callback_type *fptr); /** * Check function pointer whitelist for comm_timer callback values. @@ -137,7 +137,7 @@ int fptr_whitelist_event(void (*fptr)(int, short, void *)); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_pending_udp(comm_point_callback_t *fptr); +int fptr_whitelist_pending_udp(comm_point_callback_type *fptr); /** * Check function pointer whitelist for pending tcp callback values. @@ -145,7 +145,7 @@ int fptr_whitelist_pending_udp(comm_point_callback_t *fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_pending_tcp(comm_point_callback_t *fptr); +int fptr_whitelist_pending_tcp(comm_point_callback_type *fptr); /** * Check function pointer whitelist for serviced query callback values. @@ -153,7 +153,7 @@ int fptr_whitelist_pending_tcp(comm_point_callback_t *fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_serviced_query(comm_point_callback_t *fptr); +int fptr_whitelist_serviced_query(comm_point_callback_type *fptr); /** * Check function pointer whitelist for rbtree cmp callback values. @@ -169,7 +169,7 @@ int fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr); +int fptr_whitelist_hash_sizefunc(lruhash_sizefunc_type fptr); /** * Check function pointer whitelist for lruhash compfunc callback values. @@ -177,7 +177,7 @@ int fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr); +int fptr_whitelist_hash_compfunc(lruhash_compfunc_type fptr); /** * Check function pointer whitelist for lruhash delkeyfunc callback values. @@ -185,7 +185,7 @@ int fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr); +int fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_type fptr); /** * Check function pointer whitelist for lruhash deldata callback values. @@ -193,7 +193,7 @@ int fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr); +int fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_type fptr); /** * Check function pointer whitelist for lruhash markdel callback values. @@ -201,7 +201,7 @@ int fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr); +int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_type fptr); /** * Check function pointer whitelist for module_env send_query callback values. @@ -210,11 +210,9 @@ int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr); * @return false if not in whitelist. */ int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)( - uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, - uint16_t flags, int dnssec, int want_dnssec, int nocaps, - struct edns_option*, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, - struct module_qstate* q)); + struct query_info* qinfo, uint16_t flags, int dnssec, int want_dnssec, + int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, + uint8_t* zone, size_t zonelen, int ssl_upstream, struct module_qstate* q)); /** * Check function pointer whitelist for module_env detach_subs callback values. @@ -318,7 +316,7 @@ int fptr_whitelist_alloc_cleanup(void (*fptr)(void*)); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_tube_listen(tube_callback_t* fptr); +int fptr_whitelist_tube_listen(tube_callback_type* fptr); /** * Check function pointer whitelist for mesh state callback values. @@ -326,7 +324,7 @@ int fptr_whitelist_tube_listen(tube_callback_t* fptr); * @param fptr: function pointer to check. * @return false if not in whitelist. */ -int fptr_whitelist_mesh_cb(mesh_cb_func_t fptr); +int fptr_whitelist_mesh_cb(mesh_cb_func_type fptr); /** * Check function pointer whitelist for config_get_option func values. @@ -335,6 +333,24 @@ int fptr_whitelist_mesh_cb(mesh_cb_func_t fptr); */ int fptr_whitelist_print_func(void (*fptr)(char*,void*)); +/** + * Check function pointer whitelist for inplace_cb_reply, + * inplace_cb_reply_cache, inplace_cb_reply_local and inplace_cb_reply_servfail + * func values. + * @param fptr: function pointer to check. + * @param type: the type of the callback function. + * @return false if not in whitelist. + */ +int fptr_whitelist_inplace_cb_reply_generic(inplace_cb_reply_func_type* fptr, + enum inplace_cb_list_type type); + +/** + * Check function pointer whitelist for inplace_cb_query func values. + * @param fptr: function pointer to check. + * @return false if not in whitelist. + */ +int fptr_whitelist_inplace_cb_query(inplace_cb_query_func_type* fptr); + /** Due to module breakage by fptr wlist, these test app declarations * are presented here */ /** diff --git a/usr.sbin/unbound/util/iana_ports.inc b/usr.sbin/unbound/util/iana_ports.inc index 3856488ba34..5709a4976c1 100644 --- a/usr.sbin/unbound/util/iana_ports.inc +++ b/usr.sbin/unbound/util/iana_ports.inc @@ -1186,6 +1186,7 @@ 1525, 1526, 1527, +1528, 1529, 1530, 1531, @@ -3945,6 +3946,7 @@ 4700, 4701, 4702, +4711, 4725, 4726, 4727, @@ -3961,12 +3963,15 @@ 4743, 4744, 4745, +4746, 4747, 4749, 4750, 4751, 4752, 4753, +4754, +4755, 4784, 4785, 4789, @@ -4497,6 +4502,7 @@ 6626, 6627, 6628, +6629, 6633, 6634, 6635, @@ -4526,7 +4532,6 @@ 6786, 6787, 6788, -6789, 6790, 6791, 6801, @@ -4845,6 +4850,7 @@ 8793, 8800, 8804, +8808, 8873, 8880, 8883, @@ -4882,6 +4888,7 @@ 9024, 9025, 9026, +9060, 9080, 9084, 9085, @@ -5208,6 +5215,7 @@ 18463, 18634, 18635, +18668, 18769, 18881, 18888, @@ -5215,6 +5223,7 @@ 19007, 19191, 19194, +19220, 19283, 19315, 19398, @@ -5345,6 +5354,7 @@ 30260, 30832, 30999, +31016, 31029, 31416, 31457, @@ -5378,12 +5388,14 @@ 34249, 34378, 34379, +34567, 34962, 34963, 34964, 34980, 35001, 35004, +35100, 35355, 36001, 36411, @@ -5425,6 +5437,7 @@ 44900, 45000, 45054, +45514, 45678, 45825, 45966, diff --git a/usr.sbin/unbound/util/locks.c b/usr.sbin/unbound/util/locks.c index adfb6c062fc..b65a02bdc8d 100644 --- a/usr.sbin/unbound/util/locks.c +++ b/usr.sbin/unbound/util/locks.c @@ -110,15 +110,15 @@ void ub_thread_sig_unblock(int sig) * @param arg: user argument to func. */ void -ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg) +ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg) { pid_t pid = fork(); switch(pid) { default: /* main */ - *thr = (ub_thread_t)pid; + *thr = (ub_thread_type)pid; return; case 0: /* child */ - *thr = (ub_thread_t)getpid(); + *thr = (ub_thread_type)getpid(); (void)(*func)(arg); exit(0); case -1: /* error */ @@ -128,10 +128,10 @@ ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg) /** * There is no threading. Wait for a process to terminate. - * Note that ub_thread_t is defined as pid_t. + * Note that ub_thread_type is defined as pid_t. * @param thread: the process id to wait for. */ -void ub_thr_fork_wait(ub_thread_t thread) +void ub_thr_fork_wait(ub_thread_type thread) { int status = 0; if(waitpid((pid_t)thread, &status, 0) == -1) @@ -143,7 +143,7 @@ void ub_thr_fork_wait(ub_thread_t thread) #endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */ #ifdef HAVE_SOLARIS_THREADS -void* ub_thread_key_get(ub_thread_key_t key) +void* ub_thread_key_get(ub_thread_key_type key) { void* ret=NULL; LOCKRET(thr_getspecific(key, &ret)); @@ -167,19 +167,19 @@ static void log_win_err(const char* str, DWORD err) LocalFree(buf); } -void lock_basic_init(lock_basic_t* lock) +void lock_basic_init(lock_basic_type* lock) { /* implement own lock, because windows HANDLE as Mutex usage * uses too many handles and would bog down the whole system. */ (void)InterlockedExchange(lock, 0); } -void lock_basic_destroy(lock_basic_t* lock) +void lock_basic_destroy(lock_basic_type* lock) { (void)InterlockedExchange(lock, 0); } -void lock_basic_lock(lock_basic_t* lock) +void lock_basic_lock(lock_basic_type* lock) { LONG wait = 1; /* wait 1 msec at first */ @@ -191,13 +191,13 @@ void lock_basic_lock(lock_basic_t* lock) /* the old value was 0, but we inserted 1, we locked it! */ } -void lock_basic_unlock(lock_basic_t* lock) +void lock_basic_unlock(lock_basic_type* lock) { /* unlock it by inserting the value of 0. xchg for cache coherency. */ (void)InterlockedExchange(lock, 0); } -void ub_thread_key_create(ub_thread_key_t* key, void* f) +void ub_thread_key_create(ub_thread_key_type* key, void* f) { *key = TlsAlloc(); if(*key == TLS_OUT_OF_INDEXES) { @@ -207,14 +207,14 @@ void ub_thread_key_create(ub_thread_key_t* key, void* f) else ub_thread_key_set(*key, f); } -void ub_thread_key_set(ub_thread_key_t key, void* v) +void ub_thread_key_set(ub_thread_key_type key, void* v) { if(!TlsSetValue(key, v)) { log_win_err("TlsSetValue failed", GetLastError()); } } -void* ub_thread_key_get(ub_thread_key_t key) +void* ub_thread_key_get(ub_thread_key_type key) { void* ret = (void*)TlsGetValue(key); if(ret == NULL && GetLastError() != ERROR_SUCCESS) { @@ -223,7 +223,7 @@ void* ub_thread_key_get(ub_thread_key_t key) return ret; } -void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg) +void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg) { #ifndef HAVE__BEGINTHREADEX *thr = CreateThread(NULL, /* default security (no inherit handle) */ @@ -233,7 +233,7 @@ void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg) NULL); /* do not store thread identifier anywhere */ #else /* the beginthreadex routine setups for the C lib; aligns stack */ - *thr=(ub_thread_t)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL); + *thr=(ub_thread_type)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL); #endif if(*thr == NULL) { log_win_err("CreateThread failed", GetLastError()); @@ -241,12 +241,12 @@ void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg) } } -ub_thread_t ub_thread_self(void) +ub_thread_type ub_thread_self(void) { return GetCurrentThread(); } -void ub_thread_join(ub_thread_t thr) +void ub_thread_join(ub_thread_type thr) { DWORD ret = WaitForSingleObject(thr, INFINITE); if(ret == WAIT_FAILED) { diff --git a/usr.sbin/unbound/util/locks.h b/usr.sbin/unbound/util/locks.h index 91be5c3e26f..d86ee4923f7 100644 --- a/usr.sbin/unbound/util/locks.h +++ b/usr.sbin/unbound/util/locks.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef UTIL_LOCKS_H @@ -55,8 +55,10 @@ * Also thread creation and deletion functions are defined here. */ +/* if you define your own LOCKRET before including locks.h, you can get most + * locking functions without the dependency on log_err. */ +#ifndef LOCKRET #include "util/log.h" - /** * The following macro is used to check the return value of the * pthread calls. They return 0 on success and an errno on error. @@ -68,6 +70,7 @@ log_err("%s at %d could not " #func ": %s", \ __FILE__, __LINE__, strerror(lockret_err)); \ } while(0) +#endif /** DEBUG: use thread debug whenever possible */ #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS) @@ -92,7 +95,7 @@ /******************* PTHREAD ************************/ /** use pthread mutex for basic lock */ -typedef pthread_mutex_t lock_basic_t; +typedef pthread_mutex_t lock_basic_type; /** small front for pthread init func, NULL is default attrs. */ #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) @@ -101,7 +104,7 @@ typedef pthread_mutex_t lock_basic_t; #ifndef HAVE_PTHREAD_RWLOCK_T /** in case rwlocks are not supported, use a mutex. */ -typedef pthread_mutex_t lock_rw_t; +typedef pthread_mutex_t lock_rw_type; #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock)) @@ -109,7 +112,7 @@ typedef pthread_mutex_t lock_rw_t; #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) #else /* HAVE_PTHREAD_RWLOCK_T */ /** we use the pthread rwlock */ -typedef pthread_rwlock_t lock_rw_t; +typedef pthread_rwlock_t lock_rw_type; /** small front for pthread init func, NULL is default attrs. */ #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL)) #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock)) @@ -120,7 +123,7 @@ typedef pthread_rwlock_t lock_rw_t; #ifndef HAVE_PTHREAD_SPINLOCK_T /** in case spinlocks are not supported, use a mutex. */ -typedef pthread_mutex_t lock_quick_t; +typedef pthread_mutex_t lock_quick_type; /** small front for pthread init func, NULL is default attrs. */ #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) @@ -129,7 +132,7 @@ typedef pthread_mutex_t lock_quick_t; #else /* HAVE_PTHREAD_SPINLOCK_T */ /** use pthread spinlock for the quick lock */ -typedef pthread_spinlock_t lock_quick_t; +typedef pthread_spinlock_t lock_quick_type; /** * allocate process private since this is available whether * Thread Process-Shared Synchronization is supported or not. @@ -145,14 +148,31 @@ typedef pthread_spinlock_t lock_quick_t; #endif /* HAVE SPINLOCK */ /** Thread creation */ -typedef pthread_t ub_thread_t; -/** Pass where to store tread_t in thr. Use default NULL attributes. */ -#define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg)) +typedef pthread_t ub_thread_type; +/** On alpine linux default thread stack size is 80 Kb. See +http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size +This is not enough and cause segfault. Other linux distros have 2 Mb at least. +Wrapper for set up thread stack size */ +#define PTHREADSTACKSIZE 2*1024*1024 +#define PTHREADCREATE(thr, stackrequired, func, arg) do {\ + pthread_attr_t attr; \ + size_t stacksize; \ + LOCKRET(pthread_attr_init(&attr)); \ + LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ + if (stacksize < stackrequired) { \ + LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \ + LOCKRET(pthread_create(thr, &attr, func, arg)); \ + LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ + verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \ + } else {LOCKRET(pthread_create(thr, NULL, func, arg));} \ + } while(0) +/** Use wrapper for set thread stack size on attributes. */ +#define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg) /** get self id. */ #define ub_thread_self() pthread_self() /** wait for another thread to terminate */ #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL)) -typedef pthread_key_t ub_thread_key_t; +typedef pthread_key_t ub_thread_key_type; #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f)) #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) #define ub_thread_key_get(key) pthread_getspecific(key) @@ -164,7 +184,7 @@ typedef pthread_key_t ub_thread_key_t; #include <synch.h> #include <thread.h> -typedef rwlock_t lock_rw_t; +typedef rwlock_t lock_rw_type; #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL)) #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock)) #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock)) @@ -172,28 +192,28 @@ typedef rwlock_t lock_rw_t; #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock)) /** use basic mutex */ -typedef mutex_t lock_basic_t; +typedef mutex_t lock_basic_type; #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock)) #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock)) #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock)) /** No spinlocks in solaris threads API. Use a mutex. */ -typedef mutex_t lock_quick_t; +typedef mutex_t lock_quick_type; #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock)) #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock)) #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock)) /** Thread creation, create a default thread. */ -typedef thread_t ub_thread_t; +typedef thread_t ub_thread_type; #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr)) #define ub_thread_self() thr_self() #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL)) -typedef thread_key_t ub_thread_key_t; +typedef thread_key_t ub_thread_key_type; #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) -void* ub_thread_key_get(ub_thread_key_t key); +void* ub_thread_key_get(ub_thread_key_type key); #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ @@ -202,7 +222,7 @@ void* ub_thread_key_get(ub_thread_key_t key); #include <windows.h> /* Use a mutex */ -typedef LONG lock_rw_t; +typedef LONG lock_rw_type; #define lock_rw_init(lock) lock_basic_init(lock) #define lock_rw_destroy(lock) lock_basic_destroy(lock) #define lock_rw_rdlock(lock) lock_basic_lock(lock) @@ -210,35 +230,35 @@ typedef LONG lock_rw_t; #define lock_rw_unlock(lock) lock_basic_unlock(lock) /** the basic lock is a mutex, implemented opaquely, for error handling. */ -typedef LONG lock_basic_t; -void lock_basic_init(lock_basic_t* lock); -void lock_basic_destroy(lock_basic_t* lock); -void lock_basic_lock(lock_basic_t* lock); -void lock_basic_unlock(lock_basic_t* lock); +typedef LONG lock_basic_type; +void lock_basic_init(lock_basic_type* lock); +void lock_basic_destroy(lock_basic_type* lock); +void lock_basic_lock(lock_basic_type* lock); +void lock_basic_unlock(lock_basic_type* lock); /** on windows no spinlock, use mutex too. */ -typedef LONG lock_quick_t; +typedef LONG lock_quick_type; #define lock_quick_init(lock) lock_basic_init(lock) #define lock_quick_destroy(lock) lock_basic_destroy(lock) #define lock_quick_lock(lock) lock_basic_lock(lock) #define lock_quick_unlock(lock) lock_basic_unlock(lock) /** Thread creation, create a default thread. */ -typedef HANDLE ub_thread_t; -void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg); -ub_thread_t ub_thread_self(void); -void ub_thread_join(ub_thread_t thr); -typedef DWORD ub_thread_key_t; -void ub_thread_key_create(ub_thread_key_t* key, void* f); -void ub_thread_key_set(ub_thread_key_t key, void* v); -void* ub_thread_key_get(ub_thread_key_t key); +typedef HANDLE ub_thread_type; +void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg); +ub_thread_type ub_thread_self(void); +void ub_thread_join(ub_thread_type thr); +typedef DWORD ub_thread_key_type; +void ub_thread_key_create(ub_thread_key_type* key, void* f); +void ub_thread_key_set(ub_thread_key_type key, void* v); +void* ub_thread_key_get(ub_thread_key_type key); #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ /******************* NO THREADS ************************/ #define THREADS_DISABLED 1 /** In case there is no thread support, define locks to do nothing */ -typedef int lock_rw_t; +typedef int lock_rw_type; #define lock_rw_init(lock) /* nop */ #define lock_rw_destroy(lock) /* nop */ #define lock_rw_rdlock(lock) /* nop */ @@ -246,30 +266,30 @@ typedef int lock_rw_t; #define lock_rw_unlock(lock) /* nop */ /** define locks to do nothing */ -typedef int lock_basic_t; +typedef int lock_basic_type; #define lock_basic_init(lock) /* nop */ #define lock_basic_destroy(lock) /* nop */ #define lock_basic_lock(lock) /* nop */ #define lock_basic_unlock(lock) /* nop */ /** define locks to do nothing */ -typedef int lock_quick_t; +typedef int lock_quick_type; #define lock_quick_init(lock) /* nop */ #define lock_quick_destroy(lock) /* nop */ #define lock_quick_lock(lock) /* nop */ #define lock_quick_unlock(lock) /* nop */ /** Thread creation, threads do not exist */ -typedef pid_t ub_thread_t; +typedef pid_t ub_thread_type; /** ub_thread_create is simulated with fork (extremely heavy threads, * with no shared memory). */ #define ub_thread_create(thr, func, arg) \ ub_thr_fork_create(thr, func, arg) #define ub_thread_self() getpid() #define ub_thread_join(thread) ub_thr_fork_wait(thread) -void ub_thr_fork_wait(ub_thread_t thread); -void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg); -typedef void* ub_thread_key_t; +void ub_thr_fork_wait(ub_thread_type thread); +void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg); +typedef void* ub_thread_key_type; #define ub_thread_key_create(key, f) (*(key)) = NULL #define ub_thread_key_set(key, v) (key) = (v) #define ub_thread_key_get(key) (key) diff --git a/usr.sbin/unbound/util/log.c b/usr.sbin/unbound/util/log.c index fc07dc6a9cb..439541a7ce4 100644 --- a/usr.sbin/unbound/util/log.c +++ b/usr.sbin/unbound/util/log.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * \file @@ -40,6 +40,8 @@ #include "config.h" #include "util/log.h" #include "util/locks.h" +#include "sldns/sbuffer.h" +#include <stdarg.h> #ifdef HAVE_TIME_H #include <time.h> #endif @@ -65,7 +67,11 @@ static FILE* logfile = 0; /** if key has been created */ static int key_created = 0; /** pthread key for thread ids in logfile */ -static ub_thread_key_t logkey; +static ub_thread_key_type logkey; +#ifndef THREADS_DISABLED +/** pthread mutex to protect FILE* */ +static lock_quick_type log_lock; +#endif /** the identity of this executable/process */ static const char* ident="unbound"; #if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS) @@ -73,7 +79,7 @@ static const char* ident="unbound"; static int logging_to_syslog = 0; #endif /* HAVE_SYSLOG_H */ /** time to print in log, if NULL, use time(2) */ -static uint32_t* log_now = NULL; +static time_t* log_now = NULL; /** print time in UTC or in secondsfrom1970 */ static int log_time_asc = 0; @@ -84,14 +90,19 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) if(!key_created) { key_created = 1; ub_thread_key_create(&logkey, NULL); + lock_quick_init(&log_lock); } + lock_quick_lock(&log_lock); if(logfile #if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS) || logging_to_syslog #endif - ) - verbose(VERB_QUERY, "switching log to %s", - use_syslog?"syslog":(filename&&filename[0]?filename:"stderr")); + ) { + lock_quick_unlock(&log_lock); /* verbose() needs the lock */ + verbose(VERB_QUERY, "switching log to %s", + use_syslog?"syslog":(filename&&filename[0]?filename:"stderr")); + lock_quick_lock(&log_lock); + } if(logfile && logfile != stderr) fclose(logfile); #ifdef HAVE_SYSLOG_H @@ -104,6 +115,7 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) * chroot and no longer be able to access dev/log and so on */ openlog(ident, LOG_NDELAY, LOG_DAEMON); logging_to_syslog = 1; + lock_quick_unlock(&log_lock); return; } #elif defined(UB_ON_WINDOWS) @@ -112,11 +124,13 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) } if(use_syslog) { logging_to_syslog = 1; + lock_quick_unlock(&log_lock); return; } #endif /* HAVE_SYSLOG_H */ if(!filename || !filename[0]) { logfile = stderr; + lock_quick_unlock(&log_lock); return; } /* open the file for logging */ @@ -125,6 +139,7 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) filename += strlen(chrootdir); f = fopen(filename, "a"); if(!f) { + lock_quick_unlock(&log_lock); log_err("Could not open logfile %s: %s", filename, strerror(errno)); return; @@ -134,11 +149,14 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) setvbuf(f, NULL, (int)_IOLBF, 0); #endif logfile = f; + lock_quick_unlock(&log_lock); } void log_file(FILE *f) { + lock_quick_lock(&log_lock); logfile = f; + lock_quick_unlock(&log_lock); } void log_thread_set(int* num) @@ -146,12 +164,20 @@ void log_thread_set(int* num) ub_thread_key_set(logkey, num); } +int log_thread_get(void) +{ + unsigned int* tid; + if(!key_created) return 0; + tid = (unsigned int*)ub_thread_key_get(logkey); + return (int)(tid?*tid:0); +} + void log_ident_set(const char* id) { ident = id; } -void log_set_time(uint32_t* t) +void log_set_time(time_t* t) { log_now = t; } @@ -171,6 +197,8 @@ log_vmsg(int pri, const char* type, #if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R) char tmbuf[32]; struct tm tm; +#elif defined(UB_ON_WINDOWS) + char tmbuf[128], dtbuf[128]; #endif (void)pri; vsnprintf(message, sizeof(message), format, args); @@ -207,7 +235,11 @@ log_vmsg(int pri, const char* type, return; } #endif /* HAVE_SYSLOG_H */ - if(!logfile) return; + lock_quick_lock(&log_lock); + if(!logfile) { + lock_quick_unlock(&log_lock); + return; + } if(log_now) now = (time_t)*log_now; else now = (time_t)time(NULL); @@ -218,13 +250,21 @@ log_vmsg(int pri, const char* type, fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf, ident, (int)getpid(), tid?*tid:0, type, message); } else +#elif defined(UB_ON_WINDOWS) + if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, + tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0, + NULL, NULL, dtbuf, sizeof(dtbuf))) { + fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf, + ident, (int)getpid(), tid?*tid:0, type, message); + } else #endif - fprintf(logfile, "[%u] %s[%d:%x] %s: %s\n", (unsigned)now, + fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now, ident, (int)getpid(), tid?*tid:0, type, message); #ifdef UB_ON_WINDOWS /* line buffering does not work on windows */ fflush(logfile); #endif + lock_quick_unlock(&log_lock); } /** @@ -336,11 +376,11 @@ log_hex(const char* msg, void* data, size_t length) log_hex_f(verbosity, msg, data, length); } -void log_buf(enum verbosity_value level, const char* msg, ldns_buffer* buf) +void log_buf(enum verbosity_value level, const char* msg, sldns_buffer* buf) { if(verbosity < level) return; - log_hex_f(level, msg, ldns_buffer_begin(buf), ldns_buffer_limit(buf)); + log_hex_f(level, msg, sldns_buffer_begin(buf), sldns_buffer_limit(buf)); } #ifdef USE_WINSOCK diff --git a/usr.sbin/unbound/util/mini_event.c b/usr.sbin/unbound/util/mini_event.c index 98d15f677b0..14e9efe4790 100644 --- a/usr.sbin/unbound/util/mini_event.c +++ b/usr.sbin/unbound/util/mini_event.c @@ -147,7 +147,7 @@ static void handle_timeouts(struct event_base* base, struct timeval* now, wait->tv_sec = (time_t)-1; #endif - while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) + while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || diff --git a/usr.sbin/unbound/util/mini_event.h b/usr.sbin/unbound/util/mini_event.h index 248468ada84..204894d97af 100644 --- a/usr.sbin/unbound/util/mini_event.h +++ b/usr.sbin/unbound/util/mini_event.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -58,6 +58,21 @@ #define HAVE_EVENT_BASE_FREE #endif +/* redefine to use our own namespace so that on platforms where + * linkers crosslink library-private symbols with other symbols, it works */ +#define event_init minievent_init +#define event_get_version minievent_get_version +#define event_get_method minievent_get_method +#define event_base_dispatch minievent_base_dispatch +#define event_base_loopexit minievent_base_loopexit +#define event_base_free minievent_base_free +#define event_set minievent_set +#define event_base_set minievent_base_set +#define event_add minievent_add +#define event_del minievent_del +#define signal_add minisignal_add +#define signal_del minisignal_del + /** event timeout */ #define EV_TIMEOUT 0x01 /** event fd readable */ @@ -81,7 +96,7 @@ struct event_base { /** sorted by timeout (absolute), ptr */ - rbtree_t* times; + rbtree_type* times; /** array of 0 - maxfd of ptr to event for it */ struct event** fds; /** max fd in use */ @@ -103,7 +118,7 @@ struct event_base /** if we need to exit */ int need_to_exit; /** where to store time in seconds */ - uint32_t* time_secs; + time_t* time_secs; /** where to store time in microseconds */ struct timeval* time_tv; }; @@ -113,7 +128,7 @@ struct event_base */ struct event { /** node in timeout rbtree */ - rbnode_t node; + rbnode_type node; /** is event already added */ int added; @@ -134,7 +149,7 @@ struct event { /* function prototypes (some are as they appear in event.h) */ /** create event base */ -void *event_init(uint32_t* time_secs, struct timeval* time_tv); +void *event_init(time_t* time_secs, struct timeval* time_tv); /** get version */ const char *event_get_version(void); /** get polling method, select */ diff --git a/usr.sbin/unbound/util/module.c b/usr.sbin/unbound/util/module.c index 09e276c3015..91983b18274 100644 --- a/usr.sbin/unbound/util/module.c +++ b/usr.sbin/unbound/util/module.c @@ -39,6 +39,7 @@ #include "config.h" #include "util/module.h" +#include "sldns/wire2str.h" const char* strextstate(enum module_ext_state s) @@ -69,3 +70,256 @@ strmodulevent(enum module_ev e) } return "bad_event_value"; } + +int +edns_known_options_init(struct module_env* env) +{ + env->edns_known_options_num = 0; + env->edns_known_options = (struct edns_known_option*)calloc( + MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option)); + if(!env->edns_known_options) return 0; + return 1; +} + +void +edns_known_options_delete(struct module_env* env) +{ + free(env->edns_known_options); + env->edns_known_options = NULL; + env->edns_known_options_num = 0; +} + +int +edns_register_option(uint16_t opt_code, int bypass_cache_stage, + int no_aggregation, struct module_env* env) +{ + size_t i; + if(env->worker) { + log_err("invalid edns registration: " + "trying to register option after module init phase"); + return 0; + } + + /** + * Checking if we are full first is faster but it does not provide + * the option to change the flags when the array is full. + * It only impacts unbound initialization, leave it for now. + */ + /* Check if the option is already registered. */ + for(i=0; i<env->edns_known_options_num; i++) + if(env->edns_known_options[i].opt_code == opt_code) + break; + /* If it is not yet registered check if we have space to add a new one. */ + if(i == env->edns_known_options_num) { + if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) { + log_err("invalid edns registration: maximum options reached"); + return 0; + } + env->edns_known_options_num++; + } + env->edns_known_options[i].opt_code = opt_code; + env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage; + env->edns_known_options[i].no_aggregation = no_aggregation; + return 1; +} + +static int +inplace_cb_reply_register_generic(inplace_cb_reply_func_type* cb, + enum inplace_cb_list_type type, void* cb_arg, struct module_env* env) +{ + struct inplace_cb_reply* callback; + struct inplace_cb_reply** prevp; + if(env->worker) { + log_err("invalid edns callback registration: " + "trying to register callback after module init phase"); + return 0; + } + + callback = (struct inplace_cb_reply*)calloc(1, sizeof(*callback)); + if(callback == NULL) { + log_err("out of memory during edns callback registration."); + return 0; + } + callback->next = NULL; + callback->cb = cb; + callback->cb_arg = cb_arg; + + prevp = (struct inplace_cb_reply**) &env->inplace_cb_lists[type]; + /* append at end of list */ + while(*prevp != NULL) + prevp = &((*prevp)->next); + *prevp = callback; + return 1; +} + +int +inplace_cb_reply_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env) +{ + return inplace_cb_reply_register_generic(cb, inplace_cb_reply, cb_arg, + env); +} + +int +inplace_cb_reply_cache_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env) +{ + return inplace_cb_reply_register_generic(cb, inplace_cb_reply_cache, + cb_arg, env); +} + +int +inplace_cb_reply_local_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env) +{ + return inplace_cb_reply_register_generic(cb, inplace_cb_reply_local, + cb_arg, env); +} + +int +inplace_cb_reply_servfail_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env) +{ + return inplace_cb_reply_register_generic(cb, inplace_cb_reply_servfail, + cb_arg, env); +} + +static void +inplace_cb_reply_delete_generic(struct module_env* env, + enum inplace_cb_list_type type) +{ + struct inplace_cb_reply* curr = env->inplace_cb_lists[type]; + struct inplace_cb_reply* tmp; + /* delete list */ + while(curr) { + tmp = curr->next; + free(curr); + curr = tmp; + } + /* update head pointer */ + env->inplace_cb_lists[type] = NULL; +} + +void inplace_cb_reply_delete(struct module_env* env) +{ + inplace_cb_reply_delete_generic(env, inplace_cb_reply); +} + +void inplace_cb_reply_cache_delete(struct module_env* env) +{ + inplace_cb_reply_delete_generic(env, inplace_cb_reply_cache); +} + +void inplace_cb_reply_servfail_delete(struct module_env* env) +{ + inplace_cb_reply_delete_generic(env, inplace_cb_reply_servfail); +} + +int +inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg, + struct module_env* env) +{ + struct inplace_cb_query* callback; + struct inplace_cb_query** prevp; + if(env->worker) { + log_err("invalid edns callback registration: " + "trying to register callback after module init phase"); + return 0; + } + + callback = (struct inplace_cb_query*)calloc(1, sizeof(*callback)); + if(callback == NULL) { + log_err("out of memory during edns callback registration."); + return 0; + } + callback->next = NULL; + callback->cb = cb; + callback->cb_arg = cb_arg; + + prevp = (struct inplace_cb_query**) + &env->inplace_cb_lists[inplace_cb_query]; + /* append at end of list */ + while(*prevp != NULL) + prevp = &((*prevp)->next); + *prevp = callback; + return 1; +} + +void +inplace_cb_query_delete(struct module_env* env) +{ + struct inplace_cb_query* curr = env->inplace_cb_lists[inplace_cb_query]; + struct inplace_cb_query* tmp; + /* delete list */ + while(curr) { + tmp = curr->next; + free(curr); + curr = tmp; + } + /* update head pointer */ + env->inplace_cb_lists[inplace_cb_query] = NULL; +} + +void +inplace_cb_lists_delete(struct module_env* env) +{ + inplace_cb_reply_delete(env); + inplace_cb_reply_cache_delete(env); + inplace_cb_reply_servfail_delete(env); + inplace_cb_query_delete(env); +} + +struct edns_known_option* +edns_option_is_known(uint16_t opt_code, struct module_env* env) +{ + size_t i; + for(i=0; i<env->edns_known_options_num; i++) + if(env->edns_known_options[i].opt_code == opt_code) + return env->edns_known_options + i; + return NULL; +} + +int +edns_bypass_cache_stage(struct edns_option* list, struct module_env* env) +{ + size_t i; + for(; list; list=list->next) + for(i=0; i<env->edns_known_options_num; i++) + if(env->edns_known_options[i].opt_code == list->opt_code && + env->edns_known_options[i].bypass_cache_stage == 1) + return 1; + return 0; +} + +int +edns_unique_mesh_state(struct edns_option* list, struct module_env* env) +{ + size_t i; + for(; list; list=list->next) + for(i=0; i<env->edns_known_options_num; i++) + if(env->edns_known_options[i].opt_code == list->opt_code && + env->edns_known_options[i].no_aggregation == 1) + return 1; + return 0; +} + +void +log_edns_known_options(enum verbosity_value level, struct module_env* env) +{ + size_t i; + char str[32], *s; + size_t slen; + if(env->edns_known_options_num > 0 && verbosity >= level) { + verbose(level, "EDNS known options:"); + verbose(level, " Code: Bypass_cache_stage: Aggregate_mesh:"); + for(i=0; i<env->edns_known_options_num; i++) { + s = str; + slen = sizeof(str); + (void)sldns_wire2str_edns_option_code_print(&s, &slen, + env->edns_known_options[i].opt_code); + verbose(level, " %-8.8s %-19s %-15s", str, + env->edns_known_options[i].bypass_cache_stage?"YES":"NO", + env->edns_known_options[i].no_aggregation?"NO":"YES"); + } + } +} diff --git a/usr.sbin/unbound/util/module.h b/usr.sbin/unbound/util/module.h index c3ce8a40eda..d3db3eaec15 100644 --- a/usr.sbin/unbound/util/module.h +++ b/usr.sbin/unbound/util/module.h @@ -176,7 +176,116 @@ struct iter_forwards; struct iter_hints; /** Maximum number of modules in operation */ -#define MAX_MODULE 5 +#define MAX_MODULE 16 + +/** Maximum number of known edns options */ +#define MAX_KNOWN_EDNS_OPTS 256 + +enum inplace_cb_list_type { + /* Inplace callbacks for when a resolved reply is ready to be sent to the + * front.*/ + inplace_cb_reply = 0, + /* Inplace callbacks for when a reply is given from the cache. */ + inplace_cb_reply_cache, + /* Inplace callbacks for when a reply is given with local data + * (or Chaos reply). */ + inplace_cb_reply_local, + /* Inplace callbacks for when the reply is servfail. */ + inplace_cb_reply_servfail, + /* Inplace callbacks for when a query is ready to be sent to the back.*/ + inplace_cb_query, + /* Total number of types. Used for array initialization. + * Should always be last. */ + inplace_cb_types_total +}; + + +/** Known edns option. Can be populated during modules' init. */ +struct edns_known_option { + /** type of this edns option */ + uint16_t opt_code; + /** whether the option needs to bypass the cache stage */ + int bypass_cache_stage; + /** whether the option needs mesh aggregation */ + int no_aggregation; +}; + +/** + * Inplace callback function called before replying. + * Called as func(edns, qstate, opt_list_out, qinfo, reply_info, rcode, + * region, python_callback) + * Where: + * qinfo: the query info. + * qstate: the module state. NULL when calling before the query reaches the + * mesh states. + * rep: reply_info. Could be NULL. + * rcode: the return code. + * 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. + * region: region to store data. + * 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, void* python_callback); + +/** + * Inplace callback list of registered routines to be called before replying + * with a resolved query. + */ +struct inplace_cb_reply { + /** next in list */ + struct inplace_cb_reply* next; + /** + * Inplace callback routine for cache stage response. + * called as cb(qinfo, qstate, qinfo, reply_info, rcode, edns, + * opt_list_out, region, python_callback); + * python_callback is only used for registering a python callback function. + */ + inplace_cb_reply_func_type* cb; + void* cb_arg; +}; + +/** + * Inplace callback function called before sending the query to a nameserver. + * Called as func(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region, + * python_callback) + * Where: + * qinfo: query info. + * flags: flags of the query. + * qstate: query state. + * addr: to which server to send the query. + * addrlen: length of addr. + * zone: name of the zone of the delegation point. wireformat dname. + * This is the delegation point name for which the server is deemed + * authoritative. + * zonelen: length of zone. + * region: region to store data. + * python_callback: only used for registering a python callback function. + */ +typedef int inplace_cb_query_func_type(struct query_info* qinfo, uint16_t flags, + struct module_qstate* qstate, struct sockaddr_storage* addr, + socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region, + void* python_callback); + +/** + * Inplace callback list of registered routines to be called before quering a + * nameserver. + */ +struct inplace_cb_query { + /** next in list */ + struct inplace_cb_query* next; + /** + * Inplace callback routine for cache stage response. + * called as cb(qinfo, flags, qstate, addr, addrlen, zone, zonelen, + * region, python_callback); + * python_callback is only used for registering a python callback function. + */ + inplace_cb_query_func_type* cb; + void* cb_arg; +}; /** * Module environment. @@ -202,10 +311,7 @@ struct module_env { * will cause operate() to be called with event timeout or reply. * The time until a timeout is calculated from roundtrip timing, * several UDP retries are attempted. - * @param qname: query name. (host order) - * @param qnamelen: length in bytes of qname, including trailing 0. - * @param qtype: query type. (host order) - * @param qclass: query class. (host order) + * @param qinfo: query info. * @param flags: host order flags word, with opcode and CD bit. * @param dnssec: if set, EDNS record will have bits set. * If EDNS_DO bit is set, DO bit is set in EDNS records. @@ -214,23 +320,22 @@ struct module_env { * EDNS, the answer is likely to be useless for this domain. * @param nocaps: do not use caps_for_id, use the qname as given. * (ignored if caps_for_id is disabled). - * @param opt_list: set these EDNS options on the outgoing packet. - * or NULL if none (the list is deep-copied). * @param addr: where to. * @param addrlen: length of addr. * @param zone: delegation point name. * @param zonelen: length of zone name. + * @param ssl_upstream: use SSL for upstream queries. * @param q: wich query state to reactivate upon return. * @return: false on failure (memory or socket related). no query was * sent. Or returns an outbound entry with qsent and qstate set. * This outbound_entry will be used on later module invocations * that involve this query (timeout, error or reply). */ - struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen, - uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, - int want_dnssec, int nocaps, struct edns_option* opt_list, + struct outbound_entry* (*send_query)(struct query_info* qinfo, + uint16_t flags, int dnssec, int want_dnssec, int nocaps, struct sockaddr_storage* addr, socklen_t addrlen, - uint8_t* zone, size_t zonelen, struct module_qstate* q); + uint8_t* zone, size_t zonelen, int ssl_upstream, + struct module_qstate* q); /** * Detach-subqueries. @@ -335,6 +440,17 @@ struct module_env { struct iter_hints* hints; /** module specific data. indexed by module id. */ void* modinfo[MAX_MODULE]; + + /* Shared linked list of inplace callback functions */ + void* inplace_cb_lists[inplace_cb_types_total]; + + /** + * Shared array of known edns options (size MAX_KNOWN_EDNS_OPTS). + * Filled by edns literate modules during init. + */ + struct edns_known_option* edns_known_options; + /* Number of known edns options */ + size_t edns_known_options_num; }; /** @@ -433,6 +549,19 @@ struct module_qstate { struct mesh_state* mesh_info; /** how many seconds before expiry is this prefetched (0 if not) */ time_t prefetch_leeway; + + /** incoming edns options from the front end */ + struct edns_option* edns_opts_front_in; + /** outgoing edns options to the back end */ + struct edns_option* edns_opts_back_out; + /** incoming edns options from the back end */ + struct edns_option* edns_opts_back_in; + /** outgoing edns options to the front end */ + struct edns_option* edns_opts_front_out; + /** whether modules should answer from the cache */ + int no_cache_lookup; + /** whether modules should store answer in the cache */ + int no_cache_store; }; /** @@ -522,4 +651,156 @@ const char* strextstate(enum module_ext_state s); */ const char* strmodulevent(enum module_ev e); +/** + * Initialize the edns known options by allocating the required space. + * @param env: the module environment. + * @return false on failure (no memory). + */ +int edns_known_options_init(struct module_env* env); + +/** + * Free the allocated space for the known edns options. + * @param env: the module environment. + */ +void edns_known_options_delete(struct module_env* env); + +/** + * Register a known edns option. Overwrite the flags if it is already + * registered. Used before creating workers to register known edns options. + * @param opt_code: the edns option code. + * @param bypass_cache_stage: whether the option interacts with the cache. + * @param no_aggregation: whether the option implies more specific + * aggregation. + * @param env: the module environment. + * @return true on success, false on failure (registering more options than + * allowed or trying to register after the environment is copied to the + * threads.) + */ +int edns_register_option(uint16_t opt_code, int bypass_cache_stage, + int no_aggregation, struct module_env* env); + +/** + * Register an inplace callback function called before replying with a resolved + * query. + * @param cb: pointer to the callback function. + * @param cb_arg: optional argument for the callback function. + * @param env: the module environment. + * @return true on success, false on failure (out of memory or trying to + * register after the environment is copied to the threads.) + */ +int inplace_cb_reply_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env); + +/** + * Register an inplace callback function called before replying from the cache. + * @param cb: pointer to the callback function. + * @param cb_arg: optional argument for the callback function. + * @param env: the module environment. + * @return true on success, false on failure (out of memory or trying to + * register after the environment is copied to the threads.) + */ +int inplace_cb_reply_cache_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env); + +/** + * Register an inplace callback function called before replying with local + * data or Chaos reply. + * @param cb: pointer to the callback function. + * @param cb_arg: optional argument for the callback function. + * @param env: the module environment. + * @return true on success, false on failure (out of memory or trying to + * register after the environment is copied to the threads.) + */ +int inplace_cb_reply_local_register(inplace_cb_reply_func_type* cb, void* cb_arg, + struct module_env* env); + +/** + * Register an inplace callback function called before replying with servfail. + * @param cb: pointer to the callback function. + * @param cb_arg: optional argument for the callback function. + * @param env: the module environment. + * @return true on success, false on failure (out of memory or trying to + * register after the environment is copied to the threads.) + */ +int inplace_cb_reply_servfail_register(inplace_cb_reply_func_type* cb, + void* cb_arg, struct module_env* env); + +/** + * Delete the inplace_cb_reply callback linked list. + * @param env: the module environment. + */ +void inplace_cb_reply_delete(struct module_env* env); + +/** + * Delete the inplace_cb_reply_cache callback linked list. + * @param env: the module environment. + */ +void inplace_cb_reply_cache_delete(struct module_env* env); + +/** + * Delete the inplace_cb_reply_servfail callback linked list. + * @param env: the module environment. + */ +void inplace_cb_reply_servfail_delete(struct module_env* env); + +/** + * Register an inplace callback function called before quering a nameserver. + * @param cb: pointer to the callback function. + * @param cb_arg: optional argument for the callback function. + * @param env: the module environment. + * @return true on success, false on failure (out of memory or trying to + * register after the environment is copied to the threads.) + */ +int inplace_cb_query_register(inplace_cb_query_func_type* cb, void* cb_arg, + struct module_env* env); + +/** + * Delete the inplace_cb_query callback linked list. + * @param env: the module environment. + */ +void inplace_cb_query_delete(struct module_env* env); + +/** + * Delete all the inplace callback linked lists. + * @param env: the module environment. + */ +void inplace_cb_lists_delete(struct module_env* env); + +/** + * Check if an edns option is known. + * @param opt_code: the edns option code. + * @param env: the module environment. + * @return pointer to registered option if the edns option is known, + * NULL otherwise. + */ +struct edns_known_option* edns_option_is_known(uint16_t opt_code, + struct module_env* env); + +/** + * Check if an edns option needs to bypass the reply from cache stage. + * @param list: the edns options. + * @param env: the module environment. + * @return true if an edns option needs to bypass the cache stage, + * false otherwise. + */ +int edns_bypass_cache_stage(struct edns_option* list, + struct module_env* env); + +/** + * Check if an edns option needs a unique mesh state. + * @param list: the edns options. + * @param env: the module environment. + * @return true if an edns option needs a unique mesh state, + * false otherwise. + */ +int edns_unique_mesh_state(struct edns_option* list, struct module_env* env); + +/** + * Log the known edns options. + * @param level: the desired verbosity level. + * @param env: the module environment. + */ +void log_edns_known_options(enum verbosity_value level, + struct module_env* env); + #endif /* UTIL_MODULE_H */ diff --git a/usr.sbin/unbound/util/net_help.c b/usr.sbin/unbound/util/net_help.c index 5d6c033d659..6c0d68e312b 100644 --- a/usr.sbin/unbound/util/net_help.c +++ b/usr.sbin/unbound/util/net_help.c @@ -783,9 +783,9 @@ void* outgoing_ssl_fd(void* sslctx, int fd) #endif } -#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) +#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L /** global lock list for openssl locks */ -static lock_basic_t *ub_openssl_locks = NULL; +static lock_basic_type *ub_openssl_locks = NULL; /** callback that gets thread id for openssl */ static unsigned long @@ -808,10 +808,10 @@ ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file), int ub_openssl_lock_init(void) { -#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) +#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L int i; - ub_openssl_locks = (lock_basic_t*)reallocarray( - NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_t)); + ub_openssl_locks = (lock_basic_type*)reallocarray( + NULL, (size_t)CRYPTO_num_locks(), sizeof(lock_basic_type)); if(!ub_openssl_locks) return 0; for(i=0; i<CRYPTO_num_locks(); i++) { @@ -825,7 +825,7 @@ int ub_openssl_lock_init(void) void ub_openssl_lock_delete(void) { -#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) +#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED) && defined(CRYPTO_LOCK) && OPENSSL_VERSION_NUMBER < 0x10100000L int i; if(!ub_openssl_locks) return; diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c index bdb35739327..8e66b9045fa 100644 --- a/usr.sbin/unbound/util/netevent.c +++ b/usr.sbin/unbound/util/netevent.c @@ -80,8 +80,10 @@ # endif #endif -/** The TCP reading or writing query timeout in seconds */ -#define TCP_QUERY_TIMEOUT 120 +/** The TCP reading or 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 #ifndef NONBLOCKING_IS_BROKEN /** number of UDP reads to perform per read indication from select */ @@ -144,7 +146,7 @@ struct internal_signal { /** create a tcp handler with a parent */ static struct comm_point* comm_point_create_tcp_handler( struct comm_base *base, struct comm_point* parent, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /* -------- End of local definitions -------- */ @@ -652,7 +654,7 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg) (void)fd; (void)event; (void)arg; - fatal_exit("recvmsg: No support for IPV6_PKTINFO. " + fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. " "Please disable interface-automatic"); #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ } @@ -710,14 +712,20 @@ comm_point_udp_callback(int fd, short event, void* arg) /** Use a new tcp handler for new query fd, set to read query */ static void -setup_tcp_handler(struct comm_point* c, int fd) +setup_tcp_handler(struct comm_point* c, int fd, int cur, int max) { log_assert(c->type == comm_tcp); log_assert(c->fd == -1); sldns_buffer_clear(c->buffer); c->tcp_is_reading = 1; c->tcp_byte_count = 0; - comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT); + 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); } void comm_base_handle_slow_accept(int ATTR_UNUSED(fd), @@ -769,7 +777,7 @@ int comm_point_perform_accept(struct comm_point* c, (*b->stop_accept)(b->cb_arg); /* set timeout, no mallocs */ tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; - tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000; + tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000; b->eb->slow_accept = ub_event_new(b->eb->base, -1, UB_EV_TIMEOUT, comm_base_handle_slow_accept, b); @@ -862,6 +870,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg) /* accept incoming connection. */ c_hdl = c->tcp_free; log_assert(fd != -1); + (void)fd; new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr, &c_hdl->repinfo.addrlen); if(new_fd == -1) @@ -886,7 +895,7 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg) /* stop accepting incoming queries for now. */ comm_point_stop_listening(c); } - setup_tcp_handler(c_hdl, new_fd); + setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count); } /** Make tcp handler free for next assignment */ @@ -940,7 +949,7 @@ tcp_callback_reader(struct comm_point* c) comm_point_stop_listening(c); fptr_ok(fptr_whitelist_comm_point(c->callback)); if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) { - comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT); + comm_point_start_listening(c, -1, c->tcp_timeout_msec); } } @@ -1348,6 +1357,59 @@ comm_point_tcp_handle_write(int fd, struct comm_point* c) if(c->ssl) return ssl_handle_it(c); +#ifdef USE_MSG_FASTOPEN + /* Only try this on first use of a connection that uses tfo, + otherwise fall through to normal write */ + /* Also, TFO support on WINDOWS not implemented at the moment */ + if(c->tcp_do_fastopen == 1) { + /* this form of sendmsg() does both a connect() and send() so need to + look for various flavours of error*/ + uint16_t len = htons(sldns_buffer_limit(c->buffer)); + struct msghdr msg; + struct iovec iov[2]; + c->tcp_do_fastopen = 0; + memset(&msg, 0, sizeof(msg)); + iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count; + iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count; + iov[1].iov_base = sldns_buffer_begin(c->buffer); + iov[1].iov_len = sldns_buffer_limit(c->buffer); + log_assert(iov[0].iov_len > 0); + log_assert(iov[1].iov_len > 0); + msg.msg_name = &c->repinfo.addr; + msg.msg_namelen = c->repinfo.addrlen; + msg.msg_iov = iov; + msg.msg_iovlen = 2; + r = sendmsg(fd, &msg, MSG_FASTOPEN); + if (r == -1) { +#if defined(EINPROGRESS) && defined(EWOULDBLOCK) + /* Handshake is underway, maybe because no TFO cookie available. + Come back to write the messsage*/ + if(errno == EINPROGRESS || errno == EWOULDBLOCK) + return 1; +#endif + if(errno == EINTR || errno == EAGAIN) + return 1; + /* Not handling EISCONN here as shouldn't ever hit that case.*/ + if(errno != 0 && verbosity < 2) + return 0; /* silence lots of chatter in the logs */ + else if(errno != 0) + log_err_addr("tcp sendmsg", strerror(errno), + &c->repinfo.addr, c->repinfo.addrlen); + return 0; + } else { + c->tcp_byte_count += r; + if(c->tcp_byte_count < sizeof(uint16_t)) + return 1; + sldns_buffer_set_position(c->buffer, c->tcp_byte_count - + sizeof(uint16_t)); + if(sldns_buffer_remaining(c->buffer) == 0) { + tcp_callback_writer(c); + return 1; + } + } + } +#endif /* USE_MSG_FASTOPEN */ + if(c->tcp_byte_count < sizeof(uint16_t)) { uint16_t len = htons(sldns_buffer_limit(c->buffer)); #ifdef HAVE_WRITEV @@ -1511,7 +1573,7 @@ void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), struct comm_point* comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1540,6 +1602,9 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, c->do_not_close = 0; c->tcp_do_toggle_rw = 0; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->inuse = 0; c->callback = callback; c->cb_arg = callback_arg; @@ -1563,7 +1628,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, struct comm_point* comm_point_create_udp_ancil(struct comm_base *base, int fd, sldns_buffer* buffer, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1593,6 +1658,9 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, c->inuse = 0; c->tcp_do_toggle_rw = 0; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->callback = callback; c->cb_arg = callback_arg; evbits = UB_EV_READ | UB_EV_PERSIST; @@ -1615,7 +1683,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, static struct comm_point* comm_point_create_tcp_handler(struct comm_base *base, struct comm_point* parent, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1655,6 +1723,9 @@ comm_point_create_tcp_handler(struct comm_base *base, c->do_not_close = 0; c->tcp_do_toggle_rw = 1; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->repinfo.c = c; c->callback = callback; c->cb_arg = callback_arg; @@ -1678,7 +1749,7 @@ 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_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1715,6 +1786,9 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, c->do_not_close = 0; c->tcp_do_toggle_rw = 0; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->callback = NULL; c->cb_arg = NULL; evbits = UB_EV_READ | UB_EV_PERSIST; @@ -1746,7 +1820,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, struct comm_point* comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1780,6 +1854,9 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, c->do_not_close = 0; c->tcp_do_toggle_rw = 1; c->tcp_check_nb_connect = 1; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 1; +#endif c->repinfo.c = c; c->callback = callback; c->cb_arg = callback_arg; @@ -1800,7 +1877,7 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, struct comm_point* comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1834,6 +1911,9 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, c->do_not_close = 1; c->tcp_do_toggle_rw = 0; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->callback = callback; c->cb_arg = callback_arg; /* ub_event stuff */ @@ -1858,7 +1938,7 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, struct comm_point* comm_point_create_raw(struct comm_base* base, int fd, int writing, - comm_point_callback_t* callback, void* callback_arg) + comm_point_callback_type* callback, void* callback_arg) { struct comm_point* c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); @@ -1887,6 +1967,9 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing, c->do_not_close = 1; c->tcp_do_toggle_rw = 0; c->tcp_check_nb_connect = 0; +#ifdef USE_MSG_FASTOPEN + c->tcp_do_fastopen = 0; +#endif c->callback = callback; c->cb_arg = callback_arg; /* ub_event stuff */ @@ -1983,7 +2066,8 @@ comm_point_send_reply(struct comm_reply *repinfo) dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->addr, repinfo->c->type, repinfo->c->buffer); #endif - comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT); + comm_point_start_listening(repinfo->c, -1, + repinfo->c->tcp_timeout_msec); } } @@ -2009,7 +2093,7 @@ comm_point_stop_listening(struct comm_point* c) } void -comm_point_start_listening(struct comm_point* c, int newfd, int sec) +comm_point_start_listening(struct comm_point* c, int newfd, int msec) { verbose(VERB_ALGO, "comm point start listening %d", c->fd==-1?newfd:c->fd); @@ -2017,7 +2101,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec) /* no use to start listening no free slots. */ return; } - if(sec != -1 && sec != 0) { + if(msec != -1 && msec != 0) { if(!c->timeout) { c->timeout = (struct timeval*)malloc(sizeof( struct timeval)); @@ -2028,8 +2112,8 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec) } ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT); #ifndef S_SPLINT_S /* splint fails on struct timeval. */ - c->timeout->tv_sec = sec; - c->timeout->tv_usec = 0; + c->timeout->tv_sec = msec/1000; + c->timeout->tv_usec = (msec%1000)*1000; #endif /* S_SPLINT_S */ } if(c->type == comm_tcp) { @@ -2049,7 +2133,7 @@ comm_point_start_listening(struct comm_point* c, int newfd, int sec) c->fd = newfd; ub_event_set_fd(c->ev->ev, c->fd); } - if(ub_event_add(c->ev->ev, sec==0?NULL:c->timeout) != 0) { + if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) { log_err("event_add failed. in cpsl."); } } diff --git a/usr.sbin/unbound/util/netevent.h b/usr.sbin/unbound/util/netevent.h index bdcddd848bd..2ce716b850e 100644 --- a/usr.sbin/unbound/util/netevent.h +++ b/usr.sbin/unbound/util/netevent.h @@ -71,7 +71,7 @@ struct internal_base; struct internal_timer; /* A sub struct of the comm_timer super struct */ /** callback from communication point function type */ -typedef int comm_point_callback_t(struct comm_point*, void*, int, +typedef int comm_point_callback_type(struct comm_point*, void*, int, struct comm_reply*); /** to pass no_error to callback function */ @@ -225,9 +225,17 @@ struct comm_point { So that when that is done the callback is called. */ int tcp_do_toggle_rw; + /** timeout in msec for TCP wait times for this connection */ + int tcp_timeout_msec; + /** if set, checks for pending error from nonblocking connect() call.*/ int tcp_check_nb_connect; +#ifdef USE_MSG_FASTOPEN + /** used to track if the sendto() call should be done when using TFO. */ + int tcp_do_fastopen; +#endif + /** number of queries outstanding on this socket, used by * outside network for udp ports */ int inuse; @@ -256,7 +264,7 @@ struct comm_point { For UDP this is done without changing the commpoint. In TCP it sets write state. */ - comm_point_callback_t* callback; + comm_point_callback_type* callback; /** argument to pass to callback. */ void *cb_arg; }; @@ -374,7 +382,7 @@ struct ub_event_base* comm_base_internal(struct comm_base* b); */ struct comm_point* comm_point_create_udp(struct comm_base* base, int fd, struct sldns_buffer* buffer, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /** * Create an UDP with ancillary data comm point. Calls malloc. @@ -390,7 +398,7 @@ struct comm_point* comm_point_create_udp(struct comm_base* base, */ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, int fd, struct sldns_buffer* buffer, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /** * Create a TCP listener comm point. Calls malloc. @@ -411,7 +419,7 @@ struct comm_point* comm_point_create_udp_ancil(struct comm_base* base, */ struct comm_point* comm_point_create_tcp(struct comm_base* base, int fd, int num, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /** * Create an outgoing TCP commpoint. No file descriptor is opened, left at -1. @@ -422,7 +430,7 @@ struct comm_point* comm_point_create_tcp(struct comm_base* base, * @return: the commpoint or NULL on error. */ struct comm_point* comm_point_create_tcp_out(struct comm_base* base, - size_t bufsize, comm_point_callback_t* callback, void* callback_arg); + size_t bufsize, comm_point_callback_type* callback, void* callback_arg); /** * Create commpoint to listen to a local domain file descriptor. @@ -435,7 +443,7 @@ struct comm_point* comm_point_create_tcp_out(struct comm_base* base, */ struct comm_point* comm_point_create_local(struct comm_base* base, int fd, size_t bufsize, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /** * Create commpoint to listen to a local domain pipe descriptor. @@ -448,7 +456,7 @@ struct comm_point* comm_point_create_local(struct comm_base* base, */ struct comm_point* comm_point_create_raw(struct comm_base* base, int fd, int writing, - comm_point_callback_t* callback, void* callback_arg); + comm_point_callback_type* callback, void* callback_arg); /** * Close a comm point fd. @@ -496,9 +504,10 @@ void comm_point_stop_listening(struct comm_point* c); * Start listening again for input on the comm point. * @param c: commpoint to enable again. * @param newfd: new fd, or -1 to leave fd be. - * @param sec: timeout in seconds, or -1 for no (change to the) timeout. + * @param msec: timeout in milliseconds, or -1 for no (change to the) timeout. + * So seconds*1000. */ -void comm_point_start_listening(struct comm_point* c, int newfd, int sec); +void comm_point_start_listening(struct comm_point* c, int newfd, int msec); /** * Stop listening and start listening again for reading or writing. diff --git a/usr.sbin/unbound/util/rbtree.c b/usr.sbin/unbound/util/rbtree.c index ee5446f6cb5..f031c9a13fa 100644 --- a/usr.sbin/unbound/util/rbtree.c +++ b/usr.sbin/unbound/util/rbtree.c @@ -50,7 +50,7 @@ #define RED 1 /** the NULL node, global alloc */ -rbnode_t rbtree_null_node = { +rbnode_type rbtree_null_node = { RBTREE_NULL, /* Parent. */ RBTREE_NULL, /* Left. */ RBTREE_NULL, /* Right. */ @@ -59,13 +59,14 @@ rbnode_t rbtree_null_node = { }; /** rotate subtree left (to preserve redblack property) */ -static void rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node); +static void rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node); /** rotate subtree right (to preserve redblack property) */ -static void rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node); +static void rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node); /** Fixup node colours when insert happened */ -static void rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node); +static void rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node); /** Fixup node colours when delete happened */ -static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent); +static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, + rbnode_type* child_parent); /* * Creates a new red black tree, initializes and returns a pointer to it. @@ -73,13 +74,13 @@ static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* chi * Return NULL on failure. * */ -rbtree_t * +rbtree_type * rbtree_create (int (*cmpf)(const void *, const void *)) { - rbtree_t *rbtree; + rbtree_type *rbtree; /* Allocate memory for it */ - rbtree = (rbtree_t *) malloc(sizeof(rbtree_t)); + rbtree = (rbtree_type *) malloc(sizeof(rbtree_type)); if (!rbtree) { return NULL; } @@ -91,7 +92,7 @@ rbtree_create (int (*cmpf)(const void *, const void *)) } void -rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *)) +rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *)) { /* Initialize it */ rbtree->root = RBTREE_NULL; @@ -104,9 +105,9 @@ rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *)) * */ static void -rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node) +rbtree_rotate_left(rbtree_type *rbtree, rbnode_type *node) { - rbnode_t *right = node->right; + rbnode_type *right = node->right; node->right = right->left; if (right->left != RBTREE_NULL) right->left->parent = node; @@ -131,9 +132,9 @@ rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node) * */ static void -rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node) +rbtree_rotate_right(rbtree_type *rbtree, rbnode_type *node) { - rbnode_t *left = node->left; + rbnode_type *left = node->left; node->left = left->right; if (left->right != RBTREE_NULL) left->right->parent = node; @@ -154,9 +155,9 @@ rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node) } static void -rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node) +rbtree_insert_fixup(rbtree_type *rbtree, rbnode_type *node) { - rbnode_t *uncle; + rbnode_type *uncle; /* While not at the root and need fixing... */ while (node != rbtree->root && node->parent->color == RED) { @@ -223,15 +224,15 @@ rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node) * Returns NULL on failure or the pointer to the newly added node * otherwise. */ -rbnode_t * -rbtree_insert (rbtree_t *rbtree, rbnode_t *data) +rbnode_type * +rbtree_insert (rbtree_type *rbtree, rbnode_type *data) { /* XXX Not necessary, but keeps compiler quiet... */ int r = 0; /* We start at the root of the tree */ - rbnode_t *node = rbtree->root; - rbnode_t *parent = RBTREE_NULL; + rbnode_type *node = rbtree->root; + rbnode_type *parent = RBTREE_NULL; fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp)); /* Lets find the new parent... */ @@ -276,10 +277,10 @@ rbtree_insert (rbtree_t *rbtree, rbnode_t *data) * Searches the red black tree, returns the data if key is found or NULL otherwise. * */ -rbnode_t * -rbtree_search (rbtree_t *rbtree, const void *key) +rbnode_type * +rbtree_search (rbtree_type *rbtree, const void *key) { - rbnode_t *node; + rbnode_type *node; if (rbtree_find_less_equal(rbtree, key, &node)) { return node; @@ -295,13 +296,14 @@ static void swap_int8(uint8_t* x, uint8_t* y) } /** helpers for delete: swap node pointers */ -static void swap_np(rbnode_t** x, rbnode_t** y) +static void swap_np(rbnode_type** x, rbnode_type** y) { - rbnode_t* t = *x; *x = *y; *y = t; + rbnode_type* t = *x; *x = *y; *y = t; } /** Update parent pointers of child trees of 'parent' */ -static void change_parent_ptr(rbtree_t* rbtree, rbnode_t* parent, rbnode_t* old, rbnode_t* new) +static void change_parent_ptr(rbtree_type* rbtree, rbnode_type* parent, + rbnode_type* old, rbnode_type* new) { if(parent == RBTREE_NULL) { @@ -315,18 +317,19 @@ static void change_parent_ptr(rbtree_t* rbtree, rbnode_t* parent, rbnode_t* old, if(parent->right == old) parent->right = new; } /** Update parent pointer of a node 'child' */ -static void change_child_ptr(rbnode_t* child, rbnode_t* old, rbnode_t* new) +static void change_child_ptr(rbnode_type* child, rbnode_type* old, + rbnode_type* new) { if(child == RBTREE_NULL) return; log_assert(child->parent == old || child->parent == new); if(child->parent == old) child->parent = new; } -rbnode_t* -rbtree_delete(rbtree_t *rbtree, const void *key) +rbnode_type* +rbtree_delete(rbtree_type *rbtree, const void *key) { - rbnode_t *to_delete; - rbnode_t *child; + rbnode_type *to_delete; + rbnode_type *child; if((to_delete = rbtree_search(rbtree, key)) == 0) return 0; rbtree->count--; @@ -334,11 +337,11 @@ rbtree_delete(rbtree_t *rbtree, const void *key) if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL) { /* swap with smallest from right subtree (or largest from left) */ - rbnode_t *smright = to_delete->right; + rbnode_type *smright = to_delete->right; while(smright->left != RBTREE_NULL) smright = smright->left; /* swap the smright and to_delete elements in the tree, - * but the rbnode_t is first part of user data struct + * but the rbnode_type is first part of user data struct * so cannot just swap the keys and data pointers. Instead * readjust the pointers left,right,parent */ @@ -400,9 +403,10 @@ rbtree_delete(rbtree_t *rbtree, const void *key) return to_delete; } -static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent) +static void rbtree_delete_fixup(rbtree_type* rbtree, rbnode_type* child, + rbnode_type* child_parent) { - rbnode_t* sibling; + rbnode_type* sibling; int go_up = 1; /* determine sibling to the node that is one-black short */ @@ -504,10 +508,11 @@ static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* chi } int -rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result) +rbtree_find_less_equal(rbtree_type *rbtree, const void *key, + rbnode_type **result) { int r; - rbnode_t *node; + rbnode_type *node; log_assert(result); @@ -540,19 +545,19 @@ rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result) * Finds the first element in the red black tree * */ -rbnode_t * -rbtree_first (rbtree_t *rbtree) +rbnode_type * +rbtree_first (rbtree_type *rbtree) { - rbnode_t *node; + rbnode_type *node; for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left); return node; } -rbnode_t * -rbtree_last (rbtree_t *rbtree) +rbnode_type * +rbtree_last (rbtree_type *rbtree) { - rbnode_t *node; + rbnode_type *node; for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right); return node; @@ -562,10 +567,10 @@ rbtree_last (rbtree_t *rbtree) * Returns the next node... * */ -rbnode_t * -rbtree_next (rbnode_t *node) +rbnode_type * +rbtree_next (rbnode_type *node) { - rbnode_t *parent; + rbnode_type *parent; if (node->right != RBTREE_NULL) { /* One right, then keep on going left... */ @@ -581,10 +586,10 @@ rbtree_next (rbnode_t *node) return node; } -rbnode_t * -rbtree_previous(rbnode_t *node) +rbnode_type * +rbtree_previous(rbnode_type *node) { - rbnode_t *parent; + rbnode_type *parent; if (node->left != RBTREE_NULL) { /* One left, then keep on going right... */ @@ -602,7 +607,7 @@ rbtree_previous(rbnode_t *node) /** recursive descent traverse */ static void -traverse_post(void (*func)(rbnode_t*, void*), void* arg, rbnode_t* node) +traverse_post(void (*func)(rbnode_type*, void*), void* arg, rbnode_type* node) { if(!node || node == RBTREE_NULL) return; @@ -614,7 +619,8 @@ traverse_post(void (*func)(rbnode_t*, void*), void* arg, rbnode_t* node) } void -traverse_postorder(rbtree_t* tree, void (*func)(rbnode_t*, void*), void* arg) +traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*), + void* arg) { traverse_post(func, arg, tree->root); } diff --git a/usr.sbin/unbound/util/rbtree.h b/usr.sbin/unbound/util/rbtree.h index 879804dd860..dfcf09ac6a8 100644 --- a/usr.sbin/unbound/util/rbtree.h +++ b/usr.sbin/unbound/util/rbtree.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ @@ -45,40 +45,40 @@ /** * This structure must be the first member of the data structure in - * the rbtree. This allows easy casting between an rbnode_t and the + * the rbtree. This allows easy casting between an rbnode_type and the * user data (poor man's inheritance). */ -typedef struct rbnode_t rbnode_t; +typedef struct rbnode_type rbnode_type; /** - * The rbnode_t struct definition. + * The rbnode_type struct definition. */ -struct rbnode_t { +struct rbnode_type { /** parent in rbtree, RBTREE_NULL for root */ - rbnode_t *parent; + rbnode_type *parent; /** left node (smaller items) */ - rbnode_t *left; + rbnode_type *left; /** right node (larger items) */ - rbnode_t *right; + rbnode_type *right; /** pointer to sorting key */ - const void *key; + const void *key; /** colour of this node */ - uint8_t color; + uint8_t color; }; /** The nullpointer, points to empty node */ #define RBTREE_NULL &rbtree_null_node /** the global empty node */ -extern rbnode_t rbtree_null_node; +extern rbnode_type rbtree_null_node; /** An entire red black tree */ -typedef struct rbtree_t rbtree_t; +typedef struct rbtree_type rbtree_type; /** definition for tree struct */ -struct rbtree_t { +struct rbtree_type { /** The root of the red-black tree */ - rbnode_t *root; + rbnode_type *root; /** The number of the nodes in the tree */ - size_t count; + size_t count; /** * Key compare function. <0,0,>0 like strcmp. @@ -92,14 +92,14 @@ struct rbtree_t { * @param cmpf: compare function (like strcmp) takes pointers to two keys. * @return: new tree, empty. */ -rbtree_t *rbtree_create(int (*cmpf)(const void *, const void *)); +rbtree_type *rbtree_create(int (*cmpf)(const void *, const void *)); /** * Init a new tree (malloced by caller) with given key compare function. * @param rbtree: uninitialised memory for new tree, returned empty. * @param cmpf: compare function (like strcmp) takes pointers to two keys. */ -void rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *)); +void rbtree_init(rbtree_type *rbtree, int (*cmpf)(const void *, const void *)); /** * Insert data into the tree. @@ -107,7 +107,7 @@ void rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *)); * @param data: element to insert. * @return: data ptr or NULL if key already present. */ -rbnode_t *rbtree_insert(rbtree_t *rbtree, rbnode_t *data); +rbnode_type *rbtree_insert(rbtree_type *rbtree, rbnode_type *data); /** * Delete element from tree. @@ -116,7 +116,7 @@ rbnode_t *rbtree_insert(rbtree_t *rbtree, rbnode_t *data); * @return: node that is now unlinked from the tree. User to delete it. * returns 0 if node not present */ -rbnode_t *rbtree_delete(rbtree_t *rbtree, const void *key); +rbnode_type *rbtree_delete(rbtree_type *rbtree, const void *key); /** * Find key in tree. Returns NULL if not found. @@ -124,7 +124,7 @@ rbnode_t *rbtree_delete(rbtree_t *rbtree, const void *key); * @param key: key that must match. * @return: node that fits or NULL. */ -rbnode_t *rbtree_search(rbtree_t *rbtree, const void *key); +rbnode_type *rbtree_search(rbtree_type *rbtree, const void *key); /** * Find, but match does not have to be exact. @@ -135,45 +135,45 @@ rbnode_t *rbtree_search(rbtree_t *rbtree, const void *key); * @return: true if exact match in result. Else result points to <= element, * or NULL if key is smaller than the smallest key. */ -int rbtree_find_less_equal(rbtree_t *rbtree, const void *key, - rbnode_t **result); +int rbtree_find_less_equal(rbtree_type *rbtree, const void *key, + rbnode_type **result); /** * Returns first (smallest) node in the tree * @param rbtree: tree * @return: smallest element or NULL if tree empty. */ -rbnode_t *rbtree_first(rbtree_t *rbtree); +rbnode_type *rbtree_first(rbtree_type *rbtree); /** * Returns last (largest) node in the tree * @param rbtree: tree * @return: largest element or NULL if tree empty. */ -rbnode_t *rbtree_last(rbtree_t *rbtree); +rbnode_type *rbtree_last(rbtree_type *rbtree); /** * Returns next larger node in the tree * @param rbtree: tree * @return: next larger element or NULL if no larger in tree. */ -rbnode_t *rbtree_next(rbnode_t *rbtree); +rbnode_type *rbtree_next(rbnode_type *rbtree); /** * Returns previous smaller node in the tree * @param rbtree: tree * @return: previous smaller element or NULL if no previous in tree. */ -rbnode_t *rbtree_previous(rbnode_t *rbtree); +rbnode_type *rbtree_previous(rbnode_type *rbtree); /** - * Call with node=variable of struct* with rbnode_t as first element. + * Call with node=variable of struct* with rbnode_type as first element. * with type is the type of a pointer to that struct. */ #define RBTREE_FOR(node, type, rbtree) \ for(node=(type)rbtree_first(rbtree); \ - (rbnode_t*)node != RBTREE_NULL; \ - node = (type)rbtree_next((rbnode_t*)node)) + (rbnode_type*)node != RBTREE_NULL; \ + node = (type)rbtree_next((rbnode_type*)node)) /** * Call function for all elements in the redblack tree, such that @@ -186,7 +186,7 @@ rbnode_t *rbtree_previous(rbnode_t *rbtree); * The function must not alter the rbtree. * @param arg: user argument. */ -void traverse_postorder(rbtree_t* tree, void (*func)(rbnode_t*, void*), +void traverse_postorder(rbtree_type* tree, void (*func)(rbnode_type*, void*), void* arg); #endif /* UTIL_RBTREE_H_ */ diff --git a/usr.sbin/unbound/util/storage/dnstree.c b/usr.sbin/unbound/util/storage/dnstree.c index 003e8af3ef3..190369d851c 100644 --- a/usr.sbin/unbound/util/storage/dnstree.c +++ b/usr.sbin/unbound/util/storage/dnstree.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -71,17 +71,17 @@ int addr_tree_compare(const void* k1, const void* k2) return 0; } -void name_tree_init(rbtree_t* tree) +void name_tree_init(rbtree_type* tree) { rbtree_init(tree, &name_tree_compare); } -void addr_tree_init(rbtree_t* tree) +void addr_tree_init(rbtree_type* tree) { rbtree_init(tree, &addr_tree_compare); } -int name_tree_insert(rbtree_t* tree, struct name_tree_node* node, +int name_tree_insert(rbtree_type* tree, struct name_tree_node* node, uint8_t* name, size_t len, int labs, uint16_t dclass) { node->node.key = node; @@ -93,7 +93,7 @@ int name_tree_insert(rbtree_t* tree, struct name_tree_node* node, return rbtree_insert(tree, &node->node) != NULL; } -int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node, +int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node, struct sockaddr_storage* addr, socklen_t addrlen, int net) { node->node.key = node; @@ -104,7 +104,7 @@ int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node, return rbtree_insert(tree, &node->node) != NULL; } -void addr_tree_init_parents(rbtree_t* tree) +void addr_tree_init_parents(rbtree_type* tree) { struct addr_tree_node* node, *prev = NULL, *p; int m; @@ -130,7 +130,7 @@ void addr_tree_init_parents(rbtree_t* tree) } } -void name_tree_init_parents(rbtree_t* tree) +void name_tree_init_parents(rbtree_type* tree) { struct name_tree_node* node, *prev = NULL, *p; int m; @@ -156,7 +156,7 @@ void name_tree_init_parents(rbtree_t* tree) } } -struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name, +struct name_tree_node* name_tree_find(rbtree_type* tree, uint8_t* name, size_t len, int labs, uint16_t dclass) { struct name_tree_node key; @@ -168,10 +168,10 @@ struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name, return (struct name_tree_node*)rbtree_search(tree, &key); } -struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name, +struct name_tree_node* name_tree_lookup(rbtree_type* tree, uint8_t* name, size_t len, int labs, uint16_t dclass) { - rbnode_t* res = NULL; + rbnode_type* res = NULL; struct name_tree_node *result; struct name_tree_node key; key.node.key = &key; @@ -200,10 +200,10 @@ struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name, return result; } -struct addr_tree_node* addr_tree_lookup(rbtree_t* tree, +struct addr_tree_node* addr_tree_lookup(rbtree_type* tree, struct sockaddr_storage* addr, socklen_t addrlen) { - rbnode_t* res = NULL; + rbnode_type* res = NULL; struct addr_tree_node* result; struct addr_tree_node key; key.node.key = &key; @@ -231,11 +231,24 @@ struct addr_tree_node* addr_tree_lookup(rbtree_t* tree, return result; } +struct addr_tree_node* addr_tree_find(rbtree_type* tree, + struct sockaddr_storage* addr, socklen_t addrlen, int net) +{ + rbnode_type* res = NULL; + struct addr_tree_node key; + key.node.key = &key; + memcpy(&key.addr, addr, addrlen); + key.addrlen = addrlen; + key.net = net; + res = rbtree_search(tree, &key); + return (struct addr_tree_node*)res; +} + int -name_tree_next_root(rbtree_t* tree, uint16_t* dclass) +name_tree_next_root(rbtree_type* tree, uint16_t* dclass) { struct name_tree_node key; - rbnode_t* n; + rbnode_type* n; struct name_tree_node* p; if(*dclass == 0) { /* first root item is first item in tree */ diff --git a/usr.sbin/unbound/util/storage/dnstree.h b/usr.sbin/unbound/util/storage/dnstree.h index 3ecbd128f8c..782644b633e 100644 --- a/usr.sbin/unbound/util/storage/dnstree.h +++ b/usr.sbin/unbound/util/storage/dnstree.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -49,12 +49,12 @@ * This is not sorted canonically, but fast. * This can be looked up to obtain a closest encloser parent name. * - * The tree itself is a rbtree_t. + * The tree itself is a rbtree_type. * This is the element node put as first entry in the client structure. */ struct name_tree_node { /** rbtree node, key is this struct : dclass and name */ - rbnode_t node; + rbnode_type node; /** parent in tree */ struct name_tree_node* parent; /** name in uncompressed wireformat */ @@ -71,12 +71,12 @@ struct name_tree_node { * Tree of IP addresses. Sorted first by protocol, then by bits. * This can be looked up to obtain the enclosing subnet. * - * The tree itself is a rbtree_t. + * The tree itself is a rbtree_type. * This is the element node put as first entry in the client structure. */ struct addr_tree_node { /** rbtree node, key is this struct : proto and subnet */ - rbnode_t node; + rbnode_type node; /** parent in tree */ struct addr_tree_node* parent; /** address */ @@ -91,7 +91,7 @@ struct addr_tree_node { * Init a name tree to be empty * @param tree: to init. */ -void name_tree_init(rbtree_t* tree); +void name_tree_init(rbtree_type* tree); /** * insert element into name tree. @@ -105,7 +105,7 @@ void name_tree_init(rbtree_t* tree); * @param dclass: class of name * @return false on error (duplicate element). */ -int name_tree_insert(rbtree_t* tree, struct name_tree_node* node, +int name_tree_insert(rbtree_type* tree, struct name_tree_node* node, uint8_t* name, size_t len, int labs, uint16_t dclass); /** @@ -113,7 +113,7 @@ int name_tree_insert(rbtree_t* tree, struct name_tree_node* node, * Should be performed after insertions are done, before lookups * @param tree: name tree */ -void name_tree_init_parents(rbtree_t* tree); +void name_tree_init_parents(rbtree_type* tree); /** * Lookup exact match in name tree @@ -124,7 +124,7 @@ void name_tree_init_parents(rbtree_t* tree); * @param dclass: class of name * @return node or NULL if not found. */ -struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name, +struct name_tree_node* name_tree_find(rbtree_type* tree, uint8_t* name, size_t len, int labs, uint16_t dclass); /** @@ -136,7 +136,7 @@ struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name, * @param dclass: class of name * @return closest enclosing node (could be equal) or NULL if not found. */ -struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name, +struct name_tree_node* name_tree_lookup(rbtree_type* tree, uint8_t* name, size_t len, int labs, uint16_t dclass); /** @@ -145,13 +145,13 @@ struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name, * @param dclass: the class to look for next (or higher). * @return false if no classes found, true means class put into c. */ -int name_tree_next_root(rbtree_t* tree, uint16_t* dclass); +int name_tree_next_root(rbtree_type* tree, uint16_t* dclass); /** * Init addr tree to be empty. * @param tree: to init. */ -void addr_tree_init(rbtree_t* tree); +void addr_tree_init(rbtree_type* tree); /** * insert element into addr tree. @@ -163,7 +163,7 @@ void addr_tree_init(rbtree_t* tree); * @param net: size of subnet. * @return false on error (duplicate element). */ -int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node, +int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node, struct sockaddr_storage* addr, socklen_t addrlen, int net); /** @@ -171,7 +171,7 @@ int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node, * Should be performed after insertions are done, before lookups * @param tree: addr tree */ -void addr_tree_init_parents(rbtree_t* tree); +void addr_tree_init_parents(rbtree_type* tree); /** * Lookup closest encloser in addr tree. @@ -180,9 +180,20 @@ void addr_tree_init_parents(rbtree_t* tree); * @param addrlen: length of addr * @return closest enclosing node (could be equal) or NULL if not found. */ -struct addr_tree_node* addr_tree_lookup(rbtree_t* tree, +struct addr_tree_node* addr_tree_lookup(rbtree_type* tree, struct sockaddr_storage* addr, socklen_t addrlen); +/** + * Find element in addr tree. (search a netblock, not a match for an address) + * @param tree: addr tree + * @param addr: netblock to lookup. + * @param addrlen: length of addr + * @param net: size of subnet + * @return addr tree element, or NULL if not found. + */ +struct addr_tree_node* addr_tree_find(rbtree_type* tree, + struct sockaddr_storage* addr, socklen_t addrlen, int net); + /** compare name tree nodes */ int name_tree_compare(const void* k1, const void* k2); diff --git a/usr.sbin/unbound/util/storage/lookup3.c b/usr.sbin/unbound/util/storage/lookup3.c index ddcb56e7470..e9b05af37e3 100644 --- a/usr.sbin/unbound/util/storage/lookup3.c +++ b/usr.sbin/unbound/util/storage/lookup3.c @@ -820,7 +820,7 @@ uint32_t hashbig( const void *key, size_t length, uint32_t initval) #ifdef SELF_TEST /* used for timings */ -void driver1() +void driver1(void) { uint8_t buf[256]; uint32_t i; @@ -842,7 +842,7 @@ void driver1() #define HASHLEN 1 #define MAXPAIR 60 #define MAXLEN 70 -void driver2() +void driver2(void) { uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; @@ -912,7 +912,7 @@ void driver2() } /* Check for reading beyond the end of the buffer and alignment problems */ -void driver3() +void driver3(void) { uint8_t buf[MAXLEN+20], *b; uint32_t len; @@ -1003,7 +1003,7 @@ void driver3() } /* check for problems with nulls */ - void driver4() + void driver4(void) { uint8_t buf[1]; uint32_t h,i,state[HASHSTATE]; @@ -1020,7 +1020,7 @@ void driver3() } -int main() +int main(void) { driver1(); /* test that the key is hashed: used for timings */ driver2(); /* test that whole key is hashed thoroughly */ diff --git a/usr.sbin/unbound/util/storage/lruhash.c b/usr.sbin/unbound/util/storage/lruhash.c index c22278dda1e..97e99960562 100644 --- a/usr.sbin/unbound/util/storage/lruhash.c +++ b/usr.sbin/unbound/util/storage/lruhash.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -59,9 +59,10 @@ bin_init(struct lruhash_bin* array, size_t size) } struct lruhash* -lruhash_create(size_t start_size, size_t maxmem, lruhash_sizefunc_t sizefunc, - lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc, - lruhash_deldatafunc_t deldatafunc, void* arg) +lruhash_create(size_t start_size, size_t maxmem, + lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc, + lruhash_delkeyfunc_type delkeyfunc, + lruhash_deldatafunc_type deldatafunc, void* arg) { struct lruhash* table = (struct lruhash*)calloc(1, sizeof(struct lruhash)); @@ -215,7 +216,7 @@ reclaim_space(struct lruhash* table, struct lruhash_entry** list) struct lruhash_entry* bin_find_entry(struct lruhash* table, - struct lruhash_bin* bin, hashvalue_t hash, void* key) + struct lruhash_bin* bin, hashvalue_type hash, void* key) { struct lruhash_entry* p = bin->overflow_list; while(p) { @@ -296,7 +297,7 @@ lru_touch(struct lruhash* table, struct lruhash_entry* entry) } void -lruhash_insert(struct lruhash* table, hashvalue_t hash, +lruhash_insert(struct lruhash* table, hashvalue_type hash, struct lruhash_entry* entry, void* data, void* cb_arg) { struct lruhash_bin* bin; @@ -352,7 +353,7 @@ lruhash_insert(struct lruhash* table, hashvalue_t hash, } struct lruhash_entry* -lruhash_lookup(struct lruhash* table, hashvalue_t hash, void* key, int wr) +lruhash_lookup(struct lruhash* table, hashvalue_type hash, void* key, int wr) { struct lruhash_entry* entry; struct lruhash_bin* bin; @@ -374,7 +375,7 @@ lruhash_lookup(struct lruhash* table, hashvalue_t hash, void* key, int wr) } void -lruhash_remove(struct lruhash* table, hashvalue_t hash, void* key) +lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key) { struct lruhash_entry* entry; struct lruhash_bin* bin; @@ -512,7 +513,7 @@ lruhash_get_mem(struct lruhash* table) } void -lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md) +lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md) { lock_quick_lock(&table->lock); table->markdelfunc = md; diff --git a/usr.sbin/unbound/util/storage/lruhash.h b/usr.sbin/unbound/util/storage/lruhash.h index d0efe2d3b59..c3937408232 100644 --- a/usr.sbin/unbound/util/storage/lruhash.h +++ b/usr.sbin/unbound/util/storage/lruhash.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -116,7 +116,7 @@ struct lruhash_entry; #define HASH_DEFAULT_MAXMEM 4*1024*1024 /* bytes */ /** the type of a hash value */ -typedef uint32_t hashvalue_t; +typedef uint32_t hashvalue_type; /** * Type of function that calculates the size of an entry. @@ -124,39 +124,39 @@ typedef uint32_t hashvalue_t; * Keys that are identical must also calculate to the same size. * size = func(key, data). */ -typedef size_t (*lruhash_sizefunc_t)(void*, void*); +typedef size_t (*lruhash_sizefunc_type)(void*, void*); /** type of function that compares two keys. return 0 if equal. */ -typedef int (*lruhash_compfunc_t)(void*, void*); +typedef int (*lruhash_compfunc_type)(void*, void*); /** old keys are deleted. * The RRset type has to revoke its ID number, markdel() is used first. * This function is called: func(key, userarg) */ -typedef void (*lruhash_delkeyfunc_t)(void*, void*); +typedef void (*lruhash_delkeyfunc_type)(void*, void*); /** old data is deleted. This function is called: func(data, userarg). */ -typedef void (*lruhash_deldatafunc_t)(void*, void*); +typedef void (*lruhash_deldatafunc_type)(void*, void*); /** mark a key as pending to be deleted (and not to be used by anyone). * called: func(key) */ -typedef void (*lruhash_markdelfunc_t)(void*); +typedef void (*lruhash_markdelfunc_type)(void*); /** * Hash table that keeps LRU list of entries. */ struct lruhash { /** lock for exclusive access, to the lookup array */ - lock_quick_t lock; + lock_quick_type lock; /** the size function for entries in this table */ - lruhash_sizefunc_t sizefunc; + lruhash_sizefunc_type sizefunc; /** the compare function for entries in this table. */ - lruhash_compfunc_t compfunc; + lruhash_compfunc_type compfunc; /** how to delete keys. */ - lruhash_delkeyfunc_t delkeyfunc; + lruhash_delkeyfunc_type delkeyfunc; /** how to delete data. */ - lruhash_deldatafunc_t deldatafunc; + lruhash_deldatafunc_type deldatafunc; /** how to mark a key pending deletion */ - lruhash_markdelfunc_t markdelfunc; + lruhash_markdelfunc_type markdelfunc; /** user argument for user functions */ void* cb_arg; @@ -188,7 +188,7 @@ struct lruhash_bin { * Lock for exclusive access to the linked list * This lock makes deletion of items safe in this overflow list. */ - lock_quick_t lock; + lock_quick_type lock; /** linked list of overflow entries */ struct lruhash_entry* overflow_list; }; @@ -207,7 +207,7 @@ struct lruhash_entry { * Even with a writelock, you cannot change hash and key. * You need to delete it to change hash or key. */ - lock_rw_t lock; + lock_rw_type lock; /** next entry in overflow chain. Covered by hashlock and binlock. */ struct lruhash_entry* overflow_next; /** next entry in lru chain. covered by hashlock. */ @@ -215,7 +215,7 @@ struct lruhash_entry { /** prev entry in lru chain. covered by hashlock. */ struct lruhash_entry* lru_prev; /** hash value of the key. It may not change, until entry deleted. */ - hashvalue_t hash; + hashvalue_type hash; /** key */ void* key; /** data */ @@ -236,9 +236,9 @@ struct lruhash_entry { * @return: new hash table or NULL on malloc failure. */ struct lruhash* lruhash_create(size_t start_size, size_t maxmem, - lruhash_sizefunc_t sizefunc, lruhash_compfunc_t compfunc, - lruhash_delkeyfunc_t delkeyfunc, lruhash_deldatafunc_t deldatafunc, - void* arg); + lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc, + lruhash_delkeyfunc_type delkeyfunc, + lruhash_deldatafunc_type deldatafunc, void* arg); /** * Delete hash table. Entries are all deleted. @@ -269,7 +269,7 @@ void lruhash_clear(struct lruhash* table); * @param data: the data. * @param cb_override: if not null overrides the cb_arg for the deletefunc. */ -void lruhash_insert(struct lruhash* table, hashvalue_t hash, +void lruhash_insert(struct lruhash* table, hashvalue_type hash, struct lruhash_entry* entry, void* data, void* cb_override); /** @@ -285,8 +285,8 @@ void lruhash_insert(struct lruhash* table, hashvalue_t hash, * @return: pointer to the entry or NULL. The entry is locked. * The user must unlock the entry when done. */ -struct lruhash_entry* lruhash_lookup(struct lruhash* table, hashvalue_t hash, - void* key, int wr); +struct lruhash_entry* lruhash_lookup(struct lruhash* table, + hashvalue_type hash, void* key, int wr); /** * Touch entry, so it becomes the most recently used in the LRU list. @@ -299,7 +299,7 @@ void lru_touch(struct lruhash* table, struct lruhash_entry* entry); /** * Set the markdelfunction (or NULL) */ -void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md); +void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md); /************************* Internal functions ************************/ /*** these are only exposed for unit tests. ***/ @@ -311,7 +311,7 @@ void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md); * @param hash: hash of key. * @param key: what to look for. */ -void lruhash_remove(struct lruhash* table, hashvalue_t hash, void* key); +void lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key); /** init the hash bins for the table */ void bin_init(struct lruhash_bin* array, size_t size); @@ -328,7 +328,7 @@ void bin_delete(struct lruhash* table, struct lruhash_bin* bin); * @return: the entry or NULL if not found. */ struct lruhash_entry* bin_find_entry(struct lruhash* table, - struct lruhash_bin* bin, hashvalue_t hash, void* key); + struct lruhash_bin* bin, hashvalue_type hash, void* key); /** * Remove entry from bin overflow chain. diff --git a/usr.sbin/unbound/util/storage/slabhash.c b/usr.sbin/unbound/util/storage/slabhash.c index 9c0c5071175..ae63b97727e 100644 --- a/usr.sbin/unbound/util/storage/slabhash.c +++ b/usr.sbin/unbound/util/storage/slabhash.c @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -46,9 +46,9 @@ #include "util/storage/slabhash.h" struct slabhash* slabhash_create(size_t numtables, size_t start_size, - size_t maxmem, lruhash_sizefunc_t sizefunc, - lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc, - lruhash_deldatafunc_t deldatafunc, void* arg) + size_t maxmem, lruhash_sizefunc_type sizefunc, + lruhash_compfunc_type compfunc, lruhash_delkeyfunc_type delkeyfunc, + lruhash_deldatafunc_type deldatafunc, void* arg) { size_t i; struct slabhash* sl = (struct slabhash*)calloc(1, @@ -108,24 +108,24 @@ void slabhash_clear(struct slabhash* sl) /** helper routine to calculate the slabhash index */ static unsigned int -slab_idx(struct slabhash* sl, hashvalue_t hash) +slab_idx(struct slabhash* sl, hashvalue_type hash) { return ((hash & sl->mask) >> sl->shift); } -void slabhash_insert(struct slabhash* sl, hashvalue_t hash, +void slabhash_insert(struct slabhash* sl, hashvalue_type hash, struct lruhash_entry* entry, void* data, void* arg) { lruhash_insert(sl->array[slab_idx(sl, hash)], hash, entry, data, arg); } struct lruhash_entry* slabhash_lookup(struct slabhash* sl, - hashvalue_t hash, void* key, int wr) + hashvalue_type hash, void* key, int wr) { return lruhash_lookup(sl->array[slab_idx(sl, hash)], hash, key, wr); } -void slabhash_remove(struct slabhash* sl, hashvalue_t hash, void* key) +void slabhash_remove(struct slabhash* sl, hashvalue_type hash, void* key) { lruhash_remove(sl->array[slab_idx(sl, hash)], hash, key); } @@ -163,7 +163,7 @@ size_t slabhash_get_mem(struct slabhash* sl) return total; } -struct lruhash* slabhash_gettable(struct slabhash* sl, hashvalue_t hash) +struct lruhash* slabhash_gettable(struct slabhash* sl, hashvalue_type hash) { return sl->array[slab_idx(sl, hash)]; } @@ -202,7 +202,7 @@ void test_slabhash_deldata(void* data, void* ATTR_UNUSED(arg)) deldata((struct slabhash_testdata*)data); } -void slabhash_setmarkdel(struct slabhash* sl, lruhash_markdelfunc_t md) +void slabhash_setmarkdel(struct slabhash* sl, lruhash_markdelfunc_type md) { size_t i; for(i=0; i<sl->size; i++) { @@ -211,9 +211,21 @@ void slabhash_setmarkdel(struct slabhash* sl, lruhash_markdelfunc_t md) } void slabhash_traverse(struct slabhash* sh, int wr, - void (*func)(struct lruhash_entry*, void*), void* arg) + void (*func)(struct lruhash_entry*, void*), void* arg) { size_t i; for(i=0; i<sh->size; i++) lruhash_traverse(sh->array[i], wr, func, arg); } + +size_t count_slabhash_entries(struct slabhash* sh) +{ + size_t slab, cnt = 0; + + for(slab=0; slab<sh->size; slab++) { + lock_quick_lock(&sh->array[slab]->lock); + cnt += sh->array[slab]->num; + lock_quick_unlock(&sh->array[slab]->lock); + } + return cnt; +} diff --git a/usr.sbin/unbound/util/storage/slabhash.h b/usr.sbin/unbound/util/storage/slabhash.h index 93228febcfe..d00983fc155 100644 --- a/usr.sbin/unbound/util/storage/slabhash.h +++ b/usr.sbin/unbound/util/storage/slabhash.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -80,9 +80,9 @@ struct slabhash { * @return: new hash table or NULL on malloc failure. */ struct slabhash* slabhash_create(size_t numtables, size_t start_size, - size_t maxmem, lruhash_sizefunc_t sizefunc, - lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc, - lruhash_deldatafunc_t deldatafunc, void* arg); + size_t maxmem, lruhash_sizefunc_type sizefunc, + lruhash_compfunc_type compfunc, lruhash_delkeyfunc_type delkeyfunc, + lruhash_deldatafunc_type deldatafunc, void* arg); /** * Delete hash table. Entries are all deleted. @@ -109,7 +109,7 @@ void slabhash_clear(struct slabhash* table); * @param data: the data. * @param cb_override: if not NULL overrides the cb_arg for deletfunc. */ -void slabhash_insert(struct slabhash* table, hashvalue_t hash, +void slabhash_insert(struct slabhash* table, hashvalue_type hash, struct lruhash_entry* entry, void* data, void* cb_override); /** @@ -126,7 +126,7 @@ void slabhash_insert(struct slabhash* table, hashvalue_t hash, * The user must unlock the entry when done. */ struct lruhash_entry* slabhash_lookup(struct slabhash* table, - hashvalue_t hash, void* key, int wr); + hashvalue_type hash, void* key, int wr); /** * Remove entry from hashtable. Does nothing if not found in hashtable. @@ -135,7 +135,7 @@ struct lruhash_entry* slabhash_lookup(struct slabhash* table, * @param hash: hash of key. * @param key: what to look for. */ -void slabhash_remove(struct slabhash* table, hashvalue_t hash, void* key); +void slabhash_remove(struct slabhash* table, hashvalue_type hash, void* key); /** * Output debug info to the log as to state of the hash table. @@ -165,14 +165,14 @@ size_t slabhash_get_mem(struct slabhash* table); * @param hash: hash value. * @return the lru hash table. */ -struct lruhash* slabhash_gettable(struct slabhash* table, hashvalue_t hash); +struct lruhash* slabhash_gettable(struct slabhash* table, hashvalue_type hash); /** * Set markdel function * @param table: slabbed hash table. * @param md: markdel function ptr. */ -void slabhash_setmarkdel(struct slabhash* table, lruhash_markdelfunc_t md); +void slabhash_setmarkdel(struct slabhash* table, lruhash_markdelfunc_type md); /** * Traverse a slabhash. @@ -184,6 +184,13 @@ void slabhash_setmarkdel(struct slabhash* table, lruhash_markdelfunc_t md); void slabhash_traverse(struct slabhash* table, int wr, void (*func)(struct lruhash_entry*, void*), void* arg); +/* + * Count entries in slabhash. + * @param table: slabbed hash table; + * @return the number of items + */ +size_t count_slabhash_entries(struct slabhash* table); + /* --- test representation --- */ /** test structure contains test key */ struct slabhash_testkey { diff --git a/usr.sbin/unbound/util/tube.c b/usr.sbin/unbound/util/tube.c index e525f1ccd8a..f42d22cb3f2 100644 --- a/usr.sbin/unbound/util/tube.c +++ b/usr.sbin/unbound/util/tube.c @@ -426,7 +426,7 @@ int tube_read_fd(struct tube* tube) } int tube_setup_bg_listen(struct tube* tube, struct comm_base* base, - tube_callback_t* cb, void* arg) + tube_callback_type* cb, void* arg) { tube->listen_cb = cb; tube->listen_arg = arg; @@ -667,7 +667,7 @@ tube_handle_write(struct comm_point* ATTR_UNUSED(c), void* ATTR_UNUSED(arg), } int tube_setup_bg_listen(struct tube* tube, struct comm_base* base, - tube_callback_t* cb, void* arg) + tube_callback_type* cb, void* arg) { tube->listen_cb = cb; tube->listen_arg = arg; diff --git a/usr.sbin/unbound/util/tube.h b/usr.sbin/unbound/util/tube.h index 7971b776ae1..5b1fdb8e8f4 100644 --- a/usr.sbin/unbound/util/tube.h +++ b/usr.sbin/unbound/util/tube.h @@ -55,7 +55,7 @@ struct tube_res_list; * void mycallback(tube, msg, len, error, user_argument); * if error is true (NETEVENT_*), msg is probably NULL. */ -typedef void tube_callback_t(struct tube*, uint8_t*, size_t, int, void*); +typedef void tube_callback_type(struct tube*, uint8_t*, size_t, int, void*); /** * A pipe @@ -70,7 +70,7 @@ struct tube { /** listen commpoint */ struct comm_point* listen_com; /** listen callback */ - tube_callback_t* listen_cb; + tube_callback_type* listen_cb; /** listen callback user arg */ void* listen_arg; /** are we currently reading a command, 0 if not, else bytecount */ @@ -92,7 +92,7 @@ struct tube { #else /* USE_WINSOCK */ /** listen callback */ - tube_callback_t* listen_cb; + tube_callback_type* listen_cb; /** listen callback user arg */ void* listen_arg; /** the windows sockets event (signaled if items in pipe) */ @@ -101,7 +101,7 @@ struct tube { struct ub_event* ev_listen; /** lock on the list of outstanding items */ - lock_basic_t res_lock; + lock_basic_type res_lock; /** list of outstanding results on pipe */ struct tube_res_list* res_list; /** last in list */ @@ -222,7 +222,7 @@ int tube_read_fd(struct tube* tube); * @return true if successful, false on error. */ int tube_setup_bg_listen(struct tube* tube, struct comm_base* base, - tube_callback_t* cb, void* arg); + tube_callback_type* cb, void* arg); /** * Remove bg listen setup from event base. diff --git a/usr.sbin/unbound/util/ub_event.c b/usr.sbin/unbound/util/ub_event.c index af2a18ea0fc..3b92be1a302 100644 --- a/usr.sbin/unbound/util/ub_event.c +++ b/usr.sbin/unbound/util/ub_event.c @@ -132,16 +132,12 @@ static void (*NATIVE_BITS_CB(void (*cb)(int, short, void*)))(int, short, void*) #define EVFLAG_AUTO 0 #endif -#define AS_EVENT_BASE(x) \ - (((union {struct ub_event_base* a; struct event_base* b;})x).b) -#define AS_UB_EVENT_BASE(x) \ - (((union {struct event_base* a; struct ub_event_base* b;})x).b) -#define AS_EVENT(x) \ - (((union {struct ub_event* a; struct event* b;})x).b) -#define AS_UB_EVENT(x) \ - (((union {struct event* a; struct ub_event* b;})x).b) - -const char* ub_event_get_version() +#define AS_EVENT_BASE(x) ((struct event_base*)x) +#define AS_UB_EVENT_BASE(x) ((struct ub_event_base*)x) +#define AS_EVENT(x) ((struct event*)x) +#define AS_UB_EVENT(x) ((struct ub_event*)x) + +const char* ub_event_get_version(void) { return event_get_version(); } diff --git a/usr.sbin/unbound/util/ub_event.h b/usr.sbin/unbound/util/ub_event.h index cb42e7a7d23..9739e6d833e 100644 --- a/usr.sbin/unbound/util/ub_event.h +++ b/usr.sbin/unbound/util/ub_event.h @@ -63,7 +63,7 @@ struct event_base; * daemon compile, and will be "pluggable-event<PACKAGE_VERSION>" for * libunbound. */ -const char* ub_event_get_version(); +const char* ub_event_get_version(void); /** Return the name, system and method for the pluggable event base */ void ub_get_event_sys(struct ub_event_base*, const char** n, const char** s, const char** m); diff --git a/usr.sbin/unbound/util/ub_event_pluggable.c b/usr.sbin/unbound/util/ub_event_pluggable.c index 5c517555e71..4a9451263b7 100644 --- a/usr.sbin/unbound/util/ub_event_pluggable.c +++ b/usr.sbin/unbound/util/ub_event_pluggable.c @@ -144,12 +144,10 @@ struct my_event { struct event ev; }; -#define AS_MY_EVENT_BASE(x) \ - (((union {struct ub_event_base* a; struct my_event_base* b;})x).b) -#define AS_MY_EVENT(x) \ - (((union {struct ub_event* a; struct my_event* b;})x).b) +#define AS_MY_EVENT_BASE(x) ((struct my_event_base*)x) +#define AS_MY_EVENT(x) ((struct my_event*)x) -const char* ub_event_get_version() +const char* ub_event_get_version(void) { return "pluggable-event"PACKAGE_VERSION; } @@ -597,7 +595,7 @@ ub_event_add(struct ub_event* ev, struct timeval* tv) int ub_event_del(struct ub_event* ev) { - if (ev->magic == UB_EVENT_MAGIC) { + if (ev && ev->magic == UB_EVENT_MAGIC) { fptr_ok(ev->vmt != &default_event_vmt || ev->vmt->del == my_event_del); return (*ev->vmt->del)(ev); @@ -620,7 +618,7 @@ ub_timer_add(struct ub_event* ev, struct ub_event_base* base, int ub_timer_del(struct ub_event* ev) { - if (ev->magic == UB_EVENT_MAGIC) { + if (ev && ev->magic == UB_EVENT_MAGIC) { fptr_ok(ev->vmt != &default_event_vmt || ev->vmt->del_timer == my_timer_del); return (*ev->vmt->del_timer)(ev); @@ -642,7 +640,7 @@ ub_signal_add(struct ub_event* ev, struct timeval* tv) int ub_signal_del(struct ub_event* ev) { - if (ev->magic == UB_EVENT_MAGIC) { + if (ev && ev->magic == UB_EVENT_MAGIC) { fptr_ok(ev->vmt != &default_event_vmt || ev->vmt->del_signal == my_signal_del); return (*ev->vmt->del_signal)(ev); @@ -653,7 +651,7 @@ ub_signal_del(struct ub_event* ev) void ub_winsock_unregister_wsaevent(struct ub_event* ev) { - if (ev->magic == UB_EVENT_MAGIC) { + if (ev && ev->magic == UB_EVENT_MAGIC) { fptr_ok(ev->vmt != &default_event_vmt || ev->vmt->winsock_unregister_wsaevent == my_winsock_unregister_wsaevent); diff --git a/usr.sbin/unbound/util/winsock_event.c b/usr.sbin/unbound/util/winsock_event.c index 40b79821a47..63d98796d19 100644 --- a/usr.sbin/unbound/util/winsock_event.c +++ b/usr.sbin/unbound/util/winsock_event.c @@ -169,7 +169,7 @@ static void handle_timeouts(struct event_base* base, struct timeval* now, #endif verbose(VERB_CLIENT, "winsock_event handle_timeouts"); - while((rbnode_t*)(p = (struct event*)rbtree_first(base->times)) + while((rbnode_type*)(p = (struct event*)rbtree_first(base->times)) !=RBTREE_NULL) { #ifndef S_SPLINT_S if(p->ev_timeout.tv_sec > now->tv_sec || @@ -262,8 +262,9 @@ static int handle_select(struct event_base* base, struct timeval* wait) break; /* sanity check */ } log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS); - verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%x " - "timeout=%d", base->max, numwait, (int)wait, (int)timeout); + verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%s " + "timeout=%d", base->max, numwait, (wait?"<wait>":"<null>"), + (int)timeout); /* do the wait */ if(numwait == 0) { diff --git a/usr.sbin/unbound/util/winsock_event.h b/usr.sbin/unbound/util/winsock_event.h index d386a699fa5..d6dafac8c5c 100644 --- a/usr.sbin/unbound/util/winsock_event.h +++ b/usr.sbin/unbound/util/winsock_event.h @@ -132,7 +132,7 @@ struct event_base { /** sorted by timeout (absolute), ptr */ - rbtree_t* times; + rbtree_type* times; /** array (first part in use) of handles to work on */ struct event** items; /** number of items in use in array */ @@ -169,7 +169,7 @@ struct event_base */ struct event { /** node in timeout rbtree */ - rbnode_t node; + rbnode_type node; /** is event already added */ int added; diff --git a/usr.sbin/unbound/validator/autotrust.c b/usr.sbin/unbound/validator/autotrust.c index 232397c3106..a533733c7a6 100644 --- a/usr.sbin/unbound/validator/autotrust.c +++ b/usr.sbin/unbound/validator/autotrust.c @@ -430,6 +430,8 @@ find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, } tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr, rr_len, dname_len)); + if(!tp) + return NULL; lock_basic_lock(&tp->lock); return tp; } @@ -1062,7 +1064,7 @@ int autr_read_file(struct val_anchors* anchors, const char* nm) /** string for a trustanchor state */ static const char* -trustanchor_state2str(autr_state_t s) +trustanchor_state2str(autr_state_type s) { switch (s) { case AUTR_STATE_START: return " START "; @@ -1201,7 +1203,7 @@ void autr_write_file(struct module_env* env, struct trust_anchor* tp) if(fsync(fileno(out)) != 0) log_err("could not fsync(%s): %s", fname, strerror(errno)); #else - FlushFileBuffers((HANDLE)_fileno(out)); + FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); #endif if(fclose(out) != 0) { fatal_exit("could not complete write: %s: %s", @@ -1677,7 +1679,7 @@ reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed) /** Set the state for this trust anchor */ static void set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed, - autr_state_t s) + autr_state_type s) { verbose_key(ta, VERB_ALGO, "update: %s to %s", trustanchor_state2str(ta->s), trustanchor_state2str(s)); @@ -1987,7 +1989,7 @@ calc_next_probe(struct module_env* env, time_t wait) static time_t wait_probe_time(struct val_anchors* anchors) { - rbnode_t* t = rbtree_first(&anchors->autr->probe); + rbnode_type* t = rbtree_first(&anchors->autr->probe); if(t != RBTREE_NULL) return ((struct trust_anchor*)t->key)->autr->next_probe_time; return 0; @@ -2326,6 +2328,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) qinfo.qname_len = tp->namelen; qinfo.qtype = LDNS_RR_TYPE_DNSKEY; qinfo.qclass = tp->dclass; + qinfo.local_alias = NULL; log_query_info(VERB_ALGO, "autotrust probe", &qinfo); verbose(VERB_ALGO, "retry probe set in %d seconds", (int)tp->autr->next_probe_time - (int)*env->now); @@ -2360,7 +2363,7 @@ static struct trust_anchor* todo_probe(struct module_env* env, time_t* next) { struct trust_anchor* tp; - rbnode_t* el; + rbnode_type* el; /* get first one */ lock_basic_lock(&env->anchors->lock); if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { diff --git a/usr.sbin/unbound/validator/autotrust.h b/usr.sbin/unbound/validator/autotrust.h index 4e88ed32042..dbaf5126a0b 100644 --- a/usr.sbin/unbound/validator/autotrust.h +++ b/usr.sbin/unbound/validator/autotrust.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -48,6 +48,7 @@ struct trust_anchor; struct ub_packed_rrset_key; struct module_env; struct val_env; +struct sldns_buffer; /** Autotrust anchor states */ typedef enum { @@ -57,7 +58,7 @@ typedef enum { AUTR_STATE_MISSING = 3, AUTR_STATE_REVOKED = 4, AUTR_STATE_REMOVED = 5 -} autr_state_t; +} autr_state_type; /** * Autotrust metadata for one trust anchor key. @@ -66,11 +67,13 @@ struct autr_ta { /** next key */ struct autr_ta* next; /** the RR */ - ldns_rr* rr; + uint8_t* rr; + /** length of rr */ + size_t rr_len, dname_len; /** last update of key state (new pending count keeps date the same) */ time_t last_change; /** 5011 state */ - autr_state_t s; + autr_state_type s; /** pending count */ uint8_t pending_count; /** fresh TA was seen */ @@ -87,7 +90,7 @@ struct autr_point_data { /** file to store the trust point in. chrootdir already applied. */ char* file; /** rbtree node for probe sort, key is struct trust_anchor */ - rbnode_t pnode; + rbnode_type pnode; /** the keys */ struct autr_ta* keys; @@ -104,9 +107,9 @@ struct autr_point_data { time_t next_probe_time; /** when to query if !failed */ - uint32_t query_interval; + time_t query_interval; /** when to retry if failed */ - uint32_t retry_time; + time_t retry_time; /** * How many times did it fail. diagnostic only (has no effect). @@ -123,7 +126,7 @@ struct autr_point_data { struct autr_global_data { /** rbtree of autotrust anchors sorted by next probe time. * When time is equal, sorted by anchor class, name. */ - rbtree_t probe; + rbtree_type probe; }; /** @@ -151,7 +154,7 @@ size_t autr_get_num_anchors(struct val_anchors* anchors); * @return time of next probe (in seconds from now). * If 0, then there is no next probe anymore (trust points deleted). */ -uint32_t autr_probe_timer(struct module_env* env); +time_t autr_probe_timer(struct module_env* env); /** probe tree compare function */ int probetree_cmp(const void* x, const void* y); @@ -199,7 +202,7 @@ int autr_process_prime(struct module_env* env, struct val_env* ve, void autr_debug_print(struct val_anchors* anchors); /** callback for query answer to 5011 probe */ -void probe_answer_cb(void* arg, int rcode, ldns_buffer* buf, +void probe_answer_cb(void* arg, int rcode, struct sldns_buffer* buf, enum sec_status sec, char* errinf); #endif /* VALIDATOR_AUTOTRUST_H */ diff --git a/usr.sbin/unbound/validator/val_anchor.c b/usr.sbin/unbound/validator/val_anchor.c index 4d470b69227..2a7e0beeb6c 100644 --- a/usr.sbin/unbound/validator/val_anchor.c +++ b/usr.sbin/unbound/validator/val_anchor.c @@ -113,7 +113,7 @@ assembled_rrset_delete(struct ub_packed_rrset_key* pkey) /** destroy locks in tree and delete autotrust anchors */ static void -anchors_delfunc(rbnode_t* elem, void* ATTR_UNUSED(arg)) +anchors_delfunc(rbnode_type* elem, void* ATTR_UNUSED(arg)) { struct trust_anchor* ta = (struct trust_anchor*)elem; if(!ta) return; @@ -198,7 +198,7 @@ anchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs, size_t namelen, uint16_t dclass) { struct trust_anchor key; - rbnode_t* n; + rbnode_type* n; if(!name) return NULL; key.node.key = &key; key.name = name; @@ -222,7 +222,7 @@ anchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs, size_t namelen, uint16_t dclass, int lockit) { #ifdef UNBOUND_DEBUG - rbnode_t* r; + rbnode_type* r; #endif struct trust_anchor* ta = (struct trust_anchor*)malloc( sizeof(struct trust_anchor)); @@ -990,7 +990,7 @@ anchors_assemble_rrsets(struct val_anchors* anchors) size_t nods, nokey; lock_basic_lock(&anchors->lock); ta=(struct trust_anchor*)rbtree_first(anchors->tree); - while((rbnode_t*)ta != RBTREE_NULL) { + while((rbnode_type*)ta != RBTREE_NULL) { next = (struct trust_anchor*)rbtree_next(&ta->node); lock_basic_lock(&ta->lock); if(ta->autr || (ta->numDS == 0 && ta->numDNSKEY == 0)) { @@ -1164,7 +1164,7 @@ anchors_lookup(struct val_anchors* anchors, { struct trust_anchor key; struct trust_anchor* result; - rbnode_t* res = NULL; + rbnode_type* res = NULL; key.node.key = &key; key.name = qname; key.namelabs = dname_count_labels(qname); diff --git a/usr.sbin/unbound/validator/val_anchor.h b/usr.sbin/unbound/validator/val_anchor.h index d2f3afc43f1..226165514c5 100644 --- a/usr.sbin/unbound/validator/val_anchor.h +++ b/usr.sbin/unbound/validator/val_anchor.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -43,12 +43,12 @@ #define VALIDATOR_VAL_ANCHOR_H #include "util/rbtree.h" #include "util/locks.h" -struct regional; struct trust_anchor; struct config_file; struct ub_packed_rrset_key; struct autr_point_data; struct autr_global_data; +struct sldns_buffer; /** * Trust anchor store. @@ -59,19 +59,14 @@ struct autr_global_data; */ struct val_anchors { /** lock on trees */ - lock_basic_t lock; - /** - * region where trust anchors are allocated. - * Autotrust anchors are malloced so they can be updated. - */ - struct regional* region; + lock_basic_type lock; /** * Anchors are store in this tree. Sort order is chosen, so that * dnames are in nsec-like order. A lookup on class, name will return * an exact match of the closest match, with the ancestor needed. * contents of type trust_anchor. */ - rbtree_t* tree; + rbtree_type* tree; /** The DLV trust anchor (if one is configured, else NULL) */ struct trust_anchor* dlv_anchor; /** Autotrust global data, anchors sorted by next probe time */ @@ -98,9 +93,9 @@ struct ta_key { */ struct trust_anchor { /** rbtree node, key is this structure */ - rbnode_t node; + rbnode_type node; /** lock on the entire anchor and its keys; for autotrust changes */ - lock_basic_t lock; + lock_basic_type lock; /** name of this trust anchor */ uint8_t* name; /** length of name */ @@ -111,7 +106,6 @@ struct trust_anchor { struct trust_anchor* parent; /** * List of DS or DNSKEY rrs that form the trust anchor. - * It is allocated in the region. */ struct ta_key* keylist; /** Autotrust anchor point data, or NULL */ @@ -191,7 +185,7 @@ struct trust_anchor* anchor_find(struct val_anchors* anchors, * @return NULL on error. */ struct trust_anchor* anchor_store_str(struct val_anchors* anchors, - ldns_buffer* buffer, const char* str); + struct sldns_buffer* buffer, const char* str); /** * Get memory in use by the trust anchor storage @@ -203,4 +197,23 @@ size_t anchors_get_mem(struct val_anchors* anchors); /** compare two trust anchors */ int anchor_cmp(const void* k1, const void* k2); +/** + * Add insecure point trust anchor. For external use (locks and init_parents) + * @param anchors: anchor storage. + * @param c: class. + * @param nm: name of insecure trust point. + * @return false on alloc failure. + */ +int anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm); + +/** + * Delete insecure point trust anchor. Does not remove if no such point. + * For external use (locks and init_parents) + * @param anchors: anchor storage. + * @param c: class. + * @param nm: name of insecure trust point. + */ +void anchors_delete_insecure(struct val_anchors* anchors, uint16_t c, + uint8_t* nm); + #endif /* VALIDATOR_VAL_ANCHOR_H */ diff --git a/usr.sbin/unbound/validator/val_neg.c b/usr.sbin/unbound/validator/val_neg.c index a5e687fdc41..fe57ac2c442 100644 --- a/usr.sbin/unbound/validator/val_neg.c +++ b/usr.sbin/unbound/validator/val_neg.c @@ -111,7 +111,7 @@ size_t val_neg_get_mem(struct val_neg_cache* neg) /** clear datas on cache deletion */ static void -neg_clear_datas(rbnode_t* n, void* ATTR_UNUSED(arg)) +neg_clear_datas(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct val_neg_data* d = (struct val_neg_data*)n; free(d->name); @@ -120,7 +120,7 @@ neg_clear_datas(rbnode_t* n, void* ATTR_UNUSED(arg)) /** clear zones on cache deletion */ static void -neg_clear_zones(rbnode_t* n, void* ATTR_UNUSED(arg)) +neg_clear_zones(rbnode_type* n, void* ATTR_UNUSED(arg)) { struct val_neg_zone* z = (struct val_neg_zone*)n; /* delete all the rrset entries in the tree */ @@ -371,7 +371,7 @@ static struct val_neg_zone* neg_closest_zone_parent(struct val_neg_cache* neg, { struct val_neg_zone key; struct val_neg_zone* result; - rbnode_t* res = NULL; + rbnode_type* res = NULL; key.node.key = &key; key.name = nm; key.len = nm_len; @@ -411,7 +411,7 @@ static struct val_neg_data* neg_closest_data_parent( { struct val_neg_data key; struct val_neg_data* result; - rbnode_t* res = NULL; + rbnode_type* res = NULL; key.node.key = &key; key.name = nm; key.len = nm_len; @@ -677,7 +677,7 @@ static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone, uint8_t* end; size_t end_len; int end_labs, m; - rbnode_t* walk, *next; + rbnode_type* walk, *next; struct val_neg_data* cur; uint8_t buf[257]; /* get endpoint */ @@ -911,7 +911,7 @@ static int neg_closest_data(struct val_neg_zone* zone, uint8_t* qname, size_t len, int labs, struct val_neg_data** data) { struct val_neg_data key; - rbnode_t* r; + rbnode_type* r; key.node.key = &key; key.name = qname; key.len = len; @@ -1007,6 +1007,7 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len, qinfo.qname = qname; qinfo.qtype = LDNS_RR_TYPE_DLV; qinfo.qclass = qclass; + qinfo.local_alias = NULL; if(!nsec_proves_nodata(nsec, &qinfo, &wc) && !val_nsec_proves_name_error(nsec, qname)) { /* the NSEC is not a denial for the DLV */ diff --git a/usr.sbin/unbound/validator/val_neg.h b/usr.sbin/unbound/validator/val_neg.h index bf3a2471c78..6ae71306c37 100644 --- a/usr.sbin/unbound/validator/val_neg.h +++ b/usr.sbin/unbound/validator/val_neg.h @@ -67,9 +67,9 @@ struct ub_packed_rrset_key; struct val_neg_cache { /** the big lock on the negative cache. Because we use a rbtree * for the data (quick lookup), we need a big lock */ - lock_basic_t lock; + lock_basic_type lock; /** The zone rbtree. contents sorted canonical, type val_neg_zone */ - rbtree_t tree; + rbtree_type tree; /** the first in linked list of LRU of val_neg_data */ struct val_neg_data* first; /** last in lru (least recently used element) */ @@ -87,7 +87,7 @@ struct val_neg_cache { */ struct val_neg_zone { /** rbtree node element, key is this struct: the name, class */ - rbnode_t node; + rbnode_type node; /** name; the key */ uint8_t* name; /** length of name */ @@ -114,7 +114,7 @@ struct val_neg_zone { /** tree of NSEC data for this zone, sorted canonical * by NSEC owner name */ - rbtree_t tree; + rbtree_type tree; /** class of node; host order */ uint16_t dclass; @@ -135,7 +135,7 @@ struct val_neg_zone { */ struct val_neg_data { /** rbtree node element, key is this struct: the name */ - rbnode_t node; + rbnode_type node; /** name; the key */ uint8_t* name; /** length of name */ diff --git a/usr.sbin/unbound/validator/val_nsec.c b/usr.sbin/unbound/validator/val_nsec.c index f104a347c78..1e4f440ffc0 100644 --- a/usr.sbin/unbound/validator/val_nsec.c +++ b/usr.sbin/unbound/validator/val_nsec.c @@ -343,7 +343,7 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, } else { /* See if the next owner name covers a wildcard * empty non-terminal. */ - while (dname_strict_subdomain_c(nm, nsec->rk.dname)) { + while (dname_canonical_compare(nsec->rk.dname, nm) < 0) { /* wildcard does not apply if qname below * the name that exists under the '*' */ if (dname_subdomain_c(qinfo->qname, nm)) diff --git a/usr.sbin/unbound/validator/val_nsec3.c b/usr.sbin/unbound/validator/val_nsec3.c index 22867d170d7..4d978372aaa 100644 --- a/usr.sbin/unbound/validator/val_nsec3.c +++ b/usr.sbin/unbound/validator/val_nsec3.c @@ -623,14 +623,14 @@ nsec3_calc_b32(struct regional* region, sldns_buffer* buf, } int -nsec3_hash_name(rbtree_t* table, struct regional* region, sldns_buffer* buf, +nsec3_hash_name(rbtree_type* table, struct regional* region, sldns_buffer* buf, struct ub_packed_rrset_key* nsec3, int rr, uint8_t* dname, size_t dname_len, struct nsec3_cached_hash** hash) { struct nsec3_cached_hash* c; struct nsec3_cached_hash looki; #ifdef UNBOUND_DEBUG - rbnode_t* n; + rbnode_type* n; #endif int r; looki.node.key = &looki; @@ -730,7 +730,7 @@ nsec3_hash_matches_owner(struct nsec3_filter* flt, */ static int find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, uint8_t* nm, size_t nmlen, + rbtree_type* ct, uint8_t* nm, size_t nmlen, struct ub_packed_rrset_key** rrset, int* rr) { size_t i_rs; @@ -823,7 +823,7 @@ nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash, */ static int find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, uint8_t* nm, size_t nmlen, + rbtree_type* ct, uint8_t* nm, size_t nmlen, struct ub_packed_rrset_key** rrset, int* rr) { size_t i_rs; @@ -869,7 +869,7 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, */ static int nsec3_find_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, struct query_info* qinfo, struct ce_response* ce) + rbtree_type* ct, struct query_info* qinfo, struct ce_response* ce) { uint8_t* nm = qinfo->qname; size_t nmlen = qinfo->qname_len; @@ -936,7 +936,7 @@ next_closer(uint8_t* qname, size_t qnamelen, uint8_t* ce, */ static enum sec_status nsec3_prove_closest_encloser(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, struct query_info* qinfo, int prove_does_not_exist, + rbtree_type* ct, struct query_info* qinfo, int prove_does_not_exist, struct ce_response* ce) { uint8_t* nc; @@ -1016,7 +1016,7 @@ nsec3_ce_wildcard(struct regional* region, uint8_t* ce, size_t celen, /** Do the name error proof */ static enum sec_status nsec3_do_prove_nameerror(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, struct query_info* qinfo) + rbtree_type* ct, struct query_info* qinfo) { struct ce_response ce; uint8_t* wc; @@ -1062,7 +1062,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey) { - rbtree_t ct; + rbtree_type ct; struct nsec3_filter flt; if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) @@ -1086,7 +1086,7 @@ nsec3_prove_nameerror(struct module_env* env, struct val_env* ve, /** Do the nodata proof */ static enum sec_status nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, - rbtree_t* ct, struct query_info* qinfo) + rbtree_type* ct, struct query_info* qinfo) { struct ce_response ce; uint8_t* wc; @@ -1180,7 +1180,7 @@ nsec3_do_prove_nodata(struct module_env* env, struct nsec3_filter* flt, nsec3_has_type(rrset, rr, LDNS_RR_TYPE_NS) && !nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA)) { verbose(VERB_ALGO, "nsec3 nodata proof: matching " - "wilcard is a delegation, bogus"); + "wildcard is a delegation, bogus"); return sec_status_bogus; } /* everything is peachy keen, except for optout spans */ @@ -1221,7 +1221,7 @@ nsec3_prove_nodata(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey) { - rbtree_t ct; + rbtree_type ct; struct nsec3_filter flt; if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) @@ -1240,7 +1240,7 @@ nsec3_prove_wildcard(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc) { - rbtree_t ct; + rbtree_type ct; struct nsec3_filter flt; struct ce_response ce; uint8_t* nc; @@ -1314,7 +1314,7 @@ nsec3_prove_nods(struct module_env* env, struct val_env* ve, struct ub_packed_rrset_key** list, size_t num, struct query_info* qinfo, struct key_entry_key* kkey, char** reason) { - rbtree_t ct; + rbtree_type ct; struct nsec3_filter flt; struct ce_response ce; struct ub_packed_rrset_key* rrset; @@ -1403,7 +1403,7 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, struct query_info* qinfo, struct key_entry_key* kkey, int* nodata) { enum sec_status sec, secnx; - rbtree_t ct; + rbtree_type ct; struct nsec3_filter flt; *nodata = 0; diff --git a/usr.sbin/unbound/validator/val_nsec3.h b/usr.sbin/unbound/validator/val_nsec3.h index 69ba78d8323..27e9f9eac19 100644 --- a/usr.sbin/unbound/validator/val_nsec3.h +++ b/usr.sbin/unbound/validator/val_nsec3.h @@ -224,7 +224,7 @@ nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve, */ struct nsec3_cached_hash { /** rbtree node, key is this structure */ - rbnode_t node; + rbnode_type node; /** where are the parameters for conversion, in this rrset data */ struct ub_packed_rrset_key* nsec3; /** where are the parameters for conversion, this RR number in data */ @@ -271,7 +271,7 @@ int nsec3_hash_cmp(const void* c1, const void* c2); * 0 on a malloc failure. * -1 if the NSEC3 rr was badly formatted (i.e. formerr). */ -int nsec3_hash_name(rbtree_t* table, struct regional* region, +int nsec3_hash_name(rbtree_type* table, struct regional* region, struct sldns_buffer* buf, struct ub_packed_rrset_key* nsec3, int rr, uint8_t* dname, size_t dname_len, struct nsec3_cached_hash** hash); diff --git a/usr.sbin/unbound/validator/val_secalgo.c b/usr.sbin/unbound/validator/val_secalgo.c index 11c8cd16e8f..302820fc2f9 100644 --- a/usr.sbin/unbound/validator/val_secalgo.c +++ b/usr.sbin/unbound/validator/val_secalgo.c @@ -72,6 +72,9 @@ #include <openssl/engine.h> #endif +/** fake DSA support for unit tests */ +int fake_dsa = 0; + /* return size of digest if supported, or 0 otherwise */ size_t nsec3_hash_algo_size_supported(int id) @@ -192,9 +195,13 @@ dnskey_algo_id_is_supported(int id) case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */ return 0; -#ifdef USE_DSA case LDNS_DSA: case LDNS_DSA_NSEC3: +#ifdef USE_DSA + return 1; +#else + if(fake_dsa) return 1; + return 0; #endif case LDNS_RSASHA1: case LDNS_RSASHA1_NSEC3: @@ -264,8 +271,12 @@ setup_dsa_sig(unsigned char** sig, unsigned int* len) dsasig = DSA_SIG_new(); if(!dsasig) return 0; +#ifdef HAVE_DSA_SIG_SET0 + if(!DSA_SIG_set0(dsasig, R, S)) return 0; +#else dsasig->r = R; dsasig->s = S; +#endif *sig = NULL; newlen = i2d_DSA_SIG(dsasig, sig); if(newlen < 0) { @@ -350,6 +361,23 @@ i * the '44' is the total remaining length. } #endif /* USE_ECDSA */ +#ifdef USE_ECDSA_EVP_WORKAROUND +static EVP_MD ecdsa_evp_256_md; +static EVP_MD ecdsa_evp_384_md; +void ecdsa_evp_workaround_init(void) +{ + /* openssl before 1.0.0 fixes RSA with the SHA256 + * hash in EVP. We create one for ecdsa_sha256 */ + ecdsa_evp_256_md = *EVP_sha256(); + ecdsa_evp_256_md.required_pkey_type[0] = EVP_PKEY_EC; + ecdsa_evp_256_md.verify = (void*)ECDSA_verify; + + ecdsa_evp_384_md = *EVP_sha384(); + ecdsa_evp_384_md.required_pkey_type[0] = EVP_PKEY_EC; + ecdsa_evp_384_md.verify = (void*)ECDSA_verify; +} +#endif /* USE_ECDSA_EVP_WORKAROUND */ + /** * Setup key and digest for verification. Adjust sig if necessary. * @@ -389,7 +417,11 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, "EVP_PKEY_assign_DSA failed"); return 0; } +#ifdef HAVE_EVP_DSS1 *digest_type = EVP_dss1(); +#else + *digest_type = EVP_sha1(); +#endif break; #endif /* USE_DSA */ @@ -478,20 +510,7 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, return 0; } #ifdef USE_ECDSA_EVP_WORKAROUND - /* openssl before 1.0.0 fixes RSA with the SHA256 - * hash in EVP. We create one for ecdsa_sha256 */ - { - static int md_ecdsa_256_done = 0; - static EVP_MD md; - if(!md_ecdsa_256_done) { - EVP_MD m = *EVP_sha256(); - md_ecdsa_256_done = 1; - m.required_pkey_type[0] = (*evp_key)->type; - m.verify = (void*)ECDSA_verify; - md = m; - } - *digest_type = &md; - } + *digest_type = &ecdsa_evp_256_md; #else *digest_type = EVP_sha256(); #endif @@ -505,20 +524,7 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type, return 0; } #ifdef USE_ECDSA_EVP_WORKAROUND - /* openssl before 1.0.0 fixes RSA with the SHA384 - * hash in EVP. We create one for ecdsa_sha384 */ - { - static int md_ecdsa_384_done = 0; - static EVP_MD md; - if(!md_ecdsa_384_done) { - EVP_MD m = *EVP_sha384(); - md_ecdsa_384_done = 1; - m.required_pkey_type[0] = (*evp_key)->type; - m.verify = (void*)ECDSA_verify; - md = m; - } - *digest_type = &md; - } + *digest_type = &ecdsa_evp_384_md; #else *digest_type = EVP_sha384(); #endif @@ -554,6 +560,11 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, EVP_MD_CTX* ctx; int res, dofree = 0, docrypto_free = 0; EVP_PKEY *evp_key = NULL; + +#ifndef USE_DSA + if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && fake_dsa) + return sec_status_secure; +#endif if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) { verbose(VERB_QUERY, "verify: failed to setup key"); @@ -601,7 +612,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, log_err("EVP_MD_CTX_new: malloc failure"); EVP_PKEY_free(evp_key); if(dofree) free(sigblock); - else if(docrypto_free) CRYPTO_free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } if(EVP_VerifyInit(ctx, digest_type) == 0) { @@ -609,7 +620,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, EVP_MD_CTX_destroy(ctx); EVP_PKEY_free(evp_key); if(dofree) free(sigblock); - else if(docrypto_free) CRYPTO_free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } if(EVP_VerifyUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), @@ -618,7 +629,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, EVP_MD_CTX_destroy(ctx); EVP_PKEY_free(evp_key); if(dofree) free(sigblock); - else if(docrypto_free) CRYPTO_free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); return sec_status_unchecked; } @@ -632,7 +643,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, EVP_PKEY_free(evp_key); if(dofree) free(sigblock); - else if(docrypto_free) CRYPTO_free(sigblock); + else if(docrypto_free) OPENSSL_free(sigblock); if(res == 1) { return sec_status_secure; @@ -1207,6 +1218,9 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, #include "macros.h" #include "rsa.h" #include "dsa.h" +#ifdef HAVE_NETTLE_DSA_COMPAT_H +#include "dsa-compat.h" +#endif #include "asn1.h" #ifdef USE_ECDSA #include "ecdsa.h" @@ -1367,12 +1381,13 @@ dnskey_algo_id_is_supported(int id) } } +#ifdef USE_DSA static char * _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, unsigned int sigblock_len, unsigned char* key, unsigned int keylen) { uint8_t digest[SHA1_DIGEST_SIZE]; - uint8_t key_t; + uint8_t key_t_value; int res = 0; size_t offset; struct dsa_public_key pubkey; @@ -1411,8 +1426,8 @@ _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, } /* Validate T values constraints - RFC 2536 sec. 2 & sec. 3 */ - key_t = key[0]; - if (key_t > 8) { + key_t_value = key[0]; + if (key_t_value > 8) { return "invalid T value in DSA pubkey"; } @@ -1423,9 +1438,9 @@ _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, expected_len = 1 + /* T */ 20 + /* Q */ - (64 + key_t*8) + /* P */ - (64 + key_t*8) + /* G */ - (64 + key_t*8); /* Y */ + (64 + key_t_value*8) + /* P */ + (64 + key_t_value*8) + /* G */ + (64 + key_t_value*8); /* Y */ if (keylen != expected_len ) { return "invalid DSA pubkey length"; } @@ -1435,11 +1450,11 @@ _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, offset = 1; nettle_mpz_set_str_256_u(pubkey.q, 20, key+offset); offset += 20; - nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t*8), key+offset); - offset += (64 + key_t*8); - nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t*8), key+offset); - offset += (64 + key_t*8); - nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t*8), key+offset); + nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t_value*8), key+offset); + offset += (64 + key_t_value*8); + nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t_value*8), key+offset); + offset += (64 + key_t_value*8); + nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t_value*8), key+offset); /* Digest content of "buf" and verify its DSA signature in "sigblock"*/ res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf), @@ -1454,6 +1469,7 @@ _verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock, else return NULL; } +#endif /* USE_DSA */ static char * _verify_nettle_rsa(sldns_buffer* buf, unsigned int digest_size, char* sigblock, diff --git a/usr.sbin/unbound/validator/val_sigcrypt.c b/usr.sbin/unbound/validator/val_sigcrypt.c index 1dd07b420bd..b0b2e970ff2 100644 --- a/usr.sbin/unbound/validator/val_sigcrypt.c +++ b/usr.sbin/unbound/validator/val_sigcrypt.c @@ -483,7 +483,7 @@ dnskeyset_verify_rrset(struct module_env* env, struct val_env* ve, { enum sec_status sec; size_t i, num; - rbtree_t* sortree = NULL; + rbtree_type* sortree = NULL; /* make sure that for all DNSKEY algorithms there are valid sigs */ struct algo_needs needs; int alg; @@ -551,7 +551,7 @@ dnskey_verify_rrset(struct module_env* env, struct val_env* ve, { enum sec_status sec; size_t i, num, numchecked = 0; - rbtree_t* sortree = NULL; + rbtree_type* sortree = NULL; int buf_canon = 0; uint16_t tag = dnskey_calc_keytag(dnskey, dnskey_idx); int algo = dnskey_get_algo(dnskey, dnskey_idx); @@ -585,7 +585,7 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t sig_idx, - struct rbtree_t** sortree, char** reason) + struct rbtree_type** sortree, char** reason) { /* find matching keys and check them */ enum sec_status sec = sec_status_bogus; @@ -627,7 +627,7 @@ dnskeyset_verify_rrset_sig(struct module_env* env, struct val_env* ve, */ struct canon_rr { /** rbtree node, key is this structure */ - rbnode_t node; + rbnode_type node; /** rrset the RR is in */ struct ub_packed_rrset_key* rrset; /** which RR in the rrset */ @@ -885,7 +885,7 @@ canonical_tree_compare(const void* k1, const void* k2) */ static void canonical_sort(struct ub_packed_rrset_key* rrset, struct packed_rrset_data* d, - rbtree_t* sortree, struct canon_rr* rrs) + rbtree_type* sortree, struct canon_rr* rrs) { size_t i; /* insert into rbtree to sort and detect duplicates */ @@ -1043,7 +1043,7 @@ canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset, int rrset_canonical_equal(struct regional* region, struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2) { - struct rbtree_t sortree1, sortree2; + struct rbtree_type sortree1, sortree2; struct canon_rr *rrs1, *rrs2, *p1, *p2; struct packed_rrset_data* d1=(struct packed_rrset_data*)k1->entry.data; struct packed_rrset_data* d2=(struct packed_rrset_data*)k2->entry.data; @@ -1120,7 +1120,7 @@ int rrset_canonical_equal(struct regional* region, static int rrset_canonical(struct regional* region, sldns_buffer* buf, struct ub_packed_rrset_key* k, uint8_t* sig, size_t siglen, - struct rbtree_t** sortree) + struct rbtree_type** sortree) { struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; uint8_t* can_owner = NULL; @@ -1129,8 +1129,8 @@ rrset_canonical(struct regional* region, sldns_buffer* buf, struct canon_rr* rrs; if(!*sortree) { - *sortree = (struct rbtree_t*)regional_alloc(region, - sizeof(rbtree_t)); + *sortree = (struct rbtree_type*)regional_alloc(region, + sizeof(rbtree_type)); if(!*sortree) return 0; if(d->count > RR_COUNT_MAX) @@ -1283,15 +1283,23 @@ adjust_ttl(struct val_env* ve, uint32_t unow, /* so now: * d->ttl: rrset ttl read from message or cache. May be reduced * origttl: original TTL from signature, authoritative TTL max. + * MIN_TTL: minimum TTL from config. * expittl: TTL until the signature expires. * - * Use the smallest of these. + * Use the smallest of these, but don't let origttl set the TTL + * below the minimum. */ - if(d->ttl > (time_t)origttl) { - verbose(VERB_QUERY, "rrset TTL larger than original TTL," - " adjusting TTL downwards"); + if(MIN_TTL > (time_t)origttl && d->ttl > MIN_TTL) { + verbose(VERB_QUERY, "rrset TTL larger than original and minimum" + " TTL, adjusting TTL downwards to minimum ttl"); + d->ttl = MIN_TTL; + } + else if(MIN_TTL <= origttl && d->ttl > (time_t)origttl) { + verbose(VERB_QUERY, "rrset TTL larger than original TTL, " + "adjusting TTL downwards to original ttl"); d->ttl = origttl; } + if(expittl > 0 && d->ttl > (time_t)expittl) { verbose(VERB_ALGO, "rrset TTL larger than sig expiration ttl," " adjusting TTL downwards"); @@ -1304,7 +1312,7 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, size_t sig_idx, - struct rbtree_t** sortree, int* buf_canon, char** reason) + struct rbtree_type** sortree, int* buf_canon, char** reason) { enum sec_status sec; uint8_t* sig; /* RRSIG rdata */ diff --git a/usr.sbin/unbound/validator/val_sigcrypt.h b/usr.sbin/unbound/validator/val_sigcrypt.h index c220b0083ac..5a975acff4d 100644 --- a/usr.sbin/unbound/validator/val_sigcrypt.h +++ b/usr.sbin/unbound/validator/val_sigcrypt.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -47,8 +47,9 @@ struct val_env; struct module_env; struct ub_packed_rrset_key; -struct rbtree_t; +struct rbtree_type; struct regional; +struct sldns_buffer; /** number of entries in algorithm needs array */ #define ALGO_NEEDS_MAX 256 @@ -274,9 +275,9 @@ enum sec_status dnskey_verify_rrset(struct module_env* env, * or unchecked on error. */ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, - struct val_env* ve, uint32_t now, struct ub_packed_rrset_key* rrset, + struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t sig_idx, - struct rbtree_t** sortree, char** reason); + struct rbtree_type** sortree, char** reason); /** * verify rrset, with specific dnskey(from set), for a specific rrsig @@ -298,14 +299,25 @@ enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env, * bogus if it did not validate. */ enum sec_status dnskey_verify_rrset_sig(struct regional* region, - ldns_buffer* buf, struct val_env* ve, uint32_t now, + struct sldns_buffer* buf, struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, size_t sig_idx, - struct rbtree_t** sortree, int* buf_canon, char** reason); + struct rbtree_type** sortree, int* buf_canon, char** reason); /** * canonical compare for two tree entries */ int canonical_tree_compare(const void* k1, const void* k2); +/** + * Compare two rrsets and see if they are the same, canonicalised. + * The rrsets are not altered. + * @param region: temporary region. + * @param k1: rrset1 + * @param k2: rrset2 + * @return true if equal. + */ +int rrset_canonical_equal(struct regional* region, + struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2); + #endif /* VALIDATOR_VAL_SIGCRYPT_H */ diff --git a/usr.sbin/unbound/validator/val_utils.c b/usr.sbin/unbound/validator/val_utils.c index 94f00a7f7ee..da8066aad7e 100644 --- a/usr.sbin/unbound/validator/val_utils.c +++ b/usr.sbin/unbound/validator/val_utils.c @@ -219,7 +219,7 @@ val_find_signer(enum val_classification subtype, struct query_info* qinf, { size_t i; - if(subtype == VAL_CLASS_POSITIVE || subtype == VAL_CLASS_ANY) { + if(subtype == VAL_CLASS_POSITIVE) { /* check for the answer rrset */ for(i=skip; i<rep->an_numrrsets; i++) { if(query_dname_compare(qinf->qname, @@ -271,6 +271,29 @@ val_find_signer(enum val_classification subtype, struct query_info* qinf, signer_name, signer_len, &matchcount); } } + } else if(subtype == VAL_CLASS_ANY) { + /* check for one of the answer rrset that has signatures, + * or potentially a DNAME is in use with a different qname */ + for(i=skip; i<rep->an_numrrsets; i++) { + if(query_dname_compare(qinf->qname, + rep->rrsets[i]->rk.dname) == 0) { + val_find_rrset_signer(rep->rrsets[i], + signer_name, signer_len); + if(*signer_name) + return; + } + } + /* no answer RRSIGs with qname, try a DNAME */ + if(skip < rep->an_numrrsets && + ntohs(rep->rrsets[skip]->rk.type) == + LDNS_RR_TYPE_DNAME) { + val_find_rrset_signer(rep->rrsets[skip], + signer_name, signer_len); + if(*signer_name) + return; + } + *signer_name = NULL; + *signer_len = 0; } else if(subtype == VAL_CLASS_REFERRAL) { /* find keys for the item at skip */ if(skip < rep->rrset_count) { @@ -1115,6 +1138,7 @@ val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, qinfo.qname_len = nmlen; qinfo.qtype = LDNS_RR_TYPE_DS; qinfo.qclass = c; + qinfo.local_alias = NULL; /* do not add SOA to reply message, it is going to be used internal */ msg = val_neg_getmsg(env->neg_cache, &qinfo, region, env->rrset_cache, env->scratch_buffer, *env->now, 0, topname); diff --git a/usr.sbin/unbound/validator/validator.c b/usr.sbin/unbound/validator/validator.c index db4383bedcd..676dcdfe4d8 100644 --- a/usr.sbin/unbound/validator/validator.c +++ b/usr.sbin/unbound/validator/validator.c @@ -156,6 +156,9 @@ val_apply_cfg(struct module_env* env, struct val_env* val_env, return 1; } +#ifdef USE_ECDSA_EVP_WORKAROUND +void ecdsa_evp_workaround_init(void); +#endif int val_init(struct module_env* env, int id) { @@ -171,10 +174,14 @@ val_init(struct module_env* env, int id) lock_basic_init(&val_env->bogus_lock); lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus, sizeof(val_env->num_rrset_bogus)); +#ifdef USE_ECDSA_EVP_WORKAROUND + ecdsa_evp_workaround_init(); +#endif if(!val_apply_cfg(env, val_env, env->cfg)) { log_err("validator: could not apply configuration settings."); return 0; } + return 1; } @@ -371,6 +378,7 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name, ask.qname_len = namelen; ask.qtype = qtype; ask.qclass = qclass; + ask.local_alias = NULL; log_query_info(VERB_ALGO, "generate request", &ask); fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub)); /* enable valrec flag to avoid recursion to the same validation @@ -2081,7 +2089,7 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, } /* store results in cache */ - if(qstate->query_flags&BIT_RD) { + if(!qstate->no_cache_store && qstate->query_flags&BIT_RD) { /* if secure, this will override cache anyway, no need * to check if from parentNS */ if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo, @@ -2274,6 +2282,7 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id, (void)outbound; if(event == module_event_new || (event == module_event_pass && vq == NULL)) { + /* pass request to next module, to get it */ verbose(VERB_ALGO, "validator: pass to next module"); qstate->ext_state[id] = module_wait_module; @@ -2282,6 +2291,7 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id, if(event == module_event_moddone) { /* check if validation is needed */ verbose(VERB_ALGO, "validator: nextmodule returned"); + if(!needs_validation(qstate, qstate->return_rcode, qstate->return_msg)) { /* no need to validate this */ diff --git a/usr.sbin/unbound/validator/validator.h b/usr.sbin/unbound/validator/validator.h index 18e905efcd2..23d3072427a 100644 --- a/usr.sbin/unbound/validator/validator.h +++ b/usr.sbin/unbound/validator/validator.h @@ -21,16 +21,16 @@ * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @@ -56,13 +56,13 @@ struct config_strlist; * will be primed no more often than this interval. Used when harden- * dnssec-stripped is off and the trust anchor fails. */ -#define NULL_KEY_TTL 900 /* seconds */ +#define NULL_KEY_TTL 60 /* seconds */ /** * TTL for bogus key entries. When a DS or DNSKEY fails in the chain of * trust the entire zone for that name is blacked out for this TTL. */ -#define BOGUS_KEY_TTL 900 /* seconds */ +#define BOGUS_KEY_TTL 60 /* seconds */ /** max number of query restarts, number of IPs to probe */ #define VAL_MAX_RESTART_COUNT 5 @@ -126,7 +126,7 @@ struct val_env { size_t* nsec3_maxiter; /** lock on bogus counter */ - lock_basic_t bogus_lock; + lock_basic_type bogus_lock; /** number of times rrsets marked bogus */ size_t num_rrset_bogus; }; |