import unbound 1.6.0

This commit is contained in:
Dag-Erling Smørgrav 2017-02-03 13:06:34 +00:00
parent 27c2fff0f2
commit bd51c20871
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/unbound/dist/; revision=313158
svn path=/vendor/unbound/1.6.0/; revision=313159; tag=vendor/unbound/1.6.0
128 changed files with 9691 additions and 4262 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
testdata/*.[0-9] linguist-documentation

View File

@ -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 \
@ -625,7 +625,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 \
@ -635,7 +636,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,32 @@ listen_dnsport.lo listen_dnsport.o: $(srcdir)/services/listen_dnsport.c config.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)/util/storage/dnstree.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/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 +770,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)/util/storage/dnstree.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) $(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 +788,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 +912,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,9 +959,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)/services/localzone.h $(srcdir)/util/locks.h \
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.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 \
@ -978,10 +983,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 \
@ -992,12 +997,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 \
@ -1025,8 +1030,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 \
@ -1054,8 +1059,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 \
@ -1064,9 +1069,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)/services/localzone.h $(srcdir)/util/locks.h \
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.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 \
@ -1074,10 +1081,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 \
@ -1125,7 +1132,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 \
@ -1137,8 +1144,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)/util/storage/dnstree.h $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h \
$(srcdir)/services/cache/infra.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 \
@ -1146,9 +1154,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)/util/storage/dnstree.h $(srcdir)/services/cache/infra.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 \
@ -1156,12 +1164,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)/util/storage/dnstree.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)/sldns/str2wire.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)/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 \

View File

@ -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);

View File

@ -107,6 +107,9 @@
/* 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
@ -143,6 +146,9 @@
/* 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
@ -344,9 +350,6 @@
/* 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
@ -395,6 +398,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

77
configure vendored
View File

@ -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.10.
# Generated by GNU Autoconf 2.69 for unbound 1.6.0.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.5.10'
PACKAGE_STRING='unbound 1.5.10'
PACKAGE_VERSION='1.6.0'
PACKAGE_STRING='unbound 1.6.0'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl'
PACKAGE_URL=''
@ -659,6 +659,7 @@ WINAPPS
WINDRES
CHECKLOCK_OBJ
staticexe
PC_LIBEVENT_DEPENDENCY
UNBOUND_EVENT_UNINSTALL
UNBOUND_EVENT_INSTALL
SSLLIB
@ -678,6 +679,7 @@ WITH_PYTHONMODULE
swig
SWIG_LIB
SWIG
PC_PY_DEPENDENCY
PY_MAJOR_VERSION
PYTHON_SITE_PKG
PYTHON_LDFLAGS
@ -1401,7 +1403,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.10 to adapt to many kinds of systems.
\`configure' configures unbound 1.6.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1466,7 +1468,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.5.10:";;
short | recursive ) echo "Configuration of unbound 1.6.0:";;
esac
cat <<\_ACEOF
@ -1656,7 +1658,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.5.10
unbound configure 1.6.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -2365,7 +2367,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.10, which was
It was created by unbound $as_me 1.6.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2715,13 +2717,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=5
UNBOUND_VERSION_MINOR=6
UNBOUND_VERSION_MICRO=10
UNBOUND_VERSION_MICRO=0
LIBUNBOUND_CURRENT=6
LIBUNBOUND_REVISION=2
LIBUNBOUND_REVISION=3
LIBUNBOUND_AGE=4
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@ -2771,6 +2773,7 @@ LIBUNBOUND_AGE=4
# 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
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@ -16823,6 +16826,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
@ -17535,7 +17540,7 @@ fi
done
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
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 :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@ -17551,12 +17556,13 @@ done
# these check_funcs need -lssl
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
for ac_func in OPENSSL_init_ssl
for ac_func in OPENSSL_init_ssl SSL_CTX_set_security_level
do :
ac_fn_c_check_func "$LINENO" "OPENSSL_init_ssl" "ac_cv_func_OPENSSL_init_ssl"
if test "x$ac_cv_func_OPENSSL_init_ssl" = 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_INIT_SSL 1
#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
fi
@ -17925,13 +17931,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
@ -18378,6 +18384,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
@ -18959,33 +18967,6 @@ 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
int main(void) { void* cur = sbrk(0); printf("%u\n", (unsigned)(size_t)((char*)cur - (char*)sbrk(0))); return 0; }
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
$as_echo "#define HAVE_SBRK 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
CFLAGS="$old_cflags"
# check if setreuid en setregid fail, on MacOSX10.4(darwin8).
if echo $build_os | grep darwin8 > /dev/null; then
@ -19939,7 +19920,7 @@ _ACEOF
version=1.5.10
version=1.6.0
date=`date +'%b %e, %Y'`
@ -20454,7 +20435,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.10, which was
This file was extended by unbound $as_me 1.6.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -20520,7 +20501,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.10
unbound config.status 1.6.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -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],[10])
m4_define([VERSION_MINOR],[6])
m4_define([VERSION_MICRO],[0])
AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl, unbound)
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=6
LIBUNBOUND_REVISION=2
LIBUNBOUND_REVISION=3
LIBUNBOUND_AGE=4
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@ -67,6 +67,7 @@ LIBUNBOUND_AGE=4
# 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
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@ -543,6 +544,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
@ -673,12 +676,12 @@ else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h],,, [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])
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])
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], [], [], [
@ -864,12 +867,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 ])
@ -1000,6 +1003,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
@ -1142,19 +1147,6 @@ AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit se
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])

View File

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

View File

@ -150,7 +150,7 @@ get_state ( ) {
fi
done
# try to get it
echo $$ >$lock
if echo $$ >$lock ; then : ; else break; fi
done
# do not refetch if the file exists and only LEE seconds old
if test -f $state; then
@ -266,7 +266,6 @@ if test "$1" = "config" ; then
echo "graph_args --base 1024 -l 0"
echo "graph_vlabel memory used in bytes"
echo "graph_category DNS"
p_config "mem.total.sbrk" "Total memory" "GAUGE"
p_config "mem.cache.rrset" "RRset cache memory" "GAUGE"
p_config "mem.cache.message" "Message cache memory" "GAUGE"
p_config "mem.mod.iterator" "Iterator module memory" "GAUGE"
@ -458,20 +457,6 @@ queue)
done
;;
memory)
mn=`echo mem.total.sbrk | sed $ABBREV | tr . _`
get_value 'mem.total.sbrk'
if test $value -eq 0; then
chk=`echo $ctrl | sed -e 's/-control$/-checkconf/'`
pidf=`$chk -o pidfile $conf 2>&1`
pid=`cat $pidf 2>&1`
value=`ps -p "$pid" -o rss= 2>&1`
if test "`expr $value + 1 - 1 2>&1`" -eq "$value" 2>&1; then
value=`expr $value \* 1024`
else
value=0
fi
fi
echo "$mn.value" $value
for x in mem.cache.rrset mem.cache.message mem.mod.iterator \
mem.mod.validator msg.cache.count rrset.cache.count \
infra.cache.count key.cache.count; do

View File

@ -170,6 +170,23 @@ acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
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,
@ -210,15 +227,47 @@ acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
/** check wire data parse */
static int
check_data(const char* data)
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;
snprintf(buf, sizeof(buf), "%s %s", "example.com.", data);
/* '.' 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",
@ -258,7 +307,7 @@ acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
}
/* check data? */
if(!check_data(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;
@ -312,6 +361,27 @@ read_acl_tags(struct acl_list* acl, struct config_file* cfg)
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)
@ -362,12 +432,15 @@ read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
}
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))

View File

@ -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;
@ -100,6 +101,8 @@ struct acl_addr {
struct config_strlist** tag_datas;
/** size of the tag_datas array */
size_t tag_datas_size;
/* view element, NULL if none */
struct view* view;
};
/**
@ -118,9 +121,11 @@ 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 access control status for acl structure.

View File

@ -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 "

View File

@ -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"
@ -248,9 +249,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;
@ -347,6 +355,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);
}
/**
@ -542,8 +551,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))
@ -605,6 +621,8 @@ daemon_cleanup(struct daemon* daemon)
slabhash_clear(daemon->env->msg_cache);
local_zones_delete(daemon->local_zones);
daemon->local_zones = NULL;
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++)
@ -634,6 +652,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);

View File

@ -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;

View File

@ -146,6 +146,7 @@ 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
static DH *get_dh2048(void)
{
@ -203,6 +204,7 @@ static DH *get_dh2048(void)
return NULL;
}
#endif /* SPLINT */
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
struct daemon_remote*
daemon_remote_create(struct config_file* cfg)
@ -243,12 +245,18 @@ 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
*/
@ -257,6 +265,7 @@ daemon_remote_create(struct config_file* cfg)
daemon_remote_delete(rc);
return NULL;
}
#endif
return rc;
}
rc->use_cert = 1;
@ -760,6 +769,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,
@ -818,12 +829,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;
@ -1123,8 +1128,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;
@ -1133,83 +1138,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);
}
/** Do the local_zones_remove command */
static void
do_zones_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_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 void
do_data_add(SSL* ssl, struct worker* worker, char* arg)
static int
perform_data_add(SSL* ssl, struct local_zones* zones, char* arg)
{
if(!local_zones_add_RR(worker->daemon->local_zones, 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)
@ -1238,6 +1426,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) {
@ -2183,6 +2372,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);
}
@ -2263,9 +2460,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);
@ -2286,9 +2482,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;
@ -2324,6 +2519,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 */
@ -2436,10 +2659,16 @@ 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);
@ -2505,13 +2734,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)) {

View File

@ -251,6 +251,7 @@ 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;

View File

@ -131,7 +131,8 @@ struct server_stats {
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

View File

@ -87,11 +87,6 @@
# 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(void)
{
@ -244,19 +239,32 @@ 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);
log_ident_set_fromdefault(cfg, log_default_identity);
}
#ifdef HAVE_KILL
@ -586,9 +594,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;
@ -610,7 +619,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);
@ -618,7 +627,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 */
@ -665,19 +674,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) {
@ -721,7 +727,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;
}

View File

@ -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))
return 0;
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))
return 0;
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);
}
@ -944,12 +930,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,
acladdr->taglist, acladdr->taglen, acladdr->tag_actions,
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)) {
worker->daemon->cfg->num_tags, acladdr->view)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
@ -986,44 +972,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;
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);
/* 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);
goto send_reply;
return 0; /* drop it */
}
verbose(VERB_ALGO, "answer from the cache failed");
lock_rw_unlock(&e->lock);
qinfo.qname = d->rr_data[0] + 2;
qinfo.qname_len = d->rr_len[0] - 2;
}
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(!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);
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;
}
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);
@ -1377,11 +1389,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(
@ -1389,11 +1400,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;
}
@ -1433,14 +1443,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;

View File

@ -61,6 +61,7 @@ struct ub_randstate;
struct regional;
struct tube;
struct daemon_remote;
struct query_info;
/** worker commands */
enum worker_commands {

View File

@ -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");
}

Binary file not shown.

View File

@ -1,3 +1,177 @@
8 December 2016: Wouter
- Fix downcast warnings from visual studio in sldns code.
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.

View File

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

View File

@ -1,7 +1,7 @@
#
# Example configuration file.
#
# See unbound.conf(5) man page, version 1.5.10.
# See unbound.conf(5) man page, version 1.6.0.
#
# this is a comment.
@ -52,7 +52,7 @@ server:
# outgoing-interface: 192.0.2.153
# 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
@ -171,7 +171,7 @@ 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"
@ -230,6 +230,9 @@ server:
# 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.
@ -272,9 +275,13 @@ 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
@ -328,7 +335,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.
@ -344,6 +351,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
@ -477,6 +490,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
@ -578,7 +595,7 @@ 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.
@ -700,6 +717,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.
@ -715,6 +733,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

View File

@ -1,4 +1,4 @@
.TH "libunbound" "3" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "libunbound" "3" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" libunbound.3 -- unbound library functions manual
.\"
@ -43,7 +43,7 @@
.B ub_ctx_zone_remove,
.B ub_ctx_data_add,
.B ub_ctx_data_remove
\- Unbound DNS validating resolver 1.5.10 functions.
\- Unbound DNS validating resolver 1.6.0 functions.
.SH "SYNOPSIS"
.B #include <unbound.h>
.LP
@ -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

View File

@ -1,4 +1,4 @@
.TH "unbound-anchor" "8" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound-anchor" "8" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
.\"
@ -67,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).

View File

@ -1,4 +1,4 @@
.TH "unbound-checkconf" "8" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound-checkconf" "8" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" unbound-checkconf.8 -- unbound configuration checker manual
.\"

View File

@ -1,4 +1,4 @@
.TH "unbound-control" "8" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound-control" "8" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" 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.
@ -263,6 +279,21 @@ 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 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_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"
@ -301,6 +332,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 +384,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 +421,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

View File

@ -1,4 +1,4 @@
.TH "unbound\-host" "1" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound\-host" "1" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" unbound-host.1 -- unbound DNS lookup utility
.\"

View File

@ -1,4 +1,4 @@
.TH "unbound" "8" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound" "8" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" unbound.8 -- unbound manual
.\"
@ -9,7 +9,7 @@
.\"
.SH "NAME"
.B unbound
\- Unbound DNS validating resolver 1.5.10.
\- Unbound DNS validating resolver 1.6.0.
.SH "SYNOPSIS"
.B unbound
.RB [ \-h ]

View File

@ -1,4 +1,4 @@
.TH "unbound.conf" "5" "Sep 27, 2016" "NLnet Labs" "unbound 1.5.10"
.TH "unbound.conf" "5" "Dec 15, 2016" "NLnet Labs" "unbound 1.6.0"
.\"
.\" unbound.conf.5 -- unbound.conf manual
.\"
@ -151,8 +151,8 @@ netblock, or the randomisation will be compromised. Consider combining with
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
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
@ -474,6 +474,9 @@ order of the define-tag values.
.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
@ -531,6 +534,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
@ -614,14 +624,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
@ -658,8 +669,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
@ -859,6 +877,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
@ -978,11 +1001,11 @@ 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
@ -1280,6 +1303,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
@ -1310,6 +1337,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

View File

@ -72,6 +72,7 @@ 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, ns->lame))
return NULL;

View File

@ -81,6 +81,8 @@ struct delegpt {
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;
};
/**
@ -355,7 +357,7 @@ void delegpt_no_ipv4(struct delegpt* dp);
/**
* create malloced delegation point, with the given name
* @param name: uncompressed wireformat of degegpt name.
* @param name: uncompressed wireformat of delegpt name.
* @return NULL on alloc failure
*/
struct delegpt* delegpt_create_mlc(uint8_t* name);

View File

@ -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))

View File

@ -149,6 +149,7 @@ compile_time_root_prime(int do_ip4, int do_ip6)
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;
@ -275,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;

View File

@ -532,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,

View File

@ -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 */
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);
}
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;
}
@ -2068,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,
@ -2088,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;
@ -2106,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
@ -2117,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);
@ -2259,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;
@ -2275,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
@ -2327,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)
@ -2342,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,
@ -2355,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
@ -2445,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;
@ -2527,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);
}
@ -2927,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);
@ -2966,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,
@ -3141,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;

View File

@ -62,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;

View File

@ -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;
@ -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);

View File

@ -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,9 +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,
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, 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);
@ -678,9 +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,
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, 0, NULL, 0, NULL)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
@ -799,9 +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,
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, 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);
@ -824,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(
@ -836,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;
}
@ -955,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;

