mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
282
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82e4110e09 | ||
|
|
fb57492c0a | ||
|
|
bde1ce87d5 | ||
|
|
b7a627b8cc | ||
|
|
ea7630845f | ||
|
|
04edbb68b7 | ||
|
|
2884751446 | ||
|
|
c8982075c5 | ||
|
|
0c8d24b653 | ||
|
|
d2b3e464ac | ||
|
|
f3525b2081 | ||
|
|
849026931b | ||
|
|
da073cfc3e | ||
|
|
caaad8b810 | ||
|
|
0fe0251c8d | ||
|
|
9be27227a1 | ||
|
|
a9a47f8b41 | ||
|
|
46f7dc4d08 | ||
|
|
0e5b4105d1 | ||
|
|
9b31997a4c | ||
|
|
98552115d0 | ||
|
|
d58327876f | ||
|
|
8b048a8229 | ||
|
|
967793aad3 | ||
|
|
6ffe218762 | ||
|
|
da8ae735ce | ||
|
|
8cdb815df6 | ||
|
|
e48ecb0e15 | ||
|
|
635c65f4ed | ||
|
|
2b4ef794b9 | ||
|
|
0e1b3fb3e0 | ||
|
|
be483a3bfb | ||
|
|
6ef599255d | ||
|
|
c8f2bf0333 | ||
|
|
e5196b25ae | ||
|
|
193892e52d | ||
|
|
a6c543362d | ||
|
|
32396dc677 | ||
|
|
ed57c4de4c | ||
|
|
bfe329e34d | ||
|
|
9e30587b1e | ||
|
|
cf9837bf7f | ||
|
|
0bdfbccbdc | ||
|
|
3bb9aaafca | ||
|
|
7bfaf07981 | ||
|
|
2e28288b1d | ||
|
|
452b7cc069 | ||
|
|
4d194ac2fa | ||
|
|
f041511951 | ||
|
|
0e4bda4c55 | ||
|
|
e56a3a60ef | ||
|
|
faa7ad14c6 | ||
|
|
c87fe76e47 | ||
|
|
a18af6d1e1 | ||
|
|
3adebc8721 | ||
|
|
1a4fadaf00 | ||
|
|
b26f289ccc | ||
|
|
0e000a8587 | ||
|
|
84ae5c8e79 | ||
|
|
05f9d35f00 | ||
|
|
c7ad292438 | ||
|
|
b63db13e72 | ||
|
|
6ee18c6824 | ||
|
|
e8f4ac9b1a | ||
|
|
5e420a8275 | ||
|
|
bb3a1178b6 | ||
|
|
306db56f1f | ||
|
|
95b0a129e2 | ||
|
|
c4e1a83be5 | ||
|
|
fec9e1d262 | ||
|
|
c854c57c6f | ||
|
|
ee6e142192 | ||
|
|
ac74d176cc | ||
|
|
8343901c0f | ||
|
|
b7745a2e53 | ||
|
|
82cab3f855 | ||
|
|
6ce08cf242 | ||
|
|
877038b6d9 | ||
|
|
a2227517ed | ||
|
|
04a896098e | ||
|
|
7e84653485 | ||
|
|
71723c6276 | ||
|
|
219d0c70dd | ||
|
|
85c88707ca | ||
|
|
e7d64c7eac | ||
|
|
d7d8e117ef | ||
|
|
d9e9a31562 | ||
|
|
5d594b301f | ||
|
|
648a776493 | ||
|
|
8404701a09 | ||
|
|
4b065a443c | ||
|
|
0b04728785 | ||
|
|
76a31aacd3 | ||
|
|
179273a13a | ||
|
|
7f8b84d0e5 | ||
|
|
2b08436c4c | ||
|
|
5cc518f114 | ||
|
|
1315edc5e9 | ||
|
|
97f5d3d28e | ||
|
|
ad78119e19 | ||
|
|
2756924a44 | ||
|
|
3fd809d537 | ||
|
|
22b8057cca | ||
|
|
fe6f28ddc5 | ||
|
|
1e4dc049eb | ||
|
|
1a4d24816b | ||
|
|
1f47306af9 | ||
|
|
f1a3c9b646 | ||
|
|
a67e62dd40 | ||
|
|
1b6d254224 | ||
|
|
a0e442eb32 | ||
|
|
7eaceaab2f | ||
|
|
2ba3ff9f7d | ||
|
|
e7cb0f27cc | ||
|
|
317938efba | ||
|
|
d6ce1f426d | ||
|
|
9f97c4ac44 | ||
|
|
6a5f5e652a | ||
|
|
61b42edaef | ||
|
|
060d4740c2 | ||
|
|
5a198e0b4c | ||
|
|
abf85e9270 | ||
|
|
ab4b9aa250 | ||
|
|
a2f143cfcc | ||
|
|
e297886386 | ||
|
|
cdf334528f | ||
|
|
1f9ad9e66e | ||
|
|
75073cefea | ||
|
|
9374c1465a | ||
|
|
a2311972e7 | ||
|
|
11a764a82f | ||
|
|
f187e1da7e | ||
|
|
2dbc83d5ae | ||
|
|
fcac316d63 | ||
|
|
43a2640a9c | ||
|
|
8892d4b63c | ||
|
|
1c33240c16 | ||
|
|
b97a63aa95 | ||
|
|
2ef042ef0e | ||
|
|
185c6f76b1 | ||
|
|
87fe7013a0 | ||
|
|
77019eeb5e | ||
|
|
1152a4c5e8 | ||
|
|
83f8775d5a | ||
|
|
d9907b118f | ||
|
|
6ccdaf41e5 | ||
|
|
eb4ba518f1 | ||
|
|
6a355b37fe | ||
|
|
e12d274954 | ||
|
|
9ade3e4811 | ||
|
|
2c2eaecc6c | ||
|
|
16906c53e6 | ||
|
|
b6d9b4bfcc | ||
|
|
6bb12a5776 | ||
|
|
bce6c3405b | ||
|
|
aa0c26ddec | ||
|
|
a1cbd214a5 | ||
|
|
f64778a893 | ||
|
|
9d3b5fa30d | ||
|
|
99590f93bd | ||
|
|
b72563dcb7 | ||
|
|
6b0cf42b32 | ||
|
|
8df2959959 | ||
|
|
1cda904545 | ||
|
|
416129dedb | ||
|
|
b9c417481b | ||
|
|
eda6528c14 | ||
|
|
fc8657c421 | ||
|
|
5f50f5d2b4 | ||
|
|
31f803201d | ||
|
|
ff975871ab | ||
|
|
99a9914605 | ||
|
|
435fbd1794 | ||
|
|
fe09abe4e6 | ||
|
|
e900e44f9f | ||
|
|
bfbac6bb36 | ||
|
|
cc21a1ca9a | ||
|
|
919b1ab1b6 | ||
|
|
ad69492495 | ||
|
|
2b2cfd7e4b | ||
|
|
84a3dbe660 | ||
|
|
d7b0d86b09 | ||
|
|
bce5467f59 | ||
|
|
a6ae1d6194 | ||
|
|
0ee5532396 | ||
|
|
7c5182d3fd | ||
|
|
d41f40b028 | ||
|
|
518e7511d7 | ||
|
|
6048ba67fa | ||
|
|
0eddfd7528 | ||
|
|
3ed2f28b76 | ||
|
|
e9277fc201 | ||
|
|
5d5f08e4fd | ||
|
|
a06131872d | ||
|
|
d2892aa5ab | ||
|
|
27c8952a2c | ||
|
|
5b966557cc | ||
|
|
734abf9323 | ||
|
|
2725ad55fc | ||
|
|
f79c387f3f | ||
|
|
2e9785cfb5 | ||
|
|
75c30382ba | ||
|
|
fe44f5918a | ||
|
|
63dc8ffde2 | ||
|
|
2bb408e2aa | ||
|
|
0eb3149af5 | ||
|
|
298e1fd688 | ||
|
|
861483ac82 | ||
|
|
f92d51b3fe | ||
|
|
633daf4bc7 | ||
|
|
b247774236 | ||
|
|
63aa7463e8 | ||
|
|
280352760c | ||
|
|
f8dcdf6e3a | ||
|
|
2885210384 | ||
|
|
253a6e0143 | ||
|
|
90df76f931 | ||
|
|
391504fd03 | ||
|
|
da79cd57d9 | ||
|
|
c8c099960a | ||
|
|
3a84f02606 | ||
|
|
086b257b1d | ||
|
|
f22716c237 | ||
|
|
c74ae3212b | ||
|
|
b40163446e | ||
|
|
ce11690aa1 | ||
|
|
6f49c2fe55 | ||
|
|
63bef95aac | ||
|
|
f768fc1148 | ||
|
|
8e54424abc | ||
|
|
c41d12bb94 | ||
|
|
268ada0d33 | ||
|
|
907ab3d99a | ||
|
|
f12875c910 | ||
|
|
482658b1cc | ||
|
|
75792c34dc | ||
|
|
be0bdf0260 | ||
|
|
08549c7610 | ||
|
|
108539c94c | ||
|
|
a4d4d0fe3a | ||
|
|
9e732da50b | ||
|
|
fe33f7c72c | ||
|
|
631ccb58bf | ||
|
|
189fafa1da | ||
|
|
4260a18fb1 | ||
|
|
79f840acd4 | ||
|
|
fed59bca84 | ||
|
|
aecdb781fc | ||
|
|
bef17e9e7c | ||
|
|
25da698bf1 | ||
|
|
3aea7c2630 | ||
|
|
d4424931f4 | ||
|
|
a5ac86f410 | ||
|
|
aed61e4d8a | ||
|
|
c46e1a1ee8 | ||
|
|
2bfe2d5fe3 | ||
|
|
75bfcb8c91 | ||
|
|
f4049b54c4 | ||
|
|
9fec5d86d3 | ||
|
|
f856eef411 | ||
|
|
24d1ed15c4 | ||
|
|
26c4e7a182 | ||
|
|
8e55996b7c | ||
|
|
2a547a35a7 | ||
|
|
9a60182c86 | ||
|
|
107a915c67 | ||
|
|
41e847df18 | ||
|
|
7ccfb10392 | ||
|
|
d4614cf1ce | ||
|
|
a740dfe195 | ||
|
|
a73089c5f0 | ||
|
|
759f666177 | ||
|
|
e7883b13f4 | ||
|
|
f0015b8919 | ||
|
|
1115d50dce | ||
|
|
dc34bb36b3 | ||
|
|
8f8627a0c3 | ||
|
|
c2f8d43f9d | ||
|
|
6a482dc7f2 | ||
|
|
bc9f482b2a | ||
|
|
8659118a5e | ||
|
|
01db268dff |
+141
-57
@@ -1,9 +1,13 @@
|
||||
# Copyright 2007 NLnet Labs
|
||||
# See the file LICENSE for the license
|
||||
#
|
||||
# Standard installation pathnames
|
||||
|
||||
QUIET=yes
|
||||
debug_enabled=@debug_enabled@
|
||||
ifeq ($(debug_enabled),yes)
|
||||
QUIET=yes
|
||||
else
|
||||
QUIET=no
|
||||
endif
|
||||
|
||||
ifeq "$(QUIET)" "yes"
|
||||
Q=@
|
||||
INFO=@echo
|
||||
@@ -28,12 +32,13 @@ doxygen=@doxygen@
|
||||
libtool=@libtool@
|
||||
ldnsdir=@ldnsdir@
|
||||
staticexe=@staticexe@
|
||||
configfile=@ub_conf_file@
|
||||
|
||||
YACC=@YACC@
|
||||
LEX=@LEX@
|
||||
CC=@CC@
|
||||
CPPFLAGS=-I. @CPPFLAGS@ @DEFS@
|
||||
CFLAGS=-I. @CFLAGS@
|
||||
CPPFLAGS=-I$(srcdir) -I. @CPPFLAGS@ @DEFS@
|
||||
CFLAGS=@CFLAGS@
|
||||
LDFLAGS=@LDFLAGS@
|
||||
LIBS=@LIBS@
|
||||
LIBOBJS=@LIBOBJS@
|
||||
@@ -46,86 +51,138 @@ endif
|
||||
BUILD=build/
|
||||
|
||||
LINT=splint
|
||||
LINTFLAGS=+quiet -weak -warnposix -unrecog -Din_addr_t=uint32_t -Du_int=unsigned -Du_char=uint8_t -preproc -Drlimit=rlimit64
|
||||
LINTFLAGS=+quiet -weak -warnposix -unrecog -Din_addr_t=uint32_t -Du_int=unsigned -Du_char=uint8_t -preproc -Drlimit=rlimit64 -D__gnuc_va_list=va_list
|
||||
# compat with openssl linux edition.
|
||||
LINTFLAGS+="-DBN_ULONG=unsigned long" -Dkrb5_int32=int "-Dkrb5_ui_4=unsigned int" -DPQ_64BIT=uint64_t
|
||||
LINTFLAGS+="-DBN_ULONG=unsigned long" -Dkrb5_int32=int "-Dkrb5_ui_4=unsigned int" -DPQ_64BIT=uint64_t -DRC4_INT=unsigned
|
||||
|
||||
INSTALL=$(srcdir)/install-sh
|
||||
|
||||
COMMON_SRC=$(wildcard services/*.c services/cache/*.c util/*.c \
|
||||
util/data/*.c util/storage/*.c iterator/*.c validator/*.c) \
|
||||
COMMON_SRC=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/services/*.c \
|
||||
$(srcdir)/services/cache/*.c $(srcdir)/util/*.c \
|
||||
$(srcdir)/util/data/*.c $(srcdir)/util/storage/*.c \
|
||||
$(srcdir)/iterator/*.c $(srcdir)/validator/*.c)) \
|
||||
util/configparser.c util/configlexer.c testcode/checklocks.c
|
||||
COMMON_OBJ=$(addprefix $(BUILD),$(COMMON_SRC:.c=.o))
|
||||
COMPAT_OBJ=$(addprefix $(BUILD)compat/,$(LIBOBJS))
|
||||
UNITTEST_SRC=$(wildcard testcode/unit*.c) testcode/readhex.c \
|
||||
testcode/ldns-testpkts.c $(COMMON_SRC)
|
||||
UNITTEST_SRC=$(patsubst $(srcdir)/%,%, \
|
||||
$(wildcard $(srcdir)/testcode/unit*.c)) \
|
||||
testcode/readhex.c testcode/ldns-testpkts.c smallapp/worker_cb.c \
|
||||
$(COMMON_SRC)
|
||||
UNITTEST_OBJ=$(addprefix $(BUILD),$(UNITTEST_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
DAEMON_SRC=$(wildcard daemon/*.c) $(COMMON_SRC)
|
||||
DAEMON_SRC=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/daemon/*.c)) \
|
||||
$(COMMON_SRC)
|
||||
DAEMON_OBJ=$(addprefix $(BUILD),$(DAEMON_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
CHECKCONF_SRC=smallapp/unbound-checkconf.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
CHECKCONF_OBJ=$(addprefix $(BUILD),$(CHECKCONF_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
HOST_SRC=smallapp/unbound-host.c
|
||||
HOST_OBJ=$(addprefix $(BUILD),$(HOST_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c \
|
||||
daemon/worker.c daemon/daemon.c daemon/stats.c testcode/replay.c \
|
||||
testcode/fake_event.c $(filter-out util/netevent.c \
|
||||
daemon/worker.c daemon/acl_list.c daemon/daemon.c daemon/stats.c \
|
||||
testcode/replay.c testcode/fake_event.c $(filter-out util/netevent.c \
|
||||
services/listen_dnsport.c services/outside_network.c, $(COMMON_SRC))
|
||||
TESTBOUND_OBJ=$(addprefix $(BUILD),$(TESTBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
LOCKVERIFY_SRC=testcode/lock_verify.c $(COMMON_SRC)
|
||||
LOCKVERIFY_SRC=testcode/lock_verify.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
LOCKVERIFY_OBJ=$(addprefix $(BUILD),$(LOCKVERIFY_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
PKTVIEW_SRC=testcode/pktview.c testcode/readhex.c $(COMMON_SRC)
|
||||
PKTVIEW_SRC=testcode/pktview.c testcode/readhex.c smallapp/worker_cb.c \
|
||||
$(COMMON_SRC)
|
||||
PKTVIEW_OBJ=$(addprefix $(BUILD),$(PKTVIEW_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
SIGNIT_SRC=testcode/signit.c $(COMMON_SRC)
|
||||
SIGNIT_SRC=testcode/signit.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
SIGNIT_OBJ=$(addprefix $(BUILD),$(SIGNIT_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
MEMSTATS_SRC=testcode/memstats.c $(COMMON_SRC)
|
||||
MEMSTATS_SRC=testcode/memstats.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
|
||||
ASYNCLOOK_SRC=testcode/asynclook.c
|
||||
ASYNCLOOK_OBJ=$(addprefix $(BUILD),$(ASYNCLOOK_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
STREAMTCP_SRC=testcode/streamtcp.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
STREAMTCP_OBJ=$(addprefix $(BUILD),$(STREAMTCP_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
LIBUNBOUND_SRC=$(patsubst $(srcdir)/%,%, \
|
||||
$(wildcard $(srcdir)/libunbound/*.c) $(COMMON_SRC))
|
||||
LIBUNBOUND_OBJ=$(addprefix $(BUILD),$(LIBUNBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
ALL_SRC=$(sort $(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
|
||||
$(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
|
||||
$(MEMSTATS_SRC)
|
||||
$(MEMSTATS_SRC) $(CHECKCONF_SRC) $(LIBUNBOUND_SRC) $(HOST_SRC) \
|
||||
$(ASYNCLOOK_SRC) $(STREAMTCP_SRC))
|
||||
ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.o) \
|
||||
$(addprefix compat/,$(LIBOBJS))) $(COMPAT_OBJ)
|
||||
|
||||
COMPILE=$(LIBTOOL) --tag=CC --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS)
|
||||
LINK=$(LIBTOOL) --tag=CC --mode=link $(CC) $(staticexe) $(RUNTIME_PATH) $(CFLAGS) $(LDFLAGS)
|
||||
LINK_LIB=$(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -release $(VERSION)
|
||||
LINK_LIB=$(LIBTOOL) --tag=CC --mode=link $(CC) $(RUNTIME_PATH) $(CFLAGS) $(LDFLAGS) $(staticexe) -release $(VERSION) -no-undefined
|
||||
|
||||
.PHONY: clean realclean doc lint all install uninstall tests test download_ldns strip lib
|
||||
|
||||
$(BUILD)%.o: $(srcdir)/%.c
|
||||
$(INFO) Build $<
|
||||
@if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
@if test ! -z "$(ldnsdir)" -a ! -e $(ldnsdir)/include/ldns/ldns.h; \
|
||||
then (cd $(ldnsdir); $(MAKE) copy-headers); fi
|
||||
@-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
$Q$(COMPILE) -c $< -o $@
|
||||
|
||||
.PHONY: clean realclean doc lint all install uninstall tests test
|
||||
all: $(COMMON_OBJ) unbound unbound-checkconf lib unbound-host
|
||||
|
||||
all: $(COMMON_OBJ) unbound
|
||||
|
||||
tests: unittest testbound lock-verify pktview signit memstats
|
||||
tests: all unittest testbound lock-verify pktview signit memstats \
|
||||
asynclook streamtcp
|
||||
|
||||
test: tests
|
||||
bash testcode/do-tests.sh
|
||||
|
||||
unbound: $(DAEMON_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
lib: libunbound.la
|
||||
|
||||
unittest: $(UNITTEST_OBJ)
|
||||
libunbound.la: $(LIBUNBOUND_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
$Q$(LINK_LIB) --export-symbols $(srcdir)/libunbound/ubsyms.def -o $@ $(sort $(LIBUNBOUND_OBJ:.o=.lo)) -rpath $(libdir) $(LIBS)
|
||||
|
||||
testbound: $(TESTBOUND_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
ifeq ($(patsubst ldns-src%,ldns-src,$(ldnsdir)),ldns-src)
|
||||
ldnslib=$(ldnsdir)/lib/libldns.a
|
||||
$(ldnslib):
|
||||
@if test ! -z "$(ldnsdir)"; \
|
||||
then (cd $(ldnsdir) && $(MAKE)); fi
|
||||
else
|
||||
ldnslib=
|
||||
endif
|
||||
|
||||
lock-verify: $(LOCKVERIFY_OBJ)
|
||||
unbound: $(DAEMON_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(DAEMON_OBJ)) $(LIBS)
|
||||
|
||||
pktview: $(PKTVIEW_OBJ)
|
||||
unbound-checkconf: $(CHECKCONF_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(CHECKCONF_OBJ)) $(LIBS)
|
||||
|
||||
signit: $(SIGNIT_OBJ)
|
||||
unbound-host: $(HOST_OBJ) libunbound.la $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(HOST_OBJ)) -L. -L.libs -lunbound $(LIBS)
|
||||
|
||||
memstats: $(MEMSTATS_OBJ)
|
||||
unittest: $(UNITTEST_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $^ $(LIBS)
|
||||
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) $(LIBS)
|
||||
|
||||
testbound: $(TESTBOUND_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(TESTBOUND_OBJ)) $(LIBS)
|
||||
|
||||
lock-verify: $(LOCKVERIFY_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) $(LIBS)
|
||||
|
||||
pktview: $(PKTVIEW_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) $(LIBS)
|
||||
|
||||
signit: $(SIGNIT_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(SIGNIT_OBJ)) $(LIBS)
|
||||
|
||||
memstats: $(MEMSTATS_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(MEMSTATS_OBJ)) $(LIBS)
|
||||
|
||||
asynclook: $(ASYNCLOOK_OBJ) $(ldnslib) libunbound.la
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(ASYNCLOOK_OBJ)) $(LIBS) -L. -L.libs -lunbound
|
||||
|
||||
streamtcp: $(STREAMTCP_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(STREAMTCP_OBJ)) $(LIBS)
|
||||
|
||||
#testcode/ldns-testpkts.c: $(ldnsdir)/examples/ldns-testpkts.c \
|
||||
# $(ldnsdir)/examples/ldns-testpkts.h
|
||||
@@ -136,17 +193,16 @@ util/config_file.c: util/configparser.h
|
||||
util/configlexer.c: $(srcdir)/util/configlexer.lex util/configparser.h
|
||||
$(INFO) Lex $<
|
||||
ifeq "$(strip $(LEX))" ":"
|
||||
$Qecho "Need to rebuild lexer, but no lex program"
|
||||
exit 1
|
||||
$Qecho "rebuild lexer, but no lex program, skipped"
|
||||
else
|
||||
@if test ! -d util; then $(INSTALL) -d util; fi
|
||||
@-if test ! -d util; then $(INSTALL) -d util; fi
|
||||
$Qecho "#include \"util/configyyrename.h\"" > $@
|
||||
$Q$(LEX) -t $< >> $@
|
||||
endif
|
||||
|
||||
util/configparser.c util/configparser.h: $(srcdir)/util/configparser.y
|
||||
$(INFO) Yacc $<
|
||||
@if test ! -d util; then $(INSTALL) -d util; fi
|
||||
@-if test ! -d util; then $(INSTALL) -d util; fi
|
||||
$Q$(YACC) -d -o util/configparser.c $<
|
||||
|
||||
clean:
|
||||
@@ -157,11 +213,12 @@ realclean: clean
|
||||
rm -f config.status config.log config.h.in config.h
|
||||
rm -f configure config.sub config.guess ltmain.sh aclocal.m4 libtool
|
||||
rm -f util/configlexer.c util/configparser.c util/configparser.h
|
||||
if test -d ldns-src; then rm -rf ldns-src; fi
|
||||
rm -f Makefile
|
||||
|
||||
$(BUILD)%.lint: $(srcdir)/%.c
|
||||
$(INFO) Lint $<
|
||||
@if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
@-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
$Q$(LINT) $(LINTFLAGS) -I. -I$(srcdir) -I$(ldnsdir)/include $<
|
||||
$Qtouch $@
|
||||
|
||||
@@ -171,33 +228,60 @@ tags: $(srcdir)/*.[ch] $(srcdir)/*/*.[ch]
|
||||
ctags -f $(srcdir)/tags $(srcdir)/*.[ch] $(srcdir)/*/*.[ch]
|
||||
|
||||
doc:
|
||||
ifdef doxygen
|
||||
$(doxygen) $(srcdir)/doc/unbound.doxygen
|
||||
endif
|
||||
if test -n "$(doxygen)"; then \
|
||||
$(doxygen) $(srcdir)/doc/unbound.doxygen; fi
|
||||
|
||||
strip:
|
||||
strip unbound
|
||||
strip unbound-checkconf
|
||||
strip unbound-host
|
||||
|
||||
install:
|
||||
$(INSTALL) -d $(bindir)
|
||||
$(INSTALL) -d $(mandir)
|
||||
$(INSTALL) -d $(mandir)/man8
|
||||
$(INSTALL) -d $(mandir)/man5
|
||||
$(INSTALL) -m 755 -d $(bindir)
|
||||
$(INSTALL) -m 755 -d $(mandir)
|
||||
$(INSTALL) -m 755 -d $(mandir)/man8
|
||||
$(INSTALL) -m 755 -d $(mandir)/man5
|
||||
$(INSTALL) -m 755 -d $(libdir)
|
||||
$(INSTALL) -m 755 -d $(includedir)
|
||||
$(LIBTOOL) --mode=install cp unbound $(bindir)/unbound
|
||||
$(LIBTOOL) --mode=install cp unbound-checkconf $(bindir)/unbound-checkconf
|
||||
$(LIBTOOL) --mode=install cp unbound-host $(bindir)/unbound-host
|
||||
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound.8 $(mandir)/man8
|
||||
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound-checkconf.8 $(mandir)/man8
|
||||
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound.conf.5 $(mandir)/man5
|
||||
if test ! -e $(configfile); then $(INSTALL) -d `dirname $(configfile)`; $(INSTALL) -c -m 644 $(srcdir)/doc/example.conf $(configfile); fi
|
||||
$(LIBTOOL) --mode=install cp $(srcdir)/libunbound/unbound.h $(includedir)/unbound.h
|
||||
$(LIBTOOL) --mode=install cp libunbound.la $(libdir)
|
||||
$(LIBTOOL) --mode=finish $(libdir)
|
||||
|
||||
uninstall:
|
||||
rm -f -- $(bindir)/unbound
|
||||
rm -f -- $(mandir)/man8/unbound.8 $(mandir)/man5/unbound.conf.5
|
||||
rm -f -- $(bindir)/unbound $(bindir)/unbound-checkconf $(bindir)/unbound-host
|
||||
rm -f -- $(mandir)/man8/unbound.8 $(mandir)/man8/unbound-checkconf.8 $(mandir)/man5/unbound.conf.5
|
||||
rm -f -- $(includedir)/unbound.h
|
||||
$(LIBTOOL) --mode=uninstall rm -f $(libdir)/libunbound.la
|
||||
@echo
|
||||
@echo "You still need to remove `dirname $(configfile)` , $(configfile) by hand"
|
||||
|
||||
download_ldns:
|
||||
svn export https://www.nlnetlabs.nl/ldns/svn/trunk/makedist.sh ldns_makedist.sh
|
||||
./ldns_makedist.sh -s -d https://www.nlnetlabs.nl/ldns/svn/trunk
|
||||
mv ldns-*_pre_*.tar.gz ldns-src.tar.gz
|
||||
rm ldns-*_pre_*.tar.gz.sha1 ldns_makedist.sh
|
||||
|
||||
# Automatic dependencies.
|
||||
$(BUILD)%.d: $(srcdir)/%.c
|
||||
$(INFO) Depend $<
|
||||
@if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
@if test ! -z "$(ldnsdir)" -a ! -e $(ldnsdir)/include/ldns/ldns.h; \
|
||||
then (cd $(ldnsdir); $(MAKE) copy-headers); fi
|
||||
@-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
$Q$(SHELL) -ec '$(CC) -MM $(CPPFLAGS) $(CFLAGS) $< \
|
||||
| sed '\''s!\(.*\)\.o[ :]*!$(dir $@)\1.o $@ : !g'\'' > $@; \
|
||||
[ -s $@ ] || rm -f $@'
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
ifneq ($(MAKECMDGOALS),realclean)
|
||||
ifeq ($(debug_enabled),yes)
|
||||
-include $(addprefix $(BUILD),$(ALL_SRC:.c=.d))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
Unbound README
|
||||
* ./configure && make && make install
|
||||
* on BSDs and Solaris use gmake (GNU make).
|
||||
* If it complains that no libevent can be found; libevent is useful when
|
||||
using many (10000) outgoing ports. By default 16 ports are used and the
|
||||
builtin alternative is equally capable.
|
||||
* More detailed README, README.svn, README.tests in doc directory
|
||||
* manual pages can be found in doc directory, and are installed, unbound(8).
|
||||
* example configuration file doc/example.conf
|
||||
|
||||
+1500
File diff suppressed because it is too large
Load Diff
+431
@@ -0,0 +1,431 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Pathname to the Unbound configuration file */
|
||||
#undef CONFIGFILE
|
||||
|
||||
/* Define if you want to use debug lock checking (slow). */
|
||||
#undef ENABLE_LOCK_CHECKS
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Whether the C compiler accepts the "format" attribute */
|
||||
#undef HAVE_ATTR_FORMAT
|
||||
|
||||
/* Whether the C compiler accepts the "unused" attribute */
|
||||
#undef HAVE_ATTR_UNUSED
|
||||
|
||||
/* Define to 1 if your system has a working `chown' function. */
|
||||
#undef HAVE_CHOWN
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the `event_base_free' function. */
|
||||
#undef HAVE_EVENT_BASE_FREE
|
||||
|
||||
/* Define to 1 if you have the `event_base_once' function. */
|
||||
#undef HAVE_EVENT_BASE_ONCE
|
||||
|
||||
/* Define to 1 if you have the <event.h> header file. */
|
||||
#undef HAVE_EVENT_H
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
#undef HAVE_FORK
|
||||
|
||||
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
|
||||
#undef HAVE_FSEEKO
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
#undef HAVE_GETADDRINFO
|
||||
|
||||
/* Define to 1 if you have the <getopt.h> header file. */
|
||||
#undef HAVE_GETOPT_H
|
||||
|
||||
/* Define to 1 if you have the `inet_aton' function. */
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
/* Define to 1 if you have the `inet_ntop' function. */
|
||||
#undef HAVE_INET_NTOP
|
||||
|
||||
/* Define to 1 if you have the `inet_pton' function. */
|
||||
#undef HAVE_INET_PTON
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `ldns' library (-lldns). */
|
||||
#undef HAVE_LIBLDNS
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/err.h> header file. */
|
||||
#undef HAVE_OPENSSL_ERR_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/rand.h> header file. */
|
||||
#undef HAVE_OPENSSL_RAND_H
|
||||
|
||||
/* Define to 1 if you have the <openssl/ssl.h> header file. */
|
||||
#undef HAVE_OPENSSL_SSL_H
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#undef HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
|
||||
#undef HAVE_PTHREAD_RWLOCK_T
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
|
||||
#undef HAVE_PTHREAD_SPINLOCK_T
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#undef HAVE_SNPRINTF
|
||||
|
||||
/* Using Solaris threads */
|
||||
#undef HAVE_SOLARIS_THREADS
|
||||
|
||||
/* Define if you have the SSL libraries installed. */
|
||||
#undef HAVE_SSL
|
||||
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#undef HAVE_STDARG_H
|
||||
|
||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
||||
#undef HAVE_STDBOOL_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strlcpy' function. */
|
||||
#undef HAVE_STRLCPY
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#undef HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#undef HAVE_SYS_PARAM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <sys/uio.h> header file. */
|
||||
#undef HAVE_SYS_UIO_H
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#undef HAVE_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
#undef HAVE_VFORK
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
#undef HAVE_VFORK_H
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
#undef HAVE_WORKING_FORK
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
#undef HAVE_WORKING_VFORK
|
||||
|
||||
/* Define to the maximum message length to pass to syslog. */
|
||||
#undef MAXSYSLOGMSGLEN
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#undef PTHREAD_CREATE_JOINABLE
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* use statistics for allocs and frees, for debug use */
|
||||
#undef UNBOUND_ALLOC_STATS
|
||||
|
||||
/* define this to enable debug checks. */
|
||||
#undef UNBOUND_DEBUG
|
||||
|
||||
/* Define if you want to use internal select based events */
|
||||
#undef USE_MINI_EVENT
|
||||
|
||||
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
|
||||
`char[]'. */
|
||||
#undef YYTEXT_POINTER
|
||||
|
||||
/* Define to 1 if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
# undef _ALL_SOURCE
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
|
||||
#undef _LARGEFILE_SOURCE
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
#undef const
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef gid_t
|
||||
|
||||
/* in_addr_t */
|
||||
#undef in_addr_t
|
||||
|
||||
/* in_port_t */
|
||||
#undef in_port_t
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to `short' if <sys/types.h> does not define. */
|
||||
#undef int16_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef int32_t
|
||||
|
||||
/* Define to `long long' if <sys/types.h> does not define. */
|
||||
#undef int64_t
|
||||
|
||||
/* Define to `char' if <sys/types.h> does not define. */
|
||||
#undef int8_t
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
#undef malloc
|
||||
|
||||
/* Define to `long int' if <sys/types.h> does not define. */
|
||||
#undef off_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef pid_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to 'int' if not defined */
|
||||
#undef socklen_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to `unsigned char' if <sys/types.h> does not define. */
|
||||
#undef u_char
|
||||
|
||||
/* Define to `int' if <sys/types.h> doesn't define. */
|
||||
#undef uid_t
|
||||
|
||||
/* Define to `unsigned short' if <sys/types.h> does not define. */
|
||||
#undef uint16_t
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to `unsigned long long' if <sys/types.h> does not define. */
|
||||
#undef uint64_t
|
||||
|
||||
/* Define to `unsigned char' if <sys/types.h> does not define. */
|
||||
#undef uint8_t
|
||||
|
||||
/* Define as `fork' if `vfork' does not work. */
|
||||
#undef vfork
|
||||
|
||||
|
||||
#ifndef UNBOUND_DEBUG
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_ERR_H
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_RAND_H
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATTR_FORMAT
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
|
||||
__attribute__ ((format (archetype, string_index, first_to_check)))
|
||||
#else /* !HAVE_ATTR_FORMAT */
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) /* empty */
|
||||
#endif /* !HAVE_ATTR_FORMAT */
|
||||
#if defined(DOXYGEN)
|
||||
# define ATTR_UNUSED(x) x
|
||||
#elif defined(__cplusplus)
|
||||
# define ATTR_UNUSED(x)
|
||||
#elif defined(HAVE_ATTR_UNUSED)
|
||||
# define ATTR_UNUSED(x) x __attribute__((unused))
|
||||
#else /* !HAVE_ATTR_UNUSED */
|
||||
# define ATTR_UNUSED(x) x
|
||||
#endif /* !HAVE_ATTR_UNUSED */
|
||||
#ifndef HAVE_FSEEKO
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
#endif /* HAVE_FSEEKO */
|
||||
#if defined(HAVE_EVENT_H) && !defined(HAVE_EVENT_BASE_ONCE) && (defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS))
|
||||
/* using version of libevent that is not threadsafe. */
|
||||
# define LIBEVENT_SIGNAL_PROBLEM 1
|
||||
#endif
|
||||
|
||||
#ifndef RAND_MAX
|
||||
#define RAND_MAX 2147483647
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_MIN_MTU
|
||||
#define IPV6_MIN_MTU 1280
|
||||
#endif /* IPV6_MIN_MTU */
|
||||
|
||||
#ifndef CHECKED_INET6
|
||||
# define CHECKED_INET6
|
||||
# ifdef AF_INET6
|
||||
# define INET6
|
||||
# else
|
||||
# define AF_INET6 28
|
||||
# endif
|
||||
#endif /* CHECKED_INET6 */
|
||||
|
||||
/* maximum nesting of included files */
|
||||
#define MAXINCLUDES 10
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
#include <stdarg.h>
|
||||
int snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
#ifndef HAVE_INET_PTON
|
||||
int inet_pton(int af, const char* src, void* dst);
|
||||
#endif /* HAVE_INET_PTON */
|
||||
#ifndef HAVE_INET_NTOP
|
||||
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||
#endif
|
||||
#ifndef HAVE_INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
#endif
|
||||
#ifndef HAVE_MEMMOVE
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
#endif
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
struct sockaddr_storage;
|
||||
#include "compat/fake-rfc2553.h"
|
||||
#endif
|
||||
|
||||
#include "ldns/ldns.h"
|
||||
|
||||
#ifdef UNBOUND_ALLOC_STATS
|
||||
# define malloc(s) unbound_stat_malloc_log(s, __FILE__, __LINE__, __func__)
|
||||
# define calloc(n,s) unbound_stat_calloc_log(n, s, __FILE__, __LINE__, __func__)
|
||||
# define free(p) unbound_stat_free_log(p, __FILE__, __LINE__, __func__)
|
||||
# define realloc(p,s) unbound_stat_realloc_log(p, s, __FILE__, __LINE__, __func__)
|
||||
void *unbound_stat_malloc(size_t size);
|
||||
void *unbound_stat_calloc(size_t nmemb, size_t size);
|
||||
void unbound_stat_free(void *ptr);
|
||||
void *unbound_stat_realloc(void *ptr, size_t size);
|
||||
void *unbound_stat_malloc_log(size_t size, const char* file, int line,
|
||||
const char* func);
|
||||
void *unbound_stat_calloc_log(size_t nmemb, size_t size, const char* file,
|
||||
int line, const char* func);
|
||||
void unbound_stat_free_log(void *ptr, const char* file, int line,
|
||||
const char* func);
|
||||
void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
|
||||
int line, const char* func);
|
||||
#endif /* UNBOUND_ALLOC_STATS */
|
||||
|
||||
/** default port for DNS traffic. */
|
||||
#define UNBOUND_DNS_PORT 53
|
||||
|
||||
+1616
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+188
-62
@@ -2,11 +2,40 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(unbound, 0.5, wouter@nlnetlabs.nl, unbound)
|
||||
AC_INIT(unbound, 0.9, unbound-bugs@nlnetlabs.nl, unbound)
|
||||
|
||||
CFLAGS=
|
||||
AC_AIX
|
||||
|
||||
dnl
|
||||
dnl By default set $sysconfdir to /etc and $localstatedir to /var
|
||||
dnl
|
||||
case "$prefix" in
|
||||
NONE)
|
||||
case "$sysconfdir" in
|
||||
'${prefix}/etc')
|
||||
sysconfdir=/etc
|
||||
;;
|
||||
esac
|
||||
case "$localstatedir" in
|
||||
'${prefix}/var')
|
||||
localstatedir=/var
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# Determine configuration file
|
||||
ub_conf_file=${sysconfdir}/unbound/unbound.conf
|
||||
AC_ARG_WITH([conf_file],
|
||||
AC_HELP_STRING([--with-conf-file=path], [Pathname to the Unbound configuration file]),
|
||||
[ub_conf_file=$withval])
|
||||
AC_SUBST(ub_conf_file)
|
||||
# the eval is to evaluate shell expansion twice, once
|
||||
# for $nsd_conf_file and once for the ${prefix} within it.
|
||||
AC_DEFINE_UNQUOTED(CONFIGFILE, ["`eval echo $ub_conf_file`"], [Pathname to the Unbound configuration file])
|
||||
|
||||
dnl routine to help check for compiler flags.
|
||||
AC_DEFUN([CHECK_COMPILER_FLAG],
|
||||
[
|
||||
@@ -90,6 +119,39 @@ CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"])
|
||||
|
||||
AC_CHECK_HEADERS([getopt.h time.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
CHECK_COMPILER_FLAG_NEEDED(-std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE,
|
||||
[
|
||||
#include "confdefs.h"
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
int test() {
|
||||
int a;
|
||||
char **opts = NULL;
|
||||
struct timeval tv;
|
||||
char *t;
|
||||
time_t time = 0;
|
||||
char *buf = NULL;
|
||||
const char* str = NULL;
|
||||
t = ctime_r(&time, buf);
|
||||
tv.tv_usec = 10;
|
||||
srandom(32);
|
||||
a = getopt(2, opts, "a");
|
||||
a = isascii(32);
|
||||
str = gai_strerror(0);
|
||||
return a;
|
||||
}
|
||||
], [CFLAGS="$CFLAGS -std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_ALL_SOURCE"])
|
||||
|
||||
CHECK_COMPILER_FLAG_NEEDED(-std=c99 -D__EXTENSIONS__ -D_BSD_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -D_ALL_SOURCE,
|
||||
[
|
||||
#include "confdefs.h"
|
||||
@@ -194,10 +256,21 @@ int test() {
|
||||
CHECK_COMPILER_FLAG(xO4, [CFLAGS="$CFLAGS -xO4"])
|
||||
CHECK_COMPILER_FLAG(xtarget=generic, [CFLAGS="$CFLAGS -xtarget=generic"])
|
||||
# flag warnings.
|
||||
CHECK_COMPILER_FLAG(W, [CFLAGS="$CFLAGS -W"])
|
||||
CHECK_COMPILER_FLAG(Wall, [CFLAGS="$CFLAGS -Wall"])
|
||||
CHECK_COMPILER_FLAG(Wextra, [CFLAGS="$CFLAGS -Wextra"])
|
||||
CHECK_COMPILER_FLAG(Wdeclaration-after-statement, [CFLAGS="$CFLAGS -Wdeclaration-after-statement"])
|
||||
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [Enable debug warnings, asserts, makefile-dependencies]))
|
||||
debug_enabled="$enable_debug"
|
||||
AC_SUBST(debug_enabled)
|
||||
case "$enable_debug" in
|
||||
yes)
|
||||
CHECK_COMPILER_FLAG(W, [CFLAGS="$CFLAGS -W"])
|
||||
CHECK_COMPILER_FLAG(Wall, [CFLAGS="$CFLAGS -Wall"])
|
||||
CHECK_COMPILER_FLAG(Wextra, [CFLAGS="$CFLAGS -Wextra"])
|
||||
CHECK_COMPILER_FLAG(Wdeclaration-after-statement, [CFLAGS="$CFLAGS -Wdeclaration-after-statement"])
|
||||
AC_DEFINE([UNBOUND_DEBUG], [], [define this to enable debug checks.])
|
||||
;;
|
||||
no|*)
|
||||
# nothing to do.
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_C_INLINE
|
||||
|
||||
@@ -248,9 +321,18 @@ AC_CHECK_FORMAT_ATTRIBUTE
|
||||
AC_CHECK_UNUSED_ATTRIBUTE
|
||||
|
||||
if test "$srcdir" != "."; then
|
||||
CPPFLAGS="$CPPFLAGS -I$srcdir";
|
||||
CPPFLAGS="$CPPFLAGS -I$srcdir"
|
||||
fi
|
||||
|
||||
# skip these tests, we do not need them.
|
||||
AC_DEFUN([AC_PROG_F77], [:])
|
||||
AC_DEFUN([AC_PROG_FC], [:])
|
||||
AC_DEFUN([AC_PROG_CXX], [:])
|
||||
AC_DEFUN([AC_PROG_CXXCPP], [:])
|
||||
AC_DEFUN([AC_PROG_OBJC], [:])
|
||||
AC_DEFUN([AC_PROG_OBJCCPP], [:])
|
||||
AC_DEFUN([AC_LIBTOOL_CXX], [:])
|
||||
AC_DEFUN([AC_LIBTOOL_F77], [:])
|
||||
# Use libtool
|
||||
AC_CHECK_PROGS(libtool, [glibtool libtool15 libtool], [./libtool])
|
||||
AC_PATH_TOOL(AR, ar, [false])
|
||||
@@ -269,7 +351,7 @@ AC_PROG_LIBTOOL
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h arpa/inet.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h arpa/inet.h syslog.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
# check for types
|
||||
AC_CHECK_TYPE(int8_t, char)
|
||||
@@ -313,29 +395,6 @@ AC_INCLUDES_DEFAULT
|
||||
#endif
|
||||
])
|
||||
|
||||
# Check the type of struct msghdr msg_iovlen.
|
||||
AC_MSG_CHECKING([sign of struct msghdr.msg_iovlen])
|
||||
AC_RUN_IFELSE([
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
int main()
|
||||
{
|
||||
struct msghdr h;
|
||||
h.msg_iovlen = -1;
|
||||
if(10/h.msg_iovlen == 0) return 0; /* unsigned */
|
||||
return 1; /* signed */
|
||||
}
|
||||
], [
|
||||
# if compiled and exit status 0
|
||||
cv_msgiovlen_type="unsigned" ], [
|
||||
# not compiled or bad exit status
|
||||
cv_msgiovlen_type="int" ],
|
||||
# when cross compiling
|
||||
[ cv_msgiovlen_type="int" ])
|
||||
AC_MSG_RESULT($cv_msgiovlen_type)
|
||||
AC_DEFINE_UNQUOTED([TYPE_MSGIOVLEN], $cv_msgiovlen_type, [Define to 'int' or type of struct msghdr.msg_iovlen.])
|
||||
|
||||
# Check for yyunput
|
||||
AC_DEFUN([CHECK_YYUNPUT],
|
||||
[AC_MSG_CHECKING(whether lex can not generate yyunput)
|
||||
@@ -356,6 +415,12 @@ fi
|
||||
|
||||
CHECK_YYUNPUT
|
||||
|
||||
# add option to disable the evil rpath
|
||||
dnl Check whether to use rpath or not
|
||||
AC_ARG_ENABLE(rpath,
|
||||
[ --disable-rpath disable hardcoded rpath (default=enabled)],
|
||||
enable_rpath=$enableval, enable_rpath=yes)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
|
||||
[enable SSL (will check /usr/local/ssl
|
||||
@@ -371,9 +436,9 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
|
||||
for dir in $withval; do
|
||||
ssldir="$dir"
|
||||
if test -f "$dir/include/openssl/ssl.h"; then
|
||||
found_ssl="yes";
|
||||
found_ssl="yes"
|
||||
AC_DEFINE_UNQUOTED([HAVE_SSL], [], [Define if you have the SSL libraries installed.])
|
||||
CPPFLAGS="$CPPFLAGS -I$ssldir/include";
|
||||
CPPFLAGS="$CPPFLAGS -I$ssldir/include"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
@@ -382,8 +447,10 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
|
||||
else
|
||||
AC_MSG_RESULT(found in $ssldir)
|
||||
HAVE_SSL=yes
|
||||
LDFLAGS="$LDFLAGS -L$ssldir/lib";
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
||||
LDFLAGS="$LDFLAGS -L$ssldir/lib"
|
||||
if test "x$enable_rpath" = xyes; then
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
||||
fi
|
||||
AC_CHECK_LIB(crypto, HMAC_CTX_init,, [
|
||||
AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required])
|
||||
])
|
||||
@@ -393,6 +460,7 @@ AC_ARG_WITH(ssl, AC_HELP_STRING([--with-ssl=pathname],
|
||||
fi
|
||||
AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
|
||||
|
||||
# check for thread library.
|
||||
AC_ARG_WITH(pthreads, AC_HELP_STRING([--with-pthreads],
|
||||
@@ -430,8 +498,12 @@ if test x_$withval != x_no; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# check to see if libraries are needed for these functions.
|
||||
AC_SEARCH_LIBS([inet_pton], [nsl])
|
||||
AC_SEARCH_LIBS([socket], [socket])
|
||||
# check for library used by libevent after 1.3c
|
||||
AC_CHECK_LIB(rt, clock_gettime)
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt])
|
||||
|
||||
# check for libevent
|
||||
AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=pathname],
|
||||
[set path to libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr)]),
|
||||
@@ -439,38 +511,55 @@ AC_ARG_WITH(libevent, AC_HELP_STRING([--with-libevent=pathname],
|
||||
if test x_$withval != x_no; then
|
||||
AC_MSG_CHECKING(for libevent)
|
||||
if test x_$withval = x_ -o x_$withval = x_yes; then
|
||||
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr";
|
||||
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
|
||||
fi
|
||||
for dir in $withval; do
|
||||
thedir="$dir"
|
||||
if test -f "$dir/include/event.h"; then
|
||||
found_libevent="yes";
|
||||
CPPFLAGS="$CPPFLAGS -I$thedir/include";
|
||||
found_libevent="yes"
|
||||
CPPFLAGS="$CPPFLAGS -I$thedir/include"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
if test x_$found_libevent != x_yes; then
|
||||
if test -f "$dir/event.h" -a -f "$dir/.libs/libevent.a"; then
|
||||
if test -f "$dir/event.h" -a -f "$dir/libevent.la"; then
|
||||
# libevent source directory
|
||||
AC_MSG_RESULT(found in $thedir)
|
||||
CPPFLAGS="$CPPFLAGS -I$thedir";
|
||||
LDFLAGS="$thedir/.libs/*.o $LDFLAGS";
|
||||
CPPFLAGS="$CPPFLAGS -I$thedir"
|
||||
BAK_LDFLAGS="$LDFLAGS"
|
||||
# remove evdns from linking
|
||||
mkdir build >/dev/null 2>&1
|
||||
mkdir build/libevent >/dev/null 2>&1
|
||||
mkdir build/libevent/.libs >/dev/null 2>&1
|
||||
ev_files_o=`ls $thedir/*.o | grep -v evdns\.o`
|
||||
ev_files_lo=`ls $thedir/*.lo | grep -v evdns\.lo`
|
||||
ev_files_libso=`ls $thedir/.libs/*.o | grep -v evdns\.o`
|
||||
cp $ev_files_o build/libevent
|
||||
cp $ev_files_lo build/libevent
|
||||
cp $ev_files_libso build/libevent/.libs
|
||||
LATE_LDFLAGS="build/libevent/*.lo"
|
||||
LDFLAGS="build/libevent/*.o $LDFLAGS"
|
||||
else
|
||||
AC_MSG_ERROR([Cannot find the libevent library in $withval
|
||||
You can restart configure with --with-libevent=no to use a builtin alternative.
|
||||
You can restart ./configure --with-libevent=no to use a builtin alternative.
|
||||
Please note that this alternative is not as capable as libevent when using
|
||||
many outgoing ports. ])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT(found in $thedir)
|
||||
LDFLAGS="$LDFLAGS -L$thedir/lib";
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib"
|
||||
LDFLAGS="$LDFLAGS -L$thedir/lib"
|
||||
if test "x$enable_rpath" = xyes; then
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(RUNTIME_PATH)
|
||||
AC_SEARCH_LIBS(event_set, [event])
|
||||
AC_CHECK_HEADERS([event.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_FUNCS([event_base_free]) # only in libevent 1.2 and later
|
||||
AC_CHECK_FUNCS([event_base_once]) # only in libevent 1.4? and later
|
||||
if test -n "$BAK_LDFLAGS"; then
|
||||
LDFLAGS="$BAK_LDFLAGS"
|
||||
fi
|
||||
else
|
||||
AC_DEFINE(USE_MINI_EVENT, 1, [Define if you want to use internal select based events])
|
||||
fi
|
||||
@@ -503,28 +592,12 @@ else
|
||||
AC_FUNC_MALLOC
|
||||
fi
|
||||
|
||||
# check to see if libraries are needed for these functions.
|
||||
AC_CHECK_LIB(socket, socket)
|
||||
AC_CHECK_LIB(nsl, inet_pton)
|
||||
|
||||
AC_FUNC_CHOWN
|
||||
AC_FUNC_FORK
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_FSEEKO
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
AC_REPLACE_FUNCS(inet_aton)
|
||||
AC_REPLACE_FUNCS(inet_pton)
|
||||
AC_REPLACE_FUNCS(inet_ntop)
|
||||
AC_REPLACE_FUNCS(snprintf)
|
||||
AC_REPLACE_FUNCS(strlcpy)
|
||||
AC_REPLACE_FUNCS(memmove)
|
||||
|
||||
AC_CHECK_FUNCS([getaddrinfo])
|
||||
if test $ac_cv_func_getaddrinfo = no; then
|
||||
AC_LIBOBJ([fake-rfc2553])
|
||||
fi
|
||||
|
||||
# check this after all other compilation checks, since the linking of the lib
|
||||
# may break checks after this.
|
||||
AC_ARG_WITH(ldns,
|
||||
@@ -536,11 +609,60 @@ AC_ARG_WITH(ldns,
|
||||
AC_SUBST(ldnsdir)
|
||||
])
|
||||
|
||||
AC_CHECK_LIB(ldns, ldns_rr_new,, [AC_MSG_ERROR([Can't find ldns library])])
|
||||
AC_CHECK_LIB(ldns, ldns_rr_new, [
|
||||
dnl ldns was found, check compat functions
|
||||
AC_CHECK_LIB(ldns, [ldns_rr_free])
|
||||
AC_REPLACE_FUNCS(inet_aton)
|
||||
AC_REPLACE_FUNCS(inet_pton)
|
||||
AC_REPLACE_FUNCS(inet_ntop)
|
||||
AC_REPLACE_FUNCS(snprintf)
|
||||
AC_REPLACE_FUNCS(strlcpy)
|
||||
AC_REPLACE_FUNCS(memmove)
|
||||
|
||||
AC_DEFINE_UNQUOTED([MAXSYSLOGMSGLEN], [512], [Define to the maximum message length to pass to syslog.])
|
||||
AC_CHECK_FUNCS([getaddrinfo])
|
||||
if test $ac_cv_func_getaddrinfo = no; then
|
||||
AC_LIBOBJ([fake-rfc2553])
|
||||
fi
|
||||
|
||||
] , [
|
||||
dnl use the builtin ldns-src.tar.gz file to build ldns.
|
||||
if test ! -f $srcdir/ldns-src.tar.gz; then
|
||||
AC_MSG_ERROR([No ldns library found and no ldns-src.tar.gz, use --with-ldns=path.])
|
||||
fi
|
||||
echo "****************************************************************"
|
||||
echo "*** ***"
|
||||
echo "*** ldns library not found (--with-ldns= to specify by hand) ***"
|
||||
echo "*** Building ldns library from package included in this one. ***"
|
||||
echo "*** ***"
|
||||
echo "****************************************************************"
|
||||
if test -d ldns-src; then rm -rf ldns-src; fi
|
||||
mkdir ldns-src; cp $srcdir/ldns-src.tar.gz ldns-src/ldns-src.tar.gz; (cd ldns-src; gzip -cd ldns-src.tar.gz | tar xf -); rm -f ldns-src/ldns-src.tar.gz
|
||||
ldnsdir=`ls -d ldns-src/ldns*`
|
||||
AC_MSG_NOTICE([Configure $ldnsdir])
|
||||
echo "(cd $ldnsdir; ./configure)"
|
||||
(cd $ldnsdir; ./configure)
|
||||
AC_MSG_NOTICE([Finished $ldnsdir configure])
|
||||
CPPFLAGS="$CPPFLAGS -I$ldnsdir/include"
|
||||
LDFLAGS="$LDFLAGS $ldnsdir/*.lo"
|
||||
AC_SUBST(ldnsdir)
|
||||
dnl use ldns compat functions
|
||||
AC_DEFINE(HAVE_INET_ATON)
|
||||
AC_DEFINE(HAVE_INET_PTON)
|
||||
AC_DEFINE(HAVE_INET_NTOP)
|
||||
AC_DEFINE(HAVE_SNPRINTF)
|
||||
AC_DEFINE(HAVE_STRLCPY)
|
||||
AC_DEFINE(HAVE_MEMMOVE)
|
||||
AC_DEFINE(HAVE_GETADDRINFO)
|
||||
])
|
||||
LDFLAGS="$LATE_LDFLAGS $LDFLAGS"
|
||||
|
||||
AC_DEFINE_UNQUOTED([MAXSYSLOGMSGLEN], [5120], [Define to the maximum message length to pass to syslog.])
|
||||
|
||||
AH_BOTTOM([
|
||||
#ifndef UNBOUND_DEBUG
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -585,6 +707,10 @@ AH_BOTTOM([
|
||||
#include <openssl/err.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENSSL_RAND_H
|
||||
#include <openssl/rand.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATTR_FORMAT
|
||||
# define ATTR_FORMAT(archetype, string_index, first_to_check) \
|
||||
__attribute__ ((format (archetype, string_index, first_to_check)))
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* daemon/acl_list.h - client access control storage for the server.
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file helps the server keep out queries from outside sources, that
|
||||
* should not be answered.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "daemon/acl_list.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
int
|
||||
acl_list_cmp(const void* k1, const void* k2)
|
||||
{
|
||||
struct acl_addr* n1 = (struct acl_addr*)k1;
|
||||
struct acl_addr* n2 = (struct acl_addr*)k2;
|
||||
int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
|
||||
n2->addrlen);
|
||||
if(r != 0) return r;
|
||||
if(n1->net < n2->net)
|
||||
return -1;
|
||||
if(n1->net > n2->net)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct acl_list*
|
||||
acl_list_create()
|
||||
{
|
||||
struct acl_list* acl = (struct acl_list*)calloc(1,
|
||||
sizeof(struct acl_list));
|
||||
if(!acl)
|
||||
return NULL;
|
||||
acl->region = regional_create();
|
||||
if(!acl->region) {
|
||||
acl_list_delete(acl);
|
||||
return NULL;
|
||||
}
|
||||
return acl;
|
||||
}
|
||||
|
||||
void
|
||||
acl_list_delete(struct acl_list* acl)
|
||||
{
|
||||
if(!acl)
|
||||
return;
|
||||
regional_destroy(acl->region);
|
||||
free(acl->tree);
|
||||
free(acl);
|
||||
}
|
||||
|
||||
/** insert new address into acl_list structure */
|
||||
static int
|
||||
acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int net, enum acl_access control,
|
||||
int complain_duplicates)
|
||||
{
|
||||
struct acl_addr* node = regional_alloc(acl->region,
|
||||
sizeof(struct acl_addr));
|
||||
if(!node)
|
||||
return 0;
|
||||
node->node.key = node;
|
||||
memcpy(&node->addr, addr, addrlen);
|
||||
node->addrlen = addrlen;
|
||||
node->net = net;
|
||||
node->parent = NULL;
|
||||
node->control = control;
|
||||
if(!rbtree_insert(acl->tree, &node->node)) {
|
||||
if(complain_duplicates)
|
||||
verbose(VERB_QUERY, "duplicate acl address ignored.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply acl_list string */
|
||||
static int
|
||||
acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
|
||||
int complain_duplicates)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
enum acl_access control;
|
||||
if(strcmp(s2, "allow") == 0)
|
||||
control = acl_allow;
|
||||
else if(strcmp(s2, "deny") == 0)
|
||||
control = acl_deny;
|
||||
else if(strcmp(s2, "refuse") == 0)
|
||||
control = acl_refuse;
|
||||
else {
|
||||
log_err("access control type %s unknown", str);
|
||||
return 0;
|
||||
}
|
||||
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse access control: %s %s", str, s2);
|
||||
return 0;
|
||||
}
|
||||
if(!acl_list_insert(acl, &addr, addrlen, net, control,
|
||||
complain_duplicates)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read acl_list config */
|
||||
static int
|
||||
read_acl_list(struct acl_list* acl, struct config_file* cfg)
|
||||
{
|
||||
struct config_str2list* p;
|
||||
for(p = cfg->acls; p; p = p->next) {
|
||||
log_assert(p->str && p->str2);
|
||||
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** initialise parent pointers in the tree */
|
||||
static void
|
||||
acl_list_init_parents(struct acl_list* acl)
|
||||
{
|
||||
struct acl_addr* node, *prev = NULL, *p;
|
||||
int m;
|
||||
RBTREE_FOR(node, struct acl_addr*, acl->tree) {
|
||||
node->parent = NULL;
|
||||
if(!prev || prev->addrlen != node->addrlen) {
|
||||
prev = node;
|
||||
continue;
|
||||
}
|
||||
m = addr_in_common(&prev->addr, prev->net, &node->addr,
|
||||
node->net, node->addrlen);
|
||||
/* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
|
||||
/* find the previous, or parent-parent-parent */
|
||||
for(p = prev; p; p = p->parent)
|
||||
if(p->net <= m) {
|
||||
/* ==: since prev matched m, this is closest*/
|
||||
/* <: prev matches more, but is not a parent,
|
||||
* this one is a (grand)parent */
|
||||
node->parent = p;
|
||||
break;
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
|
||||
{
|
||||
regional_free_all(acl->region);
|
||||
free(acl->tree);
|
||||
acl->tree = rbtree_create(acl_list_cmp);
|
||||
if(!acl->tree)
|
||||
return 0;
|
||||
if(!read_acl_list(acl, cfg))
|
||||
return 0;
|
||||
/* insert defaults, with '0' to ignore them if they are duplicates */
|
||||
if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
|
||||
return 0;
|
||||
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
|
||||
return 0;
|
||||
acl_list_init_parents(acl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum acl_access
|
||||
acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
/* lookup in the tree */
|
||||
rbnode_t* res = NULL;
|
||||
struct acl_addr* result;
|
||||
struct acl_addr key;
|
||||
key.node.key = &key;
|
||||
memcpy(&key.addr, addr, addrlen);
|
||||
key.addrlen = addrlen;
|
||||
key.net = (addr_is_ip6(addr, addrlen)?128:32);
|
||||
if(rbtree_find_less_equal(acl->tree, &key, &res)) {
|
||||
/* exact */
|
||||
result = (struct acl_addr*)res;
|
||||
return result->control;
|
||||
} else {
|
||||
/* smaller element (or no element) */
|
||||
int m;
|
||||
result = (struct acl_addr*)res;
|
||||
if(!result || result->addrlen != addrlen)
|
||||
return acl_deny;
|
||||
/* count number of bits matched */
|
||||
m = addr_in_common(&result->addr, result->net, addr,
|
||||
key.net, addrlen);
|
||||
while(result) { /* go up until addr is inside netblock */
|
||||
if(result->net <= m)
|
||||
return result->control;
|
||||
result = result->parent;
|
||||
}
|
||||
}
|
||||
return acl_deny;
|
||||
}
|
||||
|
||||
size_t
|
||||
acl_list_get_mem(struct acl_list* acl)
|
||||
{
|
||||
if(!acl) return 0;
|
||||
return sizeof(*acl) + regional_get_mem(acl->region);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* daemon/acl_list.h - client access control storage for the server.
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file keeps track of the list of clients that are allowed to
|
||||
* access the server.
|
||||
*/
|
||||
|
||||
#ifndef DAEMON_ACL_LIST_H
|
||||
#define DAEMON_ACL_LIST_H
|
||||
#include "util/rbtree.h"
|
||||
struct config_file;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Enumeration of access control options for an address range.
|
||||
* Allow or deny access.
|
||||
*/
|
||||
enum acl_access {
|
||||
/** disallow any access whatsoever, drop it */
|
||||
acl_deny = 0,
|
||||
/** disallow access, send a polite 'REFUSED' reply */
|
||||
acl_refuse,
|
||||
/** allow full access */
|
||||
acl_allow
|
||||
};
|
||||
|
||||
/**
|
||||
* Access control storage structure
|
||||
*/
|
||||
struct acl_list {
|
||||
/** regional for allocation */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Tree of the addresses that are allowed/blocked.
|
||||
* contents of type acl_addr.
|
||||
*/
|
||||
rbtree_t* tree;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* An address span with access control information
|
||||
*/
|
||||
struct acl_addr {
|
||||
/** redblacktree node, key is this structure: addr and addrlen, net */
|
||||
rbnode_t node;
|
||||
/** parent node in acl tree that encompasses this entry */
|
||||
struct acl_addr* parent;
|
||||
/** address */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr */
|
||||
socklen_t addrlen;
|
||||
/** netblock size */
|
||||
int net;
|
||||
/** access control on this netblock */
|
||||
enum acl_access control;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create acl structure
|
||||
* @return new structure or NULL on error.
|
||||
*/
|
||||
struct acl_list* acl_list_create();
|
||||
|
||||
/**
|
||||
* Delete acl structure.
|
||||
* @param acl: to delete.
|
||||
*/
|
||||
void acl_list_delete(struct acl_list* acl);
|
||||
|
||||
/**
|
||||
* Process access control config.
|
||||
* @param acl: where to store.
|
||||
* @param cfg: config options.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Lookup address to see its access control status.
|
||||
* @param acl: structure for address storage.
|
||||
* @param addr: address to check
|
||||
* @param addrlen: length of addr.
|
||||
* @return: what to do with message from this address.
|
||||
*/
|
||||
enum acl_access acl_list_lookup(struct acl_list* acl,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Get memory used by acl structure.
|
||||
* @param acl: structure for address storage.
|
||||
* @return bytes in use.
|
||||
*/
|
||||
size_t acl_list_get_mem(struct acl_list* acl);
|
||||
|
||||
/** compare two acl list entries */
|
||||
int acl_list_cmp(const void* k1, const void* k2);
|
||||
|
||||
#endif /* DAEMON_ACL_LIST_H */
|
||||
+39
-130
@@ -42,6 +42,7 @@
|
||||
#include "config.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/acl_list.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/msgreply.h"
|
||||
@@ -49,9 +50,9 @@
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/modstack.h"
|
||||
#include "util/module.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "validator/validator.h"
|
||||
#include <signal.h>
|
||||
|
||||
/** How many quit requests happened. */
|
||||
@@ -67,6 +68,8 @@ static int sig_record_reload = 0;
|
||||
static RETSIGTYPE record_sigh(int sig)
|
||||
{
|
||||
#ifdef LIBEVENT_SIGNAL_PROBLEM
|
||||
verbose(VERB_OPS, "quit on signal, no cleanup and statistics, "
|
||||
"because installed libevent version is not threadsafe");
|
||||
exit(0);
|
||||
#endif
|
||||
switch(sig)
|
||||
@@ -105,10 +108,10 @@ signal_handling_record()
|
||||
static void
|
||||
signal_handling_playback(struct worker* wrk)
|
||||
{
|
||||
if(sig_record_quit)
|
||||
worker_sighandler(SIGTERM, wrk);
|
||||
if(sig_record_reload)
|
||||
worker_sighandler(SIGHUP, wrk);
|
||||
if(sig_record_quit)
|
||||
worker_sighandler(SIGTERM, wrk);
|
||||
sig_record_quit = 0;
|
||||
sig_record_reload = 0;
|
||||
}
|
||||
@@ -124,13 +127,19 @@ daemon_init()
|
||||
checklock_start();
|
||||
ERR_load_crypto_strings();
|
||||
daemon->need_to_exit = 0;
|
||||
daemon->num_modules = 0;
|
||||
modstack_init(&daemon->mods);
|
||||
if(!(daemon->env = (struct module_env*)calloc(1,
|
||||
sizeof(*daemon->env)))) {
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
alloc_init(&daemon->superalloc, NULL, 0);
|
||||
daemon->acl = acl_list_create();
|
||||
if(!daemon->acl) {
|
||||
free(daemon->env);
|
||||
free(daemon);
|
||||
return NULL;
|
||||
}
|
||||
return daemon;
|
||||
}
|
||||
|
||||
@@ -147,134 +156,19 @@ daemon_open_shared_ports(struct daemon* daemon)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** count number of modules (words) in the string */
|
||||
static int
|
||||
count_modules(const char* s)
|
||||
{
|
||||
int num = 0;
|
||||
if(!s)
|
||||
return 0;
|
||||
while(*s) {
|
||||
/* skip whitespace */
|
||||
while(*s && isspace((int)*s))
|
||||
s++;
|
||||
if(*s && !isspace((int)*s)) {
|
||||
/* skip identifier */
|
||||
num++;
|
||||
while(*s && !isspace((int)*s))
|
||||
s++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get funcblock for module name
|
||||
* @param str: string with module name. Advanced to next value on success.
|
||||
* @return funcblock or NULL on error.
|
||||
*/
|
||||
static struct module_func_block*
|
||||
daemon_module_factory(const char** str)
|
||||
{
|
||||
/* these are the modules available */
|
||||
int num = 2;
|
||||
const char* names[] = {"iterator", "validator", NULL};
|
||||
struct module_func_block* (*fb[])(void) =
|
||||
{&iter_get_funcblock, &val_get_funcblock, NULL};
|
||||
|
||||
int i;
|
||||
const char* s = *str;
|
||||
while(*s && isspace((int)*s))
|
||||
s++;
|
||||
for(i=0; i<num; i++) {
|
||||
if(strncmp(names[i], s, strlen(names[i])) == 0) {
|
||||
s += strlen(names[i]);
|
||||
*str = s;
|
||||
return (*fb[i])();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read config file module settings and set up the modfunc block
|
||||
* @param daemon: the daemon.
|
||||
* @return false on error
|
||||
*/
|
||||
static int
|
||||
daemon_config_modules(struct daemon* daemon)
|
||||
{
|
||||
const char* str = daemon->cfg->module_conf;
|
||||
int i;
|
||||
verbose(VERB_DETAIL, "module config: \"%s\"", str);
|
||||
daemon->num_modules = count_modules(str);
|
||||
if(daemon->num_modules == 0) {
|
||||
log_err("error: no modules specified");
|
||||
return 0;
|
||||
}
|
||||
if(daemon->num_modules > MAX_MODULE) {
|
||||
log_err("error: too many modules (%d max %d)",
|
||||
daemon->num_modules, MAX_MODULE);
|
||||
return 0;
|
||||
}
|
||||
daemon->modfunc = (struct module_func_block**)calloc((size_t)
|
||||
daemon->num_modules, sizeof(struct module_func_block*));
|
||||
if(!daemon->modfunc) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<daemon->num_modules; i++) {
|
||||
daemon->modfunc[i] = daemon_module_factory(&str);
|
||||
if(!daemon->modfunc[i]) {
|
||||
log_err("Unknown value for first module in: '%s'",
|
||||
str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Desetup the modules, deinit, delete.
|
||||
* @param daemon: the daemon.
|
||||
*/
|
||||
static void
|
||||
daemon_desetup_modules(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<daemon->num_modules; i++) {
|
||||
(*daemon->modfunc[i]->deinit)(daemon->env, i);
|
||||
}
|
||||
daemon->num_modules = 0;
|
||||
free(daemon->modfunc);
|
||||
daemon->modfunc = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup modules. Assigns ids and calls module_init.
|
||||
* Setup modules. setup module stack.
|
||||
* @param daemon: the daemon
|
||||
*/
|
||||
static void daemon_setup_modules(struct daemon* daemon)
|
||||
{
|
||||
int i;
|
||||
if(daemon->num_modules != 0)
|
||||
daemon_desetup_modules(daemon);
|
||||
/* fixed setup of the modules */
|
||||
if(!daemon_config_modules(daemon)) {
|
||||
fatal_exit("failed to setup modules");
|
||||
}
|
||||
daemon->env->cfg = daemon->cfg;
|
||||
daemon->env->alloc = &daemon->superalloc;
|
||||
daemon->env->worker = NULL;
|
||||
daemon->env->send_packet = &worker_send_packet;
|
||||
daemon->env->send_query = &worker_send_query;
|
||||
daemon->env->need_to_validate = 0; /* set by module init below */
|
||||
for(i=0; i<daemon->num_modules; i++) {
|
||||
log_info("init module %d: %s", i, daemon->modfunc[i]->name);
|
||||
if(!(*daemon->modfunc[i]->init)(daemon->env, i)) {
|
||||
fatal_exit("module init for module %s failed",
|
||||
daemon->modfunc[i]->name);
|
||||
}
|
||||
if(!modstack_setup(&daemon->mods, daemon->cfg->module_conf,
|
||||
daemon->env)) {
|
||||
fatal_exit("failed to setup modules");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,7 +274,7 @@ daemon_stop_others(struct daemon* daemon)
|
||||
worker_send_cmd(daemon->workers[i],
|
||||
daemon->workers[0]->front->udp_buff, worker_cmd_quit);
|
||||
}
|
||||
/** wait for them to quit */
|
||||
/* wait for them to quit */
|
||||
for(i=1; i<daemon->num; i++) {
|
||||
/* join it to make sure its dead */
|
||||
verbose(VERB_ALGO, "join %d", i);
|
||||
@@ -393,6 +287,12 @@ void
|
||||
daemon_fork(struct daemon* daemon)
|
||||
{
|
||||
log_assert(daemon);
|
||||
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg))
|
||||
fatal_exit("Could not setup access control list");
|
||||
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))
|
||||
fatal_exit("Could not set up local zones");
|
||||
|
||||
/* setup modules */
|
||||
daemon_setup_modules(daemon);
|
||||
@@ -417,13 +317,12 @@ daemon_fork(struct daemon* daemon)
|
||||
/* Start resolver service on main thread. */
|
||||
log_info("start of service (%s).", PACKAGE_STRING);
|
||||
worker_work(daemon->workers[0]);
|
||||
log_info("service stopped (%s).", PACKAGE_STRING);
|
||||
|
||||
/* we exited! a signal happened! Stop other threads */
|
||||
daemon_stop_others(daemon);
|
||||
|
||||
if(daemon->workers[0]->need_to_restart)
|
||||
daemon->need_to_exit = 0;
|
||||
else daemon->need_to_exit = 1;
|
||||
daemon->need_to_exit = daemon->workers[0]->need_to_exit;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -435,6 +334,15 @@ daemon_cleanup(struct daemon* daemon)
|
||||
don't die on multiple reload signals for example. */
|
||||
signal_handling_record();
|
||||
log_thread_set(NULL);
|
||||
/* clean up caches because
|
||||
* a) RRset IDs will be recycled after a reload, causing collisions
|
||||
* b) validation config can change, thus rrset, msg, keycache clear
|
||||
* The infra cache is kept, the timing and edns info is still valid */
|
||||
slabhash_clear(&daemon->env->rrset_cache->table);
|
||||
slabhash_clear(daemon->env->msg_cache);
|
||||
local_zones_delete(daemon->local_zones);
|
||||
daemon->local_zones = NULL;
|
||||
/* key cache is cleared by module desetup during next daemon_init() */
|
||||
for(i=0; i<daemon->num; i++)
|
||||
worker_delete(daemon->workers[i]);
|
||||
free(daemon->workers);
|
||||
@@ -448,7 +356,7 @@ daemon_delete(struct daemon* daemon)
|
||||
{
|
||||
if(!daemon)
|
||||
return;
|
||||
daemon_desetup_modules(daemon);
|
||||
modstack_desetup(&daemon->mods, daemon->env);
|
||||
listening_ports_free(daemon->ports);
|
||||
if(daemon->env) {
|
||||
slabhash_delete(daemon->env->msg_cache);
|
||||
@@ -456,7 +364,7 @@ daemon_delete(struct daemon* daemon)
|
||||
infra_delete(daemon->env->infra_cache);
|
||||
}
|
||||
alloc_clear(&daemon->superalloc);
|
||||
free(daemon->cwd);
|
||||
acl_list_delete(daemon->acl);
|
||||
free(daemon->pidfile);
|
||||
free(daemon->env);
|
||||
free(daemon);
|
||||
@@ -467,5 +375,6 @@ daemon_delete(struct daemon* daemon)
|
||||
CRYPTO_cleanup_all_ex_data(); /* safe, no more threads right now */
|
||||
ERR_remove_state(0);
|
||||
ERR_free_strings();
|
||||
RAND_cleanup();
|
||||
checklock_stop();
|
||||
}
|
||||
|
||||
+9
-6
@@ -44,12 +44,15 @@
|
||||
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "services/modstack.h"
|
||||
struct config_file;
|
||||
struct worker;
|
||||
struct listen_port;
|
||||
struct slabhash;
|
||||
struct module_env;
|
||||
struct rrset_cache;
|
||||
struct acl_list;
|
||||
struct local_zones;
|
||||
|
||||
/**
|
||||
* Structure holding worker list.
|
||||
@@ -58,8 +61,6 @@ struct rrset_cache;
|
||||
struct daemon {
|
||||
/** The config settings */
|
||||
struct config_file* cfg;
|
||||
/** current working directory */
|
||||
char* cwd;
|
||||
/** pidfile that is used */
|
||||
char* pidfile;
|
||||
/** port number that has ports opened. */
|
||||
@@ -76,10 +77,12 @@ struct daemon {
|
||||
struct alloc_cache superalloc;
|
||||
/** the module environment master value, copied and changed by threads*/
|
||||
struct module_env* env;
|
||||
/** number of modules active, ids from 0 to num-1. */
|
||||
int num_modules;
|
||||
/** the module callbacks, array of num_modules length */
|
||||
struct module_func_block** modfunc;
|
||||
/** stack of module callbacks */
|
||||
struct module_stack mods;
|
||||
/** access control, which client IPs are allowed to connect */
|
||||
struct acl_list* acl;
|
||||
/** local authority zones */
|
||||
struct local_zones* local_zones;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+5
-3
@@ -46,7 +46,7 @@
|
||||
|
||||
void server_stats_init(struct server_stats* stats)
|
||||
{
|
||||
memset(stats, 0, sizeof(stats));
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
}
|
||||
|
||||
void server_stats_querymiss(struct server_stats* stats, struct worker* worker)
|
||||
@@ -59,10 +59,12 @@ void server_stats_querymiss(struct server_stats* stats, struct worker* worker)
|
||||
|
||||
void server_stats_log(struct server_stats* stats, int threadnum)
|
||||
{
|
||||
log_info("server stats for thread %d: %u queries, %u from cache",
|
||||
log_info("server stats for thread %d: %u queries, "
|
||||
"%u answers from cache, %u recursions",
|
||||
threadnum, (unsigned)stats->num_queries,
|
||||
(unsigned)(stats->num_queries -
|
||||
stats->num_queries_missed_cache));
|
||||
stats->num_queries_missed_cache),
|
||||
(unsigned)stats->num_queries_missed_cache);
|
||||
log_info("server stats for thread %d: requestlist max %u avg %g "
|
||||
"exceeded %u", threadnum, (unsigned)stats->max_query_list_size,
|
||||
stats->num_queries_missed_cache?
|
||||
|
||||
+63
-37
@@ -61,12 +61,13 @@ void* unbound_start_brk = 0;
|
||||
/** print usage. */
|
||||
static void usage()
|
||||
{
|
||||
printf("usage: unbound [options]\n");
|
||||
printf("usage: unbound [options]\n");
|
||||
printf(" start unbound daemon DNS resolver.\n");
|
||||
printf("-h this help\n");
|
||||
printf("-c file config file to read, unbound.conf(5).\n");
|
||||
printf("-c file config file to read instead of %s\n", CONFIGFILE);
|
||||
printf(" file format is described in unbound.conf(5).\n");
|
||||
printf("-d do not fork into the background.\n");
|
||||
printf("-v verbose (multiple times increase verbosity)\n");
|
||||
printf("-v verbose (more times to increase verbosity)\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
@@ -81,7 +82,8 @@ checkrlimits(struct config_file* cfg)
|
||||
(int)cfg->incoming_num_tcp:0));
|
||||
size_t ifs = (size_t)(cfg->num_ifs==0?1:cfg->num_ifs);
|
||||
size_t listen_num = list*ifs;
|
||||
size_t outnum = cfg->outgoing_num_ports*ifs + cfg->outgoing_num_tcp;
|
||||
size_t out_ifs = (size_t)(cfg->num_out_ifs==0?1:cfg->num_out_ifs);
|
||||
size_t outnum = cfg->outgoing_num_ports*out_ifs + cfg->outgoing_num_tcp;
|
||||
size_t misc = 4; /* logfile, pidfile, stdout... */
|
||||
size_t perthread = listen_num + outnum + 2/*cmdpipe*/ + 2/*libevent*/
|
||||
+ misc;
|
||||
@@ -109,24 +111,15 @@ checkrlimits(struct config_file* cfg)
|
||||
}
|
||||
}
|
||||
|
||||
/** to changedir, logfile */
|
||||
/** set verbosity, check rlimits, cache settings */
|
||||
static void
|
||||
apply_dir(struct daemon* daemon, struct config_file* cfg, int cmdline_verbose)
|
||||
apply_settings(struct daemon* daemon, struct config_file* cfg,
|
||||
int cmdline_verbose)
|
||||
{
|
||||
/* apply if they have changed */
|
||||
daemon->cfg = cfg;
|
||||
verbosity = cmdline_verbose + cfg->verbosity;
|
||||
if(cfg->directory && cfg->directory[0]) {
|
||||
if(!daemon->cwd || strcmp(daemon->cwd, cfg->directory) != 0) {
|
||||
if(chdir(cfg->directory)) {
|
||||
log_err("Could not chdir to %s: %s",
|
||||
cfg->directory, strerror(errno));
|
||||
}
|
||||
free(daemon->cwd);
|
||||
if(!(daemon->cwd = strdup(cfg->directory)))
|
||||
log_err("cwd: malloc failed");
|
||||
}
|
||||
}
|
||||
config_apply(cfg);
|
||||
if(!daemon->env->msg_cache ||
|
||||
cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) ||
|
||||
cfg->msg_cache_slabs != daemon->env->msg_cache->size) {
|
||||
@@ -183,7 +176,8 @@ readpid (const char* file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = strtol(pidbuf, &t, 10);
|
||||
pidbuf[sizeof(pidbuf)-1] = 0;
|
||||
pid = (pid_t)strtol(pidbuf, &t, 10);
|
||||
|
||||
if (*t && *t != '\n') {
|
||||
return -1;
|
||||
@@ -220,7 +214,12 @@ static void
|
||||
checkoldpid(struct config_file* cfg)
|
||||
{
|
||||
pid_t old;
|
||||
if((old = readpid(cfg->pidfile)) != -1) {
|
||||
char* file = cfg->pidfile;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(file, cfg->chrootdir, strlen(cfg->chrootdir))==0) {
|
||||
file += strlen(cfg->chrootdir);
|
||||
}
|
||||
if((old = readpid(file)) != -1) {
|
||||
/* see if it is still alive */
|
||||
if(kill(old, 0) == 0 || errno == EPERM)
|
||||
log_warn("unbound is already running as pid %u.",
|
||||
@@ -262,35 +261,62 @@ detach(struct config_file* cfg)
|
||||
static void
|
||||
do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
/* initialize, but not to 0 (root) */
|
||||
memset(&uid, 112, sizeof(uid));
|
||||
memset(&gid, 112, sizeof(gid));
|
||||
log_assert(cfg);
|
||||
|
||||
/* daemonize last to be able to print error to user */
|
||||
if(cfg->chrootdir && cfg->chrootdir[0])
|
||||
if(chroot(cfg->chrootdir))
|
||||
fatal_exit("unable to chroot: %s", strerror(errno));
|
||||
if(cfg->directory && cfg->directory[0]) {
|
||||
if(chdir(cfg->directory)) {
|
||||
fatal_exit("Could not chdir to %s: %s",
|
||||
cfg->directory, strerror(errno));
|
||||
}
|
||||
verbose(VERB_QUERY, "chdir to %s", cfg->directory);
|
||||
}
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
struct passwd *pwd;
|
||||
if((pwd = getpwnam(cfg->username)) == NULL)
|
||||
fatal_exit("user '%s' does not exist.", cfg->username);
|
||||
if(setgid(pwd->pw_gid) != 0)
|
||||
fatal_exit("unable to set group id: %s", strerror(errno));
|
||||
if(setuid(pwd->pw_uid) != 0)
|
||||
fatal_exit("unable to set user id: %s", strerror(errno));
|
||||
uid = pwd->pw_uid;
|
||||
gid = pwd->pw_gid;
|
||||
endpwent();
|
||||
}
|
||||
if(cfg->chrootdir && cfg->chrootdir[0]) {
|
||||
if(chroot(cfg->chrootdir))
|
||||
fatal_exit("unable to chroot to %s: %s",
|
||||
cfg->chrootdir, strerror(errno));
|
||||
verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir);
|
||||
}
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if(setgid(gid) != 0)
|
||||
fatal_exit("unable to set group id of %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
if(setuid(uid) != 0)
|
||||
fatal_exit("unable to set user id of %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
verbose(VERB_QUERY, "drop user privileges, run as %s",
|
||||
cfg->username);
|
||||
}
|
||||
/* check old pid file before forking */
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
checkoldpid(cfg);
|
||||
}
|
||||
|
||||
/* init logfile just before fork */
|
||||
log_init(cfg->logfile);
|
||||
log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
|
||||
if(!debug_mode && cfg->do_daemonize) {
|
||||
detach(cfg);
|
||||
}
|
||||
if(cfg->pidfile && cfg->pidfile[0]) {
|
||||
writepid(cfg->pidfile, getpid());
|
||||
if(!(daemon->pidfile = strdup(cfg->pidfile)))
|
||||
char* pf = cfg->pidfile;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(pf, cfg->chrootdir, strlen(cfg->chrootdir))==0)
|
||||
pf += strlen(cfg->chrootdir);
|
||||
writepid(pf, getpid());
|
||||
if(!(daemon->pidfile = strdup(pf)))
|
||||
log_err("pidf: malloc failed");
|
||||
}
|
||||
}
|
||||
@@ -303,7 +329,7 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode)
|
||||
* @param debug_mode: if set, do not daemonize.
|
||||
*/
|
||||
static void
|
||||
run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
|
||||
run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode)
|
||||
{
|
||||
struct config_file* cfg = NULL;
|
||||
struct daemon* daemon = NULL;
|
||||
@@ -313,15 +339,15 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
|
||||
fatal_exit("alloc failure");
|
||||
while(!daemon->need_to_exit) {
|
||||
if(done_chroot)
|
||||
log_info("Restart of %s.", PACKAGE_STRING);
|
||||
else log_info("Start of %s.", PACKAGE_STRING);
|
||||
verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING);
|
||||
else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING);
|
||||
|
||||
/* config stuff */
|
||||
if(!(cfg = config_create()))
|
||||
fatal_exit("Could not alloc config defaults");
|
||||
if(!config_read(cfg, cfgfile))
|
||||
fatal_exit("Could not read config file: %s", cfgfile);
|
||||
apply_dir(daemon, cfg, cmdline_verbose);
|
||||
apply_settings(daemon, cfg, cmdline_verbose);
|
||||
|
||||
/* prepare */
|
||||
if(!daemon_open_shared_ports(daemon))
|
||||
@@ -329,7 +355,7 @@ run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode)
|
||||
if(!done_chroot) {
|
||||
do_chroot(daemon, cfg, debug_mode);
|
||||
done_chroot = 1;
|
||||
}
|
||||
} else log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
|
||||
/* work */
|
||||
daemon_fork(daemon);
|
||||
|
||||
@@ -359,14 +385,14 @@ int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int c;
|
||||
const char* cfgfile = NULL;
|
||||
char* cfgfile = CONFIGFILE;
|
||||
int cmdline_verbose = 0;
|
||||
int debug_mode = 0;
|
||||
|
||||
/* take debug snapshot of heap */
|
||||
unbound_start_brk = sbrk(0);
|
||||
|
||||
log_init(NULL);
|
||||
log_init(NULL, 0, NULL);
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "c:dhv")) != -1) {
|
||||
switch(c) {
|
||||
@@ -396,6 +422,6 @@ main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
run_daemon(cfgfile, cmdline_verbose, debug_mode);
|
||||
log_init(NULL); /* close logfile */
|
||||
log_init(NULL, 0, NULL); /* close logfile */
|
||||
return 0;
|
||||
}
|
||||
|
||||
+206
-89
@@ -45,10 +45,11 @@
|
||||
#include "util/random.h"
|
||||
#include "daemon/worker.h"
|
||||
#include "daemon/daemon.h"
|
||||
#include "daemon/acl_list.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/outside_network.h"
|
||||
@@ -57,9 +58,11 @@
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/mesh.h"
|
||||
#include "services/localzone.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
@@ -133,18 +136,21 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
|
||||
superac = alloc_get_mem(&worker->daemon->superalloc);
|
||||
iter = 0;
|
||||
val = 0;
|
||||
for(i=0; i<worker->env.mesh->num_modules; i++) {
|
||||
if(strcmp(worker->env.mesh->modfunc[i]->name, "validator")==0)
|
||||
val += (*worker->env.mesh->modfunc[i]->get_mem)
|
||||
for(i=0; i<worker->env.mesh->mods.num; i++) {
|
||||
log_assert(fptr_whitelist_mod_get_mem(worker->env.mesh->
|
||||
mods.mod[i]->get_mem));
|
||||
if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
|
||||
val += (*worker->env.mesh->mods.mod[i]->get_mem)
|
||||
(&worker->env, i);
|
||||
else iter += (*worker->env.mesh->modfunc[i]->get_mem)
|
||||
else iter += (*worker->env.mesh->mods.mod[i]->get_mem)
|
||||
(&worker->env, i);
|
||||
}
|
||||
me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig)
|
||||
+ comm_point_get_mem(worker->cmd_com) +
|
||||
sizeof(worker->rndstate) + region_get_mem(worker->scratchpad)+
|
||||
sizeof(*worker->env.scratch_buffer) +
|
||||
ldns_buffer_capacity(worker->env.scratch_buffer);
|
||||
+ comm_point_get_mem(worker->cmd_com)
|
||||
+ sizeof(worker->rndstate)
|
||||
+ regional_get_mem(worker->scratchpad)
|
||||
+ sizeof(*worker->env.scratch_buffer)
|
||||
+ ldns_buffer_capacity(worker->env.scratch_buffer);
|
||||
if(cur_serv) {
|
||||
me += serviced_get_mem(cur_serv);
|
||||
}
|
||||
@@ -157,6 +163,23 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
|
||||
(unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)ac,
|
||||
(unsigned)superac, (unsigned)me);
|
||||
debug_total_mem(total);
|
||||
#else /* no UNBOUND_ALLOC_STATS */
|
||||
size_t val = 0;
|
||||
int i;
|
||||
if(verbosity < VERB_QUERY)
|
||||
return;
|
||||
for(i=0; i<worker->env.mesh->mods.num; i++) {
|
||||
log_assert(fptr_whitelist_mod_get_mem(worker->env.mesh->
|
||||
mods.mod[i]->get_mem));
|
||||
if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
|
||||
val += (*worker->env.mesh->mods.mod[i]->get_mem)
|
||||
(&worker->env, i);
|
||||
}
|
||||
verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u",
|
||||
(unsigned)slabhash_get_mem(worker->env.msg_cache),
|
||||
(unsigned)slabhash_get_mem(&worker->env.rrset_cache->table),
|
||||
(unsigned)infra_get_mem(worker->env.infra_cache),
|
||||
(unsigned)val);
|
||||
#endif /* UNBOUND_ALLOC_STATS */
|
||||
}
|
||||
|
||||
@@ -174,8 +197,7 @@ worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
|
||||
log_err("write socket: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/** process incoming replies from the network */
|
||||
static int
|
||||
int
|
||||
worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info)
|
||||
{
|
||||
@@ -206,8 +228,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
static int
|
||||
int
|
||||
worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info)
|
||||
{
|
||||
@@ -246,53 +267,52 @@ static int
|
||||
worker_check_request(ldns_buffer* pkt, struct worker* worker)
|
||||
{
|
||||
if(ldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
|
||||
verbose(VERB_DETAIL, "request too short, discarded");
|
||||
verbose(VERB_QUERY, "request too short, discarded");
|
||||
return -1;
|
||||
}
|
||||
if(ldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
|
||||
worker->daemon->cfg->harden_large_queries) {
|
||||
verbose(VERB_DETAIL, "request too large, discarded");
|
||||
verbose(VERB_QUERY, "request too large, discarded");
|
||||
return -1;
|
||||
}
|
||||
if(LDNS_QR_WIRE(ldns_buffer_begin(pkt))) {
|
||||
verbose(VERB_DETAIL, "request has QR bit on, discarded");
|
||||
verbose(VERB_QUERY, "request has QR bit on, discarded");
|
||||
return -1;
|
||||
}
|
||||
if(LDNS_TC_WIRE(ldns_buffer_begin(pkt))) {
|
||||
LDNS_TC_CLR(ldns_buffer_begin(pkt));
|
||||
verbose(VERB_QUERY, "request bad, has TC bit on");
|
||||
return LDNS_RCODE_FORMERR;
|
||||
}
|
||||
if(LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
|
||||
verbose(VERB_DETAIL, "request unknown opcode %d",
|
||||
verbose(VERB_QUERY, "request unknown opcode %d",
|
||||
LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)));
|
||||
return LDNS_RCODE_NOTIMPL;
|
||||
}
|
||||
if(LDNS_QDCOUNT(ldns_buffer_begin(pkt)) != 1) {
|
||||
verbose(VERB_DETAIL, "request wrong nr qd=%d",
|
||||
verbose(VERB_QUERY, "request wrong nr qd=%d",
|
||||
LDNS_QDCOUNT(ldns_buffer_begin(pkt)));
|
||||
return LDNS_RCODE_FORMERR;
|
||||
}
|
||||
if(LDNS_ANCOUNT(ldns_buffer_begin(pkt)) != 0) {
|
||||
verbose(VERB_DETAIL, "request wrong nr an=%d",
|
||||
verbose(VERB_QUERY, "request wrong nr an=%d",
|
||||
LDNS_ANCOUNT(ldns_buffer_begin(pkt)));
|
||||
return LDNS_RCODE_FORMERR;
|
||||
}
|
||||
if(LDNS_NSCOUNT(ldns_buffer_begin(pkt)) != 0) {
|
||||
verbose(VERB_DETAIL, "request wrong nr ns=%d",
|
||||
verbose(VERB_QUERY, "request wrong nr ns=%d",
|
||||
LDNS_NSCOUNT(ldns_buffer_begin(pkt)));
|
||||
return LDNS_RCODE_FORMERR;
|
||||
}
|
||||
if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) > 1) {
|
||||
verbose(VERB_DETAIL, "request wrong nr ar=%d",
|
||||
verbose(VERB_QUERY, "request wrong nr ar=%d",
|
||||
LDNS_ARCOUNT(ldns_buffer_begin(pkt)));
|
||||
return LDNS_RCODE_FORMERR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** process control messages from the main thread.
|
||||
* @param c: comm point to read from.
|
||||
* @param arg: worker.
|
||||
* @param error: error status of comm point.
|
||||
* @param reply_info: not used.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
@@ -364,6 +384,7 @@ deleg_remove_nonsecure_additional(struct reply_info* rep)
|
||||
(rep->rrset_count - i - 1));
|
||||
rep->ar_numrrsets--;
|
||||
rep->rrset_count--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,7 +415,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
qinfo->qname_len, qinfo->qtype, qinfo->qclass,
|
||||
worker->scratchpad, &msg, timenow);
|
||||
if(!dp) { /* no delegation, need to reprime */
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
if(must_validate) {
|
||||
@@ -402,7 +423,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
case sec_status_unchecked:
|
||||
/* some rrsets have not been verified yet, go and
|
||||
* let validator do that */
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
case sec_status_bogus:
|
||||
/* some rrsets are bogus, reply servfail */
|
||||
@@ -412,7 +433,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
edns->bits &= EDNS_DO;
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
&msg->qinfo, id, flags, edns);
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 1;
|
||||
case sec_status_secure:
|
||||
/* all rrsets are secure */
|
||||
@@ -441,7 +462,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
&msg->qinfo, id, flags, edns);
|
||||
}
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -514,7 +535,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
bail_out:
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -529,7 +550,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
&mrentry->key, id, flags, edns);
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 1;
|
||||
} else if( rep->security == sec_status_unchecked && must_validate) {
|
||||
verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
|
||||
@@ -562,7 +583,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
* is bad while holding locks. */
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
|
||||
rep->ref, rep->rrset_count);
|
||||
region_free_all(worker->scratchpad);
|
||||
regional_free_all(worker->scratchpad);
|
||||
/* go and return this buffer to the client */
|
||||
return 1;
|
||||
}
|
||||
@@ -629,10 +650,11 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
|
||||
if(cfg->hide_identity)
|
||||
return 0;
|
||||
if(cfg->identity==NULL || cfg->identity[0]==0) {
|
||||
char buf[MAXHOSTNAMELEN];
|
||||
if (gethostname(buf, MAXHOSTNAMELEN) == 0)
|
||||
char buf[MAXHOSTNAMELEN+1];
|
||||
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
|
||||
buf[MAXHOSTNAMELEN] = 0;
|
||||
chaos_replystr(pkt, buf, edns);
|
||||
else {
|
||||
} else {
|
||||
log_err("gethostname: %s", strerror(errno));
|
||||
chaos_replystr(pkt, "no hostname", edns);
|
||||
}
|
||||
@@ -655,8 +677,7 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** handles callbacks from listening event interface */
|
||||
static int
|
||||
int
|
||||
worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo)
|
||||
{
|
||||
@@ -666,11 +687,30 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct lruhash_entry* e;
|
||||
struct query_info qinfo;
|
||||
struct edns_data edns;
|
||||
enum acl_access acl;
|
||||
|
||||
if(error != NETEVENT_NOERROR) {
|
||||
log_err("handle request called with err=%d", error);
|
||||
/* some bad tcp query DNS formats give these error calls */
|
||||
verbose(VERB_ALGO, "handle request called with err=%d", error);
|
||||
return 0;
|
||||
}
|
||||
acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr,
|
||||
repinfo->addrlen);
|
||||
if(acl == acl_deny) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
} else if(acl == acl_refuse) {
|
||||
ldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
|
||||
ldns_buffer_write_at(c->buffer, 4,
|
||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
log_addr(VERB_ALGO, "refused query from",
|
||||
&repinfo->addr, repinfo->addrlen);
|
||||
log_buf(VERB_ALGO, "refuse", c->buffer);
|
||||
return 1;
|
||||
}
|
||||
if((ret=worker_check_request(c->buffer, worker)) != 0) {
|
||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||
if(ret != -1) {
|
||||
@@ -718,7 +758,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
|
||||
worker->daemon->cfg->harden_short_bufsize) {
|
||||
verbose(VERB_DETAIL, "worker request: EDNS bufsize %d ignored",
|
||||
verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
|
||||
(int)edns.udp_size);
|
||||
edns.udp_size = NORMAL_UDP_SIZE;
|
||||
}
|
||||
@@ -729,6 +769,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
ldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
ldns_buffer_write_at(c->buffer, 4,
|
||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||
ldns_buffer_flip(c->buffer);
|
||||
return 1;
|
||||
}
|
||||
@@ -738,6 +780,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
&edns, c->buffer)) {
|
||||
return 1;
|
||||
}
|
||||
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
|
||||
c->buffer, worker->scratchpad)) {
|
||||
return (ldns_buffer_limit(c->buffer) != 0);
|
||||
}
|
||||
h = query_info_hash(&qinfo);
|
||||
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
|
||||
/* answer from cache - we have acquired a readlock on it */
|
||||
@@ -765,59 +811,46 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
server_stats_querymiss(&worker->stats, worker);
|
||||
|
||||
/* grab a work request structure for this new request */
|
||||
/* @@@ TODO implement overload mode */
|
||||
if(0 && worker->env.mesh->all.count > worker->request_size) {
|
||||
/* we could get this due to a slow tcp incoming query,
|
||||
that started before we performed listen_pushback */
|
||||
verbose(VERB_DETAIL, "worker: too many incoming requests "
|
||||
"active. dropping incoming query.");
|
||||
verbose(VERB_ALGO, "currently servicing %d of %d queries",
|
||||
(int)worker->env.mesh->all.count,
|
||||
(int)worker->request_size);
|
||||
if(worker->env.mesh->all.count > worker->request_size) {
|
||||
verbose(VERB_ALGO, "Too many requests active. "
|
||||
"dropping incoming query.");
|
||||
worker->stats.num_query_list_exceeded++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
query_info_clear(&qinfo);
|
||||
return 0;
|
||||
}
|
||||
mesh_new_client(worker->env.mesh, &qinfo,
|
||||
ldns_buffer_read_u16_at(c->buffer, 2),
|
||||
&edns, repinfo, *(uint16_t*)ldns_buffer_begin(c->buffer));
|
||||
|
||||
if(0) { /* TODO overload mode does not work yet. */
|
||||
if(worker->env.mesh->all.count == worker->request_size) {
|
||||
/* the max request number has been reached, stop accepting */
|
||||
listen_pushback(worker->front);
|
||||
}
|
||||
}
|
||||
worker_mem_report(worker, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** worker signal callback */
|
||||
void
|
||||
worker_sighandler(int sig, void* arg)
|
||||
{
|
||||
/* note that log, print, syscalls here give race conditions. */
|
||||
/* we still print DETAIL logs, because this is extensive per message
|
||||
* logging anyway, and the operator may then have an interest
|
||||
* in the cause for unbound to exit */
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
switch(sig) {
|
||||
case SIGHUP:
|
||||
log_info("caught signal SIGHUP");
|
||||
worker->need_to_restart = 1;
|
||||
verbose(VERB_QUERY, "caught signal SIGHUP");
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGINT:
|
||||
log_info("caught signal SIGINT");
|
||||
worker->need_to_restart = 0;
|
||||
verbose(VERB_QUERY, "caught signal SIGINT");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGQUIT:
|
||||
log_info("caught signal SIGQUIT");
|
||||
worker->need_to_restart = 0;
|
||||
verbose(VERB_QUERY, "caught signal SIGQUIT");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGTERM:
|
||||
log_info("caught signal SIGTERM");
|
||||
worker->need_to_restart = 0;
|
||||
verbose(VERB_QUERY, "caught signal SIGTERM");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
default:
|
||||
@@ -826,6 +859,30 @@ worker_sighandler(int sig, void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
/** restart statistics timer for worker, if enabled */
|
||||
static void
|
||||
worker_restart_timer(struct worker* worker)
|
||||
{
|
||||
if(worker->env.cfg->stat_interval > 0) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
comm_timer_set(worker->stat_timer, &tv);
|
||||
}
|
||||
}
|
||||
|
||||
void worker_stat_timer_cb(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
server_stats_log(&worker->stats, worker->thread_num);
|
||||
mesh_stats(worker->env.mesh, "mesh has");
|
||||
worker_mem_report(worker, NULL);
|
||||
server_stats_init(&worker->stats);
|
||||
mesh_stats_clear(worker->env.mesh);
|
||||
/* start next timer */
|
||||
worker_restart_timer(worker);
|
||||
}
|
||||
|
||||
struct worker*
|
||||
worker_create(struct daemon* daemon, int id)
|
||||
{
|
||||
@@ -863,7 +920,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
{
|
||||
unsigned int seed;
|
||||
int startport;
|
||||
worker->need_to_restart = 0;
|
||||
worker->need_to_exit = 0;
|
||||
worker->base = comm_base_create();
|
||||
if(!worker->base) {
|
||||
log_err("could not create event handling base");
|
||||
@@ -890,21 +947,16 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
} else { /* !do_sigs */
|
||||
worker->comsig = 0;
|
||||
}
|
||||
/* init random(), large table size. */
|
||||
if(!(worker->rndstate = (struct ub_randstate*)calloc(1,
|
||||
sizeof(struct ub_randstate)))) {
|
||||
log_err("malloc rndtable failed.");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
|
||||
(((unsigned int)worker->thread_num)<<17);
|
||||
/* shift thread_num so it does not match out pid bits */
|
||||
if(!ub_initstate(seed, worker->rndstate, RND_STATE_SIZE)) {
|
||||
if(!(worker->rndstate = ub_initstate(seed, NULL))) {
|
||||
seed = 0;
|
||||
log_err("could not init random numbers.");
|
||||
worker_delete(worker);
|
||||
return 0;
|
||||
}
|
||||
seed = 0;
|
||||
worker->front = listen_create(worker->base, ports,
|
||||
cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
|
||||
worker_handle_request, worker);
|
||||
@@ -917,8 +969,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
cfg->outgoing_num_ports * worker->thread_num;
|
||||
worker->back = outside_network_create(worker->base,
|
||||
cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
|
||||
cfg->ifs, cfg->num_ifs, cfg->do_ip4, cfg->do_ip6, startport,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0,
|
||||
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
startport, cfg->do_tcp?cfg->outgoing_num_tcp:0,
|
||||
worker->daemon->env->infra_cache, worker->rndstate);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
@@ -935,10 +987,15 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
worker->stat_timer = comm_timer_create(worker->base,
|
||||
worker_stat_timer_cb, worker);
|
||||
if(!worker->stat_timer) {
|
||||
log_err("could not create statistics timer");
|
||||
}
|
||||
|
||||
/* we use the msg_buffer_size as a good estimate for what the
|
||||
* user wants for memory usage sizes */
|
||||
worker->scratchpad = region_create_custom(malloc, free,
|
||||
cfg->msg_buffer_size, cfg->msg_buffer_size/4, 32, 1);
|
||||
worker->scratchpad = regional_create_custom(cfg->msg_buffer_size);
|
||||
if(!worker->scratchpad) {
|
||||
log_err("malloc failure");
|
||||
worker_delete(worker);
|
||||
@@ -949,13 +1006,15 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
server_stats_init(&worker->stats);
|
||||
alloc_init(&worker->alloc, &worker->daemon->superalloc,
|
||||
worker->thread_num);
|
||||
alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker);
|
||||
worker->env = *worker->daemon->env;
|
||||
worker->env.worker = worker;
|
||||
worker->env.send_packet = &worker_send_packet;
|
||||
worker->env.send_query = &worker_send_query;
|
||||
worker->env.alloc = &worker->alloc;
|
||||
worker->env.rnd = worker->rndstate;
|
||||
worker->env.scratch = worker->scratchpad;
|
||||
worker->env.mesh = mesh_create(worker->daemon->num_modules,
|
||||
worker->daemon->modfunc, &worker->env);
|
||||
worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
|
||||
worker->env.detach_subs = &mesh_detach_subs;
|
||||
worker->env.attach_sub = &mesh_attach_sub;
|
||||
worker->env.kill_sub = &mesh_state_delete;
|
||||
@@ -966,6 +1025,12 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
return 0;
|
||||
}
|
||||
worker_mem_report(worker, NULL);
|
||||
/* if statistics enabled start timer */
|
||||
if(worker->env.cfg->stat_interval > 0) {
|
||||
verbose(VERB_ALGO, "set statistics interval %d secs",
|
||||
worker->env.cfg->stat_interval);
|
||||
worker_restart_timer(worker);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -980,18 +1045,20 @@ worker_delete(struct worker* worker)
|
||||
{
|
||||
if(!worker)
|
||||
return;
|
||||
mesh_stats(worker->env.mesh, "mesh has");
|
||||
server_stats_log(&worker->stats, worker->thread_num);
|
||||
worker_mem_report(worker, NULL);
|
||||
if(worker->env.mesh && verbosity >= VERB_OPS) {
|
||||
server_stats_log(&worker->stats, worker->thread_num);
|
||||
mesh_stats(worker->env.mesh, "mesh has");
|
||||
worker_mem_report(worker, NULL);
|
||||
}
|
||||
mesh_delete(worker->env.mesh);
|
||||
ldns_buffer_free(worker->env.scratch_buffer);
|
||||
listen_delete(worker->front);
|
||||
outside_network_delete(worker->back);
|
||||
comm_signal_delete(worker->comsig);
|
||||
comm_point_delete(worker->cmd_com);
|
||||
comm_timer_delete(worker->stat_timer);
|
||||
comm_base_delete(worker->base);
|
||||
ub_randfree(worker->rndstate);
|
||||
free(worker->rndstate);
|
||||
/* close fds after deleting commpoints, to be sure.
|
||||
Also epoll does not like closing fd before event_del */
|
||||
if(worker->cmd_send_fd != -1)
|
||||
@@ -1001,7 +1068,7 @@ worker_delete(struct worker* worker)
|
||||
close(worker->cmd_recv_fd);
|
||||
worker->cmd_recv_fd = -1;
|
||||
alloc_clear(&worker->alloc);
|
||||
region_destroy(worker->scratchpad);
|
||||
regional_destroy(worker->scratchpad);
|
||||
free(worker);
|
||||
}
|
||||
|
||||
@@ -1038,7 +1105,7 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
struct module_qstate* q)
|
||||
{
|
||||
struct worker* worker = q->env->worker;
|
||||
struct outbound_entry* e = (struct outbound_entry*)region_alloc(
|
||||
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
|
||||
q->region, sizeof(*e));
|
||||
if(!e)
|
||||
return NULL;
|
||||
@@ -1052,3 +1119,53 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
void
|
||||
worker_alloc_cleanup(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
slabhash_clear(&worker->env.rrset_cache->table);
|
||||
slabhash_clear(worker->env.msg_cache);
|
||||
}
|
||||
|
||||
/* --- fake callbacks for fptr_wlist to work --- */
|
||||
int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
|
||||
struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
|
||||
{
|
||||
log_assert(0);
|
||||
return 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),
|
||||
int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+35
-8
@@ -57,10 +57,7 @@ struct config_file;
|
||||
struct daemon;
|
||||
struct listen_port;
|
||||
struct ub_randstate;
|
||||
struct region;
|
||||
|
||||
/** size of table used for random numbers. large to be more secure. */
|
||||
#define RND_STATE_SIZE 256
|
||||
struct regional;
|
||||
|
||||
/** worker commands */
|
||||
enum worker_commands {
|
||||
@@ -93,20 +90,22 @@ struct worker {
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
struct comm_point* cmd_com;
|
||||
/** timer for statistics */
|
||||
struct comm_timer* stat_timer;
|
||||
|
||||
/** number of requests that can be handled by this worker */
|
||||
size_t request_size;
|
||||
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** do we need to restart (instead of exit) ? */
|
||||
int need_to_restart;
|
||||
/** do we need to restart or quit (on signal) */
|
||||
int need_to_exit;
|
||||
/** allocation cache for this thread */
|
||||
struct alloc_cache alloc;
|
||||
/** per thread statistics */
|
||||
struct server_stats stats;
|
||||
/** thread scratch region */
|
||||
struct region* scratchpad;
|
||||
/** thread scratch regional */
|
||||
struct regional* scratchpad;
|
||||
|
||||
/** module environment passed to modules, changed for this thread */
|
||||
struct module_env env;
|
||||
@@ -192,4 +191,32 @@ struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct module_qstate* q);
|
||||
|
||||
/**
|
||||
* process control messages from the main thread.
|
||||
* @param c: comm point to read from.
|
||||
* @param arg: worker.
|
||||
* @param error: error status of comm point.
|
||||
* @param reply_info: not used.
|
||||
*/
|
||||
int worker_handle_control_cmd(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** handles callbacks from listening event interface */
|
||||
int worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo);
|
||||
|
||||
/** process incoming replies from the network */
|
||||
int worker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** cleanup the cache to remove all rrset IDs from it, arg is worker */
|
||||
void worker_alloc_cleanup(void* arg);
|
||||
|
||||
/** statistics timer callback handler */
|
||||
void worker_stat_timer_cb(void* arg);
|
||||
|
||||
#endif /* DAEMON_WORKER_H */
|
||||
|
||||
@@ -5,3 +5,8 @@ from the University of California and from Verisign. The Java prototype
|
||||
was made in further cooperation with Geoff Sisson and Roy Arends from Nominet.
|
||||
|
||||
At NLnet Labs, Jelte Jansen and Mark Santcroos reviewed the unbound C sources.
|
||||
|
||||
Jakob Schlyter - for advice on secure settings, random numbers and blacklists.
|
||||
|
||||
Ondřej Surý - running coverity analysis tool on 0.9 dev version.
|
||||
Alexander Gall - multihomed, anycast testing of unbound resolver server.
|
||||
|
||||
+539
@@ -1,9 +1,548 @@
|
||||
11 February 2008: Wouter
|
||||
- nicer statistic output (from trunk).
|
||||
- ub_val to ub_ for library API (from trunk).
|
||||
- (from trunk) set_option, set_debugout, etc/hosts handling.
|
||||
|
||||
8 February 2008: Wouter
|
||||
- test program for multiple queries over a TCP channel.
|
||||
- tpkg test for stream tcp queries.
|
||||
- unbound replies to multiple TCP queries on a TCP channel.
|
||||
- fixup misclassification of root referral with NS in answer
|
||||
when validating a nonrec query.
|
||||
- tag 0.9
|
||||
|
||||
7 February 2008: Wouter
|
||||
- moved up all current level 2 to be level 3. And 3 to 4.
|
||||
to make room for new debug level 2 for detailed information
|
||||
for operators.
|
||||
- verbosity level 2. Describes recursion and validation.
|
||||
- cleaner configure script and fixes for libevent solaris.
|
||||
- signedness for log output memory sizes in high verbosity.
|
||||
|
||||
6 February 2008: Wouter
|
||||
- clearer explanation of threading configure options.
|
||||
- fixup asynclook test for nothreading (it creates only one process
|
||||
to do the extended test).
|
||||
- changed name of ub_val_result_free to ub_val_resolve_free.
|
||||
- removes warning message during library linking, renamed
|
||||
libunbound/unbound.c -> libunbound.c and worker to libworker.
|
||||
- fallback without EDNS if result is NOTIMPL as well as on FORMERR.
|
||||
|
||||
5 February 2008: Wouter
|
||||
- statistics-interval: seconds option added.
|
||||
- test for statistics option
|
||||
- ignore errors making directories, these can occur in parallel builds
|
||||
- fixup Makefile strip command and libunbound docs typo.
|
||||
|
||||
31 January 2008: Wouter
|
||||
- bg thread/process reads and writes the pipe nonblocking all the time
|
||||
so that even if the pipe is buffered or so, the bg thread does not
|
||||
block, and services both pipes and queries.
|
||||
|
||||
30 January 2008: Wouter
|
||||
- check trailing / on chrootdir in checkconf.
|
||||
- check if root hints and anchor files are in chrootdir.
|
||||
- no route to host tcp error is verbosity level 2.
|
||||
- removed unused send_reply_iov. and its configure check.
|
||||
- added prints of 'remote address is 1.2.3.4 port 53' to errors
|
||||
from netevent; the basic socket errors.
|
||||
|
||||
28 January 2008: Wouter
|
||||
- fixup uninit use of buffer by libunbound (query id, flags) for
|
||||
local_zone answers.
|
||||
- fixup uninit warning from random.c; also seems to fix sporadic
|
||||
sigFPE coming out of openssl.
|
||||
- made openssl entropy warning more silent for library use. Needs
|
||||
verbosity 1 now.
|
||||
- fixup forgotten locks for rbtree_searches on ctx->query tree.
|
||||
- random generator cleanup - RND_STATE_SIZE removed, and instead
|
||||
a super-rnd can be passed at init to chain init random states.
|
||||
- test also does lock checks if available.
|
||||
- protect config access in libworker_setup().
|
||||
- libevent doesn't like comm_base_exit outside of runloop.
|
||||
- close fds after removing commpoints only (for epoll, kqueue).
|
||||
|
||||
25 January 2008: Wouter
|
||||
- added tpkg for asynclook and library use.
|
||||
- allows localhost to be queried when as a library.
|
||||
- fixup race condition between cancel and answer (in case of
|
||||
really fast answers that beat the cancel).
|
||||
- please doxygen, put doxygen comment in one place.
|
||||
- asynclook -b blocking mode and test.
|
||||
- refactor asynclook, nicer code.
|
||||
- fixup race problems from opensll in rand init from library, with
|
||||
a mutex around the rand init.
|
||||
- fix pass async_id=NULL to _async resolve().
|
||||
- rewrote _wait() routine, so that it is threadsafe.
|
||||
- cancelation is threadsafe.
|
||||
- asynclook extended test in tpkg.
|
||||
- fixed two races where forked bg process waits for (somehow shared?)
|
||||
locks, so does not service the query pipe on the bg side.
|
||||
Now those locks are only held for fg_threads and for bg_as_a_thread.
|
||||
|
||||
24 January 2008: Wouter
|
||||
- tested the cancel() function.
|
||||
- asynclook -c (cancel) feature.
|
||||
- fix fail to allocate context actions.
|
||||
- make pipe nonblocking at start.
|
||||
- update plane for retry mode with caution to limit bandwidth.
|
||||
- fix Makefile for concurrent make of unbound-host.
|
||||
- renamed ub_val_ctx_wait/poll/process/fd to ub_val*.
|
||||
- new calls to set forwarding added to header and docs.
|
||||
|
||||
23 January 2008: Wouter
|
||||
- removed debug prints from if-auto, verb-algo enables some.
|
||||
- libunbound QUIT setup, remove memory leaks, when using threads
|
||||
will share memory for passing results instead of writing it over
|
||||
the pipe, only writes ID number over the pipe (towards the handler
|
||||
thread that does process() ).
|
||||
|
||||
22 January 2008: Wouter
|
||||
- library code for async in libunbound/unbound.c.
|
||||
- fix link testbound.
|
||||
- fixup exit bug in mini_event.
|
||||
- background worker query enter and result functions.
|
||||
- bg query test application asynclook, it looks up multiple
|
||||
hostaddresses (A records) at the same time.
|
||||
|
||||
21 January 2008: Wouter
|
||||
- libworker work, netevent raw commpoints, write_msg, serialize.
|
||||
|
||||
18 January 2008: Wouter
|
||||
- touch up of manpage for libunbound.
|
||||
- support for IP_RECVDSTADDR (for *BSD ip4).
|
||||
- fix for BSD, do not use ip4to6 mapping, make two sockets, once
|
||||
ip6 and once ip4, uses socket options.
|
||||
- goodbye ip4to6 mapping.
|
||||
- update ldns-testpkts with latest version from ldns-trunk.
|
||||
- updated makedist for relative ldns pathnames.
|
||||
- library API with more information inside the result structure.
|
||||
- work on background resolves.
|
||||
|
||||
17 January 2008: Wouter
|
||||
- fixup configure in case -lldns is installed.
|
||||
- fixup a couple of doxygen warnings, about enum variables.
|
||||
- interface-automatic now copies the interface address from the
|
||||
PKT_INFO structure as well.
|
||||
- manual page with library API, all on one page 'man libunbound'.
|
||||
- rewrite of PKTINFO structure, it also captures IP4 PKTINFO.
|
||||
|
||||
16 January 2008: Wouter
|
||||
- incoming queries to the server with TC bit on are replied FORMERR.
|
||||
- interface-automatic replied the wrong source address on localhost
|
||||
queries. Seems to be due to ifnum=0 in recvmsg PKTINFO. Trying
|
||||
to use ifnum=-1 to mean 'no interface, use kernel route'.
|
||||
|
||||
15 January 2008: Wouter
|
||||
- interface-automatic feature. experimental. Nice for anycast.
|
||||
- tpkg test for ip6 ancillary data.
|
||||
- removed debug prints.
|
||||
- porting experience, define for Solaris, test refined for BSD
|
||||
compatibility. The feature probably will not work on OpenBSD.
|
||||
- makedist fixup for ldns-src in build-dir.
|
||||
|
||||
14 January 2008: Wouter
|
||||
- in no debug sets NDEBUG to remove asserts.
|
||||
- configure --enable-debug is needed for dependency generation
|
||||
for assertions and for compiler warnings.
|
||||
- ldns.tgz updated with ldns-trunk (where buffer.h is updated).
|
||||
- fix lint, unit test in optimize mode.
|
||||
- default access control allows ::ffff:127.0.0.1 v6mapped localhost.
|
||||
|
||||
11 January 2008: Wouter
|
||||
- man page, warning removed.
|
||||
- added text describing the use of stub zones for private zones.
|
||||
- checkconf tests for bad hostnames (IP address), and for doubled
|
||||
interface lines.
|
||||
- memory sizes can be given with 'k', 'Kb', or M or G appended.
|
||||
|
||||
10 January 2008: Wouter
|
||||
- typo in example.conf.
|
||||
- made using ldns-src that is included the package more portable
|
||||
by linking with .lo instead of .o files in the ldns package.
|
||||
- nicer do-ip6: yes/no documentation.
|
||||
- nicer linking of libevent .o files.
|
||||
- man pages render correctly on solaris.
|
||||
|
||||
9 January 2008: Wouter
|
||||
- fixup openssl RAND problem, when the system is not configured to
|
||||
give entropy, and the rng needs to be seeded.
|
||||
|
||||
8 January 2008: Wouter
|
||||
- print median and quartiles with extensive logging.
|
||||
|
||||
4 January 2008: Wouter
|
||||
- document misconfiguration in private network.
|
||||
|
||||
2 January 2008: Wouter
|
||||
- fixup typo in requirements.
|
||||
- document that 'refused' is a better choice than 'drop' for
|
||||
the access control list, as refused will stop retries.
|
||||
|
||||
7 December 2007: Wouter
|
||||
- unbound-host has a -d option to show what happens. This can help
|
||||
with debugging (why do I get this answer).
|
||||
- fixup CNAME handling, on nodata, sets and display canonname.
|
||||
- dot removed from CNAME display.
|
||||
- respect -v for NXDOMAINs.
|
||||
- updated ldns-src.tar.gz with ldns-trunk today (1.2.2 fixes).
|
||||
- size_t to int for portability of the header file.
|
||||
- fixup bogus handling.
|
||||
- dependencies and lint for unbound-host.
|
||||
|
||||
6 December 2007: Wouter
|
||||
- library resolution works in foreground mode, unbound-host app
|
||||
receives data.
|
||||
- unbound-host prints rdata using ldns.
|
||||
- unbound-host accepts trust anchors, and prints validation
|
||||
information when you give -v.
|
||||
|
||||
5 December 2007: Wouter
|
||||
- locking in context_new() inside the function.
|
||||
- setup of libworker.
|
||||
|
||||
4 December 2007: Wouter
|
||||
- minor Makefile fixup.
|
||||
- moved module-stack code out of daemon/daemon into services/modstack,
|
||||
preparing for code-reuse.
|
||||
- move context into own header file.
|
||||
- context query structure.
|
||||
- removed unused variable pwd from checkconf.
|
||||
- removed unused assignment from outside netw.
|
||||
- check timeval length of string.
|
||||
- fixup error in val_utils getsigner.
|
||||
- fixup same (*var) error in netblocktostr.
|
||||
- fixup memleak on parse error in localzone.
|
||||
- fixup memleak on packet parse error.
|
||||
- put ; after union in parser.y.
|
||||
- small hardening in iter_operate against iq==NULL.
|
||||
- hardening, if error reply with rcode=0 (noerror) send servfail.
|
||||
- fixup same (*var) error in find_rrset in msgparse, was harmless.
|
||||
- check return value of evtimer_add().
|
||||
- fixup lockorder in lruhash_reclaim(), building up a list of locked
|
||||
entries one at a time. Instead they are removed and unlocked.
|
||||
- fptr_wlist for markdelfunc.
|
||||
- removed is_locked param from lruhash delkeyfunc.
|
||||
- moved bin_unlock during bin_split purely to please.
|
||||
|
||||
3 December 2007: Wouter
|
||||
- changed checkconf/ to smallapp/ to make room for more support tools.
|
||||
(such as unbound-host).
|
||||
- install dirs created with -m 755 because they need to be accessible.
|
||||
- library extensive featurelist added to TODO.
|
||||
- please doxygen, lint.
|
||||
- library test application, with basic functionality.
|
||||
- fix for building in a subdirectory.
|
||||
- link lib fix for Leopard.
|
||||
|
||||
30 November 2007: Wouter
|
||||
- makefile that creates libunbound.la, basic file or libunbound.a
|
||||
when creating static executables (no libtool).
|
||||
- more API setup.
|
||||
|
||||
29 November 2007: Wouter
|
||||
- 0.9 public API start.
|
||||
|
||||
28 November 2007: Wouter
|
||||
- Changeup plan for 0.8 - no complication needed, a simple solution
|
||||
has been chosen for authoritative features.
|
||||
- you can use single quotes in the config file, so it is possible
|
||||
to specify TXT records in local data.
|
||||
- fixup small memory problem in implicit transparent zone creation.
|
||||
- test for implicit zone creation and multiple RR RRsets local data.
|
||||
- local-zone nodefault test.
|
||||
- show testbound testlist on commit.
|
||||
- iterator normalizer changes CNAME chains ending in NXDOMAIN where
|
||||
the packet got rcode NXDOMAIN into rcode NOERROR. (since the initial
|
||||
domain exists).
|
||||
- nicer verbosity: 0 and 1 levels.
|
||||
- lower nonRDquery chance of eliciting wrongly typed validation
|
||||
requiring message from the cache.
|
||||
- fix for nonRDquery validation typing; nodata is detected when
|
||||
SOA record in auth section (all validation-requiring nodata messages
|
||||
have a SOA record in authority, so this is OK for the validator),
|
||||
and NS record is needed to be a referral.
|
||||
- duplicate checking when adding NSECs for a CNAME, and test.
|
||||
- created svn tag 0.8, after completing testbed tests.
|
||||
|
||||
27 November 2007: Wouter
|
||||
- per suggestion in rfc2308, replaced default max-ttl value with 1 day.
|
||||
- set size of msgparse lookup table to 32, from 1024, so that its size
|
||||
is below the 2048 regional large size threshold, and does not cause
|
||||
a call to malloc when a message is parsed.
|
||||
- update of memstats tool to print number of allocation calls.
|
||||
This is what is taking time (not space) and indicates the avg size
|
||||
of the allocations as well. region_alloc stat is removed.
|
||||
|
||||
22 November 2007: Wouter
|
||||
- noted EDNS in-the-middle dropping trouble as a TODO.
|
||||
At this point theoretical, no user trouble has been reported.
|
||||
- added all default AS112 zones.
|
||||
- answers from local zone content.
|
||||
* positive answer, the rrset in question
|
||||
* nodata answer (exist, but not that type).
|
||||
* nxdomain answer (domain does not exist).
|
||||
* empty-nonterminal answer.
|
||||
* But not: wildcard, nsec, referral, rrsig, cname/dname,
|
||||
or additional section processing, NS put in auth.
|
||||
- test for correct working of static and transparent and couple
|
||||
of important defaults (localhost, as112, reverses).
|
||||
Also checks deny and refuse settings.
|
||||
- fixup implicit zone generation and AA bit for NXDOMAIN on localdata.
|
||||
|
||||
21 November 2007: Wouter
|
||||
- local zone internal data setup.
|
||||
|
||||
20 November 2007: Wouter
|
||||
- 0.8 - str2list config support for double string config options.
|
||||
- local-zone and local-data options, config storage and documentation.
|
||||
|
||||
19 November 2007: Wouter
|
||||
- do not downcase NSEC and RRSIG for verification. Follows
|
||||
draft-ietf-dnsext-dnssec-bis-updates-06.txt.
|
||||
- fixup leaking unbound daemons at end of tests.
|
||||
- README file updated.
|
||||
- nice libevent not found error.
|
||||
- README talks about gnu make.
|
||||
- 0.8: unit test for addr_mask and fixups for it.
|
||||
and unit test for addr_in_common().
|
||||
- 0.8: access-control config file element.
|
||||
and unit test rpl replay file.
|
||||
- 0.8: fixup address reporting from netevent.
|
||||
|
||||
16 November 2007: Wouter
|
||||
- privilege separation is not needed in unbound at this time.
|
||||
TODO item marked as such.
|
||||
- created beta-0.7 branch for support.
|
||||
- tagged 0.7 for beta release.
|
||||
- moved trunk to 0.8 for 0.8(auth features) development.
|
||||
- 0.8: access control list setup.
|
||||
|
||||
15 November 2007: Wouter
|
||||
- review fixups from Jelte.
|
||||
|
||||
14 November 2007: Wouter
|
||||
- testbed script does not recreate configure, since its in svn now.
|
||||
- fixup checkconf test so that it does not test
|
||||
/etc/unbound/unbound.conf.
|
||||
- tag 0.6.
|
||||
|
||||
13 November 2007: Wouter
|
||||
- remove debug print.
|
||||
- fixup testbound exit when LIBEVENT_SIGNAL_PROBLEM exists.
|
||||
|
||||
12 November 2007: Wouter
|
||||
- fixup signal handling where SIGTERM could be ignored if a SIGHUP
|
||||
arrives later on.
|
||||
- bugreports to unbound-bugs@nlnetlabs.nl
|
||||
- fixup testbound so it exits cleanly.
|
||||
- cleanup the caches on a reload, so that rrsetID numbers won't clash.
|
||||
|
||||
9 November 2007: Wouter
|
||||
- took ldns snapshot in repo.
|
||||
- default config file is /etc/unbound/unbound.conf.
|
||||
If it doesn't exist, it is installed with the doc/example.conf file.
|
||||
The file is not deleted on uninstall.
|
||||
- default listening is not all, but localhost interfaces.
|
||||
|
||||
8 November 2007: Wouter
|
||||
- Fixup chroot and drop user privileges.
|
||||
- new L root ip address in default hints.
|
||||
|
||||
1 November 2007: Wouter
|
||||
- Fixup of crash on reload, due to anchors in env not NULLed after
|
||||
dealloc during deinit.
|
||||
- Fixup of chroot call. Happens after privileges are dropped, so
|
||||
that checking the passwd entry still works.
|
||||
- minor touch up of clear() hashtable function.
|
||||
- VERB_DETAIL prints out what chdir, username, chroot is being done.
|
||||
- when id numbers run out, caches are cleared, as in design notes.
|
||||
Tested with a mock setup with very few bits in id, it worked.
|
||||
- harden-dnssec-stripped: yes is now default. It insists on dnssec
|
||||
data for trust anchors. Included tests for the feature.
|
||||
|
||||
31 October 2007: Wouter
|
||||
- cache-max-ttl config option.
|
||||
- building outside sourcedir works again.
|
||||
- defaults more secure:
|
||||
username: "unbound"
|
||||
chroot: "/etc/unbound"
|
||||
The operator can override them to be less secure ("") if necessary.
|
||||
- fix horrible oversight in sorting rrset references in a message,
|
||||
sort per reference key pointer, not on referencepointer itself.
|
||||
- pidfile: "/etc/unbound/unbound.pid" is now the default.
|
||||
- tests changed to reflect the updated default.
|
||||
- created hashtable clear() function that respects locks.
|
||||
|
||||
30 October 2007: Wouter
|
||||
- fixup assertion failure that relied on compressed names to be
|
||||
smaller than uncompressed names. A packet from comrite.com was seen
|
||||
to be compressed to a larger size. Added it as unit test.
|
||||
- quieter logging at low verbosity level for common tcp messages.
|
||||
- no greedy TTL update.
|
||||
|
||||
23 October 2007: Wouter
|
||||
- fixup (grand-)parent problem for dnssec-lameness detection.
|
||||
- fixup tests to do additional section processing for lame replies,
|
||||
since the detection needs that.
|
||||
- no longer trust in query section in reply during dnssec lame detect.
|
||||
- dnssec lameness does not make the server never ever queried, but
|
||||
non-preferred. If no other servers exist or answer, the dnssec lame
|
||||
server is used; the fastest dnssec lame server is chosen.
|
||||
- added test then when trust anchor cannot be primed (nodata), the
|
||||
insecure mode from unbound works.
|
||||
- Fixup max queries per thread, any more are dropped.
|
||||
|
||||
22 October 2007: Wouter
|
||||
- added donotquerylocalhost config option. Can be turned off for
|
||||
out test cases.
|
||||
- ISO C compat changes.
|
||||
- detect RA-no-AA lameness, as LAME.
|
||||
- DNSSEC-lameness detection, as LAME.
|
||||
See notes in requirements.txt for choices made.
|
||||
- tests for lameness detection.
|
||||
- added all to make test target; need unbound for fwd tests.
|
||||
- testbound does not pollute /etc/unbound.
|
||||
|
||||
19 October 2007: Wouter
|
||||
- added configure (and its files) to svn, so that the trunk is easier
|
||||
to use. ./configure, config.guess, config.sub, ltmain.sh,
|
||||
and config.h.in.
|
||||
- added yacc/lex generated files, util/configlexer.c,
|
||||
util/configparser.c util/configparser.h, to svn.
|
||||
- without lex no attempt to use it.
|
||||
- unsecure response validation collated into one block.
|
||||
- remove warning about const cast of cfgfile name.
|
||||
- outgoing-interfaces can be different from service interfaces.
|
||||
- ldns-src configure is done during unbound configure and
|
||||
ldns-src make is done during unbound make, and so inherits the
|
||||
make arguments from the unbound make invocation.
|
||||
- nicer error when libevent problem causes instant exit on signal.
|
||||
- read root hints from a root hint file (like BIND does).
|
||||
|
||||
18 October 2007: Wouter
|
||||
- addresses are logged with errors.
|
||||
- fixup testcode fake event to remove pending before callback
|
||||
since the callback may create new pending items.
|
||||
- tests updated because retries are now in iterator module.
|
||||
- ldns-testpkts code is checked for differences between unbound
|
||||
and ldns by makedist.sh.
|
||||
- ldns trunk from today added in svn repo for fallback in case
|
||||
no ldns is installed on the system.
|
||||
make download_ldns refreshes the tarball with ldns svn trunk.
|
||||
- ldns-src.tar.gz is used if no ldns is found on the system, and
|
||||
statically linked into unbound.
|
||||
- start of regional allocator code.
|
||||
- regional uses less memory and variables, simplified code.
|
||||
- remove of region-allocator.
|
||||
- alloc cache keeps a cache of recently released regional blocks,
|
||||
up to a maximum.
|
||||
- make unit test cleanly free memory.
|
||||
|
||||
17 October 2007: Wouter
|
||||
- fixup another cycle detect and ns-addr timeout resolution bug.
|
||||
This time by refusing delegations from the cache without addresses
|
||||
when resolving a mandatory-glue nameserver-address for that zone.
|
||||
We're going to have to ask a TLD server anyway; might as well be
|
||||
the TLD server for this name. And this resolves a lot of cases where
|
||||
the other nameserver names lead to cycles or are not available.
|
||||
- changed random generator from random(3) clone to arc4random wrapped
|
||||
for thread safety. The random generator is initialised with
|
||||
entropy from the system.
|
||||
- fix crash where failure to prime DNSKEY tried to print null pointer
|
||||
in the log message.
|
||||
- removed some debug prints, only verb_algo (4) enables them.
|
||||
- fixup test; new random generator took new paths; such as one
|
||||
where no scripted answer was available.
|
||||
- mark insecure RRs as insecure.
|
||||
- fixup removal of nonsecure items from the additional.
|
||||
- reduced timeout values to more realistic, 376 msec (262 msec has
|
||||
90% of roundtrip times, 512 msec has 99% of roundtrip times.)
|
||||
- server selection failover to next server after timeout (376 msec).
|
||||
|
||||
16 October 2007: Wouter
|
||||
- no malloc in log_hex.
|
||||
- assertions around system calls.
|
||||
- protect against gethostname without ending zero.
|
||||
- ntop output is null terminated by unbound.
|
||||
- pidfile content null termination
|
||||
- various snprintf use sizeof(stringbuf) instead of fixed constant.
|
||||
- changed loopdetect % 8 with & 0x7 since % can become negative for
|
||||
weird negative input and particular interpretation of integer math.
|
||||
- dname_pkt_copy checks length of result, to protect result buffers.
|
||||
prints an error, this should not happen. Bad strings should have
|
||||
been rejected earlier in the program.
|
||||
- remove a size_t underflow from msgreply size func.
|
||||
|
||||
15 October 2007: Wouter
|
||||
- nicer warning.
|
||||
- fix IP6 TCP, wrong definition check. With test package.
|
||||
- fixup the fact that the query section was not compressed to,
|
||||
the code was there but was called by value instead of by reference.
|
||||
And test for the case, uses xxd and nc.
|
||||
- more portable ip6 check for sockaddr types.
|
||||
|
||||
8 October 2007: Wouter
|
||||
- --disable-rpath option in configure for 64bit systems with
|
||||
several dynamic lib dirs.
|
||||
|
||||
7 October 2007: Wouter
|
||||
- fixup tests for no AD bit in non-DO queries.
|
||||
- test that makes sure AD bit is not set on non-DO query.
|
||||
|
||||
6 October 2007: Wouter
|
||||
- removed logfile open early. It did not have the proper permissions;
|
||||
it was opened as root instead of the user. And we cannot change user
|
||||
id yet, since chroot and bind ports need to be done.
|
||||
- callback checks for event callbacks done from mini_event. Because
|
||||
of deletions cannot do this from netevent. This means when using
|
||||
libevent the protection does not work on event-callbacks.
|
||||
- fixup too small reply (did not zero counts).
|
||||
- fixup reply no longer AD bit when query without DO bit.
|
||||
|
||||
5 October 2007: Wouter
|
||||
- function pointer whitelist.
|
||||
|
||||
4 October 2007: Wouter
|
||||
- overwrite sensitive random seed value after use.
|
||||
- switch to logfile very soon if not -d (console attached).
|
||||
- error messages do not reveal the trustanchor contents.
|
||||
- start work on function pointer whitelists.
|
||||
|
||||
3 October 2007: Wouter
|
||||
- fix for multiple empty nonterminals, after multiple DSes in the
|
||||
chain of trust.
|
||||
- mesh checks if modules are looping, and stops them.
|
||||
- refetch with CNAMEd nameserver address regression test added.
|
||||
- fixup line count bug in testcode, so testbound prints correct line
|
||||
number with parse errors.
|
||||
- unit test for multiple ENT case.
|
||||
- fix for cname out of validated unsec zone.
|
||||
- fixup nasty id=0 reuse. Also added assertions to detect its
|
||||
return (the assertion catches in the existing test cases).
|
||||
|
||||
1 October 2007: Wouter
|
||||
- skip F77, CXX, objC tests in configure step.
|
||||
- fixup crash in refetch glue after a CNAME.
|
||||
and protection against similar failures (with error print).
|
||||
|
||||
28 September 2007: Wouter
|
||||
- test case for unbound-checkconf, fixed so it also checks the
|
||||
interface: statements.
|
||||
|
||||
26 September 2007: Wouter
|
||||
- SIGHUP will reopen the log file.
|
||||
- Option to log to syslog.
|
||||
- please lint, fixup tests (that went to syslog on open, oops).
|
||||
- config check program.
|
||||
|
||||
25 September 2007: Wouter
|
||||
- tests for NSEC3. Fixup bitmap checks for NSEC3.
|
||||
- positive ANY response needs to check if wildcard expansion, and
|
||||
check that original data did not exist.
|
||||
- tests for NSEC3 that wrong use of OPTOUT is bad. For insecure
|
||||
delegation, for abuse of child zone apex nsec3.
|
||||
- create 0.5 release tag.
|
||||
|
||||
24 September 2007: Wouter
|
||||
- do not make test programs by default.
|
||||
|
||||
+26
-4
@@ -9,7 +9,7 @@ This software is under BSD license, see LICENSE for details.
|
||||
or get a beta version from the svn repository at
|
||||
http://unbound.net/svn/
|
||||
|
||||
* Needs the following libraries
|
||||
* Uses the following libraries;
|
||||
* ldns http://www.nlnetlabs.nl/ldns/ (BSD license)
|
||||
* libevent http://www.monkey.org/~provos/libevent/ (BSD license)
|
||||
|
||||
@@ -18,13 +18,21 @@ This software is under BSD license, see LICENSE for details.
|
||||
* autoreconf (autoheader && autoconf), if ./configure is missing.
|
||||
|
||||
* Make and install: ./configure; make; make install
|
||||
* Use GNU make; default on linux, often called 'gmake' on BSD and Solaris.
|
||||
* --with-ldns=/path/to/ldns
|
||||
If ldns is not detected on the system, a prepackaged tarball
|
||||
of the ldns library is used to compile and statically link against.
|
||||
If detected on the system, it will dynamically link against it.
|
||||
* --with-libevent=/path/to/libevent
|
||||
Can be set to either the system install or the build directory.
|
||||
--with-libevent=no gives a builtin alternative implementation.
|
||||
libevent is useful when having many (thousands) of outgoing ports.
|
||||
This improves randomization and spoof resistance. For the default
|
||||
of 16 ports the builtin alternative works well.
|
||||
* --without-pthreads
|
||||
This disables pthreads, and uses Solaris thr library or no threading.
|
||||
Without this option the pthreads library is detected automatically.
|
||||
This disables pthreads. Without this option the pthreads library
|
||||
is detected automatically. Use this option to disable threading
|
||||
altogether, or, on Solaris, also use --with(out)-solaris-threads.
|
||||
* --enable-static-exe
|
||||
This enables a debug option to statically link, against ldns and
|
||||
libevent libraries.
|
||||
@@ -46,6 +54,20 @@ o If libevent is older (before 1.3c), unbound will exit instead of reload
|
||||
on sighup. On a restart 'did not exit gracefully last time' warning is
|
||||
printed. Perform ./configure --with-libevent=no or update libevent, rerun
|
||||
configure and recompile unbound to make sighup work correctly.
|
||||
It is strongly suggested to use the latest version of libevent (1.4 or more)
|
||||
on Solaris, because of fixes in the solaris event port code in libevent.
|
||||
o If you receive no answers deploying unbound on a private network.
|
||||
Check that the zone you configure as a stub zone is correct, listing working
|
||||
ip-addresses. Check that the NS data in the zone, those hostnames, are
|
||||
in fact those same, working, ip-addresses. Unbound will fetch the NS data
|
||||
from the zone and use that information in preference to the config
|
||||
information.
|
||||
o If you are not receiving the correct source IP address on replies (e.g.
|
||||
you are running a multihomed, anycast server), the interface-automatic
|
||||
option can be enabled to set socket options to achieve the correct
|
||||
source IP address on UDP replies. Listing all IP addresses explicitly in
|
||||
the config file is an alternative. The interface-automatic option uses
|
||||
non portable socket options, Linux and FreeBSD should work fine.
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
@@ -56,4 +78,4 @@ o Other code origins are from the NSD (NLnet Labs) and LDNS (NLnet Labs)
|
||||
projects. Such as buffer, region-allocator and red-black tree code.
|
||||
o See Credits file for contributors.
|
||||
|
||||
* mailto:wouter@nlnetlabs.nl
|
||||
* mailto:unbound-bugs@nlnetlabs.nl
|
||||
|
||||
+5
-2
@@ -1,6 +1,9 @@
|
||||
README unbound tests
|
||||
|
||||
There is a test setup for unbound.
|
||||
There is a test setup for unbound. Use
|
||||
make test
|
||||
To make and run the tests. The results are summarized at the end.
|
||||
You can also run ./unittest by hand, if the system lacks other debug tools.
|
||||
|
||||
testdata/ contains the data for tests.
|
||||
testcode/ contains scripts and c code for the tests.
|
||||
@@ -8,4 +11,4 @@ testcode/ contains scripts and c code for the tests.
|
||||
do-tests.sh : runs all the tests in the testdata directory.
|
||||
testbed.sh : compiles on a set of (user specific) hosts and runs do-tests.
|
||||
|
||||
Tests are run using tpkg.
|
||||
Tests are run using testcode/mini_tpkg.sh.
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
TODO items.
|
||||
o use real entropy to make random (ID, port) numbers more random.
|
||||
o in production mode, do not free memory on exit. In debug mode, test leaks.
|
||||
o profile memory allocation, and if performance issues, use special memory
|
||||
allocator. For example, with caches per thread.
|
||||
o #define BIT_... different on bigendian and smallendian systems so that
|
||||
the htons on flags is not needed to send a message from the cache.
|
||||
o speed up pkt domain name decompression loop detection using counter perhaps.
|
||||
@@ -11,45 +7,51 @@ o detect OS/400 pthreads implementation that allows upgrading to writelock
|
||||
o understand synthesized DNAMEs, so those TTL=0 packets are cached properly.
|
||||
o understand NSEC/NSEC3, aggressive negative caching, so that updates to
|
||||
NSEC/NSEC3 will result in proper negative responses.
|
||||
o fallback without EDNS if result is NOTIMPL, now only on FORMERR like in java.
|
||||
o scrubber has slow pkt_subdomain and pkt_strict_subdomain functions.
|
||||
o get serverselection algorithm out of local optimum.
|
||||
make subtargets to get rtt info for a couple of targets, like fetch-policy.
|
||||
or send out multiple queries to multiple servers.
|
||||
o donotqueryaddresses allow specification of subnets, use trie to store.
|
||||
extend default list to contain illegal ip4 and ip6 addresses.
|
||||
o memory profile; and if needed put serviced queries under qstate->region
|
||||
and special purpose region code, reuse blocks, shrink if too big.
|
||||
o check query, option to enforce presence of qdsection in noerror answers.
|
||||
o configuration option where port 53 is used for send and receive, no other
|
||||
ports are used.
|
||||
o prime sequence in multiple queries, if glue missing from prime sequence.
|
||||
o (option) to not send replies to clients after a timeout of (say 5 secs) has
|
||||
passed, but keep task active for later retries by client.
|
||||
o private TTL feature
|
||||
o pretend-dnssec-unaware, and pretend-edns-unaware modes for debug/workshops.
|
||||
o delegpt use rbtree for ns-list, to avoid slowdown for very large NS sets.
|
||||
o be able to have different listen and query-to addresses to bind to,
|
||||
so you can listen to localhost and query-to to the internet.
|
||||
o reprime and refresh oft used data before timeout.
|
||||
o retain prime results in a overlaid roothints file.
|
||||
o store primed key data in a overlaid keyhints file (sort of like drafttimers).
|
||||
o windows version, auto update feature, a query to check for the version.
|
||||
o autoreport of problems
|
||||
o logrotation, syslog
|
||||
o command the server with TSIG inband. get-config, clearcache,
|
||||
get stats, get memstats, get ..., reload, clear one zone from cache
|
||||
o watch for spoof nearmisses.
|
||||
o watch for spoof nearmisses. Keep counter of nearmisses and print that
|
||||
in the stats lines, operator can determine what level is a redalert.
|
||||
o improve compression of DNS packets by first puttig uncompressible rrs, then
|
||||
compress to their rdata.
|
||||
o if one server is not responsive do not spend 75 secs on that server, but
|
||||
try other servers with lower rtt.
|
||||
o NSID rfc 5001 support.
|
||||
o timers rfc 5011 support.
|
||||
o Treat YXDOMAIN from a DNAME properly, in iterator (not throwaway), validator.
|
||||
o grab ports nonconsequtive and change the set after a while (change within
|
||||
a given range). Could be bad for OS if wrong port. unsure if it helps secure.
|
||||
o workaround for nxdomain responses for ENT DS queries. Not look at rcode and
|
||||
look at valid empty nonterminal proof that is inside the packet.
|
||||
o make timeout backoffs randomized (a couple percent random) to spread traffic.
|
||||
o inspect date on executable, then warn user in log if its more than 1 year.
|
||||
o proactively prime root, stubs and trust anchors, feature.
|
||||
early failure, faster on first query, but more traffic.
|
||||
o use privilege separation, to change privilege options during reload securely
|
||||
not needed.
|
||||
o On Windows use CryptGenRandom() to get random seed for arc4random.
|
||||
o Think about intermediate firewalls dropping EDNS UDP & handling that.
|
||||
detect nonEDNS middlebox by timeout on edns queries, and fallback to
|
||||
nonEDNS when appropriate.
|
||||
o library add convenience functions for A, AAAA, PTR, getaddrinfo, libresolve.
|
||||
o library add function to get signature data (or whole reply message).
|
||||
o library add function to validate input from app that is signed.
|
||||
o add dynamic-update requests (making a dynupd request) to libunbound api.
|
||||
o in an ipv6 connected only environment unbound cannot use outgoing IP6
|
||||
to send to ip4to6 mapped hosts, need ip4to6map of NS and disable
|
||||
V6ONLY socket option.
|
||||
o support multiple dns messages in a TCP query stream for the unbound server.
|
||||
o SIG(0) and TSIG.
|
||||
o support OPT record placement on recv anywhere in the additional section.
|
||||
o add local-file: config with authority features.
|
||||
|
||||
+98
-17
@@ -13,21 +13,38 @@ server:
|
||||
# whitespace is not necessary, but looks cleaner.
|
||||
|
||||
# verbosity number, 0 is least verbose. 1 is default.
|
||||
verbosity: 2
|
||||
|
||||
verbosity: 1
|
||||
|
||||
# print statistics to the log (for every thread) every N seconds.
|
||||
# Set to "" or 0 to disable. Default is disabled.
|
||||
# statistics-interval: 0
|
||||
|
||||
# number of threads to create. 1 disables threading.
|
||||
# num-threads: 1
|
||||
|
||||
# specify the interfaces to answer queries from by ip-address.
|
||||
# If you give none the default (all) interface is used.
|
||||
# The default is to listen to localhost (127.0.0.1 and ::1).
|
||||
# specify 0.0.0.0 and ::0 to bind to all available interfaces.
|
||||
# specify every interface on a new 'interface:' labelled line.
|
||||
# The listen interfaces are not changed on reload, only on restart.
|
||||
# interface: 192.0.2.153
|
||||
# interface: 192.0.2.154
|
||||
# interface: 2001:DB8::5
|
||||
|
||||
# enable this feature to copy the source address of queries to reply.
|
||||
# Socket options not be supported on all platforms. experimental.
|
||||
# interface-automatic: no
|
||||
|
||||
# port to answer queries from
|
||||
# port: 53
|
||||
|
||||
# specify the interfaces to send outgoing queries to authoritative
|
||||
# server from by ip-address. If none, the default (all) interface
|
||||
# is used. Specify every interface on a 'outgoing-interface:' line.
|
||||
# outgoing-interface: 192.0.2.153
|
||||
# outgoing-interface: 2001:DB8::5
|
||||
# outgoing-interface: 2001:DB8::6
|
||||
|
||||
# unbound needs to send packets to authoritative nameservers.
|
||||
# it uses a range of ports for that.
|
||||
# the start number of the port range
|
||||
@@ -50,8 +67,8 @@ server:
|
||||
# msg-buffer-size: 65552
|
||||
|
||||
# the amount of memory to use for the message cache.
|
||||
# in bytes. default is 4 Mb
|
||||
# msg-cache-size: 4194304
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# msg-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the message cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
@@ -62,13 +79,17 @@ server:
|
||||
# num-queries-per-thread: 1024
|
||||
|
||||
# the amount of memory to use for the RRset cache.
|
||||
# in bytes. default is 4 Mb
|
||||
# rrset-cache-size: 4194304
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# rrset-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the RRset cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# rrset-cache-slabs: 4
|
||||
|
||||
# the time to live (TTL) value cap for RRsets and messages in the
|
||||
# cache. Items are not cached for longer. In seconds.
|
||||
# cache-max-ttl: 86400
|
||||
|
||||
# the time to live (TTL) value for cached roundtrip times and
|
||||
# EDNS version information for hosts. In seconds.
|
||||
@@ -86,7 +107,7 @@ server:
|
||||
# infra-cache-numhosts: 10000
|
||||
|
||||
# the maximum size of the lame zones cached per host. in bytes.
|
||||
# infra-cache-lame-size: 10240
|
||||
# infra-cache-lame-size: 10k
|
||||
|
||||
# Enable IPv4, "yes" or "no".
|
||||
# do-ip4: yes
|
||||
@@ -100,23 +121,44 @@ server:
|
||||
# Enable TCP, "yes" or "no".
|
||||
# do-tcp: yes
|
||||
|
||||
# control which clients are allowed to make (recursive) queries
|
||||
# to this server. Specify classless netblocks with /size and action.
|
||||
# By default everything is refused, except for localhost.
|
||||
# Choose deny (drop message), refuse (polite error reply), allow.
|
||||
# access-control: 0.0.0.0/0 refuse
|
||||
# access-control: 127.0.0.0/8 allow
|
||||
# access-control: ::0/0 refuse
|
||||
# access-control: ::1 allow
|
||||
# access-control: ::ffff:127.0.0.1 allow
|
||||
|
||||
# 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.
|
||||
# chroot: "/some/directory"
|
||||
# If you give "" no chroot is performed.
|
||||
# chroot: "/etc/unbound"
|
||||
|
||||
# if given, user privileges are dropped (after binding port),
|
||||
# and the given username is assumed. Default is nothing "".
|
||||
# and the given username is assumed. Default is user "unbound".
|
||||
# If you give "" no privileges are dropped.
|
||||
# username: "unbound"
|
||||
|
||||
# the working directory.
|
||||
# directory: "/etc/unbound"
|
||||
|
||||
# the log file, "" means log to stderr.
|
||||
# the log file, "" means log to stderr.
|
||||
# Use of this option sets use-syslog to "no".
|
||||
# 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.
|
||||
# use-syslog: yes
|
||||
|
||||
# the pid file.
|
||||
# pidfile: "unbound.pid"
|
||||
# pidfile: "/etc/unbound/unbound.pid"
|
||||
|
||||
# file to read root hints from.
|
||||
# get one from ftp://FTP.INTERNIC.NET/domain/named.cache
|
||||
# root-hints: ""
|
||||
|
||||
# enable to not answer id.server and hostname.bind queries.
|
||||
# hide-identity: no
|
||||
@@ -149,12 +191,21 @@ server:
|
||||
# Harden against out of zone rrsets, to avoid spoofing attempts.
|
||||
# harden-glue: yes
|
||||
|
||||
# Harden against receiving dnssec-stripped data. If you turn it
|
||||
# off, failing to validate dnskey data for a trustanchor will
|
||||
# trigger insecure mode for that zone (like without a trustanchor).
|
||||
# Default on, which insists on dnssec data for trust-anchored zones.
|
||||
# harden-dnssec-stripped: yes
|
||||
|
||||
# Do not query the following addresses. No DNS queries are sent there.
|
||||
# List one address per entry. To block other ports than the default
|
||||
# DNS port, use "1.2.3.4@123" to block port 123 for 1.2.3.4.
|
||||
# do-not-query-address: 127.0.0.1
|
||||
# List one address per entry. List classless netblocks with /size,
|
||||
# do-not-query-address: 127.0.0.1/8
|
||||
# do-not-query-address: ::1
|
||||
|
||||
# if yes, the above default do-not-query-address entries are present.
|
||||
# if no, localhost can be queried (for testing and debugging).
|
||||
# do-not-query-localhost: yes
|
||||
|
||||
# module configuration of the server. A string with identifiers
|
||||
# separated by spaces. "iterator" or "validator iterator"
|
||||
# module-config: "validator iterator"
|
||||
@@ -205,14 +256,44 @@ server:
|
||||
# val-nsec3-keysize-iterations: "1024 150 2048 500 4096 2500"
|
||||
|
||||
# the amount of memory to use for the key cache.
|
||||
# in bytes. default is 4 Mb
|
||||
# key-cache-size: 4194304
|
||||
# plain value in bytes or you can append k, m or G. default is "4Mb".
|
||||
# key-cache-size: 4m
|
||||
|
||||
# the number of slabs to use for the key cache.
|
||||
# the number of slabs must be a power of 2.
|
||||
# more slabs reduce lock contention, but fragment memory usage.
|
||||
# key-cache-slabs: 4
|
||||
|
||||
# a number of locally served zones can be configured.
|
||||
# local-zone: <zone> <type>
|
||||
# local-data: "<resource record string>"
|
||||
# o deny serves local data (if any), else, drops queries.
|
||||
# o refuse serves local data (if any), else, replies with error.
|
||||
# o static serves local data, else, nxdomain or nodata answer.
|
||||
# o transparent serves local data, else, resolves normally .
|
||||
# o redirect serves the zone data for any subdomain in the zone.
|
||||
# o nodefault can be used to normally resolve AS112 zones.
|
||||
#
|
||||
# defaults are localhost address, reverse for 127.0.0.1 and ::1
|
||||
# and nxdomain for AS112 zones. If you configure one of these zones
|
||||
# the default content is omitted, or you can omit it with 'nodefault'.
|
||||
#
|
||||
# If you configure local-data without specifying local-zone, by
|
||||
# default a transparent local-zone is created for the data.
|
||||
#
|
||||
# You can add locally served data with
|
||||
# local-zone: "local." static
|
||||
# local-data: "mycomputer.local. IN A 192.0.2.51"
|
||||
# local-data: 'mytext.local TXT "content of text record"'
|
||||
#
|
||||
# You can override certain queries with
|
||||
# local-data: "adserver.example.com A 127.0.0.1"
|
||||
#
|
||||
# You can redirect a domain to a fixed address with
|
||||
# (this makes example.com, www.example.com, etc, all go to 192.0.2.3)
|
||||
# local-zone: "example.com" redirect
|
||||
# local-data: "example.com A 192.0.2.3"
|
||||
|
||||
|
||||
# Stub zones.
|
||||
# Create entries like below, to make all queries for 'example.com' and
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
.TH "libunbound" "3" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" libunbound.3 -- unbound library functions manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B libunbound,
|
||||
.B unbound.h,
|
||||
.B ub_ctx,
|
||||
.B ub_result,
|
||||
.B ub_callback_t,
|
||||
.B ub_ctx_create,
|
||||
.B ub_ctx_delete,
|
||||
.B ub_ctx_set_option,
|
||||
.B ub_ctx_config,
|
||||
.B ub_ctx_set_fwd,
|
||||
.B ub_ctx_resolvconf,
|
||||
.B ub_ctx_hosts,
|
||||
.B ub_ctx_add_ta,
|
||||
.B ub_ctx_add_ta_file,
|
||||
.B ub_ctx_trustedkeys,
|
||||
.B ub_ctx_debugout,
|
||||
.B ub_ctx_debuglevel,
|
||||
.B ub_ctx_async,
|
||||
.B ub_poll,
|
||||
.B ub_wait,
|
||||
.B ub_fd,
|
||||
.B ub_process,
|
||||
.B ub_resolve,
|
||||
.B ub_resolve_async,
|
||||
.B ub_cancel,
|
||||
.B ub_resolve_free,
|
||||
.B ub_strerror
|
||||
\- Unbound DNS validating resolver @version@ functions.
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B #include <unbound.h>
|
||||
.LP
|
||||
\fIstruct ub_ctx *\fR
|
||||
\fBub_ctx_create\fR(\fIvoid\fR);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_ctx_delete\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_option\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR opt, \fIchar*\fR val);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_config\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_set_fwd\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR addr);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_resolvconf\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_hosts\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR ta);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_add_ta_file\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_trustedkeys\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR fname);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debugout\fR(\fIstruct ub_ctx*\fR ctx, \fIFILE*\fR out);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_debuglevel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR d);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_ctx_async\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR dothread);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_poll\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_wait\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_fd\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_process\fR(\fIstruct ub_ctx*\fR ctx);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIint*\fR secure,
|
||||
.br
|
||||
\fIint*\fR data, \fIstruct ub_result**\fR result);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_resolve_async\fR(\fIstruct ub_ctx*\fR ctx, \fIchar*\fR name,
|
||||
.br
|
||||
\fIint\fR rrtype, \fIint\fR rrclass, \fIvoid*\fR mydata,
|
||||
.br
|
||||
\fIub_callback_t\fR callback, \fIint*\fR async_id);
|
||||
.LP
|
||||
\fIint\fR
|
||||
\fBub_cancel\fR(\fIstruct ub_ctx*\fR ctx, \fIint\fR async_id);
|
||||
.LP
|
||||
\fIvoid\fR
|
||||
\fBub_resolve_free\fR(\fIstruct ub_result*\fR result);
|
||||
.LP
|
||||
\fIconst char *\fR
|
||||
\fBub_strerror\fR(\fIint\fR err);
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound
|
||||
is an implementation of a DNS resolver, that does caching and
|
||||
DNSSEC validation. This is the library API, for using the \-lunbound library.
|
||||
The server daemon is described in \fIunbound\fR(8).
|
||||
The library can be used to convert hostnames to ip addresses, and back,
|
||||
and obtain other information from the DNS. The library performs public\-key
|
||||
validation of results with DNSSEC.
|
||||
.P
|
||||
The library uses a variable of type \fIstruct ub_ctx\fR to keep context
|
||||
between calls. The user must maintain it, creating it with
|
||||
.B ub_ctx_create
|
||||
and deleting it with
|
||||
.B ub_ctx_delete\fR.
|
||||
It can be created and deleted at any time. Creating it anew removes any
|
||||
previous configuration (such as trusted keys) and clears any cached results.
|
||||
.P
|
||||
The functions are thread\-safe, and a context an be used in a threaded (as
|
||||
well as in a non\-threaded) environment. Also resolution (and validation)
|
||||
can be performed blocking and non\-blocking (also called asynchronous).
|
||||
The async method returns from the call immediately, so that processing
|
||||
can go on, while the results become available later.
|
||||
.P
|
||||
The functions are discussed in turn below.
|
||||
.SH "FUNCTIONS"
|
||||
.TP
|
||||
.B ub_ctx_create
|
||||
Create a new context, initialised with defaults.
|
||||
The information from /etc/resolv.conf and /etc/hosts is not utilised
|
||||
by default. Use
|
||||
.B ub_ctx_resolvconf
|
||||
and
|
||||
.B ub_ctx_hosts
|
||||
to read them.
|
||||
.TP
|
||||
.B ub_ctx_delete
|
||||
Delete validation context and free associated resources.
|
||||
Outstanding async queries are killed and callbacks are not called for them.
|
||||
.TP
|
||||
.B ub_ctx_set_option
|
||||
A power\-user interface that lets you specify one of the options from the
|
||||
config file format, see \fIunbound.conf\fR(5). Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist. Pass the option name with the trailing ':'.
|
||||
.TP
|
||||
.B ub_ctx_config
|
||||
A power\-user interface that lets you specify an unbound config file, see
|
||||
\fIunbound.conf\fR(5), which is read for configuration. Not all options are
|
||||
relevant. For some specific options, such as adding trust anchors, special
|
||||
routines exist.
|
||||
.TP
|
||||
.B ub_ctx_set_fwd
|
||||
Set machine to forward DNS queries to, the caching resolver to use.
|
||||
IP4 or IP6 address. Forwards all DNS requests to that machine, which
|
||||
is expected to run a recursive resolver. If the proxy is not
|
||||
DNSSEC capable, validation may fail. Can be called several times, in
|
||||
that case the addresses are used as backup servers.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_resolvconf
|
||||
Read list of nameservers to use from the filename given.
|
||||
Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
|
||||
If they do not support DNSSEC, validation may fail.
|
||||
Only nameservers are picked up, the searchdomain, ndots and other
|
||||
settings from \fIresolv.conf\fR(5) are ignored.
|
||||
If fname NULL is passed, "/etc/resolv.conf" is used.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_hosts
|
||||
Read list of hosts from the filename given.
|
||||
Usually "/etc/hosts". When queried for, these addresses are not marked
|
||||
DNSSEC secure. If fname NULL is passed, "/etc/hosts" is used.
|
||||
At this time it is only possible to set configuration before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B
|
||||
ub_ctx_add_ta
|
||||
Add a trust anchor to the given context.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
The format is a string, similar to the zone-file format,
|
||||
[domainname] [type] [rdata contents]. Both DS and DNSKEY records are accepted.
|
||||
.TP
|
||||
.B ub_ctx_add_ta_file
|
||||
Add trust anchors to the given context.
|
||||
Pass name of a file with DS and DNSKEY records in zone file format.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_trustedkeys
|
||||
Add trust anchors to the given context.
|
||||
Pass the name of a bind-style config file with trusted-keys{}.
|
||||
At this time it is only possible to add trusted keys before the
|
||||
first resolve is done.
|
||||
.TP
|
||||
.B ub_ctx_debugout
|
||||
Set debug and error log output to the given stream. Pass NULL to disable
|
||||
output. Default is stderr. File-names or using syslog can be enabled
|
||||
using config options, this routine is for using your own stream.
|
||||
.TP
|
||||
.B ub_ctx_debuglevel
|
||||
Set debug verbosity for the context. Output is directed to stderr.
|
||||
Higher debug level gives more output.
|
||||
.TP
|
||||
.B ub_ctx_async
|
||||
Set a context behaviour for asynchronous action.
|
||||
if set to true, enables threading and a call to
|
||||
.B ub_resolve_async
|
||||
creates a thread to handle work in the background.
|
||||
If false, a process is forked to handle work in the background.
|
||||
Changes to this setting after
|
||||
.B ub_resolve_async
|
||||
calls have been made have no effect (delete and re\-create the context
|
||||
to change).
|
||||
.TP
|
||||
.B ub_poll
|
||||
Poll a context to see if it has any new results.
|
||||
Do not poll in a loop, instead extract the fd below to poll for readiness,
|
||||
and then check, or wait using the wait routine.
|
||||
Returns 0 if nothing to read, or nonzero if a result is available.
|
||||
If nonzero, call
|
||||
.B ub_process
|
||||
to do callbacks.
|
||||
.TP
|
||||
.B ub_wait
|
||||
Wait for a context to finish with results. Calls
|
||||
.B ub_process
|
||||
after the wait for you. After the wait, there are no more outstanding
|
||||
asynchronous queries.
|
||||
.TP
|
||||
.B ub_fd
|
||||
Get file descriptor. Wait for it to become readable, at this point
|
||||
answers are returned from the asynchronous validating resolver.
|
||||
Then call the \fBub_process\fR to continue processing.
|
||||
.TP
|
||||
.B ub_process
|
||||
Call this routine to continue processing results from the validating
|
||||
resolver (when the fd becomes readable).
|
||||
Will perform necessary callbacks.
|
||||
.TP
|
||||
.B ub_resolve
|
||||
Perform resolution and validation of the target name.
|
||||
The name is a domain name in a zero terminated text string.
|
||||
The rrtype and rrclass are DNS type and class codes.
|
||||
The value secure returns true if the answer validated securely.
|
||||
The value data returns true if there was data.
|
||||
The result structure is newly allocated with the resulting data.
|
||||
.TP
|
||||
.B ub_resolve_async
|
||||
Perform asynchronous resolution and validation of the target name.
|
||||
Arguments mean the same as for \fBub_resolve\fR except no
|
||||
data is returned immediately, instead a callback is called later.
|
||||
The callback receives a copy of the mydata pointer, that you can use to pass
|
||||
information to the callback. The callback type is a function pointer to
|
||||
a function declared as
|
||||
.IP
|
||||
void my_callback_function(void* my_arg, int err,
|
||||
.br
|
||||
struct ub_result* result);
|
||||
.IP
|
||||
The async_id is returned so you can (at your option) decide to track it
|
||||
and cancel the request if needed.
|
||||
.TP
|
||||
.B ub_cancel
|
||||
Cancel an async query in progress.
|
||||
.TP
|
||||
.B ub_resolve_free
|
||||
Free struct ub_result contents after use.
|
||||
.TP
|
||||
.B ub_strerror
|
||||
Convert error value from one of the unbound library functions
|
||||
to a human readable string.
|
||||
.SH "RESULT DATA STRUCTURE"
|
||||
.LP
|
||||
The result of the DNS resolution and validation is returned as
|
||||
\fIstruct ub_result\fR. The result structure contains the following entries.
|
||||
.P
|
||||
.nf
|
||||
struct ub_result {
|
||||
char* qname; /* text string, original question */
|
||||
int qtype; /* type code asked for */
|
||||
int qclass; /* class code asked for */
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
};
|
||||
.fi
|
||||
.P
|
||||
If both secure and bogus are false, security was not enabled for the
|
||||
domain of the query.
|
||||
.SH "RETURN VALUES"
|
||||
Many routines return an error code. The value 0 (zero) denotes no error
|
||||
happened. Other values can be passed to
|
||||
.B ub_strerror
|
||||
to obtain a readable error string.
|
||||
.B ub_strerror
|
||||
returns a zero terminated string.
|
||||
.B ub_ctx_create
|
||||
returns NULL on an error (a malloc failure).
|
||||
.B ub_poll
|
||||
returns true if some information may be available, false otherwise.
|
||||
.B ub_fd
|
||||
returns a file descriptor or -1 on error.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
||||
@@ -153,7 +153,8 @@ Styleguide:
|
||||
*** Bigger and Better
|
||||
* Config file syntax checker program. Tests on checker.
|
||||
* Logging first class feature with config options.
|
||||
* with logfile turnover to avoid Gbs of logs.
|
||||
X with logfile turnover to avoid Gbs of logs.
|
||||
* use syslog optional.
|
||||
* donotqueryaddresses with trie for blocking entire netblocks.
|
||||
* Memory overhaul, special allocators for hashtable caches, and mesh qstates.
|
||||
* keep a preallocated list of region-chunks per worker thread.
|
||||
@@ -162,14 +163,15 @@ Styleguide:
|
||||
to avoid name-collision with nsd regions, 'regional'.
|
||||
* read root hints from file.
|
||||
* failover to next server in 1 second, instead of 100 seconds on one server.
|
||||
* failure to return answer, w. reason (donotq, noanswer servers, cannot
|
||||
X failure to return answer, w. reason (donotq, noanswer servers, cannot
|
||||
find servers, validationfail w.classification, error),
|
||||
with threadno, starttime and endtime and qname/type/class, prime/qflags,
|
||||
from-clients, from-internal, has-subrequests, a nice error report,
|
||||
so that an excerpt from those times can be made from the logs.
|
||||
logfileparsing tool that makes these excerpts and emails them.
|
||||
Not done; user can change verbosity and kill -HUP.
|
||||
* clear cache as a callback from the new-rrset-id routine.
|
||||
* make overload mode work; phase 0 all ok, phase 1 some threads close ports,
|
||||
X make overload mode work; phase 0 all ok, phase 1 some threads close ports,
|
||||
to let other threads pick up work. phase 2, all threads closed, so all open
|
||||
the ports again and drop all non-cache-reply queries.
|
||||
Keep mutexed num-overloaded-threads counter. thread incs it when it hits
|
||||
@@ -179,8 +181,10 @@ Styleguide:
|
||||
if phase 1, start servicing, phase is 0 again. Make robust against delays.
|
||||
readme: max about 1 second worth of incoming queries, 10k perhaps,
|
||||
or 1/number of seconds it takes start up of 10k.
|
||||
* should the source include a copy of the ldns lib for ease of building by
|
||||
new users.
|
||||
Not done. Implement drop when full.
|
||||
* the source includes a copy of the ldns lib for ease of building by
|
||||
new users. Detect system installed ldns, if installed ldns is OK; use
|
||||
dynamic linking against it, otherwise static linking against packaged ldns.
|
||||
* no greedy TTL algo (and test).
|
||||
* maximum TTL, cap incoming values, and config option.
|
||||
|
||||
@@ -199,14 +203,18 @@ Styleguide:
|
||||
can be used to block AS112 traffic, option to unblock a zone.
|
||||
* after checking acl, do iter: static, blacklist, forwards, recurse.
|
||||
* Forward-local-zone to NSD.
|
||||
- include in package, autoforkexec on localhost to do so.
|
||||
- in package, autoforkexec on localhost to do so.
|
||||
- not included. Not necessary for localhost and AS112 service.
|
||||
* forward local zone to remote server.
|
||||
- not included. Not necessary for localhost and AS112 service.
|
||||
* stub zones - send queries for a zone to configged nameserver.
|
||||
- Can be used for complicated setups. So, run auth server on a
|
||||
different port or pc, and stub it on the resolver. Resolver is
|
||||
not auth for zones, but resolution works. This enforces the split
|
||||
of recursive and auth servers.
|
||||
* test local zones
|
||||
* for speed
|
||||
* for correctness on corner cases
|
||||
* for validation
|
||||
* in case you get data on localzone in an answer (from rootserver).
|
||||
|
||||
*** Library use
|
||||
* Create library that can do:
|
||||
@@ -236,15 +244,14 @@ Styleguide:
|
||||
*** Features features
|
||||
* aggressive negative caching for NSEC, NSEC3.
|
||||
* multiple queries per question, server exploration, server selection.
|
||||
* option to use real entropy for randomness (mix it in once in a while).
|
||||
* check query, enforce qdsection, checking for forgery-resilience.
|
||||
* NSID support.
|
||||
* support TSIG on queries, for validating resolver deployment.
|
||||
* Be able to prime roots using several queries (like, get only NS first).
|
||||
* Nicer statistics
|
||||
* private TTL, dTLS features.
|
||||
* retry-mode, where a bogus result triggers a retry-mode query, where a list
|
||||
of responses over a time interval is collected, and each is validated.
|
||||
or try in TCP mode. Do not 'try all servers several times', since we must
|
||||
not create packet storms with operator errors.
|
||||
* draft-timers, DLV features.
|
||||
|
||||
treeshrew/
|
||||
@@ -302,10 +309,10 @@ treeshrew/
|
||||
unbound.c for validating caching recursive dns server.
|
||||
scheduler.c for the modules.
|
||||
|
||||
libunbound-all/
|
||||
libunbound/
|
||||
app linkable. Can be configged to do whatever,
|
||||
validator, iterator, validating iterator, forwarding stub.
|
||||
libunbound-fwd/
|
||||
libforwardbound/
|
||||
app linkable forwarding stub. Small lib.
|
||||
|
||||
ask_cachor/ *.c *.h
|
||||
|
||||
+86
-1
@@ -34,7 +34,7 @@ then interface with the modules to perform the necessary processing.
|
||||
|
||||
In Section 2 the origins of the Unbound project are documented. Section
|
||||
3 lists the goals, while Section 4 lists the explicit non-goals of the
|
||||
project.
|
||||
project. Section 5 discusses choices made during development.
|
||||
|
||||
|
||||
2. History
|
||||
@@ -121,3 +121,88 @@ o The harden-glue feature, when yes all out of zone glue is deleted, when
|
||||
as more glue is present for the recursive service to use. The feature
|
||||
is implemented so as to minimise the security risk, while trying to
|
||||
keep this performance gain.
|
||||
o The method by which dnssec-lameness is detected is not secure. DNSSEC lame
|
||||
is when a server has the zone in question, but lacks dnssec data, such as
|
||||
signatures. The method to detect dnssec lameness looks at nonvalidated
|
||||
data from the parent of a zone. This can be used, by spoofing the parent,
|
||||
to create a false sense of dnssec-lameness in the child, or a false sense
|
||||
or dnssec-non-lameness in the child. The first results in the server marked
|
||||
lame, and not used for 900 seconds, and the second will result in a
|
||||
validator failure (SERVFAIL again), when the query is validated later on.
|
||||
|
||||
Concluding, a spoof of the parent delegation can be used for many cases
|
||||
of denial of service. I.e. a completely different NS set could be returned,
|
||||
or the information withheld. All of these alterations can be caught by
|
||||
the validator if the parent is signed, and result in 900 seconds bogus.
|
||||
The dnssec-lameness detection is used to detect operator failures,
|
||||
before the validator will properly verify the messages.
|
||||
|
||||
Also for zones for which no chain of trust exists, but a DS is given by the
|
||||
parent, dnssec-lameness detection enables. This delivers dnssec to our
|
||||
clients when possible (for client validators).
|
||||
|
||||
The following issue needs to be resolved:
|
||||
a server that serves both a parent and child zone, where
|
||||
parent is signed, but child is not. The server must not be marked
|
||||
lame for the parent zone, because the child answer is not signed.
|
||||
Instead of a false positive, we want false negatives; failure to
|
||||
detect dnssec-lameness is less of a problem than marking honest
|
||||
servers lame. dnssec-lameness is a config error and deserves the trouble.
|
||||
So, only messages that identify the zone are used to mark the zone
|
||||
lame. The zone is identified by SOA or NS RRsets in the answer/auth.
|
||||
That includes almost all negative responses and also A, AAAA qtypes.
|
||||
That would be most responses from servers.
|
||||
For referrals, delegations that add a single label can be checked to be
|
||||
from their zone, this covers most delegation-centric zones.
|
||||
|
||||
So possibly, for complicated setups, with multiple (parent-child) zones
|
||||
on a server, dnssec-lameness detection does not work - no dnssec-lameness
|
||||
is detected. Instead the zone that is dnssec-lame becomes bogus.
|
||||
|
||||
o authority features.
|
||||
This is a recursive server, and authority features are out of scope.
|
||||
However, some authority features are expected in a recursor. Things like
|
||||
localhost, reverse lookup for 127.0.0.1, or blocking AS112 traffic.
|
||||
Also redirection of domain names with fixed data is needed by service
|
||||
providers. Limited support is added specifically to address this.
|
||||
|
||||
Adding full authority support, requires much more code, and more complex
|
||||
maintenance.
|
||||
|
||||
The limited support allows adding some static data (for localhost and so),
|
||||
and to respond with a fixed rcode (NXDOMAIN) for domains (such as AS112).
|
||||
|
||||
You can put authority data on a separate server, and set the server in
|
||||
unbound.conf as stub for those zones, this allows clients to access data
|
||||
from the server without making unbound authoritative for the zones.
|
||||
|
||||
o the access control denies queries before any other processing.
|
||||
This denies queries that are not authoritative, or version.bind, or any.
|
||||
And thus prevents cache-snooping (denied hosts cannot make non-recursive
|
||||
queries and get answers from the cache).
|
||||
|
||||
o If a client makes a query without RD bit, in the case of a returned
|
||||
message from cache which is:
|
||||
answer section: empty
|
||||
auth section: NS record present, no SOA record, no DS record,
|
||||
maybe NSEC or NSEC3 records present.
|
||||
additional: A records or other relevant records.
|
||||
A SOA record would indicate that this was a NODATA answer.
|
||||
A DS records would indicate a referral.
|
||||
Absence of NS record would indicate a NODATA answer as well.
|
||||
|
||||
Then the receiver does not know whether this was a referral
|
||||
with attempt at no-DS proof) or a nodata answer with attempt
|
||||
at no-data proof. It could be determined by attempting to prove
|
||||
either condition; and looking if only one is valid, but both
|
||||
proofs could be valid, or neither could be valid, which creates
|
||||
doubt. This case is validated by unbound as a 'referral' which
|
||||
ascertains that RRSIGs are OK (and not omitted), but does not
|
||||
check NSEC/NSEC3.
|
||||
|
||||
o Case preservation
|
||||
Unbound preserves the casing received from authority servers as best
|
||||
as possible. It compresses without case, so case can get lost there.
|
||||
The casing from the authority server is used in preference to the casing
|
||||
of the query name. This is different from BIND. RFC4343 allows either
|
||||
behaviour.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
.TH "unbound-checkconf" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-checkconf.8 -- unbound configuration checker manual
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
unbound-checkconf
|
||||
\- Check unbound configuration file for errors.
|
||||
.SH "SYNOPSIS"
|
||||
.B unbound-checkconf
|
||||
.RB [ \-h ]
|
||||
.IR cfgfile
|
||||
.SH "DESCRIPTION"
|
||||
.B Unbound-checkconf
|
||||
checks the configuration file for the
|
||||
\fIunbound\fR(8)
|
||||
DNS resolver for syntax and other errors.
|
||||
The config file syntax is described in
|
||||
\fIunbound.conf\fR(5).
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.I cfgfile
|
||||
The config file to read with settings for unbound. It is checked.
|
||||
If omitted, the config file at the default location is checked.
|
||||
.SH "EXIT CODE"
|
||||
The unbound-checkconf program exits with status code 1 on error,
|
||||
0 for a correct config file.
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I /etc/unbound/unbound.conf
|
||||
unbound configuration file.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
@@ -0,0 +1,93 @@
|
||||
.TH "unbound\-host" "1" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-host.1 -- unbound DNS lookup utility
|
||||
.\"
|
||||
.\" Copyright (c) 2007, NLnet Labs. All rights reserved.
|
||||
.\"
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound\-host
|
||||
\- unbound DNS lookup utility
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B unbound\-host
|
||||
.RB [ \-vdh ]
|
||||
.RB [ \-c
|
||||
.IR class ]
|
||||
.RB [ \-t
|
||||
.IR type ]
|
||||
.I hostname
|
||||
.RB [ \-y
|
||||
.IR key ]
|
||||
.RB [ \-f
|
||||
.IR keyfile ]
|
||||
.RB [ \-F
|
||||
.IR namedkeyfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound\-host
|
||||
uses the unbound validating resolver to query for the hostname and display
|
||||
results. With the \fB\-v\fR option it displays validation
|
||||
status: secure, insecure, bogus (security failure).
|
||||
.P
|
||||
The available options are:
|
||||
.TP
|
||||
.I hostname
|
||||
This name is resolved (looked up in the DNS).
|
||||
If a IPv4 or IPv6 address is given, a reverse lookup is performed.
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.TP
|
||||
.B \-v
|
||||
Enable verbose output and it shows validation results, on every line.
|
||||
Secure means that the NXDOMAIN (no such domain name), nodata (no such data)
|
||||
or positive data response validated correctly with one of the keys.
|
||||
Insecure means that that domain name has no security set up for it.
|
||||
Bogus (security failure) means that the response failed one or more checks,
|
||||
it is likely wrong, outdated, tampered with, or broken.
|
||||
.TP
|
||||
.B \-d
|
||||
Enable debug output to stderr. One \-d shows what the resolver and validator
|
||||
are doing and may tell you what is going on. More times, \-d \-d, gives a
|
||||
lot of output, with every packet sent and received.
|
||||
.TP
|
||||
.B \-c \fIclass
|
||||
Specify the class to lookup for, the default is IN the internet class.
|
||||
.TP
|
||||
.B \-t \fItype
|
||||
Specify the type of data to lookup. The default looks for IPv4, IPv6 and
|
||||
mail handler data, or domain name pointers for reverse queries.
|
||||
.TP
|
||||
.B \-y \fIkey
|
||||
Specify a public key to use as trust anchor. This is the base for a chain
|
||||
of trust that is built up from the trust anchor to the response, in order
|
||||
to validate the response message. Can be given as a DS or DNSKEY record.
|
||||
For example \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD".
|
||||
.TP
|
||||
.B \-f \fIkeyfile
|
||||
Reads keys from a file. Every line has a DS or DNSKEY record, in the format
|
||||
as for \-y. The zone file format, the same as dig and drill produce.
|
||||
.TP
|
||||
.B \-F \fInamedkeyfile
|
||||
Reads keys from a BIND\-style named.conf file. Only the trusted\-key {}; entries
|
||||
are read.
|
||||
.SH "EXAMPLES"
|
||||
.LP
|
||||
Some examples of use.
|
||||
.P
|
||||
$ unbound\-host www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" www.example.com
|
||||
.P
|
||||
$ unbound\-host \-v \-y "example.com DS 31560 5 1 1CFED84787E6E19CCF9372C1187325972FE546CD" 192.0.2.153
|
||||
.SH "EXIT CODE"
|
||||
The unbound\-host program exits with status code 1 on error,
|
||||
0 on no error. The data may not be available on exit code 0, exit code 1
|
||||
means the lookup encountered a fatal error.
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
+35
-28
@@ -1,3 +1,4 @@
|
||||
.TH "unbound" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound.8 -- unbound manual
|
||||
.\"
|
||||
@@ -6,39 +7,45 @@
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.Dd @date@
|
||||
.Dt unbound 8
|
||||
.Sh NAME
|
||||
unbound
|
||||
.Nd Unbound DNS validating resolver @version@.
|
||||
.Sh SYNOPSIS
|
||||
.Nm unbound
|
||||
.Op Fl h
|
||||
.Op Fl d
|
||||
.Op Fl v
|
||||
.Op Fl c Ar cfgfile
|
||||
.Sh DESCRIPTION
|
||||
.Ic Unbound
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound
|
||||
\- Unbound DNS validating resolver @version@.
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B unbound
|
||||
.RB [ \-h ]
|
||||
.RB [ \-d ]
|
||||
.RB [ \-v ]
|
||||
.RB [ \-c
|
||||
.IR cfgfile ]
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B Unbound
|
||||
is an implementation of a DNS resolver, that does caching and
|
||||
DNSSEC validation.
|
||||
.Pp
|
||||
.P
|
||||
The available options are:
|
||||
.Bl -tag -width indent
|
||||
.It Fl h
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.It Fl c Ar cfgfile
|
||||
Set the config file to read with settings for unbound. The syntax is
|
||||
described in
|
||||
.Xr unbound.conf 5 .
|
||||
.It Fl d
|
||||
.TP
|
||||
.B \-c\fI cfgfile
|
||||
Set the config file with settings for unbound to read instead of the
|
||||
file at default location /etc/unbound/unbound.conf. The syntax is
|
||||
described in \fIunbound.conf\fR(5).
|
||||
.TP
|
||||
.B \-d
|
||||
Debug flag, do not fork into the background, but stay attached to the
|
||||
console.
|
||||
.It Fl v
|
||||
console. This flag will also delay writing to the logfile until the
|
||||
thread\-spawn time. So that most config and setup errors appear on stderr.
|
||||
.TP
|
||||
.B \-v
|
||||
Increase verbosity. If given multiple times, more information is logged.
|
||||
This is in addition to the verbosity (if any) from the config file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr unbound.conf 5 .
|
||||
.Sh AUTHORS
|
||||
.Ic Unbound
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\-checkconf\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
developers are mentioned in the CREDITS file in the distribution.
|
||||
|
||||
+465
-148
@@ -1,3 +1,4 @@
|
||||
.TH "unbound.conf" "5" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound.conf.5 -- unbound.conf manual
|
||||
.\"
|
||||
@@ -6,233 +7,387 @@
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.Dd @date@
|
||||
.Os FreeBSD
|
||||
.Dt unbound.conf 5
|
||||
.Sh NAME
|
||||
.Nm unbound.conf
|
||||
.Nd Unbound configuration file.
|
||||
.Sh SYNOPSIS
|
||||
.Nm unbound.conf
|
||||
.Sh DESCRIPTION
|
||||
.Ic unbound.conf
|
||||
.SH "NAME"
|
||||
.LP
|
||||
.B unbound.conf
|
||||
\- Unbound configuration file.
|
||||
.SH "SYNOPSIS"
|
||||
.LP
|
||||
.B unbound.conf
|
||||
.SH "DESCRIPTION"
|
||||
.LP
|
||||
.B unbound.conf
|
||||
is used to configure
|
||||
.Xr unbound 8 .
|
||||
\fIunbound\fR(8).
|
||||
The file format has attributes and values. Some attributes have attributes inside them.
|
||||
The notation is: attribute: value.
|
||||
.Pp
|
||||
.P
|
||||
Comments start with # and last to the end of line. Empty lines are
|
||||
ignored as is whitespace at the beginning of a line.
|
||||
.Sh EXAMPLE
|
||||
.P
|
||||
The utility
|
||||
\fIunbound\-checkconf\fR(8)
|
||||
can be used to check unbound.conf prior to usage.
|
||||
.SH "EXAMPLE"
|
||||
An example config file is shown below. Copy this to /etc/unbound/unbound.conf
|
||||
and start the server with:
|
||||
.P
|
||||
.nf
|
||||
$ unbound -c /etc/unbound/unbound.conf
|
||||
$ unbound \-c /etc/unbound/unbound.conf
|
||||
.fi
|
||||
.P
|
||||
Most settings are the defaults. Stop the server with:
|
||||
.P
|
||||
.nf
|
||||
$ kill `cat /etc/unbound/unbound.pid`
|
||||
.fi
|
||||
.P
|
||||
Below is a minimal config file. The source distribution contains an extensive
|
||||
example.conf file with all the options.
|
||||
.P
|
||||
.nf
|
||||
# unbound.conf(5) config file for unbound(8).
|
||||
server:
|
||||
directory: "/etc/unbound"
|
||||
username: unbound # make sure it can write to pidfile, logfile.
|
||||
username: unbound # make sure it can write to pidfile.
|
||||
chroot: "/etc/unbound"
|
||||
logfile: "/etc/unbound/unbound.log"
|
||||
# logfile: "/etc/unbound/unbound.log" #uncomment to use logfile.
|
||||
pidfile: "/etc/unbound/unbound.pid"
|
||||
# verbosity: 1 # uncomment and increase to get more logging.
|
||||
# listen on all interfaces, answer queries from the local subnet.
|
||||
interface: 0.0.0.0
|
||||
interface: ::0
|
||||
access\-control: 10.0.0.0/8 allow
|
||||
access\-control: 2001:DB8::/64 allow
|
||||
.fi
|
||||
.Sh FILE FORMAT
|
||||
.SH "FILE FORMAT"
|
||||
.LP
|
||||
There must be whitespace between keywords. Attribute keywords end with a colon ':'. An attribute
|
||||
is followed by its containing attributes, or a value.
|
||||
.Pp
|
||||
.P
|
||||
Files can be included using the
|
||||
.Ic include:
|
||||
.B include:
|
||||
directive. It can appear anywhere, and takes a single filename as an argument.
|
||||
Processing continues as if the text from the included file was copied into
|
||||
the config file at that point.
|
||||
.Ss Server Options
|
||||
There may only be one
|
||||
.Ic server:
|
||||
.SS "Server Options"
|
||||
These options are part of the
|
||||
.B server:
|
||||
clause.
|
||||
.Bl -tag -width indent
|
||||
.It \fBverbosity:\fR <number>
|
||||
.TP
|
||||
.B verbosity: \fI<number>
|
||||
The verbosity number, level 0 means no verbosity, only errors. Level 1
|
||||
gives operational information. Level 2 gives query level information,
|
||||
output per query. Level 3 gives algorithm level information.
|
||||
gives operational information. Level 2 gives detailed operational
|
||||
information. Level 3 gives query level information, output per query.
|
||||
Level 4 gives algorithm level information.
|
||||
Default is level 1. The verbosity can also be increased from the commandline,
|
||||
see
|
||||
.Xr unbound 8 .
|
||||
.It \fBnum-threads:\fR <number>
|
||||
\fIunbound\fR(8).
|
||||
.TP
|
||||
.B statistics-interval: \fI<seconds>
|
||||
The number of seconds between printing statistics to the log for every thread.
|
||||
Disable with value 0 or "". Default is disabled.
|
||||
.TP
|
||||
.B num\-threads: \fI<number>
|
||||
The number of threads to create to serve clients. Use 1 for no threading.
|
||||
.It \fBport:\fR <port number>
|
||||
.TP
|
||||
.B port: \fI<port number>
|
||||
The port number, default 53, on which the server responds to queries.
|
||||
.It \fBinterface:\fR <ip address>
|
||||
Interface to use to connect to the network. Can be given multiple times to
|
||||
work on several interfaces. If none are given the default (all) is used.
|
||||
.It \fBoutgoing-port:\fR <port number>
|
||||
.TP
|
||||
.B interface: \fI<ip address>
|
||||
Interface to use to connect to the network. This interface is listened to
|
||||
for queries from clients, and answers to clients are given from it.
|
||||
Can be given multiple times to work on several interfaces. If none are
|
||||
given the default is to listen to localhost.
|
||||
The interfaces are not changed on a reload (kill \-HUP) but only on restart.
|
||||
.TP
|
||||
.B interface-automatic: \fI<yes or no>
|
||||
Detect source interface on UDP queries and copy them to replies. This
|
||||
feature is experimental, and needs support in your OS for IPv6
|
||||
(and its socket options) and IPv4 (and have source-interface socket options).
|
||||
Default value is no.
|
||||
.TP
|
||||
.B outgoing\-interface: \fI<ip address>
|
||||
Interface to use to connect to the network. This interface is used to send
|
||||
queries to authoritative servers and receive their replies. Can be given
|
||||
multiple times to work on several interfaces. If none are given the
|
||||
default (all) is used. You can specify the same interfaces in
|
||||
.B interface:
|
||||
and
|
||||
.B outgoing\-interface:
|
||||
lines, the interfaces are then used for both purposes. Outgoing queries are
|
||||
sent via a random outgoing interface to counter spoofing.
|
||||
.TP
|
||||
.B outgoing\-port: \fI<port number>
|
||||
The starting port number where the outgoing query port range is allocated.
|
||||
Default is 1053.
|
||||
.It \fBoutgoing-range:\fR <number>
|
||||
.TP
|
||||
.B outgoing\-range: \fI<number>
|
||||
Number of ports to open. This number is opened per thread for every outgoing
|
||||
query interface. Must be at least 1. Default is 16.
|
||||
Larger numbers give more protection against spoofing attempts, but need
|
||||
extra resources from the operating system.
|
||||
.It \fBoutgoing-num-tcp:\fR <number>
|
||||
.TP
|
||||
.B outgoing\-num\-tcp: \fI<number>
|
||||
Number of outgoing TCP buffers to allocate per thread. Default is 10. If set
|
||||
to 0, or if do_tcp is "no", no TCP queries to authoritative servers are done.
|
||||
.It \fBincoming-num-tcp:\fR <number>
|
||||
.TP
|
||||
.B incoming\-num\-tcp: \fI<number>
|
||||
Number of incoming TCP buffers to allocate per thread. Default is 10. If set
|
||||
to 0, or if do_tcp is "no", no TCP queries from clients are accepted.
|
||||
.It \fBmsg-buffer-size:\fR <number>
|
||||
.TP
|
||||
.B msg\-buffer\-size: \fI<number>
|
||||
Number of bytes size of the message buffers. Default is 65552 bytes, enough
|
||||
for 64 Kb packets, the maximum DNS message size. No message larger than this
|
||||
can be sent or received. Can be reduced to use less memory, but some requests
|
||||
for DNS data, such as for huge resource records, will result in a SERVFAIL
|
||||
reply to the client.
|
||||
.It \fBmsg-cache-size:\fR <number>
|
||||
.TP
|
||||
.B msg\-cache\-size: \fI<number>
|
||||
Number of bytes size of the message cache. Default is 4 megabytes.
|
||||
.It \fBmsg-cache-slabs:\fR <number>
|
||||
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
.TP
|
||||
.B msg\-cache\-slabs: \fI<number>
|
||||
Number of slabs in the message cache. Slabs reduce lock contention by threads.
|
||||
Must be set to a power of 2. Setting (close) to the number of cpus is a
|
||||
reasonable guess.
|
||||
.It \fBnum-queries-per-thread:\fR <number>
|
||||
.TP
|
||||
.B num\-queries\-per\-thread: \fI<number>
|
||||
The number of queries that every thread will service simultaneously.
|
||||
.It \fBrrset-cache-size:\fR <number>
|
||||
If more queries arrive that need servicing, they are dropped. This forces
|
||||
the client to resend after a timeout; allowing the server time to work on
|
||||
the existing queries. Default 1024.
|
||||
.TP
|
||||
.B rrset\-cache\-size: \fI<number>
|
||||
Number of bytes size of the RRset cache. Default is 4 megabytes.
|
||||
.It \fBrrset-cache-slabs:\fR <number>
|
||||
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
.TP
|
||||
.B rrset\-cache\-slabs: \fI<number>
|
||||
Number of slabs in the RRset cache. Slabs reduce lock contention by threads.
|
||||
Must be set to a power of 2.
|
||||
.It \fBinfra-host-ttl:\fR <seconds>
|
||||
.TP
|
||||
.B cache\-max\-ttl: \fI<seconds>
|
||||
Time to live maximum for RRsets and messages in the cache. Default is
|
||||
86400 seconds (1 day). If the maximum kicks in, responses to clients
|
||||
still get decrementing TTLs based on the original (larger) values.
|
||||
When the internal TTL expires, the cache item has expired.
|
||||
Can be set lower to force the resolver to query for data often, and not
|
||||
trust (very large) TTL values.
|
||||
.TP
|
||||
.B infra\-host\-ttl: \fI<seconds>
|
||||
Time to live for entries in the host cache. The host cache contains
|
||||
roundtrip timing and EDNS support information. Default is 900.
|
||||
.It \fBinfra-lame-ttl:\fR <seconds>
|
||||
.TP
|
||||
.B infra\-lame\-ttl: \fI<seconds>
|
||||
The time to live when a delegation is discovered to be lame. Default is 900.
|
||||
.It \fBinfra-cache-slabs:\fR <number>
|
||||
.TP
|
||||
.B infra\-cache\-slabs: \fI<number>
|
||||
Number of slabs in the infrastructure cache. Slabs reduce lock contention
|
||||
by threads. Must be set to a power of 2.
|
||||
.It \fBinfra-cache-numhosts:\fR <number>
|
||||
.TP
|
||||
.B infra\-cache\-numhosts: \fI<number>
|
||||
Number of hosts for which information is cached. Default is 10000.
|
||||
.It \fBinfra-cache-lame-size:\fR <number>
|
||||
.TP
|
||||
.B infra\-cache\-lame\-size: \fI<number>
|
||||
Number of bytes that the lameness cache per host is allowed to use. Default
|
||||
is 10 kb, which gives maximum storage for a couple score zones, depending on
|
||||
the lame zone name lengths.
|
||||
.It \fBdo-ip4:\fR <yes or no>
|
||||
Enable or disable whether ip4 queries are answered. Default is yes.
|
||||
.It \fBdo-ip6:\fR <yes or no>
|
||||
Enable or disable whether ip6 queries are answered. Default is yes.
|
||||
.It \fBdo-udp:\fR <yes or no>
|
||||
Enable or disable whether UDP queries are answered. Default is yes.
|
||||
.It \fBdo-tcp:\fR <yes or no>
|
||||
Enable or disable whether TCP queries are answered. Default is yes.
|
||||
.It \fBchroot:\fR <directory>
|
||||
If given a chroot is done to the given directory. The default is none ("").
|
||||
.It \fBusername:\fR <name>
|
||||
.TP
|
||||
.B do\-ip4: \fI<yes or no>
|
||||
Enable or disable whether ip4 queries are answered or issued. Default is yes.
|
||||
.TP
|
||||
.B do\-ip6: \fI<yes or no>
|
||||
Enable or disable whether ip6 queries are answered or issued. Default is yes.
|
||||
If disabled, queries are not answered on IPv6, and queries are not sent on
|
||||
IPv6 to the internet nameservers.
|
||||
.TP
|
||||
.B do\-udp: \fI<yes or no>
|
||||
Enable or disable whether UDP queries are answered or issued. Default is yes.
|
||||
.TP
|
||||
.B do\-tcp: \fI<yes or no>
|
||||
Enable or disable whether TCP queries are answered or issued. Default is yes.
|
||||
.TP
|
||||
.B access\-control: \fI<IP netblock> <action>
|
||||
The netblock is given as an IP4 or IP6 address with /size appended for a
|
||||
classless network block. The action can be deny, refuse or allow.
|
||||
Deny stops queries from hosts from that netblock.
|
||||
Refuse stops queries too, but sends a DNS rcode REFUSED error message back.
|
||||
Allow gives access to clients from that netblock.
|
||||
By default only localhost is allowed, the rest is refused.
|
||||
The default is refused, because that is protocol\-friendly. The DNS protocol
|
||||
is not designed to handle dropped packets due to policy, and dropping may
|
||||
result in (possibly excessive) retried queries.
|
||||
.TP
|
||||
.B chroot: \fI<directory>
|
||||
If given a chroot is done to the given directory. The default is
|
||||
"/etc/unbound". If you give "" no chroot is performed.
|
||||
.TP
|
||||
.B username: \fI<name>
|
||||
If given, after binding the port the user privileges are dropped. Default is
|
||||
not to change user, username: "".
|
||||
.Pp
|
||||
"unbound". If you give username: "" no user change is performed.
|
||||
.IP
|
||||
If this user is not capable of binding the
|
||||
port, reloads (by signal HUP) will still retain the opened ports.
|
||||
If you change the port number in the config file, and that new port number
|
||||
requires privileges, then a reload will fail; a restart is needed.
|
||||
.It \fBdirectory:\fR <directory>
|
||||
.TP
|
||||
.B directory: \fI<directory>
|
||||
Sets the working directory for the program.
|
||||
.It \fBlogfile:\fR <filename>
|
||||
.TP
|
||||
.B logfile: \fI<filename>
|
||||
If "" is given, logging goes to stderr, or nowhere once daemonized.
|
||||
The logfile is appended to, in the following format:
|
||||
.nf
|
||||
[seconds since 1970] unbound[pid:tid]: type: message.
|
||||
.It \fBpidfile:\fR <filename>
|
||||
The process id is written to the file. Default is "unbound.pid". So,
|
||||
kill -HUP `cat /etc/unbound/unbound.pid` will trigger a reload,
|
||||
kill -QUIT `cat /etc/unbound/unbound.pid` will gracefully terminate.
|
||||
.It \fBhide-identity:\fR <yes or no>
|
||||
.fi
|
||||
If this option is given, the use\-syslog is option is set to "no".
|
||||
The logfile is reopened (for append) when the config file is reread, on
|
||||
SIGHUP.
|
||||
.TP
|
||||
.B use\-syslog: \fI<yes or no>
|
||||
Sets unbound to send log messages to the syslogd, using
|
||||
\fIsyslog\fR(3).
|
||||
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 pidfile: \fI<filename>
|
||||
The process id is written to the file. Default is "/etc/unbound/unbound.pid".
|
||||
So,
|
||||
.nf
|
||||
kill \-HUP `cat /etc/unbound/unbound.pid`
|
||||
.fi
|
||||
triggers a reload,
|
||||
.nf
|
||||
kill \-QUIT `cat /etc/unbound/unbound.pid`
|
||||
.fi
|
||||
gracefully terminates.
|
||||
.TP
|
||||
.B root\-hints: \fI<filename>
|
||||
Read the root hints from this file. Default is nothing, using builtin hints
|
||||
for the IN class. The file has the format of zone files, with root
|
||||
nameserver names and addresses only. The default may become outdated,
|
||||
when servers change, therefore it is good practice to use a root\-hints file.
|
||||
.TP
|
||||
.B hide\-identity: \fI<yes or no>
|
||||
If enabled id.server and hostname.bind queries are refused.
|
||||
.It \fBidentity:\fR <string>
|
||||
.TP
|
||||
.B identity: \fI<string>
|
||||
Set the identity to report. If set to "", the default, then the hostname
|
||||
of the server is returned.
|
||||
.It \fBhide-version:\fR <yes or no>
|
||||
.TP
|
||||
.B hide\-version: \fI<yes or no>
|
||||
If enabled version.server and version.bind queries are refused.
|
||||
.It \fBversion:\fR <string>
|
||||
.TP
|
||||
.B version: \fI<string>
|
||||
Set the version to report. If set to "", the default, then the package
|
||||
version is returned.
|
||||
.It \fBtarget-fetch-policy:\fR <"list of numbers">
|
||||
.TP
|
||||
.B target\-fetch\-policy: \fI<"list of numbers">
|
||||
Set the target fetch policy used by unbound to determine if it should fetch
|
||||
nameserver target addresses opportunistically. The policy is described per
|
||||
dependency depth.
|
||||
.Pp
|
||||
.IP
|
||||
The number of values determines the maximum dependency depth
|
||||
that unbound will pursue in answering a query.
|
||||
A value of -1 means to fetch all targets opportunistically for that dependency
|
||||
A value of \-1 means to fetch all targets opportunistically for that dependency
|
||||
depth. A value of 0 means to fetch on demand only. A positive value fetches
|
||||
that many targets opportunistically.
|
||||
.Pp
|
||||
.IP
|
||||
Enclose the list between quotes ("") and put spaces between numbers.
|
||||
The default is "3 2 1 0 0". Setting all zeroes, "0 0 0 0 0" gives behaviour
|
||||
closer to that of BIND 9, while setting "-1 -1 -1 -1 -1" gives behaviour
|
||||
closer to that of BIND 9, while setting "\-1 \-1 \-1 \-1 \-1" gives behaviour
|
||||
rumoured to be closer to that of BIND 8.
|
||||
.It \fBharden-short-bufsize:\fR <yes or no>
|
||||
.TP
|
||||
.B harden\-short\-bufsize: \fI<yes or no>
|
||||
Very small EDNS buffer sizes from queries are ignored. Default is off, since
|
||||
it is legal protocol wise to send these, and unbound tries to give very
|
||||
small answers to these queries, where possible.
|
||||
.It \fBharden-large-queries:\fR <yes or no>
|
||||
.TP
|
||||
.B harden\-large\-queries: \fI<yes or no>
|
||||
Very large queries are ignored. Default is off, since it is legal protocol
|
||||
wise to send these, and could be necessary for operation if TSIG or EDNS
|
||||
payload is very large.
|
||||
.It \fBharden-glue:\fR <yes or no>
|
||||
.TP
|
||||
.B harden\-glue: \fI<yes or no>
|
||||
Will trust glue only if it is within the servers authority. Default is on.
|
||||
.It \fBdo-not-query-address:\fR <IP address>
|
||||
Do not query the given IP address. Can be IP4 or IP6. By default the
|
||||
DNS port is blocked for that address. Appending the character '@' and then
|
||||
the portnumber will block other port numbers.
|
||||
.It \fBmodule-config:\fR <"module names">
|
||||
.TP
|
||||
.B harden\-dnssec\-stripped: \fI<yes or no>
|
||||
Require DNSSEC data for trust\-anchored zones, if such data is absent,
|
||||
the zone becomes bogus. If turned off, and no DNSSEC data is received
|
||||
(or the DNSKEY data fails to validate), then the zone is made insecure,
|
||||
this behaves like there is no trust anchor. You could turn this off if
|
||||
you are sometimes behind an intrusive firewall (of some sort) that
|
||||
removes DNSSEC data from packets, or a zone changes from signed to
|
||||
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 do\-not\-query\-address: \fI<IP address>
|
||||
Do not query the given IP address. Can be IP4 or IP6. Append /num to
|
||||
indicate a classless delegation netblock, for example like
|
||||
10.2.3.4/24 or 2001::11/64.
|
||||
.TP
|
||||
.B do\-not\-query\-localhost: \fI<yes or no>
|
||||
If yes, localhost is added to the do\-not\-query\-address entries, both
|
||||
IP6 ::1 and IP4 127.0.0.1/8. If no, then localhost can be used to send
|
||||
queries to. Default is yes.
|
||||
.TP
|
||||
.B module\-config: \fI<"module names">
|
||||
Module configuration, a list of module names separated by spaces, surround
|
||||
the string with quotes (""). The modules can be validator, iterator.
|
||||
Setting this to "iterator" will result in a non-validating server.
|
||||
Setting this to "iterator" will result in a non\-validating server.
|
||||
Setting this to "validator iterator" will turn on DNSSEC validation.
|
||||
You must also set trust-anchors for validation to be useful.
|
||||
.It \fBtrust-anchor-file:\fR <filename>
|
||||
You must also set trust\-anchors for validation to be useful.
|
||||
.TP
|
||||
.B trust\-anchor\-file: \fI<filename>
|
||||
File with trusted keys for validation. Both DS and DNSKEY entries can appear
|
||||
in the file. The format of the file is the standard DNS Zone file format.
|
||||
Default is "", or no trust anchor file.
|
||||
.It \fBtrust-anchor:\fR <"Resource Record">
|
||||
.TP
|
||||
.B trust\-anchor: \fI<"Resource Record">
|
||||
A DS or DNSKEY RR for a key to use for validation. Multiple entries can be
|
||||
given to specify multiple trusted keys, in addition to the trust-anchor-files.
|
||||
given to specify multiple trusted keys, in addition to the trust\-anchor\-files.
|
||||
The resource record is entered in the same format as 'dig' or 'drill' prints
|
||||
them, the same format as in the zone file. Has to be on a single line, with
|
||||
"" around it. A TTL can be specified for ease of cut and paste, but is ignored.
|
||||
A class can be specified, but class IN is default.
|
||||
.It \fBtrusted-keys-file:\fR <filename>
|
||||
.TP
|
||||
.B trusted\-keys\-file: \fI<filename>
|
||||
File with trusted keys for validation. Specify more than one file
|
||||
with several entries, one file per entry. Like \fBtrust-anchor-file\fR
|
||||
but has a different file format. Format is BIND-9 style format,
|
||||
the trusted-keys { name flag proto algo "key"; }; clauses are read.
|
||||
.It \fBval-override-date:\fR <rrsig-style date spec>
|
||||
with several entries, one file per entry. Like \fBtrust\-anchor\-file\fR
|
||||
but has a different file format. Format is BIND\-9 style format,
|
||||
the trusted\-keys { name flag proto algo "key"; }; clauses are read.
|
||||
.TP
|
||||
.B val\-override\-date: \fI<rrsig\-style date spec>
|
||||
Default is "" or "0", which disables this debugging feature. If enabled by
|
||||
giving a RRSIG style date, that date is used for verifying RRSIG inception
|
||||
and expiration dates, instead of the current date. Do not set this unless
|
||||
you are debugging signature inception and expiration.
|
||||
.It \fBval-bogus-ttl:\fR <number>
|
||||
.TP
|
||||
.B val\-bogus\-ttl: \fI<number>
|
||||
The time to live for bogus data. This is data that has failed validation;
|
||||
due to invalid signatures or other checks. The TTL from that data cannot be
|
||||
trusted, and this value is used instead. The value is in seconds, default 900.
|
||||
The time interval prevents repeated revalidation of bogus data.
|
||||
.It \fBval-clean-additional:\fR <yes or no>
|
||||
.TP
|
||||
.B val\-clean\-additional: \fI<yes or no>
|
||||
Instruct the validator to remove data from the additional section of secure
|
||||
messages that are not signed properly. Messages that are insecure, bogus,
|
||||
indeterminate or unchecked are not affected. Default is yes. Use this setting
|
||||
to protect the users that rely on this validator for authentication from
|
||||
protentially bad data in the additional section.
|
||||
.It \fBval-permissive-mode:\fR <yes or no>
|
||||
.TP
|
||||
.B val\-permissive\-mode: \fI<yes or no>
|
||||
Instruct the validator to mark bogus messages as indeterminate. The security
|
||||
checks are performed, but if the result is bogus (failed security), the
|
||||
reply is not withheld from the client with SERVFAIL as usual. The client
|
||||
receives the bogus data. For messages that are found to be secure the AD bit
|
||||
is set in replies. Also logging is performed as for full validation.
|
||||
The default value is "no".
|
||||
.It \fBval-nsec3-keysize-iterations:\fR <"list of values">
|
||||
.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
|
||||
maximum allowed NSEC3 iteration count before a message is simply marked
|
||||
@@ -240,88 +395,250 @@ insecure instead of performing the many hashing iterations. The list must
|
||||
be in ascending order and have at least one entry. If you set it to
|
||||
"1024 65535" there is no restriction to NSEC3 iteration values.
|
||||
This table must be kept short; a very long list could cause slower operation.
|
||||
.It \fBkey-cache-size:\fR <number>
|
||||
.TP
|
||||
.B key\-cache\-size: \fI<number>
|
||||
Number of bytes size of the key cache. Default is 4 megabytes.
|
||||
.It \fBkey-cache-slabs:\fR <number>
|
||||
A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes
|
||||
or gigabytes (1024*1024 bytes in a megabyte).
|
||||
.TP
|
||||
.B key\-cache\-slabs: \fI<number>
|
||||
Number of slabs in the key cache. Slabs reduce lock contention by threads.
|
||||
Must be set to a power of 2. Setting (close) to the number of cpus is a
|
||||
reasonable guess.
|
||||
.El
|
||||
.Ss Stub Zone Options
|
||||
.TP
|
||||
.B local\-zone: \fI<zone> <type>
|
||||
Configure a local zone. The type determines the answer to give if there is
|
||||
no match from local\-data. The types are deny, refuse, static, transparent,
|
||||
redirect, nodefault, and are explained below. After that the default settings
|
||||
are listed. Use local\-data: to enter data into the local zone. Answers for
|
||||
local zones are authoritative DNS answers. By default the zones are class IN.
|
||||
.IP
|
||||
If you need more complicated authoritative data, with referrals, wildcards,
|
||||
CNAME/DNAME support, or DNSSEC authoritative service, setup a stub\-zone for
|
||||
it as detailed in the stub zone section below.
|
||||
.TP 10
|
||||
\h'5'\fIdeny\fR
|
||||
Do not send an answer, drop the query.
|
||||
If there is a match from local data, the query is answered.
|
||||
.TP 10
|
||||
\h'5'\fIrefuse\fR
|
||||
Send an error message reply, with rcode REFUSED.
|
||||
If there is a match from local data, the query is answered.
|
||||
.TP 10
|
||||
\h'5'\fIstatic\fR
|
||||
If there is a match from local data, the query is answered.
|
||||
Otherwise, the query is answered with nodata or nxdomain.
|
||||
For a negative answer a SOA is included in the answer if present
|
||||
as local\-data for the zone apex domain.
|
||||
.TP 10
|
||||
\h'5'\fItransparent\fR
|
||||
If there is a match from local data, the query is answered.
|
||||
Otherwise, the query is resolved normally.
|
||||
If no local\-zone is given local\-data causes a transparent zone
|
||||
to be created by default.
|
||||
.TP 10
|
||||
\h'5'\fIredirect\fR
|
||||
The query is answered from the local data for the zone name.
|
||||
There may be no local data beneath the zone name.
|
||||
This answers queries for the zone, and all subdomains of the zone
|
||||
with the local data for the zone.
|
||||
It can be used to redirect a domain to a different address, with
|
||||
local\-zone: "example.com." redirect and
|
||||
local\-data: "example.com. A 127.0.0.1"
|
||||
queries for www.example.com and www.foo.example.com are redirected.
|
||||
.TP 10
|
||||
\h'5'\fInodefault\fR
|
||||
Used to turn off default contents for AS112 zones. The other types
|
||||
also turn off default contents for the zone. The 'nodefault' option
|
||||
has no other effect than turning off default contents for the
|
||||
given zone.
|
||||
.P
|
||||
The default zones are localhost, reverse 127.0.0.1 and ::1, and the AS112
|
||||
zones. The AS112 zones are reverse DNS zones for private use and reserved
|
||||
IP addresses for which the servers on the internet cannot provide correct
|
||||
answers. They are configured by default to give nxdomain (no reverse
|
||||
information) answers. The defaults can be turned off by specifying your
|
||||
own local\-zone of that name, or using the 'nodefault' type. Below is a
|
||||
list of the default zone contents.
|
||||
.TP 10
|
||||
\h'5'\fIlocalhost\fR
|
||||
The IP4 and IP6 localhost information is given. NS and SOA records are provided
|
||||
for completeness and to satisfy some DNS update tools. Default content:
|
||||
.nf
|
||||
local\-zone: "localhost." static
|
||||
local\-data: "localhost. 10800 IN NS localhost."
|
||||
local\-data: "localhost. 10800 IN
|
||||
SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
|
||||
local\-data: "localhost. 10800 IN A 127.0.0.1"
|
||||
local\-data: "localhost. 10800 IN AAAA ::1"
|
||||
.fi
|
||||
.TP 10
|
||||
\h'5'\fIreverse IPv4 loopback\fR
|
||||
Default content:
|
||||
.nf
|
||||
local\-zone: "127.in\-addr.arpa." static
|
||||
local\-data: "127.in\-addr.arpa. 10800 IN NS localhost."
|
||||
local\-data: "127.in\-addr.arpa. 10800 IN
|
||||
SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
|
||||
local\-data: "1.0.0.127.in\-addr.arpa. 10800 IN
|
||||
PTR localhost."
|
||||
.fi
|
||||
.TP 10
|
||||
\h'5'\fIreverse IPv6 loopback\fR
|
||||
Default content:
|
||||
.nf
|
||||
local\-zone: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." static
|
||||
local\-data: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN
|
||||
NS localhost."
|
||||
local\-data: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN
|
||||
SOA localhost. nobody.invalid. 1 3600 1200 604800 10800"
|
||||
local\-data: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN
|
||||
PTR localhost."
|
||||
.fi
|
||||
.TP 10
|
||||
\h'5'\fIreverse RFC1918 local use zones\fR
|
||||
Reverse data for zones 10.in\-addr.arpa, 16.172.in\-addr.arpa to
|
||||
31.172.in\-addr.arpa, 168.192.in\-addr.arpa.
|
||||
The \fBlocal\-zone:\fR is set static and as \fBlocal\-data:\fR SOA and NS
|
||||
records are provided.
|
||||
.TP 10
|
||||
\h'5'\fIreverse RFC3330 IP4 this, link\-local, testnet and broadcast\fR
|
||||
Reverse data for zones 0.in\-addr.arpa, 254.169.in\-addr.arpa,
|
||||
2.0.192.in\-addr.arpa, 255.255.255.255.in\-addr.arpa.
|
||||
.TP 10
|
||||
\h'5'\fIreverse RFC4291 IP6 unspecified\fR
|
||||
Reverse data for zone
|
||||
.nf
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
|
||||
0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.
|
||||
.fi
|
||||
.TP 10
|
||||
\h'5'\fIreverse RFC4193 IPv6 Locally Assigned Local Addresses\fR
|
||||
Reverse data for zone D.F.ip6.arpa.
|
||||
.TP 10
|
||||
\h'5'\fIreverse RFC4291 IPv6 Link Local Addresses\fR
|
||||
Reverse data for zones 8.E.F.ip6.arpa to B.E.F.ip6.arpa.
|
||||
.\" End of local-zone listing.
|
||||
.TP 5
|
||||
.B local\-data: \fI"<resource record string>"
|
||||
Configure local data, which is served in reply to queries for it.
|
||||
The query has to match exactly unless you configure the local\-zone as
|
||||
redirect. If not matched exactly, the local\-zone type determines
|
||||
further processing. If local\-data is configured that is not a subdomain of
|
||||
a local\-zone, a transparent local\-zone is configured.
|
||||
For record types such as TXT, use single quotes, as in
|
||||
local\-data: 'example. TXT "text"'.
|
||||
.IP
|
||||
If you need more complicated authoritative data, with referrals, wildcards,
|
||||
CNAME/DNAME support, or DNSSEC authoritative service, setup a stub\-zone for
|
||||
it as detailed in the stub zone section below.
|
||||
.SS "Stub Zone Options"
|
||||
.LP
|
||||
There may be multiple
|
||||
.Ic stub-zone:
|
||||
.B stub\-zone:
|
||||
clauses. Each with a name: and zero or more hostnames or IP addresses.
|
||||
For the stub zone this list of nameservers is used. Class IN is assumed.
|
||||
.Bl -tag -width indent
|
||||
.It \fBname:\fR <domain name>
|
||||
.P
|
||||
The stub zone can be used to configure authoritative data to be used
|
||||
by the resolver that cannot be accessed using the public internet servers.
|
||||
This is useful for company\-local data or private zones. Setup an
|
||||
authoritative server on a different host (or different port). Enter a config
|
||||
entry for unbound with
|
||||
.B stub\-addr:
|
||||
<ip address of host[@port]>.
|
||||
The unbound resolver can then access the data, without referring to the
|
||||
public internet for it.
|
||||
.P
|
||||
This setup allows DNSSEC signed zones to be served by that
|
||||
authoritative server, in which case a trusted key entry with the public key
|
||||
can be put in config, so that unbound can validate the data and set the AD
|
||||
bit on replies for the private zone (authoritative servers do not set the
|
||||
AD bit). This setup makes unbound capable of answering queries for the
|
||||
private zone, and can even set the AD bit ('authentic'), but the AA
|
||||
('authoritative') bit is not set on these replies.
|
||||
.TP
|
||||
.B name: \fI<domain name>
|
||||
Name of the stub zone.
|
||||
.It \fBstub-host:\fR <domain name>
|
||||
.TP
|
||||
.B stub\-host: \fI<domain name>
|
||||
Name of stub zone nameserver. Is itself resolved before it is used.
|
||||
.It \fBstub-addr:\fR <IP address>
|
||||
.TP
|
||||
.B stub\-addr: \fI<IP address>
|
||||
IP address of stub zone nameserver. Can be IP 4 or IP 6.
|
||||
To use a nondefault port for DNS communication append '@' with the port number.
|
||||
.El
|
||||
.Ss Forward Zone Options
|
||||
.SS "Forward Zone Options"
|
||||
.LP
|
||||
There may be multiple
|
||||
.Ic forward-zone:
|
||||
.B forward\-zone:
|
||||
clauses. Each with a name: and zero or more hostnames or IP addresses.
|
||||
For the forward zone this list of nameservers is used to forward the queries
|
||||
to. The servers have to handle further recursion for the query. Class IN is
|
||||
assumed. A forward-zone entry with name "." and a forward-addr target will
|
||||
assumed. A forward\-zone entry with name "." and a forward\-addr target will
|
||||
forward all queries to that other server (unless it can answer from the cache).
|
||||
.Bl -tag -width indent
|
||||
.It \fBname:\fR <domain name>
|
||||
.TP
|
||||
.B name: \fI<domain name>
|
||||
Name of the forward zone.
|
||||
.It \fBforward-host:\fR <domain name>
|
||||
.TP
|
||||
.B forward\-host: \fI<domain name>
|
||||
Name of server to forward to. Is itself resolved before it is used.
|
||||
.It \fBforward-addr:\fR <IP address>
|
||||
.TP
|
||||
.B forward\-addr: \fI<IP address>
|
||||
IP address of server to forward to. Can be IP 4 or IP 6.
|
||||
To use a nondefault port for DNS communication append '@' with the port number.
|
||||
.El
|
||||
.Sh MEMORY CONTROL EXAMPLE
|
||||
.SH "MEMORY CONTROL EXAMPLE"
|
||||
In the example config settings below memory usage is reduced. Some service
|
||||
levels are lower, notable very large data and a high TCP load are no longer
|
||||
supported. Very large data and high TCP loads are exceptional for the DNS.
|
||||
DNSSEC validation is enabled, just add trust anchors.
|
||||
If you do not have to worry about programs using more than 1 meg of memory,
|
||||
the below example is not for you. Use the defaults to receive full service.
|
||||
.Pp
|
||||
.P
|
||||
.nf
|
||||
# example settings that reduce memory usage
|
||||
server:
|
||||
num-threads: 1
|
||||
outgoing-num-tcp: 1 # this limits TCP service, uses less buffers.
|
||||
incoming-num-tcp: 1
|
||||
outgoing-range: 1 # uses less memory, but less port randomness.
|
||||
msg-buffer-size: 8192 # note this limits service, 'no huge stuff'.
|
||||
msg-cache-size: 102400 # 100 Kb.
|
||||
msg-cache-slabs: 1
|
||||
rrset-cache-size: 102400 # 100 Kb.
|
||||
rrset-cache-slabs: 1
|
||||
infra-cache-numhosts: 200
|
||||
infra-cache-numlame: 10
|
||||
key-cache-size: 102400 # 100 Kb.
|
||||
key-cache-slabs: 1
|
||||
num-queries-per-thread: 30
|
||||
target-fetch-policy: "2 1 0 0 0 0"
|
||||
harden-large-queries: "yes"
|
||||
harden-short-bufsize: "yes"
|
||||
do-ip6: no # save a bit of memory if not used.
|
||||
num\-threads: 1
|
||||
outgoing\-num\-tcp: 1 # this limits TCP service, uses less buffers.
|
||||
incoming\-num\-tcp: 1
|
||||
outgoing\-range: 1 # uses less memory, but less port randomness.
|
||||
msg\-buffer\-size: 8192 # note this limits service, 'no huge stuff'.
|
||||
msg\-cache\-size: 102400 # 100 Kb.
|
||||
msg\-cache\-slabs: 1
|
||||
rrset\-cache\-size: 102400 # 100 Kb.
|
||||
rrset\-cache\-slabs: 1
|
||||
infra\-cache\-numhosts: 200
|
||||
infra\-cache\-numlame: 10
|
||||
key\-cache\-size: 102400 # 100 Kb.
|
||||
key\-cache\-slabs: 1
|
||||
num\-queries\-per\-thread: 30
|
||||
target\-fetch\-policy: "2 1 0 0 0 0"
|
||||
harden\-large\-queries: "yes"
|
||||
harden\-short\-bufsize: "yes"
|
||||
do\-ip6: no # save a bit of memory if not used.
|
||||
.fi
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
.It Pa /etc/unbound
|
||||
default unbound working directory
|
||||
.It Pa unbound.conf
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I /etc/unbound
|
||||
default unbound working directory and default
|
||||
\fIchroot\fR(2)
|
||||
location.
|
||||
.TP
|
||||
.I unbound.conf
|
||||
unbound configuration file.
|
||||
.It Pa unbound.pid
|
||||
.TP
|
||||
.I unbound.pid
|
||||
default unbound pidfile with process ID of the running daemon.
|
||||
.It Pa unbound.log
|
||||
unbound log file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr unbound 8
|
||||
.Sh AUTHORS
|
||||
.Ic Unbound
|
||||
.TP
|
||||
.I unbound.log
|
||||
unbound log file. default is to log to
|
||||
\fIsyslog\fR(3).
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound\fR(8),
|
||||
\fIunbound\-checkconf\fR(8).
|
||||
.SH "AUTHORS"
|
||||
.B Unbound
|
||||
was written by NLnet Labs. Please see CREDITS file
|
||||
in the distribution for further details.
|
||||
|
||||
+2
-1
@@ -495,7 +495,8 @@ EXCLUDE = ./build \
|
||||
util/configparser.c \
|
||||
util/configparser.h \
|
||||
util/configlexer.c \
|
||||
util/locks.h
|
||||
util/locks.h \
|
||||
./ldns-src
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
|
||||
# directories that are symbolic links (a Unix filesystem feature) are excluded
|
||||
|
||||
+23
-19
@@ -42,23 +42,24 @@
|
||||
#include "config.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
struct delegpt*
|
||||
delegpt_create(struct region* region)
|
||||
delegpt_create(struct regional* region)
|
||||
{
|
||||
struct delegpt* dp=(struct delegpt*)region_alloc(region, sizeof(*dp));
|
||||
struct delegpt* dp=(struct delegpt*)regional_alloc(
|
||||
region, sizeof(*dp));
|
||||
if(!dp)
|
||||
return NULL;
|
||||
memset(dp, 0, sizeof(*dp));
|
||||
return dp;
|
||||
}
|
||||
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct region* region)
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
|
||||
{
|
||||
struct delegpt* copy = delegpt_create(region);
|
||||
struct delegpt_ns* ns;
|
||||
@@ -80,15 +81,15 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct region* region)
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_set_name(struct delegpt* dp, struct region* region, uint8_t* name)
|
||||
delegpt_set_name(struct delegpt* dp, struct regional* region, uint8_t* name)
|
||||
{
|
||||
dp->namelabs = dname_count_size_labels(name, &dp->namelen);
|
||||
dp->name = region_alloc_init(region, name, dp->namelen);
|
||||
dp->name = regional_alloc_init(region, name, dp->namelen);
|
||||
return dp->name != 0;
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name)
|
||||
delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
size_t len;
|
||||
@@ -97,14 +98,14 @@ delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name)
|
||||
* adding the same server as a dependency twice */
|
||||
if(delegpt_find_ns(dp, name, len))
|
||||
return 1;
|
||||
ns = (struct delegpt_ns*)region_alloc(region,
|
||||
ns = (struct delegpt_ns*)regional_alloc(region,
|
||||
sizeof(struct delegpt_ns));
|
||||
if(!ns)
|
||||
return 0;
|
||||
ns->next = dp->nslist;
|
||||
ns->namelen = len;
|
||||
dp->nslist = ns;
|
||||
ns->name = region_alloc_init(region, name, ns->namelen);
|
||||
ns->name = regional_alloc_init(region, name, ns->namelen);
|
||||
ns->resolved = 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -124,7 +125,7 @@ delegpt_find_ns(struct delegpt* dp, uint8_t* name, size_t namelen)
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_target(struct delegpt* dp, struct region* region,
|
||||
delegpt_add_target(struct delegpt* dp, struct regional* region,
|
||||
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
@@ -138,10 +139,10 @@ delegpt_add_target(struct delegpt* dp, struct region* region,
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_addr(struct delegpt* dp, struct region* region,
|
||||
delegpt_add_addr(struct delegpt* dp, struct regional* region,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
struct delegpt_addr* a = (struct delegpt_addr*)region_alloc(region,
|
||||
struct delegpt_addr* a = (struct delegpt_addr*)regional_alloc(region,
|
||||
sizeof(struct delegpt_addr));
|
||||
if(!a)
|
||||
return 0;
|
||||
@@ -152,6 +153,7 @@ delegpt_add_addr(struct delegpt* dp, struct region* region,
|
||||
dp->usable_list = a;
|
||||
memcpy(&a->addr, addr, addrlen);
|
||||
a->addrlen = addrlen;
|
||||
a->attempts = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -189,12 +191,14 @@ delegpt_count_addr(struct delegpt* dp, size_t* numaddr, size_t* numres,
|
||||
}
|
||||
}
|
||||
|
||||
void delegpt_log(struct delegpt* dp)
|
||||
void delegpt_log(enum verbosity_value v, struct delegpt* dp)
|
||||
{
|
||||
char buf[LDNS_MAX_DOMAINLEN+1];
|
||||
struct delegpt_ns* ns;
|
||||
struct delegpt_addr* a;
|
||||
size_t missing=0, numns=0, numaddr=0, numres=0, numavail=0;
|
||||
if(verbosity < v)
|
||||
return;
|
||||
dname_str(dp->name, buf);
|
||||
if(dp->nslist == NULL && dp->target_list == NULL) {
|
||||
log_info("DelegationPoint<%s>: empty", buf);
|
||||
@@ -212,7 +216,7 @@ void delegpt_log(struct delegpt* dp)
|
||||
log_info(" %s%s", buf, (ns->resolved?"*":""));
|
||||
}
|
||||
for(a = dp->target_list; a; a = a->next_target) {
|
||||
log_addr(" ", &a->addr, a->addrlen);
|
||||
log_addr(VERB_ALGO, " ", &a->addr, a->addrlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,7 +257,7 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
|
||||
}
|
||||
|
||||
struct delegpt*
|
||||
delegpt_from_message(struct dns_msg* msg, struct region* region)
|
||||
delegpt_from_message(struct dns_msg* msg, struct regional* region)
|
||||
{
|
||||
struct ub_packed_rrset_key* ns_rrset = NULL;
|
||||
struct delegpt* dp;
|
||||
@@ -302,7 +306,7 @@ delegpt_from_message(struct dns_msg* msg, struct region* region)
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
|
||||
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ns_rrset)
|
||||
{
|
||||
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
|
||||
@@ -321,7 +325,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
|
||||
delegpt_add_rrset_A(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ak)
|
||||
{
|
||||
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
|
||||
@@ -344,7 +348,7 @@ delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
|
||||
delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* ak)
|
||||
{
|
||||
struct packed_rrset_data* d=(struct packed_rrset_data*)ak->entry.data;
|
||||
@@ -367,7 +371,7 @@ delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
|
||||
}
|
||||
|
||||
int
|
||||
delegpt_add_rrset(struct delegpt* dp, struct region* region,
|
||||
delegpt_add_rrset(struct delegpt* dp, struct regional* region,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
if(!rrset)
|
||||
|
||||
+30
-24
@@ -42,7 +42,8 @@
|
||||
|
||||
#ifndef ITERATOR_ITER_DELEGPT_H
|
||||
#define ITERATOR_ITER_DELEGPT_H
|
||||
struct region;
|
||||
#include "util/log.h"
|
||||
struct regional;
|
||||
struct delegpt_ns;
|
||||
struct delegpt_addr;
|
||||
struct dns_msg;
|
||||
@@ -103,55 +104,59 @@ struct delegpt_addr {
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr */
|
||||
socklen_t addrlen;
|
||||
/** number of attempts for this addr */
|
||||
int attempts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create new delegation point.
|
||||
* @param region: where to allocate it.
|
||||
* @param regional: where to allocate it.
|
||||
* @return new delegation point or NULL on error.
|
||||
*/
|
||||
struct delegpt* delegpt_create(struct region* region);
|
||||
struct delegpt* delegpt_create(struct regional* regional);
|
||||
|
||||
/**
|
||||
* Create a copy of a delegation point.
|
||||
* @param dp: delegation point to copy.
|
||||
* @param region: where to allocate it.
|
||||
* @param regional: where to allocate it.
|
||||
* @return new delegation point or NULL on error.
|
||||
*/
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct region* region);
|
||||
struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* regional);
|
||||
|
||||
/**
|
||||
* Set name of delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the name copy.
|
||||
* @param regional: where to allocate the name copy.
|
||||
* @param name: name to use.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_set_name(struct delegpt* dp, struct region* region, uint8_t* name);
|
||||
int delegpt_set_name(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name);
|
||||
|
||||
/**
|
||||
* Add a name to the delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param name: domain name in wire format.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_ns(struct delegpt* dp, struct region* region, uint8_t* name);
|
||||
int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name);
|
||||
|
||||
/**
|
||||
* Add NS rrset; calls add_ns repeatedly.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param ns_rrset: NS rrset.
|
||||
* return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
|
||||
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* ns_rrset);
|
||||
|
||||
/**
|
||||
* Add target address to the delegation point.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param name: name for which target was found (must be in nslist).
|
||||
* This name is marked resolved.
|
||||
* @param namelen: length of name.
|
||||
@@ -159,49 +164,49 @@ int delegpt_rrset_add_ns(struct delegpt* dp, struct region* region,
|
||||
* @param addrlen: the length of addr.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_target(struct delegpt* dp, struct region* region,
|
||||
int delegpt_add_target(struct delegpt* dp, struct regional* regional,
|
||||
uint8_t* name, size_t namelen, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Add A RRset to delegpt.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset A to add.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset_A(struct delegpt* dp, struct region* region,
|
||||
int delegpt_add_rrset_A(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
|
||||
/**
|
||||
* Add AAAA RRset to delegpt.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset AAAA to add.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset_AAAA(struct delegpt* dp, struct region* region,
|
||||
int delegpt_add_rrset_AAAA(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
|
||||
/**
|
||||
* Add any RRset to delegpt.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param rrset: RRset to add, NS, A, AAAA.
|
||||
* @return 0 on alloc error.
|
||||
*/
|
||||
int delegpt_add_rrset(struct delegpt* dp, struct region* region,
|
||||
int delegpt_add_rrset(struct delegpt* dp, struct regional* regional,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
|
||||
/**
|
||||
* Add address to the delegation point. No servername is associated or checked.
|
||||
* @param dp: delegation point.
|
||||
* @param region: where to allocate the info.
|
||||
* @param regional: where to allocate the info.
|
||||
* @param addr: the address.
|
||||
* @param addrlen: the length of addr.
|
||||
* @return false on error.
|
||||
*/
|
||||
int delegpt_add_addr(struct delegpt* dp, struct region* region,
|
||||
int delegpt_add_addr(struct delegpt* dp, struct regional* regional,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
@@ -216,9 +221,10 @@ struct delegpt_ns* delegpt_find_ns(struct delegpt* dp, uint8_t* name,
|
||||
|
||||
/**
|
||||
* Print the delegation point to the log. For debugging.
|
||||
* @param v: verbosity value that is needed to emit to log.
|
||||
* @param dp: delegation point.
|
||||
*/
|
||||
void delegpt_log(struct delegpt* dp);
|
||||
void delegpt_log(enum verbosity_value v, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* Add all usable targets to the result list.
|
||||
@@ -247,11 +253,11 @@ size_t delegpt_count_missing_targets(struct delegpt* dp);
|
||||
* find "glue" in either the ADDITIONAL section or the ANSWER section.
|
||||
*
|
||||
* @param msg: the dns message, referral.
|
||||
* @param region: where to allocate delegation point.
|
||||
* @param regional: where to allocate delegation point.
|
||||
* @return new delegation point or NULL on alloc error, or if the
|
||||
* message was not appropriate.
|
||||
*/
|
||||
struct delegpt* delegpt_from_message(struct dns_msg* msg,
|
||||
struct region* region);
|
||||
struct regional* regional);
|
||||
|
||||
#endif /* ITERATOR_ITER_DELEGPT_H */
|
||||
|
||||
+92
-21
@@ -43,18 +43,24 @@
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "iterator/iter_donotq.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
|
||||
/** compare two donotq entries */
|
||||
static int
|
||||
int
|
||||
donotq_cmp(const void* k1, const void* k2)
|
||||
{
|
||||
struct iter_donotq_addr* n1 = (struct iter_donotq_addr*)k1;
|
||||
struct iter_donotq_addr* n2 = (struct iter_donotq_addr*)k2;
|
||||
return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr, n2->addrlen);
|
||||
int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
|
||||
n2->addrlen);
|
||||
if(r != 0) return r;
|
||||
if(n1->net < n2->net)
|
||||
return -1;
|
||||
if(n1->net > n2->net)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iter_donotq*
|
||||
@@ -64,7 +70,7 @@ donotq_create()
|
||||
sizeof(struct iter_donotq));
|
||||
if(!dq)
|
||||
return NULL;
|
||||
dq->region = region_create(malloc, free);
|
||||
dq->region = regional_create();
|
||||
if(!dq->region) {
|
||||
donotq_delete(dq);
|
||||
return NULL;
|
||||
@@ -77,7 +83,7 @@ donotq_delete(struct iter_donotq* dq)
|
||||
{
|
||||
if(!dq)
|
||||
return;
|
||||
region_destroy(dq->region);
|
||||
regional_destroy(dq->region);
|
||||
free(dq->tree);
|
||||
free(dq);
|
||||
}
|
||||
@@ -85,17 +91,37 @@ donotq_delete(struct iter_donotq* dq)
|
||||
/** insert new address into donotq structure */
|
||||
static int
|
||||
donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
socklen_t addrlen, int net)
|
||||
{
|
||||
struct iter_donotq_addr* node = region_alloc(dq->region,
|
||||
struct iter_donotq_addr* node = regional_alloc(dq->region,
|
||||
sizeof(struct iter_donotq_addr));
|
||||
if(!node)
|
||||
return 0;
|
||||
node->node.key = node;
|
||||
memcpy(&node->addr, addr, addrlen);
|
||||
node->addrlen = addrlen;
|
||||
node->net = net;
|
||||
node->parent = NULL;
|
||||
if(!rbtree_insert(dq->tree, &node->node)) {
|
||||
log_warn("duplicate donotquery address ignored.");
|
||||
verbose(VERB_QUERY, "duplicate donotquery address ignored.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply donotq string */
|
||||
static int
|
||||
donotq_str_cfg(struct iter_donotq* dq, const char* str)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse donotquery netblock: %s", str);
|
||||
return 0;
|
||||
}
|
||||
if(!donotq_insert(dq, &addr, addrlen, net)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -105,23 +131,42 @@ static int
|
||||
read_donotq(struct iter_donotq* dq, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
for(p = cfg->donotqueryaddrs; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(!extstrtoaddr(p->str, &addr, &addrlen)) {
|
||||
log_err("cannot parse donotquery ip address: '%s'",
|
||||
p->str);
|
||||
if(!donotq_str_cfg(dq, p->str))
|
||||
return 0;
|
||||
}
|
||||
if(!donotq_insert(dq, &addr, addrlen)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** initialise parent pointers in the tree */
|
||||
static void
|
||||
donotq_init_parents(struct iter_donotq* donotq)
|
||||
{
|
||||
struct iter_donotq_addr* node, *prev = NULL, *p;
|
||||
int m;
|
||||
RBTREE_FOR(node, struct iter_donotq_addr*, donotq->tree) {
|
||||
node->parent = NULL;
|
||||
if(!prev || prev->addrlen != node->addrlen) {
|
||||
prev = node;
|
||||
continue;
|
||||
}
|
||||
m = addr_in_common(&prev->addr, prev->net, &node->addr,
|
||||
node->net, node->addrlen);
|
||||
/* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
|
||||
/* find the previous, or parent-parent-parent */
|
||||
for(p = prev; p; p = p->parent)
|
||||
if(p->net <= m) {
|
||||
/* ==: since prev matched m, this is closest*/
|
||||
/* <: prev matches more, but is not a parent,
|
||||
* this one is a (grand)parent */
|
||||
node->parent = p;
|
||||
break;
|
||||
}
|
||||
prev = node;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
{
|
||||
@@ -131,6 +176,13 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
return 0;
|
||||
if(!read_donotq(dq, cfg))
|
||||
return 0;
|
||||
if(cfg->donotquery_localhost) {
|
||||
if(!donotq_str_cfg(dq, "127.0.0.0/8"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
return 0;
|
||||
}
|
||||
donotq_init_parents(dq);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -139,12 +191,31 @@ donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen)
|
||||
{
|
||||
/* lookup in the tree */
|
||||
rbnode_t* res = NULL;
|
||||
struct iter_donotq_addr* result;
|
||||
struct iter_donotq_addr key;
|
||||
key.node.key = &key;
|
||||
memcpy(&key.addr, addr, addrlen);
|
||||
key.addrlen = addrlen;
|
||||
if(rbtree_search(donotq->tree, &key))
|
||||
key.net = (addr_is_ip6(addr, addrlen)?128:32);
|
||||
if(rbtree_find_less_equal(donotq->tree, &key, &res)) {
|
||||
/* exact */
|
||||
return 1;
|
||||
} else {
|
||||
/* smaller element (or no element) */
|
||||
int m;
|
||||
result = (struct iter_donotq_addr*)res;
|
||||
if(!result || result->addrlen != addrlen)
|
||||
return 0;
|
||||
/* count number of bits matched */
|
||||
m = addr_in_common(&result->addr, result->net, addr,
|
||||
key.net, addrlen);
|
||||
while(result) { /* go up until addr is inside netblock */
|
||||
if(result->net <= m)
|
||||
return 1;
|
||||
result = result->parent;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -152,5 +223,5 @@ size_t
|
||||
donotq_get_mem(struct iter_donotq* donotq)
|
||||
{
|
||||
if(!donotq) return 0;
|
||||
return sizeof(*donotq) + region_get_mem(donotq->region);
|
||||
return sizeof(*donotq) + regional_get_mem(donotq->region);
|
||||
}
|
||||
|
||||
+12
-6
@@ -45,16 +45,16 @@
|
||||
#include "util/rbtree.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct region;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Iterator donotqueryaddresses structure
|
||||
*/
|
||||
struct iter_donotq {
|
||||
/** region for allocation */
|
||||
struct region* region;
|
||||
/** regional for allocation */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Tree of the single addresses that are blocked.
|
||||
* Tree of the address spans that are blocked.
|
||||
* contents of type iter_donotq_addr.
|
||||
*/
|
||||
rbtree_t* tree;
|
||||
@@ -62,15 +62,19 @@ struct iter_donotq {
|
||||
|
||||
/**
|
||||
* Iterator donotquery address.
|
||||
* A single address that must not be used to send queries to.
|
||||
* An address span that must not be used to send queries to.
|
||||
*/
|
||||
struct iter_donotq_addr {
|
||||
/** redblacktree node, key is this structure: addr and addrlen */
|
||||
/** redblacktree node, key is this structure: addr and addrlen, net */
|
||||
rbnode_t node;
|
||||
/** address */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr */
|
||||
socklen_t addrlen;
|
||||
/** netblock size */
|
||||
int net;
|
||||
/** parent node in donotq tree that encompasses this entry */
|
||||
struct iter_donotq_addr* parent;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,5 +114,7 @@ int donotq_lookup(struct iter_donotq* donotq, struct sockaddr_storage* addr,
|
||||
*/
|
||||
size_t donotq_get_mem(struct iter_donotq* donotq);
|
||||
|
||||
/** compare two donotq entries */
|
||||
int donotq_cmp(const void* k1, const void* k2);
|
||||
|
||||
#endif /* ITERATOR_ITER_DONOTQ_H */
|
||||
|
||||
+9
-10
@@ -42,14 +42,13 @@
|
||||
#include "config.h"
|
||||
#include "iterator/iter_fwd.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
/** compare two fwd entries */
|
||||
static int
|
||||
int
|
||||
fwd_cmp(const void* k1, const void* k2)
|
||||
{
|
||||
int m;
|
||||
@@ -71,7 +70,7 @@ forwards_create()
|
||||
sizeof(struct iter_forwards));
|
||||
if(!fwd)
|
||||
return NULL;
|
||||
fwd->region = region_create(malloc, free);
|
||||
fwd->region = regional_create();
|
||||
if(!fwd->region) {
|
||||
forwards_delete(fwd);
|
||||
return NULL;
|
||||
@@ -84,7 +83,7 @@ forwards_delete(struct iter_forwards* fwd)
|
||||
{
|
||||
if(!fwd)
|
||||
return;
|
||||
region_destroy(fwd->region);
|
||||
regional_destroy(fwd->region);
|
||||
free(fwd->tree);
|
||||
free(fwd);
|
||||
}
|
||||
@@ -93,13 +92,13 @@ forwards_delete(struct iter_forwards* fwd)
|
||||
static int
|
||||
forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
|
||||
{
|
||||
struct iter_forward_zone* node = region_alloc(fwd->region,
|
||||
struct iter_forward_zone* node = regional_alloc(fwd->region,
|
||||
sizeof(struct iter_forward_zone));
|
||||
if(!node)
|
||||
return 0;
|
||||
node->node.key = node;
|
||||
node->dclass = c;
|
||||
node->name = region_alloc_init(fwd->region, dp->name, dp->namelen);
|
||||
node->name = regional_alloc_init(fwd->region, dp->name, dp->namelen);
|
||||
if(!node->name)
|
||||
return 0;
|
||||
node->namelen = dp->namelen;
|
||||
@@ -229,8 +228,8 @@ read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
|
||||
return 0;
|
||||
if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
|
||||
return 0;
|
||||
log_info("Forward zone server list:");
|
||||
delegpt_log(dp);
|
||||
verbose(VERB_QUERY, "Forward zone server list:");
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -289,5 +288,5 @@ forwards_get_mem(struct iter_forwards* fwd)
|
||||
{
|
||||
if(!fwd)
|
||||
return 0;
|
||||
return sizeof(*fwd) + region_get_mem(fwd->region);
|
||||
return sizeof(*fwd) + regional_get_mem(fwd->region);
|
||||
}
|
||||
|
||||
+6
-3
@@ -46,14 +46,14 @@
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
struct region;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Iterator forward zones structure
|
||||
*/
|
||||
struct iter_forwards {
|
||||
/** region where forward zone server addresses are allocated */
|
||||
struct region* region;
|
||||
/** regional where forward zone server addresses are allocated */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Zones are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qtype. Then on dname in nsec-like order, so that
|
||||
@@ -125,4 +125,7 @@ struct delegpt* forwards_lookup(struct iter_forwards* fwd,
|
||||
*/
|
||||
size_t forwards_get_mem(struct iter_forwards* fwd);
|
||||
|
||||
/** compare two fwd entries */
|
||||
int fwd_cmp(const void* k1, const void* k2);
|
||||
|
||||
#endif /* ITERATOR_ITER_FWD_H */
|
||||
|
||||
+140
-14
@@ -42,14 +42,13 @@
|
||||
#include "config.h"
|
||||
#include "iterator/iter_hints.h"
|
||||
#include "iterator/iter_delegpt.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
/** compare two hint entries */
|
||||
static int
|
||||
int
|
||||
stub_cmp(const void* k1, const void* k2)
|
||||
{
|
||||
int m;
|
||||
@@ -71,7 +70,7 @@ hints_create()
|
||||
sizeof(struct iter_hints));
|
||||
if(!hints)
|
||||
return NULL;
|
||||
hints->region = region_create(malloc, free);
|
||||
hints->region = regional_create();
|
||||
if(!hints->region) {
|
||||
hints_delete(hints);
|
||||
return NULL;
|
||||
@@ -84,14 +83,14 @@ hints_delete(struct iter_hints* hints)
|
||||
{
|
||||
if(!hints)
|
||||
return;
|
||||
region_destroy(hints->region);
|
||||
regional_destroy(hints->region);
|
||||
free(hints->tree);
|
||||
free(hints);
|
||||
}
|
||||
|
||||
/** add hint to delegation hints */
|
||||
static int
|
||||
ah(struct delegpt* dp, struct region* r, const char* sv, const char* ip)
|
||||
ah(struct delegpt* dp, struct regional* r, const char* sv, const char* ip)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
@@ -113,7 +112,7 @@ ah(struct delegpt* dp, struct region* r, const char* sv, const char* ip)
|
||||
|
||||
/** obtain compiletime provided root hints */
|
||||
static struct delegpt*
|
||||
compile_time_root_prime(struct region* r)
|
||||
compile_time_root_prime(struct regional* r)
|
||||
{
|
||||
/* from:
|
||||
; This file is made available by InterNIC
|
||||
@@ -141,7 +140,7 @@ compile_time_root_prime(struct region* r)
|
||||
if(!ah(dp, r, "I.ROOT-SERVERS.NET.", "192.36.148.17")) return 0;
|
||||
if(!ah(dp, r, "J.ROOT-SERVERS.NET.", "192.58.128.30")) return 0;
|
||||
if(!ah(dp, r, "K.ROOT-SERVERS.NET.", "193.0.14.129")) return 0;
|
||||
if(!ah(dp, r, "L.ROOT-SERVERS.NET.", "198.32.64.12")) return 0;
|
||||
if(!ah(dp, r, "L.ROOT-SERVERS.NET.", "199.7.83.42")) return 0;
|
||||
if(!ah(dp, r, "M.ROOT-SERVERS.NET.", "202.12.27.33")) return 0;
|
||||
return dp;
|
||||
}
|
||||
@@ -150,13 +149,13 @@ compile_time_root_prime(struct region* r)
|
||||
static int
|
||||
hints_insert(struct iter_hints* hints, uint16_t c, struct delegpt* dp)
|
||||
{
|
||||
struct iter_hints_stub* node = region_alloc(hints->region,
|
||||
struct iter_hints_stub* node = regional_alloc(hints->region,
|
||||
sizeof(struct iter_hints_stub));
|
||||
if(!node)
|
||||
return 0;
|
||||
node->node.key = node;
|
||||
node->hint_class = c;
|
||||
node->name = region_alloc_init(hints->region, dp->name, dp->namelen);
|
||||
node->name = regional_alloc_init(hints->region, dp->name, dp->namelen);
|
||||
if(!node->name)
|
||||
return 0;
|
||||
node->namelen = dp->namelen;
|
||||
@@ -286,7 +285,132 @@ read_stubs(struct iter_hints* hints, struct config_file* cfg)
|
||||
return 0;
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp))
|
||||
return 0;
|
||||
delegpt_log(dp);
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read root hints from file */
|
||||
static int
|
||||
read_root_hints(struct iter_hints* hints, char* fname)
|
||||
{
|
||||
int lineno = 0;
|
||||
uint32_t default_ttl = 0;
|
||||
ldns_rdf* origin = NULL;
|
||||
ldns_rdf* prev_rr = NULL;
|
||||
struct delegpt* dp;
|
||||
ldns_rr* rr = NULL;
|
||||
ldns_status status;
|
||||
uint16_t c = LDNS_RR_CLASS_IN;
|
||||
FILE* f = fopen(fname, "r");
|
||||
if(!f) {
|
||||
log_err("could not read root hints %s: %s",
|
||||
fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
dp = delegpt_create(hints->region);
|
||||
if(!dp) {
|
||||
log_err("out of memory reading root hints");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_QUERY, "Reading root hints from %s", fname);
|
||||
while(!feof(f)) {
|
||||
status = ldns_rr_new_frm_fp_l(&rr, f,
|
||||
&default_ttl, &origin, &prev_rr, &lineno);
|
||||
if(status == LDNS_STATUS_SYNTAX_EMPTY ||
|
||||
status == LDNS_STATUS_SYNTAX_TTL ||
|
||||
status == LDNS_STATUS_SYNTAX_ORIGIN)
|
||||
continue;
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("reading root hints %s %d: %s", fname,
|
||||
lineno, ldns_get_errorstr_by_id(status));
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
|
||||
if(!delegpt_add_ns(dp, hints->region,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)))) {
|
||||
log_err("out of memory reading root hints");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
c = ldns_rr_get_class(rr);
|
||||
if(!dp->name) {
|
||||
if(!delegpt_set_name(dp, hints->region,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)))){
|
||||
log_err("out of memory.");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A) {
|
||||
struct sockaddr_in sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
memmove(&sa.sin_addr,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET_SIZE);
|
||||
if(!delegpt_add_target(dp, hints->region,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)),
|
||||
ldns_rdf_size(ldns_rr_owner(rr)),
|
||||
(struct sockaddr_storage*)&sa, len)) {
|
||||
log_err("out of memory reading root hints");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
|
||||
struct sockaddr_in6 sa;
|
||||
socklen_t len = (socklen_t)sizeof(sa);
|
||||
memset(&sa, 0, len);
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
memmove(&sa.sin6_addr,
|
||||
ldns_rdf_data(ldns_rr_rdf(rr, 0)), INET6_SIZE);
|
||||
if(!delegpt_add_target(dp, hints->region,
|
||||
ldns_rdf_data(ldns_rr_owner(rr)),
|
||||
ldns_rdf_size(ldns_rr_owner(rr)),
|
||||
(struct sockaddr_storage*)&sa, len)) {
|
||||
log_err("out of memory reading root hints");
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
log_warn("root hints %s:%d skipping type %d",
|
||||
fname, lineno, ldns_rr_get_type(rr));
|
||||
}
|
||||
|
||||
ldns_rr_free(rr);
|
||||
}
|
||||
fclose(f);
|
||||
if(!dp->name) {
|
||||
log_warn("root hints %s: no NS content", fname);
|
||||
return 1;
|
||||
}
|
||||
if(!hints_insert(hints, c, dp)) {
|
||||
return 0;
|
||||
}
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** read root hints list */
|
||||
static int
|
||||
read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
for(p = cfg->root_hints; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(p->str && p->str[0]) {
|
||||
char* f = p->str;
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
strncmp(p->str, cfg->chrootdir,
|
||||
strlen(cfg->chrootdir)) == 0)
|
||||
f += strlen(cfg->chrootdir);
|
||||
if(!read_root_hints(hints, f))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -298,7 +422,10 @@ hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
|
||||
hints->tree = rbtree_create(stub_cmp);
|
||||
if(!hints->tree)
|
||||
return 0;
|
||||
/* TODO: read root hints from file named in cfg */
|
||||
|
||||
/* read root hints */
|
||||
if(!read_root_hints_list(hints, cfg))
|
||||
return 0;
|
||||
|
||||
/* read stub hints */
|
||||
if(!read_stubs(hints, cfg))
|
||||
@@ -312,7 +439,6 @@ hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg)
|
||||
return 0;
|
||||
if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp))
|
||||
return 0;
|
||||
delegpt_log(dp);
|
||||
}
|
||||
|
||||
init_parents(hints);
|
||||
@@ -380,5 +506,5 @@ size_t
|
||||
hints_get_mem(struct iter_hints* hints)
|
||||
{
|
||||
if(!hints) return 0;
|
||||
return sizeof(*hints) + region_get_mem(hints->region);
|
||||
return sizeof(*hints) + regional_get_mem(hints->region);
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct delegpt;
|
||||
struct region;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* Iterator hints structure
|
||||
*/
|
||||
struct iter_hints {
|
||||
/** region where hints are allocated */
|
||||
struct region* region;
|
||||
/** regional where hints are allocated */
|
||||
struct regional* region;
|
||||
/**
|
||||
* Hints are stored in this tree. Sort order is specially chosen.
|
||||
* first sorted on qtype. Then on dname in nsec-like order, so that
|
||||
@@ -134,4 +134,7 @@ struct delegpt* hints_lookup_stub(struct iter_hints* hints,
|
||||
*/
|
||||
size_t hints_get_mem(struct iter_hints* hints);
|
||||
|
||||
/** compare two hint entries */
|
||||
int stub_cmp(const void* k1, const void* k2);
|
||||
|
||||
#endif /* ITERATOR_ITER_HINTS_H */
|
||||
|
||||
@@ -100,8 +100,8 @@ response_type_from_cache(struct dns_msg* msg,
|
||||
}
|
||||
|
||||
enum response_type
|
||||
response_type_from_server(struct dns_msg* msg, struct query_info* request,
|
||||
struct delegpt* dp)
|
||||
response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp)
|
||||
{
|
||||
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
|
||||
size_t origzonelen = 1;
|
||||
@@ -111,8 +111,13 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request,
|
||||
return RESPONSE_TYPE_THROWAWAY;
|
||||
|
||||
/* If the message is NXDOMAIN, then it answers the question. */
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN)
|
||||
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
|
||||
/* make sure its not recursive when we don't want it to */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
/* Other response codes mean (so far) to throw the response away as
|
||||
* meaningless and move on to the next nameserver. */
|
||||
@@ -193,6 +198,10 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request,
|
||||
/* The normal way of detecting NOERROR/NODATA. */
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA &&
|
||||
dname_subdomain_c(request->qname, s->rk.dname)) {
|
||||
/* we do our own recursion, thank you */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
@@ -203,6 +212,11 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request,
|
||||
* thought we were contacting, then it is an answer.*/
|
||||
/* FIXME: is this correct? */
|
||||
if(query_dname_compare(s->rk.dname, origzone) == 0) {
|
||||
/* see if mistakenly a recursive server was
|
||||
* deployed and is responding nonAA */
|
||||
if( (msg->rep->flags&BIT_RA) &&
|
||||
!(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
/* If we are getting a referral upwards (or to
|
||||
@@ -231,5 +245,8 @@ response_type_from_server(struct dns_msg* msg, struct query_info* request,
|
||||
|
||||
/* If we've gotten this far, this is NOERROR/NODATA (which could
|
||||
* be an entirely empty message) */
|
||||
/* check if recursive answer; saying it has empty cache */
|
||||
if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset)
|
||||
return RESPONSE_TYPE_LAME;
|
||||
return RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
|
||||
@@ -107,13 +107,14 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
|
||||
* relies somewhat on the originating zone to be accurate (for lameness
|
||||
* detection, mostly).
|
||||
*
|
||||
* @param rdset: if RD bit was sent in query sent by unbound.
|
||||
* @param msg: the message from the cache.
|
||||
* @param request: the request that generated the response.
|
||||
* @param dp: The delegation point that was being queried
|
||||
* when the response was returned.
|
||||
* @return the response type (CNAME or ANSWER).
|
||||
*/
|
||||
enum response_type response_type_from_server(struct dns_msg* msg,
|
||||
struct query_info* request, struct delegpt* dp);
|
||||
enum response_type response_type_from_server(int rdset,
|
||||
struct dns_msg* msg, struct query_info* request, struct delegpt* dp);
|
||||
|
||||
#endif /* ITERATOR_ITER_RESPTYPE_H */
|
||||
|
||||
+18
-10
@@ -44,7 +44,7 @@
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
#include "util/data/msgparse.h"
|
||||
@@ -60,11 +60,11 @@ static void
|
||||
remove_rrset(const char* str, ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct rrset_parse* prev, struct rrset_parse** rrset)
|
||||
{
|
||||
if(verbosity >= VERB_DETAIL
|
||||
if(verbosity >= VERB_QUERY
|
||||
&& (*rrset)->dname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, (*rrset)->dname);
|
||||
log_nametypeclass(VERB_DETAIL, str, buf,
|
||||
log_nametypeclass(VERB_QUERY, str, buf,
|
||||
(*rrset)->type, ntohs((*rrset)->rrset_class));
|
||||
}
|
||||
if(prev)
|
||||
@@ -224,22 +224,22 @@ synth_cname(uint8_t* qname, size_t qnamelen, struct rrset_parse* dname_rrset,
|
||||
/** synthesize a CNAME rrset */
|
||||
static struct rrset_parse*
|
||||
synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
size_t aliaslen, struct region* region, struct msg_parse* msg,
|
||||
size_t aliaslen, struct regional* region, struct msg_parse* msg,
|
||||
struct rrset_parse* rrset, struct rrset_parse* prev,
|
||||
struct rrset_parse* nx, ldns_buffer* pkt)
|
||||
{
|
||||
struct rrset_parse* cn = (struct rrset_parse*)region_alloc(region,
|
||||
struct rrset_parse* cn = (struct rrset_parse*)regional_alloc(region,
|
||||
sizeof(struct rrset_parse));
|
||||
if(!cn)
|
||||
return NULL;
|
||||
memset(cn, 0, sizeof(*cn));
|
||||
cn->rr_first = (struct rr_parse*)region_alloc(region,
|
||||
cn->rr_first = (struct rr_parse*)regional_alloc(region,
|
||||
sizeof(struct rr_parse));
|
||||
if(!cn->rr_first)
|
||||
return NULL;
|
||||
cn->rr_last = cn->rr_first;
|
||||
/* CNAME from sname to alias */
|
||||
cn->dname = (uint8_t*)region_alloc(region, *snamelen);
|
||||
cn->dname = (uint8_t*)regional_alloc(region, *snamelen);
|
||||
if(!cn->dname)
|
||||
return NULL;
|
||||
dname_pkt_copy(pkt, cn->dname, *sname);
|
||||
@@ -253,7 +253,7 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
/* allocate TTL + rdatalen + uncompressed dname */
|
||||
memset(cn->rr_first, 0, sizeof(struct rr_parse));
|
||||
cn->rr_first->outside_packet = 1;
|
||||
cn->rr_first->ttl_data = (uint8_t*)region_alloc(region,
|
||||
cn->rr_first->ttl_data = (uint8_t*)regional_alloc(region,
|
||||
sizeof(uint32_t)+sizeof(uint16_t)+aliaslen);
|
||||
if(!cn->rr_first->ttl_data)
|
||||
return NULL;
|
||||
@@ -312,7 +312,7 @@ pkt_sub(ldns_buffer* pkt, uint8_t* comprname, uint8_t* zone)
|
||||
*/
|
||||
static int
|
||||
scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, struct region* region)
|
||||
struct query_info* qinfo, struct regional* region)
|
||||
{
|
||||
uint8_t* sname = qinfo->qname;
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
@@ -350,6 +350,10 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
"too long");
|
||||
return 0;
|
||||
}
|
||||
/* internally we have CNAME'd/DNAME'd chains ending
|
||||
* in nxdomain with NOERROR rcode, change rcode
|
||||
* to reflect this (if needed) */
|
||||
FLAGS_SET_RCODE(msg->flags, LDNS_RCODE_NOERROR);
|
||||
if(nx && nx->type == LDNS_RR_TYPE_CNAME &&
|
||||
dname_pkt_compare(pkt, sname, nx->dname) == 0) {
|
||||
/* check next cname */
|
||||
@@ -392,6 +396,10 @@ scrub_normalize(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
return 0;
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
/* internally we have CNAME'd/DNAME'd chains ending
|
||||
* in nxdomain with NOERROR rcode, change rcode
|
||||
* to reflect this (if needed) */
|
||||
FLAGS_SET_RCODE(msg->flags, LDNS_RCODE_NOERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -545,7 +553,7 @@ scrub_sanitize(ldns_buffer* pkt, struct msg_parse* msg, uint8_t* zonename,
|
||||
|
||||
int
|
||||
scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct region* region,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
|
||||
struct module_env* env)
|
||||
{
|
||||
/* basic sanity checks */
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#define ITERATOR_ITER_SCRUB_H
|
||||
struct msg_parse;
|
||||
struct query_info;
|
||||
struct region;
|
||||
struct regional;
|
||||
struct module_env;
|
||||
|
||||
/**
|
||||
@@ -55,12 +55,12 @@ struct module_env;
|
||||
* @param qinfo: the query info that was sent to the server. Checked.
|
||||
* @param zonename: the name of the last delegation point.
|
||||
* Used to determine out of bailiwick information.
|
||||
* @param region: where to allocate (new) parts of the message.
|
||||
* @param regional: where to allocate (new) parts of the message.
|
||||
* @param env: module environment with config settings and cache.
|
||||
* @return: false if the message is total waste. true if scrubbed with success.
|
||||
*/
|
||||
int scrub_message(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct region* region,
|
||||
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
|
||||
struct module_env* env);
|
||||
|
||||
#endif /* ITERATOR_ITER_SCRUB_H */
|
||||
|
||||
+124
-16
@@ -53,10 +53,12 @@
|
||||
#include "util/module.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/random.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "validator/val_anchor.h"
|
||||
|
||||
/** fillup fetch policy array */
|
||||
static void
|
||||
@@ -100,7 +102,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
if(!read_fetch_policy(iter_env, cfg->target_fetch_policy))
|
||||
return 0;
|
||||
for(i=0; i<iter_env->max_dependency_depth+1; i++)
|
||||
verbose(VERB_DETAIL, "target fetch policy for level %d is %d",
|
||||
verbose(VERB_QUERY, "target fetch policy for level %d is %d",
|
||||
i, iter_env->target_fetch_policy[i]);
|
||||
|
||||
if(!iter_env->hints)
|
||||
@@ -132,19 +134,22 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
{
|
||||
int rtt;
|
||||
int lame;
|
||||
int dnsseclame;
|
||||
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
|
||||
return -1; /* server is on the donotquery list */
|
||||
}
|
||||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr)) {
|
||||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip6 available */
|
||||
}
|
||||
/* check lameness - need zone , class info */
|
||||
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
|
||||
name, namelen, &lame, &rtt, now)) {
|
||||
name, namelen, &lame, &dnsseclame, &rtt, now)) {
|
||||
if(lame)
|
||||
return -1; /* server is lame */
|
||||
else if(rtt >= USEFUL_SERVER_TOP_TIMEOUT)
|
||||
return -1; /* server is unresponsive */
|
||||
else if(dnsseclame)
|
||||
return rtt+USEFUL_SERVER_TOP_TIMEOUT; /* nonpref */
|
||||
else return rtt;
|
||||
}
|
||||
/* no server information present */
|
||||
@@ -155,7 +160,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
* returns number of best targets (or 0, no suitable targets) */
|
||||
static int
|
||||
iter_filter_order(struct iter_env* iter_env, struct module_env* env,
|
||||
uint8_t* name, size_t namelen, time_t now, struct delegpt* dp)
|
||||
uint8_t* name, size_t namelen, time_t now, struct delegpt* dp,
|
||||
int* best_rtt)
|
||||
{
|
||||
int got_num = 0, got_rtt = 0, thisrtt, swap_to_front;
|
||||
struct delegpt_addr* a, *n, *prev=NULL;
|
||||
@@ -196,23 +202,30 @@ iter_filter_order(struct iter_env* iter_env, struct module_env* env,
|
||||
a = a->next_result;
|
||||
}
|
||||
}
|
||||
*best_rtt = got_rtt;
|
||||
return got_num;
|
||||
}
|
||||
|
||||
struct delegpt_addr*
|
||||
iter_server_selection(struct iter_env* iter_env,
|
||||
struct module_env* env, struct delegpt* dp,
|
||||
uint8_t* name, size_t namelen)
|
||||
uint8_t* name, size_t namelen, int* dnssec_expected)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
int sel;
|
||||
int selrtt;
|
||||
struct delegpt_addr* a, *prev;
|
||||
int num = iter_filter_order(iter_env, env, name, namelen, now, dp);
|
||||
int num = iter_filter_order(iter_env, env, name, namelen, now, dp,
|
||||
&selrtt);
|
||||
|
||||
if(num == 0)
|
||||
return NULL;
|
||||
if(selrtt >= USEFUL_SERVER_TOP_TIMEOUT)
|
||||
*dnssec_expected = 0;
|
||||
if(num == 1) {
|
||||
a = dp->result_list;
|
||||
if(++a->attempts < OUTBOUND_MSG_RETRY)
|
||||
return a;
|
||||
dp->result_list = a->next_result;
|
||||
return a;
|
||||
}
|
||||
@@ -230,6 +243,8 @@ iter_server_selection(struct iter_env* iter_env,
|
||||
}
|
||||
if(!a) /* robustness */
|
||||
return NULL;
|
||||
if(++a->attempts < OUTBOUND_MSG_RETRY)
|
||||
return a;
|
||||
/* remove it from the delegation point result list */
|
||||
if(prev)
|
||||
prev->next_result = a->next_result;
|
||||
@@ -238,9 +253,10 @@ iter_server_selection(struct iter_env* iter_env,
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg, struct region* region)
|
||||
dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct regional* region)
|
||||
{
|
||||
struct dns_msg* m = (struct dns_msg*)region_alloc(region,
|
||||
struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
|
||||
sizeof(struct dns_msg));
|
||||
if(!m)
|
||||
return NULL;
|
||||
@@ -253,14 +269,14 @@ dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg, struct region* region)
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
dns_copy_msg(struct dns_msg* from, struct region* region)
|
||||
dns_copy_msg(struct dns_msg* from, struct regional* region)
|
||||
{
|
||||
struct dns_msg* m = (struct dns_msg*)region_alloc(region,
|
||||
struct dns_msg* m = (struct dns_msg*)regional_alloc(region,
|
||||
sizeof(struct dns_msg));
|
||||
if(!m)
|
||||
return NULL;
|
||||
m->qinfo = from->qinfo;
|
||||
if(!(m->qinfo.qname = region_alloc_init(region, from->qinfo.qname,
|
||||
if(!(m->qinfo.qname = regional_alloc_init(region, from->qinfo.qname,
|
||||
from->qinfo.qname_len)))
|
||||
return NULL;
|
||||
if(!(m->rep = reply_info_copy(from->rep, NULL, region)))
|
||||
@@ -297,6 +313,8 @@ causes_cycle(struct module_qstate* qstate, uint8_t* name, size_t namelen,
|
||||
qinf.qname_len = namelen;
|
||||
qinf.qtype = t;
|
||||
qinf.qclass = c;
|
||||
log_assert(fptr_whitelist_modenv_detect_cycle(
|
||||
qstate->env->detect_cycle));
|
||||
return (*qstate->env->detect_cycle)(qstate, &qinf,
|
||||
(uint16_t)(BIT_RD|BIT_CD), qstate->is_priming);
|
||||
}
|
||||
@@ -313,9 +331,10 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
|
||||
LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
|
||||
causes_cycle(qstate, ns->name, ns->namelen,
|
||||
LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
|
||||
log_nametypeclass(VERB_DETAIL, "skipping target due "
|
||||
log_nametypeclass(VERB_QUERY, "skipping target due "
|
||||
"to dependency cycle (harden-glue: no may "
|
||||
"fix this)", ns->name, LDNS_RR_TYPE_A,
|
||||
"fix some of the cycles)",
|
||||
ns->name, LDNS_RR_TYPE_A,
|
||||
qstate->qinfo.qclass);
|
||||
ns->resolved = 1;
|
||||
}
|
||||
@@ -323,20 +342,33 @@ iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
|
||||
}
|
||||
|
||||
int
|
||||
iter_dp_is_useless(uint16_t flags, struct delegpt* dp)
|
||||
iter_dp_is_useless(struct module_qstate* qstate, struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
/* check:
|
||||
* o all NS items are required glue.
|
||||
* o no addresses are provided.
|
||||
* o RD qflag is on.
|
||||
* OR
|
||||
* o no addresses are provided.
|
||||
* o RD qflag is on.
|
||||
* o the query is for one of the nameservers in dp,
|
||||
* and that nameserver is a glue-name for this dp.
|
||||
*/
|
||||
if(!(flags&BIT_RD))
|
||||
if(!(qstate->query_flags&BIT_RD))
|
||||
return 0;
|
||||
/* either available or unused targets */
|
||||
if(dp->usable_list || dp->result_list)
|
||||
return 0;
|
||||
|
||||
/* see if query is for one of the nameservers, which is glue */
|
||||
if( (qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) &&
|
||||
dname_subdomain_c(qstate->qinfo.qname, dp->name) &&
|
||||
delegpt_find_ns(dp, qstate->qinfo.qname,
|
||||
qstate->qinfo.qname_len))
|
||||
return 1;
|
||||
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
if(ns->resolved) /* skip failed targets */
|
||||
continue;
|
||||
@@ -345,3 +377,79 @@ iter_dp_is_useless(uint16_t flags, struct delegpt* dp)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
|
||||
struct dns_msg* msg, uint16_t dclass)
|
||||
{
|
||||
/* information not available, !env->anchors can be common */
|
||||
if(!env || !env->anchors || !dp || !dp->name || !msg || !msg->rep)
|
||||
return 0;
|
||||
/* a trust anchor exists with this name, RRSIGs expected */
|
||||
if(anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
|
||||
dclass))
|
||||
return 1;
|
||||
/* see if DS rrset was given, in AUTH section */
|
||||
if(reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_DS, dclass))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
iter_msg_has_dnssec(struct dns_msg* msg)
|
||||
{
|
||||
size_t i;
|
||||
if(!msg || !msg->rep)
|
||||
return 0;
|
||||
for(i=0; i<msg->rep->an_numrrsets + msg->rep->ns_numrrsets; i++) {
|
||||
if(((struct packed_rrset_data*)msg->rep->rrsets[i]->
|
||||
entry.data)->rrsig_count > 0)
|
||||
return 1;
|
||||
}
|
||||
/* empty message has no DNSSEC info, with DNSSEC the reply is
|
||||
* not empty (NSEC) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
|
||||
enum response_type type, uint16_t dclass)
|
||||
{
|
||||
if(!msg || !dp || !msg->rep || !dp->name)
|
||||
return 0;
|
||||
/* SOA RRset - always from reply zone */
|
||||
if(reply_find_rrset_section_an(msg->rep, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_SOA, dclass) ||
|
||||
reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_SOA, dclass))
|
||||
return 1;
|
||||
if(type == RESPONSE_TYPE_REFERRAL) {
|
||||
size_t i;
|
||||
/* if it adds a single label, i.e. we expect .com,
|
||||
* and referral to example.com. NS ... , then origin zone
|
||||
* is .com. For a referral to sub.example.com. NS ... then
|
||||
* we do not know, since example.com. may be in between. */
|
||||
for(i=0; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets;
|
||||
i++) {
|
||||
struct ub_packed_rrset_key* s = msg->rep->rrsets[i];
|
||||
if(ntohs(s->rk.type) == LDNS_RR_TYPE_NS &&
|
||||
ntohs(s->rk.rrset_class) == dclass) {
|
||||
int l = dname_count_labels(s->rk.dname);
|
||||
if(l == dp->namelabs + 1 &&
|
||||
dname_strict_subdomain(s->rk.dname,
|
||||
l, dp->name, dp->namelabs))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
log_assert(type==RESPONSE_TYPE_ANSWER || type==RESPONSE_TYPE_CNAME);
|
||||
/* not a referral, and not lame delegation (upwards), so,
|
||||
* any NS rrset must be from the zone itself */
|
||||
if(reply_find_rrset_section_an(msg->rep, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_NS, dclass) ||
|
||||
reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
|
||||
LDNS_RR_TYPE_NS, dclass))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+53
-12
@@ -42,12 +42,13 @@
|
||||
|
||||
#ifndef ITERATOR_ITER_UTILS_H
|
||||
#define ITERATOR_ITER_UTILS_H
|
||||
#include "iterator/iter_resptype.h"
|
||||
struct iter_env;
|
||||
struct config_file;
|
||||
struct module_env;
|
||||
struct delegpt_addr;
|
||||
struct delegpt;
|
||||
struct region;
|
||||
struct regional;
|
||||
struct msg_parse;
|
||||
struct ub_randstate;
|
||||
struct query_info;
|
||||
@@ -73,30 +74,32 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
|
||||
* @param dp: delegation point with result list.
|
||||
* @param name: zone name (for lameness check).
|
||||
* @param namelen: length of name.
|
||||
* @param dnssec_expected: set to 0, if a known dnssec-lame server is selected
|
||||
* these are not preferred, but are used as a last resort.
|
||||
* @return best target or NULL if no target.
|
||||
* if not null, that target is removed from the result list in the dp.
|
||||
*/
|
||||
struct delegpt_addr* iter_server_selection(struct iter_env* iter_env,
|
||||
struct module_env* env, struct delegpt* dp, uint8_t* name,
|
||||
size_t namelen);
|
||||
size_t namelen, int* dnssec_expected);
|
||||
|
||||
/**
|
||||
* Allocate dns_msg from parsed msg, in region.
|
||||
* Allocate dns_msg from parsed msg, in regional.
|
||||
* @param pkt: packet.
|
||||
* @param msg: parsed message (cleaned and ready for region allocation).
|
||||
* @param region: region to use for allocation.
|
||||
* @param msg: parsed message (cleaned and ready for regional allocation).
|
||||
* @param regional: regional to use for allocation.
|
||||
* @return newly allocated dns_msg, or NULL on memory error.
|
||||
*/
|
||||
struct dns_msg* dns_alloc_msg(ldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct region* region);
|
||||
struct regional* regional);
|
||||
|
||||
/**
|
||||
* Copy a dns_msg to this region.
|
||||
* @param from: dns message, also in region.
|
||||
* @param region: region to use for allocation.
|
||||
* Copy a dns_msg to this regional.
|
||||
* @param from: dns message, also in regional.
|
||||
* @param regional: regional to use for allocation.
|
||||
* @return newly allocated dns_msg, or NULL on memory error.
|
||||
*/
|
||||
struct dns_msg* dns_copy_msg(struct dns_msg* from, struct region* region);
|
||||
struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
|
||||
|
||||
/**
|
||||
* Allocate a dns_msg with malloc/alloc structure and store in dns cache.
|
||||
@@ -131,9 +134,47 @@ void iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp);
|
||||
/**
|
||||
* See if delegation is useful or offers immediately no targets for
|
||||
* further recursion.
|
||||
* @param flags: query flags.
|
||||
* @param qstate: query state with RD flag and query name.
|
||||
* @param dp: delegpt to check.
|
||||
*/
|
||||
int iter_dp_is_useless(uint16_t flags, struct delegpt* dp);
|
||||
int iter_dp_is_useless(struct module_qstate* qstate, struct delegpt* dp);
|
||||
|
||||
/**
|
||||
* See if delegation is expected to have DNSSEC information (RRSIGs) in
|
||||
* its answers, or not. Inspects delegation point (name), trust anchors,
|
||||
* and delegation message (DS RRset) to determine this.
|
||||
* @param env: module env with trust anchors.
|
||||
* @param dp: delegation point.
|
||||
* @param msg: delegation message, with DS if a secure referral.
|
||||
* @param dclass: class of query.
|
||||
* @return 1 if dnssec is expected, 0 if not.
|
||||
*/
|
||||
int iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
|
||||
struct dns_msg* msg, uint16_t dclass);
|
||||
|
||||
/**
|
||||
* See if a message contains DNSSEC.
|
||||
* This is examined by looking for RRSIGs. With DNSSEC a valid answer,
|
||||
* nxdomain, nodata, referral or cname reply has RRSIGs in answer or auth
|
||||
* sections, sigs on answer data, SOA, DS, or NSEC/NSEC3 records.
|
||||
* @param msg: message to examine.
|
||||
* @return true if DNSSEC information was found.
|
||||
*/
|
||||
int iter_msg_has_dnssec(struct dns_msg* msg);
|
||||
|
||||
/**
|
||||
* See if a message is known to be from a certain zone.
|
||||
* This looks for SOA or NS rrsets, for answers.
|
||||
* For referrals, when one label is delegated, the zone is detected.
|
||||
* Does not look at signatures.
|
||||
* @param msg: the message to inspect.
|
||||
* @param dp: delegation point with zone name to look for.
|
||||
* @param type: type of message.
|
||||
* @param dclass: class of query.
|
||||
* @return true if message is certain to be from zone in dp->name.
|
||||
* false if not sure (empty msg), or not from the zone.
|
||||
*/
|
||||
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
|
||||
enum response_type type, uint16_t dclass);
|
||||
|
||||
#endif /* ITERATOR_ITER_UTILS_H */
|
||||
|
||||
+144
-67
@@ -54,12 +54,12 @@
|
||||
#include "util/module.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
/** iterator init */
|
||||
static int
|
||||
int
|
||||
iter_init(struct module_env* env, int id)
|
||||
{
|
||||
struct iter_env* iter_env = (struct iter_env*)calloc(1,
|
||||
@@ -76,12 +76,11 @@ iter_init(struct module_env* env, int id)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** iterator deinit */
|
||||
static void
|
||||
void
|
||||
iter_deinit(struct module_env* env, int id)
|
||||
{
|
||||
struct iter_env* iter_env;
|
||||
if(!env || !env->modinfo || !env->modinfo[id])
|
||||
if(!env || !env->modinfo[id])
|
||||
return;
|
||||
iter_env = (struct iter_env*)env->modinfo[id];
|
||||
free(iter_env->target_fetch_policy);
|
||||
@@ -89,13 +88,14 @@ iter_deinit(struct module_env* env, int id)
|
||||
forwards_delete(iter_env->fwds);
|
||||
donotq_delete(iter_env->donotq);
|
||||
free(iter_env);
|
||||
env->modinfo[id] = NULL;
|
||||
}
|
||||
|
||||
/** new query for iterator */
|
||||
static int
|
||||
iter_new(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct iter_qstate* iq = (struct iter_qstate*)region_alloc(
|
||||
struct iter_qstate* iq = (struct iter_qstate*)regional_alloc(
|
||||
qstate->region, sizeof(struct iter_qstate));
|
||||
qstate->minfo[id] = iq;
|
||||
if(!iq)
|
||||
@@ -115,6 +115,7 @@ iter_new(struct module_qstate* qstate, int id)
|
||||
iq->referral_count = 0;
|
||||
iq->wait_priming_stub = 0;
|
||||
iq->refetch_glue = 0;
|
||||
iq->dnssec_expected = 0;
|
||||
iq->chase_flags = qstate->query_flags;
|
||||
/* Start with the (current) qname. */
|
||||
iq->qchase = qstate->qinfo;
|
||||
@@ -187,7 +188,8 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
/* not interested */
|
||||
verbose(VERB_ALGO, "subq error, but not interested");
|
||||
log_query_info(VERB_ALGO, "superq", &super->qinfo);
|
||||
delegpt_log(super_iq->dp);
|
||||
if(super_iq->dp)
|
||||
delegpt_log(VERB_ALGO, super_iq->dp);
|
||||
log_assert(0);
|
||||
return;
|
||||
}
|
||||
@@ -214,7 +216,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
static int
|
||||
error_response(struct module_qstate* qstate, int id, int rcode)
|
||||
{
|
||||
verbose(VERB_DETAIL, "return error response %s",
|
||||
verbose(VERB_QUERY, "return error response %s",
|
||||
ldns_lookup_by_id(ldns_rcodes, rcode)?
|
||||
ldns_lookup_by_id(ldns_rcodes, rcode)->name:"??");
|
||||
qstate->return_rcode = rcode;
|
||||
@@ -223,10 +225,27 @@ error_response(struct module_qstate* qstate, int id, int rcode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** check if prepend item is duplicate item */
|
||||
static int
|
||||
prepend_is_duplicate(struct ub_packed_rrset_key** sets, size_t to,
|
||||
struct ub_packed_rrset_key* dup)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<to; i++) {
|
||||
if(sets[i]->rk.type == dup->rk.type &&
|
||||
sets[i]->rk.rrset_class == dup->rk.rrset_class &&
|
||||
sets[i]->rk.dname_len == dup->rk.dname_len &&
|
||||
query_dname_compare(sets[i]->rk.dname, dup->rk.dname)
|
||||
== 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** prepend the prepend list in the answer and authority section of dns_msg */
|
||||
static int
|
||||
iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
|
||||
struct region* region)
|
||||
struct regional* region)
|
||||
{
|
||||
struct iter_prep_list* p;
|
||||
struct ub_packed_rrset_key** sets;
|
||||
@@ -238,7 +257,7 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
|
||||
if(num_an + num_ns == 0)
|
||||
return 1;
|
||||
verbose(VERB_ALGO, "prepending %d rrsets", (int)num_an + (int)num_ns);
|
||||
sets = region_alloc(region, (num_an+num_ns+msg->rep->rrset_count) *
|
||||
sets = regional_alloc(region, (num_an+num_ns+msg->rep->rrset_count) *
|
||||
sizeof(struct ub_packed_rrset_key*));
|
||||
if(!sets)
|
||||
return 0;
|
||||
@@ -252,6 +271,11 @@ iter_prepend(struct iter_qstate* iq, struct dns_msg* msg,
|
||||
/* AUTH section */
|
||||
num_ns = 0;
|
||||
for(p = iq->ns_prepend_list; p; p = p->next) {
|
||||
if(prepend_is_duplicate(sets+msg->rep->an_numrrsets+num_an,
|
||||
num_ns, p->rrset) || prepend_is_duplicate(
|
||||
msg->rep->rrsets+msg->rep->an_numrrsets,
|
||||
msg->rep->ns_numrrsets, p->rrset))
|
||||
continue;
|
||||
sets[msg->rep->an_numrrsets + num_an + num_ns++] = p->rrset;
|
||||
}
|
||||
memcpy(sets + num_an + msg->rep->an_numrrsets + num_ns,
|
||||
@@ -282,7 +306,7 @@ static int
|
||||
iter_add_prepend_answer(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
struct iter_prep_list* p = (struct iter_prep_list*)region_alloc(
|
||||
struct iter_prep_list* p = (struct iter_prep_list*)regional_alloc(
|
||||
qstate->region, sizeof(struct iter_prep_list));
|
||||
if(!p)
|
||||
return 0;
|
||||
@@ -307,7 +331,7 @@ static int
|
||||
iter_add_prepend_auth(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
struct iter_prep_list* p = (struct iter_prep_list*)region_alloc(
|
||||
struct iter_prep_list* p = (struct iter_prep_list*)regional_alloc(
|
||||
qstate->region, sizeof(struct iter_prep_list));
|
||||
if(!p)
|
||||
return 0;
|
||||
@@ -432,6 +456,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
qflags |= BIT_CD;
|
||||
|
||||
/* attach subquery, lookup existing or make a new one */
|
||||
log_assert(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, &subq)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -440,10 +465,12 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
/* initialise the new subquery */
|
||||
subq->curmod = id;
|
||||
subq->ext_state[id] = module_state_initial;
|
||||
subq->minfo[id] = region_alloc(subq->region,
|
||||
subq->minfo[id] = regional_alloc(subq->region,
|
||||
sizeof(struct iter_qstate));
|
||||
if(!subq->minfo[id]) {
|
||||
log_err("init subq: out of memory");
|
||||
log_assert(fptr_whitelist_modenv_kill_sub(
|
||||
qstate->env->kill_sub));
|
||||
(*qstate->env->kill_sub)(subq);
|
||||
return 0;
|
||||
}
|
||||
@@ -476,7 +503,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
{
|
||||
struct delegpt* dp;
|
||||
struct module_qstate* subq;
|
||||
verbose(VERB_ALGO, "priming . NS %s",
|
||||
verbose(VERB_DETAIL, "priming . %s NS",
|
||||
ldns_lookup_by_id(ldns_rr_classes, (int)qclass)?
|
||||
ldns_lookup_by_id(ldns_rr_classes, (int)qclass)->name:"??");
|
||||
dp = hints_lookup_root(ie->hints, qclass);
|
||||
@@ -560,6 +587,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
subiq->dp = delegpt_copy(stub_dp, subq->region);
|
||||
if(!subiq->dp) {
|
||||
log_err("out of memory priming stub, copydp");
|
||||
log_assert(fptr_whitelist_modenv_kill_sub(
|
||||
qstate->env->kill_sub));
|
||||
(*qstate->env->kill_sub)(subq);
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
return 1; /* return 1 to make module stop, with error */
|
||||
@@ -633,7 +662,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* We enforce a maximum number of query restarts. This is primarily a
|
||||
* cheap way to prevent CNAME loops. */
|
||||
if(iq->query_restart_count > MAX_RESTART_COUNT) {
|
||||
verbose(VERB_DETAIL, "request has exceeded the maximum number"
|
||||
verbose(VERB_QUERY, "request has exceeded the maximum number"
|
||||
" of query restarts with %d", iq->query_restart_count);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
@@ -644,7 +673,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* of work required to answer a given query. */
|
||||
verbose(VERB_ALGO, "request has dependency depth of %d", iq->depth);
|
||||
if(iq->depth > ie->max_dependency_depth) {
|
||||
verbose(VERB_DETAIL, "request has exceeded the maximum "
|
||||
verbose(VERB_QUERY, "request has exceeded the maximum "
|
||||
"dependency depth with depth of %d", iq->depth);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
@@ -661,7 +690,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* handle positive cache response */
|
||||
enum response_type type = response_type_from_cache(msg,
|
||||
&iq->qchase);
|
||||
log_dns_msg("msg from cache lookup", &msg->qinfo, msg->rep);
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("msg from cache lookup", &msg->qinfo,
|
||||
msg->rep);
|
||||
|
||||
if(type == RESPONSE_TYPE_CNAME) {
|
||||
uint8_t* sname = 0;
|
||||
@@ -706,6 +737,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* When re-fetching glue we also need to ask the parent.
|
||||
*/
|
||||
if(iq->refetch_glue) {
|
||||
if(!iq->dp) {
|
||||
log_err("internal or malloc fail: no dp for refetch");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
delname = iq->dp->name;
|
||||
delnamelen = iq->dp->namelen;
|
||||
} else {
|
||||
@@ -716,11 +751,12 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
&& !dname_is_root(delname)) {
|
||||
/* do not adjust root label, remove first label from delname */
|
||||
dname_remove_label(&delname, &delnamelen);
|
||||
iq->refetch_glue = 0; /* if CNAME causes restart, no refetch */
|
||||
}
|
||||
while(1) {
|
||||
|
||||
/* Lookup the delegation in the cache. If null, then the cache needs
|
||||
* to be primed for the qclass. */
|
||||
/* Lookup the delegation in the cache. If null, then the
|
||||
* cache needs to be primed for the qclass. */
|
||||
iq->dp = dns_cache_find_delegation(qstate->env, delname,
|
||||
delnamelen, iq->qchase.qtype, iq->qchase.qclass,
|
||||
qstate->region, &iq->deleg_msg, (uint32_t)time(NULL));
|
||||
@@ -743,7 +779,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* see if this dp not useless.
|
||||
* It is useless if:
|
||||
* o all NS items are required glue.
|
||||
* o all NS items are required glue.
|
||||
* or the query is for NS item that is required glue.
|
||||
* o no addresses are provided.
|
||||
* o RD qflag is on.
|
||||
* Instead, go up one level, and try to get even further
|
||||
@@ -752,10 +789,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* could be useless but lead to loops (bumping into the
|
||||
* same server reply) if useless-checked.
|
||||
*/
|
||||
if(iter_dp_is_useless(qstate->query_flags, iq->dp)) {
|
||||
if(iter_dp_is_useless(qstate, iq->dp)) {
|
||||
if(dname_is_root(iq->dp->name)) {
|
||||
/* use safety belt */
|
||||
verbose(VERB_OPS, "Priming problem: NS but "
|
||||
verbose(VERB_QUERY, "Cache has root NS but "
|
||||
"no addresses. Fallback to the safety belt.");
|
||||
iq->dp = hints_lookup_root(ie->hints,
|
||||
iq->qchase.qclass);
|
||||
@@ -774,8 +811,9 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
log_info("cache delegation was useless:");
|
||||
delegpt_log(iq->dp);
|
||||
verbose(VERB_ALGO,
|
||||
"cache delegation was useless:");
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
/* go up */
|
||||
delname = iq->dp->name;
|
||||
delnamelen = iq->dp->namelen;
|
||||
@@ -784,10 +822,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
} else break;
|
||||
}
|
||||
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
log_info("cache delegation returns delegpt");
|
||||
delegpt_log(iq->dp);
|
||||
}
|
||||
verbose(VERB_ALGO, "cache delegation returns delegpt");
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
|
||||
/* if the cache reply dp equals a validation anchor or msg has DS,
|
||||
* then DNSSEC RRSIGs are expected in the reply */
|
||||
iq->dnssec_expected = iter_indicates_dnssec(qstate->env, iq->dp,
|
||||
iq->deleg_msg, iq->qchase.qclass);
|
||||
|
||||
/* Reset the RD flag. If this is a query restart, then the RD
|
||||
* will have been turned off. */
|
||||
@@ -820,7 +861,7 @@ static int
|
||||
processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
struct iter_env* ie, int id)
|
||||
{
|
||||
log_query_info(VERB_DETAIL, "resolving (init part 2): ",
|
||||
log_query_info(VERB_QUERY, "resolving (init part 2): ",
|
||||
&qstate->qinfo);
|
||||
|
||||
/* Check to see if we need to prime a stub zone. */
|
||||
@@ -847,7 +888,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
static int
|
||||
processInitRequest3(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
log_query_info(VERB_DETAIL, "resolving (init part 3): ",
|
||||
log_query_info(VERB_QUERY, "resolving (init part 3): ",
|
||||
&qstate->qinfo);
|
||||
/* If the RD flag wasn't set, then we just finish with the
|
||||
* cached referral as the response. */
|
||||
@@ -897,7 +938,7 @@ generate_target_query(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
subiq->dp = delegpt_copy(iq->dp, subq->region);
|
||||
}
|
||||
}
|
||||
log_nametypeclass(VERB_DETAIL, "new target", name, qtype, qclass);
|
||||
log_nametypeclass(VERB_QUERY, "new target", name, qtype, qclass);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1011,7 +1052,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* needs to send a query to. That is, at least one per referral,
|
||||
* more if some targets timeout or return throwaway answers. */
|
||||
|
||||
log_query_info(VERB_DETAIL, "processQueryTargets:", &qstate->qinfo);
|
||||
log_query_info(VERB_QUERY, "processQueryTargets:", &qstate->qinfo);
|
||||
verbose(VERB_ALGO, "processQueryTargets: targetqueries %d, "
|
||||
"currentqueries %d", iq->num_target_queries,
|
||||
iq->num_current_queries);
|
||||
@@ -1020,7 +1061,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* Make sure that we haven't run away */
|
||||
/* FIXME: is this check even necessary? */
|
||||
if(iq->referral_count > MAX_REFERRAL_COUNT) {
|
||||
verbose(VERB_DETAIL, "request has exceeded the maximum "
|
||||
verbose(VERB_QUERY, "request has exceeded the maximum "
|
||||
"number of referrrals with %d", iq->referral_count);
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
@@ -1028,10 +1069,10 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* Make sure we have a delegation point, otherwise priming failed
|
||||
* or another failure occurred */
|
||||
if(!iq->dp) {
|
||||
verbose(VERB_DETAIL, "Failed to get a delegation, giving up");
|
||||
verbose(VERB_QUERY, "Failed to get a delegation, giving up");
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
delegpt_log(iq->dp);
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
|
||||
if(iq->num_current_queries>0) {
|
||||
/* already busy answering a query, this restart is because
|
||||
@@ -1065,7 +1106,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
|
||||
/* Select the next usable target, filtering out unsuitable targets. */
|
||||
target = iter_server_selection(ie, qstate->env, iq->dp,
|
||||
iq->dp->name, iq->dp->namelen);
|
||||
iq->dp->name, iq->dp->namelen, &iq->dnssec_expected);
|
||||
|
||||
/* If no usable target was selected... */
|
||||
if(!target) {
|
||||
@@ -1096,7 +1137,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* Since a target query might have been made, we
|
||||
* need to check again. */
|
||||
if(iq->num_target_queries == 0) {
|
||||
verbose(VERB_DETAIL, "out of query targets -- "
|
||||
verbose(VERB_QUERY, "out of query targets -- "
|
||||
"returning SERVFAIL");
|
||||
/* fail -- no more targets, no more hope
|
||||
* of targets, no hope of a response. */
|
||||
@@ -1123,17 +1164,20 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
|
||||
/* We have a valid target. */
|
||||
log_query_info(VERB_DETAIL, "sending query:", &iq->qchase);
|
||||
log_name_addr(VERB_DETAIL, "sending to target:", iq->dp->name,
|
||||
log_query_info(VERB_QUERY, "sending query:", &iq->qchase);
|
||||
log_name_addr(VERB_QUERY, "sending to target:", iq->dp->name,
|
||||
&target->addr, target->addrlen);
|
||||
log_assert(fptr_whitelist_modenv_send_query(qstate->env->send_query));
|
||||
outq = (*qstate->env->send_query)(
|
||||
iq->qchase.qname, iq->qchase.qname_len,
|
||||
iq->qchase.qtype, iq->qchase.qclass,
|
||||
iq->chase_flags, EDNS_DO|BIT_CD,
|
||||
&target->addr, target->addrlen, qstate);
|
||||
if(!outq) {
|
||||
log_err("error sending query to auth server; skip this address");
|
||||
log_addr("error for address:", &target->addr, target->addrlen);
|
||||
verbose(VERB_OPS, "error sending query to auth server; "
|
||||
"skip this address");
|
||||
log_addr(VERB_OPS, "error for address:",
|
||||
&target->addr, target->addrlen);
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
outbound_list_insert(&iq->outlist, outq);
|
||||
@@ -1160,18 +1204,36 @@ static int
|
||||
processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int id)
|
||||
{
|
||||
int dnsseclame = 0;
|
||||
enum response_type type;
|
||||
iq->num_current_queries--;
|
||||
if(iq->response == NULL) {
|
||||
verbose(VERB_ALGO, "query response was timeout");
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
}
|
||||
type = response_type_from_server(iq->response, &iq->qchase, iq->dp);
|
||||
type = response_type_from_server((int)(iq->chase_flags&BIT_RD),
|
||||
iq->response, &iq->qchase, iq->dp);
|
||||
if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD)) {
|
||||
/* When forwarding (RD bit is set), we handle referrals
|
||||
* differently. No queries should be sent elsewhere */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
}
|
||||
if(iq->dnssec_expected && !(iq->chase_flags&BIT_RD)
|
||||
&& type != RESPONSE_TYPE_LAME
|
||||
&& type != RESPONSE_TYPE_THROWAWAY
|
||||
&& type != RESPONSE_TYPE_UNTYPED) {
|
||||
/* a possible answer, see if it is missing DNSSEC */
|
||||
/* but not when forwarding, so we dont mark fwder lame */
|
||||
/* also make sure the answer is from the zone we expected,
|
||||
* otherwise, (due to parent,child on same server), we
|
||||
* might mark the server,zone lame inappropriately */
|
||||
if(!iter_msg_has_dnssec(iq->response) &&
|
||||
iter_msg_from_zone(iq->response, iq->dp, type,
|
||||
iq->qchase.qclass)) {
|
||||
type = RESPONSE_TYPE_LAME;
|
||||
dnsseclame = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle each of the type cases */
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
@@ -1184,6 +1246,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* close down outstanding requests to be discarded */
|
||||
outbound_list_clear(&iq->outlist);
|
||||
iq->num_current_queries = 0;
|
||||
log_assert(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
return final_state(iq);
|
||||
@@ -1206,9 +1270,13 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(!cache_fill_missing(qstate->env, iq->qchase.qclass,
|
||||
qstate->region, iq->dp))
|
||||
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
delegpt_log(iq->dp);
|
||||
delegpt_log(VERB_ALGO, iq->dp);
|
||||
/* Count this as a referral. */
|
||||
iq->referral_count++;
|
||||
/* see if the next dp is a trust anchor, or a DS was sent
|
||||
* along, indicating dnssec is expected for next zone */
|
||||
iq->dnssec_expected = iter_indicates_dnssec(qstate->env,
|
||||
iq->dp, iq->response, iq->qchase.qclass);
|
||||
|
||||
/* stop current outstanding queries.
|
||||
* FIXME: should the outstanding queries be waited for and
|
||||
@@ -1216,6 +1284,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
*/
|
||||
outbound_list_clear(&iq->outlist);
|
||||
iq->num_current_queries = 0;
|
||||
log_assert(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
verbose(VERB_ALGO, "cleared outbound list for next round");
|
||||
@@ -1227,7 +1297,9 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* reset of the query state and go back to INIT_REQUEST_STATE).
|
||||
*/
|
||||
verbose(VERB_DETAIL, "query response was CNAME");
|
||||
log_dns_msg("cname msg", &iq->response->qinfo, iq->response->rep);
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("cname msg", &iq->response->qinfo,
|
||||
iq->response->rep);
|
||||
/* Process the CNAME response. */
|
||||
if(!handle_cname_response(qstate, iq, iq->response,
|
||||
&sname, &snamelen))
|
||||
@@ -1244,6 +1316,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* Clear the query state, since this is a query restart. */
|
||||
iq->deleg_msg = NULL;
|
||||
iq->dp = NULL;
|
||||
iq->dnssec_expected = 0;
|
||||
/* Note the query restart. */
|
||||
iq->query_restart_count++;
|
||||
|
||||
@@ -1253,6 +1326,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
*/
|
||||
outbound_list_clear(&iq->outlist);
|
||||
iq->num_current_queries = 0;
|
||||
log_assert(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
verbose(VERB_ALGO, "cleared outbound list for query restart");
|
||||
@@ -1260,15 +1335,18 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
} else if(type == RESPONSE_TYPE_LAME) {
|
||||
/* Cache the LAMEness. */
|
||||
verbose(VERB_DETAIL, "query response was LAME");
|
||||
verbose(VERB_DETAIL, "query response was %sLAME",
|
||||
dnsseclame?"DNSSEC ":"");
|
||||
if(qstate->reply) {
|
||||
/* need addr for lameness cache, but we may have
|
||||
* gotten this from cache, so test to be sure */
|
||||
if(!infra_set_lame(qstate->env->infra_cache,
|
||||
&qstate->reply->addr, qstate->reply->addrlen,
|
||||
iq->dp->name, iq->dp->namelen, time(NULL)))
|
||||
iq->dp->name, iq->dp->namelen, time(NULL),
|
||||
dnsseclame))
|
||||
log_err("mark host lame: out of memory");
|
||||
} else log_err("lame response from cache");
|
||||
} else log_err("%slame response from cache",
|
||||
dnsseclame?"DNSSEC ":"");
|
||||
} else if(type == RESPONSE_TYPE_THROWAWAY) {
|
||||
/* LAME and THROWAWAY responses are handled the same way.
|
||||
* In this case, the event is just sent directly back to
|
||||
@@ -1317,7 +1395,7 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
|
||||
}
|
||||
|
||||
log_query_info(VERB_DETAIL, "priming successful for", &qstate->qinfo);
|
||||
delegpt_log(dp);
|
||||
delegpt_log(VERB_ALGO, dp);
|
||||
foriq->dp = dp;
|
||||
foriq->deleg_msg = dns_copy_msg(qstate->return_msg, forq->region);
|
||||
if(!foriq->deleg_msg) {
|
||||
@@ -1352,7 +1430,7 @@ static int
|
||||
processPrimeResponse(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
enum response_type type = response_type_from_server(iq->response,
|
||||
enum response_type type = response_type_from_server(0, iq->response,
|
||||
&iq->qchase, iq->dp);
|
||||
if(type == RESPONSE_TYPE_ANSWER) {
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
@@ -1430,7 +1508,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
if(!delegpt_add_rrset(foriq->dp, forq->region, rrset))
|
||||
log_err("out of memory adding targets");
|
||||
verbose(VERB_ALGO, "added target response");
|
||||
delegpt_log(foriq->dp);
|
||||
delegpt_log(VERB_ALGO, foriq->dp);
|
||||
} else {
|
||||
verbose(VERB_ALGO, "iterator TargetResponse failed");
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
@@ -1451,7 +1529,7 @@ static int
|
||||
processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int id)
|
||||
{
|
||||
log_query_info(VERB_DETAIL, "finishing processing for",
|
||||
log_query_info(VERB_QUERY, "finishing processing for",
|
||||
&qstate->qinfo);
|
||||
|
||||
if(!iq->response) {
|
||||
@@ -1504,7 +1582,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Return priming query results to interestes super querystates.
|
||||
*
|
||||
* Sets the delegation point and delegation message (not nonRD queries).
|
||||
@@ -1514,7 +1592,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* @param id: module id.
|
||||
* @param super: the qstate to inform.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
iter_inform_super(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* super)
|
||||
{
|
||||
@@ -1620,7 +1698,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
|
||||
/* parse message */
|
||||
prs = (struct msg_parse*)region_alloc(qstate->env->scratch,
|
||||
prs = (struct msg_parse*)regional_alloc(qstate->env->scratch,
|
||||
sizeof(struct msg_parse));
|
||||
if(!prs) {
|
||||
log_err("out of memory on incoming message");
|
||||
@@ -1650,7 +1728,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->response = dns_alloc_msg(pkt, prs, qstate->region);
|
||||
if(!iq->response)
|
||||
goto handle_it;
|
||||
log_name_addr(VERB_DETAIL, "incoming packet from target:", iq->dp->name,
|
||||
log_query_info(VERB_DETAIL, "reponse for", &qstate->qinfo);
|
||||
log_name_addr(VERB_DETAIL, "reply from", iq->dp->name,
|
||||
&qstate->reply->addr, qstate->reply->addrlen);
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
|
||||
@@ -1661,19 +1740,18 @@ handle_it:
|
||||
iter_handle(qstate, iq, ie, id);
|
||||
}
|
||||
|
||||
/** iterator operate on a query */
|
||||
static void
|
||||
void
|
||||
iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
struct outbound_entry* outbound)
|
||||
{
|
||||
struct iter_env* ie = (struct iter_env*)qstate->env->modinfo[id];
|
||||
struct iter_qstate* iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
verbose(VERB_DETAIL, "iterator[module %d] operate: extstate:%s event:%s",
|
||||
verbose(VERB_QUERY, "iterator[module %d] operate: extstate:%s event:%s",
|
||||
id, strextstate(qstate->ext_state[id]), strmodulevent(event));
|
||||
if(iq) log_query_info(VERB_DETAIL, "iterator operate: query",
|
||||
if(iq) log_query_info(VERB_QUERY, "iterator operate: query",
|
||||
&qstate->qinfo);
|
||||
if(iq && qstate->qinfo.qname != iq->qchase.qname)
|
||||
log_query_info(VERB_DETAIL, "iterator operate: chased to",
|
||||
log_query_info(VERB_QUERY, "iterator operate: chased to",
|
||||
&iq->qchase);
|
||||
|
||||
/* perform iterator state machine */
|
||||
@@ -1687,11 +1765,11 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
process_request(qstate, iq, ie, id);
|
||||
return;
|
||||
}
|
||||
if(event == module_event_pass) {
|
||||
if(iq && event == module_event_pass) {
|
||||
iter_handle(qstate, iq, ie, id);
|
||||
return;
|
||||
}
|
||||
if(outbound) {
|
||||
if(iq && outbound) {
|
||||
process_response(qstate, iq, ie, id, outbound, event);
|
||||
return;
|
||||
}
|
||||
@@ -1705,8 +1783,7 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
|
||||
/** iterator cleanup query state */
|
||||
static void
|
||||
void
|
||||
iter_clear(struct module_qstate* qstate, int id)
|
||||
{
|
||||
struct iter_qstate* iq;
|
||||
@@ -1720,8 +1797,8 @@ iter_clear(struct module_qstate* qstate, int id)
|
||||
qstate->minfo[id] = NULL;
|
||||
}
|
||||
|
||||
/** iterator alloc size routine */
|
||||
static size_t iter_get_mem(struct module_env* env, int id)
|
||||
size_t
|
||||
iter_get_mem(struct module_env* env, int id)
|
||||
{
|
||||
struct iter_env* ie = (struct iter_env*)env->modinfo[id];
|
||||
if(!ie)
|
||||
|
||||
+40
-2
@@ -44,7 +44,7 @@
|
||||
#define ITERATOR_ITERATOR_H
|
||||
#include "services/outbound_list.h"
|
||||
#include "util/data/msgreply.h"
|
||||
struct module_func_block;
|
||||
#include "util/module.h"
|
||||
struct delegpt;
|
||||
struct iter_hints;
|
||||
struct iter_forwards;
|
||||
@@ -58,12 +58,14 @@ struct iter_prep_list;
|
||||
/** how nice is a server without further information, in msec
|
||||
* Equals rtt initial timeout value.
|
||||
*/
|
||||
#define UNKNOWN_SERVER_NICENESS 3000
|
||||
#define UNKNOWN_SERVER_NICENESS 376
|
||||
/** maximum timeout before a host is deemed unsuitable, in msec.
|
||||
* After host_ttl this will be timed out and the host will be tried again.
|
||||
* Equals RTT_MAX_TIMEOUT
|
||||
*/
|
||||
#define USEFUL_SERVER_TOP_TIMEOUT 120000
|
||||
/** number of retries on outgoing queries */
|
||||
#define OUTBOUND_MSG_RETRY 4
|
||||
|
||||
/**
|
||||
* Global state for the iterator.
|
||||
@@ -223,6 +225,13 @@ struct iter_qstate {
|
||||
/** the number of times this query as followed a referral. */
|
||||
int referral_count;
|
||||
|
||||
/**
|
||||
* expected dnssec information for this iteration step.
|
||||
* If dnssec rrsigs are expected and not given, the server is marked
|
||||
* lame (dnssec-lame).
|
||||
*/
|
||||
int dnssec_expected;
|
||||
|
||||
/**
|
||||
* This is flag that, if true, means that this event is
|
||||
* waiting for a stub priming query.
|
||||
@@ -273,4 +282,33 @@ const char* iter_state_to_string(enum iter_state state);
|
||||
*/
|
||||
int iter_state_is_responsestate(enum iter_state s);
|
||||
|
||||
/** iterator init */
|
||||
int iter_init(struct module_env* env, int id);
|
||||
|
||||
/** iterator deinit */
|
||||
void iter_deinit(struct module_env* env, int id);
|
||||
|
||||
/** iterator operate on a query */
|
||||
void iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
struct outbound_entry* outbound);
|
||||
|
||||
/**
|
||||
* Return priming query results to interestes super querystates.
|
||||
*
|
||||
* Sets the delegation point and delegation message (not nonRD queries).
|
||||
* This is a callback from walk_supers.
|
||||
*
|
||||
* @param qstate: query state that finished.
|
||||
* @param id: module id.
|
||||
* @param super: the qstate to inform.
|
||||
*/
|
||||
void iter_inform_super(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* super);
|
||||
|
||||
/** iterator cleanup query state */
|
||||
void iter_clear(struct module_qstate* qstate, int id);
|
||||
|
||||
/** iterator alloc size routine */
|
||||
size_t iter_get_mem(struct module_env* env, int id);
|
||||
|
||||
#endif /* ITERATOR_ITERATOR_H */
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* libunbound/context.c - validating context for unbound internal use
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains the validator context structure.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "util/module.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/net_help.h"
|
||||
#include "services/modstack.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
|
||||
int
|
||||
context_finalize(struct ub_ctx* ctx)
|
||||
{
|
||||
struct config_file* cfg = ctx->env->cfg;
|
||||
verbosity = cfg->verbosity;
|
||||
if(ctx->logfile_override)
|
||||
log_file(ctx->log_out);
|
||||
else log_init(cfg->logfile, cfg->use_syslog, NULL);
|
||||
config_apply(cfg);
|
||||
if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
|
||||
return UB_INITFAIL;
|
||||
ctx->local_zones = local_zones_create();
|
||||
if(!ctx->local_zones)
|
||||
return UB_NOMEM;
|
||||
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!ctx->env->msg_cache ||
|
||||
cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) ||
|
||||
cfg->msg_cache_slabs != ctx->env->msg_cache->size) {
|
||||
slabhash_delete(ctx->env->msg_cache);
|
||||
ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
|
||||
HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
|
||||
msgreply_sizefunc, query_info_compare,
|
||||
query_entry_delete, reply_info_delete, NULL);
|
||||
if(!ctx->env->msg_cache)
|
||||
return UB_NOMEM;
|
||||
}
|
||||
ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
|
||||
ctx->env->cfg, ctx->env->alloc);
|
||||
if(!ctx->env->rrset_cache)
|
||||
return UB_NOMEM;
|
||||
ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
|
||||
if(!ctx->env->infra_cache)
|
||||
return UB_NOMEM;
|
||||
ctx->finalized = 1;
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* a, const void* b)
|
||||
{
|
||||
if( *(int*)a < *(int*)b )
|
||||
return -1;
|
||||
if( *(int*)a > *(int*)b )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
context_query_delete(struct ctx_query* q)
|
||||
{
|
||||
if(!q) return;
|
||||
ub_resolve_free(q->res);
|
||||
free(q->msg);
|
||||
free(q);
|
||||
}
|
||||
|
||||
/** How many times to try to find an unused query-id-number for async */
|
||||
#define NUM_ID_TRIES 100000
|
||||
/** find next useful id number of 0 on error */
|
||||
static int
|
||||
find_id(struct ub_ctx* ctx, int* id)
|
||||
{
|
||||
size_t tries = 0;
|
||||
ctx->next_querynum++;
|
||||
while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
|
||||
ctx->next_querynum++; /* numerical wraparound is fine */
|
||||
if(tries++ > NUM_ID_TRIES)
|
||||
return 0;
|
||||
}
|
||||
*id = ctx->next_querynum;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_new(struct ub_ctx* ctx, char* name, int rrtype, int rrclass,
|
||||
ub_callback_t cb, void* cbarg)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
|
||||
if(!q) return NULL;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!find_id(ctx, &q->querynum)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
q->node.key = &q->querynum;
|
||||
q->async = (cb != NULL);
|
||||
q->cb = cb;
|
||||
q->cb_arg = cbarg;
|
||||
q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
|
||||
if(!q->res) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qname = strdup(name);
|
||||
if(!q->res->qname) {
|
||||
free(q->res);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qtype = rrtype;
|
||||
q->res->qclass = rrclass;
|
||||
|
||||
/* add to query list */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(q->async)
|
||||
ctx->num_async ++;
|
||||
(void)rbtree_insert(&ctx->queries, &q->node);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return q;
|
||||
}
|
||||
|
||||
struct alloc_cache*
|
||||
context_obtain_alloc(struct ub_ctx* ctx, int locking)
|
||||
{
|
||||
struct alloc_cache* a;
|
||||
int tnum = 0;
|
||||
if(locking) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
a = ctx->alloc_list;
|
||||
if(a)
|
||||
ctx->alloc_list = a->super; /* snip off list */
|
||||
else tnum = ctx->thr_next_num++;
|
||||
if(locking) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
if(a) {
|
||||
a->super = &ctx->superalloc;
|
||||
return a;
|
||||
}
|
||||
a = (struct alloc_cache*)calloc(1, sizeof(*a));
|
||||
if(!a)
|
||||
return NULL;
|
||||
alloc_init(a, &ctx->superalloc, tnum);
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
|
||||
int locking)
|
||||
{
|
||||
if(!ctx || !alloc)
|
||||
return;
|
||||
if(locking) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
}
|
||||
alloc->super = ctx->alloc_list;
|
||||
ctx->alloc_list = alloc;
|
||||
if(locking) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_new_query(struct ctx_query* q, uint32_t* len)
|
||||
{
|
||||
/* format for new query is
|
||||
* o uint32 cmd
|
||||
* o uint32 id
|
||||
* o uint32 type
|
||||
* o uint32 class
|
||||
* o rest queryname (string)
|
||||
*/
|
||||
uint8_t* p;
|
||||
size_t slen = strlen(q->res->qname) + 1/*end of string*/;
|
||||
*len = sizeof(uint32_t)*4 + slen;
|
||||
p = (uint8_t*)malloc(*len);
|
||||
if(!p) return NULL;
|
||||
ldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
|
||||
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
|
||||
memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
|
||||
if(!q) return NULL;
|
||||
if(len < 4*sizeof(uint32_t)+1) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
|
||||
q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q->node.key = &q->querynum;
|
||||
q->async = 1;
|
||||
q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
|
||||
if(!q->res) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
q->res->qtype = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||
q->res->qclass = (int)ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||
q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
|
||||
if(!q->res->qname) {
|
||||
free(q->res);
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** add to query list */
|
||||
ctx->num_async++;
|
||||
(void)rbtree_insert(&ctx->queries, &q->node);
|
||||
return q;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int querynum;
|
||||
if(len < 4*sizeof(uint32_t)+1) {
|
||||
return NULL;
|
||||
}
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
|
||||
querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
|
||||
if(!q) {
|
||||
return NULL;
|
||||
}
|
||||
log_assert(q->async);
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt,
|
||||
uint32_t* len)
|
||||
{
|
||||
/* answer format
|
||||
* o uint32 cmd
|
||||
* o uint32 id
|
||||
* o uint32 error_code
|
||||
* o uint32 msg_security
|
||||
* o the remainder is the answer msg from resolver lookup.
|
||||
* remainder can be length 0.
|
||||
*/
|
||||
size_t pkt_len = pkt?ldns_buffer_remaining(pkt):0;
|
||||
uint8_t* p;
|
||||
*len = sizeof(uint32_t)*4 + pkt_len;
|
||||
p = (uint8_t*)malloc(*len);
|
||||
if(!p) return NULL;
|
||||
ldns_write_uint32(p, UB_LIBCMD_ANSWER);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
|
||||
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
|
||||
if(pkt_len > 0)
|
||||
memmove(p+4*sizeof(uint32_t), ldns_buffer_begin(pkt), pkt_len);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query*
|
||||
context_deserialize_answer(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len, int* err)
|
||||
{
|
||||
struct ctx_query* q = NULL ;
|
||||
int id;
|
||||
if(len < 4*sizeof(uint32_t)) return NULL;
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_ANSWER);
|
||||
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||
if(!q) return NULL;
|
||||
*err = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||
q->msg_security = ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||
if(len > 4*sizeof(uint32_t)) {
|
||||
q->msg_len = len - 4*sizeof(uint32_t);
|
||||
q->msg = (uint8_t*)memdup(p+4*sizeof(uint32_t), q->msg_len);
|
||||
if(!q->msg) {
|
||||
/* pass malloc failure to the user callback */
|
||||
q->msg_len = 0;
|
||||
*err = UB_NOMEM;
|
||||
return q;
|
||||
}
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_cancel(struct ctx_query* q, uint32_t* len)
|
||||
{
|
||||
/* format of cancel:
|
||||
* o uint32 cmd
|
||||
* o uint32 async-id */
|
||||
uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t));
|
||||
if(!p) return NULL;
|
||||
*len = 2*sizeof(uint32_t);
|
||||
ldns_write_uint32(p, UB_LIBCMD_CANCEL);
|
||||
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int id;
|
||||
if(len != 2*sizeof(uint32_t)) return NULL;
|
||||
log_assert( ldns_read_uint32(p) == UB_LIBCMD_CANCEL);
|
||||
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||
return q;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
context_serialize_quit(uint32_t* len)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t));
|
||||
if(!p)
|
||||
return NULL;
|
||||
*len = sizeof(uint32_t);
|
||||
ldns_write_uint32(p, UB_LIBCMD_QUIT);
|
||||
return p;
|
||||
}
|
||||
|
||||
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
|
||||
{
|
||||
uint32_t v;
|
||||
if((size_t)len < sizeof(v))
|
||||
return UB_LIBCMD_QUIT;
|
||||
v = ldns_read_uint32(p);
|
||||
return v;
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* libunbound/context.h - validating context for unbound internal use
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains the validator context structure.
|
||||
*/
|
||||
#ifndef LIBUNBOUND_CONTEXT_H
|
||||
#define LIBUNBOUND_CONTEXT_H
|
||||
#include "util/locks.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "services/modstack.h"
|
||||
#include "libunbound/unbound.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
struct libworker;
|
||||
|
||||
/**
|
||||
* The context structure
|
||||
*
|
||||
* Contains two pipes for async service
|
||||
* qq : write queries to the async service pid/tid.
|
||||
* rr : read results from the async service pid/tid.
|
||||
*/
|
||||
struct ub_ctx {
|
||||
/* --- pipes --- */
|
||||
/** mutex on query write pipe */
|
||||
lock_basic_t qqpipe_lock;
|
||||
/** the query write pipe, [0] read from, [1] write on */
|
||||
int qqpipe[2];
|
||||
/** mutex on result read pipe */
|
||||
lock_basic_t rrpipe_lock;
|
||||
/** the result read pipe, [0] read from, [1] write on */
|
||||
int rrpipe[2];
|
||||
|
||||
/* --- shared data --- */
|
||||
/** mutex for access to env.cfg, finalized and dothread */
|
||||
lock_basic_t cfglock;
|
||||
/**
|
||||
* The context has been finalized
|
||||
* This is after config when the first resolve is done.
|
||||
* The modules are inited (module-init()) and shared caches created.
|
||||
*/
|
||||
int finalized;
|
||||
|
||||
/** is bg worker created yet ? */
|
||||
int created_bg;
|
||||
/** pid of bg worker process */
|
||||
pid_t bg_pid;
|
||||
/** tid of bg worker thread */
|
||||
ub_thread_t bg_tid;
|
||||
|
||||
/** do threading (instead of forking) for async resolution */
|
||||
int dothread;
|
||||
/** next thread number for new threads */
|
||||
int thr_next_num;
|
||||
/** if logfile is overriden */
|
||||
int logfile_override;
|
||||
/** what logfile to use instead */
|
||||
FILE* log_out;
|
||||
/**
|
||||
* List of alloc-cache-id points per threadnum for notinuse threads.
|
||||
* Simply the entire struct alloc_cache with the 'super' member used
|
||||
* to link a simply linked list. Reset super member to the superalloc
|
||||
* before use.
|
||||
*/
|
||||
struct alloc_cache* alloc_list;
|
||||
|
||||
/** shared caches, and so on */
|
||||
struct alloc_cache superalloc;
|
||||
/** module env master value */
|
||||
struct module_env* env;
|
||||
/** module stack */
|
||||
struct module_stack mods;
|
||||
/** local authority zones */
|
||||
struct local_zones* local_zones;
|
||||
/** random state used to seed new random state structures */
|
||||
struct ub_randstate* seed_rnd;
|
||||
|
||||
/** next query number (to try) to use */
|
||||
int next_querynum;
|
||||
/** number of async queries outstanding */
|
||||
size_t num_async;
|
||||
/**
|
||||
* Tree of outstanding queries. Indexed by querynum
|
||||
* Used when results come in for async to lookup.
|
||||
* Used when cancel is done for lookup (and delete).
|
||||
* Used to see if querynum is free for use.
|
||||
* Content of type ctx_query.
|
||||
*/
|
||||
rbtree_t queries;
|
||||
};
|
||||
|
||||
/**
|
||||
* The queries outstanding for the libunbound resolver.
|
||||
* These are outstanding for async resolution.
|
||||
* But also, outstanding for sync resolution by one of the threads that
|
||||
* has joined the threadpool.
|
||||
*/
|
||||
struct ctx_query {
|
||||
/** node in rbtree, must be first entry, key is ptr to the querynum */
|
||||
struct rbnode_t node;
|
||||
/** query id number, key for node */
|
||||
int querynum;
|
||||
/** was this an async query? */
|
||||
int async;
|
||||
/** was this query cancelled (for bg worker) */
|
||||
int cancelled;
|
||||
|
||||
/** for async query, the callback function */
|
||||
ub_callback_t cb;
|
||||
/** for async query, the callback user arg */
|
||||
void* cb_arg;
|
||||
|
||||
/** answer message, result from resolver lookup. */
|
||||
uint8_t* msg;
|
||||
/** resulting message length. */
|
||||
size_t msg_len;
|
||||
/** validation status on security */
|
||||
enum sec_status msg_security;
|
||||
/** store libworker that is handling this query */
|
||||
struct libworker* w;
|
||||
|
||||
/** result structure, also contains original query, type, class.
|
||||
* malloced ptr ready to hand to the client. */
|
||||
struct ub_result* res;
|
||||
};
|
||||
|
||||
/**
|
||||
* The error constants
|
||||
*/
|
||||
enum ub_ctx_err {
|
||||
/** no error */
|
||||
UB_NOERROR = 0,
|
||||
/** socket operation. Set to -1, so that if an error from _fd() is
|
||||
* passed (-1) it gives a socket error. */
|
||||
UB_SOCKET = -1,
|
||||
/** alloc failure */
|
||||
UB_NOMEM = -2,
|
||||
/** syntax error */
|
||||
UB_SYNTAX = -3,
|
||||
/** DNS service failed */
|
||||
UB_SERVFAIL = -4,
|
||||
/** fork() failed */
|
||||
UB_FORKFAIL = -5,
|
||||
/** cfg change after finalize() */
|
||||
UB_AFTERFINAL = -6,
|
||||
/** initialization failed (bad settings) */
|
||||
UB_INITFAIL = -7,
|
||||
/** error in pipe communication with async bg worker */
|
||||
UB_PIPE = -8,
|
||||
/** error reading from file (resolv.conf) */
|
||||
UB_READFILE = -9
|
||||
};
|
||||
|
||||
/**
|
||||
* Command codes for libunbound pipe.
|
||||
*
|
||||
* Serialization looks like this:
|
||||
* o length (of remainder) uint32.
|
||||
* o uint32 command code.
|
||||
* o per command format.
|
||||
*/
|
||||
enum ub_ctx_cmd {
|
||||
/** QUIT */
|
||||
UB_LIBCMD_QUIT = 0,
|
||||
/** New query, sent to bg worker */
|
||||
UB_LIBCMD_NEWQUERY,
|
||||
/** Cancel query, sent to bg worker */
|
||||
UB_LIBCMD_CANCEL,
|
||||
/** Query result, originates from bg worker */
|
||||
UB_LIBCMD_ANSWER
|
||||
};
|
||||
|
||||
/**
|
||||
* finalize a context.
|
||||
* @param ctx: context to finalize. creates shared data.
|
||||
* @return 0 if OK, or errcode.
|
||||
*/
|
||||
int context_finalize(struct ub_ctx* ctx);
|
||||
|
||||
/** compare two ctx_query elements */
|
||||
int context_query_cmp(const void* a, const void* b);
|
||||
|
||||
/**
|
||||
* delete context query
|
||||
* @param q: query to delete, including message packet and prealloc result
|
||||
*/
|
||||
void context_query_delete(struct ctx_query* q);
|
||||
|
||||
/**
|
||||
* Create new query in context, add to querynum list.
|
||||
* @param ctx: context
|
||||
* @param name: query name
|
||||
* @param rrtype: type
|
||||
* @param rrclass: class
|
||||
* @param cb: callback for async, or NULL for sync.
|
||||
* @param cbarg: user arg for async queries.
|
||||
* @return new ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_new(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, ub_callback_t cb, void* cbarg);
|
||||
|
||||
/**
|
||||
* Get a new alloc. Creates a new one or uses a cached one.
|
||||
* @param ctx: context
|
||||
* @param locking: if true, cfglock is locked while getting alloc.
|
||||
* @return an alloc, or NULL on mem error.
|
||||
*/
|
||||
struct alloc_cache* context_obtain_alloc(struct ub_ctx* ctx, int locking);
|
||||
|
||||
/**
|
||||
* Release an alloc. Puts it into the cache.
|
||||
* @param ctx: context
|
||||
* @param locking: if true, cfglock is locked while releasing alloc.
|
||||
* @param alloc: alloc to relinquish.
|
||||
*/
|
||||
void context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
|
||||
int locking);
|
||||
|
||||
/**
|
||||
* Serialize a context query that questions data.
|
||||
* This serializes the query name, type, ...
|
||||
* As well as command code 'new_query'.
|
||||
* @param q: context query
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_new_query(struct ctx_query* q, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a context_query result to hand back to user.
|
||||
* This serializes the query name, type, ..., and result.
|
||||
* As well as command code 'answer'.
|
||||
* @param q: context query
|
||||
* @param err: error code to pass to client.
|
||||
* @param pkt: the packet to add, can be NULL.
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_answer(struct ctx_query* q, int err,
|
||||
ldns_buffer* pkt, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a query cancellation. Serializes query async id
|
||||
* as well as command code 'cancel'
|
||||
* @param q: context query
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_cancel(struct ctx_query* q, uint32_t* len);
|
||||
|
||||
/**
|
||||
* Serialize a 'quit' command.
|
||||
* @param len: the length of the allocation is returned.
|
||||
* @return: an alloc, or NULL on mem error.
|
||||
*/
|
||||
uint8_t* context_serialize_quit(uint32_t* len);
|
||||
|
||||
/**
|
||||
* Obtain command code from serialized buffer
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return command code or QUIT on error.
|
||||
*/
|
||||
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Lookup query from new_query buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return looked up ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_lookup_new_query(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Deserialize a new_query buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return new ctx_query or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_new_query(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
/**
|
||||
* Deserialize an answer buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @param err: error code to be returned to client is passed.
|
||||
* @return ctx_query with answer added or NULL for malloc failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_answer(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len, int* err);
|
||||
|
||||
/**
|
||||
* Deserialize a cancel buffer.
|
||||
* @param ctx: context
|
||||
* @param p: buffer serialized.
|
||||
* @param len: length of buffer.
|
||||
* @return ctx_query to cancel or NULL for failure.
|
||||
*/
|
||||
struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
|
||||
uint8_t* p, uint32_t len);
|
||||
|
||||
#endif /* LIBUNBOUND_CONTEXT_H */
|
||||
@@ -0,0 +1,923 @@
|
||||
/*
|
||||
* unbound.c - unbound validating resolver public API implementation
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions to resolve DNS queries and
|
||||
* validate the answers. Synchonously and asynchronously.
|
||||
*
|
||||
*/
|
||||
|
||||
/* include the public api first, it should be able to stand alone */
|
||||
#include "libunbound/unbound.h"
|
||||
#include "config.h"
|
||||
#include "libunbound/context.h"
|
||||
#include "libunbound/libworker.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/module.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/log.h"
|
||||
#include "util/random.h"
|
||||
#include "util/net_help.h"
|
||||
#include "services/modstack.h"
|
||||
#include "services/localzone.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/cache/rrset.h"
|
||||
|
||||
struct ub_ctx*
|
||||
ub_ctx_create()
|
||||
{
|
||||
struct ub_ctx* ctx;
|
||||
unsigned int seed;
|
||||
log_init(NULL, 0, NULL); /* logs to stderr */
|
||||
log_ident_set("libunbound");
|
||||
verbosity = 0; /* errors only */
|
||||
checklock_start();
|
||||
ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
alloc_init(&ctx->superalloc, NULL, 0);
|
||||
seed = (unsigned int)time(NULL) ^ (unsigned int)getpid();
|
||||
if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) {
|
||||
seed = 0;
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
free(ctx);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
seed = 0;
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->qqpipe) == -1) {
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, ctx->rrpipe) == -1) {
|
||||
int e = errno;
|
||||
close(ctx->qqpipe[0]);
|
||||
close(ctx->qqpipe[1]);
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
free(ctx);
|
||||
errno = e;
|
||||
return NULL;
|
||||
}
|
||||
if(!fd_set_nonblock(ctx->rrpipe[0]) ||
|
||||
!fd_set_nonblock(ctx->rrpipe[1]) ||
|
||||
!fd_set_nonblock(ctx->qqpipe[0]) ||
|
||||
!fd_set_nonblock(ctx->qqpipe[1])) {
|
||||
int e = errno;
|
||||
close(ctx->rrpipe[0]);
|
||||
close(ctx->rrpipe[1]);
|
||||
close(ctx->qqpipe[0]);
|
||||
close(ctx->qqpipe[1]);
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
free(ctx);
|
||||
errno = e;
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_init(&ctx->qqpipe_lock);
|
||||
lock_basic_init(&ctx->rrpipe_lock);
|
||||
lock_basic_init(&ctx->cfglock);
|
||||
ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
|
||||
if(!ctx->env) {
|
||||
close(ctx->rrpipe[0]);
|
||||
close(ctx->rrpipe[1]);
|
||||
close(ctx->qqpipe[0]);
|
||||
close(ctx->qqpipe[1]);
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
free(ctx);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
ctx->env->cfg = config_create_forlib();
|
||||
if(!ctx->env->cfg) {
|
||||
close(ctx->rrpipe[0]);
|
||||
close(ctx->rrpipe[1]);
|
||||
close(ctx->qqpipe[0]);
|
||||
close(ctx->qqpipe[1]);
|
||||
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;
|
||||
modstack_init(&ctx->mods);
|
||||
rbtree_init(&ctx->queries, &context_query_cmp);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/** delete q */
|
||||
static void
|
||||
delq(rbnode_t* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct ctx_query* q = (struct ctx_query*)n;
|
||||
context_query_delete(q);
|
||||
}
|
||||
|
||||
void
|
||||
ub_ctx_delete(struct ub_ctx* ctx)
|
||||
{
|
||||
struct alloc_cache* a, *na;
|
||||
if(!ctx) return;
|
||||
/* stop the bg thread */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->created_bg) {
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
uint32_t cmd = UB_LIBCMD_QUIT;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
lock_basic_lock(&ctx->qqpipe_lock);
|
||||
(void)libworker_write_msg(ctx->qqpipe[1], (uint8_t*)&cmd,
|
||||
(uint32_t)sizeof(cmd), 0);
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
while(libworker_read_msg(ctx->rrpipe[0], &msg, &len, 0)) {
|
||||
/* discard all results except a quit confirm */
|
||||
if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
|
||||
free(msg);
|
||||
break;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
|
||||
/* if bg worker is a thread, wait for it to exit, so that all
|
||||
* resources are really gone. */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->dothread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
ub_thread_join(ctx->bg_tid);
|
||||
} else {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
|
||||
|
||||
modstack_desetup(&ctx->mods, ctx->env);
|
||||
a = ctx->alloc_list;
|
||||
while(a) {
|
||||
na = a->super;
|
||||
a->super = &ctx->superalloc;
|
||||
alloc_clear(a);
|
||||
free(a);
|
||||
a = na;
|
||||
}
|
||||
local_zones_delete(ctx->local_zones);
|
||||
lock_basic_destroy(&ctx->qqpipe_lock);
|
||||
lock_basic_destroy(&ctx->rrpipe_lock);
|
||||
lock_basic_destroy(&ctx->cfglock);
|
||||
if(ctx->qqpipe[0] != -1)
|
||||
close(ctx->qqpipe[0]);
|
||||
if(ctx->qqpipe[1] != -1)
|
||||
close(ctx->qqpipe[1]);
|
||||
if(ctx->rrpipe[0] != -1)
|
||||
close(ctx->rrpipe[0]);
|
||||
if(ctx->rrpipe[1] != -1)
|
||||
close(ctx->rrpipe[1]);
|
||||
ctx->qqpipe[0] = -1;
|
||||
ctx->qqpipe[1] = -1;
|
||||
ctx->rrpipe[0] = -1;
|
||||
ctx->rrpipe[1] = -1;
|
||||
if(ctx->env) {
|
||||
slabhash_delete(ctx->env->msg_cache);
|
||||
rrset_cache_delete(ctx->env->rrset_cache);
|
||||
infra_delete(ctx->env->infra_cache);
|
||||
config_delete(ctx->env->cfg);
|
||||
free(ctx->env);
|
||||
}
|
||||
ub_randfree(ctx->seed_rnd);
|
||||
alloc_clear(&ctx->superalloc);
|
||||
traverse_postorder(&ctx->queries, delq, NULL);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val)
|
||||
{
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!config_set_option(ctx->env->cfg, opt, val)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_SYNTAX;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_config(struct ub_ctx* ctx, char* fname)
|
||||
{
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!config_read(ctx->env->cfg, fname)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_SYNTAX;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_add_ta(struct ub_ctx* ctx, char* ta)
|
||||
{
|
||||
char* dup = strdup(ta);
|
||||
if(!dup) return UB_NOMEM;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
free(dup);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname)
|
||||
{
|
||||
char* dup = strdup(fname);
|
||||
if(!dup) return UB_NOMEM;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
free(dup);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname)
|
||||
{
|
||||
char* dup = strdup(fname);
|
||||
if(!dup) return UB_NOMEM;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
free(dup);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_debuglevel(struct ub_ctx* ctx, int d)
|
||||
{
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
verbosity = d;
|
||||
ctx->env->cfg->verbosity = d;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int ub_ctx_debugout(struct ub_ctx* ctx, void* out)
|
||||
{
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
log_file((FILE*)out);
|
||||
ctx->logfile_override = 1;
|
||||
ctx->log_out = out;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_async(struct ub_ctx* ctx, int dothread)
|
||||
{
|
||||
#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS)
|
||||
if(dothread) /* cannot do threading */
|
||||
return UB_NOERROR;
|
||||
#endif
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
ctx->dothread = dothread;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
/** perform a select() on the result read pipe */
|
||||
static int
|
||||
pollit(struct ub_ctx* ctx, struct timeval* t)
|
||||
{
|
||||
fd_set r;
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&r);
|
||||
FD_SET(ctx->rrpipe[0], &r);
|
||||
#endif
|
||||
if(select(ctx->rrpipe[0]+1, &r, NULL, NULL, t) == -1) {
|
||||
return 0;
|
||||
}
|
||||
errno = 0;
|
||||
return FD_ISSET(ctx->rrpipe[0], &r);
|
||||
}
|
||||
|
||||
int
|
||||
ub_poll(struct ub_ctx* ctx)
|
||||
{
|
||||
struct timeval t;
|
||||
memset(&t, 0, sizeof(t));
|
||||
/* no need to hold lock while testing for readability. */
|
||||
return pollit(ctx, &t);
|
||||
}
|
||||
|
||||
int
|
||||
ub_fd(struct ub_ctx* ctx)
|
||||
{
|
||||
return ctx->rrpipe[0];
|
||||
}
|
||||
|
||||
/** process answer from bg worker */
|
||||
static int
|
||||
process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
|
||||
ub_callback_t* cb, void** cbarg, int* err,
|
||||
struct ub_result** res)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
|
||||
log_err("error: bad data from bg worker %d",
|
||||
(int)context_serial_getcmd(msg, len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
q = context_deserialize_answer(ctx, msg, len, err);
|
||||
if(!q) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
/* probably simply the lookup that failed, i.e.
|
||||
* response returned before cancel was sent out, so noerror */
|
||||
return 1;
|
||||
}
|
||||
log_assert(q->async);
|
||||
|
||||
/* grab cb while locked */
|
||||
if(q->cancelled) {
|
||||
*cb = NULL;
|
||||
*cbarg = NULL;
|
||||
} else {
|
||||
*cb = q->cb;
|
||||
*cbarg = q->cb_arg;
|
||||
}
|
||||
if(*err) {
|
||||
*res = NULL;
|
||||
ub_resolve_free(q->res);
|
||||
} else {
|
||||
/* parse the message, extract rcode, fill result */
|
||||
ldns_buffer* buf = ldns_buffer_new(q->msg_len);
|
||||
struct regional* region = regional_create();
|
||||
*res = q->res;
|
||||
(*res)->rcode = LDNS_RCODE_SERVFAIL;
|
||||
if(region && buf) {
|
||||
ldns_buffer_clear(buf);
|
||||
ldns_buffer_write(buf, q->msg, q->msg_len);
|
||||
ldns_buffer_flip(buf);
|
||||
libworker_enter_result(*res, buf, region,
|
||||
q->msg_security);
|
||||
}
|
||||
ldns_buffer_free(buf);
|
||||
regional_destroy(region);
|
||||
}
|
||||
q->res = NULL;
|
||||
/* delete the q from list */
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
ctx->num_async--;
|
||||
context_query_delete(q);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
if(*cb) return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** process answer from bg worker */
|
||||
static int
|
||||
process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len)
|
||||
{
|
||||
int err;
|
||||
ub_callback_t cb;
|
||||
void* cbarg;
|
||||
struct ub_result* res;
|
||||
int r;
|
||||
|
||||
r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res);
|
||||
|
||||
/* no locks held while calling callback, so that library is
|
||||
* re-entrant. */
|
||||
if(r == 2)
|
||||
(*cb)(cbarg, err, res);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ub_process(struct ub_ctx* ctx)
|
||||
{
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
while(1) {
|
||||
msg = NULL;
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
r = libworker_read_msg(ctx->rrpipe[0], &msg, &len, 1);
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
if(r == 0)
|
||||
return UB_PIPE;
|
||||
else if(r == -1)
|
||||
return UB_NOERROR;
|
||||
if(!process_answer(ctx, msg, len)) {
|
||||
free(msg);
|
||||
return UB_PIPE;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_wait(struct ub_ctx* ctx)
|
||||
{
|
||||
int err;
|
||||
ub_callback_t cb;
|
||||
void* cbarg;
|
||||
struct ub_result* res;
|
||||
int r;
|
||||
uint8_t* msg;
|
||||
uint32_t len;
|
||||
/* this is basically the same loop as _process(), but with changes.
|
||||
* holds the rrpipe lock and waits with pollit */
|
||||
while(1) {
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->num_async == 0) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
break;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
/* keep rrpipe locked, while
|
||||
* o waiting for pipe readable
|
||||
* o parsing message
|
||||
* o possibly decrementing num_async
|
||||
* do callback without lock
|
||||
*/
|
||||
r = pollit(ctx, NULL);
|
||||
if(r) {
|
||||
r = libworker_read_msg(ctx->rrpipe[0], &msg, &len, 1);
|
||||
if(r == 0) {
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
return UB_PIPE;
|
||||
}
|
||||
if(r == -1) {
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
continue;
|
||||
}
|
||||
r = process_answer_detail(ctx, msg, len,
|
||||
&cb, &cbarg, &err, &res);
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
if(r == 0)
|
||||
return UB_PIPE;
|
||||
if(r == 2)
|
||||
(*cb)(cbarg, err, res);
|
||||
} else {
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
}
|
||||
}
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_resolve(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, struct ub_result** result)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int r;
|
||||
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!ctx->finalized) {
|
||||
r = context_finalize(ctx);
|
||||
if(r) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
/* create new ctx_query and attempt to add to the list */
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
q = context_new(ctx, name, rrtype, rrclass, NULL, NULL);
|
||||
if(!q)
|
||||
return UB_NOMEM;
|
||||
/* become a resolver thread for a bit */
|
||||
*result = NULL;
|
||||
|
||||
r = libworker_fg(ctx, q);
|
||||
if(r) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
context_query_delete(q);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return r;
|
||||
}
|
||||
*result = q->res;
|
||||
q->res = NULL;
|
||||
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
context_query_delete(q);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, void* mydata, ub_callback_t callback, int* async_id)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
uint8_t* msg = NULL;
|
||||
uint32_t len = 0;
|
||||
|
||||
if(async_id)
|
||||
*async_id = 0;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!ctx->finalized) {
|
||||
int r = context_finalize(ctx);
|
||||
if(r) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if(!ctx->created_bg) {
|
||||
int r;
|
||||
ctx->created_bg = 1;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
r = libworker_bg(ctx);
|
||||
if(r) {
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
ctx->created_bg = 0;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
|
||||
/* create new ctx_query and attempt to add to the list */
|
||||
q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
|
||||
if(!q)
|
||||
return UB_NOMEM;
|
||||
|
||||
/* write over pipe to background worker */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
msg = context_serialize_new_query(q, &len);
|
||||
if(!msg) {
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
ctx->num_async--;
|
||||
context_query_delete(q);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
if(async_id)
|
||||
*async_id = q->querynum;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
lock_basic_lock(&ctx->qqpipe_lock);
|
||||
if(!libworker_write_msg(ctx->qqpipe[1], msg, len, 0)) {
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
free(msg);
|
||||
return UB_PIPE;
|
||||
}
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
free(msg);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_cancel(struct ub_ctx* ctx, int async_id)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
uint8_t* msg = NULL;
|
||||
uint32_t len = 0;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
|
||||
if(!q || !q->async) {
|
||||
/* it is not there, so nothing to do */
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
log_assert(q->async);
|
||||
q->cancelled = 1;
|
||||
|
||||
/* delete it */
|
||||
if(!ctx->dothread) { /* if forked */
|
||||
(void)rbtree_delete(&ctx->queries, q->node.key);
|
||||
ctx->num_async--;
|
||||
context_query_delete(q);
|
||||
msg = context_serialize_cancel(q, &len);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
if(!msg) {
|
||||
return UB_NOMEM;
|
||||
}
|
||||
/* send cancel to background worker */
|
||||
lock_basic_lock(&ctx->qqpipe_lock);
|
||||
if(!libworker_write_msg(ctx->qqpipe[1], msg, len, 0)) {
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
free(msg);
|
||||
return UB_PIPE;
|
||||
}
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
free(msg);
|
||||
} else {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
void
|
||||
ub_resolve_free(struct ub_result* result)
|
||||
{
|
||||
char** p;
|
||||
if(!result) return;
|
||||
free(result->qname);
|
||||
if(result->canonname != result->qname)
|
||||
free(result->canonname);
|
||||
if(result->data)
|
||||
for(p = result->data; *p; p++)
|
||||
free(*p);
|
||||
free(result->data);
|
||||
free(result->len);
|
||||
free(result);
|
||||
}
|
||||
|
||||
const char*
|
||||
ub_strerror(int err)
|
||||
{
|
||||
switch(err) {
|
||||
case UB_NOERROR: return "no error";
|
||||
case UB_SOCKET: return "socket io error";
|
||||
case UB_NOMEM: return "out of memory";
|
||||
case UB_SYNTAX: return "syntax error";
|
||||
case UB_SERVFAIL: return "server failure";
|
||||
case UB_FORKFAIL: return "could not fork";
|
||||
case UB_INITFAIL: return "initialization failure";
|
||||
case UB_AFTERFINAL: return "setting change after finalize";
|
||||
case UB_PIPE: return "error in pipe communication with async";
|
||||
case UB_READFILE: return "error reading file";
|
||||
default: return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr)
|
||||
{
|
||||
struct sockaddr_storage storage;
|
||||
socklen_t stlen;
|
||||
struct config_stub* s;
|
||||
char* dupl;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=EINVAL;
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
if(!addr) {
|
||||
/* disable fwd mode - the root stub should be first. */
|
||||
if(ctx->env->cfg->forwards &&
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
|
||||
s = ctx->env->cfg->forwards;
|
||||
ctx->env->cfg->forwards = s->next;
|
||||
s->next = NULL;
|
||||
config_delstubs(s);
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
/* check syntax for addr */
|
||||
if(!extstrtoaddr(addr, &storage, &stlen)) {
|
||||
errno=EINVAL;
|
||||
return UB_SYNTAX;
|
||||
}
|
||||
|
||||
/* it parses, add root stub in front of list */
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!ctx->env->cfg->forwards ||
|
||||
strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
|
||||
s = calloc(1, sizeof(*s));
|
||||
if(!s) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
s->name = strdup(".");
|
||||
if(!s->name) {
|
||||
free(s);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
s->next = ctx->env->cfg->forwards;
|
||||
ctx->env->cfg->forwards = s;
|
||||
} else {
|
||||
log_assert(ctx->env->cfg->forwards);
|
||||
s = ctx->env->cfg->forwards;
|
||||
}
|
||||
dupl = strdup(addr);
|
||||
if(!dupl) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
if(!cfg_strlist_insert(&s->addrs, dupl)) {
|
||||
free(dupl);
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname)
|
||||
{
|
||||
FILE* in;
|
||||
int numserv = 0;
|
||||
char buf[1024];
|
||||
char* parse, *addr;
|
||||
int r;
|
||||
if(fname == NULL)
|
||||
fname = "/etc/resolv.conf";
|
||||
in = fopen(fname, "r");
|
||||
if(!in) {
|
||||
/* error in errno! perror(fname) */
|
||||
return UB_READFILE;
|
||||
}
|
||||
while(fgets(buf, (int)sizeof(buf), in)) {
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
parse=buf;
|
||||
while(*parse == ' ' || *parse == '\t')
|
||||
parse++;
|
||||
if(strncmp(parse, "nameserver", 10) == 0) {
|
||||
numserv++;
|
||||
parse += 10; /* skip 'nameserver' */
|
||||
/* skip whitespace */
|
||||
while(*parse == ' ' || *parse == '\t')
|
||||
parse++;
|
||||
addr = parse;
|
||||
/* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
|
||||
while(isxdigit(*parse) || *parse=='.' || *parse==':')
|
||||
parse++;
|
||||
/* terminate after the address, remove newline */
|
||||
*parse = 0;
|
||||
|
||||
if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
|
||||
fclose(in);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
if(numserv == 0) {
|
||||
/* from resolv.conf(5) if none given, use localhost */
|
||||
return ub_ctx_set_fwd(ctx, "127.0.0.1");
|
||||
}
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
||||
int
|
||||
ub_ctx_hosts(struct ub_ctx* ctx, char* fname)
|
||||
{
|
||||
FILE* in;
|
||||
char buf[1024], ldata[1024];
|
||||
char* parse, *addr, *name, *ins;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(ctx->finalized) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
errno=EINVAL;
|
||||
return UB_AFTERFINAL;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
if(fname == NULL)
|
||||
fname = "/etc/hosts";
|
||||
in = fopen(fname, "r");
|
||||
if(!in) {
|
||||
/* error in errno! perror(fname) */
|
||||
return UB_READFILE;
|
||||
}
|
||||
while(fgets(buf, (int)sizeof(buf), in)) {
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
parse=buf;
|
||||
while(*parse == ' ' || *parse == '\t')
|
||||
parse++;
|
||||
if(*parse == '#')
|
||||
continue; /* skip comment */
|
||||
/* format: <addr> spaces <name> spaces <name> ... */
|
||||
addr = parse;
|
||||
/* skip addr */
|
||||
while(isxdigit(*parse) || *parse == '.' || *parse == ':')
|
||||
parse++;
|
||||
if(*parse != ' ' && *parse != '\t') {
|
||||
/* must have whitespace after address */
|
||||
fclose(in);
|
||||
errno=EINVAL;
|
||||
return UB_SYNTAX;
|
||||
}
|
||||
*parse++ = 0; /* end delimiter for addr ... */
|
||||
/* go to names and add them */
|
||||
while(*parse) {
|
||||
while(*parse == ' ' || *parse == '\t' || *parse=='\n')
|
||||
parse++;
|
||||
if(*parse == 0 || *parse == '#')
|
||||
break;
|
||||
/* skip name, allows (too) many printable characters */
|
||||
name = parse;
|
||||
while('!' <= *parse && *parse <= '~')
|
||||
parse++;
|
||||
if(*parse)
|
||||
*parse++ = 0; /* end delimiter for name */
|
||||
snprintf(ldata, sizeof(ldata), "%s %s %s",
|
||||
name, str_is_ip6(addr)?"AAAA":"A", addr);
|
||||
ins = strdup(ldata);
|
||||
if(!ins) {
|
||||
/* out of memory */
|
||||
fclose(in);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
if(!cfg_strlist_insert(&ctx->env->cfg->local_data,
|
||||
ins)) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
fclose(in);
|
||||
free(ins);
|
||||
errno=ENOMEM;
|
||||
return UB_NOMEM;
|
||||
}
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* libunbound/worker.h - worker thread or process that resolves
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains the worker process or thread that performs
|
||||
* the DNS resolving and validation. The worker is called by a procedure
|
||||
* and if in the background continues until exit, if in the foreground
|
||||
* returns from the procedure when done.
|
||||
*/
|
||||
#ifndef LIBUNBOUND_WORKER_H
|
||||
#define LIBUNBOUND_WORKER_H
|
||||
#include "util/data/packed_rrset.h"
|
||||
struct ub_ctx;
|
||||
struct ub_result;
|
||||
struct module_env;
|
||||
struct comm_base;
|
||||
struct outside_network;
|
||||
struct ub_randstate;
|
||||
struct ctx_query;
|
||||
struct outbound_entry;
|
||||
struct module_qstate;
|
||||
struct comm_point;
|
||||
struct comm_reply;
|
||||
struct libworker_res_list;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
* Internal to the worker.
|
||||
*/
|
||||
struct libworker {
|
||||
/** every worker has a unique thread_num. (first in struct) */
|
||||
int thread_num;
|
||||
/** context we are operating under */
|
||||
struct ub_ctx* ctx;
|
||||
|
||||
/** is this the bg worker? */
|
||||
int is_bg;
|
||||
/** is this a bg worker that is threaded (not forked)? */
|
||||
int is_bg_thread;
|
||||
|
||||
/** copy of the module environment with worker local entries. */
|
||||
struct module_env* env;
|
||||
/** the event base this worker works with */
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
|
||||
/** commpoint to listen to commands */
|
||||
struct comm_point* cmd_com;
|
||||
/** are we currently reading a command, 0 if not, else bytecount */
|
||||
size_t cmd_read;
|
||||
/** size of current read command, may be partially read */
|
||||
uint32_t cmd_len;
|
||||
/** the current read command content, malloced, can be partially read*/
|
||||
uint8_t* cmd_msg;
|
||||
|
||||
/** commpoint to write results back */
|
||||
struct comm_point* res_com;
|
||||
/** are we curently writing a result, 0 if not, else bytecount into
|
||||
* the res_list first entry. */
|
||||
size_t res_write;
|
||||
/** list of outstanding results to be written back */
|
||||
struct libworker_res_list* res_list;
|
||||
/** last in list */
|
||||
struct libworker_res_list* res_last;
|
||||
};
|
||||
|
||||
/**
|
||||
* List of results (arbitrary command serializations) to write back
|
||||
*/
|
||||
struct libworker_res_list {
|
||||
/** next in list */
|
||||
struct libworker_res_list* next;
|
||||
/** serialized buffer to write */
|
||||
uint8_t* buf;
|
||||
/** length to write */
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a background worker
|
||||
* @param ctx: is updated with pid/tid of the background worker.
|
||||
* a new allocation cache is obtained from ctx. It contains the
|
||||
* threadnumber and unique id for further (shared) cache insertions.
|
||||
* @return 0 if OK, else error.
|
||||
* Further communication is done via the pipes in ctx.
|
||||
*/
|
||||
int libworker_bg(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Create a foreground worker.
|
||||
* This worker will join the threadpool of resolver threads.
|
||||
* It exits when the query answer has been obtained (or error).
|
||||
* This routine blocks until the worker is finished.
|
||||
* @param ctx: new allocation cache obtained and returned to it.
|
||||
* @param q: query (result is stored in here).
|
||||
* @return 0 if finished OK, else error.
|
||||
*/
|
||||
int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q);
|
||||
|
||||
/** cleanup the cache to remove all rrset IDs from it, arg is libworker */
|
||||
void libworker_alloc_cleanup(void* arg);
|
||||
|
||||
/**
|
||||
* Worker service routine to send udp messages for modules.
|
||||
* @param pkt: packet to send.
|
||||
* @param addr: where to.
|
||||
* @param addrlen: length of addr.
|
||||
* @param timeout: seconds to wait until timeout.
|
||||
* @param q: wich query state to reactivate upon return.
|
||||
* @param use_tcp: true to use TCP, false for UDP.
|
||||
* @return: false on failure (memory or socket related). no query was
|
||||
* sent.
|
||||
*/
|
||||
int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp);
|
||||
|
||||
/**
|
||||
* 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 flags: host order flags word, with opcode and CD bit.
|
||||
* @param dnssec: if set, EDNS record will have DO bit set.
|
||||
* @param addr: where to.
|
||||
* @param addrlen: length of addr.
|
||||
* @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,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
struct module_qstate* q);
|
||||
|
||||
/** process incoming replies from the network */
|
||||
int libworker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** process incoming serviced query replies from the network */
|
||||
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* reply_info);
|
||||
|
||||
/** handle control command coming into server */
|
||||
int libworker_handle_control_cmd(struct comm_point* c, void* arg,
|
||||
int err, struct comm_reply* rep);
|
||||
|
||||
/** handle opportunity to write result back */
|
||||
int libworker_handle_result_write(struct comm_point* c, void* arg,
|
||||
int err, struct comm_reply* rep);
|
||||
|
||||
/**
|
||||
* Write length bytes followed by message.
|
||||
* @param fd: the socket to write on. Is nonblocking.
|
||||
* Set to blocking by the function,
|
||||
* and back to non-blocking at exit of function.
|
||||
* @param buf: the message.
|
||||
* @param len: length of message.
|
||||
* @param nonblock: if set to true, the first write is nonblocking.
|
||||
* If the first write fails the function returns -1.
|
||||
* If set false, the first write is blocking.
|
||||
* @return: all remainder writes are nonblocking.
|
||||
* return 0 on error, in that case blocking/nonblocking of socket is
|
||||
* unknown.
|
||||
* return 1 if all OK.
|
||||
*/
|
||||
int libworker_write_msg(int fd, uint8_t* buf, uint32_t len, int nonblock);
|
||||
|
||||
/**
|
||||
* Read length bytes followed by message.
|
||||
* @param fd: the socket to write on. Is nonblocking.
|
||||
* Set to blocking by the function,
|
||||
* and back to non-blocking at exit of function.
|
||||
* @param buf: the message, malloced.
|
||||
* @param len: length of message, returned.
|
||||
* @param nonblock: if set to true, the first read is nonblocking.
|
||||
* If the first read fails the function returns -1.
|
||||
* If set false, the first read is blocking.
|
||||
* @return: all remainder reads are nonblocking.
|
||||
* return 0 on error, in that case blocking/nonblocking of socket is
|
||||
* unknown. On EOF 0 is returned.
|
||||
* return 1 if all OK.
|
||||
*/
|
||||
int libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock);
|
||||
|
||||
/**
|
||||
* fill result from parsed message, on error fills servfail
|
||||
* @param res: is clear at start, filled in at end.
|
||||
* @param buf: contains DNS message.
|
||||
* @param temp: temporary buffer for parse.
|
||||
* @param msg_security: security status of the DNS message.
|
||||
* On error, the res may contain a different status
|
||||
* (out of memory is not secure, not bogus).
|
||||
*/
|
||||
void libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
|
||||
struct regional* temp, enum sec_status msg_security);
|
||||
|
||||
#endif /* LIBUNBOUND_WORKER_H */
|
||||
@@ -0,0 +1,22 @@
|
||||
ub_ctx_create
|
||||
ub_ctx_delete
|
||||
ub_ctx_set_option
|
||||
ub_ctx_config
|
||||
ub_ctx_set_fwd
|
||||
ub_ctx_resolvconf
|
||||
ub_ctx_hosts
|
||||
ub_ctx_add_ta
|
||||
ub_ctx_add_ta_file
|
||||
ub_ctx_trustedkeys
|
||||
ub_ctx_debugout
|
||||
ub_ctx_debuglevel
|
||||
ub_ctx_async
|
||||
ub_poll
|
||||
ub_wait
|
||||
ub_fd
|
||||
ub_process
|
||||
ub_resolve
|
||||
ub_resolve_async
|
||||
ub_cancel
|
||||
ub_resolve_free
|
||||
ub_strerror
|
||||
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* unbound.h - unbound validating resolver public API
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions to resolve DNS queries and
|
||||
* validate the answers. Synchonously and asynchronously.
|
||||
*
|
||||
* Several ways to use this interface from an application wishing
|
||||
* to perform (validated) DNS lookups.
|
||||
*
|
||||
* All start with
|
||||
* ctx = ub_ctx_create();
|
||||
* err = ub_ctx_add_ta(ctx, "...");
|
||||
* err = ub_ctx_add_ta(ctx, "...");
|
||||
* ... some lookups
|
||||
* ... call ub_ctx_delete(ctx); when you want to stop.
|
||||
*
|
||||
* Application not threaded. Blocking.
|
||||
* int err = ub_resolve(ctx, "www.example.com", ...
|
||||
* if(err) fprintf(stderr, "lookup error: %s\n", ub_strerror(err));
|
||||
* ... use the answer
|
||||
*
|
||||
* Application not threaded. Non-blocking ('asynchronous').
|
||||
* err = ub_resolve_async(ctx, "www.example.com", ... my_callback);
|
||||
* ... application resumes processing ...
|
||||
* ... and when either ub_poll(ctx) is true
|
||||
* ... or when the file descriptor ub_fd(ctx) is readable,
|
||||
* ... or whenever, the app calls ...
|
||||
* ub_process(ctx);
|
||||
* ... if no result is ready, the app resumes processing above,
|
||||
* ... or process() calls my_callback() with results.
|
||||
*
|
||||
* ... if the application has nothing more to do, wait for answer
|
||||
* ub_wait(ctx);
|
||||
*
|
||||
* Application threaded. Blocking.
|
||||
* Blocking, same as above. The current thread does the work.
|
||||
* Multiple threads can use the *same context*, each does work and uses
|
||||
* shared cache data from the context.
|
||||
*
|
||||
* Application threaded. Non-blocking ('asynchronous').
|
||||
* ... setup threaded-asynchronous config option
|
||||
* err = ub_ctx_async(ctx, 1);
|
||||
* ... same as async for non-threaded
|
||||
* ... the callbacks are called in the thread that calls process(ctx)
|
||||
*
|
||||
* If no threading is compiled in, the above async example uses fork(2) to
|
||||
* create a process to perform the work. The forked process exits when the
|
||||
* calling process exits, or ctx_delete() is called.
|
||||
* Otherwise, for asynchronous with threading, a worker thread is created.
|
||||
*
|
||||
* The blocking calls use shared ctx-cache when threaded. Thus
|
||||
* ub_resolve() and ub_resolve_async() && ub_wait() are
|
||||
* not the same. The first makes the current thread do the work, setting
|
||||
* up buffers, etc, to perform the work (but using shared cache data).
|
||||
* The second calls another worker thread (or process) to perform the work.
|
||||
* And no buffers need to be set up, but a context-switch happens.
|
||||
*/
|
||||
#ifndef _UB_UNBOUND_H
|
||||
#define _UB_UNBOUND_H
|
||||
|
||||
/**
|
||||
* The validation context is created to hold the resolver status,
|
||||
* validation keys and a small cache (containing messages, rrsets,
|
||||
* roundtrip times, trusted keys, lameness information).
|
||||
*
|
||||
* Its contents are internally defined.
|
||||
*/
|
||||
struct ub_ctx;
|
||||
|
||||
/**
|
||||
* The validation and resolution results.
|
||||
* Allocated by the resolver, and need to be freed by the application
|
||||
* with ub_resolve_free().
|
||||
*/
|
||||
struct ub_result {
|
||||
/** The original question, name text string. */
|
||||
char* qname;
|
||||
/** the type asked for */
|
||||
int qtype;
|
||||
/** the class asked for */
|
||||
int qclass;
|
||||
|
||||
/**
|
||||
* a list of network order DNS rdata items, terminated with a
|
||||
* NULL pointer, so that data[0] is the first result entry,
|
||||
* data[1] the second, and the last entry is NULL.
|
||||
* If there was no data, data[0] is NULL.
|
||||
*/
|
||||
char** data;
|
||||
|
||||
/** the length in bytes of the data items, len[i] for data[i] */
|
||||
int* len;
|
||||
|
||||
/**
|
||||
* canonical name for the result (the final cname).
|
||||
* zero terminated string.
|
||||
* May be NULL if no canonical name exists.
|
||||
*/
|
||||
char* canonname;
|
||||
|
||||
/**
|
||||
* DNS RCODE for the result. May contain additional error code if
|
||||
* there was no data due to an error. 0 (NOERROR) if okay.
|
||||
*/
|
||||
int rcode;
|
||||
|
||||
/**
|
||||
* If there is any data, this is true.
|
||||
* If false, there was no data (nxdomain may be true, rcode can be set).
|
||||
*/
|
||||
int havedata;
|
||||
|
||||
/**
|
||||
* If there was no data, and the domain did not exist, this is true.
|
||||
* If it is false, and there was no data, then the domain name
|
||||
* is purported to exist, but the requested data type is not available.
|
||||
*/
|
||||
int nxdomain;
|
||||
|
||||
/**
|
||||
* True, if the result is validated securely.
|
||||
* False, if validation failed or domain queried has no security info.
|
||||
*
|
||||
* It is possible to get a result with no data (havedata is false),
|
||||
* and secure is true. This means that the non-existance of the data
|
||||
* was cryptographically proven (with signatures).
|
||||
*/
|
||||
int secure;
|
||||
|
||||
/**
|
||||
* If the result was not secure (secure==0), and this result is due
|
||||
* to a security failure, bogus is true.
|
||||
* This means the data has been actively tampered with, signatures
|
||||
* failed, expected signatures were not present, timestamps on
|
||||
* signatures were out of date and so on.
|
||||
*
|
||||
* If !secure and !bogus, this can happen if the data is not secure
|
||||
* because security is disabled for that domain name.
|
||||
* This means the data is from a domain where data is not signed.
|
||||
*/
|
||||
int bogus;
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for results of async queries.
|
||||
* The readable function definition looks like:
|
||||
* void my_callback(void* my_arg, int err, struct ub_result* result);
|
||||
* It is called with
|
||||
* void* my_arg: your pointer to a (struct of) data of your choice,
|
||||
* or NULL.
|
||||
* int err: if 0 all is OK, otherwise an error occured and no results
|
||||
* are forthcoming.
|
||||
* struct result: pointer to more detailed result structure.
|
||||
* This structure is allocated on the heap and needs to be
|
||||
* freed with ub_resolve_free(result);
|
||||
*/
|
||||
typedef void (*ub_callback_t)(void*, int, struct ub_result*);
|
||||
|
||||
/**
|
||||
* Create a resolving and validation context.
|
||||
* The information from /etc/resolv.conf and /etc/hosts is not utilised by
|
||||
* default. Use ub_ctx_resolvconf and ub_ctx_hosts to read them.
|
||||
* @return a new context. default initialisation.
|
||||
* returns NULL on error.
|
||||
*/
|
||||
struct ub_ctx* ub_ctx_create(void);
|
||||
|
||||
/**
|
||||
* Destroy a validation context and free all its resources.
|
||||
* Outstanding async queries are killed and callbacks are not called for them.
|
||||
* @param ctx: context to delete.
|
||||
*/
|
||||
void ub_ctx_delete(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Set an option for the context.
|
||||
* @param ctx: context.
|
||||
* @param opt: option name from the unbound.conf config file format.
|
||||
* (not all settings applicable). The name includes the trailing ':'
|
||||
* for example ub_ctx_set_option("logfile:", "mylog.txt");
|
||||
* This is a power-users interface that lets you specify all sorts
|
||||
* of options.
|
||||
* For some specific options, such as adding trust anchors, special
|
||||
* routines exist.
|
||||
* @param val: value of the option.
|
||||
* @return: 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val);
|
||||
|
||||
/**
|
||||
* setup configuration for the given context.
|
||||
* @param ctx: context.
|
||||
* @param fname: unbound config file (not all settings applicable).
|
||||
* This is a power-users interface that lets you specify all sorts
|
||||
* of options.
|
||||
* For some specific options, such as adding trust anchors, special
|
||||
* routines exist.
|
||||
* @return: 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_config(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
/**
|
||||
* Set machine to forward DNS queries to, the caching resolver to use.
|
||||
* IP4 or IP6 address. Forwards all DNS requests to that machine, which
|
||||
* is expected to run a recursive resolver. If the proxy is not
|
||||
* DNSSEC-capable, validation may fail. Can be called several times, in
|
||||
* that case the addresses are used as backup servers.
|
||||
*
|
||||
* To read the list of nameservers from /etc/resolv.conf (from DHCP or so),
|
||||
* use the call ub_ctx_resolvconf.
|
||||
*
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to set configuration before the
|
||||
* first resolve is done.
|
||||
* @param addr: address, IP4 or IP6 in string format.
|
||||
* If the addr is NULL, forwarding is disabled.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr);
|
||||
|
||||
/**
|
||||
* Read list of nameservers to use from the filename given.
|
||||
* Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
|
||||
* If they do not support DNSSEC, validation may fail.
|
||||
*
|
||||
* Only nameservers are picked up, the searchdomain, ndots and other
|
||||
* settings from resolv.conf(5) are ignored.
|
||||
*
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to set configuration before the
|
||||
* first resolve is done.
|
||||
* @param fname: file name string. If NULL "/etc/resolv.conf" is used.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
/**
|
||||
* Read list of hosts from the filename given.
|
||||
* Usually "/etc/hosts".
|
||||
* These addresses are not flagged as DNSSEC secure when queried for.
|
||||
*
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to set configuration before the
|
||||
* first resolve is done.
|
||||
* @param fname: file name string. If NULL "/etc/hosts" is used.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_hosts(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
/**
|
||||
* Add a trust anchor to the given context.
|
||||
* The trust anchor is a string, on one line, that holds a valid DNSKEY or
|
||||
* DS RR.
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to add trusted keys before the
|
||||
* first resolve is done.
|
||||
* @param ta: string, with zone-format RR on one line.
|
||||
* [domainname] [TTL optional] [type] [class optional] [rdata contents]
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_add_ta(struct ub_ctx* ctx, char* ta);
|
||||
|
||||
/**
|
||||
* Add trust anchors to the given context.
|
||||
* Pass name of a file with DS and DNSKEY records (like from dig or drill).
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to add trusted keys before the
|
||||
* first resolve is done.
|
||||
* @param fname: filename of file with keyfile with trust anchors.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
/**
|
||||
* Add trust anchors to the given context.
|
||||
* Pass the name of a bind-style config file with trusted-keys{}.
|
||||
* @param ctx: context.
|
||||
* At this time it is only possible to add trusted keys before the
|
||||
* first resolve is done.
|
||||
* @param fname: filename of file with bind-style config entries with trust
|
||||
* anchors.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname);
|
||||
|
||||
/**
|
||||
* Set debug output (and error output) to the specified stream.
|
||||
* Pass NULL to disable. Default is stderr.
|
||||
* @param ctx: context.
|
||||
* @param out: FILE* out file stream to log to.
|
||||
* Type void* to avoid stdio dependency of this header file.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_debugout(struct ub_ctx* ctx, void* out);
|
||||
|
||||
/**
|
||||
* Set debug verbosity for the context
|
||||
* Output is directed to stderr.
|
||||
* @param ctx: context.
|
||||
* @param d: debug level, 0 is off, 1 is very minimal, 2 is detailed,
|
||||
* and 3 is lots.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_debuglevel(struct ub_ctx* ctx, int d);
|
||||
|
||||
/**
|
||||
* Set a context behaviour for asynchronous action.
|
||||
* @param ctx: context.
|
||||
* @param dothread: if true, enables threading and a call to resolve_async()
|
||||
* creates a thread to handle work in the background.
|
||||
* If false, a process is forked to handle work in the background.
|
||||
* Changes to this setting after async() calls have been made have
|
||||
* no effect (delete and re-create the context to change).
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_ctx_async(struct ub_ctx* ctx, int dothread);
|
||||
|
||||
/**
|
||||
* Poll a context to see if it has any new results
|
||||
* Do not poll in a loop, instead extract the fd below to poll for readiness,
|
||||
* and then check, or wait using the wait routine.
|
||||
* @param ctx: context.
|
||||
* @return: 0 if nothing to read, or nonzero if a result is available.
|
||||
* If nonzero, call ctx_process() to do callbacks.
|
||||
*/
|
||||
int ub_poll(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Wait for a context to finish with results. Calls ub_process() after
|
||||
* the wait for you. After the wait, there are no more outstanding
|
||||
* asynchronous queries.
|
||||
* @param ctx: context.
|
||||
* @return: 0 if OK, else error.
|
||||
*/
|
||||
int ub_wait(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Get file descriptor. Wait for it to become readable, at this point
|
||||
* answers are returned from the asynchronous validating resolver.
|
||||
* Then call the ub_process to continue processing.
|
||||
* This routine works immediately after context creation, the fd
|
||||
* does not change.
|
||||
* @param ctx: context.
|
||||
* @return: -1 on error, or file descriptor to use select(2) with.
|
||||
*/
|
||||
int ub_fd(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Call this routine to continue processing results from the validating
|
||||
* resolver (when the fd becomes readable).
|
||||
* Will perform necessary callbacks.
|
||||
* @param ctx: context
|
||||
* @return: 0 if OK, else error.
|
||||
*/
|
||||
int ub_process(struct ub_ctx* ctx);
|
||||
|
||||
/**
|
||||
* Perform resolution and validation of the target name.
|
||||
* @param ctx: context.
|
||||
* The context is finalized, and can no longer accept config changes.
|
||||
* @param name: domain name in text format (a zero terminated text string).
|
||||
* @param rrtype: type of RR in host order, 1 is A (address).
|
||||
* @param rrclass: class of RR in host order, 1 is IN (for internet).
|
||||
* @param result: the result data is returned in a newly allocated result
|
||||
* structure. May be NULL on return, return value is set to an error
|
||||
* in that case (out of memory).
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_resolve(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, struct ub_result** result);
|
||||
|
||||
/**
|
||||
* Perform resolution and validation of the target name.
|
||||
* Asynchronous, after a while, the callback will be called with your
|
||||
* data and the result.
|
||||
* @param ctx: context.
|
||||
* If no thread or process has been created yet to perform the
|
||||
* work in the background, it is created now.
|
||||
* The context is finalized, and can no longer accept config changes.
|
||||
* @param name: domain name in text format (a string).
|
||||
* @param rrtype: type of RR in host order, 1 is A.
|
||||
* @param rrclass: class of RR in host order, 1 is IN (for internet).
|
||||
* @param mydata: this data is your own data (you can pass NULL),
|
||||
* and is passed on to the callback function.
|
||||
* @param callback: this is called on completion of the resolution.
|
||||
* It is called as:
|
||||
* void callback(void* mydata, int err, struct ub_result* result)
|
||||
* with mydata: the same as passed here, you may pass NULL,
|
||||
* with err: is 0 when a result has been found.
|
||||
* with result: a newly allocated result structure.
|
||||
* The result may be NULL, in that case err is set.
|
||||
*
|
||||
* If an error happens during processing, your callback will be called
|
||||
* with error set to a nonzero value (and result==NULL).
|
||||
* @param async_id: if you pass a non-NULL value, an identifier number is
|
||||
* returned for the query as it is in progress. It can be used to
|
||||
* cancel the query.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
|
||||
int rrclass, void* mydata, ub_callback_t callback, int* async_id);
|
||||
|
||||
/**
|
||||
* Cancel an async query in progress.
|
||||
* Its callback will not be called.
|
||||
*
|
||||
* @param ctx: context.
|
||||
* @param async_id: which query to cancel.
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int ub_cancel(struct ub_ctx* ctx, int async_id);
|
||||
|
||||
/**
|
||||
* Free storage associated with a result structure.
|
||||
* @param result: to free
|
||||
*/
|
||||
void ub_resolve_free(struct ub_result* result);
|
||||
|
||||
/**
|
||||
* Convert error value to a human readable string.
|
||||
* @param err: error code from one of the ub_val* functions.
|
||||
* @return pointer to constant text string, zero terminated.
|
||||
*/
|
||||
const char* ub_strerror(int err);
|
||||
|
||||
#endif /* _UB_UNBOUND_H */
|
||||
+18
-8
@@ -146,17 +146,15 @@ if test -z "$LDNSDIR"; then
|
||||
# try to autodetect from Makefile (if present)
|
||||
if test -f Makefile; then
|
||||
eval `grep 'ldnsdir=' Makefile`
|
||||
LDNSDIR="$ldnsdir"
|
||||
fi
|
||||
if test -z "$LDNSDIR"; then
|
||||
error "LDNSDIR not detected in Makefile, specify manually (using -l)"
|
||||
if echo "$ldnsdir" | grep -v ldns-src/ >/dev/null 2>&1; then
|
||||
LDNSDIR="$ldnsdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Start the packaging process.
|
||||
info "SVNROOT is $SVNROOT"
|
||||
info "SNAPSHOT is $SNAPSHOT"
|
||||
info "LDNSDIR is $LDNSDIR"
|
||||
|
||||
#question "Do you wish to continue with these settings?" || error "User abort."
|
||||
|
||||
@@ -185,9 +183,17 @@ echo "#include \"util/configyyrename.h\"" > util/configlexer.c || error_cleanup
|
||||
flex -i -t util/configlexer.lex >> util/configlexer.c || error_cleanup "Failed to create configlexer"
|
||||
bison -y -d -o util/configparser.c util/configparser.y || error_cleanup "Failed to create configparser"
|
||||
|
||||
# copy ldns-testpkts from ldns examples
|
||||
#cp $LDNSDIR/examples/ldns-testpkts.c testcode/ldns-testpkts.c || error_cleanup "copy ldns/examples/.. failed"
|
||||
#cp $LDNSDIR/examples/ldns-testpkts.h testcode/ldns-testpkts.h || error_cleanup "copy ldns/examples/.. failed"
|
||||
# check shared code, ldns-testpkts from ldns examples, if possible.
|
||||
cd ../..
|
||||
if test ! -z "$LDNSDIR"; then
|
||||
if diff -q $LDNSDIR/examples/ldns-testpkts.c testcode/ldns-testpkts.c &&
|
||||
diff -q $LDNSDIR/examples/ldns-testpkts.h testcode/ldns-testpkts.h; then
|
||||
info "ldns-testpkts.c and ldns-testpkts.h are OK"
|
||||
else
|
||||
error_cleanup "ldns-testpkts is different in ldns and unbound"
|
||||
fi
|
||||
fi
|
||||
cd $temp_dir/unbound
|
||||
|
||||
find . -name .c-mode-rc.el -exec rm {} \;
|
||||
find . -name .cvsignore -exec rm {} \;
|
||||
@@ -207,6 +213,10 @@ fi
|
||||
|
||||
replace_all doc/README
|
||||
replace_all doc/unbound.8
|
||||
replace_all doc/unbound.conf.5
|
||||
replace_all doc/unbound-checkconf.8
|
||||
replace_all doc/unbound-host.1
|
||||
replace_all doc/libunbound.3
|
||||
|
||||
info "Renaming Unbound directory to unbound-$version."
|
||||
cd ..
|
||||
|
||||
Vendored
+32
-29
@@ -47,7 +47,7 @@
|
||||
#include "util/data/dname.h"
|
||||
#include "util/module.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
|
||||
/** store rrsets in the rrset cache.
|
||||
* @param env: module environment with caches.
|
||||
@@ -103,10 +103,10 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
|
||||
/** allocate rrset in region - no more locks needed */
|
||||
static struct ub_packed_rrset_key*
|
||||
copy_rrset(struct ub_packed_rrset_key* key, struct region* region,
|
||||
copy_rrset(struct ub_packed_rrset_key* key, struct regional* region,
|
||||
uint32_t now)
|
||||
{
|
||||
struct ub_packed_rrset_key* ck = region_alloc(region,
|
||||
struct ub_packed_rrset_key* ck = regional_alloc(region,
|
||||
sizeof(struct ub_packed_rrset_key));
|
||||
struct packed_rrset_data* d;
|
||||
struct packed_rrset_data* data = (struct packed_rrset_data*)
|
||||
@@ -119,12 +119,12 @@ copy_rrset(struct ub_packed_rrset_key* key, struct region* region,
|
||||
ck->entry.hash = key->entry.hash;
|
||||
ck->entry.key = ck;
|
||||
ck->rk = key->rk;
|
||||
ck->rk.dname = region_alloc_init(region, key->rk.dname,
|
||||
ck->rk.dname = regional_alloc_init(region, key->rk.dname,
|
||||
key->rk.dname_len);
|
||||
if(!ck->rk.dname)
|
||||
return NULL;
|
||||
dsize = packed_rrset_sizeof(data);
|
||||
d = (struct packed_rrset_data*)region_alloc_init(region, data, dsize);
|
||||
d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
|
||||
if(!d)
|
||||
return NULL;
|
||||
ck->entry.data = d;
|
||||
@@ -167,7 +167,7 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/** add addr to additional section */
|
||||
static void
|
||||
addr_to_additional(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
struct dns_msg* msg, uint32_t now)
|
||||
{
|
||||
if((msg->rep->rrsets[msg->rep->rrset_count] =
|
||||
@@ -179,8 +179,9 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
|
||||
/** find and add A and AAAA records for nameservers in delegpt */
|
||||
static int
|
||||
find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region,
|
||||
struct delegpt* dp, uint32_t now, struct dns_msg** msg)
|
||||
find_add_addrs(struct module_env* env, uint16_t qclass,
|
||||
struct regional* region, struct delegpt* dp, uint32_t now,
|
||||
struct dns_msg** msg)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
struct ub_packed_rrset_key* akey;
|
||||
@@ -214,7 +215,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, struct region* region,
|
||||
/** find and add A and AAAA records for missing nameservers in delegpt */
|
||||
int
|
||||
cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
struct region* region, struct delegpt* dp)
|
||||
struct regional* region, struct delegpt* dp)
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
struct ub_packed_rrset_key* akey;
|
||||
@@ -250,7 +251,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
|
||||
/** find and add DS or NSEC to delegation msg */
|
||||
static void
|
||||
find_add_ds(struct module_env* env, struct region* region,
|
||||
find_add_ds(struct module_env* env, struct regional* region,
|
||||
struct dns_msg* msg, struct delegpt* dp, uint32_t now)
|
||||
{
|
||||
/* Lookup the DS or NSEC at the delegation point. */
|
||||
@@ -281,21 +282,21 @@ find_add_ds(struct module_env* env, struct region* region,
|
||||
/** create referral message with NS and query */
|
||||
static struct dns_msg*
|
||||
create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct region* region, struct ub_packed_rrset_key* nskey,
|
||||
struct regional* region, struct ub_packed_rrset_key* nskey,
|
||||
struct packed_rrset_data* nsdata, uint32_t now)
|
||||
{
|
||||
struct dns_msg* msg = (struct dns_msg*)region_alloc(region,
|
||||
struct dns_msg* msg = (struct dns_msg*)regional_alloc(region,
|
||||
sizeof(struct dns_msg));
|
||||
if(!msg)
|
||||
return NULL;
|
||||
msg->qinfo.qname = region_alloc_init(region, qname, qnamelen);
|
||||
msg->qinfo.qname = regional_alloc_init(region, qname, qnamelen);
|
||||
if(!msg->qinfo.qname)
|
||||
return NULL;
|
||||
msg->qinfo.qname_len = qnamelen;
|
||||
msg->qinfo.qtype = qtype;
|
||||
msg->qinfo.qclass = qclass;
|
||||
/* non-packed reply_info, because it needs to grow the array */
|
||||
msg->rep = (struct reply_info*)region_alloc(region,
|
||||
msg->rep = (struct reply_info*)regional_alloc(region,
|
||||
sizeof(struct reply_info)-sizeof(struct rrset_ref));
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
@@ -308,7 +309,8 @@ create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
* A rrset for every NS RR
|
||||
* AAAA rrset for every NS RR
|
||||
*/
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)region_alloc(region,
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)
|
||||
regional_alloc(region,
|
||||
(2 + nsdata->count*2)*sizeof(struct ub_packed_rrset_key*));
|
||||
if(!msg->rep->rrsets)
|
||||
return NULL;
|
||||
@@ -323,7 +325,7 @@ create_msg(uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct delegpt*
|
||||
dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
||||
size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct region* region, struct dns_msg** msg, uint32_t now)
|
||||
struct regional* region, struct dns_msg** msg, uint32_t now)
|
||||
{
|
||||
/* try to find closest NS rrset */
|
||||
struct ub_packed_rrset_key* nskey;
|
||||
@@ -366,22 +368,23 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
|
||||
|
||||
/** allocate dns_msg from query_info and reply_info */
|
||||
static struct dns_msg*
|
||||
gen_dns_msg(struct region* region, struct query_info* q, size_t num)
|
||||
gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
|
||||
{
|
||||
struct dns_msg* msg = (struct dns_msg*)region_alloc(region,
|
||||
struct dns_msg* msg = (struct dns_msg*)regional_alloc(region,
|
||||
sizeof(struct dns_msg));
|
||||
if(!msg)
|
||||
return NULL;
|
||||
memcpy(&msg->qinfo, q, sizeof(struct query_info));
|
||||
msg->qinfo.qname = region_alloc_init(region, q->qname, q->qname_len);
|
||||
msg->qinfo.qname = regional_alloc_init(region, q->qname, q->qname_len);
|
||||
if(!msg->qinfo.qname)
|
||||
return NULL;
|
||||
/* allocate replyinfo struct and rrset key array separately */
|
||||
msg->rep = (struct reply_info*)region_alloc(region,
|
||||
msg->rep = (struct reply_info*)regional_alloc(region,
|
||||
sizeof(struct reply_info) - sizeof(struct rrset_ref));
|
||||
if(!msg->rep)
|
||||
return NULL;
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)region_alloc(region,
|
||||
msg->rep->rrsets = (struct ub_packed_rrset_key**)
|
||||
regional_alloc(region,
|
||||
num * sizeof(struct ub_packed_rrset_key*));
|
||||
if(!msg->rep->rrsets)
|
||||
return NULL;
|
||||
@@ -391,7 +394,7 @@ gen_dns_msg(struct region* region, struct query_info* q, size_t num)
|
||||
/** generate dns_msg from cached message */
|
||||
static struct dns_msg*
|
||||
tomsg(struct module_env* env, struct msgreply_entry* e, struct reply_info* r,
|
||||
struct region* region, uint32_t now, struct region* scratch)
|
||||
struct regional* region, uint32_t now, struct regional* scratch)
|
||||
{
|
||||
struct dns_msg* msg;
|
||||
size_t i;
|
||||
@@ -424,7 +427,7 @@ tomsg(struct module_env* env, struct msgreply_entry* e, struct reply_info* r,
|
||||
|
||||
/** synthesize RRset-only response from cached RRset item */
|
||||
static struct dns_msg*
|
||||
rrset_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
uint32_t now, struct query_info* q)
|
||||
{
|
||||
struct dns_msg* msg;
|
||||
@@ -451,7 +454,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
|
||||
/** synthesize DNAME+CNAME response from cached DNAME item */
|
||||
static struct dns_msg*
|
||||
synth_dname_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
uint32_t now, struct query_info* q)
|
||||
{
|
||||
struct dns_msg* msg;
|
||||
@@ -485,7 +488,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
msg->rep->flags |= LDNS_RCODE_YXDOMAIN;
|
||||
return msg;
|
||||
}
|
||||
newname = (uint8_t*)region_alloc(region, newlen);
|
||||
newname = (uint8_t*)regional_alloc(region, newlen);
|
||||
if(!newname)
|
||||
return NULL;
|
||||
/* new name is concatenation of qname front (without DNAME owner)
|
||||
@@ -493,7 +496,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
memcpy(newname, q->qname, q->qname_len-rrset->rk.dname_len);
|
||||
memmove(newname+(q->qname_len-rrset->rk.dname_len), dtarg, dtarglen);
|
||||
/* create rest of CNAME rrset */
|
||||
ck = (struct ub_packed_rrset_key*)region_alloc(region,
|
||||
ck = (struct ub_packed_rrset_key*)regional_alloc(region,
|
||||
sizeof(struct ub_packed_rrset_key));
|
||||
if(!ck)
|
||||
return NULL;
|
||||
@@ -503,12 +506,12 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
ck->rk.type = htons(LDNS_RR_TYPE_CNAME);
|
||||
ck->rk.rrset_class = rrset->rk.rrset_class;
|
||||
ck->rk.flags = 0;
|
||||
ck->rk.dname = region_alloc_init(region, q->qname, q->qname_len);
|
||||
ck->rk.dname = regional_alloc_init(region, q->qname, q->qname_len);
|
||||
if(!ck->rk.dname)
|
||||
return NULL;
|
||||
ck->rk.dname_len = q->qname_len;
|
||||
ck->entry.hash = rrset_key_hash(&ck->rk);
|
||||
newd = (struct packed_rrset_data*)region_alloc(region,
|
||||
newd = (struct packed_rrset_data*)regional_alloc(region,
|
||||
sizeof(struct packed_rrset_data) + sizeof(size_t) +
|
||||
sizeof(uint8_t*) + sizeof(uint32_t) + sizeof(uint16_t)
|
||||
+ newlen);
|
||||
@@ -535,7 +538,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct region* region,
|
||||
struct dns_msg*
|
||||
dns_cache_lookup(struct module_env* env,
|
||||
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct region* region, struct region* scratch)
|
||||
struct regional* region, struct regional* scratch)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
struct query_info k;
|
||||
|
||||
Vendored
+4
-6
@@ -46,7 +46,7 @@
|
||||
struct module_env;
|
||||
struct query_info;
|
||||
struct reply_info;
|
||||
struct region;
|
||||
struct regional;
|
||||
struct delegpt;
|
||||
|
||||
/**
|
||||
@@ -107,7 +107,7 @@ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
*/
|
||||
struct delegpt* dns_cache_find_delegation(struct module_env* env,
|
||||
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct region* region, struct dns_msg** msg, uint32_t timenow);
|
||||
struct regional* region, struct dns_msg** msg, uint32_t timenow);
|
||||
|
||||
/**
|
||||
* Find cached message
|
||||
@@ -124,7 +124,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
|
||||
*/
|
||||
struct dns_msg* dns_cache_lookup(struct module_env* env,
|
||||
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
|
||||
struct region* region, struct region* scratch);
|
||||
struct regional* region, struct regional* scratch);
|
||||
|
||||
/**
|
||||
* find and add A and AAAA records for missing nameservers in delegpt
|
||||
@@ -135,8 +135,6 @@ struct dns_msg* dns_cache_lookup(struct module_env* env,
|
||||
* @return false on alloc failure.
|
||||
*/
|
||||
int cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
struct region* region, struct delegpt* dp);
|
||||
|
||||
/** Find covering DNAME */
|
||||
struct regional* region, struct delegpt* dp);
|
||||
|
||||
#endif /* SERVICES_CACHE_DNS_H */
|
||||
|
||||
Vendored
+48
-28
@@ -47,9 +47,7 @@
|
||||
#include "util/net_help.h"
|
||||
#include "util/config_file.h"
|
||||
|
||||
/** calculate size for the hashtable, does not count size of lameness,
|
||||
* so the hashtable is a fixed number of items */
|
||||
static size_t
|
||||
size_t
|
||||
infra_host_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
{
|
||||
struct infra_host_key* key = (struct infra_host_key*)k;
|
||||
@@ -57,8 +55,7 @@ infra_host_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
+ lock_get_mem(&key->entry.lock);
|
||||
}
|
||||
|
||||
/** compare two addresses, returns -1, 0, or +1 */
|
||||
static int
|
||||
int
|
||||
infra_host_compfunc(void* key1, void* key2)
|
||||
{
|
||||
struct infra_host_key* k1 = (struct infra_host_key*)key1;
|
||||
@@ -66,20 +63,17 @@ infra_host_compfunc(void* key1, void* key2)
|
||||
return sockaddr_cmp(&k1->addr, k1->addrlen, &k2->addr, k2->addrlen);
|
||||
}
|
||||
|
||||
/** delete key, and destroy the lock */
|
||||
static void
|
||||
infra_host_delkeyfunc(void* k, void* ATTR_UNUSED(arg), int il)
|
||||
void
|
||||
infra_host_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct infra_host_key* key = (struct infra_host_key*)k;
|
||||
if(!key)
|
||||
return;
|
||||
if(il) { lock_rw_unlock(&key->entry.lock); }
|
||||
lock_rw_destroy(&key->entry.lock);
|
||||
free(key);
|
||||
}
|
||||
|
||||
/** delete data and destroy the lameness hashtable */
|
||||
static void
|
||||
void
|
||||
infra_host_deldatafunc(void* d, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct infra_host_data* data = (struct infra_host_data*)d;
|
||||
@@ -271,6 +265,7 @@ infra_lookup_lame(struct infra_host_data* host,
|
||||
struct lruhash_entry* e;
|
||||
struct infra_lame_key k;
|
||||
struct infra_lame_data *d;
|
||||
int dl;
|
||||
if(!host->lameness)
|
||||
return 0;
|
||||
k.entry.hash = hash_lameness(name, namelen);
|
||||
@@ -286,13 +281,12 @@ infra_lookup_lame(struct infra_host_data* host,
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
dl = d->isdnsseclame;
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
return dl?2:1;
|
||||
}
|
||||
|
||||
/** calculate size, which is fixed, zonename does not count so that
|
||||
* a fixed number of items is stored */
|
||||
static size_t
|
||||
size_t
|
||||
infra_lame_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
{
|
||||
struct infra_lame_key* key = (struct infra_lame_key*)k;
|
||||
@@ -300,8 +294,7 @@ infra_lame_sizefunc(void* k, void* ATTR_UNUSED(d))
|
||||
+ key->namelen + lock_get_mem(&key->entry.lock);
|
||||
}
|
||||
|
||||
/** compare zone names, returns -1, 0, +1 */
|
||||
static int
|
||||
int
|
||||
infra_lame_compfunc(void* key1, void* key2)
|
||||
{
|
||||
struct infra_lame_key* k1 = (struct infra_lame_key*)key1;
|
||||
@@ -314,21 +307,18 @@ infra_lame_compfunc(void* key1, void* key2)
|
||||
return query_dname_compare(k1->zonename, k2->zonename);
|
||||
}
|
||||
|
||||
/** free key, lock and zonename */
|
||||
static void
|
||||
infra_lame_delkeyfunc(void* k, void* ATTR_UNUSED(arg), int il)
|
||||
void
|
||||
infra_lame_delkeyfunc(void* k, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct infra_lame_key* key = (struct infra_lame_key*)k;
|
||||
if(!key)
|
||||
return;
|
||||
if(il) { lock_rw_unlock(&key->entry.lock); }
|
||||
lock_rw_destroy(&key->entry.lock);
|
||||
free(key->zonename);
|
||||
free(key);
|
||||
}
|
||||
|
||||
/** free the lameness data */
|
||||
static void
|
||||
void
|
||||
infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
if(!d)
|
||||
@@ -339,7 +329,7 @@ infra_lame_deldatafunc(void* d, void* ATTR_UNUSED(arg))
|
||||
int
|
||||
infra_set_lame(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, time_t timenow)
|
||||
uint8_t* name, size_t namelen, time_t timenow, int dnsseclame)
|
||||
{
|
||||
struct infra_host_data* data;
|
||||
struct lruhash_entry* e;
|
||||
@@ -370,6 +360,7 @@ infra_set_lame(struct infra_cache* infra,
|
||||
k->entry.key = (void*)k;
|
||||
k->entry.data = (void*)d;
|
||||
d->ttl = timenow + infra->lame_ttl;
|
||||
d->isdnsseclame = dnsseclame;
|
||||
k->namelen = namelen;
|
||||
e = infra_lookup_host_nottl(infra, addr, addrlen, 1);
|
||||
if(!e) {
|
||||
@@ -411,6 +402,23 @@ infra_set_lame(struct infra_cache* infra,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
infra_update_tcp_works(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
addrlen, 1);
|
||||
struct infra_host_data* data;
|
||||
if(!e)
|
||||
return; /* doesn't exist */
|
||||
data = (struct infra_host_data*)e->data;
|
||||
if(data->rtt.rto >= RTT_MAX_TIMEOUT)
|
||||
/* do not disqualify this server altogether, it is better
|
||||
* than nothing */
|
||||
data->rtt.rto = RTT_MAX_TIMEOUT-1;
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
|
||||
int
|
||||
infra_rtt_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
@@ -420,6 +428,7 @@ infra_rtt_update(struct infra_cache* infra,
|
||||
addrlen, 1);
|
||||
struct infra_host_data* data;
|
||||
int needtoinsert = 0;
|
||||
int rto = 1;
|
||||
if(!e) {
|
||||
if(!(e = new_host_entry(infra, addr, addrlen, timenow)))
|
||||
return 0;
|
||||
@@ -431,11 +440,13 @@ infra_rtt_update(struct infra_cache* infra,
|
||||
if(roundtrip == -1)
|
||||
rtt_lost(&data->rtt);
|
||||
else rtt_update(&data->rtt, roundtrip);
|
||||
if(data->rtt.rto > 0)
|
||||
rto = data->rtt.rto;
|
||||
|
||||
if(needtoinsert)
|
||||
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
|
||||
else { lock_rw_unlock(&e->lock); }
|
||||
return 1;
|
||||
return rto;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -466,22 +477,31 @@ infra_edns_update(struct infra_cache* infra,
|
||||
int
|
||||
infra_get_lame_rtt(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, int* lame, int* rtt, time_t timenow)
|
||||
uint8_t* name, size_t namelen, int* lame, int* dnsseclame,
|
||||
int* rtt, time_t timenow)
|
||||
{
|
||||
struct infra_host_data* host;
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
addrlen, 0);
|
||||
int lm;
|
||||
if(!e)
|
||||
return 0;
|
||||
host = (struct infra_host_data*)e->data;
|
||||
*rtt = rtt_unclamped(&host->rtt);
|
||||
/* check lameness first, if so, ttl on host does not matter anymore */
|
||||
if(infra_lookup_lame(host, name, namelen, timenow)) {
|
||||
if((lm=infra_lookup_lame(host, name, namelen, timenow))) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
*lame = 1;
|
||||
if(lm == 1) {
|
||||
*lame = 1;
|
||||
*dnsseclame = 0;
|
||||
} else {
|
||||
*lame = 0;
|
||||
*dnsseclame = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
*lame = 0;
|
||||
*dnsseclame = 0;
|
||||
if(timenow > host->ttl) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
|
||||
Vendored
+47
-4
@@ -91,6 +91,9 @@ struct infra_lame_key {
|
||||
struct infra_lame_data {
|
||||
/** TTL of this entry. absolute time. */
|
||||
time_t ttl;
|
||||
/** is the host lame (does not serve the zone authoritatively),
|
||||
* or is the host dnssec lame (does not serve DNSSEC data) */
|
||||
int isdnsseclame;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -172,7 +175,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
* @param name: domain name of zone apex.
|
||||
* @param namelen: length of domain name.
|
||||
* @param timenow: what time it is now.
|
||||
* @return: 0 if not lame or unknown or timed out, true if lame.
|
||||
* @return: 0 if not lame or unknown or timed out, 1 if lame, 2 if dnsseclame.
|
||||
*/
|
||||
int infra_lookup_lame(struct infra_host_data* host,
|
||||
uint8_t* name, size_t namelen, time_t timenow);
|
||||
@@ -185,11 +188,13 @@ int infra_lookup_lame(struct infra_host_data* host,
|
||||
* @param name: domain name of zone apex.
|
||||
* @param namelen: length of domain name.
|
||||
* @param timenow: what time it is now.
|
||||
* @param dnsseclame: if true the host is set dnssec lame.
|
||||
* if false, the host is marked lame (not serving the zone).
|
||||
* @return: 0 on error.
|
||||
*/
|
||||
int infra_set_lame(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, time_t timenow);
|
||||
uint8_t* name, size_t namelen, time_t timenow, int dnsseclame);
|
||||
|
||||
/**
|
||||
* Update rtt information for the host.
|
||||
@@ -199,12 +204,21 @@ int infra_set_lame(struct infra_cache* infra,
|
||||
* @param roundtrip: estimate of roundtrip time in milliseconds or -1 for
|
||||
* timeout.
|
||||
* @param timenow: what time it is now.
|
||||
* @return: 0 on error.
|
||||
* @return: 0 on error. new rto otherwise.
|
||||
*/
|
||||
int infra_rtt_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int roundtrip, time_t timenow);
|
||||
|
||||
/**
|
||||
* Update information for the host, store that a TCP transaction works.
|
||||
* @param infra: infrastructure cache.
|
||||
* @param addr: host address.
|
||||
* @param addrlen: length of addr.
|
||||
*/
|
||||
void infra_update_tcp_works(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Update edns information for the host.
|
||||
* @param infra: infrastructure cache.
|
||||
@@ -226,6 +240,8 @@ int infra_edns_update(struct infra_cache* infra,
|
||||
* @param name: zone name.
|
||||
* @param namelen: zone name length.
|
||||
* @param lame: if function returns true, this returns lameness of the zone.
|
||||
* @param dnsseclame: if function returns true, this returns if the zone
|
||||
* is dnssec-lame.
|
||||
* @param rtt: if function returns true, this returns avg rtt of the server.
|
||||
* The rtt value is unclamped and reflects recent timeouts.
|
||||
* @param timenow: what time it is now.
|
||||
@@ -233,7 +249,8 @@ int infra_edns_update(struct infra_cache* infra,
|
||||
*/
|
||||
int infra_get_lame_rtt(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, int* lame, int* rtt, time_t timenow);
|
||||
uint8_t* name, size_t namelen, int* lame, int* dnsseclame,
|
||||
int* rtt, time_t timenow);
|
||||
|
||||
/**
|
||||
* Get memory used by the infra cache.
|
||||
@@ -242,4 +259,30 @@ int infra_get_lame_rtt(struct infra_cache* infra,
|
||||
*/
|
||||
size_t infra_get_mem(struct infra_cache* infra);
|
||||
|
||||
/** calculate size for the hashtable, does not count size of lameness,
|
||||
* so the hashtable is a fixed number of items */
|
||||
size_t infra_host_sizefunc(void* k, void* d);
|
||||
|
||||
/** compare two addresses, returns -1, 0, or +1 */
|
||||
int infra_host_compfunc(void* key1, void* key2);
|
||||
|
||||
/** delete key, and destroy the lock */
|
||||
void infra_host_delkeyfunc(void* k, void* arg);
|
||||
|
||||
/** delete data and destroy the lameness hashtable */
|
||||
void infra_host_deldatafunc(void* d, void* arg);
|
||||
|
||||
/** calculate size, which is fixed, zonename does not count so that
|
||||
* a fixed number of items is stored */
|
||||
size_t infra_lame_sizefunc(void* k, void* d);
|
||||
|
||||
/** compare zone names, returns -1, 0, +1 */
|
||||
int infra_lame_compfunc(void* key1, void* key2);
|
||||
|
||||
/** free key, lock and zonename */
|
||||
void infra_lame_delkeyfunc(void* k, void* arg);
|
||||
|
||||
/** free the lameness data */
|
||||
void infra_lame_deldatafunc(void* d, void* arg);
|
||||
|
||||
#endif /* SERVICES_CACHE_INFRA_H */
|
||||
|
||||
Vendored
+14
-18
@@ -44,9 +44,16 @@
|
||||
#include "util/config_file.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
|
||||
void
|
||||
rrset_markdel(void* key)
|
||||
{
|
||||
struct ub_packed_rrset_key* r = (struct ub_packed_rrset_key*)key;
|
||||
r->id = 0;
|
||||
}
|
||||
|
||||
struct rrset_cache* rrset_cache_create(struct config_file* cfg,
|
||||
struct alloc_cache* alloc)
|
||||
{
|
||||
@@ -57,6 +64,7 @@ struct rrset_cache* rrset_cache_create(struct config_file* cfg,
|
||||
struct rrset_cache *r = (struct rrset_cache*)slabhash_create(slabs,
|
||||
startarray, maxmem, ub_rrset_sizefunc, ub_rrset_compare,
|
||||
ub_rrset_key_delete, rrset_data_delete, alloc);
|
||||
slabhash_setmarkdel(&r->table, &rrset_markdel);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -65,6 +73,7 @@ void rrset_cache_delete(struct rrset_cache* r)
|
||||
if(!r)
|
||||
return;
|
||||
slabhash_delete(&r->table);
|
||||
/* slabhash delete also does free(r), since table is first in struct*/
|
||||
}
|
||||
|
||||
struct rrset_cache* rrset_cache_adjust(struct rrset_cache *r,
|
||||
@@ -134,21 +143,6 @@ need_to_update_rrset(void* nd, void* cd, uint32_t timenow, int equal)
|
||||
/* o same trust, but different in data - insert it */
|
||||
if( newd->trust == cached->trust && !equal )
|
||||
return 1;
|
||||
/* o see if TTL is better than TTL in cache. */
|
||||
/* if so, see if rrset+rdata is the same */
|
||||
/* if so, update TTL in cache, even if trust is worse. */
|
||||
if( newd->ttl > cached->ttl && equal ) {
|
||||
/* if the cached rrset is bogus, and this one equal,
|
||||
* do not update the TTL - let it expire. */
|
||||
if(cached->security == sec_status_bogus)
|
||||
return 0;
|
||||
/* since all else is the same, use the best trust value */
|
||||
if(newd->trust < cached->trust) {
|
||||
newd->trust = cached->trust;
|
||||
newd->security = cached->security;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -177,6 +171,7 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
hashvalue_t h = k->entry.hash;
|
||||
uint16_t rrset_type = ntohs(k->rk.type);
|
||||
int equal = 0;
|
||||
log_assert(ref->id != 0 && k->id != 0);
|
||||
/* looks up item with a readlock - no editing! */
|
||||
if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) {
|
||||
/* return id and key as they will be used in the cache
|
||||
@@ -206,6 +201,7 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
/* use insert to update entry to manage lruhash
|
||||
* cache size values nicely. */
|
||||
}
|
||||
log_assert(ref->key->id != 0);
|
||||
slabhash_insert(&r->table, h, &k->entry, k->entry.data, alloc);
|
||||
if(e) {
|
||||
/* For NSEC, NSEC3, DNAME, when rdata is updated, update
|
||||
@@ -284,12 +280,12 @@ rrset_array_unlock(struct rrset_ref* ref, size_t count)
|
||||
}
|
||||
|
||||
void
|
||||
rrset_array_unlock_touch(struct rrset_cache* r, struct region* scratch,
|
||||
rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch,
|
||||
struct rrset_ref* ref, size_t count)
|
||||
{
|
||||
hashvalue_t* h;
|
||||
size_t i;
|
||||
if(!(h = (hashvalue_t*)region_alloc(scratch,
|
||||
if(!(h = (hashvalue_t*)regional_alloc(scratch,
|
||||
sizeof(hashvalue_t)*count)))
|
||||
log_warn("rrset LRU: memory allocation failed");
|
||||
else /* store hash values */
|
||||
|
||||
Vendored
+5
-2
@@ -47,7 +47,7 @@
|
||||
struct config_file;
|
||||
struct alloc_cache;
|
||||
struct rrset_ref;
|
||||
struct region;
|
||||
struct regional;
|
||||
|
||||
/**
|
||||
* The rrset cache
|
||||
@@ -181,7 +181,7 @@ void rrset_array_unlock(struct rrset_ref* ref, size_t count);
|
||||
* duplicate references are allowed and handled.
|
||||
* @param count: size of array.
|
||||
*/
|
||||
void rrset_array_unlock_touch(struct rrset_cache* r, struct region* scratch,
|
||||
void rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch,
|
||||
struct rrset_ref* ref, size_t count);
|
||||
|
||||
/**
|
||||
@@ -207,4 +207,7 @@ void rrset_update_sec_status(struct rrset_cache* r,
|
||||
void rrset_check_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
|
||||
/** mark rrset to be deleted, set id=0 */
|
||||
void rrset_markdel(void* key);
|
||||
|
||||
#endif /* SERVICES_CACHE_RRSET_H */
|
||||
|
||||
+113
-29
@@ -74,6 +74,7 @@ verbose_print_addr(struct addrinfo *addr)
|
||||
(socklen_t)sizeof(buf)) == 0) {
|
||||
strncpy(buf, "(null)", sizeof(buf));
|
||||
}
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
verbose(VERB_ALGO, "creating %s%s socket %s %d",
|
||||
addr->ai_socktype==SOCK_DGRAM?"udp":
|
||||
addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
|
||||
@@ -85,11 +86,13 @@ verbose_print_addr(struct addrinfo *addr)
|
||||
}
|
||||
|
||||
int
|
||||
create_udp_sock(struct addrinfo *addr)
|
||||
create_udp_sock(struct addrinfo *addr, int v6only)
|
||||
{
|
||||
int s;
|
||||
# if defined(IPV6_V6ONLY)
|
||||
# if defined(IPV6_USE_MIN_MTU)
|
||||
int on=1;
|
||||
# else
|
||||
(void)v6only;
|
||||
# endif
|
||||
verbose_print_addr(addr);
|
||||
if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
|
||||
@@ -98,11 +101,14 @@ create_udp_sock(struct addrinfo *addr)
|
||||
}
|
||||
if(addr->ai_family == AF_INET6) {
|
||||
# if defined(IPV6_V6ONLY)
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
if(v6only) {
|
||||
int val=(v6only==2)?0:1;
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&val, (socklen_t)sizeof(val)) < 0) {
|
||||
log_err("setsockopt(..., IPV6_V6ONLY"
|
||||
", ...) failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
# if defined(IPV6_USE_MIN_MTU)
|
||||
@@ -134,10 +140,11 @@ create_udp_sock(struct addrinfo *addr)
|
||||
/**
|
||||
* Create and bind TCP listening socket
|
||||
* @param addr: address info ready to make socket.
|
||||
* @param v6only: enable ip6 only flag on ip6 sockets.
|
||||
* @return: the socket. -1 on error.
|
||||
*/
|
||||
static int
|
||||
create_tcp_accept_sock(struct addrinfo *addr)
|
||||
create_tcp_accept_sock(struct addrinfo *addr, int v6only)
|
||||
{
|
||||
int s, flag;
|
||||
#if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
|
||||
@@ -157,7 +164,7 @@ create_tcp_accept_sock(struct addrinfo *addr)
|
||||
}
|
||||
#endif /* SO_REUSEADDR */
|
||||
#if defined(IPV6_V6ONLY)
|
||||
if(addr->ai_family == AF_INET6) {
|
||||
if(addr->ai_family == AF_INET6 && v6only) {
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
|
||||
@@ -165,6 +172,8 @@ create_tcp_accept_sock(struct addrinfo *addr)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)v6only;
|
||||
#endif /* IPV6_V6ONLY */
|
||||
if(bind(s, (struct sockaddr*)addr->ai_addr, addr->ai_addrlen) != 0) {
|
||||
log_err("can't bind socket: %s", strerror(errno));
|
||||
@@ -191,7 +200,7 @@ create_tcp_accept_sock(struct addrinfo *addr)
|
||||
*/
|
||||
static int
|
||||
make_sock(int stype, const char* ifname, const char* port,
|
||||
struct addrinfo *hints)
|
||||
struct addrinfo *hints, int v6only)
|
||||
{
|
||||
struct addrinfo *res = NULL;
|
||||
int r, s;
|
||||
@@ -203,8 +212,8 @@ make_sock(int stype, const char* ifname, const char* port,
|
||||
return -1;
|
||||
}
|
||||
if(stype == SOCK_DGRAM)
|
||||
s = create_udp_sock(res);
|
||||
else s = create_tcp_accept_sock(res);
|
||||
s = create_udp_sock(res, v6only);
|
||||
else s = create_tcp_accept_sock(res, v6only);
|
||||
freeaddrinfo(res);
|
||||
return s;
|
||||
}
|
||||
@@ -213,11 +222,11 @@ make_sock(int stype, const char* ifname, const char* port,
|
||||
* Add port to open ports list.
|
||||
* @param list: list head. changed.
|
||||
* @param s: fd.
|
||||
* @param is_udp: if fd is UDP.
|
||||
* @param ftype: if fd is UDP.
|
||||
* @return false on failure. list in unchanged then.
|
||||
*/
|
||||
static int
|
||||
port_insert(struct listen_port** list, int s, int is_udp)
|
||||
port_insert(struct listen_port** list, int s, enum listen_type ftype)
|
||||
{
|
||||
struct listen_port* item = (struct listen_port*)malloc(
|
||||
sizeof(struct listen_port));
|
||||
@@ -225,14 +234,67 @@ port_insert(struct listen_port** list, int s, int is_udp)
|
||||
return 0;
|
||||
item->next = *list;
|
||||
item->fd = s;
|
||||
item->is_udp = is_udp;
|
||||
item->ftype = ftype;
|
||||
*list = item;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** set fd to receive source address packet info */
|
||||
static int
|
||||
set_recvpktinfo(int s, int family)
|
||||
{
|
||||
int on = 1;
|
||||
if(family == AF_INET6) {
|
||||
# ifdef IPV6_RECVPKTINFO
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IPV6_RECVPKTINFO, ...) failed: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
# elif defined(IPV6_PKTINFO)
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IPV6_PKTINFO, ...) failed: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please "
|
||||
"disable interface-automatic in config");
|
||||
return 0;
|
||||
# endif /* defined IPV6_RECVPKTINFO */
|
||||
|
||||
} else if(family == AF_INET) {
|
||||
# ifdef IP_RECVDSTADDR
|
||||
if(setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IP_RECVDSTADDR, ...) failed: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
# elif defined(IP_PKTINFO)
|
||||
if(setsockopt(s, IPPROTO_IP, IP_PKTINFO,
|
||||
&on, (socklen_t)sizeof(on)) < 0) {
|
||||
log_err("setsockopt(..., IP_PKTINFO, ...) failed: %s",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
# else
|
||||
log_err("no IP_RECVDSTADDR or IP_PKTINFO option, please disable "
|
||||
"interface-automatic in config");
|
||||
return 0;
|
||||
# endif /* IP_PKTINFO */
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for ports_open. Creates one interface (or NULL for default).
|
||||
* @param ifname: The interface ip address.
|
||||
* @param do_auto: use automatic interface detection.
|
||||
* If enabled, then ifname must be the wildcard name.
|
||||
* @param do_udp: if udp should be used.
|
||||
* @param do_tcp: if udp should be used.
|
||||
* @param hints: for getaddrinfo. family and flags have to be set by caller.
|
||||
@@ -241,25 +303,36 @@ port_insert(struct listen_port** list, int s, int is_udp)
|
||||
* @return: returns false on error.
|
||||
*/
|
||||
static int
|
||||
ports_create_if(const char* ifname, int do_udp, int do_tcp,
|
||||
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
|
||||
struct addrinfo *hints, const char* port, struct listen_port** list)
|
||||
{
|
||||
int s;
|
||||
if(!do_udp && !do_tcp)
|
||||
return 0;
|
||||
if(do_udp) {
|
||||
if((s = make_sock(SOCK_DGRAM, ifname, port, hints)) == -1)
|
||||
if(do_auto) {
|
||||
if((s = make_sock(SOCK_DGRAM, ifname, port, hints, 1)) == -1)
|
||||
return 0;
|
||||
if(!port_insert(list, s, 1)) {
|
||||
/* getting source addr packet info is highly non-portable */
|
||||
if(!set_recvpktinfo(s, hints->ai_family))
|
||||
return 0;
|
||||
if(!port_insert(list, s, listen_type_udpancil)) {
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
} else if(do_udp) {
|
||||
/* regular udp socket */
|
||||
if((s = make_sock(SOCK_DGRAM, ifname, port, hints, 1)) == -1)
|
||||
return 0;
|
||||
if(!port_insert(list, s, listen_type_udp)) {
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(do_tcp) {
|
||||
if((s = make_sock(SOCK_STREAM, ifname, port, hints)) == -1) {
|
||||
if((s = make_sock(SOCK_STREAM, ifname, port, hints, 1)) == -1) {
|
||||
return 0;
|
||||
}
|
||||
if(!port_insert(list, s, 0)) {
|
||||
if(!port_insert(list, s, listen_type_tcp)) {
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
@@ -305,11 +378,15 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
||||
/* create comm points as needed */
|
||||
while(ports) {
|
||||
struct comm_point* cp = NULL;
|
||||
if(ports->is_udp)
|
||||
if(ports->ftype == listen_type_udp)
|
||||
cp = comm_point_create_udp(base, ports->fd,
|
||||
front->udp_buff, cb, cb_arg);
|
||||
else cp = comm_point_create_tcp(base, ports->fd,
|
||||
else if(ports->ftype == listen_type_tcp)
|
||||
cp = comm_point_create_tcp(base, ports->fd,
|
||||
tcp_accept_count, bufsize, cb, cb_arg);
|
||||
else if(ports->ftype == listen_type_udpancil)
|
||||
cp = comm_point_create_udp_ancil(base, ports->fd,
|
||||
front->udp_buff, cb, cb_arg);
|
||||
if(!cp) {
|
||||
log_err("can't create commpoint");
|
||||
listen_delete(front);
|
||||
@@ -382,12 +459,13 @@ listening_ports_open(struct config_file* cfg)
|
||||
struct listen_port* list = NULL;
|
||||
struct addrinfo hints;
|
||||
int i, do_ip4, do_ip6;
|
||||
int do_tcp;
|
||||
int do_tcp, do_auto;
|
||||
char portbuf[32];
|
||||
snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
|
||||
do_ip4 = cfg->do_ip4;
|
||||
do_ip6 = cfg->do_ip6;
|
||||
do_tcp = cfg->do_tcp;
|
||||
do_auto = cfg->if_automatic && cfg->do_udp;
|
||||
if(cfg->incoming_num_tcp == 0)
|
||||
do_tcp = 0;
|
||||
|
||||
@@ -404,11 +482,16 @@ listening_ports_open(struct config_file* cfg)
|
||||
if(!do_ip4 && !do_ip6) {
|
||||
return NULL;
|
||||
}
|
||||
if(do_auto && (!do_ip4 || !do_ip6)) {
|
||||
log_warn("interface_automatic option does not work when IP4 or IP6 is not enabled. Disabling option.");
|
||||
do_auto = 0;
|
||||
}
|
||||
/* create ip4 and ip6 ports so that return addresses are nice. */
|
||||
if(cfg->num_ifs == 0) {
|
||||
if(do_auto || cfg->num_ifs == 0) {
|
||||
if(do_ip6) {
|
||||
hints.ai_family = AF_INET6;
|
||||
if(!ports_create_if(NULL, cfg->do_udp, do_tcp,
|
||||
if(!ports_create_if(do_auto?"::0":"::1",
|
||||
do_auto, cfg->do_udp, do_tcp,
|
||||
&hints, portbuf, &list)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
@@ -416,7 +499,8 @@ listening_ports_open(struct config_file* cfg)
|
||||
}
|
||||
if(do_ip4) {
|
||||
hints.ai_family = AF_INET;
|
||||
if(!ports_create_if(NULL, cfg->do_udp, do_tcp,
|
||||
if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
|
||||
do_auto, cfg->do_udp, do_tcp,
|
||||
&hints, portbuf, &list)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
@@ -427,7 +511,7 @@ listening_ports_open(struct config_file* cfg)
|
||||
if(!do_ip6)
|
||||
continue;
|
||||
hints.ai_family = AF_INET6;
|
||||
if(!ports_create_if(cfg->ifs[i], cfg->do_udp,
|
||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
@@ -436,7 +520,7 @@ listening_ports_open(struct config_file* cfg)
|
||||
if(!do_ip4)
|
||||
continue;
|
||||
hints.ai_family = AF_INET;
|
||||
if(!ports_create_if(cfg->ifs[i], cfg->do_udp,
|
||||
if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
|
||||
do_tcp, &hints, portbuf, &list)) {
|
||||
listening_ports_free(list);
|
||||
return NULL;
|
||||
|
||||
@@ -74,6 +74,18 @@ struct listen_list {
|
||||
struct comm_point* com;
|
||||
};
|
||||
|
||||
/**
|
||||
* type of ports
|
||||
*/
|
||||
enum listen_type {
|
||||
/** udp type */
|
||||
listen_type_udp,
|
||||
/** tcp type */
|
||||
listen_type_tcp,
|
||||
/** udp ipv6 (v4mapped) for use with ancillary data */
|
||||
listen_type_udpancil
|
||||
};
|
||||
|
||||
/**
|
||||
* Single linked list to store shared ports that have been
|
||||
* opened for use by all threads.
|
||||
@@ -84,7 +96,7 @@ struct listen_port {
|
||||
/** file descriptor, open and ready for use */
|
||||
int fd;
|
||||
/** type of file descriptor, udp or tcp */
|
||||
int is_udp;
|
||||
enum listen_type ftype;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -154,8 +166,10 @@ size_t listen_get_mem(struct listen_dnsport* listen);
|
||||
/**
|
||||
* Create and bind nonblocking UDP socket
|
||||
* @param addr: address info ready to make socket.
|
||||
* @param v6only: if enabled, IP6 sockets get IP6ONLY option set.
|
||||
* if enabled with value 2 IP6ONLY option is disabled.
|
||||
* @return: the socket. -1 on error.
|
||||
*/
|
||||
int create_udp_sock(struct addrinfo* addr);
|
||||
int create_udp_sock(struct addrinfo* addr, int v6only);
|
||||
|
||||
#endif /* LISTEN_DNSPORT_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* services/localzone.h - local zones authority service.
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions to enable local zone authority service.
|
||||
*/
|
||||
|
||||
#ifndef SERVICES_LOCALZONE_H
|
||||
#define SERVICES_LOCALZONE_H
|
||||
#include "util/rbtree.h"
|
||||
struct ub_packed_rrset_key;
|
||||
struct regional;
|
||||
struct config_file;
|
||||
struct edns_data;
|
||||
struct query_info;
|
||||
|
||||
/**
|
||||
* Local zone type
|
||||
* This type determines processing for queries that did not match
|
||||
* local-data directly.
|
||||
*/
|
||||
enum localzone_type {
|
||||
/** drop query */
|
||||
local_zone_deny = 0,
|
||||
/** answer with error */
|
||||
local_zone_refuse,
|
||||
/** answer nxdomain or nodata */
|
||||
local_zone_static,
|
||||
/** resolve normally */
|
||||
local_zone_transparent,
|
||||
/** answer with data at zone apex */
|
||||
local_zone_redirect,
|
||||
/** remove default AS112 blocking contents for zone
|
||||
* nodefault is used in config not during service. */
|
||||
local_zone_nodefault
|
||||
};
|
||||
|
||||
/**
|
||||
* Authoritative local zones storage, shared.
|
||||
* This tree is fixed at startup, so, readonly, no locks or mutexes necessary.
|
||||
*/
|
||||
struct local_zones {
|
||||
/** rbtree of struct local_zone */
|
||||
rbtree_t ztree;
|
||||
};
|
||||
|
||||
/**
|
||||
* Local zone. A locally served authoritative zone.
|
||||
*/
|
||||
struct local_zone {
|
||||
/** rbtree node, key is name and class */
|
||||
rbnode_t node;
|
||||
/** parent zone, if any. */
|
||||
struct local_zone* parent;
|
||||
|
||||
/** zone name, in uncompressed wireformat */
|
||||
uint8_t* name;
|
||||
/** length of zone name */
|
||||
size_t namelen;
|
||||
/** number of labels in zone name */
|
||||
int namelabs;
|
||||
/** the class of this zone.
|
||||
* uses 'dclass' to not conflict with c++ keyword class. */
|
||||
uint16_t dclass;
|
||||
|
||||
/** how to process zone */
|
||||
enum localzone_type type;
|
||||
|
||||
/** in this region the zone's data is allocated.
|
||||
* the struct local_zone itself is malloced. */
|
||||
struct regional* region;
|
||||
/** local data for this zone
|
||||
* rbtree of struct local_data */
|
||||
rbtree_t data;
|
||||
/** if data contains zone apex SOA data, this is a ptr to it. */
|
||||
struct ub_packed_rrset_key* soa;
|
||||
};
|
||||
|
||||
/**
|
||||
* Local data. One domain name, and the RRs to go with it.
|
||||
*/
|
||||
struct local_data {
|
||||
/** rbtree node, key is name only */
|
||||
rbnode_t node;
|
||||
/** domain name */
|
||||
uint8_t* name;
|
||||
/** length of name */
|
||||
size_t namelen;
|
||||
/** number of labels in name */
|
||||
int namelabs;
|
||||
/** the data rrsets, with different types, linked list.
|
||||
* If this list is NULL, the node is an empty non-terminal. */
|
||||
struct local_rrset* rrsets;
|
||||
};
|
||||
|
||||
/**
|
||||
* A local data RRset
|
||||
*/
|
||||
struct local_rrset {
|
||||
/** next in list */
|
||||
struct local_rrset* next;
|
||||
/** RRset data item */
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create local zones storage
|
||||
* @return new struct or NULL on error.
|
||||
*/
|
||||
struct local_zones* local_zones_create();
|
||||
|
||||
/**
|
||||
* Delete local zones storage
|
||||
* @param zones: to delete.
|
||||
*/
|
||||
void local_zones_delete(struct local_zones* zones);
|
||||
|
||||
/**
|
||||
* Apply config settings; setup the local authoritative data.
|
||||
* @param zones: is set up.
|
||||
* @param cfg: config data.
|
||||
* @return false on error.
|
||||
*/
|
||||
int local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg);
|
||||
|
||||
/**
|
||||
* Compare two local_zone entries in rbtree. Sort hierarchical but not
|
||||
* canonical
|
||||
* @param z1: zone 1
|
||||
* @param z2: zone 2
|
||||
* @return: -1, 0, +1 comparison value.
|
||||
*/
|
||||
int local_zone_cmp(const void* z1, const void* z2);
|
||||
|
||||
/**
|
||||
* Compare two local_data entries in rbtree. Sort canonical.
|
||||
* @param d1: data 1
|
||||
* @param d2: data 2
|
||||
* @return: -1, 0, +1 comparison value.
|
||||
*/
|
||||
int local_data_cmp(const void* d1, const void* d2);
|
||||
|
||||
/**
|
||||
* Delete one zone
|
||||
* @param z: to delete.
|
||||
*/
|
||||
void local_zone_delete(struct local_zone* z);
|
||||
|
||||
/**
|
||||
* Lookup zone that contains the given name, class.
|
||||
* @param zones: the zones tree
|
||||
* @param name: dname to lookup
|
||||
* @param len: length of name.
|
||||
* @param labs: labelcount of name.
|
||||
* @param dclass: class to lookup.
|
||||
* @return closest local_zone or NULL if no covering zone is found.
|
||||
*/
|
||||
struct local_zone* local_zones_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass);
|
||||
|
||||
/**
|
||||
* Debug helper. Print all zones
|
||||
* @param zones: the zones tree
|
||||
*/
|
||||
void local_zones_print(struct local_zones* zones);
|
||||
|
||||
/**
|
||||
* Answer authoritatively for local zones.
|
||||
* @param zones: the stored zones (shared, read only).
|
||||
* @param qinfo: query info (parsed).
|
||||
* @param edns: edns info (parsed).
|
||||
* @param buf: buffer with query ID and flags, also for reply.
|
||||
* @param temp: temporary storage region.
|
||||
* @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).
|
||||
*/
|
||||
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
|
||||
struct edns_data* edns, ldns_buffer* buf, struct regional* temp);
|
||||
|
||||
#endif /* SERVICES_LOCALZONE_H */
|
||||
+187
-45
@@ -49,12 +49,13 @@
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/module.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/timehist.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "util/alloc.h"
|
||||
|
||||
/** compare two mesh_states */
|
||||
static int
|
||||
int
|
||||
mesh_state_compare(const void* ap, const void* bp)
|
||||
{
|
||||
struct mesh_state* a = (struct mesh_state*)ap;
|
||||
@@ -78,8 +79,7 @@ mesh_state_compare(const void* ap, const void* bp)
|
||||
return query_info_compare(&a->s.qinfo, &b->s.qinfo);
|
||||
}
|
||||
|
||||
/** compare two mesh references */
|
||||
static int
|
||||
int
|
||||
mesh_state_ref_compare(const void* ap, const void* bp)
|
||||
{
|
||||
struct mesh_state_ref* a = (struct mesh_state_ref*)ap;
|
||||
@@ -88,8 +88,7 @@ mesh_state_ref_compare(const void* ap, const void* bp)
|
||||
}
|
||||
|
||||
struct mesh_area*
|
||||
mesh_create(int num_modules, struct module_func_block** modfunc,
|
||||
struct module_env* env)
|
||||
mesh_create(struct module_stack* stack, struct module_env* env)
|
||||
{
|
||||
struct mesh_area* mesh = calloc(1, sizeof(struct mesh_area));
|
||||
if(!mesh) {
|
||||
@@ -102,8 +101,7 @@ mesh_create(int num_modules, struct module_func_block** modfunc,
|
||||
log_err("mesh area alloc: out of memory");
|
||||
return NULL;
|
||||
}
|
||||
mesh->num_modules = num_modules;
|
||||
mesh->modfunc = modfunc;
|
||||
mesh->mods = *stack;
|
||||
mesh->env = env;
|
||||
rbtree_init(&mesh->run, &mesh_state_compare);
|
||||
rbtree_init(&mesh->all, &mesh_state_compare);
|
||||
@@ -157,9 +155,9 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh->num_detached_states++;
|
||||
added = 1;
|
||||
}
|
||||
if(!s->reply_list && s->super_set.count == 0)
|
||||
if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
|
||||
was_detached = 1;
|
||||
if(!s->reply_list)
|
||||
if(!s->reply_list && !s->cb_list)
|
||||
was_noreply = 1;
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags)) {
|
||||
@@ -184,6 +182,52 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh_run(mesh, s, module_event_new, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, struct edns_data* edns, ldns_buffer* buf,
|
||||
uint16_t qid, mesh_cb_func_t cb, void* cb_arg)
|
||||
{
|
||||
struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags, 0);
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
/* see if it already exists, if not, create one */
|
||||
if(!s) {
|
||||
struct rbnode_t* n;
|
||||
s = mesh_state_create(mesh->env,qinfo, qflags, 0);
|
||||
if(!s) {
|
||||
return 0;
|
||||
}
|
||||
n = rbtree_insert(&mesh->all, &s->node);
|
||||
log_assert(n != NULL);
|
||||
/* set detached (it is now) */
|
||||
mesh->num_detached_states++;
|
||||
added = 1;
|
||||
}
|
||||
if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
|
||||
was_detached = 1;
|
||||
if(!s->reply_list && !s->cb_list)
|
||||
was_noreply = 1;
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
}
|
||||
/* update statistics */
|
||||
if(was_detached) {
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
mesh->num_detached_states--;
|
||||
}
|
||||
if(was_noreply) {
|
||||
mesh->num_reply_states ++;
|
||||
}
|
||||
mesh->num_reply_addrs++;
|
||||
if(added)
|
||||
mesh_run(mesh, s, module_event_new, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
|
||||
int is_ok, struct comm_reply* reply)
|
||||
{
|
||||
@@ -196,15 +240,15 @@ struct mesh_state*
|
||||
mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
uint16_t qflags, int prime)
|
||||
{
|
||||
region_type* region = region_create(malloc, free);
|
||||
struct regional* region = alloc_reg_obtain(env->alloc);
|
||||
struct mesh_state* mstate;
|
||||
int i;
|
||||
if(!region)
|
||||
return NULL;
|
||||
mstate = (struct mesh_state*)region_alloc(region,
|
||||
mstate = (struct mesh_state*)regional_alloc(region,
|
||||
sizeof(struct mesh_state));
|
||||
if(!mstate) {
|
||||
region_destroy(region);
|
||||
alloc_reg_release(env->alloc, region);
|
||||
return NULL;
|
||||
}
|
||||
memset(mstate, 0, sizeof(*mstate));
|
||||
@@ -215,14 +259,15 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
mstate->reply_list = NULL;
|
||||
rbtree_init(&mstate->super_set, &mesh_state_ref_compare);
|
||||
rbtree_init(&mstate->sub_set, &mesh_state_ref_compare);
|
||||
mstate->num_activated = 0;
|
||||
/* init module qstate */
|
||||
mstate->s.qinfo.qtype = qinfo->qtype;
|
||||
mstate->s.qinfo.qclass = qinfo->qclass;
|
||||
mstate->s.qinfo.qname_len = qinfo->qname_len;
|
||||
mstate->s.qinfo.qname = region_alloc_init(region, qinfo->qname,
|
||||
mstate->s.qinfo.qname = regional_alloc_init(region, qinfo->qname,
|
||||
qinfo->qname_len);
|
||||
if(!mstate->s.qinfo.qname) {
|
||||
region_destroy(region);
|
||||
alloc_reg_release(env->alloc, region);
|
||||
return NULL;
|
||||
}
|
||||
/* remove all weird bits from qflags */
|
||||
@@ -236,7 +281,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
mstate->s.env = env;
|
||||
mstate->s.mesh_info = mstate;
|
||||
/* init modules */
|
||||
for(i=0; i<env->mesh->num_modules; i++) {
|
||||
for(i=0; i<env->mesh->mods.num; i++) {
|
||||
mstate->s.minfo[i] = NULL;
|
||||
mstate->s.ext_state[i] = module_state_initial;
|
||||
}
|
||||
@@ -252,12 +297,13 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
return;
|
||||
/* de-init modules */
|
||||
mesh = mstate->s.env->mesh;
|
||||
for(i=0; i<mesh->num_modules; i++) {
|
||||
(*mesh->modfunc[i]->clear)(&mstate->s, i);
|
||||
for(i=0; i<mesh->mods.num; i++) {
|
||||
log_assert(fptr_whitelist_mod_clear(mesh->mods.mod[i]->clear));
|
||||
(*mesh->mods.mod[i]->clear)(&mstate->s, i);
|
||||
mstate->s.minfo[i] = NULL;
|
||||
mstate->s.ext_state[i] = module_finished;
|
||||
}
|
||||
region_destroy(mstate->s.region);
|
||||
alloc_reg_release(mstate->s.env->alloc, mstate->s.region);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -271,11 +317,12 @@ mesh_state_delete(struct module_qstate* qstate)
|
||||
mstate = qstate->mesh_info;
|
||||
mesh = mstate->s.env->mesh;
|
||||
mesh_detach_subs(&mstate->s);
|
||||
if(!mstate->reply_list && mstate->super_set.count == 0) {
|
||||
if(!mstate->reply_list && !mstate->cb_list
|
||||
&& mstate->super_set.count == 0) {
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
mesh->num_detached_states--;
|
||||
}
|
||||
if(mstate->reply_list) {
|
||||
if(mstate->reply_list || mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
@@ -299,7 +346,8 @@ void mesh_detach_subs(struct module_qstate* qstate)
|
||||
RBTREE_FOR(ref, struct mesh_state_ref*, &qstate->mesh_info->sub_set) {
|
||||
n = rbtree_delete(&ref->s->super_set, &lookup);
|
||||
log_assert(n != NULL); /* must have been present */
|
||||
if(!ref->s->reply_list && ref->s->super_set.count == 0) {
|
||||
if(!ref->s->reply_list && !ref->s->cb_list
|
||||
&& ref->s->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
log_assert(mesh->num_detached_states +
|
||||
mesh->num_reply_states <= mesh->all.count);
|
||||
@@ -334,7 +382,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
|
||||
*newq = NULL;
|
||||
if(!mesh_state_attachment(qstate->mesh_info, sub))
|
||||
return 0;
|
||||
if(!sub->reply_list && sub->super_set.count == 1) {
|
||||
if(!sub->reply_list && !sub->cb_list && sub->super_set.count == 1) {
|
||||
/* it used to be detached, before this one got added */
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
mesh->num_detached_states--;
|
||||
@@ -348,9 +396,9 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub)
|
||||
struct rbnode_t* n;
|
||||
struct mesh_state_ref* subref; /* points to sub, inserted in super */
|
||||
struct mesh_state_ref* superref; /* points to super, inserted in sub */
|
||||
if( !(subref = region_alloc(super->s.region,
|
||||
if( !(subref = regional_alloc(super->s.region,
|
||||
sizeof(struct mesh_state_ref))) ||
|
||||
!(superref = region_alloc(sub->s.region,
|
||||
!(superref = regional_alloc(sub->s.region,
|
||||
sizeof(struct mesh_state_ref))) ) {
|
||||
log_err("mesh_state_attachment: out of memory");
|
||||
return 0;
|
||||
@@ -413,6 +461,49 @@ timeval_divide(struct timeval* avg, struct timeval* sum, size_t d)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* callback results to mesh cb entry
|
||||
* @param m: mesh state to send it for.
|
||||
* @param rcode: if not 0, error code.
|
||||
* @param rep: reply to send (or NULL if rcode is set).
|
||||
* @param r: callback entry
|
||||
*/
|
||||
static void
|
||||
mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
struct mesh_cb* r)
|
||||
{
|
||||
int secure;
|
||||
/* bogus messages are not made into servfail, sec_status passed
|
||||
* to the callback function */
|
||||
if(rep && rep->security == sec_status_secure)
|
||||
secure = 1;
|
||||
else secure = 0;
|
||||
if(!rep && rcode == LDNS_RCODE_NOERROR)
|
||||
rcode = LDNS_RCODE_SERVFAIL;
|
||||
/* send the reply */
|
||||
if(rcode) {
|
||||
(*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked);
|
||||
} else {
|
||||
size_t udp_size = r->edns.udp_size;
|
||||
ldns_buffer_clear(r->buf);
|
||||
r->edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
r->edns.ext_rcode = 0;
|
||||
r->edns.bits &= EDNS_DO;
|
||||
if(!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))
|
||||
{
|
||||
(*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
|
||||
sec_status_unchecked);
|
||||
}
|
||||
else (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf,
|
||||
rep->security);
|
||||
}
|
||||
m->s.env->mesh->num_reply_addrs--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send reply to mesh reply entry
|
||||
* @param m: mesh state to send it for.
|
||||
@@ -434,6 +525,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
if(rep && rep->security == sec_status_secure)
|
||||
secure = 1;
|
||||
else secure = 0;
|
||||
if(!rep && rcode == LDNS_RCODE_NOERROR)
|
||||
rcode = LDNS_RCODE_SERVFAIL;
|
||||
/* send the reply */
|
||||
if(rcode) {
|
||||
error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
|
||||
@@ -475,11 +568,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
void mesh_query_done(struct mesh_state* mstate)
|
||||
{
|
||||
struct mesh_reply* r;
|
||||
struct mesh_cb* c;
|
||||
struct reply_info* rep = (mstate->s.return_msg?
|
||||
mstate->s.return_msg->rep:NULL);
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
mesh_send_reply(mstate, mstate->s.return_rcode, rep, r);
|
||||
}
|
||||
for(c = mstate->cb_list; c; c = c->next) {
|
||||
mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
|
||||
}
|
||||
}
|
||||
|
||||
void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
|
||||
@@ -490,7 +587,9 @@ void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate)
|
||||
/* make super runnable */
|
||||
(void)rbtree_insert(&mesh->run, &ref->s->run_node);
|
||||
/* callback the function to inform super of result */
|
||||
(*mesh->modfunc[ref->s->s.curmod]->inform_super)(&mstate->s,
|
||||
log_assert(fptr_whitelist_mod_inform_super(
|
||||
mesh->mods.mod[ref->s->s.curmod]->inform_super));
|
||||
(*mesh->mods.mod[ref->s->s.curmod]->inform_super)(&mstate->s,
|
||||
ref->s->s.curmod, &ref->s->s);
|
||||
}
|
||||
}
|
||||
@@ -510,10 +609,30 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
|
||||
return result;
|
||||
}
|
||||
|
||||
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
ldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg,
|
||||
uint16_t qid, uint16_t qflags)
|
||||
{
|
||||
struct mesh_cb* r = regional_alloc(s->s.region,
|
||||
sizeof(struct mesh_cb));
|
||||
if(!r)
|
||||
return 0;
|
||||
r->buf = buf;
|
||||
r->cb = cb;
|
||||
r->cb_arg = cb_arg;
|
||||
r->edns = *edns;
|
||||
r->qid = qid;
|
||||
r->qflags = qflags;
|
||||
r->next = s->cb_list;
|
||||
s->cb_list = r;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags)
|
||||
{
|
||||
struct mesh_reply* r = region_alloc(s->s.region,
|
||||
struct mesh_reply* r = regional_alloc(s->s.region,
|
||||
sizeof(struct mesh_reply));
|
||||
if(!r)
|
||||
return 0;
|
||||
@@ -550,14 +669,21 @@ static int
|
||||
mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
enum module_ext_state s, enum module_ev* ev)
|
||||
{
|
||||
mstate->num_activated++;
|
||||
if(mstate->num_activated > MESH_MAX_ACTIVATION) {
|
||||
/* module is looping. Stop it. */
|
||||
log_err("internal error: looping module stopped");
|
||||
log_query_info(VERB_QUERY, "pass error for qstate",
|
||||
&mstate->s.qinfo);
|
||||
s = module_error;
|
||||
}
|
||||
if(s == module_wait_module) {
|
||||
/* start next module */
|
||||
mstate->s.curmod++;
|
||||
if(mesh->num_modules == mstate->s.curmod) {
|
||||
if(mesh->mods.num == mstate->s.curmod) {
|
||||
log_err("Cannot pass to next module; at last module");
|
||||
log_query_info(VERB_DETAIL, "pass error for qstate",
|
||||
log_query_info(VERB_QUERY, "pass error for qstate",
|
||||
&mstate->s.qinfo);
|
||||
log_assert(0); /* catch this for now */
|
||||
mstate->s.curmod--;
|
||||
return mesh_continue(mesh, mstate, module_error, ev);
|
||||
}
|
||||
@@ -590,15 +716,17 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
verbose(VERB_ALGO, "mesh_run: start");
|
||||
while(mstate) {
|
||||
/* run the module */
|
||||
(*mesh->modfunc[mstate->s.curmod]->operate)
|
||||
log_assert(fptr_whitelist_mod_operate(
|
||||
mesh->mods.mod[mstate->s.curmod]->operate));
|
||||
(*mesh->mods.mod[mstate->s.curmod]->operate)
|
||||
(&mstate->s, ev, mstate->s.curmod, e);
|
||||
|
||||
/* examine results */
|
||||
mstate->s.reply = NULL;
|
||||
region_free_all(mstate->s.env->scratch);
|
||||
regional_free_all(mstate->s.env->scratch);
|
||||
s = mstate->s.ext_state[mstate->s.curmod];
|
||||
verbose(VERB_ALGO, "mesh_run: %s module exit state is %s",
|
||||
mesh->modfunc[mstate->s.curmod]->name, strextstate(s));
|
||||
mesh->mods.mod[mstate->s.curmod]->name, strextstate(s));
|
||||
e = NULL;
|
||||
if(mesh_continue(mesh, mstate, s, &ev))
|
||||
continue;
|
||||
@@ -624,13 +752,15 @@ mesh_log_list(struct mesh_area* mesh)
|
||||
struct mesh_state* m;
|
||||
int num = 0;
|
||||
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
|
||||
snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s",
|
||||
snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s%s",
|
||||
num++, (m->s.is_priming)?"p":"", /* prime */
|
||||
(m->s.query_flags&BIT_RD)?"RD":"",
|
||||
(m->s.query_flags&BIT_CD)?"CD":"",
|
||||
(m->super_set.count==0)?"d":"", /* detached */
|
||||
(m->sub_set.count!=0)?"c":"", /* children */
|
||||
m->s.curmod, (m->reply_list)?"hr":"nr"); /*hasreply*/
|
||||
m->s.curmod, (m->reply_list)?"rep":"", /*hasreply*/
|
||||
(m->cb_list)?"cb":"" /* callbacks */
|
||||
);
|
||||
log_query_info(VERB_ALGO, buf, &m->s.qinfo);
|
||||
}
|
||||
}
|
||||
@@ -638,23 +768,35 @@ mesh_log_list(struct mesh_area* mesh)
|
||||
void
|
||||
mesh_stats(struct mesh_area* mesh, const char* str)
|
||||
{
|
||||
log_info("%s %u states (%u with reply, %u detached), "
|
||||
"%u waiting replies", str, (unsigned)mesh->all.count,
|
||||
verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, "
|
||||
"%u detached), %u waiting replies, %u recursion replies "
|
||||
"sent", str, (unsigned)mesh->all.count,
|
||||
(unsigned)mesh->num_reply_states,
|
||||
(unsigned)mesh->num_detached_states,
|
||||
(unsigned)mesh->num_reply_addrs);
|
||||
(unsigned)mesh->num_reply_addrs,
|
||||
(unsigned)mesh->replies_sent);
|
||||
if(mesh->replies_sent > 0) {
|
||||
struct timeval avg;
|
||||
timeval_divide(&avg, &mesh->replies_sum_wait,
|
||||
mesh->replies_sent);
|
||||
log_info("sent %u replies, with average wait "
|
||||
"of %d.%6.6d sec", (unsigned)mesh->replies_sent,
|
||||
(int)avg.tv_sec, (int)avg.tv_usec);
|
||||
log_info("histogram of reply wait times");
|
||||
timehist_log(mesh->histogram);
|
||||
log_info("average recursion processing time "
|
||||
"%d.%6.6d sec", (int)avg.tv_sec, (int)avg.tv_usec);
|
||||
log_info("histogram of recursion processing times");
|
||||
timehist_log(mesh->histogram, "recursions");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mesh_stats_clear(struct mesh_area* mesh)
|
||||
{
|
||||
if(!mesh)
|
||||
return;
|
||||
mesh->replies_sent = 0;
|
||||
mesh->replies_sum_wait.tv_sec = 0;
|
||||
mesh->replies_sum_wait.tv_usec = 0;
|
||||
timehist_clear(mesh->histogram);
|
||||
}
|
||||
|
||||
size_t
|
||||
mesh_get_mem(struct mesh_area* mesh)
|
||||
{
|
||||
@@ -663,7 +805,7 @@ mesh_get_mem(struct mesh_area* mesh)
|
||||
sizeof(struct th_buck)*mesh->histogram->num;
|
||||
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
|
||||
/* all, including m itself allocated in qstate region */
|
||||
s += region_get_mem(m->s.region);
|
||||
s += regional_get_mem(m->s.region);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
+93
-9
@@ -50,21 +50,27 @@
|
||||
#include "util/netevent.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/module.h"
|
||||
#include "services/modstack.h"
|
||||
struct mesh_state;
|
||||
struct mesh_reply;
|
||||
struct mesh_cb;
|
||||
struct query_info;
|
||||
struct reply_info;
|
||||
struct outbound_entry;
|
||||
struct timehist;
|
||||
|
||||
/**
|
||||
* Maximum number of mesh state activations. Any more is likely an
|
||||
* infinite loop in the module. It is then terminated.
|
||||
*/
|
||||
#define MESH_MAX_ACTIVATION 1000
|
||||
|
||||
/**
|
||||
* Mesh of query states
|
||||
*/
|
||||
struct mesh_area {
|
||||
/** the number of modules */
|
||||
int num_modules;
|
||||
/** the module callbacks, array of num_modules length (ref only) */
|
||||
struct module_func_block** modfunc;
|
||||
/** active module stack */
|
||||
struct module_stack mods;
|
||||
/** environment for new states */
|
||||
struct module_env* env;
|
||||
|
||||
@@ -111,12 +117,16 @@ struct mesh_state {
|
||||
struct module_qstate s;
|
||||
/** the list of replies to clients for the results */
|
||||
struct mesh_reply* reply_list;
|
||||
/** the list of callbacks for the results */
|
||||
struct mesh_cb* cb_list;
|
||||
/** set of superstates (that want this state's result)
|
||||
* contains struct mesh_state_ref* */
|
||||
rbtree_t super_set;
|
||||
/** set of substates (that this state needs to continue)
|
||||
* contains struct mesh_state_ref* */
|
||||
rbtree_t sub_set;
|
||||
/** number of activations for the mesh state */
|
||||
size_t num_activated;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -148,18 +158,45 @@ struct mesh_reply {
|
||||
uint16_t qflags;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mesh result callback func.
|
||||
* called as func(cb_arg, rcode, buffer_with_reply, security);
|
||||
* */
|
||||
typedef void (*mesh_cb_func_t)(void*, int, ldns_buffer*, enum sec_status);
|
||||
|
||||
/**
|
||||
* Callback to result routine
|
||||
*/
|
||||
struct mesh_cb {
|
||||
/** next in list */
|
||||
struct mesh_cb* next;
|
||||
/** edns data from query */
|
||||
struct edns_data edns;
|
||||
/** id of query, in network byteorder. */
|
||||
uint16_t qid;
|
||||
/** flags of query, for reply flags */
|
||||
uint16_t qflags;
|
||||
/** buffer for reply */
|
||||
ldns_buffer* buf;
|
||||
|
||||
/** callback routine for results. if rcode != 0 buf has message.
|
||||
* called as cb(cb_arg, rcode, buf);
|
||||
*/
|
||||
mesh_cb_func_t cb;
|
||||
/** user arg for callback */
|
||||
void* cb_arg;
|
||||
};
|
||||
|
||||
/* ------------------- Functions for worker -------------------- */
|
||||
|
||||
/**
|
||||
* Allocate mesh, to empty.
|
||||
* @param num_modules: number of modules that are present.
|
||||
* @param modfunc: array passed (alloced and deleted by caller), that has
|
||||
* num_modules function callbacks for the modules.
|
||||
* @param stack: module stack to activate, copied (as readonly reference).
|
||||
* @param env: environment for new queries.
|
||||
* @return mesh: the new mesh or NULL on error.
|
||||
*/
|
||||
struct mesh_area* mesh_create(int num_modules,
|
||||
struct module_func_block** modfunc, struct module_env* env);
|
||||
struct mesh_area* mesh_create(struct module_stack* stack,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Delete mesh, and all query states and replies in it.
|
||||
@@ -183,6 +220,25 @@ 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);
|
||||
|
||||
/**
|
||||
* New query with callback. Create new query state if needed, and
|
||||
* add mesh_cb to it.
|
||||
* Will run the mesh area queries to process if a new query state is created.
|
||||
*
|
||||
* @param mesh: the mesh.
|
||||
* @param qinfo: query from client.
|
||||
* @param qflags: flags from client query.
|
||||
* @param edns: edns data from client query.
|
||||
* @param buf: buffer for reply contents.
|
||||
* @param qid: query id to reply with.
|
||||
* @param cb: callback function.
|
||||
* @param cb_arg: callback user arg.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, struct edns_data* edns, ldns_buffer* buf,
|
||||
uint16_t qid, mesh_cb_func_t cb, void* cb_arg);
|
||||
|
||||
/**
|
||||
* Handle new event from the wire. A serviced query has returned.
|
||||
* The query state will be made runnable, and the mesh_area will process
|
||||
@@ -324,6 +380,22 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub);
|
||||
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags);
|
||||
|
||||
/**
|
||||
* Create new callback structure and attach it to a mesh state.
|
||||
* Does not update stat items in mesh area.
|
||||
* @param s: the mesh state.
|
||||
* @param edns: edns data for reply (bufsize).
|
||||
* @param buf: buffer for reply
|
||||
* @param cb: callback to call with results.
|
||||
* @param cb_arg: callback user arg.
|
||||
* @param qid: ID of reply.
|
||||
* @param qflags: original query flags.
|
||||
* @return: 0 on alloc error.
|
||||
*/
|
||||
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
||||
ldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg, uint16_t qid,
|
||||
uint16_t qflags);
|
||||
|
||||
/**
|
||||
* Run the mesh. Run all runnable mesh states. Which can create new
|
||||
* runnable mesh states. Until completion. Automatically called by
|
||||
@@ -343,6 +415,12 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
*/
|
||||
void mesh_stats(struct mesh_area* mesh, const char* str);
|
||||
|
||||
/**
|
||||
* Clear the stats that the mesh keeps (number of queries serviced)
|
||||
* @param mesh: the mesh
|
||||
*/
|
||||
void mesh_stats_clear(struct mesh_area* mesh);
|
||||
|
||||
/**
|
||||
* Print all the states in the mesh to the log.
|
||||
* @param mesh: the mesh to print all states of.
|
||||
@@ -370,4 +448,10 @@ size_t mesh_get_mem(struct mesh_area* mesh);
|
||||
int mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
|
||||
uint16_t flags, int prime);
|
||||
|
||||
/** compare two mesh_states */
|
||||
int mesh_state_compare(const void* ap, const void* bp);
|
||||
|
||||
/** compare two mesh references */
|
||||
int mesh_state_ref_compare(const void* ap, const void* bp);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* services/modstack.c - stack of modules
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions to help maintain a stack of modules.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "services/modstack.h"
|
||||
#include "util/module.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "validator/validator.h"
|
||||
|
||||
/** count number of modules (words) in the string */
|
||||
static int
|
||||
count_modules(const char* s)
|
||||
{
|
||||
int num = 0;
|
||||
if(!s)
|
||||
return 0;
|
||||
while(*s) {
|
||||
/* skip whitespace */
|
||||
while(*s && isspace((int)*s))
|
||||
s++;
|
||||
if(*s && !isspace((int)*s)) {
|
||||
/* skip identifier */
|
||||
num++;
|
||||
while(*s && !isspace((int)*s))
|
||||
s++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void
|
||||
modstack_init(struct module_stack* stack)
|
||||
{
|
||||
stack->num = 0;
|
||||
stack->mod = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
modstack_config(struct module_stack* stack, const char* module_conf)
|
||||
{
|
||||
int i;
|
||||
verbose(VERB_QUERY, "module config: \"%s\"", module_conf);
|
||||
stack->num = count_modules(module_conf);
|
||||
if(stack->num == 0) {
|
||||
log_err("error: no modules specified");
|
||||
return 0;
|
||||
}
|
||||
if(stack->num > MAX_MODULE) {
|
||||
log_err("error: too many modules (%d max %d)",
|
||||
stack->num, MAX_MODULE);
|
||||
return 0;
|
||||
}
|
||||
stack->mod = (struct module_func_block**)calloc((size_t)
|
||||
stack->num, sizeof(struct module_func_block*));
|
||||
if(!stack->mod) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
for(i=0; i<stack->num; i++) {
|
||||
stack->mod[i] = module_factory(&module_conf);
|
||||
if(!stack->mod[i]) {
|
||||
log_err("Unknown value for next module: '%s'",
|
||||
module_conf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct
|
||||
module_func_block* module_factory(const char** str)
|
||||
{
|
||||
/* these are the modules available */
|
||||
int num = 2;
|
||||
const char* names[] = {"iterator", "validator", NULL};
|
||||
struct module_func_block* (*fb[])(void) =
|
||||
{&iter_get_funcblock, &val_get_funcblock, NULL};
|
||||
|
||||
int i;
|
||||
const char* s = *str;
|
||||
while(*s && isspace((int)*s))
|
||||
s++;
|
||||
for(i=0; i<num; i++) {
|
||||
if(strncmp(names[i], s, strlen(names[i])) == 0) {
|
||||
s += strlen(names[i]);
|
||||
*str = s;
|
||||
return (*fb[i])();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
modstack_setup(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env)
|
||||
{
|
||||
int i;
|
||||
if(stack->num != 0)
|
||||
modstack_desetup(stack, env);
|
||||
/* fixed setup of the modules */
|
||||
if(!modstack_config(stack, module_conf)) {
|
||||
return 0;
|
||||
}
|
||||
env->need_to_validate = 0; /* set by module init below */
|
||||
for(i=0; i<stack->num; i++) {
|
||||
verbose(VERB_OPS, "init module %d: %s",
|
||||
i, stack->mod[i]->name);
|
||||
log_assert(fptr_whitelist_mod_init(stack->mod[i]->init));
|
||||
if(!(*stack->mod[i]->init)(env, i)) {
|
||||
log_err("module init for module %s failed",
|
||||
stack->mod[i]->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
modstack_desetup(struct module_stack* stack, struct module_env* env)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<stack->num; i++) {
|
||||
log_assert(fptr_whitelist_mod_deinit(stack->mod[i]->deinit));
|
||||
(*stack->mod[i]->deinit)(env, i);
|
||||
}
|
||||
stack->num = 0;
|
||||
free(stack->mod);
|
||||
stack->mod = NULL;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* services/modstack.h - stack of modules
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains functions to help maintain a stack of modules.
|
||||
*/
|
||||
|
||||
#ifndef SERVICES_MODSTACK_H
|
||||
#define SERVICES_MODSTACK_H
|
||||
struct module_func_block;
|
||||
struct module_env;
|
||||
|
||||
/**
|
||||
* Stack of modules.
|
||||
*/
|
||||
struct module_stack {
|
||||
/** the number of modules */
|
||||
int num;
|
||||
/** the module callbacks, array of num_modules length (ref only) */
|
||||
struct module_func_block** mod;
|
||||
};
|
||||
|
||||
/**
|
||||
* Init a stack of modules
|
||||
* @param stack: initialised as empty.
|
||||
*/
|
||||
void modstack_init(struct module_stack* stack);
|
||||
|
||||
/**
|
||||
* Read config file module settings and set up the modfunc block
|
||||
* @param stack: the stack of modules (empty before call).
|
||||
* @param module_conf: string what modules to insert.
|
||||
* @return false on error
|
||||
*/
|
||||
int modstack_config(struct module_stack* stack, const char* module_conf);
|
||||
|
||||
/**
|
||||
* Get funcblock for module name
|
||||
* @param str: string with module name. Advanced to next value on success.
|
||||
* The string is assumed whitespace separated list of module names.
|
||||
* @return funcblock or NULL on error.
|
||||
*/
|
||||
struct module_func_block* module_factory(const char** str);
|
||||
|
||||
/**
|
||||
* Setup modules. Assigns ids and calls module_init.
|
||||
* @param stack: if not empty beforehand, it will be desetup()ed.
|
||||
* It is then modstack_configged().
|
||||
* @param module_conf: string what modules to insert.
|
||||
* @param env: module environment which is inited by the modules.
|
||||
* environment should have a superalloc, cfg,
|
||||
* env.need_to_validate is set by the modules.
|
||||
* @return on false a module init failed.
|
||||
*/
|
||||
int modstack_setup(struct module_stack* stack, const char* module_conf,
|
||||
struct module_env* env);
|
||||
|
||||
/**
|
||||
* Desetup the modules, deinit, delete.
|
||||
* @param stack: made empty.
|
||||
* @param env: module env for module deinit() calls.
|
||||
*/
|
||||
void modstack_desetup(struct module_stack* stack, struct module_env* env);
|
||||
|
||||
#endif /* SERVICES_MODSTACK_H */
|
||||
+77
-61
@@ -50,6 +50,7 @@
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/random.h"
|
||||
#include "util/fptr_wlist.h"
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
@@ -60,17 +61,13 @@
|
||||
/** number of times to retry making a random ID that is unique. */
|
||||
#define MAX_ID_RETRY 1000
|
||||
/** number of retries on outgoing UDP queries */
|
||||
#define OUTBOUND_UDP_RETRY 4
|
||||
#define OUTBOUND_UDP_RETRY 1
|
||||
|
||||
/** callback for serviced query UDP answers */
|
||||
static int serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* rep);
|
||||
/** initiate TCP transaction for serviced query */
|
||||
static void serviced_tcp_initiate(struct outside_network* outnet,
|
||||
struct serviced_query* sq, ldns_buffer* buff);
|
||||
|
||||
/** compare function of pending rbtree */
|
||||
static int
|
||||
int
|
||||
pending_cmp(const void* key1, const void* key2)
|
||||
{
|
||||
struct pending *p1 = (struct pending*)key1;
|
||||
@@ -83,8 +80,7 @@ pending_cmp(const void* key1, const void* key2)
|
||||
return sockaddr_cmp(&p1->addr, p1->addrlen, &p2->addr, p2->addrlen);
|
||||
}
|
||||
|
||||
/** compare function of serviced query rbtree */
|
||||
static int
|
||||
int
|
||||
serviced_cmp(const void* key1, const void* key2)
|
||||
{
|
||||
struct serviced_query* q1 = (struct serviced_query*)key1;
|
||||
@@ -95,7 +91,7 @@ serviced_cmp(const void* key1, const void* key2)
|
||||
if(q1->qbuflen > q2->qbuflen)
|
||||
return 1;
|
||||
log_assert(q1->qbuflen == q2->qbuflen);
|
||||
/* FIXME: will not detect alternate casing of qname */
|
||||
/* will not detect alternate casing of qname */
|
||||
if((r = memcmp(q1->qbuf, q2->qbuf, q1->qbuflen)) != 0)
|
||||
return r;
|
||||
if(q1->dnssec != q2->dnssec) {
|
||||
@@ -126,23 +122,24 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
|
||||
int s;
|
||||
log_assert(pend);
|
||||
log_assert(pkt);
|
||||
log_assert(w->addrlen > 0);
|
||||
/* open socket */
|
||||
#ifndef INET6
|
||||
if(addr_is_ip6(addr))
|
||||
#ifdef INET6
|
||||
if(addr_is_ip6(&w->addr, w->addrlen))
|
||||
s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
||||
else
|
||||
#endif
|
||||
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(s == -1) {
|
||||
log_err("outgoing tcp: socket: %s", strerror(errno));
|
||||
log_addr("failed address", &w->addr, w->addrlen);
|
||||
log_addr(0, "failed address", &w->addr, w->addrlen);
|
||||
return 0;
|
||||
}
|
||||
fd_set_nonblock(s);
|
||||
if(connect(s, (struct sockaddr*)&w->addr, w->addrlen) == -1) {
|
||||
if(errno != EINPROGRESS) {
|
||||
log_err("outgoing tcp: connect: %s", strerror(errno));
|
||||
log_addr("failed address", &w->addr, w->addrlen);
|
||||
log_addr(0, "failed address", &w->addr, w->addrlen);
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
@@ -153,6 +150,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
|
||||
w->outnet->tcp_free = pend->next_free;
|
||||
pend->next_free = NULL;
|
||||
pend->query = w;
|
||||
pend->c->repinfo.addrlen = w->addrlen;
|
||||
memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
|
||||
ldns_buffer_clear(pend->c->buffer);
|
||||
ldns_buffer_write(pend->c->buffer, pkt, pkt_len);
|
||||
ldns_buffer_flip(pend->c->buffer);
|
||||
@@ -176,6 +175,7 @@ use_free_buffer(struct outside_network* outnet)
|
||||
comm_point_callback_t* cb = w->cb;
|
||||
void* cb_arg = w->cb_arg;
|
||||
waiting_tcp_delete(w);
|
||||
log_assert(fptr_whitelist_pending_tcp(cb));
|
||||
(void)(*cb)(NULL, cb_arg, NETEVENT_CLOSED, NULL);
|
||||
}
|
||||
}
|
||||
@@ -194,8 +194,7 @@ decomission_pending_tcp(struct outside_network* outnet,
|
||||
use_free_buffer(outnet);
|
||||
}
|
||||
|
||||
/** callback for pending tcp connections */
|
||||
static int
|
||||
int
|
||||
outnet_tcp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info)
|
||||
{
|
||||
@@ -203,24 +202,25 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct outside_network* outnet = pend->query->outnet;
|
||||
verbose(VERB_ALGO, "outnettcp cb");
|
||||
if(error != NETEVENT_NOERROR) {
|
||||
verbose(VERB_DETAIL, "outnettcp got tcp error %d", error);
|
||||
verbose(VERB_QUERY, "outnettcp got tcp error %d", error);
|
||||
/* pass error below and exit */
|
||||
} else {
|
||||
/* check ID */
|
||||
if(ldns_buffer_limit(c->buffer) < sizeof(uint16_t) ||
|
||||
LDNS_ID_WIRE(ldns_buffer_begin(c->buffer))!=pend->id) {
|
||||
log_addr("outnettcp: bad ID in reply, from:",
|
||||
log_addr(VERB_QUERY,
|
||||
"outnettcp: bad ID in reply, from:",
|
||||
&pend->query->addr, pend->query->addrlen);
|
||||
error = NETEVENT_CLOSED;
|
||||
}
|
||||
}
|
||||
log_assert(fptr_whitelist_pending_tcp(pend->query->cb));
|
||||
(void)(*pend->query->cb)(c, pend->query->cb_arg, error, reply_info);
|
||||
decomission_pending_tcp(outnet, pend);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** callback for incoming udp answers from the network */
|
||||
static int
|
||||
int
|
||||
outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info)
|
||||
{
|
||||
@@ -230,11 +230,11 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "answer cb");
|
||||
|
||||
if(error != NETEVENT_NOERROR) {
|
||||
verbose(VERB_DETAIL, "outnetudp got udp error %d", error);
|
||||
verbose(VERB_QUERY, "outnetudp got udp error %d", error);
|
||||
return 0;
|
||||
}
|
||||
if(ldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
|
||||
verbose(VERB_DETAIL, "outnetudp udp too short");
|
||||
verbose(VERB_QUERY, "outnetudp udp too short");
|
||||
return 0;
|
||||
}
|
||||
log_assert(reply_info);
|
||||
@@ -244,28 +244,22 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
memcpy(&key.addr, &reply_info->addr, reply_info->addrlen);
|
||||
key.addrlen = reply_info->addrlen;
|
||||
verbose(VERB_ALGO, "Incoming reply id = %4.4x", key.id);
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
log_addr("Incoming reply addr =", &reply_info->addr, reply_info->addrlen);
|
||||
}
|
||||
log_addr(VERB_ALGO, "Incoming reply addr =",
|
||||
&reply_info->addr, reply_info->addrlen);
|
||||
|
||||
/* find it, see if this thing is a valid query response */
|
||||
verbose(VERB_ALGO, "lookup size is %d entries", (int)outnet->pending->count);
|
||||
p = (struct pending*)rbtree_search(outnet->pending, &key);
|
||||
if(!p) {
|
||||
verbose(VERB_DETAIL, "received unwanted or unsolicited udp reply dropped.");
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_hex("dropped message",
|
||||
ldns_buffer_begin(c->buffer),
|
||||
ldns_buffer_limit(c->buffer));
|
||||
verbose(VERB_QUERY, "received unwanted or unsolicited udp reply dropped.");
|
||||
log_buf(VERB_ALGO, "dropped message", c->buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
verbose(VERB_ALGO, "received udp reply.");
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_hex("udp message", ldns_buffer_begin(c->buffer),
|
||||
ldns_buffer_limit(c->buffer));
|
||||
log_buf(VERB_ALGO, "udp message", c->buffer);
|
||||
if(p->c != c) {
|
||||
verbose(VERB_DETAIL, "received reply id,addr on wrong port. "
|
||||
verbose(VERB_QUERY, "received reply id,addr on wrong port. "
|
||||
"dropped.");
|
||||
return 0;
|
||||
}
|
||||
@@ -273,6 +267,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "outnet handle udp reply");
|
||||
/* delete from tree first in case callback creates a retry */
|
||||
(void)rbtree_delete(outnet->pending, p->node.key);
|
||||
log_assert(fptr_whitelist_pending_udp(p->cb));
|
||||
(void)(*p->cb)(p->c, p->cb_arg, NETEVENT_NOERROR, reply_info);
|
||||
pending_delete(NULL, p);
|
||||
return 0;
|
||||
@@ -293,6 +288,11 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
|
||||
char portstr[32];
|
||||
if(porthint != -1)
|
||||
snprintf(portstr, sizeof(portstr), "%d", porthint);
|
||||
else if(!ifname) {
|
||||
if(hints->ai_family == AF_INET)
|
||||
ifname = "0.0.0.0";
|
||||
else ifname="::";
|
||||
}
|
||||
|
||||
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
|
||||
&res)) != 0 || !res) {
|
||||
@@ -302,7 +302,7 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
|
||||
r==EAI_SYSTEM?(char*)strerror(errno):"");
|
||||
return -1;
|
||||
}
|
||||
s = create_udp_sock(res);
|
||||
s = create_udp_sock(res, 1);
|
||||
freeaddrinfo(res);
|
||||
return s;
|
||||
}
|
||||
@@ -381,13 +381,13 @@ calc_num46(char** ifs, int num_ifs, int do_ip4, int do_ip6,
|
||||
|
||||
}
|
||||
|
||||
/** callback for udp timeout */
|
||||
static void
|
||||
void
|
||||
pending_udp_timer_cb(void *arg)
|
||||
{
|
||||
struct pending* p = (struct pending*)arg;
|
||||
/* it timed out */
|
||||
verbose(VERB_ALGO, "timeout udp");
|
||||
log_assert(fptr_whitelist_pending_udp(p->cb));
|
||||
(void)(*p->cb)(p->c, p->cb_arg, NETEVENT_TIMEOUT, NULL);
|
||||
pending_delete(p->outnet, p);
|
||||
}
|
||||
@@ -492,6 +492,11 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
outnet->num_udp6 = done_6;
|
||||
outnet->num_udp4 = done_4;
|
||||
}
|
||||
if(outnet->num_udp4 + outnet->num_udp6 == 0) {
|
||||
log_err("Could not open any ports on outgoing interfaces");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
return outnet;
|
||||
}
|
||||
|
||||
@@ -605,7 +610,6 @@ new_pending(struct outside_network* outnet, ldns_buffer* packet,
|
||||
return NULL;
|
||||
}
|
||||
/* set */
|
||||
/* id uses lousy random() TODO use better and entropy */
|
||||
pend->id = ((unsigned)ub_random(rnd)>>8) & 0xffff;
|
||||
LDNS_ID_SET(ldns_buffer_begin(packet), pend->id);
|
||||
memcpy(&pend->addr, addr, addrlen);
|
||||
@@ -646,7 +650,7 @@ select_port(struct outside_network* outnet, struct pending* pend,
|
||||
|
||||
log_assert(outnet && pend);
|
||||
/* first select ip4 or ip6. */
|
||||
if(addr_is_ip6(&pend->addr))
|
||||
if(addr_is_ip6(&pend->addr, pend->addrlen))
|
||||
nummax = (int)outnet->num_udp6;
|
||||
else nummax = (int)outnet->num_udp4;
|
||||
|
||||
@@ -657,7 +661,6 @@ select_port(struct outside_network* outnet, struct pending* pend,
|
||||
}
|
||||
|
||||
/* choose a random outgoing port and interface */
|
||||
/* TODO: entropy source. */
|
||||
precho = (double)ub_random(rnd) * (double)nummax /
|
||||
((double)RAND_MAX + 1.0);
|
||||
chosen = (int)precho;
|
||||
@@ -666,7 +669,7 @@ select_port(struct outside_network* outnet, struct pending* pend,
|
||||
if(chosen < 0) chosen = 0;
|
||||
if(chosen >= nummax) chosen = nummax-1;
|
||||
|
||||
if(addr_is_ip6(&pend->addr))
|
||||
if(addr_is_ip6(&pend->addr, pend->addrlen))
|
||||
pend->c = outnet->udp6_ports[chosen];
|
||||
else pend->c = outnet->udp4_ports[chosen];
|
||||
log_assert(pend->c);
|
||||
@@ -709,8 +712,7 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
return pend;
|
||||
}
|
||||
|
||||
/** callback for outgoing TCP timer event */
|
||||
static void
|
||||
void
|
||||
outnet_tcptimer(void* arg)
|
||||
{
|
||||
struct waiting_tcp* w = (struct waiting_tcp*)arg;
|
||||
@@ -741,6 +743,7 @@ outnet_tcptimer(void* arg)
|
||||
cb = w->cb;
|
||||
cb_arg = w->cb_arg;
|
||||
waiting_tcp_delete(w);
|
||||
log_assert(fptr_whitelist_pending_tcp(cb));
|
||||
(void)(*cb)(NULL, cb_arg, NETEVENT_TIMEOUT, NULL);
|
||||
use_free_buffer(outnet);
|
||||
}
|
||||
@@ -767,7 +770,6 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
|
||||
}
|
||||
w->pkt = NULL;
|
||||
w->pkt_len = 0;
|
||||
/* id uses lousy random() TODO use better and entropy */
|
||||
id = ((unsigned)ub_random(rnd)>>8) & 0xffff;
|
||||
LDNS_ID_SET(ldns_buffer_begin(packet), id);
|
||||
memcpy(&w->addr, addr, addrlen);
|
||||
@@ -1006,6 +1008,7 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
|
||||
ldns_buffer_write(c->buffer, backup_p, backlen);
|
||||
ldns_buffer_flip(c->buffer);
|
||||
}
|
||||
log_assert(fptr_whitelist_serviced_query(p->cb));
|
||||
(void)(*p->cb)(c, p->cb_arg, error, rep);
|
||||
p = n;
|
||||
}
|
||||
@@ -1018,19 +1021,23 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
|
||||
serviced_delete(sq);
|
||||
}
|
||||
|
||||
/** TCP reply or error callback for serviced queries */
|
||||
static int
|
||||
int
|
||||
serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* rep)
|
||||
{
|
||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||
struct comm_reply r2;
|
||||
sq->pending = NULL; /* removed after this callback */
|
||||
if(error != NETEVENT_NOERROR && verbosity >= VERB_DETAIL)
|
||||
log_addr("tcp error for address", &sq->addr, sq->addrlen);
|
||||
if(error==NETEVENT_NOERROR && LDNS_RCODE_WIRE(ldns_buffer_begin(
|
||||
c->buffer)) == LDNS_RCODE_FORMERR &&
|
||||
sq->status == serviced_query_TCP_EDNS) {
|
||||
if(error != NETEVENT_NOERROR)
|
||||
log_addr(VERB_QUERY, "tcp error for address",
|
||||
&sq->addr, sq->addrlen);
|
||||
if(error==NETEVENT_NOERROR)
|
||||
infra_update_tcp_works(sq->outnet->infra, &sq->addr,
|
||||
sq->addrlen);
|
||||
if(error==NETEVENT_NOERROR && sq->status == serviced_query_TCP_EDNS &&
|
||||
(LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
|
||||
LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(ldns_buffer_begin(
|
||||
c->buffer)) == LDNS_RCODE_NOTIMPL) ) {
|
||||
if(!infra_edns_update(sq->outnet->infra, &sq->addr,
|
||||
sq->addrlen, -1, time(0)))
|
||||
log_err("Out of memory caching no edns for host");
|
||||
@@ -1056,7 +1063,7 @@ serviced_tcp_initiate(struct outside_network* outnet,
|
||||
{
|
||||
serviced_encode(sq, buff, sq->status == serviced_query_TCP_EDNS);
|
||||
sq->pending = pending_tcp_query(outnet, buff, &sq->addr,
|
||||
sq->addrlen, TCP_QUERY_TIMEOUT, serviced_tcp_callback,
|
||||
sq->addrlen, TCP_AUTH_QUERY_TIMEOUT, serviced_tcp_callback,
|
||||
sq, outnet->rnd);
|
||||
if(!sq->pending) {
|
||||
/* delete from tree so that a retry by above layer does not
|
||||
@@ -1066,13 +1073,14 @@ serviced_tcp_initiate(struct outside_network* outnet,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* rep)
|
||||
{
|
||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||
struct outside_network* outnet = sq->outnet;
|
||||
struct timeval now;
|
||||
int fallback_tcp = 0;
|
||||
if(gettimeofday(&now, NULL) < 0) {
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
/* this option does not need current time */
|
||||
@@ -1080,9 +1088,10 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
sq->pending = NULL; /* removed after callback */
|
||||
if(error == NETEVENT_TIMEOUT) {
|
||||
int rto = 0;
|
||||
sq->retry++;
|
||||
if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||
-1, (time_t)now.tv_sec))
|
||||
if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||
-1, (time_t)now.tv_sec)))
|
||||
log_err("out of memory in UDP exponential backoff");
|
||||
if(sq->retry < OUTBOUND_UDP_RETRY) {
|
||||
log_name_addr(VERB_ALGO, "retry query", sq->qbuf+10,
|
||||
@@ -1092,12 +1101,18 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
error = NETEVENT_TIMEOUT;
|
||||
/* UDP does not work, fallback to TCP below */
|
||||
if(rto >= RTT_MAX_TIMEOUT) {
|
||||
fallback_tcp = 1;
|
||||
/* UDP does not work, fallback to TCP below */
|
||||
} else {
|
||||
serviced_callbacks(sq, NETEVENT_TIMEOUT, c, rep);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(error == NETEVENT_NOERROR && sq->status == serviced_query_UDP_EDNS
|
||||
&& LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
||||
== LDNS_RCODE_FORMERR) {
|
||||
&& (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
||||
== LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(
|
||||
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) {
|
||||
/* note no EDNS, fallback without EDNS */
|
||||
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||
-1, (time_t)now.tv_sec)) {
|
||||
@@ -1110,8 +1125,8 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(error != NETEVENT_NOERROR ||
|
||||
LDNS_TC_WIRE(ldns_buffer_begin(c->buffer))) {
|
||||
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) ||
|
||||
(error != NETEVENT_NOERROR && fallback_tcp) ) {
|
||||
/* fallback to TCP */
|
||||
/* this discards partial UDP contents */
|
||||
if(sq->status == serviced_query_UDP_EDNS)
|
||||
@@ -1128,6 +1143,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
int roundtime = (now.tv_sec - sq->last_sent_time.tv_sec)*1000
|
||||
+ ((int)now.tv_usec - (int)sq->last_sent_time.tv_usec)/1000;
|
||||
verbose(VERB_ALGO, "measured roundtrip at %d msec", roundtime);
|
||||
log_assert(roundtime >= 0);
|
||||
if(!infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||
roundtime, (time_t)now.tv_sec))
|
||||
log_err("out of memory noting rtt.");
|
||||
@@ -1163,7 +1179,7 @@ outnet_serviced_query(struct outside_network* outnet,
|
||||
sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen);
|
||||
if(sq) {
|
||||
/* see if it is a duplicate notification request for cb_arg */
|
||||
if((cb = callback_list_find(sq, callback_arg, arg_compare))) {
|
||||
if(callback_list_find(sq, callback_arg, arg_compare)) {
|
||||
return sq;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +225,9 @@ struct serviced_query {
|
||||
serviced_query_TCP_EDNS,
|
||||
/** TCP without EDNS sent */
|
||||
serviced_query_TCP
|
||||
} status;
|
||||
}
|
||||
/** variable with current status */
|
||||
status;
|
||||
/** true if serviced_query is scheduled for deletion already */
|
||||
int to_be_deleted;
|
||||
/** number of UDP retries */
|
||||
@@ -369,4 +371,32 @@ size_t outnet_get_mem(struct outside_network* outnet);
|
||||
*/
|
||||
size_t serviced_get_mem(struct serviced_query* sq);
|
||||
|
||||
/** callback for incoming udp answers from the network */
|
||||
int outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info);
|
||||
|
||||
/** callback for pending tcp connections */
|
||||
int outnet_tcp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info);
|
||||
|
||||
/** callback for udp timeout */
|
||||
void pending_udp_timer_cb(void *arg);
|
||||
|
||||
/** callback for outgoing TCP timer event */
|
||||
void outnet_tcptimer(void* arg);
|
||||
|
||||
/** callback for serviced query UDP answers */
|
||||
int serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** TCP reply or error callback for serviced queries */
|
||||
int serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* rep);
|
||||
|
||||
/** compare function of pending rbtree */
|
||||
int pending_cmp(const void* key1, const void* key2);
|
||||
|
||||
/** compare function of serviced query rbtree */
|
||||
int serviced_cmp(const void* key1, const void* key2);
|
||||
|
||||
#endif /* OUTSIDE_NETWORK_H */
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* checkconf/unbound-checkconf.c - config file checker for unbound.conf file.
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* The config checker checks for syntax and other errors in the unbound.conf
|
||||
* file, and can be used to check for errors before the server is started
|
||||
* or sigHUPped.
|
||||
* Exit status 1 means an error.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/regional.h"
|
||||
#include "iterator/iterator.h"
|
||||
#include "validator/validator.h"
|
||||
#include "services/localzone.h"
|
||||
#include <pwd.h>
|
||||
|
||||
/** Give checkconf usage, and exit (1). */
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
printf("Usage: unbound-checkconf [file]\n");
|
||||
printf(" Checks unbound configuration file for errors.\n");
|
||||
printf("file if omitted %s is used.\n", CONFIGFILE);
|
||||
printf("-h show this usage help.\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** check if module works with config */
|
||||
static void
|
||||
check_mod(struct config_file* cfg, struct module_func_block* fb)
|
||||
{
|
||||
struct module_env env;
|
||||
memset(&env, 0, sizeof(env));
|
||||
env.cfg = cfg;
|
||||
env.scratch = regional_create();
|
||||
env.scratch_buffer = ldns_buffer_new(BUFSIZ);
|
||||
if(!env.scratch || !env.scratch_buffer)
|
||||
fatal_exit("out of memory");
|
||||
if(!(*fb->init)(&env, 0)) {
|
||||
fatal_exit("bad config for %s module", fb->name);
|
||||
}
|
||||
(*fb->deinit)(&env, 0);
|
||||
ldns_buffer_free(env.scratch_buffer);
|
||||
regional_destroy(env.scratch);
|
||||
}
|
||||
|
||||
/** check localzones */
|
||||
static void
|
||||
localzonechecks(struct config_file* cfg)
|
||||
{
|
||||
struct local_zones* zs;
|
||||
if(!(zs = local_zones_create()))
|
||||
fatal_exit("out of memory");
|
||||
if(!local_zones_apply_cfg(zs, cfg))
|
||||
fatal_exit("failed local-zone, local-data configuration");
|
||||
local_zones_delete(zs);
|
||||
}
|
||||
|
||||
/** emit warnings for IP in hosts */
|
||||
static void
|
||||
warn_hosts(const char* typ, struct config_stub* list)
|
||||
{
|
||||
struct sockaddr_storage a;
|
||||
socklen_t alen;
|
||||
struct config_stub* s;
|
||||
struct config_strlist* h;
|
||||
for(s=list; s; s=s->next) {
|
||||
for(h=s->hosts; h; h=h->next) {
|
||||
if(extstrtoaddr(h->str, &a, &alen)) {
|
||||
fprintf(stderr, "unbound-checkconf: warning:"
|
||||
" %s %s: \"%s\" is an IP%s address, "
|
||||
"and when looked up as a host name "
|
||||
"during use may not resolve.\n",
|
||||
s->name, typ, h->str,
|
||||
addr_is_ip6(&a, alen)?"6":"4");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** check interface strings */
|
||||
static void
|
||||
interfacechecks(struct config_file* cfg)
|
||||
{
|
||||
struct sockaddr_storage a;
|
||||
socklen_t alen;
|
||||
int i, j;
|
||||
for(i=0; i<cfg->num_ifs; i++) {
|
||||
if(!ipstrtoaddr(cfg->ifs[i], UNBOUND_DNS_PORT, &a, &alen)) {
|
||||
fatal_exit("cannot parse interface specified as '%s'",
|
||||
cfg->ifs[i]);
|
||||
}
|
||||
for(j=0; j<cfg->num_ifs; j++) {
|
||||
if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0)
|
||||
fatal_exit("interface: %s present twice, "
|
||||
"cannot bind same ports twice.",
|
||||
cfg->ifs[i]);
|
||||
}
|
||||
}
|
||||
for(i=0; i<cfg->num_out_ifs; i++) {
|
||||
if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT,
|
||||
&a, &alen)) {
|
||||
fatal_exit("cannot parse outgoing-interface "
|
||||
"specified as '%s'", cfg->out_ifs[i]);
|
||||
}
|
||||
for(j=0; j<cfg->num_out_ifs; j++) {
|
||||
if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0)
|
||||
fatal_exit("outgoing-interface: %s present "
|
||||
"twice, cannot bind same ports twice.",
|
||||
cfg->out_ifs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** check acl ips */
|
||||
static void
|
||||
aclchecks(struct config_file* cfg)
|
||||
{
|
||||
int d;
|
||||
struct sockaddr_storage a;
|
||||
socklen_t alen;
|
||||
struct config_str2list* acl;
|
||||
for(acl=cfg->acls; acl; acl = acl->next) {
|
||||
if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen,
|
||||
&d)) {
|
||||
fatal_exit("cannot parse access control address %s %s",
|
||||
acl->str, acl->str2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** check file list, every file must be inside the chroot location */
|
||||
static void
|
||||
check_chroot_filelist(const char* desc, struct config_strlist* list,
|
||||
const char* chrootdir)
|
||||
{
|
||||
struct config_strlist* p;
|
||||
if(!chrootdir) return;
|
||||
for(p=list; p; p=p->next) {
|
||||
if(p->str && p->str[0] && strncmp(chrootdir, p->str,
|
||||
strlen(chrootdir)) != 0) {
|
||||
fatal_exit("%s: \"%s\" not in chrootdir %s",
|
||||
desc, p->str, chrootdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** check configuration for errors */
|
||||
static void
|
||||
morechecks(struct config_file* cfg)
|
||||
{
|
||||
warn_hosts("stub-host", cfg->stubs);
|
||||
warn_hosts("forward-host", cfg->forwards);
|
||||
interfacechecks(cfg);
|
||||
aclchecks(cfg);
|
||||
|
||||
if(cfg->verbosity < 0)
|
||||
fatal_exit("verbosity value < 0");
|
||||
if(cfg->num_threads < 0 || cfg->num_threads > 10000)
|
||||
fatal_exit("num_threads value weird");
|
||||
if(!cfg->do_ip4 && !cfg->do_ip6)
|
||||
fatal_exit("ip4 and ip6 are both disabled, pointless");
|
||||
if(!cfg->do_udp && !cfg->do_tcp)
|
||||
fatal_exit("udp and tcp are both disabled, pointless");
|
||||
|
||||
if(cfg->chrootdir && cfg->chrootdir[0] &&
|
||||
cfg->chrootdir[strlen(cfg->chrootdir)-1] == '/')
|
||||
fatal_exit("chootdir %s has trailing slash '/' please remove.",
|
||||
cfg->chrootdir);
|
||||
if(cfg->chrootdir && strncmp(cfg->chrootdir, cfg->directory,
|
||||
strlen(cfg->chrootdir)) != 0)
|
||||
fatal_exit("working directory %s not in chrootdir %s",
|
||||
cfg->directory, cfg->chrootdir);
|
||||
if(cfg->chrootdir && cfg->pidfile && cfg->pidfile[0] &&
|
||||
strncmp(cfg->chrootdir, cfg->pidfile,
|
||||
strlen(cfg->chrootdir)) != 0)
|
||||
fatal_exit("pid file %s not in chrootdir %s",
|
||||
cfg->pidfile, cfg->chrootdir);
|
||||
if(cfg->chrootdir && cfg->logfile && cfg->logfile[0] &&
|
||||
strncmp(cfg->chrootdir, cfg->logfile,
|
||||
strlen(cfg->chrootdir)) != 0)
|
||||
fatal_exit("log file %s not in chrootdir %s",
|
||||
cfg->logfile, cfg->chrootdir);
|
||||
check_chroot_filelist("file with root-hints",
|
||||
cfg->root_hints, cfg->chrootdir);
|
||||
check_chroot_filelist("trust-anchor-file",
|
||||
cfg->trust_anchor_file_list, cfg->chrootdir);
|
||||
check_chroot_filelist("trusted-keys-file",
|
||||
cfg->trusted_keys_file_list, cfg->chrootdir);
|
||||
|
||||
if(strcmp(cfg->module_conf, "iterator") != 0 &&
|
||||
strcmp(cfg->module_conf, "validator iterator") != 0) {
|
||||
fatal_exit("module conf '%s' is not known to work",
|
||||
cfg->module_conf);
|
||||
}
|
||||
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if(getpwnam(cfg->username) == NULL)
|
||||
fatal_exit("user '%s' does not exist.", cfg->username);
|
||||
endpwent();
|
||||
}
|
||||
|
||||
localzonechecks(cfg);
|
||||
}
|
||||
|
||||
/** check config file */
|
||||
static void
|
||||
checkconf(char* cfgfile)
|
||||
{
|
||||
struct config_file* cfg = config_create();
|
||||
if(!cfg)
|
||||
fatal_exit("out of memory");
|
||||
if(!config_read(cfg, cfgfile)) {
|
||||
/* config_read prints messages to stderr */
|
||||
config_delete(cfg);
|
||||
exit(1);
|
||||
}
|
||||
morechecks(cfg);
|
||||
check_mod(cfg, iter_get_funcblock());
|
||||
check_mod(cfg, val_get_funcblock());
|
||||
config_delete(cfg);
|
||||
printf("unbound-checkconf: no errors in %s\n", cfgfile);
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/** Main routine for checkconf */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int c;
|
||||
char* f;
|
||||
log_ident_set("unbound-checkconf");
|
||||
log_init(NULL, 0, NULL);
|
||||
checklock_start();
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "h")) != -1) {
|
||||
switch(c) {
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if(argc != 0 && argc != 1)
|
||||
usage();
|
||||
if(argc == 1)
|
||||
f = argv[0];
|
||||
else f = CONFIGFILE;
|
||||
checkconf(f);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* checkconf/unbound-host.c - replacement for host that supports validation.
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file performs functionality like 'host', and also supports validation.
|
||||
* It uses the libunbound library.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libunbound/unbound.h"
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
/** verbosity for unbound-host app */
|
||||
static int verb = 0;
|
||||
|
||||
/** Give unbound-host usage, and exit (1). */
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
printf("Usage: unbound-host [-vdh] [-c class] [-t type] hostname\n");
|
||||
printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n");
|
||||
printf(" Queries the DNS for information.\n");
|
||||
printf(" The hostname is looked up for IP4, IP6 and mail.\n");
|
||||
printf(" If an ip-address is given a reverse lookup is done.\n");
|
||||
printf(" Use the -v option to see DNSSEC security information.\n");
|
||||
printf(" -t type what type to look for.\n");
|
||||
printf(" -c class what class to look for, if not class IN.\n");
|
||||
printf(" -y 'keystring' specify trust anchor, DS or DNSKEY, like\n");
|
||||
printf(" -y 'example.com DS 31560 5 1 1CFED8478...'\n");
|
||||
printf(" -f keyfile read trust anchors from file, with lines as -y.\n");
|
||||
printf(" -F keyfile read named.conf-style trust anchors.\n");
|
||||
printf(" -v be more verbose, shows nodata and security.\n");
|
||||
printf(" -d debug, traces the action, -d -d shows more.\n");
|
||||
printf(" -h show this usage help.\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** determine if str is ip4 and put into reverse lookup format */
|
||||
static int
|
||||
isip4(const char* nm, char** res)
|
||||
{
|
||||
struct in_addr addr;
|
||||
/* ddd.ddd.ddd.ddd.in-addr.arpa. is less than 32 */
|
||||
char buf[32];
|
||||
if(inet_pton(AF_INET, nm, &addr) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa",
|
||||
(unsigned)((uint8_t*)&addr)[3], (unsigned)((uint8_t*)&addr)[2],
|
||||
(unsigned)((uint8_t*)&addr)[1], (unsigned)((uint8_t*)&addr)[0]);
|
||||
*res = strdup(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** determine if str is ip6 and put into reverse lookup format */
|
||||
static int
|
||||
isip6(const char* nm, char** res)
|
||||
{
|
||||
struct in6_addr addr;
|
||||
/* [nibble.]{32}.ip6.arpa. is less than 128 */
|
||||
char* hex = "0123456789abcdef";
|
||||
char buf[128];
|
||||
char *p;
|
||||
int i;
|
||||
if(inet_pton(AF_INET6, nm, &addr) <= 0) {
|
||||
return 0;
|
||||
}
|
||||
p = buf;
|
||||
for(i=15; i>=0; i--) {
|
||||
uint8_t b = ((uint8_t*)&addr)[i];
|
||||
*p++ = hex[ (b&0x0f) ];
|
||||
*p++ = '.';
|
||||
*p++ = hex[ (b&0xf0) >> 4 ];
|
||||
*p++ = '.';
|
||||
}
|
||||
snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa");
|
||||
*res = strdup(buf);
|
||||
if(!*res) {
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** massage input name */
|
||||
static char*
|
||||
massage_qname(const char* nm, int* reverse)
|
||||
{
|
||||
/* recognise IP4 and IP6, create reverse addresses if needed */
|
||||
char* res;
|
||||
if(isip4(nm, &res)) {
|
||||
*reverse = 1;
|
||||
} else if(isip6(nm, &res)) {
|
||||
*reverse = 1;
|
||||
} else {
|
||||
res = strdup(nm);
|
||||
}
|
||||
if(!res) {
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** massage input type */
|
||||
static int
|
||||
massage_type(const char* t, int reverse, int* multi)
|
||||
{
|
||||
if(t) {
|
||||
int r = ldns_get_rr_type_by_name(t);
|
||||
if(r == 0 && strcasecmp(t, "TYPE0") != 0 &&
|
||||
strcmp(t, "") != 0) {
|
||||
fprintf(stderr, "error unknown type %s\n", t);
|
||||
exit(1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if(!t && reverse)
|
||||
return LDNS_RR_TYPE_PTR;
|
||||
*multi = 1;
|
||||
return LDNS_RR_TYPE_A;
|
||||
}
|
||||
|
||||
/** massage input class */
|
||||
static int
|
||||
massage_class(const char* c)
|
||||
{
|
||||
if(c) {
|
||||
int r = ldns_get_rr_class_by_name(c);
|
||||
if(r == 0 && strcasecmp(c, "CLASS0") != 0 &&
|
||||
strcmp(c, "") != 0) {
|
||||
fprintf(stderr, "error unknown class %s\n", c);
|
||||
exit(1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return LDNS_RR_CLASS_IN;
|
||||
}
|
||||
|
||||
/** nice security status string */
|
||||
static const char*
|
||||
secure_str(struct ub_result* result)
|
||||
{
|
||||
if(result->secure) return "(secure)";
|
||||
if(result->bogus) return "(BOGUS (security failure))";
|
||||
return "(insecure)";
|
||||
}
|
||||
|
||||
/** nice string for type */
|
||||
static void
|
||||
pretty_type(char* s, size_t len, int t)
|
||||
{
|
||||
const ldns_rr_descriptor *d = ldns_rr_descript((uint16_t)t);
|
||||
if(d) {
|
||||
snprintf(s, len, "%s", d->_name);
|
||||
} else {
|
||||
snprintf(s, len, "TYPE%d", t);
|
||||
}
|
||||
}
|
||||
|
||||
/** nice string for class */
|
||||
static void
|
||||
pretty_class(char* s, size_t len, int c)
|
||||
{
|
||||
ldns_lookup_table *cl = ldns_lookup_by_id(ldns_rr_classes, c);
|
||||
if(cl) {
|
||||
snprintf(s, len, "%s", cl->name);
|
||||
} else {
|
||||
snprintf(s, len, "CLASS%d", c);
|
||||
}
|
||||
}
|
||||
|
||||
/** nice string for rcode */
|
||||
static void
|
||||
pretty_rcode(char* s, size_t len, int r)
|
||||
{
|
||||
ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, r);
|
||||
if(rcode) {
|
||||
snprintf(s, len, "%s", rcode->name);
|
||||
} else {
|
||||
snprintf(s, len, "RCODE%d", r);
|
||||
}
|
||||
}
|
||||
|
||||
/** convert and print rdata */
|
||||
static void
|
||||
print_rd(int t, char* data, size_t len)
|
||||
{
|
||||
size_t i, pos = 0;
|
||||
uint8_t* rd = (uint8_t*)malloc(len+2);
|
||||
ldns_rr* rr = ldns_rr_new();
|
||||
ldns_status status;
|
||||
if(!rd || !rr) {
|
||||
fprintf(stderr, "out of memory");
|
||||
exit(1);
|
||||
}
|
||||
ldns_rr_set_type(rr, t);
|
||||
ldns_write_uint16(rd, len);
|
||||
memmove(rd+2, data, len);
|
||||
ldns_rr_set_owner(rr, NULL);
|
||||
status = ldns_wire2rdf(rr, rd, len+2, &pos);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
|
||||
free(rd);
|
||||
printf("error_printing_data");
|
||||
}
|
||||
for(i=0; i<ldns_rr_rd_count(rr); i++) {
|
||||
printf(" ");
|
||||
ldns_rdf_print(stdout, ldns_rr_rdf(rr, i));
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
free(rd);
|
||||
}
|
||||
|
||||
/** pretty line of RR data for results */
|
||||
static void
|
||||
pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
|
||||
char* data, size_t len)
|
||||
{
|
||||
printf("%s", q);
|
||||
if(strcmp(cstr, "IN") != 0)
|
||||
printf(" in class %s", cstr);
|
||||
if(t == LDNS_RR_TYPE_A)
|
||||
printf(" has address");
|
||||
else if(t == LDNS_RR_TYPE_AAAA)
|
||||
printf(" has IPv6 address");
|
||||
else if(t == LDNS_RR_TYPE_MX)
|
||||
printf(" mail is handled by");
|
||||
else if(t == LDNS_RR_TYPE_PTR)
|
||||
printf(" domain name pointer");
|
||||
else printf(" has %s record", tstr);
|
||||
print_rd(t, data, len);
|
||||
if(verb > 0)
|
||||
printf(" %s", sec);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/** pretty line of output for results */
|
||||
static void
|
||||
pretty_output(char* q, int t, int c, struct ub_result* result, int docname)
|
||||
{
|
||||
int i;
|
||||
const char *secstatus = secure_str(result);
|
||||
char tstr[16];
|
||||
char cstr[16];
|
||||
char rcodestr[16];
|
||||
pretty_type(tstr, 16, t);
|
||||
pretty_class(cstr, 16, c);
|
||||
pretty_rcode(rcodestr, 16, result->rcode);
|
||||
|
||||
if(!result->havedata && result->rcode) {
|
||||
printf("Host %s not found: %d(%s).",
|
||||
q, result->rcode, rcodestr);
|
||||
if(verb > 0)
|
||||
printf(" %s", secstatus);
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
if(docname && result->canonname &&
|
||||
result->canonname != result->qname) {
|
||||
printf("%s is an alias for %s", result->qname,
|
||||
result->canonname);
|
||||
if(verb > 0)
|
||||
printf(" %s", secstatus);
|
||||
printf("\n");
|
||||
}
|
||||
/* remove trailing . from long canonnames for nicer output */
|
||||
if(result->canonname && strlen(result->canonname) > 1 &&
|
||||
result->canonname[strlen(result->canonname)-1] == '.')
|
||||
result->canonname[strlen(result->canonname)-1] = 0;
|
||||
if(!result->havedata) {
|
||||
if(verb > 0) {
|
||||
printf("%s", result->canonname?result->canonname:q);
|
||||
if(strcmp(cstr, "IN") != 0)
|
||||
printf(" in class %s", cstr);
|
||||
if(t == LDNS_RR_TYPE_A)
|
||||
printf(" has no address");
|
||||
else if(t == LDNS_RR_TYPE_AAAA)
|
||||
printf(" has no IPv6 address");
|
||||
else if(t == LDNS_RR_TYPE_PTR)
|
||||
printf(" has no domain name ptr");
|
||||
else if(t == LDNS_RR_TYPE_MX)
|
||||
printf(" has no mail handler record");
|
||||
else printf(" has no %s record", tstr);
|
||||
printf(" %s\n", secstatus);
|
||||
}
|
||||
/* else: emptiness to indicate no data */
|
||||
return;
|
||||
}
|
||||
i=0;
|
||||
while(result->data[i])
|
||||
{
|
||||
pretty_rdata(
|
||||
result->canonname?result->canonname:q,
|
||||
cstr, tstr, t, secstatus, result->data[i],
|
||||
(size_t)result->len[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/** perform a lookup and printout return if domain existed */
|
||||
static int
|
||||
dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname)
|
||||
{
|
||||
int ret;
|
||||
struct ub_result* result;
|
||||
|
||||
ret = ub_resolve(ctx, q, t, c, &result);
|
||||
if(ret != 0) {
|
||||
fprintf(stderr, "resolve error: %s\n", ub_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
pretty_output(q, t, c, result, docname);
|
||||
ret = result->nxdomain;
|
||||
ub_resolve_free(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** perform host lookup */
|
||||
static void
|
||||
lookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc)
|
||||
{
|
||||
/* massage input into a query name, type and class */
|
||||
int multi = 0; /* no type, so do A, AAAA, MX */
|
||||
int reverse = 0; /* we are doing a reverse lookup */
|
||||
char* realq = massage_qname(nm, &reverse);
|
||||
int t = massage_type(qt, reverse, &multi);
|
||||
int c = massage_class(qc);
|
||||
|
||||
/* perform the query */
|
||||
if(multi) {
|
||||
if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) {
|
||||
/* domain exists, lookup more */
|
||||
(void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0);
|
||||
(void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0);
|
||||
}
|
||||
} else {
|
||||
(void)dnslook(ctx, realq, t, c, 1);
|
||||
}
|
||||
ub_ctx_delete(ctx);
|
||||
free(realq);
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/** Main routine for checkconf */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int c;
|
||||
char* qclass = NULL;
|
||||
char* qtype = NULL;
|
||||
struct ub_ctx* ctx = NULL;
|
||||
int debuglevel = 0;
|
||||
|
||||
ctx = ub_ctx_create();
|
||||
if(!ctx) {
|
||||
fprintf(stderr, "error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "F:c:df:ht:vy:")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
qclass = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
debuglevel++;
|
||||
if(debuglevel < 2)
|
||||
debuglevel = 2; /* at least VERB_DETAIL */
|
||||
ub_ctx_debuglevel(ctx, debuglevel);
|
||||
break;
|
||||
case 't':
|
||||
qtype = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verb++;
|
||||
break;
|
||||
case 'y':
|
||||
ub_ctx_add_ta(ctx, optarg);
|
||||
break;
|
||||
case 'f':
|
||||
ub_ctx_add_ta_file(ctx, optarg);
|
||||
break;
|
||||
case 'F':
|
||||
ub_ctx_trustedkeys(ctx, optarg);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if(argc != 1)
|
||||
usage();
|
||||
|
||||
lookup(ctx, argv[0], qtype, qclass);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* checkconf/worker_cb.c - fake callback routines to make fptr_wlist work
|
||||
*
|
||||
* Copyright (c) 2007, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This file contains fake callback functions, so that the symbols exist
|
||||
* and the fptr_wlist continues to work even if the daemon/worker is not
|
||||
* linked into the resulting program.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "util/log.h"
|
||||
struct comm_reply;
|
||||
struct comm_point;
|
||||
struct module_qstate;
|
||||
|
||||
int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(repinfo))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int worker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
|
||||
struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
|
||||
{
|
||||
log_assert(0);
|
||||
return 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), struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
worker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int
|
||||
acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
|
||||
struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout),
|
||||
struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp))
|
||||
{
|
||||
log_assert(0);
|
||||
return 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),
|
||||
int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
|
||||
socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* testcode/asynclook.c - debug program perform async libunbound queries.
|
||||
*
|
||||
* Copyright (c) 2008, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This program shows the results from several background lookups,
|
||||
* while printing time in the foreground.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "libunbound/unbound.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
|
||||
/**
|
||||
* result list for the lookups
|
||||
*/
|
||||
struct lookinfo {
|
||||
/** name to look up */
|
||||
char* name;
|
||||
/** tracking number that can be used to cancel the query */
|
||||
int async_id;
|
||||
/** error code from libunbound */
|
||||
int err;
|
||||
/** result from lookup */
|
||||
struct ub_result* result;
|
||||
};
|
||||
|
||||
/** global variable to see how many queries we have left */
|
||||
static int num_wait = 0;
|
||||
|
||||
/** usage information for asynclook */
|
||||
void usage(char* argv[])
|
||||
{
|
||||
printf("usage: %s [options] name ...\n", argv[0]);
|
||||
printf("names are looked up at the same time, asynchronously.\n");
|
||||
printf(" -b : use blocking requests\n");
|
||||
printf(" -c : cancel the requests\n");
|
||||
printf(" -d : enable debug output\n");
|
||||
printf(" -f addr : use addr, forward to that server\n");
|
||||
printf(" -h : this help message\n");
|
||||
printf(" -H fname : read hosts from fname\n");
|
||||
printf(" -r fname : read resolv.conf from fname\n");
|
||||
printf(" -t : use a resolver thread instead of forking a process\n");
|
||||
printf(" -x : perform extended threaded test\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** print result from lookup nicely */
|
||||
static void
|
||||
print_result(struct lookinfo* info)
|
||||
{
|
||||
char buf[100];
|
||||
if(info->err) /* error (from libunbound) */
|
||||
printf("%s: error %s\n", info->name,
|
||||
ub_strerror(info->err));
|
||||
else if(!info->result)
|
||||
printf("%s: cancelled\n", info->name);
|
||||
else if(info->result->havedata)
|
||||
printf("%s: %s\n", info->name,
|
||||
inet_ntop(AF_INET, info->result->data[0],
|
||||
buf, (socklen_t)sizeof(buf)));
|
||||
else {
|
||||
/* there is no data, why that? */
|
||||
if(info->result->rcode == 0 /*noerror*/ ||
|
||||
info->result->nxdomain)
|
||||
printf("%s: no data %s\n", info->name,
|
||||
info->result->nxdomain?"(no such host)":
|
||||
"(no IP4 address)");
|
||||
else /* some error (from the server) */
|
||||
printf("%s: DNS error %d\n", info->name,
|
||||
info->result->rcode);
|
||||
}
|
||||
}
|
||||
|
||||
/** this is a function of type ub_callback_t */
|
||||
static void
|
||||
lookup_is_done(void* mydata, int err, struct ub_result* result)
|
||||
{
|
||||
/* cast mydata back to the correct type */
|
||||
struct lookinfo* info = (struct lookinfo*)mydata;
|
||||
fprintf(stderr, "name %s resolved\n", info->name);
|
||||
info->err = err;
|
||||
info->result = result;
|
||||
/* one less to wait for */
|
||||
num_wait--;
|
||||
}
|
||||
|
||||
/** check error, if bad, exit with error message */
|
||||
static void
|
||||
checkerr(const char* desc, int err)
|
||||
{
|
||||
if(err != 0) {
|
||||
printf("%s error: %s\n", desc, ub_strerror(err));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS)
|
||||
/** only one process can communicate with async worker */
|
||||
#define NUMTHR 1
|
||||
#else /* have threads */
|
||||
/** number of threads to make in extended test */
|
||||
#define NUMTHR 10
|
||||
#endif
|
||||
|
||||
/** struct for extended thread info */
|
||||
struct ext_thr_info {
|
||||
/** thread num for debug */
|
||||
int thread_num;
|
||||
/** thread id */
|
||||
ub_thread_t tid;
|
||||
/** context */
|
||||
struct ub_ctx* ctx;
|
||||
/** size of array to query */
|
||||
int argc;
|
||||
/** array of names to query */
|
||||
char** argv;
|
||||
/** number of queries to do */
|
||||
int numq;
|
||||
};
|
||||
|
||||
/** if true, we are testing against 'localhost' and extra checking is done */
|
||||
static int q_is_localhost = 0;
|
||||
|
||||
/** check result structure for the 'correct' answer */
|
||||
static void
|
||||
ext_check_result(const char* desc, int err, struct ub_result* result)
|
||||
{
|
||||
checkerr(desc, err);
|
||||
if(result == NULL) {
|
||||
printf("%s: error result is NULL.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(q_is_localhost) {
|
||||
if(strcmp(result->qname, "localhost") != 0) {
|
||||
printf("%s: error result has wrong qname.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->qtype != LDNS_RR_TYPE_A) {
|
||||
printf("%s: error result has wrong qtype.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->qclass != LDNS_RR_CLASS_IN) {
|
||||
printf("%s: error result has wrong qclass.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->data == NULL) {
|
||||
printf("%s: error result->data is NULL.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->len == NULL) {
|
||||
printf("%s: error result->len is NULL.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->rcode != 0) {
|
||||
printf("%s: error result->rcode is set.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->havedata == 0) {
|
||||
printf("%s: error result->havedata is unset.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->nxdomain != 0) {
|
||||
printf("%s: error result->nxdomain is set.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->secure || result->bogus) {
|
||||
printf("%s: error result->secure or bogus is set.\n",
|
||||
desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->data[0] == NULL) {
|
||||
printf("%s: error result->data[0] is NULL.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->len[0] != 4) {
|
||||
printf("%s: error result->len[0] is wrong.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->len[1] != 0 || result->data[1] != NULL) {
|
||||
printf("%s: error result->data[1] or len[1] is "
|
||||
"wrong.\n", desc);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** extended bg result callback, this function is ub_callback_t */
|
||||
static void
|
||||
ext_callback(void* mydata, int err, struct ub_result* result)
|
||||
{
|
||||
int* my_id = (int*)mydata;
|
||||
int doprint = 0;
|
||||
if(my_id) {
|
||||
/* I have an id, make sure we are not cancelled */
|
||||
if(*my_id == 0) {
|
||||
printf("error: query returned, but was cancelled\n");
|
||||
abort();
|
||||
exit(1);
|
||||
}
|
||||
if(doprint)
|
||||
printf("cb %d: ", *my_id);
|
||||
}
|
||||
ext_check_result("ext_callback", err, result);
|
||||
log_assert(result);
|
||||
if(doprint) {
|
||||
struct lookinfo pi;
|
||||
pi.name = result?result->qname:"noname";
|
||||
pi.result = result;
|
||||
pi.err = 0;
|
||||
print_result(&pi);
|
||||
}
|
||||
ub_resolve_free(result);
|
||||
}
|
||||
|
||||
/** extended thread worker */
|
||||
static void*
|
||||
ext_thread(void* arg)
|
||||
{
|
||||
struct ext_thr_info* inf = (struct ext_thr_info*)arg;
|
||||
int i, r;
|
||||
struct ub_result* result;
|
||||
int* async_ids = NULL;
|
||||
log_thread_set(&inf->thread_num);
|
||||
if(inf->thread_num > NUMTHR*2/3) {
|
||||
async_ids = (int*)calloc((size_t)inf->numq, sizeof(int));
|
||||
if(!async_ids) {
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for(i=0; i<inf->numq; i++) {
|
||||
if(async_ids) {
|
||||
r = ub_resolve_async(inf->ctx,
|
||||
inf->argv[i%inf->argc], LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, &async_ids[i], ext_callback,
|
||||
&async_ids[i]);
|
||||
checkerr("ub_resolve_async", r);
|
||||
if(i > 100) {
|
||||
r = ub_cancel(inf->ctx, async_ids[i-100]);
|
||||
checkerr("ub_cancel", r);
|
||||
async_ids[i-100]=0;
|
||||
}
|
||||
} else if(inf->thread_num > NUMTHR/2) {
|
||||
/* async */
|
||||
r = ub_resolve_async(inf->ctx,
|
||||
inf->argv[i%inf->argc], LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, NULL, ext_callback, NULL);
|
||||
checkerr("ub_resolve_async", r);
|
||||
} else {
|
||||
/* blocking */
|
||||
r = ub_resolve(inf->ctx, inf->argv[i%inf->argc],
|
||||
LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &result);
|
||||
ext_check_result("ub_resolve", r, result);
|
||||
}
|
||||
}
|
||||
if(inf->thread_num > NUMTHR/2) {
|
||||
r = ub_wait(inf->ctx);
|
||||
checkerr("ub_ctx_wait", r);
|
||||
}
|
||||
free(async_ids);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** perform extended threaded test */
|
||||
static int
|
||||
ext_test(struct ub_ctx* ctx, int argc, char** argv)
|
||||
{
|
||||
struct ext_thr_info inf[NUMTHR];
|
||||
int i;
|
||||
if(argc == 1 && strcmp(argv[0], "localhost") == 0)
|
||||
q_is_localhost = 1;
|
||||
printf("extended test start (%d threads)\n", NUMTHR);
|
||||
for(i=0; i<NUMTHR; i++) {
|
||||
/* 0 = this, 1 = library bg worker */
|
||||
inf[i].thread_num = i+2;
|
||||
inf[i].ctx = ctx;
|
||||
inf[i].argc = argc;
|
||||
inf[i].argv = argv;
|
||||
inf[i].numq = 1000;
|
||||
ub_thread_create(&inf[i].tid, ext_thread, &inf[i]);
|
||||
}
|
||||
/* the work happens here */
|
||||
for(i=0; i<NUMTHR; i++) {
|
||||
ub_thread_join(inf[i].tid);
|
||||
}
|
||||
printf("extended test end\n");
|
||||
ub_ctx_delete(ctx);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/** main program for asynclook */
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int c;
|
||||
struct ub_ctx* ctx;
|
||||
struct lookinfo* lookups;
|
||||
int i, r, cancel=0, blocking=0, ext=0;
|
||||
|
||||
/* lock debug start (if any) */
|
||||
checklock_start();
|
||||
|
||||
/* create context */
|
||||
ctx = ub_ctx_create();
|
||||
if(!ctx) {
|
||||
printf("could not create context, %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* command line options */
|
||||
if(argc == 1) {
|
||||
usage(argv);
|
||||
}
|
||||
while( (c=getopt(argc, argv, "bcdf:hH:r:tx")) != -1) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
r = ub_ctx_debuglevel(ctx, 3);
|
||||
checkerr("ub_ctx_debuglevel", r);
|
||||
break;
|
||||
case 't':
|
||||
r = ub_ctx_async(ctx, 1);
|
||||
checkerr("ub_ctx_async", r);
|
||||
break;
|
||||
case 'c':
|
||||
cancel = 1;
|
||||
break;
|
||||
case 'b':
|
||||
blocking = 1;
|
||||
break;
|
||||
case 'r':
|
||||
r = ub_ctx_resolvconf(ctx, optarg);
|
||||
if(r != 0) {
|
||||
printf("ub_ctx_resolvconf "
|
||||
"error: %s : %s\n",
|
||||
ub_strerror(r),
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
r = ub_ctx_hosts(ctx, optarg);
|
||||
if(r != 0) {
|
||||
printf("ub_ctx_hosts "
|
||||
"error: %s : %s\n",
|
||||
ub_strerror(r),
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
r = ub_ctx_set_fwd(ctx, optarg);
|
||||
checkerr("ub_ctx_set_fwd", r);
|
||||
break;
|
||||
case 'x':
|
||||
ext = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage(argv);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(ext)
|
||||
return ext_test(ctx, argc, argv);
|
||||
|
||||
/* allocate array for results. */
|
||||
lookups = (struct lookinfo*)calloc((size_t)argc,
|
||||
sizeof(struct lookinfo));
|
||||
if(!lookups) {
|
||||
printf("out of memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* perform asyncronous calls */
|
||||
num_wait = argc;
|
||||
for(i=0; i<argc; i++) {
|
||||
lookups[i].name = argv[i];
|
||||
if(blocking) {
|
||||
fprintf(stderr, "lookup %s\n", argv[i]);
|
||||
r = ub_resolve(ctx, argv[i], LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, &lookups[i].result);
|
||||
checkerr("ub_resolve", r);
|
||||
} else {
|
||||
fprintf(stderr, "start async lookup %s\n", argv[i]);
|
||||
r = ub_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done,
|
||||
&lookups[i].async_id);
|
||||
checkerr("ub_resolve_async", r);
|
||||
}
|
||||
}
|
||||
if(blocking)
|
||||
num_wait = 0;
|
||||
else if(cancel) {
|
||||
for(i=0; i<argc; i++) {
|
||||
fprintf(stderr, "cancel %s\n", argv[i]);
|
||||
r = ub_cancel(ctx, lookups[i].async_id);
|
||||
checkerr("ub_cancel", r);
|
||||
}
|
||||
num_wait = 0;
|
||||
}
|
||||
|
||||
/* wait while the hostnames are looked up. Do something useful here */
|
||||
if(num_wait > 0)
|
||||
for(i=0; i<1000; i++) {
|
||||
usleep(100000);
|
||||
fprintf(stderr, "%g seconds passed\n", 0.1*(double)i);
|
||||
r = ub_process(ctx);
|
||||
checkerr("ub_process", r);
|
||||
if(num_wait == 0)
|
||||
break;
|
||||
}
|
||||
if(i>=999) {
|
||||
printf("timed out\n");
|
||||
return 0;
|
||||
}
|
||||
printf("lookup complete\n");
|
||||
|
||||
/* print lookup results */
|
||||
for(i=0; i<argc; i++) {
|
||||
print_result(&lookups[i]);
|
||||
ub_resolve_free(lookups[i].result);
|
||||
}
|
||||
|
||||
ub_ctx_delete(ctx);
|
||||
free(lookups);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
+21
-2
@@ -63,7 +63,7 @@ static ub_thread_key_t thr_debug_key;
|
||||
/** the list of threads, so all threads can be examined. NULL if unused. */
|
||||
static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS];
|
||||
/** do we check locking order */
|
||||
int check_locking_order = 0;
|
||||
int check_locking_order = 1;
|
||||
/** the pid of this runset, reasonably unique. */
|
||||
static pid_t check_lock_pid;
|
||||
|
||||
@@ -658,7 +658,9 @@ static void* checklock_main(void* arg)
|
||||
/* Hack to get same numbers as in log file */
|
||||
thr->num = *(int*)(thr->arg);
|
||||
log_assert(thr->num < THRDEBUG_MAX_THREADS);
|
||||
log_assert(thread_infos[thr->num] == NULL);
|
||||
/* as an aside, due to this, won't work for libunbound bg thread */
|
||||
if(thread_infos[thr->num] != NULL)
|
||||
log_warn("thread warning, thr->num %d not NULL", thr->num);
|
||||
thread_infos[thr->num] = thr;
|
||||
LOCKRET(pthread_setspecific(thr_debug_key, thr));
|
||||
if(check_locking_order)
|
||||
@@ -830,3 +832,20 @@ checklock_thrjoin(pthread_t thread)
|
||||
}
|
||||
|
||||
#endif /* USE_THREAD_DEBUG */
|
||||
|
||||
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;
|
||||
if(o1->thr < o2->thr) return -1;
|
||||
if(o1->thr > o2->thr) return 1;
|
||||
if(o1->instance < o2->instance) return -1;
|
||||
if(o1->instance > o2->instance) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
codeline_cmp(const void* a, const void* b)
|
||||
{
|
||||
return strcmp((const char*)a, (const char*)b);
|
||||
}
|
||||
|
||||
@@ -341,4 +341,16 @@ typedef pthread_key_t ub_thread_key_t;
|
||||
|
||||
#endif /* USE_THREAD_DEBUG */
|
||||
|
||||
/** keep track of lock id in lock-verify application */
|
||||
struct order_id {
|
||||
/** the thread id that created it */
|
||||
int thr;
|
||||
/** the instance number of creation */
|
||||
int instance;
|
||||
};
|
||||
/** compare two order_ids */
|
||||
int order_lock_cmp(const void* e1, const void* e2);
|
||||
/** compare two codeline structs for rbtree */
|
||||
int codeline_cmp(const void* a, const void* b);
|
||||
|
||||
#endif /* TESTCODE_CHECK_LOCKS_H */
|
||||
|
||||
+13
-1
@@ -2,7 +2,9 @@
|
||||
|
||||
NEED_SPLINT='00-lint.tpkg'
|
||||
NEED_DOXYGEN='01-doc.tpkg'
|
||||
NEED_LDNS_TESTNS='fwd_no_edns.tpkg fwd_tcp_tc.tpkg fwd_tcp.tpkg fwd_three_service.tpkg fwd_three.tpkg fwd_ttlexpire.tpkg fwd_udp.tpkg'
|
||||
NEED_LDNS_TESTNS='fwd_no_edns.tpkg fwd_tcp_tc.tpkg fwd_tcp.tpkg fwd_three_service.tpkg fwd_three.tpkg fwd_ttlexpire.tpkg fwd_udp.tpkg fwd_tcp_tc6.tpkg fwd_compress_c00c.tpkg fwd_ancil.tpkg stat_timer.tpkg 05-asynclook.tpkg stream_tcp.tpkg'
|
||||
NEED_XXD='fwd_compress_c00c.tpkg'
|
||||
NEED_NC='fwd_compress_c00c.tpkg'
|
||||
|
||||
cd testdata;
|
||||
sh ../testcode/mini_tpkg.sh clean
|
||||
@@ -23,6 +25,16 @@ for test in `ls *.tpkg`; do
|
||||
SKIP=1;
|
||||
fi
|
||||
fi
|
||||
if echo $NEED_XXD | grep $test >/dev/null; then
|
||||
if test ! -x "`which xxd`"; then
|
||||
SKIP=1;
|
||||
fi
|
||||
fi
|
||||
if echo $NEED_NC | grep $test >/dev/null; then
|
||||
if test ! -x "`which nc`"; then
|
||||
SKIP=1;
|
||||
fi
|
||||
fi
|
||||
if test $SKIP -eq 0; then
|
||||
echo $test
|
||||
sh ../testcode/mini_tpkg.sh -a ../.. exe $test
|
||||
|
||||
+145
-16
@@ -56,6 +56,7 @@
|
||||
#include "testcode/replay.h"
|
||||
#include "testcode/ldns-testpkts.h"
|
||||
#include "util/log.h"
|
||||
#include <signal.h>
|
||||
|
||||
/** Global variable: the scenario. Saved here for when event_init is done. */
|
||||
static struct replay_scenario* saved_scenario = NULL;
|
||||
@@ -178,7 +179,7 @@ pending_find_match(struct replay_runtime* runtime, struct entry** entry,
|
||||
"with entry line %d", timenow,
|
||||
p->start_step, p->end_step, (*entry)->lineno);
|
||||
if(p->addrlen != 0)
|
||||
log_addr("matched ip", &p->addr, p->addrlen);
|
||||
log_addr(0, "matched ip", &p->addr, p->addrlen);
|
||||
log_pkt("matched pkt: ", (*entry)->reply_list->reply);
|
||||
return 1;
|
||||
}
|
||||
@@ -359,6 +360,7 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
|
||||
else repinfo.c->type = comm_udp;
|
||||
fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL);
|
||||
log_info("testbound: incoming QUERY");
|
||||
log_pkt("query pkt", todo->match->reply_list->reply);
|
||||
/* call the callback for incoming queries */
|
||||
if((*runtime->callback_query)(repinfo.c, runtime->cb_arg,
|
||||
NETEVENT_NOERROR, &repinfo)) {
|
||||
@@ -379,6 +381,9 @@ fake_pending_callback(struct replay_runtime* runtime,
|
||||
struct fake_pending* p = runtime->pending_list;
|
||||
struct comm_reply repinfo;
|
||||
struct comm_point c;
|
||||
void* cb_arg = p->cb_arg;
|
||||
comm_point_callback_t* cb = p->callback;
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
if(!p) fatal_exit("No pending queries.");
|
||||
log_assert(todo->qname == NULL); /* or find that one */
|
||||
@@ -392,12 +397,13 @@ fake_pending_callback(struct replay_runtime* runtime,
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = p->addrlen;
|
||||
memcpy(&repinfo.addr, &p->addr, p->addrlen);
|
||||
if((*p->callback)(&c, p->cb_arg, error, &repinfo)) {
|
||||
if(!p->serviced)
|
||||
pending_list_delete(runtime, p);
|
||||
if((*cb)(&c, cb_arg, error, &repinfo)) {
|
||||
fatal_exit("unexpected: pending callback returned 1");
|
||||
}
|
||||
/* delete the pending item. */
|
||||
ldns_buffer_free(c.buffer);
|
||||
pending_list_delete(runtime, p);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,6 +523,7 @@ run_scenario(struct replay_runtime* runtime)
|
||||
fatal_exit("testbound: there are unmatched answers.");
|
||||
}
|
||||
log_info("testbound: exiting fake runloop.");
|
||||
runtime->exit_cleanly = 1;
|
||||
}
|
||||
|
||||
/*********** Dummy routines ***********/
|
||||
@@ -590,13 +597,19 @@ comm_base_dispatch(struct comm_base* b)
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)b;
|
||||
run_scenario(runtime);
|
||||
if(runtime->sig_cb)
|
||||
(*runtime->sig_cb)(SIGTERM, runtime->sig_cb_arg);
|
||||
else exit(0); /* OK exit when LIBEVENT_SIGNAL_PROBLEM exists */
|
||||
}
|
||||
|
||||
void
|
||||
comm_base_exit(struct comm_base* ATTR_UNUSED(b))
|
||||
comm_base_exit(struct comm_base* b)
|
||||
{
|
||||
/* some sort of failure */
|
||||
fatal_exit("testbound: comm_base_exit was called.");
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)b;
|
||||
if(!runtime->exit_cleanly) {
|
||||
/* some sort of failure */
|
||||
fatal_exit("testbound: comm_base_exit was called.");
|
||||
}
|
||||
}
|
||||
|
||||
struct comm_signal*
|
||||
@@ -649,15 +662,6 @@ comm_point_send_reply(struct comm_reply* repinfo)
|
||||
log_pkt("reply pkt: ", ans->pkt);
|
||||
}
|
||||
|
||||
void
|
||||
comm_point_send_reply_iov(struct comm_reply* repinfo, struct iovec* iov,
|
||||
size_t iovlen)
|
||||
{
|
||||
/* skip tcp len at [0]. */
|
||||
write_iov_buffer(repinfo->c->buffer, iov+1, iovlen-1);
|
||||
comm_point_send_reply(repinfo);
|
||||
}
|
||||
|
||||
void
|
||||
comm_point_drop_reply(struct comm_reply* repinfo)
|
||||
{
|
||||
@@ -850,7 +854,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
||||
pend->addrlen = addrlen;
|
||||
pend->callback = callback;
|
||||
pend->cb_arg = callback_arg;
|
||||
pend->timeout = UDP_QUERY_TIMEOUT;
|
||||
pend->timeout = UDP_AUTH_QUERY_TIMEOUT;
|
||||
pend->transport = transport_udp; /* pretend UDP */
|
||||
pend->pkt = NULL;
|
||||
pend->runtime = runtime;
|
||||
@@ -959,4 +963,129 @@ size_t serviced_get_mem(struct serviced_query* ATTR_UNUSED(c))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fake for fptr wlist */
|
||||
int outnet_udp_cb(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply *ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int outnet_tcp_cb(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply *ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pending_udp_timer_cb(void *ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void outnet_tcptimer(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_udp_ancil_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_tcp_accept_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_tcp_handle_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_timer_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_signal_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_local_handle_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
|
||||
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int serviced_udp_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serviced_tcp_callback(struct comm_point* ATTR_UNUSED(c),
|
||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||
struct comm_reply* ATTR_UNUSED(reply_info))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pending_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serviced_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* no statistics timers in testbound */
|
||||
struct comm_timer* comm_timer_create(struct comm_base* ATTR_UNUSED(base),
|
||||
void (*cb)(void*), void* ATTR_UNUSED(cb_arg))
|
||||
{
|
||||
(void)cb;
|
||||
return malloc(1);
|
||||
}
|
||||
|
||||
void comm_timer_disable(struct comm_timer* ATTR_UNUSED(timer))
|
||||
{
|
||||
}
|
||||
|
||||
void comm_timer_set(struct comm_timer* ATTR_UNUSED(timer),
|
||||
struct timeval* ATTR_UNUSED(tv))
|
||||
{
|
||||
}
|
||||
|
||||
void comm_timer_delete(struct comm_timer* timer)
|
||||
{
|
||||
free(timer);
|
||||
}
|
||||
|
||||
/*********** End of Dummy routines ***********/
|
||||
|
||||
@@ -185,6 +185,7 @@ static void replyline(const char* line, ldns_pkt *reply)
|
||||
} else if(str_keyword(&parse, "AD")) {
|
||||
ldns_pkt_set_ad(reply, true);
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
ldns_pkt_set_edns_udp_size(reply, 4096);
|
||||
ldns_pkt_set_edns_do(reply, true);
|
||||
} else {
|
||||
error("could not parse REPLY: '%s'", parse);
|
||||
@@ -503,7 +504,7 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** reads the canned reply file and returns a list of structs */
|
||||
/* reads the canned reply file and returns a list of structs */
|
||||
struct entry*
|
||||
read_datafile(const char* name)
|
||||
{
|
||||
@@ -533,6 +534,8 @@ read_datafile(const char* name)
|
||||
verbose(1, "%s: Read %d entries\n", prog_name, entry_num);
|
||||
|
||||
fclose(in);
|
||||
ldns_rdf_deep_free(origin);
|
||||
ldns_rdf_deep_free(prev_rr);
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -642,7 +645,7 @@ match_all(ldns_pkt* q, ldns_pkt* p, bool mttl)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** finds entry in list, or returns NULL */
|
||||
/* finds entry in list, or returns NULL */
|
||||
struct entry*
|
||||
find_match(struct entry* entries, ldns_pkt* query_pkt,
|
||||
enum transport_type transport)
|
||||
@@ -778,9 +781,14 @@ handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count,
|
||||
answer_pkt = NULL;
|
||||
} else {
|
||||
verbose(3, "Could not parse hex data (%s), sending hex data directly.\n", ldns_get_errorstr_by_id(status));
|
||||
/* still try to adjust ID */
|
||||
answer_size = ldns_buffer_capacity(p->reply_from_hex);
|
||||
outbuf = LDNS_XMALLOC(uint8_t, answer_size);
|
||||
memcpy(outbuf, ldns_buffer_export(p->reply_from_hex), answer_size);
|
||||
if(entry->copy_id) {
|
||||
ldns_write_uint16(outbuf,
|
||||
ldns_pkt_id(query_pkt));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
answer_pkt = ldns_pkt_clone(p->reply);
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
; with the SECTION keywords (only SECTION QUERY
|
||||
; is used to match queries). If the data cannot
|
||||
; be parsed, ADJUST rules for the answer packet
|
||||
; are ignored
|
||||
; are ignored. Only copy_id is done.
|
||||
HEX_ANSWER_END
|
||||
ENTRY_END
|
||||
|
||||
|
||||
+3
-21
@@ -46,18 +46,12 @@
|
||||
#include "config.h"
|
||||
#include "util/log.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "util/locks.h"
|
||||
#include "testcode/checklocks.h"
|
||||
|
||||
/* --- data structures --- */
|
||||
struct lock_ref;
|
||||
|
||||
/** key for lock lookup */
|
||||
struct order_id {
|
||||
/** the thread id that created it */
|
||||
int thr;
|
||||
/** the instance number of creation */
|
||||
int instance;
|
||||
};
|
||||
|
||||
/** a lock */
|
||||
struct order_lock {
|
||||
/** rbnode in all tree */
|
||||
@@ -103,18 +97,6 @@ usage()
|
||||
printf("lock_verify <trace files>\n");
|
||||
}
|
||||
|
||||
/** compare two order_ids */
|
||||
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;
|
||||
if(o1->thr < o2->thr) return -1;
|
||||
if(o1->thr > o2->thr) return 1;
|
||||
if(o1->instance < o2->instance) return -1;
|
||||
if(o1->instance > o2->instance) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** read header entry.
|
||||
* @param in: file to read header of.
|
||||
* @return: False if it does not belong to the rest. */
|
||||
@@ -403,7 +385,7 @@ main(int argc, char* argv[])
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
log_init(NULL);
|
||||
log_init(NULL, 0, NULL);
|
||||
log_ident_set("lock-verify");
|
||||
/* init */
|
||||
all_locks = rbtree_create(order_lock_cmp);
|
||||
|
||||
+16
-42
@@ -42,6 +42,8 @@
|
||||
#include "config.h"
|
||||
#include "util/log.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "util/locks.h"
|
||||
#include "testcode/checklocks.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
@@ -58,14 +60,8 @@ struct codeline {
|
||||
uint64_t alloc;
|
||||
/** number of bytes freed */
|
||||
uint64_t free;
|
||||
};
|
||||
|
||||
/**
|
||||
* Other allocation stats
|
||||
*/
|
||||
struct alloc_misc {
|
||||
/** number of region allocs */
|
||||
uint64_t region_alloc;
|
||||
/** number allocations and frees */
|
||||
uint64_t calls;
|
||||
};
|
||||
|
||||
/** print usage and exit */
|
||||
@@ -77,13 +73,6 @@ usage()
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** compare two codeline structs for rbtree */
|
||||
static int
|
||||
codeline_cmp(const void* a, const void* b)
|
||||
{
|
||||
return strcmp((const char*)a, (const char*)b);
|
||||
}
|
||||
|
||||
/** match logfile line to see if it needs accounting processing */
|
||||
static int
|
||||
match(char* line)
|
||||
@@ -106,18 +95,6 @@ match(char* line)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** read up the region stats */
|
||||
static void
|
||||
read_region_stat(char* line, struct alloc_misc* misc)
|
||||
{
|
||||
long num = 0;
|
||||
if(sscanf(line+50, "%ld", &num) != 1) {
|
||||
printf("%s\n%s\n", line, line+50);
|
||||
fatal_exit("unhandled region");
|
||||
}
|
||||
misc->region_alloc += num;
|
||||
}
|
||||
|
||||
/** find or alloc codeline in tree */
|
||||
static struct codeline*
|
||||
get_codeline(rbtree_t* tree, char* key, char* func)
|
||||
@@ -158,6 +135,7 @@ read_malloc_stat(char* line, rbtree_t* tree)
|
||||
if(!cl)
|
||||
fatal_exit("alloc failure");
|
||||
cl->alloc += num;
|
||||
cl->calls ++;
|
||||
}
|
||||
|
||||
/** read up the calloc stats */
|
||||
@@ -182,6 +160,7 @@ read_calloc_stat(char* line, rbtree_t* tree)
|
||||
if(!cl)
|
||||
fatal_exit("alloc failure");
|
||||
cl->alloc += num*sz;
|
||||
cl->calls ++;
|
||||
}
|
||||
|
||||
/** get size of file */
|
||||
@@ -197,7 +176,7 @@ get_file_size(const char* fname)
|
||||
|
||||
/** read the logfile */
|
||||
static void
|
||||
readfile(rbtree_t* tree, const char* fname, struct alloc_misc* misc)
|
||||
readfile(rbtree_t* tree, const char* fname)
|
||||
{
|
||||
off_t total = get_file_size(fname);
|
||||
off_t done = (off_t)0;
|
||||
@@ -218,8 +197,6 @@ readfile(rbtree_t* tree, const char* fname, struct alloc_misc* misc)
|
||||
|
||||
if(!match(buf))
|
||||
continue;
|
||||
if(strncmp(buf+36, "region ", 7) == 0)
|
||||
read_region_stat(buf, misc);
|
||||
else if(strstr(buf+36, "malloc("))
|
||||
read_malloc_stat(buf, tree);
|
||||
else if(strstr(buf+36, "calloc("))
|
||||
@@ -235,20 +212,19 @@ readfile(rbtree_t* tree, const char* fname, struct alloc_misc* misc)
|
||||
|
||||
/** print memory stats */
|
||||
static void
|
||||
printstats(rbtree_t* tree, struct alloc_misc* misc)
|
||||
printstats(rbtree_t* tree)
|
||||
{
|
||||
struct codeline* cl;
|
||||
uint64_t total = 0;
|
||||
printf("%12lld in region alloc\n", (long long)misc->region_alloc);
|
||||
total += misc->region_alloc;
|
||||
uint64_t total = 0, tcalls = 0;
|
||||
RBTREE_FOR(cl, struct codeline*, tree) {
|
||||
printf("%12lld in %s %s\n", (long long)cl->alloc,
|
||||
cl->codeline, cl->func);
|
||||
printf("%12lld / %8lld in %s %s\n", (long long)cl->alloc,
|
||||
(long long)cl->calls, cl->codeline, cl->func);
|
||||
total += cl->alloc;
|
||||
tcalls += cl->calls;
|
||||
}
|
||||
printf("------------\n");
|
||||
printf("%12lld total in %ld code lines\n", (long long)total,
|
||||
(long)tree->count);
|
||||
printf("%12lld / %8lld total in %ld code lines\n", (long long)total,
|
||||
(long long)tcalls, (long)tree->count);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -256,15 +232,13 @@ printstats(rbtree_t* tree, struct alloc_misc* misc)
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
rbtree_t* tree = 0;
|
||||
struct alloc_misc misc;
|
||||
if(argc != 2) {
|
||||
usage();
|
||||
}
|
||||
tree = rbtree_create(codeline_cmp);
|
||||
if(!tree)
|
||||
fatal_exit("alloc failure");
|
||||
memset(&misc, 0, sizeof(misc));
|
||||
readfile(tree, argv[1], &misc);
|
||||
printstats(tree, &misc);
|
||||
readfile(tree, argv[1]);
|
||||
printstats(tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ skip_whites(const char** p)
|
||||
}
|
||||
}
|
||||
|
||||
/** takes a hex string and puts into buffer */
|
||||
/* takes a hex string and puts into buffer */
|
||||
void hex_to_buf(ldns_buffer* pkt, const char* hex)
|
||||
{
|
||||
const char* p = hex;
|
||||
|
||||
+5
-1
@@ -41,7 +41,11 @@
|
||||
#ifndef TESTCODE_READHEX_H
|
||||
#define TESTCODE_READHEX_H
|
||||
|
||||
/** helper to convert hex string to packet buffer */
|
||||
/**
|
||||
* Helper to convert hex string to packet buffer.
|
||||
* @param pkt: buffer to put result in.
|
||||
* @param hex: string of hex data. Spaces and ';...' comments are skipped.
|
||||
*/
|
||||
void hex_to_buf(ldns_buffer* pkt, const char* hex);
|
||||
|
||||
#endif /* TESTCODE_READHEX_H */
|
||||
|
||||
+11
-2
@@ -135,8 +135,10 @@ replay_range_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
parse = line;
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
if(!*parse || *parse == ';')
|
||||
if(!*parse || *parse == ';') {
|
||||
pos = ftello(in);
|
||||
continue;
|
||||
}
|
||||
if(parse_keyword(&parse, "ADDRESS")) {
|
||||
while(isspace((int)*parse))
|
||||
parse++;
|
||||
@@ -206,6 +208,8 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
} else if(parse_keyword(&remain, "QUERY")) {
|
||||
mom->evt_type = repevt_front_query;
|
||||
readentry = 1;
|
||||
if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen))
|
||||
fatal_exit("internal error");
|
||||
} else if(parse_keyword(&remain, "CHECK_ANSWER")) {
|
||||
mom->evt_type = repevt_front_reply;
|
||||
readentry = 1;
|
||||
@@ -227,13 +231,18 @@ replay_moment_read(char* remain, FILE* in, const char* name, int* lineno,
|
||||
while(isspace((int)*remain))
|
||||
remain++;
|
||||
if(parse_keyword(&remain, "ADDRESS")) {
|
||||
while(isspace((int)*remain))
|
||||
remain++;
|
||||
if(strlen(remain) > 0) /* remove \n */
|
||||
remain[strlen(remain)-1] = 0;
|
||||
printf("remain '%s'\n", remain);
|
||||
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) {
|
||||
log_err("line %d: could not parse ADDRESS: %s",
|
||||
*lineno, remain);
|
||||
free(mom);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(readentry) {
|
||||
mom->match = read_entry(in, name, lineno, ttl, or, prev);
|
||||
|
||||
+5
-1
@@ -155,7 +155,9 @@ struct replay_moment {
|
||||
repevt_back_query,
|
||||
/** an error happens to outbound query */
|
||||
repevt_error
|
||||
} evt_type;
|
||||
}
|
||||
/** variable with what is to happen this moment */
|
||||
evt_type;
|
||||
|
||||
/** The sent packet must match this. Incoming events, the data. */
|
||||
struct entry* match;
|
||||
@@ -228,6 +230,8 @@ struct replay_runtime {
|
||||
void (*sig_cb)(int, void*);
|
||||
/** signal handler user arg */
|
||||
void *sig_cb_arg;
|
||||
/** time to exit cleanly */
|
||||
int exit_cleanly;
|
||||
|
||||
/** size of buffers */
|
||||
size_t bufsize;
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ process_nsec3(int argc, char* argv[])
|
||||
/** main program */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
log_init(NULL);
|
||||
log_init(NULL, 0, NULL);
|
||||
if(argc != 6) {
|
||||
usage();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* testcode/streamtcp.c - debug program perform multiple DNS queries on tcp.
|
||||
*
|
||||
* Copyright (c) 2008, 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 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* This program performs multiple DNS queries on a TCP stream.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <signal.h>
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
/** usage information for streamtcp */
|
||||
void usage(char* argv[])
|
||||
{
|
||||
printf("usage: %s [options] name type class ...\n", argv[0]);
|
||||
printf(" sends the name-type-class queries over TCP.\n");
|
||||
printf("-f server what ipaddr@portnr to send the queries to\n");
|
||||
printf("-h this help text\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** open TCP socket to svr */
|
||||
static int
|
||||
open_svr(char* svr)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int fd = -1;
|
||||
/* svr can be ip@port */
|
||||
if(!extstrtoaddr(svr, &addr, &addrlen)) {
|
||||
printf("fatal: bad server specs '%s'\n", svr);
|
||||
exit(1);
|
||||
}
|
||||
fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
|
||||
SOCK_STREAM, 0);
|
||||
if(fd == -1) {
|
||||
perror("socket() error");
|
||||
exit(1);
|
||||
}
|
||||
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
|
||||
perror("connect() error");
|
||||
exit(1);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/** write a query over the TCP fd */
|
||||
static void
|
||||
write_q(int fd, ldns_buffer* buf, int id,
|
||||
char* strname, char* strtype, char* strclass)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
ldns_rdf* rdf;
|
||||
int labs;
|
||||
uint16_t len;
|
||||
/* qname */
|
||||
rdf = ldns_dname_new_frm_str(strname);
|
||||
if(!rdf) {
|
||||
printf("cannot parse query name: '%s'\n", strname);
|
||||
exit(1);
|
||||
}
|
||||
qinfo.qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
|
||||
labs = dname_count_size_labels(qinfo.qname, &qinfo.qname_len);
|
||||
ldns_rdf_deep_free(rdf);
|
||||
if(!qinfo.qname) fatal_exit("out of memory");
|
||||
|
||||
/* qtype and qclass */
|
||||
qinfo.qtype = ldns_get_rr_type_by_name(strtype);
|
||||
qinfo.qclass = ldns_get_rr_class_by_name(strclass);
|
||||
|
||||
/* make query */
|
||||
qinfo_query_encode(buf, &qinfo);
|
||||
ldns_buffer_write_u16_at(buf, 0, (uint16_t)id);
|
||||
ldns_buffer_write_u16_at(buf, 2, BIT_RD);
|
||||
|
||||
/* send it */
|
||||
len = (uint16_t)ldns_buffer_limit(buf);
|
||||
len = htons(len);
|
||||
if(write(fd, &len, sizeof(len)) < (ssize_t)sizeof(len)) {
|
||||
perror("write() len failed");
|
||||
exit(1);
|
||||
}
|
||||
if(write(fd, ldns_buffer_begin(buf), ldns_buffer_limit(buf)) <
|
||||
(ssize_t)ldns_buffer_limit(buf)) {
|
||||
perror("write() data failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(qinfo.qname);
|
||||
}
|
||||
|
||||
/** receive DNS datagram over TCP and print it */
|
||||
static void
|
||||
recv_one(int fd, ldns_buffer* buf)
|
||||
{
|
||||
uint16_t len;
|
||||
ldns_pkt* pkt;
|
||||
ldns_status status;
|
||||
if(read(fd, &len, sizeof(len)) < (ssize_t)sizeof(len)) {
|
||||
perror("read() len failed");
|
||||
exit(1);
|
||||
}
|
||||
len = ntohs(len);
|
||||
ldns_buffer_clear(buf);
|
||||
ldns_buffer_set_limit(buf, len);
|
||||
if(read(fd, ldns_buffer_begin(buf), len) < (ssize_t)len) {
|
||||
perror("read() data failed");
|
||||
exit(1);
|
||||
}
|
||||
printf("\nnext received packet\n");
|
||||
log_buf(0, "data", buf);
|
||||
|
||||
status = ldns_wire2pkt(&pkt, ldns_buffer_begin(buf), len);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
printf("could not parse incoming packet: %s\n",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
log_buf(0, "data was", buf);
|
||||
exit(1);
|
||||
}
|
||||
ldns_pkt_print(stdout, pkt);
|
||||
ldns_pkt_free(pkt);
|
||||
}
|
||||
|
||||
/** send the TCP queries and print answers */
|
||||
static void
|
||||
send_em(char* svr, int num, char** qs)
|
||||
{
|
||||
ldns_buffer* buf = ldns_buffer_new(65553);
|
||||
int fd = open_svr(svr);
|
||||
int i;
|
||||
if(!buf) fatal_exit("out of memory");
|
||||
for(i=0; i<num; i+=3) {
|
||||
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
||||
write_q(fd, buf, i, qs[i], qs[i+1], qs[i+2]);
|
||||
/* print at least one result */
|
||||
recv_one(fd, buf);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
ldns_buffer_free(buf);
|
||||
printf("orderly exit\n");
|
||||
}
|
||||
|
||||
/** SIGPIPE handler */
|
||||
static RETSIGTYPE sigh(int sig)
|
||||
{
|
||||
if(sig == SIGPIPE) {
|
||||
printf("got SIGPIPE, remote connection gone\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Got unhandled signal %d\n", sig);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern int optind;
|
||||
/** getopt global, in case header files fail to declare it. */
|
||||
extern char* optarg;
|
||||
|
||||
/** main program for streamtcp */
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int c;
|
||||
char* svr = "127.0.0.1";
|
||||
|
||||
/* lock debug start (if any) */
|
||||
log_init(0, 0, 0);
|
||||
checklock_start();
|
||||
|
||||
if(signal(SIGPIPE, &sigh) == SIG_ERR) {
|
||||
perror("could not install signal handler");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* command line options */
|
||||
if(argc == 1) {
|
||||
usage(argv);
|
||||
}
|
||||
while( (c=getopt(argc, argv, "f:h")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
svr = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage(argv);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc % 3 != 0) {
|
||||
printf("queries must be multiples of name,type,class\n");
|
||||
return 1;
|
||||
}
|
||||
send_em(svr, argc, argv);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
+4
-4
@@ -43,10 +43,10 @@ function dotest()
|
||||
fi
|
||||
|
||||
cat >makeconf.mak.$$ << EOF
|
||||
configure: configure.ac
|
||||
$AC_CMD
|
||||
touch configure
|
||||
Makefile: configure Makefile.in
|
||||
#configure: configure.ac
|
||||
# $AC_CMD
|
||||
# touch configure
|
||||
Makefile: Makefile.in #configure
|
||||
./configure $CONFIGURE_FLAGS $DISABLE
|
||||
touch Makefile
|
||||
EOF
|
||||
|
||||
@@ -135,6 +135,12 @@ setup_config(FILE* in, char* configfile, int* lineno,
|
||||
if(!cfg) fatal_exit("could not open %s: %s",
|
||||
configfile, strerror(errno));
|
||||
line[MAX_LINE_LEN-1] = 0;
|
||||
/* some basic settings to not pollute the host system */
|
||||
fprintf(cfg, "server: use-syslog: no\n");
|
||||
fprintf(cfg, " directory: \"\"\n");
|
||||
fprintf(cfg, " chroot: \"\"\n");
|
||||
fprintf(cfg, " username: \"\"\n");
|
||||
fprintf(cfg, " pidfile: \"\"\n");
|
||||
while(fgets(line, MAX_LINE_LEN-1, in)) {
|
||||
parse = line;
|
||||
(*lineno)++;
|
||||
@@ -204,7 +210,7 @@ main(int argc, char* argv[])
|
||||
char* init_optarg = optarg;
|
||||
struct replay_scenario* scen = NULL;
|
||||
|
||||
log_init(NULL);
|
||||
log_init(NULL, 0, NULL);
|
||||
log_info("Start of %s testbound program.", PACKAGE_STRING);
|
||||
/* determine commandline options for the daemon */
|
||||
cfgfile[0] = 0;
|
||||
|
||||
+55
-92
@@ -42,36 +42,24 @@
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/log.h"
|
||||
#include "util/storage/lruhash.h"
|
||||
#include "util/storage/slabhash.h" /* for the test structures */
|
||||
|
||||
/* --- test representation --- */
|
||||
/** structure contains test key */
|
||||
struct testkey {
|
||||
/** the key id */
|
||||
int id;
|
||||
/** the entry */
|
||||
struct lruhash_entry entry;
|
||||
};
|
||||
/** structure contains test data */
|
||||
struct testdata {
|
||||
/** data value */
|
||||
int data;
|
||||
};
|
||||
/** use this type for the lruhash test key */
|
||||
typedef struct slabhash_testkey testkey_t;
|
||||
/** use this type for the lruhash test data */
|
||||
typedef struct slabhash_testdata testdata_t;
|
||||
|
||||
/** sizefunc for lruhash */
|
||||
static size_t test_sizefunc(void*, void*);
|
||||
/** comparefunc for lruhash */
|
||||
static int test_compfunc(void*, void*);
|
||||
/** delkey for lruhash */
|
||||
static void test_delkey(void*, void*, int);
|
||||
/** deldata for lruhash */
|
||||
static void test_deldata(void*, void*);
|
||||
/* --- end test representation --- */
|
||||
/** delete key */
|
||||
static void delkey(struct slabhash_testkey* k) {
|
||||
lock_rw_destroy(&k->entry.lock); free(k);}
|
||||
/** delete data */
|
||||
static void deldata(struct slabhash_testdata* d) {free(d);}
|
||||
|
||||
/** hash func, very bad to improve collisions */
|
||||
static hashvalue_t myhash(int id) {return (hashvalue_t)id & 0x0f;}
|
||||
/** allocate new key, fill in hash */
|
||||
static struct testkey* newkey(int id) {
|
||||
struct testkey* k = (struct testkey*)calloc(1, sizeof(struct testkey));
|
||||
static testkey_t* newkey(int id) {
|
||||
testkey_t* k = (testkey_t*)calloc(1, sizeof(testkey_t));
|
||||
if(!k) fatal_exit("out of memory");
|
||||
k->id = id;
|
||||
k->entry.hash = myhash(id);
|
||||
@@ -80,28 +68,23 @@ static struct testkey* newkey(int id) {
|
||||
return k;
|
||||
}
|
||||
/** new data el */
|
||||
static struct testdata* newdata(int val) {
|
||||
struct testdata* d = (struct testdata*)calloc(1,
|
||||
sizeof(struct testdata));
|
||||
static testdata_t* newdata(int val) {
|
||||
testdata_t* d = (testdata_t*)calloc(1,
|
||||
sizeof(testdata_t));
|
||||
if(!d) fatal_exit("out of memory");
|
||||
d->data = val;
|
||||
return d;
|
||||
}
|
||||
/** delete key */
|
||||
static void delkey(struct testkey* k) {
|
||||
lock_rw_destroy(&k->entry.lock); free(k);}
|
||||
/** delete data */
|
||||
static void deldata(struct testdata* d) {free(d);}
|
||||
|
||||
/** test bin_find_entry function and bin_overflow_remove */
|
||||
static void
|
||||
test_bin_find_entry(struct lruhash* table)
|
||||
{
|
||||
struct testkey* k = newkey(12);
|
||||
struct testdata* d = newdata(128);
|
||||
struct testkey* k2 = newkey(12 + 1024);
|
||||
struct testkey* k3 = newkey(14);
|
||||
struct testkey* k4 = newkey(12 + 1024*2);
|
||||
testkey_t* k = newkey(12);
|
||||
testdata_t* d = newdata(128);
|
||||
testkey_t* k2 = newkey(12 + 1024);
|
||||
testkey_t* k3 = newkey(14);
|
||||
testkey_t* k4 = newkey(12 + 1024*2);
|
||||
hashvalue_t h = myhash(12);
|
||||
struct lruhash_bin bin;
|
||||
memset(&bin, 0, sizeof(bin));
|
||||
@@ -178,8 +161,8 @@ test_bin_find_entry(struct lruhash* table)
|
||||
/** test lru_front lru_remove */
|
||||
static void test_lru(struct lruhash* table)
|
||||
{
|
||||
struct testkey* k = newkey(12);
|
||||
struct testkey* k2 = newkey(14);
|
||||
testkey_t* k = newkey(12);
|
||||
testkey_t* k2 = newkey(14);
|
||||
lock_quick_lock(&table->lock);
|
||||
|
||||
unit_assert( table->lru_start == NULL && table->lru_end == NULL);
|
||||
@@ -225,10 +208,10 @@ static void test_lru(struct lruhash* table)
|
||||
static void
|
||||
test_short_table(struct lruhash* table)
|
||||
{
|
||||
struct testkey* k = newkey(12);
|
||||
struct testkey* k2 = newkey(14);
|
||||
struct testdata* d = newdata(128);
|
||||
struct testdata* d2 = newdata(129);
|
||||
testkey_t* k = newkey(12);
|
||||
testkey_t* k2 = newkey(14);
|
||||
testdata_t* d = newdata(128);
|
||||
testdata_t* d2 = newdata(129);
|
||||
|
||||
k->entry.data = d;
|
||||
k2->entry.data = d2;
|
||||
@@ -249,11 +232,11 @@ test_short_table(struct lruhash* table)
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testadd(struct lruhash* table, struct testdata* ref[])
|
||||
testadd(struct lruhash* table, testdata_t* ref[])
|
||||
{
|
||||
int numtoadd = random() % HASHTESTMAX;
|
||||
struct testdata* data = newdata(numtoadd);
|
||||
struct testkey* key = newkey(numtoadd);
|
||||
testdata_t* data = newdata(numtoadd);
|
||||
testkey_t* key = newkey(numtoadd);
|
||||
key->entry.data = data;
|
||||
lruhash_insert(table, myhash(numtoadd), &key->entry, data, NULL);
|
||||
ref[numtoadd] = data;
|
||||
@@ -261,10 +244,10 @@ testadd(struct lruhash* table, struct testdata* ref[])
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testremove(struct lruhash* table, struct testdata* ref[])
|
||||
testremove(struct lruhash* table, testdata_t* ref[])
|
||||
{
|
||||
int num = random() % HASHTESTMAX;
|
||||
struct testkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
lruhash_remove(table, myhash(num), key);
|
||||
ref[num] = NULL;
|
||||
delkey(key);
|
||||
@@ -272,12 +255,12 @@ testremove(struct lruhash* table, struct testdata* ref[])
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testlookup(struct lruhash* table, struct testdata* ref[])
|
||||
testlookup(struct lruhash* table, testdata_t* ref[])
|
||||
{
|
||||
int num = random() % HASHTESTMAX;
|
||||
struct testkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
struct lruhash_entry* en = lruhash_lookup(table, myhash(num), key, 0);
|
||||
struct testdata* data = en? (struct testdata*)en->data : NULL;
|
||||
testdata_t* data = en? (testdata_t*)en->data : NULL;
|
||||
if(en) {
|
||||
unit_assert(en->key);
|
||||
unit_assert(en->data);
|
||||
@@ -321,17 +304,17 @@ check_table(struct lruhash* table)
|
||||
|
||||
/* this assertion is specific to the unit test */
|
||||
unit_assert( table->space_used ==
|
||||
table->num * test_sizefunc(NULL, NULL) );
|
||||
table->num * test_slabhash_sizefunc(NULL, NULL) );
|
||||
lock_quick_unlock(&table->lock);
|
||||
}
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testadd_unlim(struct lruhash* table, struct testdata** ref)
|
||||
testadd_unlim(struct lruhash* table, testdata_t** ref)
|
||||
{
|
||||
int numtoadd = random() % (HASHTESTMAX * 10);
|
||||
struct testdata* data = newdata(numtoadd);
|
||||
struct testkey* key = newkey(numtoadd);
|
||||
testdata_t* data = newdata(numtoadd);
|
||||
testkey_t* key = newkey(numtoadd);
|
||||
key->entry.data = data;
|
||||
lruhash_insert(table, myhash(numtoadd), &key->entry, data, NULL);
|
||||
if(ref)
|
||||
@@ -340,10 +323,10 @@ testadd_unlim(struct lruhash* table, struct testdata** ref)
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testremove_unlim(struct lruhash* table, struct testdata** ref)
|
||||
testremove_unlim(struct lruhash* table, testdata_t** ref)
|
||||
{
|
||||
int num = random() % (HASHTESTMAX*10);
|
||||
struct testkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
lruhash_remove(table, myhash(num), key);
|
||||
if(ref)
|
||||
ref[num] = NULL;
|
||||
@@ -352,12 +335,12 @@ testremove_unlim(struct lruhash* table, struct testdata** ref)
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testlookup_unlim(struct lruhash* table, struct testdata** ref)
|
||||
testlookup_unlim(struct lruhash* table, testdata_t** ref)
|
||||
{
|
||||
int num = random() % (HASHTESTMAX*10);
|
||||
struct testkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
struct lruhash_entry* en = lruhash_lookup(table, myhash(num), key, 0);
|
||||
struct testdata* data = en? (struct testdata*)en->data : NULL;
|
||||
testdata_t* data = en? (testdata_t*)en->data : NULL;
|
||||
if(en) {
|
||||
unit_assert(en->key);
|
||||
unit_assert(en->data);
|
||||
@@ -377,17 +360,22 @@ static void
|
||||
test_long_table(struct lruhash* table)
|
||||
{
|
||||
/* assuming it all fits in the hastable, this check will work */
|
||||
struct testdata* ref[HASHTESTMAX * 100];
|
||||
testdata_t* ref[HASHTESTMAX * 100];
|
||||
size_t i;
|
||||
memset(ref, 0, sizeof(ref));
|
||||
/* test assumption */
|
||||
if(0) log_info(" size %d x %d < %d", (int)test_sizefunc(NULL, NULL),
|
||||
if(0) log_info(" size %d x %d < %d", (int)test_slabhash_sizefunc(NULL, NULL),
|
||||
(int)HASHTESTMAX, (int)table->space_max);
|
||||
unit_assert( test_sizefunc(NULL, NULL)*HASHTESTMAX < table->space_max);
|
||||
unit_assert( test_slabhash_sizefunc(NULL, NULL)*HASHTESTMAX < table->space_max);
|
||||
if(0) lruhash_status(table, "unit test", 1);
|
||||
srandom(48);
|
||||
for(i=0; i<1000; i++) {
|
||||
/* what to do? */
|
||||
if(i == 500) {
|
||||
lruhash_clear(table);
|
||||
memset(ref, 0, sizeof(ref));
|
||||
continue;
|
||||
}
|
||||
switch(random() % 4) {
|
||||
case 0:
|
||||
case 3:
|
||||
@@ -496,41 +484,16 @@ void lruhash_test()
|
||||
struct lruhash* table ;
|
||||
printf("lruhash test\n");
|
||||
table = lruhash_create(2, 4096,
|
||||
test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
|
||||
test_slabhash_sizefunc, test_slabhash_compfunc,
|
||||
test_slabhash_delkey, test_slabhash_deldata, NULL);
|
||||
test_bin_find_entry(table);
|
||||
test_lru(table);
|
||||
test_short_table(table);
|
||||
test_long_table(table);
|
||||
lruhash_delete(table);
|
||||
table = lruhash_create(2, 4096,
|
||||
test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
|
||||
test_slabhash_sizefunc, test_slabhash_compfunc,
|
||||
test_slabhash_delkey, test_slabhash_deldata, NULL);
|
||||
test_threaded_table(table);
|
||||
lruhash_delete(table);
|
||||
}
|
||||
|
||||
static size_t test_sizefunc(void* ATTR_UNUSED(key), void* ATTR_UNUSED(data))
|
||||
{
|
||||
return sizeof(struct testkey) + sizeof(struct testdata);
|
||||
}
|
||||
|
||||
static int test_compfunc(void* key1, void* key2)
|
||||
{
|
||||
struct testkey* k1 = (struct testkey*)key1;
|
||||
struct testkey* k2 = (struct testkey*)key2;
|
||||
if(k1->id == k2->id)
|
||||
return 0;
|
||||
if(k1->id > k2->id)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void test_delkey(void* key, void* ATTR_UNUSED(arg), int l)
|
||||
{
|
||||
if(l) { lock_rw_unlock(&((struct testkey*)key)->entry.lock); }
|
||||
delkey((struct testkey*)key);
|
||||
}
|
||||
|
||||
static void test_deldata(void* data, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
deldata((struct testdata*)data);
|
||||
}
|
||||
|
||||
+195
-11
@@ -89,6 +89,42 @@ alloc_test() {
|
||||
static void
|
||||
net_test()
|
||||
{
|
||||
char* t4[] = {"\000\000\000\000",
|
||||
"\200\000\000\000",
|
||||
"\300\000\000\000",
|
||||
"\340\000\000\000",
|
||||
"\360\000\000\000",
|
||||
"\370\000\000\000",
|
||||
"\374\000\000\000",
|
||||
"\376\000\000\000",
|
||||
"\377\000\000\000",
|
||||
"\377\200\000\000",
|
||||
"\377\300\000\000",
|
||||
"\377\340\000\000",
|
||||
"\377\360\000\000",
|
||||
"\377\370\000\000",
|
||||
"\377\374\000\000",
|
||||
"\377\376\000\000",
|
||||
"\377\377\000\000",
|
||||
"\377\377\200\000",
|
||||
"\377\377\300\000",
|
||||
"\377\377\340\000",
|
||||
"\377\377\360\000",
|
||||
"\377\377\370\000",
|
||||
"\377\377\374\000",
|
||||
"\377\377\376\000",
|
||||
"\377\377\377\000",
|
||||
"\377\377\377\200",
|
||||
"\377\377\377\300",
|
||||
"\377\377\377\340",
|
||||
"\377\377\377\360",
|
||||
"\377\377\377\370",
|
||||
"\377\377\377\374",
|
||||
"\377\377\377\376",
|
||||
"\377\377\377\377",
|
||||
"\377\377\377\377",
|
||||
"\377\377\377\377",
|
||||
};
|
||||
unit_assert( str_is_ip6("::") );
|
||||
unit_assert( str_is_ip6("::1") );
|
||||
unit_assert( str_is_ip6("2001:7b8:206:1:240:f4ff:fe37:8810") );
|
||||
@@ -117,6 +153,129 @@ net_test()
|
||||
unit_assert( !is_pow2(23) );
|
||||
unit_assert( !is_pow2(257) );
|
||||
unit_assert( !is_pow2(259) );
|
||||
|
||||
/* test addr_mask */
|
||||
if(1) {
|
||||
struct sockaddr_in a4;
|
||||
struct sockaddr_in6 a6;
|
||||
socklen_t l4 = (socklen_t)sizeof(a4);
|
||||
socklen_t l6 = (socklen_t)sizeof(a6);
|
||||
int i;
|
||||
a4.sin_family = AF_INET;
|
||||
a6.sin6_family = AF_INET6;
|
||||
for(i=0; i<35; i++) {
|
||||
/* address 255.255.255.255 */
|
||||
memcpy(&a4.sin_addr, "\377\377\377\377", 4);
|
||||
addr_mask((struct sockaddr_storage*)&a4, l4, i);
|
||||
unit_assert(memcmp(&a4.sin_addr, t4[i], 4) == 0);
|
||||
}
|
||||
memcpy(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16);
|
||||
addr_mask((struct sockaddr_storage*)&a6, l6, 128);
|
||||
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16) == 0);
|
||||
addr_mask((struct sockaddr_storage*)&a6, l6, 122);
|
||||
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\300", 16) == 0);
|
||||
addr_mask((struct sockaddr_storage*)&a6, l6, 120);
|
||||
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000", 16) == 0);
|
||||
addr_mask((struct sockaddr_storage*)&a6, l6, 64);
|
||||
unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\000\000\000\000\000\000\000\000", 16) == 0);
|
||||
addr_mask((struct sockaddr_storage*)&a6, l6, 0);
|
||||
unit_assert(memcmp(&a6.sin6_addr, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16) == 0);
|
||||
}
|
||||
|
||||
/* test addr_in_common */
|
||||
if(1) {
|
||||
struct sockaddr_in a4, b4;
|
||||
struct sockaddr_in6 a6, b6;
|
||||
socklen_t l4 = (socklen_t)sizeof(a4);
|
||||
socklen_t l6 = (socklen_t)sizeof(a6);
|
||||
int i;
|
||||
a4.sin_family = AF_INET;
|
||||
b4.sin_family = AF_INET;
|
||||
a6.sin6_family = AF_INET6;
|
||||
b6.sin6_family = AF_INET6;
|
||||
memcpy(&a4.sin_addr, "abcd", 4);
|
||||
memcpy(&b4.sin_addr, "abcd", 4);
|
||||
unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 32,
|
||||
(struct sockaddr_storage*)&b4, 32, l4) == 32);
|
||||
unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 34,
|
||||
(struct sockaddr_storage*)&b4, 32, l4) == 32);
|
||||
for(i=0; i<=32; i++) {
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a4, 32,
|
||||
(struct sockaddr_storage*)&b4, i, l4) == i);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a4, i,
|
||||
(struct sockaddr_storage*)&b4, 32, l4) == i);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a4, i,
|
||||
(struct sockaddr_storage*)&b4, i, l4) == i);
|
||||
}
|
||||
for(i=0; i<=32; i++) {
|
||||
memcpy(&a4.sin_addr, "\377\377\377\377", 4);
|
||||
memcpy(&b4.sin_addr, t4[i], 4);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a4, 32,
|
||||
(struct sockaddr_storage*)&b4, 32, l4) == i);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&b4, 32,
|
||||
(struct sockaddr_storage*)&a4, 32, l4) == i);
|
||||
}
|
||||
memcpy(&a6.sin6_addr, "abcdefghabcdefgh", 16);
|
||||
memcpy(&b6.sin6_addr, "abcdefghabcdefgh", 16);
|
||||
unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 128,
|
||||
(struct sockaddr_storage*)&b6, 128, l6) == 128);
|
||||
unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 129,
|
||||
(struct sockaddr_storage*)&b6, 128, l6) == 128);
|
||||
for(i=0; i<=128; i++) {
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a6, 128,
|
||||
(struct sockaddr_storage*)&b6, i, l6) == i);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a6, i,
|
||||
(struct sockaddr_storage*)&b6, 128, l6) == i);
|
||||
unit_assert(addr_in_common(
|
||||
(struct sockaddr_storage*)&a6, i,
|
||||
(struct sockaddr_storage*)&b6, i, l6) == i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "util/config_file.h"
|
||||
/** test config_file: cfg_parse_memsize */
|
||||
static void
|
||||
config_memsize_test()
|
||||
{
|
||||
size_t v = 0;
|
||||
if(0) {
|
||||
/* these emit errors */
|
||||
unit_assert( cfg_parse_memsize("", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("bla", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("nop", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("n0b", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("gb", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("b", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("kb", &v) == 0);
|
||||
unit_assert( cfg_parse_memsize("kk kb", &v) == 0);
|
||||
}
|
||||
unit_assert( cfg_parse_memsize("0", &v) && v==0);
|
||||
unit_assert( cfg_parse_memsize("1", &v) && v==1);
|
||||
unit_assert( cfg_parse_memsize("10", &v) && v==10);
|
||||
unit_assert( cfg_parse_memsize("10b", &v) && v==10);
|
||||
unit_assert( cfg_parse_memsize("5b", &v) && v==5);
|
||||
unit_assert( cfg_parse_memsize("1024", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("1k", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("1K", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("1Kb", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("1kb", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("1 kb", &v) && v==1024);
|
||||
unit_assert( cfg_parse_memsize("10 kb", &v) && v==10240);
|
||||
unit_assert( cfg_parse_memsize("2k", &v) && v==2048);
|
||||
unit_assert( cfg_parse_memsize("2m", &v) && v==2048*1024);
|
||||
unit_assert( cfg_parse_memsize("3M", &v) && v==3072*1024);
|
||||
unit_assert( cfg_parse_memsize("40m", &v) && v==40960*1024);
|
||||
unit_assert( cfg_parse_memsize("1G", &v) && v==1024*1024*1024);
|
||||
unit_assert( cfg_parse_memsize("1 Gb", &v) && v==1024*1024*1024);
|
||||
unit_assert( cfg_parse_memsize("0 Gb", &v) && v==0*1024*1024);
|
||||
}
|
||||
|
||||
#include "util/rtt.h"
|
||||
@@ -124,17 +283,18 @@ net_test()
|
||||
static void
|
||||
rtt_test()
|
||||
{
|
||||
int init = 376;
|
||||
int i;
|
||||
struct rtt_info r;
|
||||
rtt_init(&r);
|
||||
/* initial value sensible */
|
||||
unit_assert( rtt_timeout(&r) == 3000 );
|
||||
unit_assert( rtt_timeout(&r) == init );
|
||||
rtt_lost(&r);
|
||||
unit_assert( rtt_timeout(&r) == 6000 );
|
||||
unit_assert( rtt_timeout(&r) == init*2 );
|
||||
rtt_lost(&r);
|
||||
unit_assert( rtt_timeout(&r) == 12000 );
|
||||
unit_assert( rtt_timeout(&r) == init*4 );
|
||||
rtt_update(&r, 4000);
|
||||
unit_assert( rtt_timeout(&r) >= 5000 );
|
||||
unit_assert( rtt_timeout(&r) >= 2000 );
|
||||
rtt_lost(&r);
|
||||
for(i=0; i<100; i++) {
|
||||
rtt_lost(&r);
|
||||
@@ -158,36 +318,37 @@ infra_test()
|
||||
int vs, to;
|
||||
struct infra_host_key* k;
|
||||
struct infra_host_data* d;
|
||||
int init = 376;
|
||||
|
||||
slab = infra_create(cfg);
|
||||
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), now, &vs, &to) );
|
||||
unit_assert( vs == 0 && to == 3000 );
|
||||
unit_assert( vs == 0 && to == init );
|
||||
|
||||
unit_assert( infra_rtt_update(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), -1, now) );
|
||||
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), now, &vs, &to) );
|
||||
unit_assert( vs == 0 && to == 6000 );
|
||||
unit_assert( vs == 0 && to == init*2 );
|
||||
|
||||
unit_assert( infra_edns_update(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), -1, now) );
|
||||
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), now, &vs, &to) );
|
||||
unit_assert( vs == -1 && to == 6000 );
|
||||
unit_assert( vs == -1 && to == init*2 );
|
||||
|
||||
now += cfg->host_ttl + 10;
|
||||
unit_assert( infra_host(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), now, &vs, &to) );
|
||||
unit_assert( vs == 0 && to == 3000 );
|
||||
unit_assert( vs == 0 && to == init );
|
||||
|
||||
unit_assert( infra_set_lame(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), zone, zonelen, now) );
|
||||
(socklen_t)sizeof(int), zone, zonelen, now, 0) );
|
||||
unit_assert( (d=infra_lookup_host(slab, (struct sockaddr_storage*)&one,
|
||||
(socklen_t)sizeof(int), 0, now, &k)) );
|
||||
unit_assert( d->ttl == now+cfg->host_ttl );
|
||||
unit_assert( d->edns_version == 0 );
|
||||
unit_assert( infra_lookup_lame(d, zone, zonelen, now) );
|
||||
unit_assert( infra_lookup_lame(d, zone, zonelen, now)==1 );
|
||||
unit_assert( !infra_lookup_lame(d, zone, zonelen,
|
||||
now+cfg->lame_ttl+10) );
|
||||
unit_assert( !infra_lookup_lame(d, (uint8_t*)"\000", 1, now) );
|
||||
@@ -197,6 +358,27 @@ infra_test()
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
#include "util/random.h"
|
||||
/** test randomness */
|
||||
static void
|
||||
rnd_test()
|
||||
{
|
||||
struct ub_randstate* r;
|
||||
int num = 100, i;
|
||||
long int a[100];
|
||||
unit_assert( (r = ub_initstate((unsigned)time(NULL), NULL)) );
|
||||
for(i=0; i<num; i++) {
|
||||
a[i] = ub_random(r);
|
||||
unit_assert(a[i] >= 0);
|
||||
unit_assert((size_t)a[i] <= (size_t)RAND_MAX);
|
||||
if(i > 5)
|
||||
unit_assert(a[i] != a[i-1] || a[i] != a[i-2] ||
|
||||
a[i] != a[i-3] || a[i] != a[i-4] ||
|
||||
a[i] != a[i-5] || a[i] != a[i-6]);
|
||||
}
|
||||
ub_randfree(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main unit test program. Setup, teardown and report errors.
|
||||
* @param argc: arg count.
|
||||
@@ -205,7 +387,7 @@ infra_test()
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
log_init(NULL);
|
||||
log_init(NULL, 0, NULL);
|
||||
if(argc != 1) {
|
||||
printf("usage: %s\n", argv[0]);
|
||||
printf("\tperforms unit tests.\n");
|
||||
@@ -213,8 +395,10 @@ main(int argc, char* argv[])
|
||||
}
|
||||
printf("Start of %s unit test.\n", PACKAGE_STRING);
|
||||
checklock_start();
|
||||
rnd_test();
|
||||
verify_test();
|
||||
net_test();
|
||||
config_memsize_test();
|
||||
dname_test();
|
||||
anchors_test();
|
||||
rtt_test();
|
||||
|
||||
@@ -45,7 +45,11 @@
|
||||
/** number of tests done */
|
||||
extern int testcount;
|
||||
/** test bool x, exits on failure, increases testcount. */
|
||||
#ifdef DEBUG_UNBOUND
|
||||
#define unit_assert(x) do {testcount++; log_assert(x);} while(0)
|
||||
#else
|
||||
#define unit_assert(x) do {testcount++; if(!(x)) { fprintf(stderr, "assertion failure %s:%d\n", __FILE__, __LINE__); exit(1);}} while(0)
|
||||
#endif
|
||||
|
||||
/** unit test lruhashtable implementation */
|
||||
void lruhash_test();
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/net_help.h"
|
||||
#include "testcode/readhex.h"
|
||||
|
||||
@@ -206,10 +206,8 @@ test_buffers(ldns_buffer* pkt, ldns_buffer* out)
|
||||
s1 = ldns_buffer2pkt_wire(&p1, pkt);
|
||||
s2 = ldns_buffer2pkt_wire(&p2, out);
|
||||
if(vbmp) {
|
||||
log_hex("orig in hex", ldns_buffer_begin(pkt),
|
||||
ldns_buffer_limit(pkt));
|
||||
log_hex("unbound out in hex", ldns_buffer_begin(out),
|
||||
ldns_buffer_limit(out));
|
||||
log_buf(0, "orig in hex", pkt);
|
||||
log_buf(0, "unbound out in hex", out);
|
||||
printf("\npacket from unbound (%d):\n",
|
||||
(int)ldns_buffer_limit(out));
|
||||
ldns_pkt_print(stdout, p2);
|
||||
@@ -260,7 +258,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint32_t timenow = 0;
|
||||
region_type *region = region_create(malloc, free);
|
||||
struct regional* region = regional_create();
|
||||
struct edns_data edns;
|
||||
|
||||
hex_to_buf(pkt, hex);
|
||||
@@ -309,7 +307,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
|
||||
query_info_clear(&qi);
|
||||
reply_info_parsedelete(rep, alloc);
|
||||
region_destroy(region);
|
||||
regional_destroy(region);
|
||||
}
|
||||
|
||||
/** simple test of parsing */
|
||||
|
||||
+43
-83
@@ -43,29 +43,14 @@
|
||||
#include "util/log.h"
|
||||
#include "util/storage/slabhash.h"
|
||||
|
||||
/* --- test representation --- */
|
||||
/** structure contains test key */
|
||||
struct slabtestkey {
|
||||
/** the key id */
|
||||
int id;
|
||||
/** the entry */
|
||||
struct lruhash_entry entry;
|
||||
};
|
||||
/** structure contains test data */
|
||||
struct slabtestdata {
|
||||
/** data value */
|
||||
int data;
|
||||
};
|
||||
/** use this type for the slabhash test key */
|
||||
typedef struct slabhash_testkey testkey_t;
|
||||
/** use this type for the slabhash test data */
|
||||
typedef struct slabhash_testdata testdata_t;
|
||||
|
||||
/** sizefunc for lruhash */
|
||||
static size_t test_sizefunc(void*, void*);
|
||||
/** comparefunc for lruhash */
|
||||
static int test_compfunc(void*, void*);
|
||||
/** delkey for lruhash */
|
||||
static void test_delkey(void*, void*, int);
|
||||
/** deldata for lruhash */
|
||||
static void test_deldata(void*, void*);
|
||||
/* --- end test representation --- */
|
||||
/** delete key */
|
||||
static void delkey(struct slabhash_testkey* k) {
|
||||
lock_rw_destroy(&k->entry.lock); free(k);}
|
||||
|
||||
/** hash func, very bad to improve collisions, both high and low bits */
|
||||
static hashvalue_t myhash(int id) {
|
||||
@@ -75,8 +60,8 @@ static hashvalue_t myhash(int id) {
|
||||
}
|
||||
|
||||
/** allocate new key, fill in hash */
|
||||
static struct slabtestkey* newkey(int id) {
|
||||
struct slabtestkey* k = (struct slabtestkey*)calloc(1, sizeof(struct slabtestkey));
|
||||
static testkey_t* newkey(int id) {
|
||||
testkey_t* k = (testkey_t*)calloc(1, sizeof(testkey_t));
|
||||
if(!k) fatal_exit("out of memory");
|
||||
k->id = id;
|
||||
k->entry.hash = myhash(id);
|
||||
@@ -85,27 +70,22 @@ static struct slabtestkey* newkey(int id) {
|
||||
return k;
|
||||
}
|
||||
/** new data el */
|
||||
static struct slabtestdata* newdata(int val) {
|
||||
struct slabtestdata* d = (struct slabtestdata*)calloc(1,
|
||||
sizeof(struct slabtestdata));
|
||||
static testdata_t* newdata(int val) {
|
||||
testdata_t* d = (testdata_t*)calloc(1,
|
||||
sizeof(testdata_t));
|
||||
if(!d) fatal_exit("out of memory");
|
||||
d->data = val;
|
||||
return d;
|
||||
}
|
||||
/** delete key */
|
||||
static void delkey(struct slabtestkey* k) {
|
||||
lock_rw_destroy(&k->entry.lock); free(k);}
|
||||
/** delete data */
|
||||
static void deldata(struct slabtestdata* d) {free(d);}
|
||||
|
||||
/** test hashtable using short sequence */
|
||||
static void
|
||||
test_short_table(struct slabhash* table)
|
||||
{
|
||||
struct slabtestkey* k = newkey(12);
|
||||
struct slabtestkey* k2 = newkey(14);
|
||||
struct slabtestdata* d = newdata(128);
|
||||
struct slabtestdata* d2 = newdata(129);
|
||||
testkey_t* k = newkey(12);
|
||||
testkey_t* k2 = newkey(14);
|
||||
testdata_t* d = newdata(128);
|
||||
testdata_t* d2 = newdata(129);
|
||||
|
||||
k->entry.data = d;
|
||||
k2->entry.data = d2;
|
||||
@@ -126,11 +106,11 @@ test_short_table(struct slabhash* table)
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testadd(struct slabhash* table, struct slabtestdata* ref[])
|
||||
testadd(struct slabhash* table, testdata_t* ref[])
|
||||
{
|
||||
int numtoadd = random() % HASHTESTMAX;
|
||||
struct slabtestdata* data = newdata(numtoadd);
|
||||
struct slabtestkey* key = newkey(numtoadd);
|
||||
testdata_t* data = newdata(numtoadd);
|
||||
testkey_t* key = newkey(numtoadd);
|
||||
key->entry.data = data;
|
||||
slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL);
|
||||
ref[numtoadd] = data;
|
||||
@@ -138,10 +118,10 @@ testadd(struct slabhash* table, struct slabtestdata* ref[])
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testremove(struct slabhash* table, struct slabtestdata* ref[])
|
||||
testremove(struct slabhash* table, testdata_t* ref[])
|
||||
{
|
||||
int num = random() % HASHTESTMAX;
|
||||
struct slabtestkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
slabhash_remove(table, myhash(num), key);
|
||||
ref[num] = NULL;
|
||||
delkey(key);
|
||||
@@ -149,12 +129,12 @@ testremove(struct slabhash* table, struct slabtestdata* ref[])
|
||||
|
||||
/** test adding a random element */
|
||||
static void
|
||||
testlookup(struct slabhash* table, struct slabtestdata* ref[])
|
||||
testlookup(struct slabhash* table, testdata_t* ref[])
|
||||
{
|
||||
int num = random() % HASHTESTMAX;
|
||||
struct slabtestkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0);
|
||||
struct slabtestdata* data = en? (struct slabtestdata*)en->data : NULL;
|
||||
testdata_t* data = en? (testdata_t*)en->data : NULL;
|
||||
if(en) {
|
||||
unit_assert(en->key);
|
||||
unit_assert(en->data);
|
||||
@@ -198,7 +178,7 @@ check_lru_table(struct lruhash* table)
|
||||
|
||||
/* this assertion is specific to the unit test */
|
||||
unit_assert( table->space_used ==
|
||||
table->num * test_sizefunc(NULL, NULL) );
|
||||
table->num * test_slabhash_sizefunc(NULL, NULL) );
|
||||
lock_quick_unlock(&table->lock);
|
||||
}
|
||||
|
||||
@@ -213,11 +193,11 @@ check_table(struct slabhash* table)
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testadd_unlim(struct slabhash* table, struct slabtestdata** ref)
|
||||
testadd_unlim(struct slabhash* table, testdata_t** ref)
|
||||
{
|
||||
int numtoadd = random() % (HASHTESTMAX * 10);
|
||||
struct slabtestdata* data = newdata(numtoadd);
|
||||
struct slabtestkey* key = newkey(numtoadd);
|
||||
testdata_t* data = newdata(numtoadd);
|
||||
testkey_t* key = newkey(numtoadd);
|
||||
key->entry.data = data;
|
||||
slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL);
|
||||
if(ref)
|
||||
@@ -226,10 +206,10 @@ testadd_unlim(struct slabhash* table, struct slabtestdata** ref)
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testremove_unlim(struct slabhash* table, struct slabtestdata** ref)
|
||||
testremove_unlim(struct slabhash* table, testdata_t** ref)
|
||||
{
|
||||
int num = random() % (HASHTESTMAX*10);
|
||||
struct slabtestkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
slabhash_remove(table, myhash(num), key);
|
||||
if(ref)
|
||||
ref[num] = NULL;
|
||||
@@ -238,12 +218,12 @@ testremove_unlim(struct slabhash* table, struct slabtestdata** ref)
|
||||
|
||||
/** test adding a random element (unlimited range) */
|
||||
static void
|
||||
testlookup_unlim(struct slabhash* table, struct slabtestdata** ref)
|
||||
testlookup_unlim(struct slabhash* table, testdata_t** ref)
|
||||
{
|
||||
int num = random() % (HASHTESTMAX*10);
|
||||
struct slabtestkey* key = newkey(num);
|
||||
testkey_t* key = newkey(num);
|
||||
struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0);
|
||||
struct slabtestdata* data = en? (struct slabtestdata*)en->data : NULL;
|
||||
testdata_t* data = en? (testdata_t*)en->data : NULL;
|
||||
if(en) {
|
||||
unit_assert(en->key);
|
||||
unit_assert(en->data);
|
||||
@@ -263,7 +243,7 @@ static void
|
||||
test_long_table(struct slabhash* table)
|
||||
{
|
||||
/* assuming it all fits in the hastable, this check will work */
|
||||
struct slabtestdata* ref[HASHTESTMAX * 100];
|
||||
testdata_t* ref[HASHTESTMAX * 100];
|
||||
size_t i;
|
||||
memset(ref, 0, sizeof(ref));
|
||||
/* test assumption */
|
||||
@@ -271,6 +251,11 @@ test_long_table(struct slabhash* table)
|
||||
srandom(48);
|
||||
for(i=0; i<1000; i++) {
|
||||
/* what to do? */
|
||||
if(i == 500) {
|
||||
slabhash_clear(table);
|
||||
memset(ref, 0, sizeof(ref));
|
||||
continue;
|
||||
}
|
||||
switch(random() % 4) {
|
||||
case 0:
|
||||
case 3:
|
||||
@@ -378,39 +363,14 @@ void slabhash_test()
|
||||
struct slabhash* table;
|
||||
printf("slabhash test\n");
|
||||
table = slabhash_create(4, 2, 5200,
|
||||
test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
|
||||
test_slabhash_sizefunc, test_slabhash_compfunc,
|
||||
test_slabhash_delkey, test_slabhash_deldata, NULL);
|
||||
test_short_table(table);
|
||||
test_long_table(table);
|
||||
slabhash_delete(table);
|
||||
table = slabhash_create(4, 2, 5200,
|
||||
test_sizefunc, test_compfunc, test_delkey, test_deldata, NULL);
|
||||
test_slabhash_sizefunc, test_slabhash_compfunc,
|
||||
test_slabhash_delkey, test_slabhash_deldata, NULL);
|
||||
test_threaded_table(table);
|
||||
slabhash_delete(table);
|
||||
}
|
||||
|
||||
static size_t test_sizefunc(void* ATTR_UNUSED(key), void* ATTR_UNUSED(data))
|
||||
{
|
||||
return sizeof(struct slabtestkey) + sizeof(struct slabtestdata);
|
||||
}
|
||||
|
||||
static int test_compfunc(void* key1, void* key2)
|
||||
{
|
||||
struct slabtestkey* k1 = (struct slabtestkey*)key1;
|
||||
struct slabtestkey* k2 = (struct slabtestkey*)key2;
|
||||
if(k1->id == k2->id)
|
||||
return 0;
|
||||
if(k1->id > k2->id)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void test_delkey(void* key, void* ATTR_UNUSED(arg), int l)
|
||||
{
|
||||
if(l) { lock_rw_unlock(&((struct slabtestkey*)key)->entry.lock); }
|
||||
delkey((struct slabtestkey*)key);
|
||||
}
|
||||
|
||||
static void test_deldata(void* data, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
deldata((struct slabtestdata*)data);
|
||||
}
|
||||
|
||||
+25
-23
@@ -49,7 +49,7 @@
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/rbtree.h"
|
||||
#include "util/net_help.h"
|
||||
@@ -86,8 +86,8 @@ entry_to_buf(struct entry* e, ldns_buffer* pkt)
|
||||
|
||||
/** entry to reply info conversion */
|
||||
static void
|
||||
entry_to_repinfo(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
region, ldns_buffer* pkt, struct query_info* qi,
|
||||
entry_to_repinfo(struct entry* e, struct alloc_cache* alloc,
|
||||
struct regional* region, ldns_buffer* pkt, struct query_info* qi,
|
||||
struct reply_info** rep)
|
||||
{
|
||||
int ret;
|
||||
@@ -109,8 +109,8 @@ entry_to_repinfo(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
|
||||
/** extract DNSKEY rrset from answer and convert it */
|
||||
static struct ub_packed_rrset_key*
|
||||
extract_keys(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
region, ldns_buffer* pkt)
|
||||
extract_keys(struct entry* e, struct alloc_cache* alloc,
|
||||
struct regional* region, ldns_buffer* pkt)
|
||||
{
|
||||
struct ub_packed_rrset_key* dnskey = NULL;
|
||||
struct query_info qinfo;
|
||||
@@ -150,7 +150,7 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
|
||||
{
|
||||
enum sec_status sec;
|
||||
if(vsig) {
|
||||
log_nametypeclass(VERB_DETAIL, "verify of rrset",
|
||||
log_nametypeclass(VERB_QUERY, "verify of rrset",
|
||||
rrset->rk.dname, ntohs(rrset->rk.type),
|
||||
ntohs(rrset->rk.rrset_class));
|
||||
}
|
||||
@@ -167,15 +167,16 @@ verifytest_rrset(struct module_env* env, struct val_env* ve,
|
||||
|
||||
/** verify and test an entry - every rr in the message */
|
||||
static void
|
||||
verifytest_entry(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
region, ldns_buffer* pkt, struct ub_packed_rrset_key* dnskey,
|
||||
struct module_env* env, struct val_env* ve)
|
||||
verifytest_entry(struct entry* e, struct alloc_cache* alloc,
|
||||
struct regional* region, ldns_buffer* pkt,
|
||||
struct ub_packed_rrset_key* dnskey, struct module_env* env,
|
||||
struct val_env* ve)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
struct reply_info* rep = NULL;
|
||||
size_t i;
|
||||
|
||||
region_free_all(region);
|
||||
regional_free_all(region);
|
||||
if(vsig) {
|
||||
printf("verifying pkt:\n");
|
||||
ldns_pkt_print(stdout, e->reply_list->reply);
|
||||
@@ -205,15 +206,15 @@ find_rrset_type(struct reply_info* rep, uint16_t type)
|
||||
|
||||
/** DS sig test an entry - get DNSKEY and DS in entry and verify */
|
||||
static void
|
||||
dstest_entry(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
region, ldns_buffer* pkt, struct module_env* env)
|
||||
dstest_entry(struct entry* e, struct alloc_cache* alloc,
|
||||
struct regional* region, ldns_buffer* pkt, struct module_env* env)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
struct reply_info* rep = NULL;
|
||||
struct ub_packed_rrset_key* ds, *dnskey;
|
||||
int ret;
|
||||
|
||||
region_free_all(region);
|
||||
regional_free_all(region);
|
||||
if(vsig) {
|
||||
printf("verifying DS-DNSKEY match:\n");
|
||||
ldns_pkt_print(stdout, e->reply_list->reply);
|
||||
@@ -236,7 +237,7 @@ dstest_entry(struct entry* e, struct alloc_cache* alloc, struct region*
|
||||
printf("result(no)= %s\n", ret?"yes":"no");
|
||||
}
|
||||
unit_assert(!ret);
|
||||
verbose(VERB_DETAIL, "DS fail: OK; matched unit test");
|
||||
verbose(VERB_QUERY, "DS fail: OK; matched unit test");
|
||||
} else {
|
||||
fatal_exit("Bad qname in DS unit test, yes or no");
|
||||
}
|
||||
@@ -255,7 +256,7 @@ verifytest_file(const char* fname, const char* at_date)
|
||||
* The answer rrset is the keyset that will be used for verification
|
||||
*/
|
||||
struct ub_packed_rrset_key* dnskey;
|
||||
struct region* region = region_create(malloc, free);
|
||||
struct regional* region = regional_create();
|
||||
struct alloc_cache alloc;
|
||||
ldns_buffer* buf = ldns_buffer_new(65535);
|
||||
struct entry* e;
|
||||
@@ -273,7 +274,7 @@ verifytest_file(const char* fname, const char* at_date)
|
||||
ve.date_override = cfg_convert_timeval(at_date);
|
||||
unit_assert(region && buf);
|
||||
dnskey = extract_keys(list, &alloc, region, buf);
|
||||
if(vsig) log_nametypeclass(VERB_DETAIL, "test dnskey",
|
||||
if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey",
|
||||
dnskey->rk.dname, ntohs(dnskey->rk.type),
|
||||
ntohs(dnskey->rk.rrset_class));
|
||||
/* ready to go! */
|
||||
@@ -281,8 +282,9 @@ verifytest_file(const char* fname, const char* at_date)
|
||||
verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve);
|
||||
}
|
||||
|
||||
ub_packed_rrset_parsedelete(dnskey, &alloc);
|
||||
delete_entry(list);
|
||||
region_destroy(region);
|
||||
regional_destroy(region);
|
||||
alloc_clear(&alloc);
|
||||
ldns_buffer_free(buf);
|
||||
}
|
||||
@@ -296,7 +298,7 @@ dstest_file(const char* fname)
|
||||
* The first entry must be a query for DNSKEY.
|
||||
* The answer rrset is the keyset that will be used for verification
|
||||
*/
|
||||
struct region* region = region_create(malloc, free);
|
||||
struct regional* region = regional_create();
|
||||
struct alloc_cache alloc;
|
||||
ldns_buffer* buf = ldns_buffer_new(65535);
|
||||
struct entry* e;
|
||||
@@ -317,7 +319,7 @@ dstest_file(const char* fname)
|
||||
}
|
||||
|
||||
delete_entry(list);
|
||||
region_destroy(region);
|
||||
regional_destroy(region);
|
||||
alloc_clear(&alloc);
|
||||
ldns_buffer_free(buf);
|
||||
}
|
||||
@@ -374,7 +376,7 @@ nsectest()
|
||||
/** Test hash algo - NSEC3 hash it and compare result */
|
||||
static void
|
||||
nsec3_hash_test_entry(struct entry* e, rbtree_t* ct,
|
||||
struct alloc_cache* alloc, struct region* region,
|
||||
struct alloc_cache* alloc, struct regional* region,
|
||||
ldns_buffer* buf)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
@@ -392,7 +394,7 @@ nsec3_hash_test_entry(struct entry* e, rbtree_t* ct,
|
||||
entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep);
|
||||
nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3);
|
||||
answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA);
|
||||
qname = region_alloc_init(region, qinfo.qname, qinfo.qname_len);
|
||||
qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len);
|
||||
/* check test is OK */
|
||||
unit_assert(nsec3 && answer && qname);
|
||||
|
||||
@@ -429,7 +431,7 @@ nsec3_hash_test(const char* fname)
|
||||
* The test does not perform canonicalization during the compare.
|
||||
*/
|
||||
rbtree_t ct;
|
||||
struct region* region = region_create(malloc, free);
|
||||
struct regional* region = regional_create();
|
||||
struct alloc_cache alloc;
|
||||
ldns_buffer* buf = ldns_buffer_new(65535);
|
||||
struct entry* e;
|
||||
@@ -447,7 +449,7 @@ nsec3_hash_test(const char* fname)
|
||||
}
|
||||
|
||||
delete_entry(list);
|
||||
region_destroy(region);
|
||||
regional_destroy(region);
|
||||
alloc_clear(&alloc);
|
||||
ldns_buffer_free(buf);
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user