View File

@ -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

View File

@ -82,10 +82,13 @@
# Options for HTML output
# -----------------------
# The theme that the html output should use.
html_theme = "classic"
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
#html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".

View File

@ -1,26 +1,33 @@
.. _example_resolve_name:
==============================
Resolve a name
==============================
==============
This basic example shows how to create a context and resolve a host address (DNS record of A type).
This basic example shows how to create a context and resolve a host address
(DNS record of A type).
Source code
-----------
::
#!/usr/bin/python
import unbound
ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
status, result = ctx.resolve("www.google.com")
if status == 0 and result.havedata:
print "Result.data:", result.data.address_list
elif status != 0:
print "Resolve error:", unbound.ub_strerror(status)
#!/usr/bin/python
import unbound
In contrast with C API, the source code is more compact while the performance of C implementation is preserved.
The main advantage is that you need not take care about the deallocation and allocation of context and result structures; pyUnbound module do it automatically for you.
ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
If only domain name is given, the :meth:`unbound.ub_ctx.resolve` looks for A records in IN class.
status, result = ctx.resolve("www.google.com")
if status == 0 and result.havedata:
print "Result.data:", result.data.address_list
elif status != 0:
print "Resolve error:", unbound.ub_strerror(status)
In contrast with the C API, the source code is more compact while the
performance of C implementation is preserved.
The main advantage is that you need not take care about the deallocation and
allocation of context and result structures; pyUnbound module does it
automatically for you.
If only domain name is given, the :meth:`unbound.ub_ctx.resolve` looks for
A records in IN class.

View File

@ -1,33 +1,37 @@
.. _example_reverse_lookup:
==============================
Reverse DNS lookup
==============================
==================
Reverse DNS lookup involves determining the hostname associated with a given IP address.
Reverse DNS lookup involves determining the hostname associated with a given IP
address.
This example shows how reverse lookup can be done using unbound module.
For the reverse DNS records, the special domain in-addr.arpa is reserved.
For example, a host name for the IP address 74.125.43.147 can be obtained by issuing a DNS query for the PTR record for address 147.43.125.74.in-addr.arpa.
For example, a host name for the IP address ``74.125.43.147`` can be obtained
by issuing a DNS query for the PTR record for address
``147.43.125.74.in-addr.arpa.``
Source code
-----------
::
#!/usr/bin/python
import unbound
ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
print "Result.data:", result.data.domain_list
elif status != 0:
print "Resolve error:", unbound.ub_strerror(status)
#!/usr/bin/python
import unbound
In order to simplify the python code, unbound module contains function which reverses the hostname components.
ctx = unbound.ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
if status == 0 and result.havedata:
print "Result.data:", result.data.domain_list
elif status != 0:
print "Resolve error:", unbound.ub_strerror(status)
In order to simplify the python code, unbound module contains the
:meth:`unbound.reverse` function which reverses the hostname components.
This function is defined as follows::
def reverse(domain):
return '.'.join([a for a in domain.split(".")][::-1])
def reverse(domain):
return '.'.join([a for a in domain.split(".")][::-1])

View File

@ -1,41 +1,41 @@
.. _example_setup_ctx:
==============================
Lookup from threads
==============================
===================
This example shows how to use unbound module from a threaded program.
In this example, three lookup threads are created which work in background.
Each thread resolves different DNS record.
This example shows how to use unbound module from a threaded program.
In this example, three lookup threads are created which work in background.
Each thread resolves different DNS record.
Source code
-----------
::
#!/usr/bin/python
from unbound import ub_ctx, RR_TYPE_A, RR_CLASS_IN
from threading import Thread
ctx = ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
class LookupThread(Thread):
def __init__(self,ctx, name):
Thread.__init__(self)
self.ctx = ctx
self.name = name
#!/usr/bin/python
from unbound import ub_ctx, RR_TYPE_A, RR_CLASS_IN
from threading import Thread
def run(self):
print "Thread lookup started:",self.name
status, result = self.ctx.resolve(self.name, RR_TYPE_A, RR_CLASS_IN)
if status == 0 and result.havedata:
print " Result:",self.name,":", result.data.address_list
threads = []
for name in ["www.fit.vutbr.cz","www.vutbr.cz","www.google.com"]:
thread = LookupThread(ctx, name)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
ctx = ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
class LookupThread(Thread):
def __init__(self,ctx, name):
Thread.__init__(self)
self.ctx = ctx
self.name = name
def run(self):
print "Thread lookup started:",self.name
status, result = self.ctx.resolve(self.name, RR_TYPE_A, RR_CLASS_IN)
if status == 0 and result.havedata:
print " Result:",self.name,":", result.data.address_list
threads = []
for name in ["www.fit.vutbr.cz","www.vutbr.cz","www.google.com"]:
thread = LookupThread(ctx, name)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()

View File

@ -1,12 +1,14 @@
.. _example_asynch:
==============================
Asynchronous lookup
==============================
===================
This example performs the name lookup in the background.
The main program keeps running while the name is resolved.
Source code
-----------
::
#!/usr/bin/python
@ -33,4 +35,5 @@ The main program keeps running while the name is resolved.
if (status != 0):
print "Resolve error:", unbound.ub_strerror(status)
The :meth:`unbound.ub_ctx.resolve_async` method is able to pass on any Python object. In this example, we used a dictionary object `my_data`.
The :meth:`unbound.ub_ctx.resolve_async` method is able to pass on any Python
object. In this example, we used a dictionary object ``my_data``.

View File

@ -1,33 +1,35 @@
.. _example_examine:
==============================
DNSSEC validator
==============================
================
This example program performs DNSSEC validation of a DNS lookup.
Source code
-----------
::
#!/usr/bin/python
import os
from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
ctx = ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
if (os.path.isfile("keys")):
ctx.add_ta_file("keys") #read public keys for DNSSEC verification
status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
if status == 0 and result.havedata:
print "Result:", result.data.address_list
if result.secure:
print "Result is secure"
elif result.bogus:
print "Result is bogus"
else:
print "Result is insecure"
#!/usr/bin/python
import os
from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
ctx = ub_ctx()
ctx.resolvconf("/etc/resolv.conf")
if (os.path.isfile("keys")):
ctx.add_ta_file("keys") #read public keys for DNSSEC verification
status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
if status == 0 and result.havedata:
print "Result:", result.data.address_list
if result.secure:
print "Result is secure"
elif result.bogus:
print "Result is bogus"
else:
print "Result is insecure"
More detailed informations can be seen in libUnbound DNSSEC tutorial `here`_.

View File

@ -1,13 +1,17 @@
.. _example_resolver_only:
==============================
Resolver only
==============================
=============
This example program shows how to perform DNS resolution only.
Unbound contains two basic modules: resolver and validator.
In case, the validator is not necessary, the validator module can be turned off using "module-config" option.
This option contains a list of module names separated by the space char. This list determined which modules should be employed and in what order.
In case, the validator is not necessary, the validator module can be turned off
using "module-config" option.
This option contains a list of module names separated by the space char. This
list determined which modules should be employed and in what order.
Source code
-----------
::
@ -25,5 +29,6 @@ This option contains a list of module names separated by the space char. This li
print "Result:", result.data.address_list
.. note::
The :meth:`unbound.ub_ctx.set_option` method must be used before the first resolution (i.e. before :meth:`unbound.ub_ctx.resolve` or :meth:`unbound.ub_ctx.resolve_async` call).
The :meth:`unbound.ub_ctx.set_option` method must be used before the first
resolution (i.e. before :meth:`unbound.ub_ctx.resolve` or
:meth:`unbound.ub_ctx.resolve_async` call).

View File

@ -1,11 +1,13 @@
.. _example_localzone:
==============================
Local zone manipulation
==============================
=======================
This example program shows how to define local zone containing custom DNS records.
This example program shows how to define local zone containing custom DNS
records.
.. literalinclude:: example6-1.py
:language: python
Source code
-----------
.. literalinclude:: example6-1.py
:language: python

View File

@ -1,18 +1,33 @@
.. _example_idna:
=================================================
Internationalized domain name support
=================================================
=====================================
Unlike the libUnbound, pyUnbound is able to handle IDN queries.
.. literalinclude:: example7-1.py
:language: python
Automatic IDN DNAME conversion
-------------------------------
If we use unicode string in :meth:`unbound.ub_ctx.resolve` method, the IDN DNAME conversion (if it is necessary) is performed on background.
If we use unicode string in :meth:`unbound.ub_ctx.resolve` method,
the IDN DNAME conversion (if it is necessary) is performed on background.
.. literalinclude:: example7-2.py
:language: python
Source code
...........
The :class:`unbound.ub_data` class contains attributes suffix which converts the dname to UTF string. These attributes have the '_idn' suffix.
Apart from this aproach, two conversion functions exist (:func:`unbound.idn2dname` and :func:`unbound.dname2idn`).
.. literalinclude:: example7-1.py
:language: python
IDN converted attributes
------------------------
The :class:`unbound.ub_data` class contains attributes suffix which converts
the dname to UTF string. These attributes have the ``_idn`` suffix.
Apart from this aproach, two conversion functions exist
(:func:`unbound.idn2dname` and :func:`unbound.dname2idn`).
Source code
...........
.. literalinclude:: example7-2.py
:language: python

View File

@ -1,28 +1,34 @@
.. _example_mxlookup:
=================================================
Lookup for MX and NS records
=================================================
============================
The pyUnbound extension provides functions which are able to encode RAW RDATA produces by unbound resolver (see :class:`unbound.ub_data`).
The pyUnbound extension provides functions which are able to encode RAW RDATA
produces by unbound resolver (see :class:`unbound.ub_data`).
.. literalinclude:: example8-1.py
:language: python
Source code
-----------
Previous example produces following output::
.. literalinclude:: example8-1.py
:language: python
Result:
raw data: 00 0F 05 6D 61 69 6C 34 03 6E 69 63 02 63 7A 00;00 14 02 6D 78 05 63 7A 6E 69 63 03 6F 72 67 00;00 0A 04 6D 61 69 6C 03 6E 69 63 02 63 7A 00
priority:15 address: mail4.nic.cz.
priority:20 address: mx.cznic.org.
priority:10 address: mail.nic.cz.
Output
------
Result:
raw data: D9 1F CD 32
address: 217.31.205.50
The previous example produces the following output::
Result:
raw data: 01 61 02 6E 73 03 6E 69 63 02 63 7A 00;01 65 02 6E 73 03 6E 69 63 02 63 7A 00;01 63 02 6E 73 03 6E 69 63 02 63 7A 00
host: a.ns.nic.cz.
host: e.ns.nic.cz.
host: c.ns.nic.cz.
Result:
raw data: 00 0F 05 6D 61 69 6C 34 03 6E 69 63 02 63 7A 00;00 14 02 6D 78 05 63 7A 6E 69 63 03 6F 72 67 00;00 0A 04 6D 61 69 6C 03 6E 69 63 02 63 7A 00
priority:15 address: mail4.nic.cz.
priority:20 address: mx.cznic.org.
priority:10 address: mail.nic.cz.
Result:
raw data: D9 1F CD 32
address: 217.31.205.50
Result:
raw data: 01 61 02 6E 73 03 6E 69 63 02 63 7A 00;01 65 02 6E 73 03 6E 69 63 02 63 7A 00;01 63 02 6E 73 03 6E 69 63 02 63 7A 00
host: a.ns.nic.cz.
host: e.ns.nic.cz.
host: c.ns.nic.cz.

View File

@ -1,14 +1,16 @@
Examples
==============================
========
Here you can find several examples which utilizes the unbound library in Python environment.
Unbound is a caching validator and resolver and can be linked into an application, as a library where can answer DNS queries for the application.
Here you can find several examples which utilizes the unbound library in Python
environment. Unbound is a caching validator and resolver and can be linked into
an application, as a library where can answer DNS queries for the application.
This set of examples shows how to use the functions from Python environment.
`Tutorials`
Tutorials
---------
.. toctree::
:maxdepth: 1
:glob:
:maxdepth: 1
:glob:
example*
example*

View File

@ -1,31 +1,38 @@
Installation
===================================
============
**Prerequisites**
Prerequisites
-------------
Python 2.4 or higher, SWIG 1.3 or higher, GNU make
**Compiling**
Compiling
---------
After downloading, you can compile the pyUnbound library by doing::
> tar -xzf unbound-x.x.x-py.tar.gz
> cd unbound-x.x.x
> ./configure --with-pyunbound
> make
> tar -xzf unbound-x.x.x-py.tar.gz
> cd unbound-x.x.x
> ./configure --with-pyunbound
> make
You may want to --with-pythonmodule as well if you want to use python as
a module in the resolver.
You may want to enable ``--with-pythonmodule`` as well if you want to use
python as a module in the resolver.
You need GNU make to compile sources; SWIG and Python devel libraries to compile extension module.
You need ``GNU make`` to compile sources; ``SWIG`` and ``Python devel``
libraries to compile extension module.
**Testing**
Testing
-------
If the compilation is successful, you can test the python LDNS extension module by::
If the compilation is successful, you can test the python LDNS extension module
by::
> cd contrib/python
> make testenv
> ./dns-lookup.py
> cd contrib/python
> make testenv
> ./dns-lookup.py
You may want to make install in the main directory since make testenv is for debugging. In contrib/examples you can find simple applications written in Python using the Unbound extension.
You may want to ``make install`` in the main directory since ``make testenv``
is for debugging. In contrib/examples you can find simple applications written
in Python using the Unbound extension.

View File

@ -1,39 +1,58 @@
Introduction
===================================
============
**Unbound**
Unbound
-------
`Unbound`_ is an implementation of a DNS resolver, that performs caching and DNSSEC validation.
Together with unbound, the libunbound library is provided.
This library can be used to convert hostnames to ip addresses, and back, as well as obtain other information.
Since the resolver allows to specify the class and type of a query (A record, NS, MX, ...), this library offers powerful resolving tool.
The library also performs public-key validation of results with DNSSEC.
.. _Unbound: http://www.unbound.net/documentation
`Unbound`_ is an implementation of a DNS resolver, that performs caching and
DNSSEC validation.
Together with unbound, the libunbound library is provided.
This library can be used to convert hostnames to ip addresses, and back, as
well as obtain other information.
Since the resolver allows to specify the class and type of a query (A record,
NS, MX, ...), this library offers powerful resolving tool.
The library also performs public-key validation of results with DNSSEC.
**pyUnbound**
.. _Unbound: http://www.unbound.net/documentation
The pyUnbound is an extension module for Python which provides an object-oriented interface to libunbound.
It is the first Python module which offers thread-safe caching resolver.
The interface was designed with the emphasis on the simplicity of use.
There are two main classes :class:`unbound.ub_ctx` (a validation and resolution context) and :class:`unbound.ub_result` which contains the validation and resolution results.
The objects are thread-safe, and a context can be used in non-threaded as well as threaded environment.
Resolution can be performed blocking and non-blocking (i.e. asynchronous).
The asynchronous method returns from the call immediately, so that processing can go on, while the results become available later.
pyUnbound
---------
**Features**
* customizable caching validation resolver for synchronous and asynchronous lookups
* easy to use object interface
* easy to integrate extension module
* designed for thread environment (i.e. thread-safe)
* allows define and customize of local zone and its RR's during the operation (i.e. without restart)
* includes encoding functions to simplify the results retrieval
* Internationalized domain name (`IDN`_) support
The pyUnbound is an extension module for Python which provides an
object-oriented interface to libunbound.
It is the first Python module which offers thread-safe caching resolver.
.. _IDN: http://en.wikipedia.org/wiki/Internationalized_domain_name
The interface was designed with the emphasis on the simplicity of use.
There are two main classes :class:`unbound.ub_ctx` (a validation and resolution
context) and :class:`unbound.ub_result` which contains the validation and
resolution results.
The objects are thread-safe, and a context can be used in non-threaded as well
as threaded environment.
Resolution can be performed blocking and non-blocking (i.e. asynchronous).
The asynchronous method returns from the call immediately, so that processing
can go on, while the results become available later.
**Application area**
* DNS-based applications performing DNS lookups; the caching resolver can reduce overhead
* Applications where the validation of DNS records is required
* Great solution for customizable and dynamic DNS-based white/blacklists (spam rejection, connection rejection, ...) using the dynamic local zone manipulation
Features
--------
* Customizable caching validation resolver for synchronous and asynchronous
lookups
* Easy to use object interface
* Easy to integrate extension module
* Designed for thread environment (i.e. thread-safe)
* Allows define and customize of local zone and its RR's during the operation
(i.e. without restart)
* Includes encoding functions to simplify the results retrieval
* Internationalized domain name (`IDN`_) support
.. _IDN: http://en.wikipedia.org/wiki/Internationalized_domain_name
Application area
----------------
* DNS-based applications performing DNS lookups; the caching resolver can
reduce overhead
* Applications where the validation of DNS records is required
* Great solution for customizable and dynamic DNS-based white/blacklists (spam
rejection, connection rejection, ...) using the dynamic local zone
manipulation

View File

@ -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

View File

@ -80,10 +80,13 @@
# Options for HTML output
# -----------------------
# The theme that the html output should use.
html_theme = "classic"
# The style sheet to use for HTML and HTML Help pages. A file of that name
# must exist either in Sphinx' static/ path, or in one of the custom paths
# given in html_static_path.
html_style = 'default.css'
#html_style = 'default.css'
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".

View File

@ -1,10 +1,12 @@
.. _log_handler:
Packet logger
=========================
=============
This example shows how to log and print details about query and response.
As soon as the ``iterator`` has finished (event is :data:`module_event_moddone`), ``qstate.return_msg`` contains response packet or ``None``.
As soon as the ``iterator`` has finished (event is
:data:`module_event_moddone`), ``qstate.return_msg`` contains response packet
or ``None``.
This packet will be send to a client that asked for it.
Complete source code
@ -14,14 +16,16 @@ Complete source code
:language: python
Testing
------------------
-------
Run the unbound server:
``root@localhost>unbound -dv -c ./test-log.conf``
In case you use own configuration file, don't forget to enable python module: ``module-config: "validator python iterator"`` and use valid script path: ``python-script: "./examples/log.py"``.
In case you use own configuration file, don't forget to enable python module:
``module-config: "validator python iterator"`` and use valid script path:
``python-script: "./examples/log.py"``.
Example of output::
Example of output::
[1231790168] unbound[7941:0] info: response for <f.gtld-servers.NET. AAAA IN>
[1231790168] unbound[7941:0] info: reply from <gtld-servers.NET.> 192.5.6.31#53

View File

@ -1,12 +1,14 @@
Response generation
=====================
===================
This example shows how to handle queries and generate response packet.
.. note::
If the python module is the first module and validator module is enabled (``module-config: "python validator iterator"``),
a return_msg security flag has to be set at least to 2. Leaving security flag untouched causes that the
response will be refused by unbound worker as unbound will consider it as non-valid response.
If the python module is the first module and validator module is enabled
(``module-config: "python validator iterator"``), a return_msg security flag
has to be set at least to 2. Leaving security flag untouched causes that the
response will be refused by unbound worker as unbound will consider it as
non-valid response.
Complete source code
--------------------
@ -27,20 +29,21 @@ Query for a A record ending with .localdomain
Dig produces the following output::
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48426
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;test.xxx.localdomain. IN A
;; ANSWER SECTION:
test.xxx.localdomain. 10 IN A 127.0.0.1
;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 12:46:02 2009
;; MSG SIZE rcvd: 54
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48426
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
As we handle (override) in python module only queries ending with "localdomain.", the unboud can still resolve host names.
;; QUESTION SECTION:
;test.xxx.localdomain. IN A
;; ANSWER SECTION:
test.xxx.localdomain. 10 IN A 127.0.0.1
;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 12:46:02 2009
;; MSG SIZE rcvd: 54
As we handle (override) in the python module only queries ending with
``localdomain.``, unboud can still resolve host names.

View File

@ -1,15 +1,19 @@
DNS-based language dictionary
===============================
=============================
This example shows how to create a simple language dictionary based on **DNS**
service within 15 minutes. The translation will be performed using TXT resource records.
service within 15 minutes. The translation will be performed using TXT resource
records.
Key parts
-----------
---------
Initialization
~~~~~~~~~~~~~~~~~~~~~~~
On **init()** module loads dictionary from a text file containing records in ``word [tab] translation`` format.
~~~~~~~~~~~~~~
On **init()** module loads dictionary from a text file containing records in
``word [tab] translation`` format.
::
def init(id, cfg):
@ -20,11 +24,14 @@ On **init()** module loads dictionary from a text file containing records in ``w
The suitable file can be found at http://slovnik.zcu.cz
DNS query and word lookup
~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~
Let's define the following format od DNS queries: ``word1[.]word2[.] ... wordN[.]{en,cs}[._dict_.cz.]``.
Let's define the following format od DNS queries:
``word1[.]word2[.] ... wordN[.]{en,cs}[._dict_.cz.]``.
Word lookup is done by simple ``dict`` lookup from broken DNS request.
Query name is divided into a list of labels. This list is accessible as qname_list attribute.
Query name is divided into a list of labels. This list is accessible as
``qname_list`` attribute.
::
aword = ' '.join(qstate.qinfo.qname_list[0:-4]) #skip last four labels
@ -37,35 +44,40 @@ Query name is divided into a list of labels. This list is accessible as qname_li
if (adict == "cs") and (aword in cz_dict):
words = cz_dict[aword] # CS -> EN
In the first step, we get a string in the form: ``word1[space]word2[space]...word[space]``.
In the second assignment, fourth label from the end is obtained. This label should contains *"cs"* or *"en"*.
This label determines the direction of translation.
In the first step, we get a string in the form:
``word1[space]word2[space]...word[space]``.
In the second assignment, fourth label from the end is obtained. This label
should contains *"cs"* or *"en"*. This label determines the direction of
translation.
Forming of a DNS reply
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~
DNS reply is formed only on valid match and added as TXT answer.
::
msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_AA)
msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_TXT, RR_CLASS_IN, PKT_AA)
for w in words:
msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str, w.replace("\"", "\\\"")))
for w in words:
msg.answer.append("%s 300 IN TXT \"%s\"" % (qstate.qinfo.qname_str, w.replace("\"", "\\\"")))
if not msg.set_return_msg(qstate):
qstate.ext_state[id] = MODULE_ERROR
return True
if not msg.set_return_msg(qstate):
qstate.ext_state[id] = MODULE_ERROR
return True
qstate.return_rcode = RCODE_NOERROR
qstate.ext_state[id] = MODULE_FINISHED
return True
qstate.return_rcode = RCODE_NOERROR
qstate.ext_state[id] = MODULE_FINISHED
return True
In the first step, a :class:`DNSMessage` instance is created for a given query *(type TXT)*.
In the first step, a :class:`DNSMessage` instance is created for a given query
*(type TXT)*.
The fourth argument specifies the flags *(authoritative answer)*.
In the second step, we append TXT records containing the translation *(on the right side of RR)*.
In the second step, we append TXT records containing the translation *(on the
right side of RR)*.
Then, the response is finished and ``qstate.return_msg`` contains new response.
If no error, the module sets :attr:`module_qstate.return_rcode` and :attr:`module_qstate.ext_state`.
If no error, the module sets :attr:`module_qstate.return_rcode` and
:attr:`module_qstate.ext_state`.
**Steps:**
@ -82,80 +94,82 @@ Run the Unbound server:
In case you use own configuration file, don't forget to enable Python module::
module-config: "validator python iterator"
module-config: "validator python iterator"
and use valid script path::
python-script: "./examples/dict.py"
python-script: "./examples/dict.py"
The translation from english word *"a bar fly"* to Czech can be done by doing:
``>>>dig TXT @127.0.0.1 a.bar.fly.en._dict_.cz``
::
::
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48691
;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;a.bar.fly.en._dict_.cz. IN TXT
;; ANSWER SECTION:
a.bar.fly.en._dict_.cz. 300 IN TXT "barov\253 povale\232"
;; Query time: 5 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 17:44:18 2009
;; MSG SIZE rcvd: 67
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48691
;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;a.bar.fly.en._dict_.cz. IN TXT
;; ANSWER SECTION:
a.bar.fly.en._dict_.cz. 300 IN TXT "barov\253 povale\232"
;; Query time: 5 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 17:44:18 2009
;; MSG SIZE rcvd: 67
``>>>dig TXT @127.0.0.1 nic.cs._dict_.cz``
::
; <<>> DiG 9.5.0-P2 <<>> TXT @127.0.0.1 nic.cs._dict_.cz
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58710
;; flags: aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;nic.cs._dict_.cz. IN TXT
;; ANSWER SECTION:
nic.cs._dict_.cz. 300 IN TXT "aught"
nic.cs._dict_.cz. 300 IN TXT "naught"
nic.cs._dict_.cz. 300 IN TXT "nihil"
nic.cs._dict_.cz. 300 IN TXT "nix"
nic.cs._dict_.cz. 300 IN TXT "nothing"
nic.cs._dict_.cz. 300 IN TXT "zilch"
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 17:45:39 2009
;; MSG SIZE rcvd: 143
; <<>> DiG 9.5.0-P2 <<>> TXT @127.0.0.1 nic.cs._dict_.cz
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58710
;; flags: aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 0
Proof that the unbound still works as resolver.
;; QUESTION SECTION:
;nic.cs._dict_.cz. IN TXT
;; ANSWER SECTION:
nic.cs._dict_.cz. 300 IN TXT "aught"
nic.cs._dict_.cz. 300 IN TXT "naught"
nic.cs._dict_.cz. 300 IN TXT "nihil"
nic.cs._dict_.cz. 300 IN TXT "nix"
nic.cs._dict_.cz. 300 IN TXT "nothing"
nic.cs._dict_.cz. 300 IN TXT "zilch"
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Jan 01 17:45:39 2009
;; MSG SIZE rcvd: 143
Proof that the unbound still works as resolver.
``>>>dig A @127.0.0.1 www.nic.cz``
::
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19996
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
;; QUESTION SECTION:
;www.nic.cz. IN A
;; ANSWER SECTION:
www.nic.cz. 1662 IN A 217.31.205.50
;; AUTHORITY SECTION:
...
; (1 server found)
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19996
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5
;; QUESTION SECTION:
;www.nic.cz. IN A
;; ANSWER SECTION:
www.nic.cz. 1662 IN A 217.31.205.50
;; AUTHORITY SECTION:
...
Complete source code
--------------------

View File

@ -0,0 +1,191 @@
EDNS options
============
This example shows how to interact with EDNS options.
When quering unbound with the EDNS option ``65001`` and data ``0xc001`` we
expect an answer with the same EDNS option code and data ``0xdeadbeef``.
Key parts
~~~~~~~~~
This example relies on the following functionalities:
Registering EDNS options
------------------------
By registering EDNS options we can tune unbound's behavior when encountering a
query with a known EDNS option. The two available options are:
- ``bypass_cache_stage``: If set to ``True`` unbound will not try to answer
from cache. Instead execution is passed to the modules
- ``no_aggregation``: If set to ``True`` unbound will consider this query
unique and will not aggregate it with similar queries
Both values default to ``False``.
.. code-block:: python
if not register_edns_option(env, 65001, bypass_cache_stage=True,
no_aggregation=True):
log_info("python: Could not register EDNS option {}".format(65001))
EDNS option lists
-----------------
EDNS option lists can be found in the :class:`module_qstate` class. There are
four available lists in total:
- :class:`module_qstate.edns_opts_front_in`: options that came from the client
side. **Should not** be changed
- :class:`module_qstate.edns_opts_back_out`: options that will be sent to the
server side. Can be populated by edns literate modules
- :class:`module_qstate.edns_opts_back_in`: options that came from the server
side. **Should not** be changed
- :class:`module_qstate.edns_opts_front_out`: options that will be sent to the
client side. Can be populated by edns literate modules
Each list element has the following members:
- ``code``: the EDNS option code;
- ``data``: the EDNS option data.
Reading an EDNS option list
...........................
The lists' contents can be accessed in python by their ``_iter`` counterpart as
an iterator:
.. code-block:: python
if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
for o in qstate.edns_opts_front_in_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
Writing to an EDNS option list
..............................
By appending to an EDNS option list we can add new EDNS options. The new
element is going to be allocated in :class:`module_qstate.region`. The data
**must** be represented with a python ``bytearray``:
.. code-block:: python
b = bytearray.fromhex("deadbeef")
if not edns_opt_list_append(qstate.edns_opts_front_out,
o.code, b, qstate.region):
log_info("python: Could not append EDNS option {}".format(o.code))
We can also remove an EDNS option code from an EDNS option list.
.. code-block:: python
if not edns_opt_list_remove(edns_opt_list, code):
log_info("python: Option code {} was not found in the "
"list.".format(code))
.. note:: All occurences of the EDNS option code will be removed from the list:
Controlling other modules' cache behavior
-----------------------------------------
During the modules' operation, some modules may interact with the cache
(e.g., iterator). This behavior can be controlled by using the following
:class:`module_qstate` flags:
- :class:`module_qstate.no_cache_lookup`: Modules *operating after* this module
will not lookup the cache for an answer
- :class:`module_qstate.no_cache_store`: Modules *operating after* this module
will not store the response in the cache
Both values default to ``0``.
.. code-block:: python
def operate(id, event, qstate, qdata):
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
# Detect if edns option code 56001 is present from the client side. If
# so turn on the flags for cache management.
if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
log_info("python: searching for edns option code 65001 during NEW "
"or PASS event ")
for o in qstate.edns_opts_front_in_iter:
if o.code == 65001:
log_info("python: found edns option code 65001")
# Instruct other modules to not lookup for an
# answer in the cache.
qstate.no_cache_lookup = 1
log_info("python: enabled no_cache_lookup")
# Instruct other modules to not store the answer in
# the cache.
qstate.no_cache_store = 1
log_info("python: enabled no_cache_store")
Testing
~~~~~~~
Run the Unbound server: ::
root@localhost$ unbound -dv -c ./test-edns.conf
In case you use your own configuration file, don't forget to enable the Python
module::
module-config: "validator python iterator"
and use a valid script path::
python-script: "./examples/edns.py"
Quering with EDNS option ``65001:0xc001``:
::
root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65001:c001
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65001:c001
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33450
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; OPT=65001: de ad be ef ("....")
;; QUESTION SECTION:
;nlnetlabs.nl. IN A
;; ANSWER SECTION:
nlnetlabs.nl. 10200 IN A 185.49.140.10
;; AUTHORITY SECTION:
nlnetlabs.nl. 10200 IN NS anyns.pch.net.
nlnetlabs.nl. 10200 IN NS ns.nlnetlabs.nl.
nlnetlabs.nl. 10200 IN NS ns-ext1.sidn.nl.
nlnetlabs.nl. 10200 IN NS sec2.authdns.ripe.net.
;; ADDITIONAL SECTION:
ns.nlnetlabs.nl. 10200 IN AAAA 2a04:b900::8:0:0:60
ns.nlnetlabs.nl. 10200 IN A 185.49.140.60
;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Dec 05 14:50:56 CET 2016
;; MSG SIZE rcvd: 212
Complete source code
~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/edns.py
:language: python

View File

@ -0,0 +1,299 @@
Inplace callbacks
=================
This example shows how to register and use inplace callback functions. These
functions are going to be called just before unbound replies back to a client.
They can perform certain actions without interrupting unbound's execution flow
(e.g. add/remove EDNS options, manipulate the reply).
Two different scenarios will be shown:
- If answering from cache and the client used EDNS option code ``65002`` we
will answer with the same code but with data ``0xdeadbeef``;
- When answering with a SERVFAIL we also add an empty EDNS option code
``65003``.
Key parts
~~~~~~~~~
This example relies on the following functionalities:
Registering inplace callback functions
--------------------------------------
There are four types of inplace callback functions:
- `inplace callback reply functions`_
- `inplace callback reply_cache functions`_
- `inplace callback reply_local functions`_
- `inplace callback reply_servfail functions`_
Inplace callback reply functions
................................
Called when answering with a *resolved* query.
The callback function's prototype is the following:
.. code-block:: python
def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
"""Function that will be registered as an inplace callback function.
It will be called when answering with a resolved query.
:param qinfo: query_info struct;
:param qstate: module qstate. It contains the available opt_lists; It
SHOULD NOT be altered;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data to be sent to the client side. It SHOULD NOT be
altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_reply(inplace_reply_callback, env):
log_info("python: Could not register inplace callback function.")
Inplace callback reply_cache functions
......................................
Called when answering *from cache*.
The callback function's prototype is the following:
.. code-block:: python
def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
"""Function that will be registered as an inplace callback function.
It will be called when answering from the cache.
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data sent from the client side. The list with the EDNS
options is accesible through edns.opt_list. It SHOULD NOT be
altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_reply_cache(inplace_cache_callback, env):
log_info("python: Could not register inplace callback function.")
Inplace callback reply_local functions
......................................
Called when answering with *local data* or a *Chaos(CH) reply*.
The callback function's prototype is the following:
.. code-block:: python
def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
"""Function that will be registered as an inplace callback function.
It will be called when answering from local data.
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data sent from the client side. The list with the
EDNS options is accesible through edns.opt_list. It
SHOULD NOT be altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_reply_local(inplace_local_callback, env):
log_info("python: Could not register inplace callback function.")
Inplace callback reply_servfail functions
.........................................
Called when answering with *SERVFAIL*.
The callback function's prototype is the following:
.. code-block:: python
def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out, region):
"""Function that will be registered as an inplace callback function.
It will be called when answering with SERVFAIL.
:param qinfo: query_info struct;
:param qstate: module qstate. If not None the relevant opt_lists are
available here;
:param rep: reply_info struct. None;
:param rcode: return code for the query. LDNS_RCODE_SERVFAIL;
:param edns: edns_data to be sent to the client side. If qstate is None
edns.opt_list contains the EDNS options sent from the client
side. It SHOULD NOT be altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_reply_servfail(inplace_servfail_callback, env):
log_info("python: Could not register inplace callback function.")
Testing
~~~~~~~
Run the Unbound server: ::
root@localhost$ unbound -dv -c ./test-inplace_callbacks.conf
In case you use your own configuration file, don't forget to enable the Python
module::
module-config: "validator python iterator"
and use a valid script path ::
python-script: "./examples/inplace_callbacks.py"
On the first query for the nlnetlabs.nl A record we get no EDNS option back:
::
root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65002
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65002
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48057
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nlnetlabs.nl. IN A
;; ANSWER SECTION:
nlnetlabs.nl. 10200 IN A 185.49.140.10
;; AUTHORITY SECTION:
nlnetlabs.nl. 10200 IN NS ns.nlnetlabs.nl.
nlnetlabs.nl. 10200 IN NS sec2.authdns.ripe.net.
nlnetlabs.nl. 10200 IN NS anyns.pch.net.
nlnetlabs.nl. 10200 IN NS ns-ext1.sidn.nl.
;; ADDITIONAL SECTION:
ns.nlnetlabs.nl. 10200 IN A 185.49.140.60
ns.nlnetlabs.nl. 10200 IN AAAA 2a04:b900::8:0:0:60
;; Query time: 813 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Dec 05 16:15:32 CET 2016
;; MSG SIZE rcvd: 204
When we issue the same query again we get a cached response and the expected
``65002: 0xdeadbeef`` EDNS option:
::
root@localhost$ dig @localhost nlnetlabs.nl +ednsopt=65002
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost nlnetlabs.nl +ednsopt=65002
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26489
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; OPT=65002: de ad be ef ("....")
;; QUESTION SECTION:
;nlnetlabs.nl. IN A
;; ANSWER SECTION:
nlnetlabs.nl. 10197 IN A 185.49.140.10
;; AUTHORITY SECTION:
nlnetlabs.nl. 10197 IN NS ns.nlnetlabs.nl.
nlnetlabs.nl. 10197 IN NS sec2.authdns.ripe.net.
nlnetlabs.nl. 10197 IN NS anyns.pch.net.
nlnetlabs.nl. 10197 IN NS ns-ext1.sidn.nl.
;; ADDITIONAL SECTION:
ns.nlnetlabs.nl. 10197 IN AAAA 2a04:b900::8:0:0:60
ns.nlnetlabs.nl. 10197 IN A 185.49.140.60
;; Query time: 0 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Dec 05 16:50:04 CET 2016
;; MSG SIZE rcvd: 212
By issuing a query for a bogus domain unbound replies with SERVFAIL and an
empty EDNS option code ``65003``. *For this example to work unbound needs to be
validating*:
::
root@localhost$ dig @localhost bogus.nlnetlabs.nl txt
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @localhost bogus.nlnetlabs.nl txt
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 19865
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; OPT=65003
;; QUESTION SECTION:
;bogus.nlnetlabs.nl. IN TXT
;; Query time: 11 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Mon Dec 05 17:06:01 CET 2016
;; MSG SIZE rcvd: 51
Complete source code
~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/inplace_callbacks.py
:language: python

View File

@ -1,15 +1,16 @@
.. _Tutorials:
==============================
Examples
========
Here you can find several tutorials which clarify the usage and capabilities of
the Unbound scriptable interface.
Tutorials
==============================
Here you can find several tutorials which clarify the usage and capabilities of Unbound scriptable interface.
`Tutorials`
---------
.. toctree::
:maxdepth: 2
:glob:
:maxdepth: 2
:glob:
example*
example*

View File

@ -1,39 +1,44 @@
Installation
===================================
============
**Prerequisites**
Prerequisites
-------------
Python 2.4 or higher, SWIG 1.3 or higher, GNU make
**Download**
Download
--------
You can download the source codes `here`_.
The latest release is 1.1.1, Jan 15, 2009.
.. _here: unbound-1.1.1-py.tar.gz
**Compiling**
Compiling
---------
After downloading, you can compile the Unbound library by doing::
> tar -xzf unbound-1.1.1-py.tar.gz
> cd unbound-1.1.1
> ./configure --with-pythonmodule
> make
> tar -xzf unbound-1.1.1-py.tar.gz
> cd unbound-1.1.1
> ./configure --with-pythonmodule
> make
You need GNU make to compile sources.
SWIG and Python devel libraries to compile extension module.
**Testing**
Testing
-------
If the compilation is successful, you can test the extension module by::
> cd pythonmod
> make sudo # or "make test" or "make suexec"
> cd pythonmod
> make sudo # or "make test" or "make suexec"
This will start unbound server with language dictionary service (see :ref:`Tutorials`).
This will start unbound server with language dictionary service
(see :ref:`Tutorials`).
In order to test this service, type::
> dig TXT @127.0.0.1 aught.en._dict_.cz
Dig should print this message (czech equivalent of aught)::
@ -44,16 +49,17 @@ Dig should print this message (czech equivalent of aught)::
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30085
;; flags: aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;aught.en._dict_.cz. IN TXT
;aught.en._dict_.cz. IN TXT
;; ANSWER SECTION:
aught.en._dict_.cz. 300 IN TXT "nic"
aught.en._dict_.cz. 300 IN TXT "nic"
;; Query time: 11 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Jan 10 16:45:58 2009
;; MSG SIZE rcvd: 52
The ``pythonmod/examples`` directory contains simple applications written in Python.
The ``pythonmod/examples`` directory contains simple applications written in
Python.

View File

@ -7,25 +7,26 @@ Network
.. function:: ntohs(netshort)
This subroutine converts values between the host and network byte order.
Specifically, **ntohs()** converts 16-bit quantities from network byte order to host byte order.
Specifically, **ntohs()** converts 16-bit quantities from network byte order
to host byte order.
:param netshort: 16-bit short addr
:rtype: converted addr
Cache
-----
.. function:: storeQueryInCache(qstate, qinfo, msgrep, is_referral)
Store pending query in local cache.
:param qstate: :class:`module_qstate`
:param qinfo: :class:`query_info`
:param msgrep: :class:`reply_info`
:param is_referal: integer
:rtype: boolean
.. function:: invalidateQueryInCache(qstate, qinfo)
Invalidate record in local cache.
@ -34,6 +35,111 @@ Cache
:param qinfo: :class:`query_info`
EDNS options
------------
.. function:: register_edns_option(env, code, bypass_cache_stage=False, no_aggregation=False)
Register EDNS option code.
:param env: :class:`module_env`
:param code: option code(integer)
:param bypass_cache_stage: whether to bypass the cache response stage
:param no_aggregation: whether this query should be unique
:return: ``1`` if successful, ``0`` otherwise
:rtype: integer
.. function:: edns_opt_list_find(list, code)
Find the EDNS option code in the EDNS option list.
:param list: linked list of :class:`edns_option`
:param code: option code (integer)
:return: the edns option if found or None
:rtype: :class:`edns_option` or None
.. function:: edns_opt_list_remove(list, code);
Remove an ENDS option code from the list.
.. note:: All :class:`edns_option` with the code will be removed
:param list: linked list of :class:`edns_option`
:param code: option code (integer)
:return: ``1`` if at least one :class:`edns_option` was removed, ``0`` otherwise
:rtype: integer
.. function:: edns_opt_list_append(list, code, data, region)
Append given EDNS option code with data to the list.
:param list: linked list of :class:`edns_option`
:param code: option code (integer)
:param data: EDNS data. **Must** be a :class:`bytearray`
:param region: :class:`regional`
.. function:: edns_opt_list_is_empty(list)
Check if an EDNS option list is empty.
:param list: linked list of :class:`edns_option`
:return: ``1`` if list is empty, ``0`` otherwise
:rtype: integer
Inplace callbacks
-----------------
.. function:: inplace_cb_reply(qinfo, qstate, rep, rcode, edns, opt_list_out, region)
Function prototype for callback functions used in
`register_inplace_cb_reply`_, `register_inplace_cb_reply_cache`_,
`register_inplace_cb_reply_local` and `register_inplace_cb_reply_servfail`.
:param qinfo: :class:`query_info`
:param qstate: :class:`module_qstate`
:param rep: :class:`reply_info`
:param rcode: return code (integer), check ``RCODE_`` constants.
:param edns: :class:`edns_data`
:param opt_list_out: :class:`edns_option`. EDNS option list to append options to.
:param region: :class:`regional`
.. function:: register_inplace_cb_reply(py_cb, env)
Register py_cb as an inplace reply callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
:return: True on success, False otherwise
:rtype: boolean
.. function:: register_inplace_cb_reply_cache(py_cb, env)
Register py_cb as an inplace reply_cache callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
:return: True on success, False otherwise
:rtype: boolean
.. function:: register_inplace_cb_reply_local(py_cb, env)
Register py_cb as an inplace reply_local callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
:return: True on success, False otherwise
:rtype: boolean
.. function:: register_inplace_cb_reply_servfail(py_cb, env)
Register py_cb as an inplace reply_servfail callback function.
:param py_cb: Python function that follows `inplace_cb_reply`_'s prototype. **Must** be callable.
:param env: :class:`module_env`
:return: True on success, False otherwise
:rtype: boolean
Logging
-------
@ -71,50 +177,51 @@ Logging
:param msg: string desc to accompany the hexdump.
:param data: data to dump in hex format.
:param length: length of data.
.. function:: log_dns_msg(str, qinfo, reply)
Log DNS message.
:param str: string message
:param qinfo: :class:`query_info`
:param reply: :class:`reply_info`
.. function:: log_query_info(verbosity_value, str, qinf)
Log query information.
:param verbosity_value: see constants
:param str: string message
:param qinf: :class:`query_info`
.. function:: regional_log_stats(r)
Log regional statistics.
:param r: :class:`regional`
Debugging
---------
.. function:: strextstate(module_ext_state)
Debug utility, module external qstate to string.
:param module_ext_state: the state value.
:rtype: descriptive string.
.. function:: strmodulevent(module_event)
Debug utility, module event to string.
:param module_event: the module event value.
:rtype: descriptive string.
.. function:: ldns_rr_type2str(atype)
Convert RR type to string.
.. function:: ldns_rr_class2str(aclass)
Convert RR class to string.

View File

@ -6,55 +6,94 @@ module_qstate
.. class:: module_qstate
Module state, per query.
This class provides these data attributes:
.. attribute:: qinfo
(:class:`query_info`) Informations about query being answered. Name, RR type, RR class.
.. attribute:: query_flags
(uint16) Flags for query. See QF_BIT\_ predefined constants.
.. attribute:: is_priming
If this is a (stub or root) priming query (with hints).
.. attribute:: reply
comm_reply contains server replies.
.. attribute:: return_msg
(:class:`dns_msg`) The reply message, with message for client and calling module (read-only attribute).
Note that if you want to create of modify return_msg you should use :class:`DNSMessage`.
.. attribute:: return_rcode
The rcode, in case of error, instead of a reply message. Determines whether the return_msg contains reply.
.. attribute:: region
Region for this query. Cleared when query process finishes.
.. attribute:: curmod
Which module is executing.
.. attribute:: ext_state[]
Module states.
.. attribute:: env
Environment for this query.
.. attribute:: mesh_info
Mesh related information for this query.
Module state, per query.
This class provides these data attributes:
.. attribute:: qinfo
(:class:`query_info`) Informations about query being answered. Name, RR type, RR class.
.. attribute:: query_flags
(uint16) Flags for query. See QF_BIT\_ predefined constants.
.. attribute:: is_priming
If this is a (stub or root) priming query (with hints).
.. attribute:: reply
comm_reply contains server replies.
.. attribute:: return_msg
(:class:`dns_msg`) The reply message, with message for client and calling module (read-only attribute).
Note that if you want to create of modify return_msg you should use :class:`DNSMessage`.
.. attribute:: return_rcode
The rcode, in case of error, instead of a reply message. Determines whether the return_msg contains reply.
.. attribute:: region
Region for this query. Cleared when query process finishes.
.. attribute:: curmod
Which module is executing.
.. attribute:: ext_state[]
Module states.
.. attribute:: env
Environment for this query.
.. attribute:: mesh_info
Mesh related information for this query.
.. attribute:: edns_opts_front_in
Incoming EDNS options from the front end.
.. attribute:: edns_opts_front_in_iter
Iterator for `edns_opts_front_in`.
.. attribute:: edns_opts_back_out
Outgoing EDNS options to the back end.
.. attribute:: edns_opts_back_out_iter
Iterator for `edns_opts_back_out`.
.. attribute:: edns_opts_back_in
Incoming EDNS options from the back end.
.. attribute:: edns_opts_back_in_iter
Iterator for `ends_opts_back_in`.
.. attribute:: edns_opts_front_out
Outgoing EDNS options to the front end.
.. attribute:: edns_opts_front_out_iter
Iterator for `edns_opts_front_out`.
.. attribute:: no_cache_lookup
Flag to indicate whether modules should answer from the cache.
.. attribute:: no_cache_store
Flag to indicate whether modules should store answer in the cache.
query_info
----------------
@ -94,7 +133,57 @@ query_info
.. attribute:: qclass_str
The ``qclass`` in display presentation format (string).
edns_data
---------
.. class:: edns_data
This class represents the EDNS information parsed/encoded from/to a packet. It provides these data attributes:
.. attribute:: edns_present
If EDNS OPT record is present.
.. attribute:: ext_rcode
Extended RCODE.
.. attribute:: edns_version
The EDNS version number.
.. attribute:: bits
The EDNS bits field from ttl (host order): Z.
.. attribute:: udp_size
UDP reassembly size.
.. attribute:: opt_list
The EDNS option list.
.. attribute:: opt_list_iter
Iterator for `opt_list`.
edns_option
-----------
.. class:: edns_option
This class represents an EDNS option (code, data) found in EDNS option lists. It provides these data attributes:
.. attribute:: code
The EDNS option code.
.. attribute:: data
The EDNS option data.
reply_info
--------------------

194
pythonmod/examples/edns.py Normal file
View File

@ -0,0 +1,194 @@
# -*- coding: utf-8 -*-
'''
edns.py: python module showcasing EDNS option functionality.
Copyright (c) 2016, NLnet Labs.
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 organization 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 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.
'''
#Try:
# - dig @localhost nlnetlabs.nl +ednsopt=65001:c001
# This query will always reach the modules stage as EDNS option 65001 is
# registered to bypass the cache response stage. It will also be handled
# as a unique query because of the no_aggregation flag. This means that
# it will not be aggregated with other queries for the same qinfo.
# For demonstration purposes when option 65001 with hexdata 'c001' is
# sent from the client side this module will reply with the same code and
# data 'deadbeef'.
# Useful functions:
# edns_opt_list_is_empty(edns_opt_list):
# Check if the option list is empty.
# Return True if empty, False otherwise.
#
# edns_opt_list_append(edns_opt_list, code, data_bytearray, region):
# Append the EDNS option with code and data_bytearray to the given
# edns_opt_list.
# NOTE: data_bytearray MUST be a Python bytearray.
# Return True on success, False on failure.
#
# edns_opt_list_remove(edns_opt_list, code):
# Remove all occurences of the given EDNS option code from the
# edns_opt_list.
# Return True when at least one EDNS option was removed, False otherwise.
#
# register_edns_option(env, code, bypass_cache_stage=True,
# no_aggregation=True):
# Register EDNS option code as a known EDNS option.
# bypass_cache_stage:
# bypasses answering from cache and allows the query to reach the
# modules for further EDNS handling.
# no_aggregation:
# makes every query with the said EDNS option code unique.
# Return True on success, False on failure.
#
# Examples on how to use the functions are given in this file.
def init_standard(id, env):
"""New version of the init function.
The function's signature is the same as the C counterpart and allows for
extra functionality during init.
..note:: This function is preferred by unbound over the old init function.
..note:: The previously accesible configuration options can now be found in
env.cgf.
"""
log_info("python: inited script {}".format(env.cfg.python_script))
# Register EDNS option 65001 as a known EDNS option.
if not register_edns_option(env, 65001, bypass_cache_stage=True,
no_aggregation=True):
return False
return True
def init(id, cfg):
"""Previous version init function.
..note:: This function is still supported for backwards compatibility when
the init_standard function is missing. When init_standard is
present this function SHOULD be ommited to avoid confusion to the
reader.
"""
return True
def deinit(id): return True
def inform_super(id, qstate, superqstate, qdata): return True
def operate(id, event, qstate, qdata):
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
# Detect if EDNS option code 56001 is present from the client side. If
# so turn on the flags for cache management.
if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
log_info("python: searching for EDNS option code 65001 during NEW "
"or PASS event ")
for o in qstate.edns_opts_front_in_iter:
if o.code == 65001:
log_info("python: found EDNS option code 65001")
# Instruct other modules to not lookup for an
# answer in the cache.
qstate.no_cache_lookup = 1
log_info("python: enabled no_cache_lookup")
# Instruct other modules to not store the answer in
# the cache.
qstate.no_cache_store = 1
log_info("python: enabled no_cache_store")
#Pass on the query
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
elif event == MODULE_EVENT_MODDONE:
# If the client sent EDNS option code 65001 and data 'c001' reply
# with the same code and data 'deadbeef'.
if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
log_info("python: searching for EDNS option code 65001 during "
"MODDONE")
for o in qstate.edns_opts_front_in_iter:
if o.code == 65001 and o.data == bytearray.fromhex("c001"):
b = bytearray.fromhex("deadbeef")
if not edns_opt_list_append(qstate.edns_opts_front_out,
o.code, b, qstate.region):
qstate.ext_state[id] = MODULE_ERROR
return False
# List every EDNS option in all lists.
# The available lists are:
# - qstate.edns_opts_front_in: EDNS options that came from the
# client side. SHOULD NOT be changed;
#
# - qstate.edns_opts_back_out: EDNS options that will be sent to the
# server side. Can be populated by
# EDNS literate modules;
#
# - qstate.edns_opts_back_in: EDNS options that came from the
# server side. SHOULD NOT be changed;
#
# - qstate.edns_opts_front_out: EDNS options that will be sent to the
# client side. Can be populated by
# EDNS literate modules;
#
# The lists' contents can be accessed in python by their _iter
# counterpart as an iterator.
if not edns_opt_list_is_empty(qstate.edns_opts_front_in):
log_info("python: EDNS options in edns_opts_front_in:")
for o in qstate.edns_opts_front_in_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
if not edns_opt_list_is_empty(qstate.edns_opts_back_out):
log_info("python: EDNS options in edns_opts_back_out:")
for o in qstate.edns_opts_back_out_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
if not edns_opt_list_is_empty(qstate.edns_opts_back_in):
log_info("python: EDNS options in edns_opts_back_in:")
for o in qstate.edns_opts_back_in_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
if not edns_opt_list_is_empty(qstate.edns_opts_front_out):
log_info("python: EDNS options in edns_opts_front_out:")
for o in qstate.edns_opts_front_out_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
qstate.ext_state[id] = MODULE_FINISHED
return True
log_err("pythonmod: Unknown event")
qstate.ext_state[id] = MODULE_ERROR
return True

View File

@ -0,0 +1,244 @@
# -*- coding: utf-8 -*-
'''
inplace_callbacks.py: python module showcasing inplace callback function
registration and functionality.
Copyright (c) 2016, NLnet Labs.
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 organization 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 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.
'''
#Try:
# - dig @localhost nlnetlabs.nl +ednsopt=65002:
# This query *could* be answered from cache. If so, unbound will reply
# with the same EDNS option 65002, but with hexdata 'deadbeef' as data.
#
# - dig @localhost bogus.nlnetlabs.nl txt:
# This query returns SERVFAIL as the txt record of bogus.nlnetlabs.nl is
# intentionally bogus. The reply will contain an empty EDNS option
# with option code 65003.
# (unbound needs to be validating for this example to work)
# Useful functions:
# register_inplace_cb_reply(inplace_reply_callback, env):
# Register the reply_callback function as an inplace callback function
# when answering with a resolved query.
# Return True on success, False on failure.
#
# register_inplace_cb_reply_cache(inplace_reply_cache_callback, env):
# Register the reply_cache_callback function as an inplace callback
# function when answering from cache.
# Return True on success, False on failure.
#
# register_inplace_cb_reply_local(inplace_reply_local_callback, env):
# Register the reply_local_callback function as an inplace callback
# function when answering from local data or chaos reply.
# Return True on success, False on failure.
#
# register_inplace_cb_reply_servfail(inplace_reply_servfail_callback, env):
# Register the reply_servfail_callback function as an inplace callback
# function when answering with servfail.
# Return True on success, False on failure.
#
# Examples on how to use the functions are given in this file.
def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
region):
"""Function that will be registered as an inplace callback function.
It will be called when answering with a resolved query.
:param qinfo: query_info struct;
:param qstate: module qstate. It contains the available opt_lists; It
SHOULD NOT be altered;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data to be sent to the client side. It SHOULD NOT be
altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
log_info("python: called back while replying.")
return True
def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
region):
"""Function that will be registered as an inplace callback function.
It will be called when answering from the cache.
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data sent from the client side. The list with the EDNS
options is accesible through edns.opt_list. It SHOULD NOT be
altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
For demostration purposes we want to see if EDNS option 65002 is present
and reply with a new value.
"""
log_info("python: called back while answering from cache.")
# Inspect the incoming EDNS options.
if not edns_opt_list_is_empty(edns.opt_list):
log_info("python: available EDNS options:")
for o in edns.opt_list_iter:
log_info("python: Code: {}, Data: '{}'".format(o.code,
"".join('{:02x}'.format(x) for x in o.data)))
if o.code == 65002:
log_info("python: *found option code 65002*")
# add to opt_list
# Data MUST be represented in a bytearray.
b = bytearray.fromhex("deadbeef")
if edns_opt_list_append(opt_list_out, o.code, b, region):
log_info("python: *added new option code 65002*")
else:
log_info("python: *failed to add new option code 65002*")
return False
break
return True
def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
region):
"""Function that will be registered as an inplace callback function.
It will be called when answering from local data.
:param qinfo: query_info struct;
:param qstate: module qstate. None;
:param rep: reply_info struct;
:param rcode: return code for the query;
:param edns: edns_data sent from the client side. The list with the
EDNS options is accesible through edns.opt_list. It
SHOULD NOT be altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
"""
log_info("python: called back while replying with local data or chaos"
" reply.")
return True
def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
region):
"""Function that will be registered as an inplace callback function.
It will be called when answering with SERVFAIL.
:param qinfo: query_info struct;
:param qstate: module qstate. If not None the relevant opt_lists are
available here;
:param rep: reply_info struct. None;
:param rcode: return code for the query. LDNS_RCODE_SERVFAIL;
:param edns: edns_data to be sent to the client side. If qstate is None
edns.opt_list contains the EDNS options sent from the client
side. It SHOULD NOT be altered;
:param opt_list_out: the list with the EDNS options that will be sent as a
reply. It can be populated with EDNS options;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_list_out.
:return: True on success, False on failure.
For demostration purposes we want to reply with an empty EDNS code '65003'.
"""
log_info("python: called back while servfail.")
b = bytearray.fromhex("")
edns_opt_list_append(opt_list_out, 65003, b, region)
return True
def init_standard(id, env):
"""New version of the init function.
The function's signature is the same as the C counterpart and allows for
extra functionality during init.
..note:: This function is preferred by unbound over the old init function.
..note:: The previously accesible configuration options can now be found in
env.cgf.
"""
log_info("python: inited script {}".format(env.cfg.python_script))
# Register the inplace_reply_callback function as an inplace callback
# function when answering a resolved query.
if not register_inplace_cb_reply(inplace_reply_callback, env):
return False
# Register the inplace_cache_callback function as an inplace callback
# function when answering from cache.
if not register_inplace_cb_reply_cache(inplace_cache_callback, env):
return False
# Register the inplace_local_callback function as an inplace callback
# function when answering from local data.
if not register_inplace_cb_reply_local(inplace_local_callback, env):
return False
# Register the inplace_servfail_callback function as an inplace callback
# function when answering with SERVFAIL.
if not register_inplace_cb_reply_servfail(inplace_servfail_callback, env):
return False
return True
def init(id, cfg):
"""Previous version init function.
..note:: This function is still supported for backwards compatibility when
the init_standard function is missing. When init_standard is
present this function SHOULD be ommited to avoid confusion to the
reader.
"""
return True
def deinit(id): return True
def inform_super(id, qstate, superqstate, qdata): return True
def operate(id, event, qstate, qdata):
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
elif event == MODULE_EVENT_MODDONE:
qstate.ext_state[id] = MODULE_FINISHED
return True
log_err("pythonmod: Unknown event")
qstate.ext_state[id] = MODULE_ERROR
return True

View File

@ -1,7 +1,6 @@
/*
* interface.i: unbound python module
*/
%module unboundmodule
%{
/**
@ -34,10 +33,10 @@
#include "sldns/pkthdr.h"
%}
%include "stdint.i" // uint_16_t can be known type now
%include "stdint.i" /* uint_16_t can be known type now */
%inline %{
//converts [len][data][len][data][0] string to a List of labels (PyBytes)
/* converts [len][data][len][data][0] string to a List of labels (PyBytes) */
PyObject* GetNameAsLabelList(const char* name, int len) {
PyObject* list;
int cnt=0, i;
@ -202,13 +201,16 @@ struct packed_rrset_key {
char* dname;
size_t dname_len;
uint32_t flags;
uint16_t type; //rrset type in network format
uint16_t rrset_class; //rrset class in network format
uint16_t type; /* rrset type in network format */
uint16_t rrset_class; /* rrset class in network format */
%mutable;
};
//This subroutine converts values between the host and network byte order.
//Specifically, ntohs() converts 16-bit quantities from network byte order to host byte order.
/**
* This subroutine converts values between the host and network byte order.
* Specifically, ntohs() converts 16-bit quantities from network byte order to
* host byte order.
*/
uint16_t ntohs(uint16_t netshort);
%inline %{
@ -269,17 +271,24 @@ struct lruhash_entry {
%ignore packed_rrset_data::rr_data;
struct packed_rrset_data {
uint32_t ttl; //TTL (in seconds like time())
/* TTL (in seconds like time()) */
uint32_t ttl;
size_t count; //number of rrs
size_t rrsig_count; //number of rrsigs
/* number of rrs */
size_t count;
/* number of rrsigs */
size_t rrsig_count;
enum rrset_trust trust;
enum sec_status security;
size_t* rr_len; //length of every rr's rdata
uint32_t *rr_ttl; //ttl of every rr
uint8_t** rr_data; //array of pointers to every rr's rdata; The rr_data[i] rdata is stored in uncompressed wireformat.
/* length of every rr's rdata */
size_t* rr_len;
/* ttl of every rr */
uint32_t *rr_ttl;
/* array of pointers to every rr's rdata. The rr_data[i] rdata is stored in
* uncompressed wireformat. */
uint8_t** rr_data;
};
%pythoncode %{
@ -359,10 +368,10 @@ struct reply_info {
size_t an_numrrsets;
size_t ns_numrrsets;
size_t ar_numrrsets;
size_t rrset_count; // an_numrrsets + ns_numrrsets + ar_numrrsets
size_t rrset_count; /* an_numrrsets + ns_numrrsets + ar_numrrsets */
struct ub_packed_rrset_key** rrsets;
struct rrset_ref ref[1]; //?
struct rrset_ref ref[1]; /* ? */
};
struct rrset_ref {
@ -396,11 +405,11 @@ struct dns_msg {
struct rrset_ref* _rrset_ref_get(struct reply_info* r, int idx) {
if ((r != NULL) && (idx >= 0) && ((size_t)idx < r->rrset_count)) {
//printf("_rrset_ref_get: %lX key:%lX\n", r->ref + idx, r->ref[idx].key);
/* printf("_rrset_ref_get: %lX key:%lX\n", r->ref + idx, r->ref[idx].key); */
return &(r->ref[idx]);
// return &(r->ref[idx]);
/* return &(r->ref[idx]); */
}
//printf("_rrset_ref_get: NULL\n");
/* printf("_rrset_ref_get: NULL\n"); */
return NULL;
}
%}
@ -479,30 +488,166 @@ struct comm_reply {
if _newclass:family = _swig_property(_family_get)
%}
}
/* ************************************************************************************ *
Structure edns_option
* ************************************************************************************ */
/* Rename the members to follow the python convention of marking them as
* private. Access to the opt_code and opt_data members is given by the later
* python defined code and data members respectively. */
%rename(_next) edns_option::next;
%rename(_opt_code) edns_option::opt_code;
%rename(_opt_len) edns_option::opt_len;
%rename(_opt_data) edns_option::opt_data;
struct edns_option {
struct edns_option* next;
uint16_t opt_code;
size_t opt_len;
uint8_t* opt_data;
};
%inline %{
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
uint16_t opt_code = option->opt_code;
return PyInt_FromLong(opt_code);
}
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
return PyByteArray_FromStringAndSize((uint8_t*)option->opt_data,
option->opt_len);
}
%}
%extend edns_option {
%pythoncode %{
def _opt_code_get(self): return _edns_option_opt_code_get(self)
__swig_getmethods__["code"] = _opt_code_get
if _newclass: opt_code = _swig_property(_opt_code_get)
def _opt_data_get(self): return _edns_option_opt_data_get(self)
__swig_getmethods__["data"] = _opt_data_get
if _newclass: opt_data = _swig_property(_opt_data_get)
%}
}
/* ************************************************************************************ *
Structure edns_data
* ************************************************************************************ */
/* This is ignored because we will pass a double pointer of this to Python
* with custom getmethods. This is done to bypass Swig's behavior to pass NULL
* pointers as None. */
%ignore edns_data::opt_list;
struct edns_data {
int edns_present;
uint8_t ext_rcode;
uint8_t edns_version;
uint16_t bits;
uint16_t udp_size;
struct edns_option* opt_list;
};
%inline %{
struct edns_option** _edns_data_opt_list_get(struct edns_data* edns) {
return &edns->opt_list;
}
%}
%extend edns_data {
%pythoncode %{
def _opt_list_iter(self): return EdnsOptsListIter(self.opt_list)
__swig_getmethods__["opt_list_iter"] = _opt_list_iter
if _newclass:opt_list_iter = _swig_property(_opt_list_iter)
def _opt_list(self): return _edns_data_opt_list_get(self)
__swig_getmethods__["opt_list"] = _opt_list
if _newclass:opt_list = _swig_property(_opt_list)
%}
}
/* ************************************************************************************ *
Structure module_env
* ************************************************************************************ */
struct module_env {
struct config_file* cfg;
struct slabhash* msg_cache;
struct rrset_cache* rrset_cache;
struct infra_cache* infra_cache;
struct key_cache* key_cache;
/* --- services --- */
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, int ssl_upstream,
struct module_qstate* q);
void (*detach_subs)(struct module_qstate* qstate);
int (*attach_sub)(struct module_qstate* qstate,
struct query_info* qinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq);
void (*kill_sub)(struct module_qstate* newq);
int (*detect_cycle)(struct module_qstate* qstate,
struct query_info* qinfo, uint16_t flags, int prime,
int valrec);
struct regional* scratch;
struct sldns_buffer* scratch_buffer;
struct worker* worker;
struct mesh_area* mesh;
struct alloc_cache* alloc;
struct ub_randstate* rnd;
time_t* now;
struct timeval* now_tv;
int need_to_validate;
struct val_anchors* anchors;
struct val_neg_cache* neg_cache;
struct comm_timer* probe_timer;
struct iter_forwards* fwds;
struct iter_hints* hints;
void* modinfo[MAX_MODULE];
void* inplace_cb_lists[inplace_cb_types_total];
struct edns_known_option* edns_known_options;
size_t edns_known_options_num;
};
/* ************************************************************************************ *
Structure module_qstate
* ************************************************************************************ */
%ignore module_qstate::ext_state;
%ignore module_qstate::minfo;
/* These are ignored because we will pass a double pointer of them to Python
* with custom getmethods. This is done to bypass Swig's behavior to pass NULL
* pointers as None. */
%ignore module_qstate::edns_opts_front_in;
%ignore module_qstate::edns_opts_back_out;
%ignore module_qstate::edns_opts_back_in;
%ignore module_qstate::edns_opts_front_out;
/* Query state */
struct module_qstate {
struct query_info qinfo;
uint16_t query_flags; //See QF_BIT_xx constants
int is_priming;
uint16_t query_flags; /* See QF_BIT_xx constants */
int is_priming;
int is_valrec;
struct comm_reply* reply;
struct dns_msg* return_msg;
int return_rcode;
int return_rcode;
struct regional* region; /* unwrapped */
int curmod;
int curmod;
enum module_ext_state ext_state[MAX_MODULE];
void* minfo[MAX_MODULE];
enum module_ext_state ext_state[MAX_MODULE];
void* minfo[MAX_MODULE];
time_t prefetch_leeway;
struct module_env* env; /* unwrapped */
struct mesh_state* mesh_info;
struct edns_option* edns_opts_front_in;
struct edns_option* edns_opts_back_out;
struct edns_option* edns_opts_back_in;
struct edns_option* edns_opts_front_out;
int no_cache_lookup;
int no_cache_store;
};
%constant int MODULE_COUNT = MAX_MODULE;
@ -540,6 +685,25 @@ struct module_qstate {
def __getitem__(self, index): return _unboundmodule._ext_state_get(self.obj, index)
def __setitem__(self, index, value): _unboundmodule._ext_state_set(self.obj, index, value)
def __len__(self): return _unboundmodule.MODULE_COUNT
class EdnsOptsListIter:
def __init__(self, obj):
self._current = obj
self._temp = None
def __iter__(self): return self
def __next__(self):
"""Python 3 compatibility"""
return self._get_next()
def next(self):
"""Python 2 compatibility"""
return self._get_next()
def _get_next(self):
if not edns_opt_list_is_empty(self._current):
self._temp = self._current
self._current = _p_p_edns_option_get_next(self._current)
return _dereference_edns_option(self._temp)
else:
raise StopIteration
%}
%inline %{
@ -549,12 +713,42 @@ struct module_qstate {
}
return 0;
}
void _ext_state_set(struct module_qstate* q, int idx, enum module_ext_state state) {
if ((q != NULL) && (idx >= 0) && (idx < MAX_MODULE)) {
q->ext_state[idx] = state;
}
}
int edns_opt_list_is_empty(struct edns_option** opt) {
if (!opt || !(*opt)) return 1;
return 0;
}
struct edns_option* _dereference_edns_option(struct edns_option** opt) {
if (!opt) return NULL;
return *opt;
}
struct edns_option** _p_p_edns_option_get_next(struct edns_option** opt) {
return &(*opt)->next;
}
struct edns_option** _edns_opts_front_in_get(struct module_qstate* q) {
return &q->edns_opts_front_in;
}
struct edns_option** _edns_opts_back_out_get(struct module_qstate* q) {
return &q->edns_opts_back_out;
}
struct edns_option** _edns_opts_back_in_get(struct module_qstate* q) {
return &q->edns_opts_back_in;
}
struct edns_option** _edns_opts_front_out_get(struct module_qstate* q) {
return &q->edns_opts_front_out;
}
%}
%extend module_qstate {
@ -566,6 +760,32 @@ struct module_qstate {
def __ext_state_get(self): return ExtState(self)
__swig_getmethods__["ext_state"] = __ext_state_get
if _newclass:ext_state = _swig_property(__ext_state_get)#, __ext_state_set)
def _edns_opts_front_in_iter(self): return EdnsOptsListIter(self.edns_opts_front_in)
__swig_getmethods__["edns_opts_front_in_iter"] = _edns_opts_front_in_iter
if _newclass:edns_opts_front_in_iter = _swig_property(_edns_opts_front_in_iter)
def _edns_opts_back_out_iter(self): return EdnsOptsListIter(self.edns_opts_back_out)
__swig_getmethods__["edns_opts_back_out_iter"] = _edns_opts_back_out_iter
if _newclass:edns_opts_back_out_iter = _swig_property(_edns_opts_back_out_iter)
def _edns_opts_back_in_iter(self): return EdnsOptsListIter(self.edns_opts_back_in)
__swig_getmethods__["edns_opts_back_in_iter"] = _edns_opts_back_in_iter
if _newclass:edns_opts_back_in_iter = _swig_property(_edns_opts_back_in_iter)
def _edns_opts_front_out_iter(self): return EdnsOptsListIter(self.edns_opts_front_out)
__swig_getmethods__["edns_opts_front_out_iter"] = _edns_opts_front_out_iter
if _newclass:edns_opts_front_out_iter = _swig_property(_edns_opts_front_out_iter)
def _edns_opts_front_in(self): return _edns_opts_front_in_get(self)
__swig_getmethods__["edns_opts_front_in"] = _edns_opts_front_in
if _newclass:edns_opts_front_in = _swig_property(_edns_opts_front_in)
def _edns_opts_back_out(self): return _edns_opts_back_out_get(self)
__swig_getmethods__["edns_opts_back_out"] = _edns_opts_back_out
if _newclass:edns_opts_back_out = _swig_property(_edns_opts_back_out)
def _edns_opts_back_in(self): return _edns_opts_back_in_get(self)
__swig_getmethods__["edns_opts_back_in"] = _edns_opts_back_in
if _newclass:edns_opts_back_in = _swig_property(_edns_opts_back_in)
def _edns_opts_front_out(self): return _edns_opts_front_out_get(self)
__swig_getmethods__["edns_opts_front_out"] = _edns_opts_front_out
if _newclass:edns_opts_front_out = _swig_property(_edns_opts_front_out)
%}
}
@ -1037,8 +1257,9 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n
/* ************************************************************************************ *
Functions
* ************************************************************************************ */
// Various debuging functions
/******************************
* Various debuging functions *
******************************/
void verbose(enum verbosity_value level, const char* format, ...);
void log_info(const char* format, ...);
void log_err(const char* format, ...);
@ -1048,24 +1269,166 @@ void log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* r
void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf);
void regional_log_stats(struct regional *r);
// Free allocated memory from marked sources returning corresponding types
/***************************************************************************
* Free allocated memory from marked sources returning corresponding types *
***************************************************************************/
%typemap(newfree, noblock = 1) char * {
free($1);
}
// Mark as source returning newly allocated memory
/***************************************************
* Mark as source returning newly allocated memory *
***************************************************/
%newobject sldns_wire2str_type;
%newobject sldns_wire2str_class;
// LDNS functions
/******************
* LDNS functions *
******************/
char *sldns_wire2str_type(const uint16_t atype);
char *sldns_wire2str_class(const uint16_t aclass);
// Functions from pythonmod_utils
/**********************************
* Functions from pythonmod_utils *
**********************************/
int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo, struct reply_info* msgrep, int is_referral);
void invalidateQueryInCache(struct module_qstate* qstate, struct query_info* qinfo);
// Module conversion functions
/*******************************
* Module conversion functions *
*******************************/
const char* strextstate(enum module_ext_state s);
const char* strmodulevent(enum module_ev e);
/**************************
* Edns related functions *
**************************/
struct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code);
int edns_register_option(uint16_t opt_code, int bypass_cache_stage,
int no_aggregation, struct module_env* env);
%pythoncode %{
def register_edns_option(env, code, bypass_cache_stage=False,
no_aggregation=False):
"""Wrapper function to provide keyword attributes."""
return edns_register_option(code, bypass_cache_stage,
no_aggregation, env)
%}
/******************************
* Callback related functions *
******************************/
/* typemap to check if argument is callable */
%typemap(in) PyObject *py_cb {
if (!PyCallable_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "Need a callable object!");
return NULL;
}
$1 = $input;
}
/* typemap to get content/size from a bytearray */
%typemap(in) (size_t len, uint8_t* py_bytearray_data) {
if (!PyByteArray_CheckExact($input)) {
SWIG_exception_fail(SWIG_TypeError, "Expected bytearray!");
return NULL;
}
$2 = PyByteArray_AsString($input);
$1 = PyByteArray_Size($input);
}
int edns_opt_list_remove(struct edns_option** list, uint16_t code);
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
uint8_t* py_bytearray_data, struct regional* region);
%{
/* This function is called by unbound in order to call the python
* callback function. */
int python_inplace_cb_reply_generic(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)
{
PyObject *func, *py_edns, *py_qstate, *py_opt_list_out, *py_qinfo;
PyObject *py_rep, *py_region;
PyObject *result;
int res = 0;
func = (PyObject *) python_callback;
PyGILState_STATE gstate = PyGILState_Ensure();
py_edns = SWIG_NewPointerObj((void*) edns, SWIGTYPE_p_edns_data, 0);
py_qstate = SWIG_NewPointerObj((void*) qstate,
SWIGTYPE_p_module_qstate, 0);
py_opt_list_out = SWIG_NewPointerObj((void*) opt_list_out,
SWIGTYPE_p_p_edns_option, 0);
py_qinfo = SWIG_NewPointerObj((void*) qinfo, SWIGTYPE_p_query_info, 0);
py_rep = SWIG_NewPointerObj((void*) rep, SWIGTYPE_p_reply_info, 0);
py_region = SWIG_NewPointerObj((void*) region, SWIGTYPE_p_regional, 0);
result = PyObject_CallFunction(func, "OOOiOOO", py_qinfo, py_qstate,
py_rep, rcode, py_edns, py_opt_list_out, py_region);
Py_XDECREF(py_edns);
Py_XDECREF(py_qstate);
Py_XDECREF(py_opt_list_out);
Py_XDECREF(py_qinfo);
Py_XDECREF(py_rep);
Py_XDECREF(py_region);
if (result) {
res = PyInt_AsLong(result);
}
Py_XDECREF(result);
PyGILState_Release(gstate);
return res;
}
/* Swig implementations for Python */
static int register_inplace_cb_reply(PyObject* py_cb,
struct module_env* env)
{
int ret = inplace_cb_reply_register(
python_inplace_cb_reply_generic, (void*) py_cb, env);
if (ret) Py_INCREF(py_cb);
return ret;
}
static int register_inplace_cb_reply_cache(PyObject* py_cb,
struct module_env* env)
{
int ret = inplace_cb_reply_cache_register(
python_inplace_cb_reply_generic, (void*) py_cb, env);
if (ret) Py_INCREF(py_cb);
return ret;
}
static int register_inplace_cb_reply_local(PyObject* py_cb,
struct module_env* env)
{
int ret = inplace_cb_reply_local_register(
python_inplace_cb_reply_generic, (void*) py_cb, env);
if (ret) Py_INCREF(py_cb);
return ret;
}
static int register_inplace_cb_reply_servfail(PyObject* py_cb,
struct module_env* env)
{
int ret = inplace_cb_reply_servfail_register(
python_inplace_cb_reply_generic, (void*) py_cb, env);
if (ret) Py_INCREF(py_cb);
return ret;
}
%}
/* C declarations */
int inplace_cb_reply_register(
inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env);
int inplace_cb_reply_cache_register(
inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env);
int inplace_cb_reply_local_register(
inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env);
int inplace_cb_reply_servfail_register(
inplace_cb_reply_func_t* cb, void* cb_arg, struct module_env* env);
/* Swig declarations */
static int register_inplace_cb_reply(PyObject* py_cb,
struct module_env* env);
static int register_inplace_cb_reply_cache(PyObject* py_cb,
struct module_env* env);
static int register_inplace_cb_reply_local(PyObject* py_cb,
struct module_env* env);
static int register_inplace_cb_reply_servfail(PyObject* py_cb,
struct module_env* env);

View File

@ -112,8 +112,10 @@ int pythonmod_init(struct module_env* env, int id)
{
/* Initialize module */
FILE* script_py = NULL;
PyObject* py_cfg, *res;
PyObject* py_init_arg, *res;
PyGILState_STATE gil;
int init_standard = 1;
struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
if (!pe)
{
@ -156,10 +158,10 @@ int pythonmod_init(struct module_env* env, int id)
PyRun_SimpleString("import sys \n");
PyRun_SimpleString("sys.path.append('.') \n");
if(env->cfg->directory && env->cfg->directory[0]) {
char wdir[1524];
snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
env->cfg->directory);
PyRun_SimpleString(wdir);
char wdir[1524];
snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
env->cfg->directory);
PyRun_SimpleString(wdir);
}
PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
@ -198,11 +200,15 @@ int pythonmod_init(struct module_env* env, int id)
fclose(script_py);
if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
{
log_err("pythonmod: function init is missing in %s", pe->fname);
PyGILState_Release(gil);
return 0;
init_standard = 0;
if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
{
log_err("pythonmod: function init is missing in %s", pe->fname);
PyGILState_Release(gil);
return 0;
}
}
if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
{
@ -223,16 +229,28 @@ int pythonmod_init(struct module_env* env, int id)
return 0;
}
py_cfg = SWIG_NewPointerObj((void*) env->cfg, SWIGTYPE_p_config_file, 0);
res = PyObject_CallFunction(pe->func_init, "iO", id, py_cfg);
if (init_standard)
{
py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
}
else
{
py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
SWIGTYPE_p_config_file, 0);
}
res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
if (PyErr_Occurred())
{
log_err("pythonmod: Exception occurred in function init");
PyErr_Print();
Py_XDECREF(res);
Py_XDECREF(py_init_arg);
PyGILState_Release(gil);
return 0;
}
Py_XDECREF(res);
Py_XDECREF(py_cfg);
Py_XDECREF(py_init_arg);
PyGILState_Release(gil);
return 1;

View File

@ -55,14 +55,22 @@ int pythonmod_init(struct module_env* env, int id);
void pythonmod_deinit(struct module_env* env, int id);
/** python module operate on a query */
void pythonmod_operate(struct module_qstate* qstate, enum module_ev event, int id, struct outbound_entry* outbound);
void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
int id, struct outbound_entry* outbound);
/** python module */
void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super);
void pythonmod_inform_super(struct module_qstate* qstate, int id,
struct module_qstate* super);
/** python module cleanup query state */
void pythonmod_clear(struct module_qstate* qstate, int id);
/** python module alloc size routine */
size_t pythonmod_get_mem(struct module_env* env, int id);
/** Declared here for fptr_wlist access. The definition is in interface.i. */
int python_inplace_cb_reply_generic(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);
#endif /* PYTHONMOD_H */

17
pythonmod/test-edns.conf Normal file
View File

@ -0,0 +1,17 @@
# Example configuration file for edns.py
server:
verbosity: 1
interface: 0.0.0.0
do-daemonize: no
access-control: 0.0.0.0/0 allow
chroot: ""
username: ""
directory: ""
logfile: ""
pidfile: "unbound.pid"
module-config: "validator python iterator"
# Python config section
python:
# Script file to load
python-script: "./examples/edns.py"

View File

@ -0,0 +1,17 @@
# Example configuration file for edns.py
server:
verbosity: 1
interface: 0.0.0.0
do-daemonize: no
access-control: 0.0.0.0/0 allow
chroot: ""
username: ""
directory: ""
logfile: ""
pidfile: "unbound.pid"
module-config: "validator python iterator"
# Python config section
python:
# Script file to load
python-script: "./examples/inplace_callbacks.py"

View File

@ -194,6 +194,7 @@ msg_cache_lookup(struct module_env* env, uint8_t* qname, size_t qnamelen,
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));
@ -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) {

View File

@ -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)
@ -154,7 +159,7 @@ 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;
@ -181,13 +186,17 @@ 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);
local_zone_delete(oldz);
return z;
}
lock_rw_unlock(&zones->lock);
@ -275,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;
}
@ -342,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);
@ -459,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)
@ -479,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 */
@ -1148,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;
@ -1168,23 +1202,22 @@ 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;
}
/** 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,
uint8_t* zname, size_t zlen)
struct ub_packed_rrset_key* r, struct regional* temp)
{
struct config_strlist* p;
char buf[65536];
@ -1193,18 +1226,21 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
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,
zname, zlen, NULL, 0);
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;
if(sldns_wirerr_get_type(rr, len, 1) != qinfo->qtype)
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 */
@ -1212,7 +1248,7 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
r->entry.key = r;
r->rk.dname = qinfo->qname;
r->rk.dname_len = qinfo->qname_len;
r->rk.type = htons(qinfo->qtype);
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(
@ -1261,6 +1297,20 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
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;
@ -1268,11 +1318,11 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
/** answer local data match */
static int
local_data_answer(struct local_zone* z, struct 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)
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;
@ -1288,11 +1338,17 @@ local_data_answer(struct local_zone* z, struct query_info* qinfo,
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,
z->name, z->namelen)) {
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"));
return local_encode(qinfo, edns, buf, temp,
/* 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);
}
}
@ -1302,24 +1358,42 @@ local_data_answer(struct local_zone* z, struct query_info* qinfo,
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;
/* 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.
@ -1329,9 +1403,9 @@ local_data_answer(struct local_zone* z, struct query_info* qinfo,
* @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, enum localzone_type lz_type)
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(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) {
/** no reply at all, signal caller by clearing buffer. */
@ -1357,7 +1431,7 @@ lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
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),
@ -1375,7 +1449,7 @@ lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
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),
@ -1402,7 +1476,7 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo,
log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
}
enum localzone_type
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_t* override_tree, int* tag,
@ -1448,54 +1522,79 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
}
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, uint8_t* taglist, size_t taglen,
uint8_t* tagactions, size_t tagactionssize,
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)
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 = NULL;
struct local_zone* z;
enum localzone_type lzt;
struct local_zone* z = NULL;
enum localzone_type lzt = local_zone_transparent;
int r, tag = -1;
lock_rw_rdlock(&zones->lock);
z = local_zones_tags_lookup(zones, qinfo->qname,
qinfo->qname_len, labs, qinfo->qclass, taglist, taglen, 0);
if(!z) {
lock_rw_unlock(&zones->lock);
return 0;
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);
}
lock_rw_rdlock(&z->lock);
lock_rw_unlock(&zones->lock);
lzt = lz_type(taglist, taglen, z->taglist, z->taglen, tagactions,
tagactionssize, z->type, repinfo, z->override_tree, &tag,
tagname, num_tags);
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);
}
if((lzt == local_zone_inform || lzt == local_zone_inform_deny)
&& repinfo)
lz_inform_print(z, qinfo, repinfo);
if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain
&& local_data_answer(z, qinfo, edns, buf, temp, labs, &ld, lzt,
tag, tag_datas, tag_datas_size, tagname, num_tags)) {
&& 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, lzt);
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";

View File

@ -44,6 +44,8 @@
#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;
@ -59,8 +61,10 @@ struct config_strlist;
* 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 */
@ -264,6 +268,7 @@ 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.
@ -277,16 +282,25 @@ void local_zones_print(struct local_zones* zones);
* @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, uint8_t* taglist, size_t taglen,
uint8_t* tagactions, size_t tagactionssize,
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);
char** tagname, int num_tags, struct view* view);
/**
* Parse the string into localzone type.

View File

@ -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)
@ -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)) {
@ -315,13 +326,32 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
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);
@ -380,10 +411,13 @@ 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)
{
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 */
@ -395,6 +429,15 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
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,7 +476,8 @@ 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;
#endif
@ -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)
{
@ -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");
@ -701,8 +767,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
struct rbnode_t* 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;
@ -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 */
@ -963,6 +1064,10 @@ 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;
@ -996,7 +1101,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 +1120,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 +1370,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);
}

View File

@ -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;
@ -214,6 +216,8 @@ 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;
};
/**
@ -414,6 +418,21 @@ void mesh_state_delete(struct module_qstate* qstate);
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.
@ -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.

View File

@ -1879,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,
@ -1986,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_t* 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). */
@ -2006,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;

View File

@ -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.
@ -471,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.
@ -484,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_t* callback, void* callback_arg,
struct sldns_buffer* buff, struct module_env* env);
/**
* Remove service query callback.

207
services/view.c Normal file
View File

@ -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_t* 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_t));
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;
}

135
services/view.h Normal file
View File

@ -0,0 +1,135 @@
/*
* 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_t lock;
/** rbtree of struct view */
rbtree_t vtree;
};
/**
* View. Named structure holding local authority zones.
*/
struct view {
/** rbtree node, key is name */
rbnode_t 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 (or to
* delete this view) */
lock_rw_t 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 */

View File

@ -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;

View File

@ -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;

View File

@ -420,8 +420,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);
@ -432,6 +438,7 @@ read_builtin_cert(void)
exit(0);
}
BIO_free(bio);
free(d);
return sk;
}

View File

@ -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 */
@ -486,7 +492,7 @@ check_hints(struct config_file* cfg)
static void
checkconf(const char* cfgfile, const char* opt, int final)
{
char oldwd[PATH_MAX];
char oldwd[4096];
struct config_file* cfg = config_create();
if(!cfg)
fatal_exit("out of memory");

View File

@ -176,7 +176,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;
@ -300,6 +303,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 +337,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();

View File

@ -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))

View File

@ -470,7 +470,7 @@ int main(int argc, char** argv)
return 1;
}
/* perform asyncronous calls */
/* perform asynchronous calls */
num_wait = argc;
for(i=0; i<argc; i++) {
lookups[i].name = argv[i];

View File

@ -1036,13 +1036,13 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
}
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 ATTR_UNUSED(want_dnssec),
int ATTR_UNUSED(nocaps), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), struct edns_option* opt_list,
struct query_info* qinfo, uint16_t flags, int dnssec,
int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(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* ATTR_UNUSED(buff))
size_t zonelen, struct module_qstate* qstate,
comm_point_callback_t* callback, void* callback_arg,
sldns_buffer* ATTR_UNUSED(buff), struct module_env* ATTR_UNUSED(env))
{
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
struct fake_pending* pend = (struct fake_pending*)calloc(1,
@ -1050,7 +1050,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
char z[256];
log_assert(pend);
log_nametypeclass(VERB_OPS, "pending serviced query",
qname, qtype, qclass);
qinfo->qname, qinfo->qtype, qinfo->qclass);
dname_str(zone, z);
verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s",
z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"",
@ -1065,9 +1065,9 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
sldns_buffer_write_u16(pend->buffer, 0); /* ancount */
sldns_buffer_write_u16(pend->buffer, 0); /* nscount */
sldns_buffer_write_u16(pend->buffer, 0); /* arcount */
sldns_buffer_write(pend->buffer, qname, qnamelen);
sldns_buffer_write_u16(pend->buffer, qtype);
sldns_buffer_write_u16(pend->buffer, qclass);
sldns_buffer_write(pend->buffer, qinfo->qname, qinfo->qname_len);
sldns_buffer_write_u16(pend->buffer, qinfo->qtype);
sldns_buffer_write_u16(pend->buffer, qinfo->qclass);
sldns_buffer_flip(pend->buffer);
if(1) {
/* add edns */
@ -1077,7 +1077,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits = 0;
edns.opt_list = opt_list;
edns.opt_list = qstate->edns_opts_back_out;
if(dnssec)
edns.bits = EDNS_DO;
attach_edns_record(pend->buffer, &edns);
@ -1086,7 +1086,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
pend->addrlen = addrlen;
pend->zone = memdup(zone, zonelen);
pend->zonelen = zonelen;
pend->qtype = (int)qtype;
pend->qtype = (int)qinfo->qtype;
log_assert(pend->zone);
pend->callback = callback;
pend->cb_arg = callback_arg;

View File

@ -236,6 +236,7 @@ printstats(rbtree_t* tree)
int main(int argc, const char* argv[])
{
rbtree_t* tree = 0;
log_init(NULL, 0, 0);
if(argc != 2) {
usage();
}

View File

@ -487,6 +487,7 @@ qlist_parse_line(sldns_buffer* buf, char* p)
qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len);
if(!qinfo.qname)
return 0;
qinfo.local_alias = NULL;
qinfo_query_encode(buf, &qinfo);
sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */
if(rec) LDNS_RD_SET(sldns_buffer_begin(buf));

View File

@ -128,6 +128,9 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
/* clear local alias */
qinfo.local_alias = NULL;
/* make query */
qinfo_query_encode(buf, &qinfo);
sldns_buffer_write_u16_at(buf, 0, id);

Binary file not shown.

Binary file not shown.

491
testdata/local_cname.rpl vendored Normal file
View File

@ -0,0 +1,491 @@
; config options
server:
# put unbound.conf config options here.
access-control: 127.0.0.1/32 allow_snoop #allow queries with RD bit
# DNSSEC trust anchor taken from a real world example. Used for
# DNSSEC-signed CNAME target.
trust-anchor: "infoblox.com. 172800 IN DNSKEY 257 3 5 AwEAAerW6xQkJIb5wxm48RoHD/LE8r/GzmdIGOam0lQczIth+I9ctltV dDJXz5BH8j4TOaOH1gBRCXhsPDyPom/eLEkdUuXNuhV6QnWGHOtz1fuY EO+kBqaI79jR0K31OmevR/H/F3C8gi4T6//6G9qsftvcl6m7+V1vI2+c cgxiiOlMrZZb4YAhue1+tRw57f3aVOSNtcrONO/Jffgb9jbDTKRi33oT fDznyPa1lCWMbuybr/LaCU0LP6fG4BII/FDWFi5rQxMHygWfscdYX06c eGUzHqiuNNGL8Jze6johni71T/hJGtLMozkY7qxOLfWBXOu9kr1MBQh5 6hfibOZMZJM="
# Use a fixed and faked date for DNSSEC validation to avoid run-time
# re-signing test signatures.
val-override-date: "20161001003725"
define-tag: "cname cname2 nx servfail sec ambiguous"
access-control-tag: 127.0.0.1/32 "cname cname2 nx servfail sec"
# Basic case: one CNAME whose target exists.
local-zone: example.com static
local-zone-tag: example.com "cname"
access-control-tag: 127.0.0.1/32 "cname"
access-control-tag-action: 127.0.0.1/32 "cname" redirect
access-control-tag-data: 127.0.0.1/32 "cname" "CNAME example.org."
# Similar to the above, but different original query name.
local-zone: another.example.com static
local-zone-tag: another.example.com "cname2"
access-control-tag: 127.0.0.1/32 "cname2"
access-control-tag-action: 127.0.0.1/32 "cname2" redirect
access-control-tag-data: 127.0.0.1/32 "cname2" "CNAME example.org."
# CNAME target is expected to be nonexistent.
local-zone: nx.example.com static
local-zone-tag: nx.example.com "nx"
access-control-tag: 127.0.0.1/32 "nx"
access-control-tag-action: 127.0.0.1/32 "nx" redirect
access-control-tag-data: 127.0.0.1/32 "nx" "CNAME nx.example.org."
# Resolution of this CNAME target will result in SERVFAIL.
local-zone: servfail.example.com static
local-zone-tag: servfail.example.com "servfail"
access-control-tag-action: 127.0.0.1/32 "servfail" redirect
access-control-tag-data: 127.0.0.1/32 "servfail" "CNAME servfail.example.org."
# CNAME target is supposed to be DNSSEC-signed.
local-zone: sec.example.com static
local-zone-tag: sec.example.com "sec"
access-control-tag-action: 127.0.0.1/32 "sec" redirect
access-control-tag-data: 127.0.0.1/32 "sec" "CNAME www.infoblox.com."
# Test setup for non-tag based redirect
local-zone: example.net redirect
local-data: "example.net. IN CNAME cname.example.org."
### template zone and tag intended to be used for tests with CNAME and
### other data.
##local-zone: ambiguous.example.com redirect
##@LOCALDATA1@
##@LOCALDATA2@
##local-zone-tag: ambiguous.example.com "ambiguous"
##access-control-tag-action: 127.0.0.1/32 "ambiguous" redirect
##@TAGDATA1@
##@TAGDATA2@
target-fetch-policy: "0 0 0 0 0"
# send the queries to the test server (see the 10.0.10.3 entries below)
forward-zone:
name: "."
forward-addr: 10.0.10.3
CONFIG_END
; short one-line description of scenario:
SCENARIO_BEGIN Test local-data CNAME aliases
; Specification of the answers that the upstream server provides to unbound
RANGE_BEGIN 0 1000
ADDRESS 10.0.10.3
; put entries here with answers to specific qname, qtype
; infoblox.com
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
infoblox.com. IN DNSKEY
SECTION ANSWER
infoblox.com. 172800 IN DNSKEY 256 3 5 AwEAAbi2VnVHFm5rO2EiawNWhTTRPPzaA+VEdpGOc+CtwIZq86C4Ndbp 0M7XTi0wru0Pgh54oGZ3ty9WllYEnVfoA1rcGwFJmAln7KKAuQP+dlGE yHPJYduAjG/JFA6Qq0zj18AmWgks+qvethASMm3PtihQkNytjmQWjiL6 6h8cQwFP
infoblox.com. 172800 IN DNSKEY 257 3 5 AwEAAerW6xQkJIb5wxm48RoHD/LE8r/GzmdIGOam0lQczIth+I9ctltV dDJXz5BH8j4TOaOH1gBRCXhsPDyPom/eLEkdUuXNuhV6QnWGHOtz1fuY EO+kBqaI79jR0K31OmevR/H/F3C8gi4T6//6G9qsftvcl6m7+V1vI2+c cgxiiOlMrZZb4YAhue1+tRw57f3aVOSNtcrONO/Jffgb9jbDTKRi33oT fDznyPa1lCWMbuybr/LaCU0LP6fG4BII/FDWFi5rQxMHygWfscdYX06c eGUzHqiuNNGL8Jze6johni71T/hJGtLMozkY7qxOLfWBXOu9kr1MBQh5 6hfibOZMZJM=
infoblox.com. 172800 IN RRSIG DNSKEY 5 2 172800 20161004003725 20160930000830 31651 infoblox.com. Ds7LZY2W59fq9cWgqi3W6so1NGFa7JdjO8zlhK3hGu2a2WG1W/rVftom rCf0gdI5q4BZJnq2o0SdLd/U7he1uWz8ATntEETiNs9/8G7myNK17wQu AN/+3gol+qT4DX0CA3Boz7Z+xFQbTwnnJJvGASa/1jPMIYU8DiyNx3Pe SSh9lbyU/4YI0mshn5ZC2HCFChxr+aVJxk4UHjaPfHhWwVu9oM4IbEfn KD9x4ltKjjy0pXMYqVlNs9+tG2nXdwr/6Q4G+yfRBAcW+cWeW5w4igxf xYFq4Y5gkZetGOReoNODZ9YC9WvcxBo+qY/iUN2k+lEFq+oL8+DthAGH uA1krw==
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
www.infoblox.com. IN A
SECTION ANSWER
www.infoblox.com. 3600 IN A 161.47.10.70
www.infoblox.com. 3600 IN RRSIG A 5 3 3600 20161003223322 20160929221122 14916 infoblox.com. WbO9ydRAoRTPvdK18atTdLEkkMGoOjuwbcb6vVI0d6Sea3xkcBMNmtst Wdzr+pKEJqO2bfm167X6uhcOHanHZRnirlTnEbuTdsP0HCiIEGQD5iHg UNH2FJSKGNYBmgZKJpuLhDca7oqtkl8EyGA+UEt6Rtq6aW8V0wpkhPHi Pug='
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; example.org
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.org. IN A
SECTION ANSWER
example.org. IN A 192.0.2.1
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
cname.example.org. IN A
SECTION ANSWER
cname.example.org. IN A 192.0.2.2
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.org. IN AAAA
SECTION ANSWER
SECTION AUTHORITY
example.org. IN SOA ns.example.org. hostmaster.example.org. 2016101900 28800 7200 604800 3600
SECTION ADDITIONAL
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NXDOMAIN
SECTION QUESTION
nx.example.org. IN A
SECTION ANSWER
SECTION AUTHORITY
example.org. IN SOA ns.example.org. hostmaster.example.org. 2016101900 28800 7200 604800 3600
SECTION ADDITIONAL
ENTRY_END
; for norec query
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example.org. IN NS
SECTION ANSWER
example.org. IN NS ns.example.
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR SERVFAIL
SECTION QUESTION
servfail.example.org. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; end of entries with answers from upstream server
RANGE_END
; Steps where queries are sent, one at a time, to unbound.
; QUERY is what the downstream client sends to unbound.
; CHECK_ANSWER contains the response from unbound.
; Basic case: both exact and subdomain matches result in the same CNAME
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.com. IN CNAME
ENTRY_END
; For type-CNAME queries, the CNAME itself will be returned
STEP 20 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
example.com. IN CNAME
SECTION ANSWER
example.com. IN CNAME example.org.
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
alias.example.com. IN CNAME
ENTRY_END
; For type-CNAME queries, the CNAME itself will be returned
STEP 40 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
alias.example.com. IN CNAME
SECTION ANSWER
alias.example.com. IN CNAME example.org.
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; Basic case: both exact and subdomain matches result in the same CNAME
; For other types, a complete CNAME chain will have to be returned
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.com. IN A
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
example.com. IN A
SECTION ANSWER
example.com. IN CNAME example.org.
example.org. IN A 192.0.2.1
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 70 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
alias.example.com. IN A
ENTRY_END
STEP 80 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
alias.example.com. IN A
SECTION ANSWER
alias.example.com. IN CNAME example.org.
example.org. IN A 192.0.2.1
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; Basic case: both exact and subdomain matches result in the same CNAME.
; The result is the same for non-recursive query as long as a
; complete chain is cached.
STEP 90 QUERY
ENTRY_BEGIN
REPLY
SECTION QUESTION
example.com. IN A
ENTRY_END
STEP 100 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RA AA NOERROR
SECTION QUESTION
example.com. IN A
SECTION ANSWER
example.com. IN CNAME example.org.
example.org. IN A 192.0.2.1
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 110 QUERY
ENTRY_BEGIN
REPLY
SECTION QUESTION
alias.example.com. IN A
ENTRY_END
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RA AA NOERROR
SECTION QUESTION
alias.example.com. IN A
SECTION ANSWER
alias.example.com. IN CNAME example.org.
example.org. IN A 192.0.2.1
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; Similar to the above, but these are local-zone redirect, instead of
; tag-based policies.
STEP 130 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.net. IN CNAME
ENTRY_END
; For type-CNAME queries, the CNAME itself will be returned
STEP 140 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
example.net. IN CNAME
SECTION ANSWER
example.net. IN CNAME cname.example.org.
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 150 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
alias.example.net. IN CNAME
ENTRY_END
; For type-CNAME queries, the CNAME itself will be returned
STEP 160 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
alias.example.net. IN CNAME
SECTION ANSWER
alias.example.net. IN CNAME cname.example.org.
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 170 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.net. IN A
ENTRY_END
STEP 180 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
example.net. IN A
SECTION ANSWER
example.net. IN CNAME cname.example.org.
cname.example.org. IN A 192.0.2.2
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
STEP 190 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
alias.example.net. IN A
ENTRY_END
STEP 200 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
alias.example.net. IN A
SECTION ANSWER
alias.example.net. IN CNAME cname.example.org.
cname.example.org. IN A 192.0.2.2
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; Relatively minor cases follow
; query type doesn't exist for the CNAME target. The original query
; succeeds with an "incomplete" chain only containing the CNAME.
STEP 210 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.com. IN AAAA
ENTRY_END
STEP 220 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
example.com. IN AAAA
SECTION ANSWER
example.com. IN CNAME example.org.
SECTION AUTHORITY
example.org. 3600 IN SOA ns.example.org. hostmaster.example.org. 2016101900 28800 7200 604800 3600
SECTION ADDITIONAL
ENTRY_END
; The CNAME target name doesn't exist. NXDOMAIN with the CNAME will
; be returned.
STEP 230 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
nx.example.com. IN A
ENTRY_END
STEP 240 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
nx.example.com. IN A
SECTION ANSWER
nx.example.com. IN CNAME nx.example.org.
SECTION AUTHORITY
example.org. 3600 IN SOA ns.example.org. hostmaster.example.org. 2016101900 28800 7200 604800 3600
SECTION ADDITIONAL
ENTRY_END
; Resolution for the CNAME target will result in SERVFAIL. It will
; be forwarded to the original query. The answer section should be
; empty.
STEP 250 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
servfail.example.com. IN A
ENTRY_END
STEP 260 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA SERVFAIL
SECTION QUESTION
servfail.example.com. IN A
SECTION ANSWER
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
; The CNAME target is DNSSEC-signed and it's validated. If the original
; query enabled the DNSSEC, the RRSIGs will be included in the answer,
; but the response should have the AD bit off
STEP 270 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
sec.example.com. IN A
ENTRY_END
STEP 280 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD DO RA AA NOERROR
SECTION QUESTION
sec.example.com. IN A
SECTION ANSWER
sec.example.com. IN CNAME www.infoblox.com.
www.infoblox.com. 3600 IN A 161.47.10.70
www.infoblox.com. 3600 IN RRSIG A 5 3 3600 20161003223322 20160929221122 14916 infoblox.com. WbO9ydRAoRTPvdK18atTdLEkkMGoOjuwbcb6vVI0d6Sea3xkcBMNmtst Wdzr+pKEJqO2bfm167X6uhcOHanHZRnirlTnEbuTdsP0HCiIEGQD5iHg UNH2FJSKGNYBmgZKJpuLhDca7oqtkl8EyGA+UEt6Rtq6aW8V0wpkhPHi Pug='
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
SCENARIO_END

110
testdata/stop_nxdomain_minimised.rpl vendored Normal file
View File

@ -0,0 +1,110 @@
; config options
server:
target-fetch-policy: "0 0 0 0 0"
harden-below-nxdomain: yes
qname-minimisation: yes
trust-anchor: ". IN DNSKEY 257 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3"
val-override-date: "20070916134226"
stub-zone:
name: "."
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
stub-zone:
name: "anotherexample.local."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test stop cache search on nxdomain for QNAME minimised query
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN DNSKEY
SECTION ANSWER
. 3600 IN DNSKEY 257 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30900 (ksk), size = 512b}
. 3600 IN RRSIG DNSKEY 5 0 3600 20070926134150 20070829134150 30900 . BlVcSh8xSgm7ne+XVCJwNHQKjk5kTJgG4Fa3sOSfp3YUjb2YclmVWyIw7XEHl0/C6CN5gdy18idnM6vT6Hy42A== ;{id = 30900}
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NXDOMAIN
SECTION QUESTION
local. IN A
SECTION AUTHORITY
. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400
. 86400 IN RRSIG SOA 5 0 86400 20070926134150 20070829134150 30900 . bOYbFZZp7vWWC2oxV+kph+YXjoQj2f6QJktlgmzRI7oReFX9jy/LibTPQi/sW0SGHpLaj3G5p4IfIlBibne4DA== ;{id = 30900}
. 86400 IN NSEC ac. NS SOA RRSIG NSEC DNSKEY
. 86400 IN RRSIG NSEC 5 0 86400 20070926134150 20070829134150 30900 . U+/m5+FmczzkosEx1aTP7MK/F3PpcKWct8CzM1jhjwNe2RlnW7qFe0IH8SLzD/elvxDTQMpJSMlKOhUUdapB8g== ;{id = 30900}
lk. 86400 IN NSEC lr. NS DS RRSIG NSEC
lk. 86400 IN RRSIG NSEC 5 1 86400 20070926134150 20070829134150 30900 . j6Pw5Eu9vGHDJcckTSWa8YD1b7FV7c/Z8aVkLfJCH+iPcaa40/LSp784+t2PnAAXL8fgriNL6jF/ve1rti3ANQ== ;{id = 30900}
ENTRY_END
RANGE_END
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
anotherexample.local. IN TXT
SECTION ANSWER
anotherexample.local. 86400 IN TXT "should not resolve this"
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
example.local. IN TXT
ENTRY_END
; recursion happens here.
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
example.local. IN TXT
SECTION AUTHORITY
. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
anotherexample.local. IN TXT
ENTRY_END
; query should be answered using NXDOMAIN for local in cache
STEP 30 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
anotherexample.local. IN TXT
SECTION AUTHORITY
. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400
ENTRY_END
SCENARIO_END

View File

@ -11,7 +11,7 @@ stub-zone:
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
CONFIG_END
SCENARIO_BEGIN Test validator with wilcard cname to nodata
SCENARIO_BEGIN Test validator with wildcard cname to nodata
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100

View File

@ -4,6 +4,7 @@ server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
fake-dsa: yes
stub-zone:
name: "."

View File

@ -4,6 +4,7 @@ server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
fake-dsa: yes
stub-zone:
name: "."

View File

@ -130,8 +130,10 @@ SECTION ANSWER
SECTION AUTHORITY
; SOA record is missing in reply.
; Denies A, note this is the end of the NSEC chain.
; this RRSIG is failed, we set to 0 base64 data to make this easy to detect
www.example.com. IN NSEC example.com. RRSIG NSEC
www.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFDA8yqBITvLruoQjn/eqjYjwCwySAhUAk5/f3H1HKMsvM+spmmswwFtndyY= ;{id = 2854}
;www.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFDA8yqBITvLruoQjn/eqjYjwCwySAhUAk5/f3H1HKMsvM+spmmswwFtndyY= ;{id = 2854}
www.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926135752 20070829135752 2854 example.com.
; Denies wildcard
example.com. IN NSEC ns.example.com. NS SOA RRSIG NSEC DNSKEY
example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. MCwCFGlz/gvGdVxEo3Kpr+MijEGCZgwaAhRU7qbF13vmCVgR8dFw7LQFKopV6w== ;{id = 2854}

Some files were not shown because too many files have changed in this diff Show More