mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
239
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a359e134b | ||
|
|
c9447139c8 | ||
|
|
822422cbfb | ||
|
|
34da89510c | ||
|
|
c5ef04b7b4 | ||
|
|
372b4a1c12 | ||
|
|
3e103c2983 | ||
|
|
6b51790054 | ||
|
|
9be7d20ac6 | ||
|
|
d0da5bc14c | ||
|
|
28dfc5fc39 | ||
|
|
bc6617cf11 | ||
|
|
2b95664a66 | ||
|
|
acb8698a3c | ||
|
|
7a8fa9e3de | ||
|
|
d90c162edf | ||
|
|
130a5f2dee | ||
|
|
39b2a21a81 | ||
|
|
c00d1e02cd | ||
|
|
c2390d030d | ||
|
|
5979bc061f | ||
|
|
1dc9abfb79 | ||
|
|
9071852837 | ||
|
|
2f4be547bd | ||
|
|
cc8dfa660d | ||
|
|
99dfad38b2 | ||
|
|
fa368eff78 | ||
|
|
fb1bdb8ee0 | ||
|
|
9c0b217980 | ||
|
|
bc7d3dc192 | ||
|
|
104a7fb3ea | ||
|
|
6591aab69f | ||
|
|
49fd904db2 | ||
|
|
57511c1114 | ||
|
|
bb1bf0505e | ||
|
|
0253676384 | ||
|
|
0627d1a43e | ||
|
|
f3cfe6ed9c | ||
|
|
b018f6d9f7 | ||
|
|
7b8218b2a2 | ||
|
|
1b403f6ee1 | ||
|
|
8a7bb2c4f6 | ||
|
|
b2710818d4 | ||
|
|
0866b8e60b | ||
|
|
8b3c553f23 | ||
|
|
db6178e670 | ||
|
|
dd7ffb54ee | ||
|
|
a0cc6dfc5a | ||
|
|
ffee03db49 | ||
|
|
f3cdeb500c | ||
|
|
a345ffccfa | ||
|
|
c9d58a02d7 | ||
|
|
a561a26a80 | ||
|
|
45e6964a92 | ||
|
|
94bf5d116f | ||
|
|
94f8dd838c | ||
|
|
ed224e1d64 | ||
|
|
00165cbe65 | ||
|
|
06890aaf8e | ||
|
|
954a73f8c6 | ||
|
|
5d8fe6ec49 | ||
|
|
d7f47f4de6 | ||
|
|
49d73f5f56 | ||
|
|
1dd130be61 | ||
|
|
58c34b2dda | ||
|
|
8bde1c7cb3 | ||
|
|
0dcf1d71dc | ||
|
|
09e18ffdbb | ||
|
|
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 |
+100
-32
@@ -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
|
||||
@@ -18,6 +22,7 @@ srcdir=@srcdir@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
bindir=@bindir@
|
||||
sbindir=@sbindir@
|
||||
mandir=@mandir@
|
||||
libdir=@libdir@
|
||||
# datarootdir is here to please some checkers, use datadir.
|
||||
@@ -62,54 +67,78 @@ COMMON_OBJ=$(addprefix $(BUILD),$(COMMON_SRC:.c=.o))
|
||||
COMPAT_OBJ=$(addprefix $(BUILD)compat/,$(LIBOBJS))
|
||||
UNITTEST_SRC=$(patsubst $(srcdir)/%,%, \
|
||||
$(wildcard $(srcdir)/testcode/unit*.c)) \
|
||||
testcode/readhex.c testcode/ldns-testpkts.c checkconf/worker_cb.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=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/daemon/*.c)) \
|
||||
$(COMMON_SRC)
|
||||
DAEMON_OBJ=$(addprefix $(BUILD),$(DAEMON_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
CHECKCONF_SRC=checkconf/unbound-checkconf.c checkconf/worker_cb.c $(COMMON_SRC)
|
||||
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 checkconf/worker_cb.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 checkconf/worker_cb.c \
|
||||
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 checkconf/worker_cb.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 checkconf/worker_cb.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)
|
||||
PERF_SRC=testcode/perf.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
PERF_OBJ=$(addprefix $(BUILD),$(PERF_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
DELAYER_SRC=testcode/delayer.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||
DELAYER_OBJ=$(addprefix $(BUILD),$(DELAYER_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||
HARVEST_SRC=testcode/harvest.c
|
||||
HARVEST_OBJ=$(addprefix $(BUILD),$(HARVEST_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) $(CHECKCONF_SRC)
|
||||
$(MEMSTATS_SRC) $(CHECKCONF_SRC) $(LIBUNBOUND_SRC) $(HOST_SRC) \
|
||||
$(ASYNCLOOK_SRC) $(STREAMTCP_SRC) $(PERF_SRC) $(DELAYER_SRC) \
|
||||
$(HARVEST_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
|
||||
.PHONY: clean realclean doc lint all install uninstall tests test download_ldns strip lib
|
||||
|
||||
$(BUILD)%.o: $(srcdir)/%.c
|
||||
$(INFO) Build $<
|
||||
@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
|
||||
@-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
|
||||
$Q$(COMPILE) -c $< -o $@
|
||||
|
||||
all: $(COMMON_OBJ) unbound unbound-checkconf
|
||||
all: $(COMMON_OBJ) unbound unbound-checkconf lib unbound-host
|
||||
|
||||
tests: all unittest testbound lock-verify pktview signit memstats
|
||||
tests: all unittest testbound lock-verify pktview signit memstats \
|
||||
asynclook streamtcp perf delayer harvest
|
||||
|
||||
test: tests
|
||||
bash testcode/do-tests.sh
|
||||
|
||||
lib: libunbound.la
|
||||
|
||||
libunbound.la: $(LIBUNBOUND_OBJ)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK_LIB) --export-symbols $(srcdir)/libunbound/ubsyms.def -o $@ $(sort $(LIBUNBOUND_OBJ:.o=.lo)) -rpath $(libdir) $(LIBS)
|
||||
|
||||
ifeq ($(patsubst ldns-src%,ldns-src,$(ldnsdir)),ldns-src)
|
||||
ldnslib=$(ldnsdir)/lib/libldns.a
|
||||
$(ldnslib):
|
||||
@@ -127,6 +156,10 @@ unbound-checkconf: $(CHECKCONF_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(CHECKCONF_OBJ)) $(LIBS)
|
||||
|
||||
unbound-host: $(HOST_OBJ) libunbound.la $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(HOST_OBJ)) -L. -L.libs -lunbound $(LIBS)
|
||||
|
||||
unittest: $(UNITTEST_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) $(LIBS)
|
||||
@@ -151,6 +184,26 @@ 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)
|
||||
|
||||
perf: $(PERF_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(PERF_OBJ)) $(LIBS)
|
||||
|
||||
delayer: $(DELAYER_OBJ) $(ldnslib)
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(DELAYER_OBJ)) $(LIBS)
|
||||
|
||||
harvest: $(HARVEST_OBJ) $(ldnslib) libunbound.la
|
||||
$(INFO) Link $@
|
||||
$Q$(LINK) -o $@ $(sort $(HARVEST_OBJ)) $(LIBS) -L. -L.libs -lunbound
|
||||
|
||||
#testcode/ldns-testpkts.c: $(ldnsdir)/examples/ldns-testpkts.c \
|
||||
# $(ldnsdir)/examples/ldns-testpkts.h
|
||||
# cp $(ldnsdir)/examples/ldns-testpkts.c testcode/ldns-testpkts.c
|
||||
@@ -162,14 +215,14 @@ util/configlexer.c: $(srcdir)/util/configlexer.lex util/configparser.h
|
||||
ifeq "$(strip $(LEX))" ":"
|
||||
$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:
|
||||
@@ -185,7 +238,7 @@ realclean: clean
|
||||
|
||||
$(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 $@
|
||||
|
||||
@@ -195,29 +248,42 @@ 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
|
||||
$(LIBTOOL) --mode=install cp unbound $(bindir)/unbound
|
||||
$(LIBTOOL) --mode=install cp unbound-checkconf $(bindir)/unbound-checkconf
|
||||
$(INSTALL) -m 755 -d $(sbindir)
|
||||
$(INSTALL) -m 755 -d $(mandir)
|
||||
$(INSTALL) -m 755 -d $(mandir)/man8
|
||||
$(INSTALL) -m 755 -d $(mandir)/man5
|
||||
$(INSTALL) -m 755 -d $(mandir)/man3
|
||||
$(INSTALL) -m 755 -d $(mandir)/man1
|
||||
$(INSTALL) -m 755 -d $(libdir)
|
||||
$(INSTALL) -m 755 -d $(includedir)
|
||||
$(LIBTOOL) --mode=install cp unbound $(sbindir)/unbound
|
||||
$(LIBTOOL) --mode=install cp unbound-checkconf $(sbindir)/unbound-checkconf
|
||||
$(LIBTOOL) --mode=install cp unbound-host $(sbindir)/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
|
||||
$(INSTALL) -c -m 644 $(srcdir)/doc/unbound-host.1 $(mandir)/man1
|
||||
$(INSTALL) -c -m 644 $(srcdir)/doc/libunbound.3 $(mandir)/man3
|
||||
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 $(bindir)/unbound-checkconf
|
||||
rm -f -- $(sbindir)/unbound $(sbindir)/unbound-checkconf $(sbindir)/unbound-host
|
||||
rm -f -- $(mandir)/man8/unbound.8 $(mandir)/man8/unbound-checkconf.8 $(mandir)/man5/unbound.conf.5
|
||||
rm -f -- $(mandir)/man1/unbound-host.1 $(mandir)/man3/libunbound.3
|
||||
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"
|
||||
|
||||
@@ -232,13 +298,15 @@ $(BUILD)%.d: $(srcdir)/%.c
|
||||
$(INFO) Depend $<
|
||||
@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
|
||||
@-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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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.
|
||||
* You can use libevent if you want. libevent is useful when using
|
||||
many (10000) outgoing ports. By default 16 ports are used and the
|
||||
builtin alternative is equally capable and a little faster.
|
||||
* 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
|
||||
|
||||
+5
-5
@@ -528,7 +528,7 @@ static long double abs_val (long double value)
|
||||
return result;
|
||||
}
|
||||
|
||||
static long double pow10 (int exp)
|
||||
static long double compat_pow10 (int exp)
|
||||
{
|
||||
long double result = 1;
|
||||
|
||||
@@ -541,7 +541,7 @@ static long double pow10 (int exp)
|
||||
return result;
|
||||
}
|
||||
|
||||
static long round (long double value)
|
||||
static long compat_round (long double value)
|
||||
{
|
||||
long intpart;
|
||||
|
||||
@@ -602,12 +602,12 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
/* We "cheat" by converting the fractional part to integer by
|
||||
* multiplying by a factor of 10
|
||||
*/
|
||||
fracpart = round ((pow10 (max)) * (ufvalue - intpart));
|
||||
fracpart = compat_round ((compat_pow10 (max)) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= pow10 (max))
|
||||
if (fracpart >= compat_pow10 (max))
|
||||
{
|
||||
intpart++;
|
||||
fracpart -= pow10 (max);
|
||||
fracpart -= compat_pow10 (max);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
|
||||
+25
-11
@@ -1,5 +1,8 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Directory to chroot to */
|
||||
#undef CHROOT_DIR
|
||||
|
||||
/* Pathname to the Unbound configuration file */
|
||||
#undef CONFIGFILE
|
||||
|
||||
@@ -57,14 +60,8 @@
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `nsl' library (-lnsl). */
|
||||
#undef HAVE_LIBNSL
|
||||
|
||||
/* Define to 1 if you have the `rt' library (-lrt). */
|
||||
#undef HAVE_LIBRT
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#undef HAVE_LIBSOCKET
|
||||
/* 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. */
|
||||
@@ -82,6 +79,9 @@
|
||||
/* 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
|
||||
|
||||
@@ -178,6 +178,9 @@
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Pathname to unbound process id file */
|
||||
#undef PIDFILE
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#undef PTHREAD_CREATE_JOINABLE
|
||||
@@ -185,15 +188,18 @@
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#undef RETSIGTYPE
|
||||
|
||||
/* Directory to chdir to */
|
||||
#undef RUN_DIR
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Define to 'int' or type of struct msghdr.msg_iovlen. */
|
||||
#undef TYPE_MSGIOVLEN
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -287,6 +293,10 @@
|
||||
#undef vfork
|
||||
|
||||
|
||||
#ifndef UNBOUND_DEBUG
|
||||
# define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -331,6 +341,10 @@
|
||||
#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)))
|
||||
|
||||
+105
-51
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.57)
|
||||
|
||||
AC_INIT(unbound, 0.7.2, unbound-bugs@nlnetlabs.nl, unbound)
|
||||
AC_INIT(unbound, 0.10, unbound-bugs@nlnetlabs.nl, unbound)
|
||||
|
||||
CFLAGS=
|
||||
AC_AIX
|
||||
@@ -36,6 +36,13 @@ AC_SUBST(ub_conf_file)
|
||||
# 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])
|
||||
|
||||
# Determine run, chroot directory and pidfile locations
|
||||
ub_cfg=`eval echo $ub_conf_file`
|
||||
ub_dir=`dirname $ub_cfg`
|
||||
AC_DEFINE_UNQUOTED(RUN_DIR, ["$ub_dir"], [Directory to chdir to])
|
||||
AC_DEFINE_UNQUOTED(CHROOT_DIR, ["$ub_dir"], [Directory to chroot to])
|
||||
AC_DEFINE_UNQUOTED(PIDFILE, ["$ub_dir/unbound.pid"], [Pathname to unbound process id file])
|
||||
|
||||
dnl routine to help check for compiler flags.
|
||||
AC_DEFUN([CHECK_COMPILER_FLAG],
|
||||
[
|
||||
@@ -119,6 +126,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"
|
||||
@@ -223,10 +263,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
|
||||
|
||||
@@ -277,7 +328,7 @@ 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.
|
||||
@@ -351,29 +402,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)
|
||||
@@ -415,9 +443,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
|
||||
@@ -426,7 +454,7 @@ 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";
|
||||
LDFLAGS="$LDFLAGS -L$ssldir/lib"
|
||||
if test "x$enable_rpath" = xyes; then
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$ssldir/lib"
|
||||
fi
|
||||
@@ -439,6 +467,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],
|
||||
@@ -476,40 +505,56 @@ 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)]),
|
||||
[ ],[ withval="yes" ])
|
||||
if test x_$withval != x_no; then
|
||||
[use libevent (will check /usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr or you can specify an explicit path). Slower, but allows use of large outgoing port ranges.]),
|
||||
[ ],[ withval="no" ])
|
||||
if test x_$withval == x_yes -o 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-libevent=no to use a builtin alternative.
|
||||
Please note that this alternative is not as capable as libevent when using
|
||||
many outgoing ports. ])
|
||||
large outgoing port ranges. ])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT(found in $thedir)
|
||||
LDFLAGS="$LDFLAGS -L$thedir/lib";
|
||||
LDFLAGS="$LDFLAGS -L$thedir/lib"
|
||||
if test "x$enable_rpath" = xyes; then
|
||||
RUNTIME_PATH="$RUNTIME_PATH -R$thedir/lib"
|
||||
fi
|
||||
@@ -519,6 +564,9 @@ many outgoing ports. ])
|
||||
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
|
||||
@@ -551,10 +599,6 @@ 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
|
||||
@@ -574,6 +618,7 @@ AC_ARG_WITH(ldns,
|
||||
|
||||
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)
|
||||
@@ -601,11 +646,11 @@ 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)
|
||||
echo "(cd $ldnsdir && ./configure)"
|
||||
(cd $ldnsdir && ./configure)
|
||||
AC_MSG_NOTICE([Finished $ldnsdir configure])
|
||||
CPPFLAGS="$CPPFLAGS -I$ldnsdir/include"
|
||||
LDFLAGS="$LDFLAGS $ldnsdir/lib/*.o"
|
||||
LDFLAGS="$LDFLAGS $ldnsdir/*.lo"
|
||||
AC_SUBST(ldnsdir)
|
||||
dnl use ldns compat functions
|
||||
AC_DEFINE(HAVE_INET_ATON)
|
||||
@@ -616,10 +661,15 @@ 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>
|
||||
@@ -664,6 +714,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,4 @@
|
||||
These files are contributed to unbound, and are not part of the official
|
||||
distribution but may be helpful.
|
||||
|
||||
* rc_d_unbound: FreeBSD compatible /etc/rc.d script.
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# unbound freebsd startup rc.d script, modified from the named script.
|
||||
# uses the default unbound installation path and pidfile location.
|
||||
# copy this to /etc/rc.d/unbound
|
||||
# and put unbound_enable="YES" into rc.conf
|
||||
#
|
||||
|
||||
# PROVIDE: unbound
|
||||
# REQUIRE: SERVERS cleanvar
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="unbound"
|
||||
rcvar=`set_rcvar`
|
||||
|
||||
command="/usr/local/sbin/unbound"
|
||||
pidfile="/etc/unbound/unbound.pid"
|
||||
extra_commands="reload"
|
||||
|
||||
load_rc_config $name
|
||||
run_rc_command "$1"
|
||||
@@ -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 */
|
||||
+26
-125
@@ -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,10 +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 "util/fptr_wlist.h"
|
||||
#include <signal.h>
|
||||
|
||||
/** How many quit requests happened. */
|
||||
@@ -127,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;
|
||||
}
|
||||
|
||||
@@ -150,135 +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++) {
|
||||
log_assert(fptr_whitelist_mod_deinit(
|
||||
daemon->modfunc[i]->deinit));
|
||||
(*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->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);
|
||||
log_assert(fptr_whitelist_mod_init(daemon->modfunc[i]->init));
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,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);
|
||||
@@ -421,6 +317,7 @@ 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);
|
||||
@@ -443,6 +340,8 @@ daemon_cleanup(struct daemon* daemon)
|
||||
* 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]);
|
||||
@@ -457,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);
|
||||
@@ -465,6 +364,7 @@ daemon_delete(struct daemon* daemon)
|
||||
infra_delete(daemon->env->infra_cache);
|
||||
}
|
||||
alloc_clear(&daemon->superalloc);
|
||||
acl_list_delete(daemon->acl);
|
||||
free(daemon->pidfile);
|
||||
free(daemon->env);
|
||||
free(daemon);
|
||||
@@ -475,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
-4
@@ -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.
|
||||
@@ -74,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?
|
||||
|
||||
+22
-9
@@ -55,6 +55,13 @@
|
||||
#include <pwd.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
|
||||
#ifdef USE_MINI_EVENT
|
||||
#include "util/mini_event.h"
|
||||
#else
|
||||
#include <event.h>
|
||||
#endif
|
||||
|
||||
/** global debug value to keep track of heap memory allocation */
|
||||
void* unbound_start_brk = 0;
|
||||
|
||||
@@ -69,6 +76,8 @@ static void usage()
|
||||
printf("-d do not fork into the background.\n");
|
||||
printf("-v verbose (more times to increase verbosity)\n");
|
||||
printf("Version %s\n", PACKAGE_VERSION);
|
||||
printf("libevent %s, libldns %s\n",
|
||||
event_get_version(), ldns_version());
|
||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||
}
|
||||
@@ -264,8 +273,8 @@ 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, -12, sizeof(uid));
|
||||
memset(&gid, -12, sizeof(gid));
|
||||
memset(&uid, 112, sizeof(uid));
|
||||
memset(&gid, 112, sizeof(gid));
|
||||
log_assert(cfg);
|
||||
|
||||
/* daemonize last to be able to print error to user */
|
||||
@@ -274,7 +283,7 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode)
|
||||
fatal_exit("Could not chdir to %s: %s",
|
||||
cfg->directory, strerror(errno));
|
||||
}
|
||||
verbose(VERB_DETAIL, "chdir to %s", cfg->directory);
|
||||
verbose(VERB_QUERY, "chdir to %s", cfg->directory);
|
||||
}
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
struct passwd *pwd;
|
||||
@@ -288,7 +297,7 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode)
|
||||
if(chroot(cfg->chrootdir))
|
||||
fatal_exit("unable to chroot to %s: %s",
|
||||
cfg->chrootdir, strerror(errno));
|
||||
verbose(VERB_DETAIL, "chroot to %s", cfg->chrootdir);
|
||||
verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir);
|
||||
}
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
if(setgid(gid) != 0)
|
||||
@@ -297,7 +306,7 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode)
|
||||
if(setuid(uid) != 0)
|
||||
fatal_exit("unable to set user id of %s: %s",
|
||||
cfg->username, strerror(errno));
|
||||
verbose(VERB_DETAIL, "drop user privileges, run as %s",
|
||||
verbose(VERB_QUERY, "drop user privileges, run as %s",
|
||||
cfg->username);
|
||||
}
|
||||
/* check old pid file before forking */
|
||||
@@ -339,14 +348,18 @@ run_daemon(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);
|
||||
if(!config_read(cfg, cfgfile)) {
|
||||
if(errno != ENOENT)
|
||||
fatal_exit("Could not read config file: %s",
|
||||
cfgfile);
|
||||
log_warn("Continuing with default config settings");
|
||||
}
|
||||
apply_settings(daemon, cfg, cmdline_verbose);
|
||||
|
||||
/* prepare */
|
||||
|
||||
+173
-44
@@ -45,6 +45,7 @@
|
||||
#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"
|
||||
@@ -57,6 +58,7 @@
|
||||
#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"
|
||||
@@ -134,13 +136,13 @@ 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++) {
|
||||
log_assert(fptr_whitelist_mod_get_mem(worker->env.mesh->
|
||||
modfunc[i]->get_mem));
|
||||
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++) {
|
||||
fptr_ok(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)
|
||||
@@ -161,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++) {
|
||||
fptr_ok(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 */
|
||||
}
|
||||
|
||||
@@ -248,40 +267,45 @@ 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;
|
||||
}
|
||||
@@ -382,7 +406,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
*/
|
||||
uint16_t udpsize = edns->udp_size;
|
||||
int secure = 0;
|
||||
uint32_t timenow = (uint32_t)time(0);
|
||||
uint32_t timenow = *worker->env.now;
|
||||
int must_validate = !(flags&BIT_CD) && worker->env.need_to_validate;
|
||||
struct dns_msg *msg = NULL;
|
||||
struct delegpt *dp;
|
||||
@@ -481,12 +505,11 @@ all_rrsets_secure(struct reply_info* rep) {
|
||||
|
||||
/** answer query from the cache */
|
||||
static int
|
||||
answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
uint16_t flags, struct comm_reply* repinfo, struct edns_data* edns)
|
||||
answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
struct reply_info* rep, uint16_t id, uint16_t flags,
|
||||
struct comm_reply* repinfo, struct edns_data* edns)
|
||||
{
|
||||
struct msgreply_entry* mrentry = (struct msgreply_entry*)e->key;
|
||||
struct reply_info* rep = (struct reply_info*)e->data;
|
||||
uint32_t timenow = time(0);
|
||||
uint32_t timenow = *worker->env.now;
|
||||
uint16_t udpsize = edns->udp_size;
|
||||
int secure;
|
||||
int must_validate = !(flags&BIT_CD) && worker->env.need_to_validate;
|
||||
@@ -523,7 +546,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
&mrentry->key, id, flags, edns);
|
||||
qinfo, id, flags, edns);
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -549,11 +572,11 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
|
||||
if(!reply_info_answer_encode(qinfo, rep, id, flags,
|
||||
repinfo->c->buffer, timenow, 1, worker->scratchpad,
|
||||
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
&mrentry->key, id, flags, edns);
|
||||
qinfo, id, flags, edns);
|
||||
}
|
||||
/* cannot send the reply right now, because blocking network syscall
|
||||
* is bad while holding locks. */
|
||||
@@ -663,12 +686,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) {
|
||||
/* 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) {
|
||||
@@ -716,7 +757,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;
|
||||
}
|
||||
@@ -738,10 +779,15 @@ 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 */
|
||||
if(answer_from_cache(worker, e,
|
||||
if(answer_from_cache(worker, &qinfo,
|
||||
(struct reply_info*)e->data,
|
||||
*(uint16_t*)ldns_buffer_begin(c->buffer),
|
||||
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||
&edns)) {
|
||||
@@ -771,6 +817,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->stats.num_query_list_exceeded++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
} else if(worker->env.mesh->num_reply_addrs>worker->request_size*16) {
|
||||
verbose(VERB_ALGO, "Too many requests queued. "
|
||||
"dropping incoming query.");
|
||||
worker->stats.num_query_list_exceeded++;
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
mesh_new_client(worker->env.mesh, &qinfo,
|
||||
ldns_buffer_read_u16_at(c->buffer, 2),
|
||||
@@ -789,21 +841,21 @@ worker_sighandler(int sig, void* arg)
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
switch(sig) {
|
||||
case SIGHUP:
|
||||
verbose(VERB_DETAIL, "caught signal SIGHUP");
|
||||
verbose(VERB_QUERY, "caught signal SIGHUP");
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGINT:
|
||||
verbose(VERB_DETAIL, "caught signal SIGINT");
|
||||
verbose(VERB_QUERY, "caught signal SIGINT");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGQUIT:
|
||||
verbose(VERB_DETAIL, "caught signal SIGQUIT");
|
||||
verbose(VERB_QUERY, "caught signal SIGQUIT");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
case SIGTERM:
|
||||
verbose(VERB_DETAIL, "caught signal SIGTERM");
|
||||
verbose(VERB_QUERY, "caught signal SIGTERM");
|
||||
worker->need_to_exit = 1;
|
||||
comm_base_exit(worker->base);
|
||||
break;
|
||||
@@ -813,6 +865,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)
|
||||
{
|
||||
@@ -877,17 +953,10 @@ 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);
|
||||
@@ -908,7 +977,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
|
||||
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);
|
||||
worker->daemon->env->infra_cache, worker->rndstate,
|
||||
cfg->use_caps_bits_for_id);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
@@ -924,6 +994,12 @@ 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 = regional_create_custom(cfg->msg_buffer_size);
|
||||
@@ -939,14 +1015,16 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
worker->thread_num);
|
||||
alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker);
|
||||
worker->env = *worker->daemon->env;
|
||||
comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv);
|
||||
if(worker->thread_num == 0)
|
||||
log_set_time(worker->env.now);
|
||||
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;
|
||||
@@ -957,6 +1035,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;
|
||||
}
|
||||
|
||||
@@ -971,19 +1055,22 @@ worker_delete(struct worker* worker)
|
||||
{
|
||||
if(!worker)
|
||||
return;
|
||||
if(worker->env.mesh)
|
||||
if(worker->env.mesh && verbosity >= VERB_OPS) {
|
||||
server_stats_log(&worker->stats, worker->thread_num);
|
||||
mesh_stats(worker->env.mesh, "mesh has");
|
||||
server_stats_log(&worker->stats, worker->thread_num);
|
||||
worker_mem_report(worker, NULL);
|
||||
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);
|
||||
if(worker->thread_num == 0)
|
||||
log_set_time(NULL);
|
||||
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)
|
||||
@@ -1052,3 +1139,45 @@ worker_alloc_cleanup(void* 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;
|
||||
}
|
||||
|
||||
+5
-3
@@ -59,9 +59,6 @@ struct listen_port;
|
||||
struct ub_randstate;
|
||||
struct regional;
|
||||
|
||||
/** size of table used for random numbers. large to be more secure. */
|
||||
#define RND_STATE_SIZE 256
|
||||
|
||||
/** worker commands */
|
||||
enum worker_commands {
|
||||
/** make the worker quit */
|
||||
@@ -93,6 +90,8 @@ 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;
|
||||
@@ -217,4 +216,7 @@ int worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
/** 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 */
|
||||
|
||||
@@ -7,3 +7,6 @@ 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.
|
||||
|
||||
+443
-10
@@ -1,16 +1,449 @@
|
||||
29 February 2008: Wouter
|
||||
- documentation update.
|
||||
- fixup port to Solaris of perf test tool.
|
||||
- updated ldns-tarball with decl-after-statement fixes.
|
||||
|
||||
28 February 2008: Wouter
|
||||
- fixed memory leaks in libunbound (during cancellation and wait).
|
||||
- libunbound returns the answer packet in full.
|
||||
- snprintf compat update.
|
||||
- harvest performs lookup.
|
||||
- ldns-tarball update with fix for ldns_dname_label.
|
||||
- installs to sbin by default.
|
||||
- install all manual pages (unbound-host and libunbound too).
|
||||
|
||||
27 February 2008: Wouter
|
||||
- option to use caps for id randomness.
|
||||
- config file option use-caps-for-id: yes
|
||||
- harvest debug tool
|
||||
|
||||
26 February 2008: Wouter
|
||||
- delay utility delays TCP as well. If the server that is forwarded
|
||||
to has a TCP error, the delay utility closes the connection.
|
||||
- delay does REUSE_ADDR, and can handle a server that closes its end.
|
||||
- answers use casing from query.
|
||||
|
||||
25 February 2008: Wouter
|
||||
- delay utility works. Gets decent thoughput too (>20000).
|
||||
|
||||
22 February 2008: Wouter
|
||||
- +2% for recursions, if identical queries (except for destination
|
||||
and query ID) in the reply list, avoid re-encoding the answer.
|
||||
- removed TODO items for optimizations that do not show up in
|
||||
profile reports.
|
||||
- default is now minievent - not libevent. As its faster and
|
||||
not needed for regular installs, only for very large port ranges.
|
||||
- loop check different speedup pkt-dname-reading, 1% faster for
|
||||
nocache-recursion check.
|
||||
- less hashing during msg parse, 4% for recursion.
|
||||
- small speed fix for dname_count_size_labels, +1 or +2% recursion.
|
||||
- some speed results noted:
|
||||
optimization resulted in +40% for recursion (cache miss) and
|
||||
+70 to +80 for cache hits, and +96% for version.bind.
|
||||
zone nsec3 example, 100 NXDOMAIN queries, NSD 35182.8 Ub 36048.4
|
||||
www.nlnetlabs.nl from cache: BIND 8987.99 Ub 31218.3
|
||||
www with DO bit set : BIND 8269.31 Ub 28735.6 qps.
|
||||
So, unbound can be about equal qps to NSD in cache hits.
|
||||
And about 3.4x faster than BIND in cache performance.
|
||||
- delay utility for testing.
|
||||
|
||||
21 February 2008: Wouter
|
||||
- speedup of root-delegation message encoding by 15%.
|
||||
- minor speedup of compress tree_lookup, maybe 1%.
|
||||
- speedup of dname_lab_cmp and memlowercmp - the top functions in
|
||||
profiler output, maybe a couple percent when it matters.
|
||||
|
||||
20 February 2008: Wouter
|
||||
- setup speec_cache for need-ldns-testns in dotests.
|
||||
- check number of queued replies on incoming queries to avoid overload
|
||||
on that account.
|
||||
- fptr whitelist checks are not disabled in optimize mode.
|
||||
- do-daemonize config file option.
|
||||
- minievent time share initializes time at start.
|
||||
- updated testdata for nsec3 new algorithm numbers (6, 7).
|
||||
- small performance test of packet encoding (root delegation).
|
||||
|
||||
19 February 2008: Wouter
|
||||
- applied patch to unbound-host man page from Jan-Piet Mens.
|
||||
- fix donotquery-localhost: yes default (it erroneously was switched
|
||||
to default 'no').
|
||||
- time is only gotten once and the value is shared across unbound.
|
||||
- unittest cleans up crypto, so that it has no memory leaks.
|
||||
- mini_event shares the time value with unbound this results in
|
||||
+3% speed for cache responses and +9% for recursions.
|
||||
- ldns tarball update with new NSEC3 sign code numbers.
|
||||
- perform several reads per UDP operation. This improves performance
|
||||
in DoS conditions, and costs very little in normal conditions.
|
||||
improves cache response +50%, and recursions +10%.
|
||||
- modified asynclook test. because the callback from async is not
|
||||
in any sort of lock (and thus can use all library functions freely),
|
||||
this causes a tiny race condition window when the last lock is
|
||||
released for a callback and a new cancel() for that callback.
|
||||
The only way to remove this is by putting callbacks into some
|
||||
lock window. I'd rather have the small possibility of a callback
|
||||
for a cancelled function then no use of library functions in
|
||||
callbacks. Could be possible to only outlaw process(), wait(),
|
||||
cancel() from callbacks, by adding another lock, but I'd rather not.
|
||||
|
||||
18 February 2008: Wouter
|
||||
- patch to unbound-host from Jan-Piet Mens.
|
||||
- unbound host prints errors if fails to configure context.
|
||||
- fixup perf to resend faster, so that long waiting requests do
|
||||
not hold up the queue, they become lost packets or SERVFAILs,
|
||||
or can be sent a little while later (i.e. processing time may
|
||||
take long, but throughput has to be high).
|
||||
- fixup iterator operating in no cache conditions (RD flag unset
|
||||
after a CNAME).
|
||||
- streamlined code for RD flag setting.
|
||||
- profiled code and changed dname compares to be faster.
|
||||
The speedup is about +3% to +8% (depending on the test).
|
||||
- minievent tests for eintr and eagain.
|
||||
|
||||
15 February 2008: Wouter
|
||||
- added FreeBSD rc.d script to contrib.
|
||||
- --prefix option for configure also changes directory: pidfile:
|
||||
and chroot: defaults in config file.
|
||||
- added cache speed test, for cache size OK and cache too small.
|
||||
|
||||
14 February 2008: Wouter
|
||||
- start without a config file (will complain, but start with
|
||||
defaults).
|
||||
- perf test program works.
|
||||
|
||||
13 February 2008: Wouter
|
||||
- 0.9 released.
|
||||
- 1.0 development. Printout ldns version on unbound -h.
|
||||
- start of perf tool.
|
||||
- bugfix to read empty lines from /etc/hosts.
|
||||
|
||||
12 February 2008: Wouter
|
||||
- fixup problem with configure calling itself if ldns-src tarball
|
||||
is not present.
|
||||
|
||||
11 February 2008: Wouter
|
||||
- changed library to use ub_ instead of ub_val_ as prefix.
|
||||
- statistics output text nice.
|
||||
- etc/hosts handling.
|
||||
- library function to put logging to a stream.
|
||||
- set any option interface.
|
||||
|
||||
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
|
||||
- layout of manpages, spelling fix in header, manpages process by
|
||||
makedist, list asynclook and tcpstream tests as ldns-testns
|
||||
required.
|
||||
|
||||
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
|
||||
- Fixup building in a subdirectory. (for 0.7.2)
|
||||
- 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
|
||||
- version 0.7.1:
|
||||
* includes tpkg fixes to kill daemons at end of test
|
||||
* includes NSEC/RRSIG not downcasing fixup from
|
||||
dnssec-bis-updates draft-06.
|
||||
* README file updated.
|
||||
* nice libevent not found error.
|
||||
* README talks about gnu make.
|
||||
- for 0.7.2:
|
||||
* fixup for donotq matching.
|
||||
- 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.
|
||||
|
||||
+26
-11
@@ -4,18 +4,16 @@ http://unbound.net
|
||||
|
||||
This software is under BSD license, see LICENSE for details.
|
||||
|
||||
* Download the latest version of this software from
|
||||
* Download the latest release version of this software from
|
||||
http://unbound.net
|
||||
or get a beta version from the svn repository at
|
||||
http://unbound.net/svn/
|
||||
|
||||
* Uses the following libraries;
|
||||
* ldns http://www.nlnetlabs.nl/ldns/ (BSD license)
|
||||
(required) can use tarball from source directory.
|
||||
* libevent http://www.monkey.org/~provos/libevent/ (BSD license)
|
||||
|
||||
* Create build environment
|
||||
* run libtoolize -c if config.sub is missing, or run glibtoolize.
|
||||
* autoreconf (autoheader && autoconf), if ./configure is missing.
|
||||
(optional) can use builtin alternative instead.
|
||||
|
||||
* Make and install: ./configure; make; make install
|
||||
* Use GNU make; default on linux, often called 'gmake' on BSD and Solaris.
|
||||
@@ -25,13 +23,15 @@ This software is under BSD license, see LICENSE for details.
|
||||
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.
|
||||
--with-libevent=no (default) 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 and is a little faster.
|
||||
* --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.
|
||||
@@ -53,9 +53,24 @@ 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
|
||||
----------------
|
||||
o Unbound was written in portable C by Wouter Wijngaards (NLnet Labs).
|
||||
o Thanks to David Blacka and Matt Larson (Verisign) for the unbound-java
|
||||
prototype. Design and code from that prototype has been used to create
|
||||
this program. Such as the iterator state machine and the cache design.
|
||||
|
||||
+5
-3
@@ -1,11 +1,13 @@
|
||||
README.svn
|
||||
|
||||
For a svn checkout
|
||||
* Create build environment - see README.
|
||||
* possibly copy aclocal.m4 from your autoconf/libtool setup.
|
||||
* configure script, aclocal.m4, as well as yacc/lex output files are
|
||||
committed to the repository.
|
||||
* use --enable-debug flag for configure to enable dependency tracking and
|
||||
assertions, otherwise, use make clean; make after svn update.
|
||||
|
||||
* Note changes in the Changelog.
|
||||
* Every checking a postcommit hook is run
|
||||
* Every check-in a postcommit hook is run
|
||||
(the postcommit hook is in the svn/unbound/hooks directory).
|
||||
* generates commit email with your changes and comment.
|
||||
* compiles and runs the tests (with testcode/do-tests.sh).
|
||||
|
||||
+12
-1
@@ -3,7 +3,18 @@ README unbound tests
|
||||
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.
|
||||
|
||||
You need to have the following programs installed and in your PATH.
|
||||
* dig - from the bind-tools package. Used to send DNS queries.
|
||||
* splint (optional) - for lint test
|
||||
* doxygen (optional) - for doc completeness test
|
||||
* ldns-testns (optional) - from ldns examples. Used as DNS auth server.
|
||||
* xxd and nc (optional) - for (malformed) packet transmission.
|
||||
The optional programs are detected and can be omitted.
|
||||
|
||||
Without any support programs, unittest and testbound can still be used.
|
||||
(cd testdata; ../testcode/mini_tpkg.sh exe 02-unittest.tpkg)
|
||||
(cd testdata; ../testcode/mini_tpkg.sh exe 03-testbound.tpkg)
|
||||
|
||||
testdata/ contains the data for tests.
|
||||
testcode/ contains scripts and c code for the tests.
|
||||
|
||||
@@ -1,58 +1,41 @@
|
||||
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.
|
||||
o detect OS/400 pthreads implementation that allows upgrading to writelock
|
||||
on pthreads rwlocks and use it to examine-rd before storing-wr rrset cache.
|
||||
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 NSEC/NSEC3 aggressive negative caching, so that updates to NSEC/NSEC3
|
||||
will result in proper negative responses.
|
||||
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 (option) where port 53 is used for send and receive, no other ports are used.
|
||||
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 (option) private TTL feature (always report TTL x in answers).
|
||||
o (option) pretend-dnssec-unaware, and pretend-edns-unaware modes for 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 (option) reprime and refresh oft used data before timeout.
|
||||
o (option) retain prime results in a overlaid roothints file.
|
||||
o (option) 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 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 watch for spoof nearmisses. Keep counter of nearmisses and print that
|
||||
in the stats lines, operator can determine what level is a redalert.
|
||||
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 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.
|
||||
o (option) 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 check if for PowerDNS(2.9.21) CNAME in Answer section & rcode=NXDOMAIN needs
|
||||
to be fixed up to be rcode=NOERROR?
|
||||
o On Windows use CryptGenRandom() to get random seed for arc4random.
|
||||
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.
|
||||
o (option) to make local-data answers be secure for libunbound (default=no)
|
||||
|
||||
+66
-9
@@ -15,6 +15,10 @@ server:
|
||||
# verbosity number, 0 is least verbose. 1 is default.
|
||||
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
|
||||
|
||||
@@ -26,6 +30,10 @@ server:
|
||||
# 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
|
||||
@@ -59,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.
|
||||
@@ -71,8 +79,8 @@ 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.
|
||||
@@ -81,7 +89,7 @@ server:
|
||||
|
||||
# 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: 864000
|
||||
# cache-max-ttl: 86400
|
||||
|
||||
# the time to live (TTL) value for cached roundtrip times and
|
||||
# EDNS version information for hosts. In seconds.
|
||||
@@ -99,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
|
||||
@@ -113,6 +121,19 @@ server:
|
||||
# Enable TCP, "yes" or "no".
|
||||
# do-tcp: yes
|
||||
|
||||
# Detach from the terminal, run in background, "yes" or "no".
|
||||
# do-daemonize: 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.
|
||||
@@ -121,7 +142,7 @@ server:
|
||||
|
||||
# if given, user privileges are dropped (after binding port),
|
||||
# and the given username is assumed. Default is user "unbound".
|
||||
# If you give "" no priviliges are dropped.
|
||||
# If you give "" no privileges are dropped.
|
||||
# username: "unbound"
|
||||
|
||||
# the working directory.
|
||||
@@ -179,6 +200,12 @@ server:
|
||||
# Default on, which insists on dnssec data for trust-anchored zones.
|
||||
# harden-dnssec-stripped: yes
|
||||
|
||||
# Use 0x20-encoded random bits in the query to foil spoof attempts.
|
||||
# Disabled by default, because some caching forwarders may not
|
||||
# support this (if you have forward-zones). Most authority servers do.
|
||||
# This feature is an experimental implementation of draft dns-0x20.
|
||||
# use-caps-for-id: no
|
||||
|
||||
# Do not query the following addresses. No DNS queries are sent there.
|
||||
# List one address per entry. List classless netblocks with /size,
|
||||
# do-not-query-address: 127.0.0.1/8
|
||||
@@ -238,14 +265,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,335 @@
|
||||
.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 */
|
||||
void* answer_packet; /* full network format answer packet */
|
||||
int answer_len; /* length of packet in octets */
|
||||
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.
|
||||
@@ -203,14 +203,18 @@ X make overload mode work; phase 0 all ok, phase 1 some threads close ports,
|
||||
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:
|
||||
@@ -240,14 +244,14 @@ X make overload mode work; phase 0 all ok, phase 1 some threads close ports,
|
||||
*** 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.
|
||||
* 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/
|
||||
|
||||
+33
-2
@@ -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
|
||||
@@ -138,7 +138,7 @@ o The method by which dnssec-lameness is detected is not secure. DNSSEC lame
|
||||
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 dnnsec to our
|
||||
parent, dnssec-lameness detection enables. This delivers dnssec to our
|
||||
clients when possible (for client validators).
|
||||
|
||||
The following issue needs to be resolved:
|
||||
@@ -175,3 +175,34 @@ o authority features.
|
||||
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.
|
||||
|
||||
+25
-27
@@ -1,3 +1,4 @@
|
||||
.TH "unbound-checkconf" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound-checkconf.8 -- unbound configuration checker manual
|
||||
.\"
|
||||
@@ -6,40 +7,37 @@
|
||||
.\" See LICENSE for the license.
|
||||
.\"
|
||||
.\"
|
||||
.Dd @date@
|
||||
.Dt unbound-checkconf 8
|
||||
.Sh NAME
|
||||
.SH "NAME"
|
||||
.LP
|
||||
unbound-checkconf
|
||||
.Nd Check unbound configuration file for errors.
|
||||
.Sh SYNOPSIS
|
||||
.Nm unbound-checkconf
|
||||
.Op Fl h
|
||||
.Op cfgfile
|
||||
.Sh DESCRIPTION
|
||||
.Ic 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
|
||||
.Xr unbound 8
|
||||
\fIunbound\fR(8)
|
||||
DNS resolver for syntax and other errors.
|
||||
The config file syntax is
|
||||
described in
|
||||
.Xr unbound.conf 5 .
|
||||
.Pp
|
||||
The config file syntax is described in
|
||||
\fIunbound.conf\fR(5).
|
||||
.P
|
||||
The available options are:
|
||||
.Bl -tag -width indent
|
||||
.It Fl h
|
||||
.TP
|
||||
.B \-h
|
||||
Show the version and commandline option help.
|
||||
.It cfgfile
|
||||
.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
|
||||
.SH "EXIT CODE"
|
||||
The unbound-checkconf program exits with status code 1 on error,
|
||||
0 for a correct config file.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
.It Pa /etc/unbound/unbound.conf
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I /etc/unbound/unbound.conf
|
||||
unbound configuration file.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr unbound.conf 5 ,
|
||||
.Xr unbound 8 .
|
||||
.SH "SEE ALSO"
|
||||
\fIunbound.conf\fR(5),
|
||||
\fIunbound\fR(8).
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
.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 ]
|
||||
.RB [ \-C
|
||||
.IR configfile ]
|
||||
.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.
|
||||
.TP
|
||||
.B \-C \fIconfigfile
|
||||
Uses the specified unbound.conf to prime
|
||||
.IR libunbound (3).
|
||||
.SH "EXAMPLES"
|
||||
.LP
|
||||
Some examples of use. The keys shown below are fakes, thus a security failure
|
||||
is encountered.
|
||||
.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).
|
||||
+32
-28
@@ -1,3 +1,4 @@
|
||||
.TH "unbound" "8" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound.8 -- unbound manual
|
||||
.\"
|
||||
@@ -6,42 +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
|
||||
.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
|
||||
.Xr unbound.conf 5 .
|
||||
.It Fl d
|
||||
described in \fIunbound.conf\fR(5).
|
||||
.TP
|
||||
.B \-d
|
||||
Debug flag, do not fork into the background, but stay attached to the
|
||||
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.
|
||||
.It Fl v
|
||||
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 ,
|
||||
.Xr unbound-checkconf 8 .
|
||||
.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.
|
||||
|
||||
+424
-158
@@ -1,3 +1,4 @@
|
||||
.TH "unbound.conf" "5" "@date@" "NLnet Labs" "unbound @version@"
|
||||
.\"
|
||||
.\" unbound.conf.5 -- unbound.conf manual
|
||||
.\"
|
||||
@@ -6,39 +7,44 @@
|
||||
.\" 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.
|
||||
.Pp
|
||||
.P
|
||||
The utility
|
||||
.Xr unbound-checkconf 8
|
||||
\fIunbound\-checkconf\fR(8)
|
||||
can be used to check unbound.conf prior to usage.
|
||||
.Sh EXAMPLE
|
||||
.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:
|
||||
@@ -48,192 +54,272 @@ server:
|
||||
# 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
|
||||
.SS "Server Options"
|
||||
These options are part of the
|
||||
.Ic server:
|
||||
.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>
|
||||
.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.
|
||||
.It \fBoutgoing-interface:\fR <ip address>
|
||||
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
|
||||
.Ic interface:
|
||||
.B interface:
|
||||
and
|
||||
.Ic outgoing-interface:
|
||||
.B outgoing\-interface:
|
||||
lines, the interfaces are then used for both purposes. Outgoing queries are
|
||||
sent via a random outgoing interface to counter spoofing.
|
||||
.It \fBoutgoing-port:\fR <port number>
|
||||
.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.
|
||||
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.
|
||||
.It \fBrrset-cache-size:\fR <number>
|
||||
.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 \fBcache-max-ttl:\fR <seconds>
|
||||
.TP
|
||||
.B cache\-max\-ttl: \fI<seconds>
|
||||
Time to live maximum for RRsets and messages in the cache. Default is
|
||||
864000 seconds (10 days). If the maximum kicks in, responses to clients
|
||||
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.
|
||||
.It \fBinfra-host-ttl:\fR <seconds>
|
||||
.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>
|
||||
.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 do\-daemonize: \fI<yes or no>
|
||||
Enable or disable whether the unbound server forks into the background as
|
||||
a daemon. 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.
|
||||
.It \fBusername:\fR <name>
|
||||
.TP
|
||||
.B username: \fI<name>
|
||||
If given, after binding the port the user privileges are dropped. Default is
|
||||
"unbound". If you give username: "" no user change is performed.
|
||||
.Pp
|
||||
.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.
|
||||
If this option is given, the use-syslog is option is set to "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.
|
||||
.It \fBuse-syslog:\fR <yes or no>
|
||||
.TP
|
||||
.B use\-syslog: \fI<yes or no>
|
||||
Sets unbound to send log messages to the syslogd, using
|
||||
.Xr syslog 3 .
|
||||
\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 logfile setting is overridden when use\-syslog is turned on.
|
||||
The default is to log to syslog.
|
||||
.It \fBpidfile:\fR <filename>
|
||||
.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`
|
||||
kill \-HUP `cat /etc/unbound/unbound.pid`
|
||||
.fi
|
||||
triggers a reload,
|
||||
.nf
|
||||
kill -QUIT `cat /etc/unbound/unbound.pid`
|
||||
kill \-QUIT `cat /etc/unbound/unbound.pid`
|
||||
.fi
|
||||
gracefully terminates.
|
||||
.It \fBroot-hints:\fR <filename>
|
||||
.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.
|
||||
.It \fBhide-identity:\fR <yes or no>
|
||||
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 \fBharden-dnssec-stripped:\fR <yes or no>
|
||||
Require DNSSEC data for trust-anchored zones, if such data is absent,
|
||||
.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
|
||||
@@ -241,60 +327,81 @@ 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.
|
||||
.It \fBdo-not-query-address:\fR <IP address>
|
||||
.TP
|
||||
.B use\-caps\-for\-id: \fI<yes or no>
|
||||
Use 0x20-encoded random bits in the query to foil spoof attempts.
|
||||
This perturbs the lowercase and uppercase of query names sent to
|
||||
authority servers and checks if the reply still has the correct casing.
|
||||
Use together with a large outgoing port range to obtain a high spoof resistance.
|
||||
Disabled by default, because some caching forwarders may not
|
||||
support this. If you have no forward\-zones it should be possible to enable
|
||||
this without problem, it works with most authority servers.
|
||||
This feature is an experimental implementation of draft dns\-0x20.
|
||||
.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.
|
||||
.It \fBdo-not-query-localhost:\fR <yes or no>
|
||||
If yes, localhost is added to the do-not-query-address entries, both
|
||||
.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.
|
||||
.It \fBmodule-config:\fR <"module names">
|
||||
.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
|
||||
@@ -302,92 +409,251 @@ 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
|
||||
If you do not have to worry about programs using more than 3 Mb of memory,
|
||||
the below example is not for you. Use the defaults to receive full service,
|
||||
which on BSD-32bit tops out at 30-40 Mb after heavy usage.
|
||||
.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: 100k
|
||||
msg\-cache\-slabs: 1
|
||||
rrset\-cache\-size: 100k
|
||||
rrset\-cache\-slabs: 1
|
||||
infra\-cache\-numhosts: 200
|
||||
infra\-cache\-slabs: 1
|
||||
infra\-cache\-lame\-size: 1k
|
||||
key\-cache\-size: 100k
|
||||
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"
|
||||
.fi
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
.It Pa /etc/unbound
|
||||
.SH "FILES"
|
||||
.TP
|
||||
.I /etc/unbound
|
||||
default unbound working directory and default
|
||||
.Xr chroot 2
|
||||
\fIchroot\fR(2)
|
||||
location.
|
||||
.It Pa unbound.conf
|
||||
.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
|
||||
.TP
|
||||
.I unbound.log
|
||||
unbound log file. default is to log to
|
||||
.Xr syslog 3 .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr unbound 8 ,
|
||||
.Xr unbound-checkconf 8 .
|
||||
.Sh AUTHORS
|
||||
.Ic Unbound
|
||||
\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.
|
||||
|
||||
+4
-85
@@ -103,68 +103,23 @@ donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
|
||||
node->net = net;
|
||||
node->parent = NULL;
|
||||
if(!rbtree_insert(dq->tree, &node->node)) {
|
||||
verbose(VERB_DETAIL, "duplicate donotquery address ignored.");
|
||||
verbose(VERB_QUERY, "duplicate donotquery address ignored.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** make sure the netblock ends in zeroes for compare in tree */
|
||||
static void
|
||||
mask_block(int ip6, struct sockaddr_storage* addr, int net)
|
||||
{
|
||||
uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
|
||||
int i, max;
|
||||
uint8_t* s;
|
||||
if(ip6) {
|
||||
s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
|
||||
max = 128;
|
||||
} else {
|
||||
s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
|
||||
max = 32;
|
||||
}
|
||||
if(net >= max)
|
||||
return;
|
||||
for(i=net/8+1; i<max/8; i++) {
|
||||
s[i] = 0;
|
||||
}
|
||||
s[net/8] &= mask[net&0x7];
|
||||
}
|
||||
|
||||
/** apply donotq string */
|
||||
static int
|
||||
donotq_str_cfg(struct iter_donotq* dq, const char* str)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
char* s = NULL;
|
||||
socklen_t addrlen;
|
||||
net = (str_is_ip6(str)?128:32);
|
||||
if((s=strchr(str, '/'))) {
|
||||
if(atoi(s+1) > net) {
|
||||
log_err("netblock too large: %s", str);
|
||||
return 0;
|
||||
}
|
||||
net = atoi(s+1);
|
||||
if(net == 0 && strcmp(s+1, "0") != 0) {
|
||||
log_err("cannot parse donotquery netblock:"
|
||||
" '%s'", str);
|
||||
return 0;
|
||||
}
|
||||
if(!(s = strdup(str))) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
}
|
||||
*strchr(s, '/') = '\0';
|
||||
}
|
||||
if(!ipstrtoaddr(s?s:str, UNBOUND_DNS_PORT, &addr, &addrlen)) {
|
||||
free(s);
|
||||
log_err("cannot parse donotquery ip address: '%s'", str);
|
||||
verbose(VERB_ALGO, "donotq: %s", str);
|
||||
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
|
||||
log_err("cannot parse donotquery netblock: %s", str);
|
||||
return 0;
|
||||
}
|
||||
if(s) {
|
||||
free(s);
|
||||
mask_block(str_is_ip6(str), &addr, net);
|
||||
}
|
||||
if(!donotq_insert(dq, &addr, addrlen, net)) {
|
||||
log_err("out of memory");
|
||||
return 0;
|
||||
@@ -185,42 +140,6 @@ read_donotq(struct iter_donotq* dq, struct config_file* cfg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** number of bits that two addrs share (are equal) */
|
||||
static int
|
||||
addr_in_common(struct sockaddr_storage* addr1, int net1,
|
||||
struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
|
||||
{
|
||||
int min = (net1<net2)?net1:net2;
|
||||
int i, to;
|
||||
int match = 0;
|
||||
uint8_t* s1, *s2;
|
||||
if(addr_is_ip6(addr1, addrlen)) {
|
||||
s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
|
||||
s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
|
||||
to = 16;
|
||||
} else {
|
||||
s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
|
||||
s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
|
||||
to = 4;
|
||||
}
|
||||
/* match = bits_in_common(s1, s2, to); */
|
||||
for(i=0; i<to; i++) {
|
||||
if(s1[i] == s2[i]) {
|
||||
match += 8;
|
||||
} else {
|
||||
uint8_t z = s1[i]^s2[i];
|
||||
log_assert(z);
|
||||
while(!(z&0x80)) {
|
||||
match++;
|
||||
z<<=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(match > min) match = min;
|
||||
return match;
|
||||
}
|
||||
|
||||
/** initialise parent pointers in the tree */
|
||||
static void
|
||||
donotq_init_parents(struct iter_donotq* donotq)
|
||||
|
||||
@@ -54,7 +54,7 @@ struct iter_donotq {
|
||||
/** 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,10 +62,10 @@ 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;
|
||||
|
||||
+2
-2
@@ -228,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;
|
||||
verbose(VERB_DETAIL, "Forward zone server list:");
|
||||
delegpt_log(VERB_DETAIL, dp);
|
||||
verbose(VERB_QUERY, "Forward zone server list:");
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ 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(VERB_DETAIL, dp);
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
verbose(VERB_DETAIL, "Reading root hints from %s", fname);
|
||||
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);
|
||||
@@ -391,7 +391,7 @@ read_root_hints(struct iter_hints* hints, char* fname)
|
||||
if(!hints_insert(hints, c, dp)) {
|
||||
return 0;
|
||||
}
|
||||
delegpt_log(VERB_DETAIL, dp);
|
||||
delegpt_log(VERB_QUERY, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,12 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg)
|
||||
for(p = cfg->root_hints; p; p = p->next) {
|
||||
log_assert(p->str);
|
||||
if(p->str && p->str[0]) {
|
||||
if(!read_root_hints(hints, p->str))
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -434,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(VERB_DETAIL, dp);
|
||||
}
|
||||
|
||||
init_parents(hints);
|
||||
|
||||
+11
-3
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -459,7 +467,7 @@ store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
|
||||
struct ub_packed_rrset_key* k;
|
||||
struct packed_rrset_data* d;
|
||||
struct rrset_ref ref;
|
||||
uint32_t now = time(NULL);
|
||||
uint32_t now = *env->now;
|
||||
|
||||
k = alloc_special_obtain(env->alloc);
|
||||
if(!k)
|
||||
|
||||
@@ -102,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)
|
||||
@@ -130,7 +130,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
/** filter out unsuitable targets, return rtt or -1 */
|
||||
static int
|
||||
iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
uint8_t* name, size_t namelen, time_t now, struct delegpt_addr* a)
|
||||
uint8_t* name, size_t namelen, uint32_t now, struct delegpt_addr* a)
|
||||
{
|
||||
int rtt;
|
||||
int lame;
|
||||
@@ -160,7 +160,7 @@ 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, uint32_t now, struct delegpt* dp,
|
||||
int* best_rtt)
|
||||
{
|
||||
int got_num = 0, got_rtt = 0, thisrtt, swap_to_front;
|
||||
@@ -211,12 +211,11 @@ iter_server_selection(struct iter_env* iter_env,
|
||||
struct module_env* env, struct delegpt* dp,
|
||||
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,
|
||||
&selrtt);
|
||||
int num = iter_filter_order(iter_env, env, name, namelen,
|
||||
*env->now, dp, &selrtt);
|
||||
|
||||
if(num == 0)
|
||||
return NULL;
|
||||
@@ -313,7 +312,7 @@ 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(
|
||||
fptr_ok(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);
|
||||
@@ -331,7 +330,7 @@ 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 some of the cycles)",
|
||||
ns->name, LDNS_RR_TYPE_A,
|
||||
|
||||
+66
-52
@@ -80,7 +80,7 @@ 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);
|
||||
@@ -188,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(VERB_ALGO, super_iq->dp);
|
||||
if(super_iq->dp)
|
||||
delegpt_log(VERB_ALGO, super_iq->dp);
|
||||
log_assert(0);
|
||||
return;
|
||||
}
|
||||
@@ -215,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;
|
||||
@@ -224,6 +225,23 @@ 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,
|
||||
@@ -253,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,
|
||||
@@ -433,7 +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));
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, &subq)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -446,7 +469,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
sizeof(struct iter_qstate));
|
||||
if(!subq->minfo[id]) {
|
||||
log_err("init subq: out of memory");
|
||||
log_assert(fptr_whitelist_modenv_kill_sub(
|
||||
fptr_ok(fptr_whitelist_modenv_kill_sub(
|
||||
qstate->env->kill_sub));
|
||||
(*qstate->env->kill_sub)(subq);
|
||||
return 0;
|
||||
@@ -480,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);
|
||||
@@ -564,7 +587,7 @@ 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(
|
||||
fptr_ok(fptr_whitelist_modenv_kill_sub(
|
||||
qstate->env->kill_sub));
|
||||
(*qstate->env->kill_sub)(subq);
|
||||
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
@@ -639,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);
|
||||
}
|
||||
@@ -650,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);
|
||||
}
|
||||
@@ -736,7 +759,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* 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));
|
||||
qstate->region, &iq->deleg_msg, *qstate->env->now);
|
||||
|
||||
/* If the cache has returned nothing, then we have a
|
||||
* root priming situation. */
|
||||
@@ -769,7 +792,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
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);
|
||||
@@ -802,17 +825,6 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
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. */
|
||||
if(qstate->query_flags & BIT_RD)
|
||||
iq->chase_flags |= BIT_RD;
|
||||
else iq->chase_flags &= ~BIT_RD;
|
||||
|
||||
/* Otherwise, set the current delegation point and move on to the
|
||||
* next state. */
|
||||
return next_state(iq, INIT_REQUEST_2_STATE);
|
||||
@@ -838,7 +850,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. */
|
||||
@@ -865,11 +877,16 @@ 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 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);
|
||||
|
||||
/* If the RD flag wasn't set, then we just finish with the
|
||||
* cached referral as the response. */
|
||||
if(!(iq->chase_flags & BIT_RD)) {
|
||||
if(!(qstate->query_flags & BIT_RD)) {
|
||||
iq->response = iq->deleg_msg;
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("no RD requested, using delegation msg",
|
||||
@@ -915,7 +932,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;
|
||||
}
|
||||
|
||||
@@ -1029,7 +1046,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);
|
||||
@@ -1038,7 +1055,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);
|
||||
}
|
||||
@@ -1046,7 +1063,7 @@ 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(VERB_ALGO, iq->dp);
|
||||
@@ -1114,7 +1131,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. */
|
||||
@@ -1141,18 +1158,19 @@ 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));
|
||||
fptr_ok(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(0, "error for address:",
|
||||
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);
|
||||
}
|
||||
@@ -1222,7 +1240,7 @@ 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(
|
||||
fptr_ok(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
@@ -1260,7 +1278,7 @@ 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(
|
||||
fptr_ok(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
@@ -1302,7 +1320,7 @@ 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(
|
||||
fptr_ok(fptr_whitelist_modenv_detach_subs(
|
||||
qstate->env->detach_subs));
|
||||
(*qstate->env->detach_subs)(qstate);
|
||||
iq->num_target_queries = 0;
|
||||
@@ -1318,8 +1336,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* 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),
|
||||
dnsseclame))
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
*qstate->env->now, dnsseclame))
|
||||
log_err("mark host lame: out of memory");
|
||||
} else log_err("%slame response from cache",
|
||||
dnsseclame?"DNSSEC ":"");
|
||||
@@ -1505,7 +1523,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) {
|
||||
@@ -1548,11 +1566,6 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
}
|
||||
if(query_dname_compare(qstate->qinfo.qname,
|
||||
iq->response->qinfo.qname) == 0) {
|
||||
/* use server supplied upper/lower case */
|
||||
qstate->qinfo.qname = iq->response->qinfo.qname;
|
||||
}
|
||||
qstate->return_rcode = LDNS_RCODE_NOERROR;
|
||||
qstate->return_msg = iq->response;
|
||||
return 0;
|
||||
@@ -1704,7 +1717,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,
|
||||
@@ -1721,12 +1735,12 @@ iter_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
{
|
||||
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 */
|
||||
@@ -1740,11 +1754,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;
|
||||
}
|
||||
|
||||
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,934 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
(*res)->answer_packet = q->msg;
|
||||
(*res)->answer_len = (int)q->msg_len;
|
||||
q->msg = NULL;
|
||||
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;
|
||||
ub_resolve_free(*res);
|
||||
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);
|
||||
free(msg);
|
||||
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;
|
||||
}
|
||||
q->res->answer_packet = q->msg;
|
||||
q->res->answer_len = (int)q->msg_len;
|
||||
q->msg = NULL;
|
||||
*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--;
|
||||
msg = context_serialize_cancel(q, &len);
|
||||
context_query_delete(q);
|
||||
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->answer_packet);
|
||||
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 == '\n' || *parse == 0)
|
||||
continue;
|
||||
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,468 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The DNS answer packet. Network formatted. Can contain DNSSEC types.
|
||||
*/
|
||||
void* answer_packet;
|
||||
/** length of the answer packet in octets. */
|
||||
int answer_len;
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
+9
-1
@@ -146,7 +146,9 @@ if test -z "$LDNSDIR"; then
|
||||
# try to autodetect from Makefile (if present)
|
||||
if test -f Makefile; then
|
||||
eval `grep 'ldnsdir=' Makefile`
|
||||
LDNSDIR="$ldnsdir"
|
||||
if echo "$ldnsdir" | grep -v ldns-src/ >/dev/null 2>&1; then
|
||||
LDNSDIR="$ldnsdir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -182,6 +184,7 @@ flex -i -t util/configlexer.lex >> util/configlexer.c || error_cleanup "Failed
|
||||
bison -y -d -o util/configparser.c util/configparser.y || error_cleanup "Failed to create configparser"
|
||||
|
||||
# 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
|
||||
@@ -190,6 +193,7 @@ if test ! -z "$LDNSDIR"; then
|
||||
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 {} \;
|
||||
@@ -209,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
+8
-9
@@ -52,7 +52,7 @@
|
||||
/** store rrsets in the rrset cache.
|
||||
* @param env: module environment with caches.
|
||||
* @param rep: contains list of rrsets to store.
|
||||
* @param now: current time(NULL).
|
||||
* @param now: current time.
|
||||
*/
|
||||
static void
|
||||
store_rrsets(struct module_env* env, struct reply_info* rep, uint32_t now)
|
||||
@@ -73,7 +73,7 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
hashvalue_t hash, struct reply_info* rep)
|
||||
{
|
||||
struct msgreply_entry* e;
|
||||
uint32_t now = time(NULL), ttl = rep->ttl;
|
||||
uint32_t ttl = rep->ttl;
|
||||
size_t i;
|
||||
|
||||
/* store RRsets */
|
||||
@@ -82,8 +82,8 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
|
||||
rep->ref[i].id = rep->rrsets[i]->id;
|
||||
}
|
||||
reply_info_sortref(rep);
|
||||
reply_info_set_ttls(rep, now);
|
||||
store_rrsets(env, rep, now);
|
||||
reply_info_set_ttls(rep, *env->now);
|
||||
store_rrsets(env, rep, *env->now);
|
||||
if(ttl == 0) {
|
||||
/* we do not store the message, but we did store the RRs,
|
||||
* which could be useful for delegation information */
|
||||
@@ -219,7 +219,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
{
|
||||
struct delegpt_ns* ns;
|
||||
struct ub_packed_rrset_key* akey;
|
||||
uint32_t now = time(NULL);
|
||||
uint32_t now = *env->now;
|
||||
for(ns = dp->nslist; ns; ns = ns->next) {
|
||||
if(ns->resolved)
|
||||
continue;
|
||||
@@ -543,7 +543,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
struct lruhash_entry* e;
|
||||
struct query_info k;
|
||||
hashvalue_t h;
|
||||
uint32_t now = (uint32_t)time(NULL);
|
||||
uint32_t now = *env->now;
|
||||
struct ub_packed_rrset_key* rrset;
|
||||
|
||||
/* lookup first, this has both NXdomains and ANSWER responses */
|
||||
@@ -630,16 +630,15 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
|
||||
if(is_referral) {
|
||||
/* store rrsets */
|
||||
struct rrset_ref ref;
|
||||
uint32_t now = time(NULL);
|
||||
size_t i;
|
||||
for(i=0; i<rep->rrset_count; i++) {
|
||||
packed_rrset_ttl_add((struct packed_rrset_data*)
|
||||
rep->rrsets[i]->entry.data, now);
|
||||
rep->rrsets[i]->entry.data, *env->now);
|
||||
ref.key = rep->rrsets[i];
|
||||
ref.id = rep->rrsets[i]->id;
|
||||
/*ignore ret: it was in the cache, ref updated */
|
||||
(void)rrset_cache_update(env->rrset_cache, &ref,
|
||||
env->alloc, now);
|
||||
env->alloc, *env->now);
|
||||
}
|
||||
free(rep);
|
||||
return 1;
|
||||
|
||||
Vendored
-2
@@ -137,6 +137,4 @@ struct dns_msg* dns_cache_lookup(struct module_env* env,
|
||||
int cache_fill_missing(struct module_env* env, uint16_t qclass,
|
||||
struct regional* region, struct delegpt* dp);
|
||||
|
||||
/** Find covering DNAME */
|
||||
|
||||
#endif /* SERVICES_CACHE_DNS_H */
|
||||
|
||||
Vendored
+10
-12
@@ -64,12 +64,11 @@ infra_host_compfunc(void* key1, void* key2)
|
||||
}
|
||||
|
||||
void
|
||||
infra_host_delkeyfunc(void* k, void* ATTR_UNUSED(arg), int il)
|
||||
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);
|
||||
}
|
||||
@@ -159,7 +158,7 @@ infra_lookup_host_nottl(struct infra_cache* infra,
|
||||
struct infra_host_data*
|
||||
infra_lookup_host(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int wr,
|
||||
time_t timenow, struct infra_host_key** key)
|
||||
uint32_t timenow, struct infra_host_key** key)
|
||||
{
|
||||
struct infra_host_data* data;
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
@@ -187,7 +186,7 @@ infra_lookup_host(struct infra_cache* infra,
|
||||
*/
|
||||
static struct lruhash_entry*
|
||||
new_host_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, time_t tm)
|
||||
socklen_t addrlen, uint32_t tm)
|
||||
{
|
||||
struct infra_host_data* data;
|
||||
struct infra_host_key* key = (struct infra_host_key*)malloc(
|
||||
@@ -215,7 +214,7 @@ new_host_entry(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
|
||||
int
|
||||
infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, time_t timenow, int* edns_vs, int* to)
|
||||
socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
addrlen, 0);
|
||||
@@ -261,7 +260,7 @@ hash_lameness(uint8_t* name, size_t namelen)
|
||||
|
||||
int
|
||||
infra_lookup_lame(struct infra_host_data* host,
|
||||
uint8_t* name, size_t namelen, time_t timenow)
|
||||
uint8_t* name, size_t namelen, uint32_t timenow)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
struct infra_lame_key k;
|
||||
@@ -309,12 +308,11 @@ infra_lame_compfunc(void* key1, void* key2)
|
||||
}
|
||||
|
||||
void
|
||||
infra_lame_delkeyfunc(void* k, void* ATTR_UNUSED(arg), int il)
|
||||
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);
|
||||
@@ -331,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, int dnsseclame)
|
||||
uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame)
|
||||
{
|
||||
struct infra_host_data* data;
|
||||
struct lruhash_entry* e;
|
||||
@@ -424,7 +422,7 @@ infra_update_tcp_works(struct infra_cache* infra,
|
||||
int
|
||||
infra_rtt_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int roundtrip, time_t timenow)
|
||||
int roundtrip, uint32_t timenow)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
addrlen, 1);
|
||||
@@ -454,7 +452,7 @@ infra_rtt_update(struct infra_cache* infra,
|
||||
int
|
||||
infra_edns_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int edns_version, time_t timenow)
|
||||
int edns_version, uint32_t timenow)
|
||||
{
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
addrlen, 1);
|
||||
@@ -480,7 +478,7 @@ 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* dnsseclame,
|
||||
int* rtt, time_t timenow)
|
||||
int* rtt, uint32_t timenow)
|
||||
{
|
||||
struct infra_host_data* host;
|
||||
struct lruhash_entry* e = infra_lookup_host_nottl(infra, addr,
|
||||
|
||||
Vendored
+11
-11
@@ -63,7 +63,7 @@ struct infra_host_key {
|
||||
*/
|
||||
struct infra_host_data {
|
||||
/** TTL value for this entry. absolute time. */
|
||||
time_t ttl;
|
||||
uint32_t ttl;
|
||||
/** round trip times for timeout calculation */
|
||||
struct rtt_info rtt;
|
||||
/** Names of the zones that are lame. NULL=no lame zones. */
|
||||
@@ -90,7 +90,7 @@ struct infra_lame_key {
|
||||
*/
|
||||
struct infra_lame_data {
|
||||
/** TTL of this entry. absolute time. */
|
||||
time_t ttl;
|
||||
uint32_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;
|
||||
@@ -151,7 +151,7 @@ struct infra_cache* infra_adjust(struct infra_cache* infra,
|
||||
*/
|
||||
struct infra_host_data* infra_lookup_host(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int wr,
|
||||
time_t timenow, struct infra_host_key** key);
|
||||
uint32_t timenow, struct infra_host_key** key);
|
||||
|
||||
/**
|
||||
* Find host information to send a packet. Creates new entry if not found.
|
||||
@@ -166,7 +166,7 @@ struct infra_host_data* infra_lookup_host(struct infra_cache* infra,
|
||||
* @return: 0 on error.
|
||||
*/
|
||||
int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, time_t timenow, int* edns_vs, int* to);
|
||||
socklen_t addrlen, uint32_t timenow, int* edns_vs, int* to);
|
||||
|
||||
/**
|
||||
* Check for lameness of this server for a particular zone.
|
||||
@@ -178,7 +178,7 @@ int infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
|
||||
* @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);
|
||||
uint8_t* name, size_t namelen, uint32_t timenow);
|
||||
|
||||
/**
|
||||
* Set a host to be lame for the given zone.
|
||||
@@ -194,7 +194,7 @@ int infra_lookup_lame(struct infra_host_data* host,
|
||||
*/
|
||||
int infra_set_lame(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, time_t timenow, int dnsseclame);
|
||||
uint8_t* name, size_t namelen, uint32_t timenow, int dnsseclame);
|
||||
|
||||
/**
|
||||
* Update rtt information for the host.
|
||||
@@ -208,7 +208,7 @@ int infra_set_lame(struct infra_cache* infra,
|
||||
*/
|
||||
int infra_rtt_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int roundtrip, time_t timenow);
|
||||
int roundtrip, uint32_t timenow);
|
||||
|
||||
/**
|
||||
* Update information for the host, store that a TCP transaction works.
|
||||
@@ -230,7 +230,7 @@ void infra_update_tcp_works(struct infra_cache* infra,
|
||||
*/
|
||||
int infra_edns_update(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
int edns_version, time_t timenow);
|
||||
int edns_version, uint32_t timenow);
|
||||
|
||||
/**
|
||||
* Get Lameness information and average RTT if host is in the cache.
|
||||
@@ -250,7 +250,7 @@ int infra_edns_update(struct infra_cache* infra,
|
||||
int infra_get_lame_rtt(struct infra_cache* infra,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen,
|
||||
uint8_t* name, size_t namelen, int* lame, int* dnsseclame,
|
||||
int* rtt, time_t timenow);
|
||||
int* rtt, uint32_t timenow);
|
||||
|
||||
/**
|
||||
* Get memory used by the infra cache.
|
||||
@@ -267,7 +267,7 @@ size_t infra_host_sizefunc(void* k, void* d);
|
||||
int infra_host_compfunc(void* key1, void* key2);
|
||||
|
||||
/** delete key, and destroy the lock */
|
||||
void infra_host_delkeyfunc(void* k, void* arg, int il);
|
||||
void infra_host_delkeyfunc(void* k, void* arg);
|
||||
|
||||
/** delete data and destroy the lameness hashtable */
|
||||
void infra_host_deldatafunc(void* d, void* arg);
|
||||
@@ -280,7 +280,7 @@ size_t infra_lame_sizefunc(void* k, void* d);
|
||||
int infra_lame_compfunc(void* key1, void* key2);
|
||||
|
||||
/** free key, lock and zonename */
|
||||
void infra_lame_delkeyfunc(void* k, void* arg, int il);
|
||||
void infra_lame_delkeyfunc(void* k, void* arg);
|
||||
|
||||
/** free the lameness data */
|
||||
void infra_lame_deldatafunc(void* d, void* arg);
|
||||
|
||||
Vendored
+11
-4
@@ -47,6 +47,13 @@
|
||||
#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,
|
||||
@@ -300,9 +309,8 @@ rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch,
|
||||
|
||||
void
|
||||
rrset_update_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now)
|
||||
{
|
||||
uint32_t now = (uint32_t)time(0);
|
||||
struct packed_rrset_data* updata =
|
||||
(struct packed_rrset_data*)rrset->entry.data;
|
||||
struct lruhash_entry* e;
|
||||
@@ -330,9 +338,8 @@ rrset_update_sec_status(struct rrset_cache* r,
|
||||
|
||||
void
|
||||
rrset_check_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now)
|
||||
{
|
||||
uint32_t now = (uint32_t)time(0);
|
||||
struct packed_rrset_data* updata =
|
||||
(struct packed_rrset_data*)rrset->entry.data;
|
||||
struct lruhash_entry* e;
|
||||
|
||||
Vendored
+7
-2
@@ -192,9 +192,10 @@ void rrset_array_unlock_touch(struct rrset_cache* r, struct regional* scratch,
|
||||
* @param r: the rrset cache.
|
||||
* @param rrset: which rrset to attempt to update. This rrset is left
|
||||
* untouched. The rrset in the cache is updated in-place.
|
||||
* @param now: current time.
|
||||
*/
|
||||
void rrset_update_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now);
|
||||
|
||||
/**
|
||||
* Looks up security status of an rrset. Looks up the rrset.
|
||||
@@ -203,8 +204,12 @@ void rrset_update_sec_status(struct rrset_cache* r,
|
||||
* @param r: the rrset cache.
|
||||
* @param rrset: This rrset may change security status due to the cache.
|
||||
* But its status will only improve, towards secure.
|
||||
* @param now: current time.
|
||||
*/
|
||||
void rrset_check_sec_status(struct rrset_cache* r,
|
||||
struct ub_packed_rrset_key* rrset);
|
||||
struct ub_packed_rrset_key* rrset, uint32_t now);
|
||||
|
||||
/** mark rrset to be deleted, set id=0 */
|
||||
void rrset_markdel(void* key);
|
||||
|
||||
#endif /* SERVICES_CACHE_RRSET_H */
|
||||
|
||||
+112
-29
@@ -86,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) {
|
||||
@@ -99,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)
|
||||
@@ -135,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)
|
||||
@@ -158,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",
|
||||
@@ -166,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));
|
||||
@@ -192,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;
|
||||
@@ -204,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;
|
||||
}
|
||||
@@ -214,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));
|
||||
@@ -226,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.
|
||||
@@ -242,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;
|
||||
}
|
||||
@@ -306,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);
|
||||
@@ -383,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;
|
||||
|
||||
@@ -405,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("::1", 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;
|
||||
@@ -417,7 +499,8 @@ listening_ports_open(struct config_file* cfg)
|
||||
}
|
||||
if(do_ip4) {
|
||||
hints.ai_family = AF_INET;
|
||||
if(!ports_create_if("127.0.0.1", 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;
|
||||
@@ -428,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;
|
||||
@@ -437,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 */
|
||||
+199
-55
@@ -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,12 +155,12 @@ 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)) {
|
||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) {
|
||||
log_err("mesh_new_client: out of memory; SERVFAIL");
|
||||
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, qid, qflags, edns);
|
||||
@@ -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)
|
||||
{
|
||||
@@ -237,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;
|
||||
}
|
||||
@@ -253,9 +297,9 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
return;
|
||||
/* de-init modules */
|
||||
mesh = mstate->s.env->mesh;
|
||||
for(i=0; i<mesh->num_modules; i++) {
|
||||
log_assert(fptr_whitelist_mod_clear(mesh->modfunc[i]->clear));
|
||||
(*mesh->modfunc[i]->clear)(&mstate->s, i);
|
||||
for(i=0; i<mesh->mods.num; i++) {
|
||||
fptr_ok(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;
|
||||
}
|
||||
@@ -273,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--;
|
||||
}
|
||||
@@ -301,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);
|
||||
@@ -336,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--;
|
||||
@@ -415,18 +461,63 @@ 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.
|
||||
* @param rcode: if not 0, error code.
|
||||
* @param rep: reply to send (or NULL if rcode is set).
|
||||
* @param r: reply entry
|
||||
* @param prev: previous reply, already has its answer encoded in buffer.
|
||||
*/
|
||||
static void
|
||||
mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
struct mesh_reply* r)
|
||||
struct mesh_reply* r, struct mesh_reply* prev)
|
||||
{
|
||||
struct timeval end_time;
|
||||
struct timeval duration;
|
||||
int secure;
|
||||
/* examine security status */
|
||||
if(m->s.env->need_to_validate && !(r->qflags&BIT_CD) && rep &&
|
||||
@@ -436,8 +527,24 @@ 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) {
|
||||
if(prev && prev->qflags == r->qflags &&
|
||||
prev->edns.edns_present == r->edns.edns_present &&
|
||||
prev->edns.bits == r->edns.bits &&
|
||||
prev->edns.udp_size == r->edns.udp_size) {
|
||||
/* if the previous reply is identical to this one, fix ID */
|
||||
if(prev->query_reply.c->buffer != r->query_reply.c->buffer)
|
||||
ldns_buffer_copy(r->query_reply.c->buffer,
|
||||
prev->query_reply.c->buffer);
|
||||
ldns_buffer_write_at(r->query_reply.c->buffer, 0,
|
||||
&r->qid, sizeof(uint16_t));
|
||||
ldns_buffer_write_at(r->query_reply.c->buffer, 12,
|
||||
r->qname, m->s.qinfo.qname_len);
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
} else if(rcode) {
|
||||
m->s.qinfo.qname = r->qname;
|
||||
error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
|
||||
r->qid, r->qflags, &r->edns);
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
@@ -447,6 +554,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
r->edns.ext_rcode = 0;
|
||||
r->edns.bits &= EDNS_DO;
|
||||
m->s.qinfo.qname = r->qname;
|
||||
if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
|
||||
r->qflags, r->query_reply.c->buffer, 0, 1,
|
||||
m->s.env->scratch, udp_size, &r->edns,
|
||||
@@ -460,27 +568,28 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
}
|
||||
/* account */
|
||||
m->s.env->mesh->num_reply_addrs--;
|
||||
if(gettimeofday(&end_time, NULL) < 0) {
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
return;
|
||||
} else {
|
||||
struct timeval duration;
|
||||
timeval_subtract(&duration, &end_time, &r->start_time);
|
||||
verbose(VERB_ALGO, "query took %d.%6.6d sec",
|
||||
(int)duration.tv_sec, (int)duration.tv_usec);
|
||||
m->s.env->mesh->replies_sent++;
|
||||
timeval_add(&m->s.env->mesh->replies_sum_wait, &duration);
|
||||
timehist_insert(m->s.env->mesh->histogram, &duration);
|
||||
}
|
||||
end_time = *m->s.env->now_tv;
|
||||
timeval_subtract(&duration, &end_time, &r->start_time);
|
||||
verbose(VERB_ALGO, "query took %d.%6.6d sec",
|
||||
(int)duration.tv_sec, (int)duration.tv_usec);
|
||||
m->s.env->mesh->replies_sent++;
|
||||
timeval_add(&m->s.env->mesh->replies_sum_wait, &duration);
|
||||
timehist_insert(m->s.env->mesh->histogram, &duration);
|
||||
}
|
||||
|
||||
void mesh_query_done(struct mesh_state* mstate)
|
||||
{
|
||||
struct mesh_reply* r;
|
||||
struct mesh_reply* prev = NULL;
|
||||
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);
|
||||
mesh_send_reply(mstate, mstate->s.return_rcode, rep, r, prev);
|
||||
prev = r;
|
||||
}
|
||||
for(c = mstate->cb_list; c; c = c->next) {
|
||||
mesh_do_callback(mstate, mstate->s.return_rcode, rep, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,9 +601,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 */
|
||||
log_assert(fptr_whitelist_mod_inform_super(
|
||||
mesh->modfunc[ref->s->s.curmod]->inform_super));
|
||||
(*mesh->modfunc[ref->s->s.curmod]->inform_super)(&mstate->s,
|
||||
fptr_ok(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);
|
||||
}
|
||||
}
|
||||
@@ -514,8 +623,28 @@ 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 comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname)
|
||||
{
|
||||
struct mesh_reply* r = regional_alloc(s->s.region,
|
||||
sizeof(struct mesh_reply));
|
||||
@@ -525,11 +654,12 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
r->edns = *edns;
|
||||
r->qid = qid;
|
||||
r->qflags = qflags;
|
||||
if(gettimeofday(&r->start_time, NULL) < 0) {
|
||||
log_err("addrep: gettimeofday: %s", strerror(errno));
|
||||
memset(&r->start_time, 0, sizeof(r->start_time));
|
||||
}
|
||||
r->start_time = *s->s.env->now_tv;
|
||||
r->next = s->reply_list;
|
||||
r->qname = regional_alloc_init(s->s.region, qname,
|
||||
s->s.qinfo.qname_len);
|
||||
if(!r->qname)
|
||||
return 0;
|
||||
s->reply_list = r;
|
||||
return 1;
|
||||
|
||||
@@ -558,16 +688,16 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
if(mstate->num_activated > MESH_MAX_ACTIVATION) {
|
||||
/* module is looping. Stop it. */
|
||||
log_err("internal error: looping module stopped");
|
||||
log_query_info(VERB_DETAIL, "pass error for qstate",
|
||||
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);
|
||||
mstate->s.curmod--;
|
||||
return mesh_continue(mesh, mstate, module_error, ev);
|
||||
@@ -601,9 +731,9 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
verbose(VERB_ALGO, "mesh_run: start");
|
||||
while(mstate) {
|
||||
/* run the module */
|
||||
log_assert(fptr_whitelist_mod_operate(
|
||||
mesh->modfunc[mstate->s.curmod]->operate));
|
||||
(*mesh->modfunc[mstate->s.curmod]->operate)
|
||||
fptr_ok(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 */
|
||||
@@ -611,7 +741,7 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
|
||||
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;
|
||||
@@ -637,13 +767,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);
|
||||
}
|
||||
}
|
||||
@@ -651,23 +783,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)
|
||||
{
|
||||
|
||||
+83
-10
@@ -50,8 +50,10 @@
|
||||
#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;
|
||||
@@ -67,10 +69,8 @@ struct timehist;
|
||||
* 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;
|
||||
|
||||
@@ -117,6 +117,8 @@ 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;
|
||||
@@ -154,20 +156,49 @@ struct mesh_reply {
|
||||
uint16_t qid;
|
||||
/** flags of query, for reply flags */
|
||||
uint16_t qflags;
|
||||
/** qname from this query. len same as mesh qinfo. */
|
||||
uint8_t* qname;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -191,6 +222,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
|
||||
@@ -327,10 +377,27 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub);
|
||||
* @param rep: comm point reply info.
|
||||
* @param qid: ID of reply.
|
||||
* @param qflags: original query flags.
|
||||
* @param qname: original query name.
|
||||
* @return: 0 on alloc error.
|
||||
*/
|
||||
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags);
|
||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags, uint8_t* qname);
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -351,6 +418,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.
|
||||
|
||||
@@ -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);
|
||||
fptr_ok(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++) {
|
||||
fptr_ok(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 */
|
||||
+164
-39
@@ -46,6 +46,7 @@
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/netevent.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
@@ -91,14 +92,19 @@ serviced_cmp(const void* key1, const void* key2)
|
||||
if(q1->qbuflen > q2->qbuflen)
|
||||
return 1;
|
||||
log_assert(q1->qbuflen == q2->qbuflen);
|
||||
/* will not detect alternate casing of qname */
|
||||
if((r = memcmp(q1->qbuf, q2->qbuf, q1->qbuflen)) != 0)
|
||||
log_assert(q1->qbuflen >= 15 /* 10 header, root, type, class */);
|
||||
/* alternate casing of qname is still the same query */
|
||||
if((r = memcmp(q1->qbuf, q2->qbuf, 10)) != 0)
|
||||
return r;
|
||||
if((r = memcmp(q1->qbuf+q1->qbuflen-4, q2->qbuf+q2->qbuflen-4, 4)) != 0)
|
||||
return r;
|
||||
if(q1->dnssec != q2->dnssec) {
|
||||
if(q1->dnssec < q2->dnssec)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
if((r = query_dname_compare(q1->qbuf+10, q2->qbuf+10)) != 0)
|
||||
return r;
|
||||
return sockaddr_cmp(&q1->addr, q1->addrlen, &q2->addr, q2->addrlen);
|
||||
}
|
||||
|
||||
@@ -150,6 +156,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);
|
||||
@@ -173,7 +181,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));
|
||||
fptr_ok(fptr_whitelist_pending_tcp(cb));
|
||||
(void)(*cb)(NULL, cb_arg, NETEVENT_CLOSED, NULL);
|
||||
}
|
||||
}
|
||||
@@ -200,19 +208,19 @@ 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(VERB_DETAIL,
|
||||
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));
|
||||
fptr_ok(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;
|
||||
@@ -228,11 +236,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);
|
||||
@@ -249,7 +257,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
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.");
|
||||
verbose(VERB_QUERY, "received unwanted or unsolicited udp reply dropped.");
|
||||
log_buf(VERB_ALGO, "dropped message", c->buffer);
|
||||
return 0;
|
||||
}
|
||||
@@ -257,7 +265,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "received udp reply.");
|
||||
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;
|
||||
}
|
||||
@@ -265,7 +273,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));
|
||||
fptr_ok(fptr_whitelist_pending_udp(p->cb));
|
||||
(void)(*p->cb)(p->c, p->cb_arg, NETEVENT_NOERROR, reply_info);
|
||||
pending_delete(NULL, p);
|
||||
return 0;
|
||||
@@ -286,6 +294,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) {
|
||||
@@ -295,7 +308,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;
|
||||
}
|
||||
@@ -380,7 +393,7 @@ 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));
|
||||
fptr_ok(fptr_whitelist_pending_udp(p->cb));
|
||||
(void)(*p->cb)(p->c, p->cb_arg, NETEVENT_TIMEOUT, NULL);
|
||||
pending_delete(p->outnet, p);
|
||||
}
|
||||
@@ -414,7 +427,7 @@ struct outside_network*
|
||||
outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, int port_base, size_t num_tcp, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd)
|
||||
struct ub_randstate* rnd, int use_caps_for_id)
|
||||
{
|
||||
struct outside_network* outnet = (struct outside_network*)
|
||||
calloc(1, sizeof(struct outside_network));
|
||||
@@ -423,11 +436,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
log_err("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
comm_base_timept(base, &outnet->now_secs, &outnet->now_tv);
|
||||
outnet->base = base;
|
||||
outnet->num_tcp = num_tcp;
|
||||
outnet->infra = infra;
|
||||
outnet->rnd = rnd;
|
||||
outnet->svcd_overhead = 0;
|
||||
outnet->use_caps_for_id = use_caps_for_id;
|
||||
#ifndef INET6
|
||||
do_ip6 = 0;
|
||||
#endif
|
||||
@@ -736,7 +751,7 @@ outnet_tcptimer(void* arg)
|
||||
cb = w->cb;
|
||||
cb_arg = w->cb_arg;
|
||||
waiting_tcp_delete(w);
|
||||
log_assert(fptr_whitelist_pending_tcp(cb));
|
||||
fptr_ok(fptr_whitelist_pending_tcp(cb));
|
||||
(void)(*cb)(NULL, cb_arg, NETEVENT_TIMEOUT, NULL);
|
||||
use_free_buffer(outnet);
|
||||
}
|
||||
@@ -904,10 +919,52 @@ serviced_delete(struct serviced_query* sq)
|
||||
serviced_node_del(&sq->node, NULL);
|
||||
}
|
||||
|
||||
/** perturb a dname capitalization randomly */
|
||||
static void
|
||||
serviced_perturb_qname(struct ub_randstate* rnd, uint8_t* qbuf, size_t len)
|
||||
{
|
||||
uint8_t lablen;
|
||||
uint8_t* d = qbuf + 10;
|
||||
long int random = 0;
|
||||
int bits = 0;
|
||||
log_assert(len >= 10 + 5 /* offset qname, root, qtype, qclass */);
|
||||
lablen = *d++;
|
||||
while(lablen) {
|
||||
while(lablen--) {
|
||||
/* only perturb A-Z, a-z */
|
||||
if(isalpha((int)*d)) {
|
||||
/* get a random bit */
|
||||
if(bits == 0) {
|
||||
random = ub_random(rnd);
|
||||
bits = 30;
|
||||
}
|
||||
if(random & 0x1) {
|
||||
*d = (uint8_t)toupper((int)*d);
|
||||
} else {
|
||||
*d = (uint8_t)tolower((int)*d);
|
||||
}
|
||||
random >>= 1;
|
||||
bits--;
|
||||
}
|
||||
d++;
|
||||
}
|
||||
lablen = *d++;
|
||||
}
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
char buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_str(qbuf+10, buf);
|
||||
verbose(VERB_ALGO, "qname perturbed to %s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
/** put serviced query into a buffer */
|
||||
static void
|
||||
serviced_encode(struct serviced_query* sq, ldns_buffer* buff, int with_edns)
|
||||
{
|
||||
/* if we are using 0x20 bits for ID randomness, perturb them */
|
||||
if(sq->outnet->use_caps_for_id) {
|
||||
serviced_perturb_qname(sq->outnet->rnd, sq->qbuf, sq->qbuflen);
|
||||
}
|
||||
/* generate query */
|
||||
ldns_buffer_clear(buff);
|
||||
ldns_buffer_write_u16(buff, 0); /* id placeholder */
|
||||
@@ -940,7 +997,7 @@ static int
|
||||
serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
|
||||
{
|
||||
int rtt, vs;
|
||||
time_t now = time(0);
|
||||
uint32_t now = *sq->outnet->now_secs;
|
||||
|
||||
if(!infra_host(sq->outnet->infra, &sq->addr, sq->addrlen, now, &vs,
|
||||
&rtt))
|
||||
@@ -951,10 +1008,7 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
|
||||
else sq->status = serviced_query_UDP;
|
||||
}
|
||||
serviced_encode(sq, buff, sq->status == serviced_query_UDP_EDNS);
|
||||
if(gettimeofday(&sq->last_sent_time, NULL) < 0) {
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
sq->last_sent_time = *sq->outnet->now_tv;
|
||||
verbose(VERB_ALGO, "serviced query UDP timeout=%d msec", rtt);
|
||||
sq->pending = pending_udp_query(sq->outnet, buff, &sq->addr,
|
||||
sq->addrlen, rtt, serviced_udp_callback, sq, sq->outnet->rnd);
|
||||
@@ -963,6 +1017,49 @@ serviced_udp_send(struct serviced_query* sq, ldns_buffer* buff)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** check that perturbed qname is identical */
|
||||
static int
|
||||
serviced_check_qname(ldns_buffer* pkt, uint8_t* qbuf, size_t qbuflen)
|
||||
{
|
||||
uint8_t* d1 = ldns_buffer_at(pkt, 12);
|
||||
uint8_t* d2 = qbuf+10;
|
||||
uint8_t len1, len2;
|
||||
int count = 0;
|
||||
log_assert(qbuflen >= 15 /* 10 header, root, type, class */);
|
||||
len1 = *d1++;
|
||||
len2 = *d2++;
|
||||
if(ldns_buffer_limit(pkt) < 12+1+4) /* packet too small for qname */
|
||||
return 0;
|
||||
while(len1 != 0 || len2 != 0) {
|
||||
if(LABEL_IS_PTR(len1)) {
|
||||
d1 = ldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
|
||||
if(d1 >= ldns_buffer_at(pkt, ldns_buffer_limit(pkt)))
|
||||
return 0;
|
||||
len1 = *d1++;
|
||||
if(count++ > MAX_COMPRESS_PTRS)
|
||||
return 0;
|
||||
continue;
|
||||
}
|
||||
if(d2 > qbuf+qbuflen)
|
||||
return 0;
|
||||
if(len1 != len2)
|
||||
return 0;
|
||||
if(len1 > LDNS_MAX_LABELLEN)
|
||||
return 0;
|
||||
log_assert(len1 <= LDNS_MAX_LABELLEN);
|
||||
log_assert(len2 <= LDNS_MAX_LABELLEN);
|
||||
log_assert(len1 == len2 && len1 != 0);
|
||||
/* compare the labels - bitwise identical */
|
||||
if(memcmp(d1, d2, len1) != 0)
|
||||
return 0;
|
||||
d1 += len1;
|
||||
d2 += len2;
|
||||
len1 = *d1++;
|
||||
len2 = *d2++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** call the callbacks for a serviced query */
|
||||
static void
|
||||
serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
|
||||
@@ -980,6 +1077,36 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
|
||||
log_assert(rem); /* should have been present */
|
||||
sq->to_be_deleted = 1;
|
||||
verbose(VERB_ALGO, "svcd callbacks start");
|
||||
if(sq->outnet->use_caps_for_id && error == NETEVENT_NOERROR && c) {
|
||||
/* noerror and nxdomain must have a qname in reply */
|
||||
if(ldns_buffer_read_u16_at(c->buffer, 4) == 0 &&
|
||||
(LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
||||
== LDNS_RCODE_NOERROR ||
|
||||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
|
||||
== LDNS_RCODE_NXDOMAIN)) {
|
||||
verbose(VERB_OPS, "no qname in reply to check 0x20ID");
|
||||
log_addr(VERB_OPS, "from server",
|
||||
&sq->addr, sq->addrlen);
|
||||
log_buf(VERB_OPS, "for packet", c->buffer);
|
||||
error = NETEVENT_CLOSED;
|
||||
c = NULL;
|
||||
} else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
|
||||
!serviced_check_qname(c->buffer, sq->qbuf,
|
||||
sq->qbuflen)) {
|
||||
verbose(VERB_OPS, "wrong 0x20-ID in reply qname, "
|
||||
"answer dropped");
|
||||
log_addr(VERB_OPS, "from server",
|
||||
&sq->addr, sq->addrlen);
|
||||
log_buf(VERB_OPS, "for packet", c->buffer);
|
||||
error = NETEVENT_CLOSED;
|
||||
c = NULL;
|
||||
} else {
|
||||
verbose(VERB_ALGO, "good 0x20-ID in reply qname");
|
||||
/* cleanup caps, prettier cache contents. */
|
||||
pkt_dname_tolower(c->buffer,
|
||||
ldns_buffer_at(c->buffer, 12));
|
||||
}
|
||||
}
|
||||
if(dobackup && c) {
|
||||
/* make a backup of the query, since the querystate processing
|
||||
* may send outgoing queries that overwrite the buffer.
|
||||
@@ -1001,7 +1128,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));
|
||||
fptr_ok(fptr_whitelist_serviced_query(p->cb));
|
||||
(void)(*p->cb)(c, p->cb_arg, error, rep);
|
||||
p = n;
|
||||
}
|
||||
@@ -1022,16 +1149,17 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply r2;
|
||||
sq->pending = NULL; /* removed after this callback */
|
||||
if(error != NETEVENT_NOERROR)
|
||||
log_addr(VERB_DETAIL, "tcp error for address",
|
||||
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 && LDNS_RCODE_WIRE(ldns_buffer_begin(
|
||||
c->buffer)) == LDNS_RCODE_FORMERR &&
|
||||
sq->status == serviced_query_TCP_EDNS) {
|
||||
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)))
|
||||
sq->addrlen, -1, *sq->outnet->now_secs))
|
||||
log_err("Out of memory caching no edns for host");
|
||||
sq->status = serviced_query_TCP;
|
||||
serviced_tcp_initiate(sq->outnet, sq, c->buffer);
|
||||
@@ -1055,7 +1183,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
|
||||
@@ -1071,19 +1199,15 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
{
|
||||
struct serviced_query* sq = (struct serviced_query*)arg;
|
||||
struct outside_network* outnet = sq->outnet;
|
||||
struct timeval now;
|
||||
struct timeval now = *sq->outnet->now_tv;
|
||||
int fallback_tcp = 0;
|
||||
if(gettimeofday(&now, NULL) < 0) {
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
/* this option does not need current time */
|
||||
error = NETEVENT_CLOSED;
|
||||
}
|
||||
|
||||
sq->pending = NULL; /* removed after callback */
|
||||
if(error == NETEVENT_TIMEOUT) {
|
||||
int rto = 0;
|
||||
sq->retry++;
|
||||
if(!(rto=infra_rtt_update(outnet->infra, &sq->addr, sq->addrlen,
|
||||
-1, (time_t)now.tv_sec)))
|
||||
-1, (uint32_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,
|
||||
@@ -1102,11 +1226,12 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
-1, (uint32_t)now.tv_sec)) {
|
||||
log_err("Out of memory caching no edns for host");
|
||||
}
|
||||
sq->status = serviced_query_UDP;
|
||||
@@ -1136,7 +1261,7 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
|
||||
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))
|
||||
roundtime, (uint32_t)now.tv_sec))
|
||||
log_err("out of memory noting rtt.");
|
||||
}
|
||||
serviced_callbacks(sq, error, c, rep);
|
||||
@@ -1170,7 +1295,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ struct infra_cache;
|
||||
struct outside_network {
|
||||
/** Base for select calls */
|
||||
struct comm_base* base;
|
||||
/** pointer to time in seconds */
|
||||
uint32_t* now_secs;
|
||||
/** pointer to time in microseconds */
|
||||
struct timeval* now_tv;
|
||||
|
||||
/** buffer shared by UDP connections, since there is only one
|
||||
datagram at any time. */
|
||||
@@ -67,6 +71,8 @@ struct outside_network {
|
||||
/** serviced_callbacks malloc overhead when processing multiple
|
||||
* identical serviced queries to the same server. */
|
||||
size_t svcd_overhead;
|
||||
/** use x20 bits to encode additional ID random bits */
|
||||
int use_caps_for_id;
|
||||
|
||||
/**
|
||||
* Array of udp comm point* that are used to listen to pending events.
|
||||
@@ -225,7 +231,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 */
|
||||
@@ -255,12 +263,14 @@ struct serviced_query {
|
||||
* @param num_tcp: number of outgoing tcp buffers to preallocate.
|
||||
* @param infra: pointer to infra cached used for serviced queries.
|
||||
* @param rnd: stored to create random numbers for serviced queries.
|
||||
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
|
||||
* @return: the new structure (with no pending answers) or NULL on error.
|
||||
*/
|
||||
struct outside_network* outside_network_create(struct comm_base* base,
|
||||
size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
|
||||
int do_ip4, int do_ip6, int port_base, size_t num_tcp,
|
||||
struct infra_cache* infra, struct ub_randstate* rnd);
|
||||
struct infra_cache* infra, struct ub_randstate* rnd,
|
||||
int use_caps_for_id);
|
||||
|
||||
/**
|
||||
* Delete outside_network structure.
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#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). */
|
||||
@@ -85,18 +86,58 @@ check_mod(struct config_file* cfg, struct module_func_block* fb)
|
||||
regional_destroy(env.scratch);
|
||||
}
|
||||
|
||||
/** check configuration for errors */
|
||||
/** check localzones */
|
||||
static void
|
||||
morechecks(struct config_file* cfg)
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
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,
|
||||
@@ -104,7 +145,56 @@ morechecks(struct config_file* cfg)
|
||||
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");
|
||||
@@ -115,6 +205,10 @@ morechecks(struct config_file* cfg)
|
||||
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",
|
||||
@@ -129,19 +223,26 @@ morechecks(struct config_file* cfg)
|
||||
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",
|
||||
fatal_exit("module conf '%s' is not known to work",
|
||||
cfg->module_conf);
|
||||
}
|
||||
|
||||
if(cfg->username && cfg->username[0]) {
|
||||
struct passwd *pwd;
|
||||
if((pwd = getpwnam(cfg->username)) == NULL)
|
||||
if(getpwnam(cfg->username) == NULL)
|
||||
fatal_exit("user '%s' does not exist.", cfg->username);
|
||||
endpwent();
|
||||
}
|
||||
|
||||
localzonechecks(cfg);
|
||||
}
|
||||
|
||||
/** check config file */
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* 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(" [-C configfile]\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(" -C config use the specified unbound.conf\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);
|
||||
}
|
||||
|
||||
/** print error if any */
|
||||
static void
|
||||
check_ub_res(int r)
|
||||
{
|
||||
if(r != 0) {
|
||||
fprintf(stderr, "error: %s\n", ub_strerror(r));
|
||||
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 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:C:")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
qclass = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
check_ub_res(ub_ctx_config(ctx, optarg));
|
||||
break;
|
||||
case 'd':
|
||||
debuglevel++;
|
||||
if(debuglevel < 2)
|
||||
debuglevel = 2; /* at least VERB_DETAIL */
|
||||
check_ub_res(ub_ctx_debuglevel(ctx, debuglevel));
|
||||
break;
|
||||
case 't':
|
||||
qtype = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verb++;
|
||||
break;
|
||||
case 'y':
|
||||
check_ub_res(ub_ctx_add_ta(ctx, optarg));
|
||||
break;
|
||||
case 'f':
|
||||
check_ub_res(ub_ctx_add_ta_file(ctx, optarg));
|
||||
break;
|
||||
case 'F':
|
||||
check_ub_res(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;
|
||||
}
|
||||
@@ -107,3 +107,56 @@ 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,485 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
if(result->answer_packet == NULL) {
|
||||
printf("%s: error result->answer_packet is NULL.\n",
|
||||
desc);
|
||||
exit(1);
|
||||
}
|
||||
if(result->answer_len != 54) {
|
||||
printf("%s: error result->answer_len 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);
|
||||
}
|
||||
if(i > 200) {
|
||||
async_ids[i-200]=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);
|
||||
ub_resolve_free(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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
+1052
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,13 @@
|
||||
|
||||
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 fwd_tcp_tc6.tpkg fwd_compress_c00c.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 speed_cache.tpkg'
|
||||
NEED_XXD='fwd_compress_c00c.tpkg'
|
||||
NEED_NC='fwd_compress_c00c.tpkg'
|
||||
|
||||
cd testdata;
|
||||
sh ../testcode/mini_tpkg.sh clean
|
||||
rm -f .perfstats.txt
|
||||
for test in `ls *.tpkg`; do
|
||||
SKIP=0
|
||||
if echo $NEED_SPLINT | grep $test >/dev/null; then
|
||||
@@ -43,3 +44,4 @@ for test in `ls *.tpkg`; do
|
||||
fi
|
||||
done
|
||||
sh ../testcode/mini_tpkg.sh report
|
||||
cat .perfstats.txt
|
||||
|
||||
+44
-11
@@ -592,6 +592,14 @@ comm_base_delete(struct comm_base* b)
|
||||
free(runtime);
|
||||
}
|
||||
|
||||
void
|
||||
comm_base_timept(struct comm_base* b, uint32_t** tt, struct timeval** tv)
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)b;
|
||||
*tt = &runtime->now_secs;
|
||||
*tv = &runtime->now_tv;
|
||||
}
|
||||
|
||||
void
|
||||
comm_base_dispatch(struct comm_base* b)
|
||||
{
|
||||
@@ -662,15 +670,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)
|
||||
{
|
||||
@@ -687,7 +686,7 @@ outside_network_create(struct comm_base* base, size_t bufsize,
|
||||
int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4),
|
||||
int ATTR_UNUSED(do_ip6), int ATTR_UNUSED(port_base),
|
||||
size_t ATTR_UNUSED(num_tcp), struct infra_cache* ATTR_UNUSED(infra),
|
||||
struct ub_randstate* ATTR_UNUSED(rnd))
|
||||
struct ub_randstate* ATTR_UNUSED(rnd), int ATTR_UNUSED(use_caps_for_id))
|
||||
{
|
||||
struct outside_network* outnet = calloc(1,
|
||||
sizeof(struct outside_network));
|
||||
@@ -863,7 +862,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;
|
||||
@@ -1005,6 +1004,12 @@ void comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
|
||||
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))
|
||||
{
|
||||
@@ -1035,6 +1040,12 @@ void comm_point_local_handle_callback(int ATTR_UNUSED(fd),
|
||||
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))
|
||||
@@ -1063,4 +1074,26 @@ int serviced_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
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 ***********/
|
||||
|
||||
@@ -0,0 +1,818 @@
|
||||
/*
|
||||
* testcode/harvest.c - debug program to get relevant data to a set of 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 downloads relevant DNS data to a set of queries.
|
||||
* This means that the queries are asked to root, TLD, SLD servers and
|
||||
* the results stored per zone.
|
||||
* The following data is pertinent:
|
||||
*
|
||||
* At each label:
|
||||
* SOA
|
||||
* NS
|
||||
* DNSKEY
|
||||
* DS
|
||||
* For the whole query:
|
||||
* the result.
|
||||
* For NS-records:
|
||||
* their label data
|
||||
* and the A and AAAA records for it.
|
||||
* (as if the name, with A and AAAA query type is in the list,
|
||||
* referred to as recursion depth+1)
|
||||
* Any NSEC, NSEC3, SOA records or additional data found in answers.
|
||||
*
|
||||
* All of this is data that would be encountered during an iterative lookup
|
||||
* for the queries in the list. It is saved to enable a replay of iterative
|
||||
* lookups for performance testing.
|
||||
*
|
||||
* A number of assumptions are made.
|
||||
* 1) configuration is correct.
|
||||
* The parent has the same NS records as the child.
|
||||
* All nameservers carry the same data.
|
||||
* 2) EDNS/nonEDNS responses and other behaviour is ignored.
|
||||
* Only the data is saved.
|
||||
* This creates a snapshot that represents the data as this resolver saw it.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <signal.h>
|
||||
#include "libunbound/unbound.h"
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
struct todo_item;
|
||||
struct labdata;
|
||||
|
||||
/** this represents the data that has been collected
|
||||
* as well as a todo list and some settings */
|
||||
struct harvest_data {
|
||||
/** the unbound context */
|
||||
struct ub_ctx* ctx;
|
||||
|
||||
/** a tree per label; thus this first one is one root entry,
|
||||
* that has a tree of TLD labels. Those have trees of SLD labels. */
|
||||
struct labdata* root;
|
||||
/** the original query list */
|
||||
struct todo_item* orig_list;
|
||||
/** the query list todo */
|
||||
struct todo_item* todo_list;
|
||||
/** last item in todo list */
|
||||
struct todo_item* todo_last;
|
||||
/** number of todo items */
|
||||
int numtodo;
|
||||
|
||||
/** where to store the results */
|
||||
char* resultdir;
|
||||
/** maximum recursion depth */
|
||||
int maxdepth;
|
||||
/** current recursion depth */
|
||||
int curdepth;
|
||||
|
||||
/** max depth of labels */
|
||||
int maxlabels;
|
||||
/** number of RRs stored */
|
||||
int num_rrs;
|
||||
/** number of zones written */
|
||||
int num_zones;
|
||||
};
|
||||
|
||||
/**
|
||||
* Todo item
|
||||
*/
|
||||
struct todo_item {
|
||||
/** the next item */
|
||||
struct todo_item* next;
|
||||
|
||||
/** query as rdf */
|
||||
ldns_rdf* qname;
|
||||
/** the query type */
|
||||
int qtype;
|
||||
/** query class */
|
||||
int qclass;
|
||||
|
||||
/** recursion depth of todo item (orig list is 0) */
|
||||
int depth;
|
||||
/** the label associated with the query */
|
||||
struct labdata* lab;
|
||||
};
|
||||
|
||||
/**
|
||||
* Every label has a sest of sublabels, that have sets of sublabels ...
|
||||
* Per label is stored also a set of data items, and todo information
|
||||
*/
|
||||
struct labdata {
|
||||
/** node in ldns rbtree */
|
||||
ldns_rbnode_t node;
|
||||
/** the name of this label */
|
||||
ldns_rdf* label;
|
||||
/** full name of point in domain tree */
|
||||
ldns_rdf* name;
|
||||
|
||||
/** parent in label tree (NULL for root) */
|
||||
struct labdata* parent;
|
||||
/** tree of sublabels (if any) */
|
||||
ldns_rbtree_t* sublabels;
|
||||
|
||||
/** list of RRs for this label */
|
||||
ldns_rr_list* rrlist;
|
||||
/** have queries for this label been queued */
|
||||
int done;
|
||||
};
|
||||
|
||||
/** usage information for harvest */
|
||||
static void usage(char* nm)
|
||||
{
|
||||
printf("usage: %s [options]\n", nm);
|
||||
printf("-f fnm query list to read from file\n");
|
||||
printf(" every line has format: qname qclass qtype\n");
|
||||
printf("-v verbose (-v -v even more)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** verbosity for harvest */
|
||||
static int hverb = 0;
|
||||
|
||||
/** exit with error */
|
||||
static void error_exit(char* str)
|
||||
{
|
||||
printf("error: %s\n", str);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** read a query file */
|
||||
static void
|
||||
qlist_read_file(struct harvest_data* data, char* fname)
|
||||
{
|
||||
char buf[1024];
|
||||
char nm[1024], cl[1024], tp[1024];
|
||||
int r;
|
||||
int num = 0;
|
||||
FILE* in = fopen(fname, "r");
|
||||
struct todo_item* t;
|
||||
if(!in) {
|
||||
perror(fname);
|
||||
error_exit("could not open file");
|
||||
}
|
||||
while(fgets(buf, (int)sizeof(buf), in)) {
|
||||
if(buf[0] == 0) continue;
|
||||
if(buf[0] == '\n') continue;
|
||||
/* allow some comments */
|
||||
if(buf[0] == ';') continue;
|
||||
if(buf[0] == '#') continue;
|
||||
nm[0] = 0; cl[0] = 0; tp[0] = 0;
|
||||
r = sscanf(buf, " %1023s %1023s %1023s", nm, cl, tp);
|
||||
if(r == 0) continue;
|
||||
t = (struct todo_item*)calloc(1, sizeof(*t));
|
||||
if(!t) error_exit("out of memory");
|
||||
t->qname = ldns_dname_new_frm_str(nm);
|
||||
if(!t->qname) {
|
||||
printf("parse error: %s\n", nm);
|
||||
error_exit("bad qname");
|
||||
}
|
||||
t->depth = 0;
|
||||
t->qtype = LDNS_RR_TYPE_A;
|
||||
t->qclass = LDNS_RR_CLASS_IN;
|
||||
if(r >= 2) {
|
||||
if(strcmp(cl, "IN") == 0 || strcmp(cl, "CH") == 0)
|
||||
t->qclass = ldns_get_rr_class_by_name(cl);
|
||||
else t->qtype = ldns_get_rr_type_by_name(cl);
|
||||
}
|
||||
if(r >= 3) {
|
||||
if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0)
|
||||
t->qclass = ldns_get_rr_class_by_name(tp);
|
||||
else t->qtype = ldns_get_rr_type_by_name(tp);
|
||||
}
|
||||
num++;
|
||||
|
||||
t->next = data->orig_list;
|
||||
data->orig_list = t;
|
||||
}
|
||||
printf("read %s: %d queries\n", fname, num);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/** compare two labels */
|
||||
static int
|
||||
lab_cmp(const void *x, const void *y)
|
||||
{
|
||||
return ldns_dname_compare((const ldns_rdf*)x, (const ldns_rdf*)y);
|
||||
}
|
||||
|
||||
/** create label entry */
|
||||
static struct labdata*
|
||||
lab_create(char* name)
|
||||
{
|
||||
struct labdata* lab = (struct labdata*)calloc(1, sizeof(*lab));
|
||||
if(!lab) error_exit("out of memory");
|
||||
lab->label = ldns_dname_new_frm_str(name);
|
||||
if(!lab->label) error_exit("out of memory");
|
||||
lab->name = ldns_dname_new_frm_str(name);
|
||||
if(!lab->name) error_exit("out of memory");
|
||||
lab->node.key = lab->label;
|
||||
lab->node.data = lab;
|
||||
lab->sublabels = ldns_rbtree_create(lab_cmp);
|
||||
if(!lab->sublabels) error_exit("out of memory");
|
||||
lab->rrlist = ldns_rr_list_new();
|
||||
if(!lab->rrlist) error_exit("out of memory");
|
||||
|
||||
return lab;
|
||||
}
|
||||
|
||||
/** for this name, lookup the label, create if does not exist */
|
||||
static struct labdata*
|
||||
find_create_lab(struct harvest_data* data, ldns_rdf* name)
|
||||
{
|
||||
struct labdata* lab = data->root;
|
||||
struct labdata* nextlab;
|
||||
ldns_rdf* next;
|
||||
uint8_t numlab = ldns_dname_label_count(name);
|
||||
if((int)numlab > data->maxlabels)
|
||||
data->maxlabels = (int)numlab;
|
||||
while(numlab--) {
|
||||
next = ldns_dname_label(name, numlab);
|
||||
if(!next) error_exit("ldns_dname_label");
|
||||
|
||||
nextlab = (struct labdata*)
|
||||
ldns_rbtree_search(lab->sublabels, next);
|
||||
if(!nextlab) {
|
||||
/* create it */
|
||||
nextlab = (struct labdata*)calloc(1, sizeof(*lab));
|
||||
if(!nextlab) error_exit("out of memory");
|
||||
nextlab->label = ldns_rdf_clone(next);
|
||||
if(!nextlab->label) error_exit("out of memory");
|
||||
nextlab->node.key = nextlab->label;
|
||||
nextlab->node.data = nextlab;
|
||||
nextlab->sublabels = ldns_rbtree_create(lab_cmp);
|
||||
if(!nextlab->sublabels) error_exit("out of memory");
|
||||
nextlab->parent = lab;
|
||||
nextlab->name = ldns_rdf_clone(next);
|
||||
if(!nextlab->name) error_exit("out of memory");
|
||||
if(ldns_dname_cat(nextlab->name, lab->name)
|
||||
!= LDNS_STATUS_OK) error_exit("outofmem");
|
||||
nextlab->rrlist = ldns_rr_list_new();
|
||||
if(!nextlab->rrlist) error_exit("out of memory");
|
||||
(void)ldns_rbtree_insert(lab->sublabels,
|
||||
&nextlab->node);
|
||||
if(hverb) {
|
||||
printf("new label: ");
|
||||
ldns_rdf_print(stdout, nextlab->name);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
lab = nextlab;
|
||||
ldns_rdf_deep_free(next);
|
||||
}
|
||||
return lab;
|
||||
}
|
||||
|
||||
/** for given query, create todo items, and labels if needed */
|
||||
static void
|
||||
new_todo_item(struct harvest_data* data, ldns_rdf* qname, int qtype,
|
||||
int qclass, int depth)
|
||||
{
|
||||
struct labdata* lab = find_create_lab(data, qname);
|
||||
struct todo_item* it;
|
||||
if(!lab) error_exit("out of memory creating new label");
|
||||
it = (struct todo_item*)calloc(1, sizeof(*it));
|
||||
it->qname = ldns_rdf_clone(qname);
|
||||
it->qtype = qtype;
|
||||
it->qclass = qclass;
|
||||
it->depth = depth;
|
||||
it->lab = lab;
|
||||
it->next = NULL;
|
||||
if(data->todo_last)
|
||||
data->todo_last->next = it;
|
||||
else data->todo_list = it;
|
||||
data->todo_last = it;
|
||||
data->numtodo ++;
|
||||
if(hverb >= 2) {
|
||||
printf("new todo: ");
|
||||
ldns_rdf_print(stdout, it->qname);
|
||||
if(ldns_rr_descript((uint16_t)it->qtype) &&
|
||||
ldns_rr_descript((uint16_t)it->qtype)->_name)
|
||||
printf(" %s", ldns_rr_descript((uint16_t)
|
||||
it->qtype)->_name);
|
||||
if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) &&
|
||||
ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name)
|
||||
printf(" %s", ldns_lookup_by_id(ldns_rr_classes,
|
||||
it->qclass)->name);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** add infra todo items for this query */
|
||||
static void
|
||||
new_todo_infra(struct harvest_data* data, struct labdata* startlab, int depth)
|
||||
{
|
||||
struct labdata* lab;
|
||||
for(lab = startlab; lab; lab = lab->parent) {
|
||||
if(lab->done)
|
||||
return;
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_NS,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_SOA,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_DNSKEY,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_DS,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_A,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
new_todo_item(data, lab->name, LDNS_RR_TYPE_AAAA,
|
||||
LDNS_RR_CLASS_IN, depth);
|
||||
lab->done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** make todo items for initial data */
|
||||
static void
|
||||
make_todo(struct harvest_data* data)
|
||||
{
|
||||
struct todo_item* it;
|
||||
for(it=data->orig_list; it; it = it->next) {
|
||||
/* create todo item for this query itself */
|
||||
new_todo_item(data, it->qname, it->qtype, it->qclass, 0);
|
||||
/* create todo items for infra queries to support it */
|
||||
new_todo_infra(data, data->todo_list->lab,
|
||||
data->todo_list->depth);
|
||||
}
|
||||
}
|
||||
|
||||
/** store RR and make new work items for it if needed */
|
||||
static void
|
||||
process_rr(struct harvest_data* data, ldns_rr* rr, int depth)
|
||||
{
|
||||
/* must free or store rr */
|
||||
struct labdata* lab = find_create_lab(data, ldns_rr_owner(rr));
|
||||
if(!lab) error_exit("cannot find/create label");
|
||||
/* generate extra queries */
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_ns_nsdname(rr)), depth+1);
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_MX) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_mx_exchange(rr)), depth+1);
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
|
||||
new_todo_infra(data, find_create_lab(data,
|
||||
ldns_rr_rdf(rr, 0)), depth+1);
|
||||
}
|
||||
/* store it */
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC) {
|
||||
/* find correct zone to store NSEC in (for delegation zones) */
|
||||
if(ldns_dname_compare(ldns_rr_rdf(rr, 0), ldns_rr_owner(rr))
|
||||
== 0) {
|
||||
/* store at the single name = apex */
|
||||
} else if(!ldns_dname_is_subdomain(ldns_rr_rdf(rr, 0),
|
||||
ldns_rr_owner(rr)) && lab->parent) {
|
||||
/* if owner NSEC subdomain-of-owner then
|
||||
* store at owner (owner is apex or empty nonterminal).
|
||||
* Otherwise at owner parent. */
|
||||
lab = lab->parent;
|
||||
}
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
|
||||
/* store DSes in parent zone */
|
||||
if(lab->parent)
|
||||
lab = lab->parent;
|
||||
} else if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3) {
|
||||
/* store NSEC3s one label up at zone apex */
|
||||
if(lab->parent)
|
||||
lab = lab->parent;
|
||||
}
|
||||
/* we assume NS set is equal across parent-child border. */
|
||||
|
||||
if(!ldns_rr_list_contains_rr(lab->rrlist, rr)) {
|
||||
if(hverb >= 2) {
|
||||
printf("store RR ");
|
||||
ldns_rr_print(stdout, rr);
|
||||
printf("\n");
|
||||
}
|
||||
if(!ldns_rr_list_push_rr(lab->rrlist, rr))
|
||||
error_exit("outofmem ldns_rr_list_push_rr");
|
||||
data->num_rrs++;
|
||||
} else {
|
||||
if(hverb >= 2) {
|
||||
printf("duplicate RR ");
|
||||
ldns_rr_print(stdout, rr);
|
||||
printf("\n");
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
}
|
||||
}
|
||||
|
||||
/** store RRs and make new work items if needed */
|
||||
static void
|
||||
process_pkt(struct harvest_data* data, ldns_pkt* pkt, int depth)
|
||||
{
|
||||
size_t i;
|
||||
ldns_rr_list* list;
|
||||
list = ldns_pkt_get_section_clone(pkt, LDNS_SECTION_ANY_NOQUESTION);
|
||||
if(!list) error_exit("outofmemory");
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); i++) {
|
||||
process_rr(data, ldns_rr_list_rr(list, i), depth);
|
||||
}
|
||||
ldns_rr_list_free(list);
|
||||
}
|
||||
|
||||
/** process a todo item */
|
||||
static void
|
||||
process(struct harvest_data* data, struct todo_item* it)
|
||||
{
|
||||
int r;
|
||||
char* nm;
|
||||
struct ub_result* result = NULL;
|
||||
ldns_pkt* pkt = NULL;
|
||||
ldns_status s;
|
||||
if(hverb) {
|
||||
printf("process: ");
|
||||
ldns_rdf_print(stdout, it->qname);
|
||||
if(ldns_rr_descript((uint16_t)it->qtype) &&
|
||||
ldns_rr_descript((uint16_t)it->qtype)->_name)
|
||||
printf(" %s", ldns_rr_descript((uint16_t)
|
||||
it->qtype)->_name);
|
||||
if(ldns_lookup_by_id(ldns_rr_classes, it->qclass) &&
|
||||
ldns_lookup_by_id(ldns_rr_classes, it->qclass)->name)
|
||||
printf(" %s", ldns_lookup_by_id(ldns_rr_classes,
|
||||
it->qclass)->name);
|
||||
printf("\n");
|
||||
}
|
||||
/* do lookup */
|
||||
nm = ldns_rdf2str(it->qname);
|
||||
if(!nm) error_exit("ldns_rdf2str");
|
||||
r = ub_resolve(data->ctx, nm, it->qtype, it->qclass, &result);
|
||||
if(r != 0) {
|
||||
printf("ub_resolve(%s, %d, %d): %s\n", nm, it->qtype,
|
||||
it->qclass, ub_strerror(r));
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
/* even if result is a negative, try to store resulting SOA/NSEC */
|
||||
|
||||
/* create ldns pkt */
|
||||
s = ldns_wire2pkt(&pkt, result->answer_packet,
|
||||
(size_t)result->answer_len);
|
||||
if(s != LDNS_STATUS_OK) {
|
||||
printf("ldns_wire2pkt failed! %s %d %d %s", nm,
|
||||
it->qtype, it->qclass, ldns_get_errorstr_by_id(s));
|
||||
free(nm);
|
||||
return;
|
||||
}
|
||||
if(hverb >= 2) {
|
||||
printf("answer: ");
|
||||
ldns_pkt_print(stdout, pkt);
|
||||
printf("\n");
|
||||
}
|
||||
/* process results */
|
||||
process_pkt(data, pkt, it->depth);
|
||||
|
||||
ldns_pkt_free(pkt);
|
||||
free(nm);
|
||||
ub_resolve_free(result);
|
||||
}
|
||||
|
||||
/** perform main harvesting */
|
||||
static void
|
||||
harvest_main(struct harvest_data* data)
|
||||
{
|
||||
struct todo_item* it;
|
||||
int numdone = 0;
|
||||
/* register todo queries for all original queries */
|
||||
make_todo(data);
|
||||
printf("depth 0: done %d todo %d\n", 0, data->numtodo);
|
||||
/* pick up a todo item and process it */
|
||||
while(data->todo_list) {
|
||||
numdone++;
|
||||
it = data->todo_list;
|
||||
data->todo_list = it->next;
|
||||
if(!data->todo_list) data->todo_last = NULL;
|
||||
if(numdone%1000==0 || it->depth > data->curdepth) {
|
||||
data->curdepth = it->depth;
|
||||
printf("depth %d: done %d todo %d, %d rrs\n",
|
||||
it->depth, numdone, data->numtodo,
|
||||
data->num_rrs);
|
||||
}
|
||||
if(it->depth >= data->maxdepth) {
|
||||
printf("obtained %d rrs to a max of %d labels.\n",
|
||||
data->num_rrs, data->maxlabels);
|
||||
return;
|
||||
}
|
||||
data->numtodo--;
|
||||
process(data, it);
|
||||
}
|
||||
}
|
||||
|
||||
/** create directory if it does not exist */
|
||||
static void
|
||||
hv_mkdir(char* dir)
|
||||
{
|
||||
if(mkdir(dir, 0755) == -1) {
|
||||
if(errno == EEXIST)
|
||||
return;
|
||||
perror(dir);
|
||||
error_exit("mkdir failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** see if rrlist contains a SOA record */
|
||||
static ldns_rr*
|
||||
has_SOA(ldns_rr_list* list)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<ldns_rr_list_rr_count(list); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(list, i))
|
||||
== LDNS_RR_TYPE_SOA)
|
||||
return ldns_rr_list_rr(list, i);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** write moredata for a zone*/
|
||||
static void
|
||||
write_moredata(struct harvest_data* data, struct labdata* zone,
|
||||
FILE *f, struct labdata* thislab, ldns_rr* nslist)
|
||||
{
|
||||
struct labdata* lab;
|
||||
size_t i;
|
||||
ldns_rr* ns;
|
||||
LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) {
|
||||
if(has_SOA(lab->rrlist)) {
|
||||
/* copy only NS glue */
|
||||
for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) {
|
||||
ns = ldns_rr_list_rr(lab->rrlist, i);
|
||||
if(ldns_rr_get_type(ns) == LDNS_RR_TYPE_NS) {
|
||||
ldns_rr_print(f, ns);
|
||||
if(ldns_dname_is_subdomain(
|
||||
ldns_rr_ns_nsdname(ns),
|
||||
lab->name)) {
|
||||
ldns_rr_push_rdf(nslist,
|
||||
ldns_rdf_clone(
|
||||
ldns_rr_ns_nsdname(ns)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* copy all, recurse */
|
||||
for(i=0; i<ldns_rr_list_rr_count(lab->rrlist); i++) {
|
||||
ldns_rr_print(f,
|
||||
ldns_rr_list_rr(lab->rrlist, i));
|
||||
}
|
||||
write_moredata(data, zone, f, lab, nslist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** find and write glue into zone file */
|
||||
static void
|
||||
write_glue(struct harvest_data* data, struct labdata* thislab, FILE* f,
|
||||
ldns_rdf* name, int dep)
|
||||
{
|
||||
size_t i;
|
||||
struct labdata* lab;
|
||||
ldns_rr* rr;
|
||||
if(ldns_dname_compare(name, thislab->name) == 0) {
|
||||
/* this is it! Did we go outside the zone? */
|
||||
if(dep == 0)
|
||||
return;
|
||||
/* find A and AAAA */
|
||||
for(i=0; i<ldns_rr_list_rr_count(thislab->rrlist); i++) {
|
||||
rr = ldns_rr_list_rr(thislab->rrlist, i);
|
||||
if(ldns_rr_get_type(rr) == LDNS_RR_TYPE_A ||
|
||||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
|
||||
ldns_rr_print(f, rr);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* recurse deeper */
|
||||
LDNS_RBTREE_FOR(lab, struct labdata*, thislab->sublabels) {
|
||||
if(has_SOA(lab->rrlist)) {
|
||||
write_glue(data, lab, f, name, dep+1);
|
||||
} else {
|
||||
write_glue(data, lab, f, name, dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** write zonefile for zone at this apex */
|
||||
static void
|
||||
write_zonefile(struct harvest_data* data, int dep, FILE* zlist,
|
||||
struct labdata* apex, ldns_rr* soa)
|
||||
{
|
||||
FILE *f;
|
||||
char fname[1024];
|
||||
char* zname = ldns_rdf2str(apex->name);
|
||||
time_t tm = time(NULL);
|
||||
size_t i;
|
||||
ldns_rr* nslist;
|
||||
if(!zname) error_exit("out of mem ldns_rdf2str");
|
||||
if(strcmp(zname, ".") == 0)
|
||||
snprintf(fname, sizeof(fname), "l%d/root.zone", dep);
|
||||
else snprintf(fname, sizeof(fname), "l%d/%szone", dep, zname);
|
||||
|
||||
fprintf(zlist, "zone: name: \"%s\" %s%szonefile: \"%s\"\n",
|
||||
zname,
|
||||
strlen(zname)/8<1?"\t":"",
|
||||
strlen(zname)/8<2?"\t":"",
|
||||
fname);
|
||||
|
||||
if(hverb) printf("writing %s\n", fname);
|
||||
f = fopen(fname, "w");
|
||||
if(!f) {
|
||||
perror(fname);
|
||||
error_exit("cannot open zone file");
|
||||
}
|
||||
fprintf(f, "; %s - generated by harvest program.\n", fname);
|
||||
fprintf(f, "; zone name %s - this is a partial snapshot of "
|
||||
"data relevant to the query list.\n", zname);
|
||||
fprintf(f, "; created %u - date %s\n", (unsigned)tm, ctime(&tm));
|
||||
ldns_rr_print(f, soa);
|
||||
fprintf(f, "\n");
|
||||
for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i))
|
||||
== LDNS_RR_TYPE_SOA) continue;
|
||||
ldns_rr_print(f, ldns_rr_list_rr(apex->rrlist, i));
|
||||
}
|
||||
/* search for more data - subdomains inside the zone, NS glue */
|
||||
nslist = ldns_rr_new();
|
||||
if(!nslist) error_exit("out of memory");
|
||||
fprintf(f, "; end of apex, more data follows\n");
|
||||
write_moredata(data, apex, f, apex, nslist);
|
||||
|
||||
/* add NS from apex that need glue too */
|
||||
for(i=0; i<ldns_rr_list_rr_count(apex->rrlist); i++) {
|
||||
if(ldns_rr_get_type(ldns_rr_list_rr(apex->rrlist, i)) !=
|
||||
LDNS_RR_TYPE_NS)
|
||||
continue;
|
||||
/* these are only added again if in a subzone */
|
||||
if(ldns_dname_is_subdomain(ldns_rr_ns_nsdname(
|
||||
ldns_rr_list_rr(apex->rrlist, i)), apex->name)) {
|
||||
ldns_rr_push_rdf(nslist, ldns_rdf_clone(
|
||||
ldns_rr_ns_nsdname(ldns_rr_list_rr(
|
||||
apex->rrlist, i))));
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "; glue data follows\n");
|
||||
/* lookup and add glue (if not already in zone) */
|
||||
for(i=0; i<ldns_rr_rd_count(nslist); i++) {
|
||||
write_glue(data, apex, f, ldns_rr_rdf(nslist, i), 0);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
ldns_rr_free(nslist);
|
||||
free(zname);
|
||||
}
|
||||
|
||||
/** create zones at depth d in label tree */
|
||||
static void
|
||||
create_zones(struct harvest_data* data, int dep, FILE* zlist,
|
||||
struct labdata* labnow, int depnow)
|
||||
{
|
||||
struct labdata* s;
|
||||
ldns_rr* soa;
|
||||
if(depnow == dep) {
|
||||
/* see if this is a zone start - a SOA */
|
||||
if((soa=has_SOA(labnow->rrlist))) {
|
||||
write_zonefile(data, dep, zlist, labnow, soa);
|
||||
data->num_zones++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* recurse */
|
||||
LDNS_RBTREE_FOR(s, struct labdata*, labnow->sublabels) {
|
||||
create_zones(data, dep, zlist, s, depnow+1);
|
||||
}
|
||||
}
|
||||
|
||||
/** sort rrlists */
|
||||
static void
|
||||
harvest_sort(struct labdata* lab)
|
||||
{
|
||||
struct labdata* s;
|
||||
/* prettier output if sorted here */
|
||||
ldns_rr_list_sort(lab->rrlist);
|
||||
/* and recurse */
|
||||
LDNS_RBTREE_FOR(s, struct labdata*, lab->sublabels) {
|
||||
harvest_sort(s);
|
||||
}
|
||||
}
|
||||
|
||||
/** output harvested results */
|
||||
static void
|
||||
harvest_output(struct harvest_data* data)
|
||||
{
|
||||
int d;
|
||||
char buf[20];
|
||||
FILE* zlist;
|
||||
int lastzones;
|
||||
hv_mkdir(data->resultdir);
|
||||
if(chdir(data->resultdir) == -1) {
|
||||
perror(data->resultdir);
|
||||
error_exit("cannot chdir");
|
||||
}
|
||||
harvest_sort(data->root);
|
||||
/* create zones */
|
||||
for(d = 0; d<data->maxlabels; d++) {
|
||||
lastzones = data->num_zones;
|
||||
printf("creating zones %d\n", d);
|
||||
snprintf(buf, sizeof(buf), "l%d", d);
|
||||
hv_mkdir(buf);
|
||||
snprintf(buf, sizeof(buf), "l%d.zones", d);
|
||||
zlist = fopen(buf, "w");
|
||||
if(!zlist) {
|
||||
perror(buf);
|
||||
error_exit("cannot write zonelist file");
|
||||
}
|
||||
fprintf(zlist, "# partial zones at depth %d\n", d);
|
||||
create_zones(data, d, zlist, data->root, 0);
|
||||
fclose(zlist);
|
||||
printf("creating zones %d - %d zones written\n", d,
|
||||
data->num_zones - lastzones);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 harvest */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
struct harvest_data data;
|
||||
char* nm = argv[0];
|
||||
int c;
|
||||
|
||||
/* defaults */
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.ctx = ub_ctx_create();
|
||||
data.resultdir = strdup("harvested_zones");
|
||||
if(!data.resultdir) error_exit("out of memory");
|
||||
data.maxdepth = 2;
|
||||
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "hf:v")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
qlist_read_file(&data, optarg);
|
||||
break;
|
||||
case 'v':
|
||||
hverb++;
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage(nm);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if(argc != 0)
|
||||
usage(nm);
|
||||
if(data.orig_list == NULL)
|
||||
error_exit("No queries to make, use -f (help with -h).");
|
||||
data.root = lab_create(".");
|
||||
if(!data.root) error_exit("out of memory");
|
||||
|
||||
/* harvest the data */
|
||||
harvest_main(&data);
|
||||
harvest_output(&data);
|
||||
|
||||
/* no cleanup except the context (to close open sockets) */
|
||||
ub_ctx_delete(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -504,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)
|
||||
{
|
||||
@@ -645,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)
|
||||
@@ -781,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
|
||||
|
||||
|
||||
+14
-35
@@ -60,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 */
|
||||
@@ -101,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)
|
||||
@@ -153,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 */
|
||||
@@ -177,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 */
|
||||
@@ -192,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;
|
||||
@@ -213,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("))
|
||||
@@ -230,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");
|
||||
}
|
||||
|
||||
@@ -251,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;
|
||||
}
|
||||
|
||||
+614
@@ -0,0 +1,614 @@
|
||||
/*
|
||||
* testcode/perf.c - debug program to estimate name server performance.
|
||||
*
|
||||
* 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 estimates DNS name server performance.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <signal.h>
|
||||
#include "util/log.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/msgparse.h"
|
||||
|
||||
/** usage information for perf */
|
||||
static void usage(char* nm)
|
||||
{
|
||||
printf("usage: %s [options] server\n", nm);
|
||||
printf("server: ip address of server, IP4 or IP6.\n");
|
||||
printf(" If not on port %d add @port.\n", UNBOUND_DNS_PORT);
|
||||
printf("-d sec duration of test in whole seconds (0: wait for ^C)\n");
|
||||
printf("-a str query to ask, interpreted as a line from qfile\n");
|
||||
printf("-f fnm query list to read from file\n");
|
||||
printf(" every line has format: qname qclass qtype [+-]{E}\n");
|
||||
printf(" where + means RD set, E means EDNS enabled\n");
|
||||
printf("-q quiet mode, print only final qps\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
struct perfinfo;
|
||||
struct perfio;
|
||||
|
||||
/** Global info for perf */
|
||||
struct perfinfo {
|
||||
/** need to exit */
|
||||
volatile int exit;
|
||||
/** all purpose buffer (for UDP send and receive) */
|
||||
ldns_buffer* buf;
|
||||
|
||||
/** destination */
|
||||
struct sockaddr_storage dest;
|
||||
/** length of dest socket addr */
|
||||
socklen_t destlen;
|
||||
|
||||
/** when did this time slice start */
|
||||
struct timeval since;
|
||||
/** number of queries received in that time */
|
||||
size_t numrecv;
|
||||
/** number of queries sent out in that time */
|
||||
size_t numsent;
|
||||
|
||||
/** duration of test in seconds */
|
||||
int duration;
|
||||
/** quiet mode? */
|
||||
int quiet;
|
||||
|
||||
/** when did the total test start */
|
||||
struct timeval start;
|
||||
/** total number recvd */
|
||||
size_t total_recv;
|
||||
/** total number sent */
|
||||
size_t total_sent;
|
||||
/** numbers by rcode */
|
||||
size_t by_rcode[32];
|
||||
|
||||
/** number of I/O ports */
|
||||
size_t io_num;
|
||||
/** I/O ports array */
|
||||
struct perfio* io;
|
||||
/** max fd value in io ports */
|
||||
int maxfd;
|
||||
/** readset */
|
||||
fd_set rset;
|
||||
|
||||
/** size of querylist */
|
||||
size_t qlist_size;
|
||||
/** allocated size of qlist array */
|
||||
size_t qlist_capacity;
|
||||
/** list of query packets (data) */
|
||||
uint8_t** qlist_data;
|
||||
/** list of query packets (length of a packet) */
|
||||
size_t* qlist_len;
|
||||
/** index into querylist, for walking the list */
|
||||
size_t qlist_idx;
|
||||
};
|
||||
|
||||
/** I/O port for perf */
|
||||
struct perfio {
|
||||
/** id number */
|
||||
size_t id;
|
||||
/** file descriptor of socket */
|
||||
int fd;
|
||||
/** timeout value */
|
||||
struct timeval timeout;
|
||||
/** ptr back to perfinfo */
|
||||
struct perfinfo* info;
|
||||
};
|
||||
|
||||
/** number of msec between starting io ports */
|
||||
#define START_IO_INTERVAL 10
|
||||
/** number of msec timeout on io ports */
|
||||
#define IO_TIMEOUT 10
|
||||
|
||||
/** signal handler global info */
|
||||
static struct perfinfo* sig_info;
|
||||
|
||||
/** signal handler for user quit */
|
||||
static RETSIGTYPE perf_sigh(int sig)
|
||||
{
|
||||
log_assert(sig_info);
|
||||
if(!sig_info->quiet)
|
||||
printf("exit on signal %d\n", sig);
|
||||
sig_info->exit = 1;
|
||||
}
|
||||
|
||||
/** timeval compare, t1 < t2 */
|
||||
static int
|
||||
perf_tv_smaller(struct timeval* t1, struct timeval* t2)
|
||||
{
|
||||
#ifndef S_SPLINT_S
|
||||
if(t1->tv_sec < t2->tv_sec)
|
||||
return 1;
|
||||
if(t1->tv_sec == t2->tv_sec &&
|
||||
t1->tv_usec < t2->tv_usec)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** timeval add, t1 += t2 */
|
||||
static void
|
||||
perf_tv_add(struct timeval* t1, struct timeval* t2)
|
||||
{
|
||||
#ifndef S_SPLINT_S
|
||||
t1->tv_sec += t2->tv_sec;
|
||||
t1->tv_usec += t2->tv_usec;
|
||||
while(t1->tv_usec > 1000000) {
|
||||
t1->tv_usec -= 1000000;
|
||||
t1->tv_sec++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/** timeval subtract, t1 -= t2 */
|
||||
static void
|
||||
perf_tv_subtract(struct timeval* t1, struct timeval* t2)
|
||||
{
|
||||
#ifndef S_SPLINT_S
|
||||
t1->tv_sec -= t2->tv_sec;
|
||||
if(t1->tv_usec >= t2->tv_usec) {
|
||||
t1->tv_usec -= t2->tv_usec;
|
||||
} else {
|
||||
t1->tv_sec--;
|
||||
t1->tv_usec = 1000000-(t2->tv_usec-t1->tv_usec);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** setup perf test environment */
|
||||
static void
|
||||
perfsetup(struct perfinfo* info)
|
||||
{
|
||||
size_t i;
|
||||
if(gettimeofday(&info->start, NULL) < 0)
|
||||
fatal_exit("gettimeofday: %s", strerror(errno));
|
||||
sig_info = info;
|
||||
if( signal(SIGINT, perf_sigh) == SIG_ERR ||
|
||||
signal(SIGTERM, perf_sigh) == SIG_ERR ||
|
||||
signal(SIGHUP, perf_sigh) == SIG_ERR ||
|
||||
signal(SIGQUIT, perf_sigh) == SIG_ERR)
|
||||
fatal_exit("could not bind to signal");
|
||||
info->io = (struct perfio*)calloc(sizeof(struct perfio), info->io_num);
|
||||
if(!info->io) fatal_exit("out of memory");
|
||||
#ifndef S_SPLINT_S
|
||||
FD_ZERO(&info->rset);
|
||||
#endif
|
||||
info->since = info->start;
|
||||
for(i=0; i<info->io_num; i++) {
|
||||
info->io[i].id = i;
|
||||
info->io[i].info = info;
|
||||
info->io[i].fd = socket(
|
||||
addr_is_ip6(&info->dest, info->destlen)?
|
||||
AF_INET6:AF_INET, SOCK_DGRAM, 0);
|
||||
if(info->io[i].fd == -1)
|
||||
fatal_exit("socket: %s", strerror(errno));
|
||||
if(info->io[i].fd > info->maxfd)
|
||||
info->maxfd = info->io[i].fd;
|
||||
#ifndef S_SPLINT_S
|
||||
FD_SET(info->io[i].fd, &info->rset);
|
||||
info->io[i].timeout.tv_usec = ((START_IO_INTERVAL*i)%1000)
|
||||
*1000;
|
||||
info->io[i].timeout.tv_sec = (START_IO_INTERVAL*i)/1000;
|
||||
perf_tv_add(&info->io[i].timeout, &info->since);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/** cleanup perf test environment */
|
||||
static void
|
||||
perffree(struct perfinfo* info)
|
||||
{
|
||||
size_t i;
|
||||
if(!info) return;
|
||||
if(info->io) {
|
||||
for(i=0; i<info->io_num; i++) {
|
||||
close(info->io[i].fd);
|
||||
}
|
||||
free(info->io);
|
||||
}
|
||||
for(i=0; i<info->qlist_size; i++)
|
||||
free(info->qlist_data[i]);
|
||||
free(info->qlist_data);
|
||||
free(info->qlist_len);
|
||||
}
|
||||
|
||||
/** send new query for io */
|
||||
static void
|
||||
perfsend(struct perfinfo* info, size_t n, struct timeval* now)
|
||||
{
|
||||
ssize_t r;
|
||||
r = sendto(info->io[n].fd, info->qlist_data[info->qlist_idx],
|
||||
info->qlist_len[info->qlist_idx], 0,
|
||||
(struct sockaddr*)&info->dest, info->destlen);
|
||||
/*log_hex("send", info->qlist_data[info->qlist_idx],
|
||||
info->qlist_len[info->qlist_idx]);*/
|
||||
if(r == -1)
|
||||
log_err("sendto: %s", strerror(errno));
|
||||
else if(r != (ssize_t)info->qlist_len[info->qlist_idx]) {
|
||||
log_err("partial sendto");
|
||||
}
|
||||
info->qlist_idx = (info->qlist_idx+1) % info->qlist_size;
|
||||
info->numsent++;
|
||||
|
||||
info->io[n].timeout.tv_sec = IO_TIMEOUT/1000;
|
||||
info->io[n].timeout.tv_usec = (IO_TIMEOUT%1000)*1000;
|
||||
perf_tv_add(&info->io[n].timeout, now);
|
||||
}
|
||||
|
||||
/** got reply for io */
|
||||
static void
|
||||
perfreply(struct perfinfo* info, size_t n, struct timeval* now)
|
||||
{
|
||||
ssize_t r;
|
||||
r = recv(info->io[n].fd, ldns_buffer_begin(info->buf),
|
||||
ldns_buffer_capacity(info->buf), 0);
|
||||
if(r == -1) {
|
||||
log_err("recv: %s", strerror(errno));
|
||||
} else {
|
||||
info->by_rcode[LDNS_RCODE_WIRE(ldns_buffer_begin(
|
||||
info->buf))]++;
|
||||
info->numrecv++;
|
||||
}
|
||||
/*ldns_buffer_set_limit(info->buf, r);
|
||||
log_buf(0, "reply", info->buf);*/
|
||||
perfsend(info, n, now);
|
||||
}
|
||||
|
||||
/** got timeout for io */
|
||||
static void
|
||||
perftimeout(struct perfinfo* info, size_t n, struct timeval* now)
|
||||
{
|
||||
/* may not be a dropped packet, this is also used to start
|
||||
* up the sending IOs */
|
||||
perfsend(info, n, now);
|
||||
}
|
||||
|
||||
/** print nice stats about qps */
|
||||
static void
|
||||
stat_printout(struct perfinfo* info, struct timeval* now,
|
||||
struct timeval* elapsed)
|
||||
{
|
||||
/* calculate qps */
|
||||
double dt, qps = 0;
|
||||
#ifndef S_SPLINT_S
|
||||
dt = (double)(elapsed->tv_sec*1000000 + elapsed->tv_usec) / 1000000;
|
||||
#endif
|
||||
if(dt > 0.001)
|
||||
qps = (double)(info->numrecv) / dt;
|
||||
if(!info->quiet)
|
||||
printf("qps: %g\n", qps);
|
||||
/* setup next slice */
|
||||
info->since = *now;
|
||||
info->total_sent += info->numsent;
|
||||
info->total_recv += info->numrecv;
|
||||
info->numrecv = 0;
|
||||
info->numsent = 0;
|
||||
}
|
||||
|
||||
/** wait for new events for performance test */
|
||||
static void
|
||||
perfselect(struct perfinfo* info)
|
||||
{
|
||||
fd_set rset = info->rset;
|
||||
struct timeval timeout, now;
|
||||
int num;
|
||||
size_t i;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
fatal_exit("gettimeofday: %s", strerror(errno));
|
||||
/* time to exit? */
|
||||
if(info->duration > 0) {
|
||||
timeout = now;
|
||||
perf_tv_subtract(&timeout, &info->start);
|
||||
if((int)timeout.tv_sec >= info->duration) {
|
||||
info->exit = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* time for stats printout? */
|
||||
timeout = now;
|
||||
perf_tv_subtract(&timeout, &info->since);
|
||||
if(timeout.tv_sec > 0) {
|
||||
stat_printout(info, &now, &timeout);
|
||||
}
|
||||
/* see what is closest port to timeout; or if there is a timeout */
|
||||
timeout = info->io[0].timeout;
|
||||
for(i=0; i<info->io_num; i++) {
|
||||
if(perf_tv_smaller(&info->io[i].timeout, &now)) {
|
||||
perftimeout(info, i, &now);
|
||||
return;
|
||||
}
|
||||
if(perf_tv_smaller(&info->io[i].timeout, &timeout)) {
|
||||
timeout = info->io[i].timeout;
|
||||
}
|
||||
}
|
||||
perf_tv_subtract(&timeout, &now);
|
||||
|
||||
num = select(info->maxfd+1, &rset, NULL, NULL, &timeout);
|
||||
if(num == -1) {
|
||||
if(errno == EAGAIN || errno == EINTR)
|
||||
return;
|
||||
log_err("select: %s", strerror(errno));
|
||||
}
|
||||
|
||||
/* handle new events */
|
||||
for(i=0; num && i<info->io_num; i++) {
|
||||
if(FD_ISSET(info->io[i].fd, &rset)) {
|
||||
perfreply(info, i, &now);
|
||||
num--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** show end stats */
|
||||
static void
|
||||
perfendstats(struct perfinfo* info)
|
||||
{
|
||||
double dt, qps;
|
||||
struct timeval timeout, now;
|
||||
int i, lost;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
fatal_exit("gettimeofday: %s", strerror(errno));
|
||||
timeout = now;
|
||||
perf_tv_subtract(&timeout, &info->since);
|
||||
stat_printout(info, &now, &timeout);
|
||||
|
||||
timeout = now;
|
||||
perf_tv_subtract(&timeout, &info->start);
|
||||
dt = (double)(timeout.tv_sec*1000000 + timeout.tv_usec) / 1000000.0;
|
||||
qps = (double)(info->total_recv) / dt;
|
||||
lost = (int)(info->total_sent - info->total_recv) - (int)info->io_num;
|
||||
if(!info->quiet) {
|
||||
printf("overall time: %g sec\n",
|
||||
(double)timeout.tv_sec +
|
||||
(double)timeout.tv_usec/1000000.);
|
||||
if(lost > 0)
|
||||
printf("Packets lost: %d\n", (int)lost);
|
||||
|
||||
for(i=0; i<(int)(sizeof(info->by_rcode)/sizeof(size_t)); i++)
|
||||
{
|
||||
if(info->by_rcode[i] > 0) {
|
||||
printf("%d(%5s): %u replies\n",
|
||||
i, ldns_lookup_by_id(ldns_rcodes, i)?
|
||||
ldns_lookup_by_id(ldns_rcodes,
|
||||
i)->name:"??",
|
||||
(unsigned)info->by_rcode[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("average qps: %g\n", qps);
|
||||
}
|
||||
|
||||
/** perform the performance test */
|
||||
static void
|
||||
perfmain(struct perfinfo* info)
|
||||
{
|
||||
perfsetup(info);
|
||||
while(!info->exit) {
|
||||
perfselect(info);
|
||||
}
|
||||
perfendstats(info);
|
||||
perffree(info);
|
||||
}
|
||||
|
||||
/** parse a query line to a packet into buffer */
|
||||
static int
|
||||
qlist_parse_line(ldns_buffer* buf, char* p)
|
||||
{
|
||||
char nm[1024], cl[1024], tp[1024], fl[1024];
|
||||
int r;
|
||||
int rec = 1, edns = 0;
|
||||
struct query_info qinfo;
|
||||
ldns_rdf* rdf;
|
||||
nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0;
|
||||
r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl);
|
||||
if(r != 3 && r != 4)
|
||||
return 0;
|
||||
/*printf("nm='%s', cl='%s', tp='%s', fl='%s'\n", nm, cl, tp, fl);*/
|
||||
if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) {
|
||||
qinfo.qtype = ldns_get_rr_type_by_name(cl);
|
||||
qinfo.qclass = ldns_get_rr_class_by_name(tp);
|
||||
} else {
|
||||
qinfo.qtype = ldns_get_rr_type_by_name(tp);
|
||||
qinfo.qclass = ldns_get_rr_class_by_name(cl);
|
||||
}
|
||||
if(fl[0] == '+') rec = 1;
|
||||
else if(fl[0] == '-') rec = 0;
|
||||
else if(fl[0] == 'E') edns = 1;
|
||||
if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E')
|
||||
edns = 1;
|
||||
rdf = ldns_dname_new_frm_str(nm);
|
||||
if(!rdf)
|
||||
return 0;
|
||||
qinfo.qname = ldns_rdf_data(rdf);
|
||||
qinfo.qname_len = ldns_rdf_size(rdf);
|
||||
qinfo_query_encode(buf, &qinfo);
|
||||
ldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */
|
||||
if(rec) LDNS_RD_SET(ldns_buffer_begin(buf));
|
||||
if(edns) {
|
||||
struct edns_data edns;
|
||||
memset(&edns, 0, sizeof(edns));
|
||||
edns.edns_present = 1;
|
||||
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||
/* Set DO bit in all EDNS datagrams ... */
|
||||
edns.bits = EDNS_DO;
|
||||
attach_edns_record(buf, &edns);
|
||||
}
|
||||
ldns_rdf_deep_free(rdf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** grow query list capacity */
|
||||
static void
|
||||
qlist_grow_capacity(struct perfinfo* info)
|
||||
{
|
||||
size_t newcap = (size_t)((info->qlist_capacity==0)?16:
|
||||
info->qlist_capacity*2);
|
||||
uint8_t** d = (uint8_t**)calloc(sizeof(uint8_t*), newcap);
|
||||
size_t* l = (size_t*)calloc(sizeof(size_t), newcap);
|
||||
if(!d || !l) fatal_exit("out of memory");
|
||||
memcpy(d, info->qlist_data, sizeof(uint8_t*)*
|
||||
info->qlist_capacity);
|
||||
memcpy(l, info->qlist_len, sizeof(size_t)*
|
||||
info->qlist_capacity);
|
||||
free(info->qlist_data);
|
||||
free(info->qlist_len);
|
||||
info->qlist_data = d;
|
||||
info->qlist_len = l;
|
||||
info->qlist_capacity = newcap;
|
||||
}
|
||||
|
||||
/** setup query list in info */
|
||||
static void
|
||||
qlist_add_line(struct perfinfo* info, char* line, int no)
|
||||
{
|
||||
if(!qlist_parse_line(info->buf, line)) {
|
||||
printf("error parsing query %d: %s\n", no, line);
|
||||
exit(1);
|
||||
}
|
||||
ldns_buffer_write_u16_at(info->buf, 0, (uint16_t)info->qlist_size);
|
||||
if(info->qlist_size + 1 > info->qlist_capacity) {
|
||||
qlist_grow_capacity(info);
|
||||
}
|
||||
info->qlist_len[info->qlist_size] = ldns_buffer_limit(info->buf);
|
||||
info->qlist_data[info->qlist_size] = memdup(
|
||||
ldns_buffer_begin(info->buf), ldns_buffer_limit(info->buf));
|
||||
if(!info->qlist_data[info->qlist_size])
|
||||
fatal_exit("out of memory");
|
||||
info->qlist_size ++;
|
||||
}
|
||||
|
||||
/** setup query list in info */
|
||||
static void
|
||||
qlist_read_file(struct perfinfo* info, char* fname)
|
||||
{
|
||||
char buf[1024];
|
||||
char *p;
|
||||
FILE* in = fopen(fname, "r");
|
||||
int lineno = 0;
|
||||
if(!in) {
|
||||
perror(fname);
|
||||
exit(1);
|
||||
}
|
||||
while(fgets(buf, (int)sizeof(buf), in)) {
|
||||
lineno++;
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
p = buf;
|
||||
while(*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
if(p[0] == 0 || p[0] == '\n' || p[0] == ';' || p[0] == '#')
|
||||
continue;
|
||||
qlist_add_line(info, p, lineno);
|
||||
}
|
||||
printf("Read %s, got %u queries\n", fname, (unsigned)info->qlist_size);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
/** 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 perf */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char* nm = argv[0];
|
||||
int c;
|
||||
struct perfinfo info;
|
||||
|
||||
/* defaults */
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.io_num = 16;
|
||||
|
||||
log_init(NULL, 0, NULL);
|
||||
log_ident_set("perf");
|
||||
checklock_start();
|
||||
|
||||
info.buf = ldns_buffer_new(65553);
|
||||
if(!info.buf) fatal_exit("out of memory");
|
||||
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "d:ha:f:q")) != -1) {
|
||||
switch(c) {
|
||||
case 'q':
|
||||
info.quiet = 1;
|
||||
break;
|
||||
case 'd':
|
||||
if(atoi(optarg)==0 && strcmp(optarg, "0")!=0) {
|
||||
printf("-d not a number %s", optarg);
|
||||
return 1;
|
||||
}
|
||||
info.duration = atoi(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
qlist_add_line(&info, optarg, 0);
|
||||
break;
|
||||
case 'f':
|
||||
qlist_read_file(&info, optarg);
|
||||
break;
|
||||
case '?':
|
||||
case 'h':
|
||||
default:
|
||||
usage(nm);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc != 1) {
|
||||
printf("error: pass server IP address on commandline.\n");
|
||||
usage(nm);
|
||||
}
|
||||
if(!extstrtoaddr(argv[0], &info.dest, &info.destlen)) {
|
||||
printf("Could not parse ip: %s\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if(info.qlist_size == 0) {
|
||||
printf("No queries to make, use -f or -a.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* do the performance test */
|
||||
perfmain(&info);
|
||||
|
||||
ldns_buffer_free(info.buf);
|
||||
checklock_stop();
|
||||
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 */
|
||||
|
||||
+8
-1
@@ -208,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;
|
||||
@@ -229,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);
|
||||
|
||||
+8
-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;
|
||||
@@ -224,6 +226,11 @@ struct replay_runtime {
|
||||
/** user argument for incoming query callback */
|
||||
void *cb_arg;
|
||||
|
||||
/** the current time in seconds */
|
||||
uint32_t now_secs;
|
||||
/** the current time in microseconds */
|
||||
struct timeval now_tv;
|
||||
|
||||
/** signal handler callback */
|
||||
void (*sig_cb)(int, void*);
|
||||
/** signal handler user arg */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+167
-5
@@ -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"
|
||||
@@ -155,7 +314,7 @@ infra_test()
|
||||
size_t zonelen = 13;
|
||||
struct infra_cache* slab;
|
||||
struct config_file* cfg = config_create();
|
||||
time_t now = 0;
|
||||
uint32_t now = 0;
|
||||
int vs, to;
|
||||
struct infra_host_key* k;
|
||||
struct infra_host_data* d;
|
||||
@@ -204,12 +363,12 @@ infra_test()
|
||||
static void
|
||||
rnd_test()
|
||||
{
|
||||
struct ub_randstate r;
|
||||
struct ub_randstate* r;
|
||||
int num = 100, i;
|
||||
long int a[100];
|
||||
unit_assert( ub_initstate((unsigned)time(NULL), &r, 256) );
|
||||
unit_assert( (r = ub_initstate((unsigned)time(NULL), NULL)) );
|
||||
for(i=0; i<num; i++) {
|
||||
a[i] = ub_random(&r);
|
||||
a[i] = ub_random(r);
|
||||
unit_assert(a[i] >= 0);
|
||||
unit_assert((size_t)a[i] <= (size_t)RAND_MAX);
|
||||
if(i > 5)
|
||||
@@ -217,7 +376,7 @@ rnd_test()
|
||||
a[i] != a[i-3] || a[i] != a[i-4] ||
|
||||
a[i] != a[i-5] || a[i] != a[i-6]);
|
||||
}
|
||||
ub_randfree(&r);
|
||||
ub_randfree(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,6 +398,7 @@ main(int argc, char* argv[])
|
||||
rnd_test();
|
||||
verify_test();
|
||||
net_test();
|
||||
config_memsize_test();
|
||||
dname_test();
|
||||
anchors_test();
|
||||
rtt_test();
|
||||
@@ -249,5 +409,7 @@ main(int argc, char* argv[])
|
||||
msgparse_test();
|
||||
checklock_stop();
|
||||
printf("%d checks ok.\n", testcount);
|
||||
EVP_cleanup();
|
||||
CRYPTO_cleanup_all_ex_data();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -247,6 +247,76 @@ checkformerr(ldns_buffer* pkt)
|
||||
unit_assert(status != LDNS_STATUS_OK);
|
||||
}
|
||||
|
||||
/** performance test message encoding */
|
||||
static void
|
||||
perf_encode(struct query_info* qi, struct reply_info* rep, uint16_t id,
|
||||
uint16_t flags, ldns_buffer* out, uint32_t timenow,
|
||||
struct edns_data* edns)
|
||||
{
|
||||
static int num = 0;
|
||||
int ret;
|
||||
size_t max = 10000;
|
||||
size_t i;
|
||||
struct timeval start, end;
|
||||
double dt;
|
||||
struct regional* r2 = regional_create();
|
||||
if(gettimeofday(&start, NULL) < 0)
|
||||
fatal_exit("gettimeofday: %s", strerror(errno));
|
||||
/* encode a couple times */
|
||||
for(i=0; i<max; i++) {
|
||||
ret = reply_info_encode(qi, rep, id, flags, out, timenow,
|
||||
r2, 65535, (int)(edns->bits & EDNS_DO) );
|
||||
unit_assert(ret != 0); /* udp packets should fit */
|
||||
attach_edns_record(out, edns);
|
||||
regional_free_all(r2);
|
||||
}
|
||||
if(gettimeofday(&end, NULL) < 0)
|
||||
fatal_exit("gettimeofday: %s", strerror(errno));
|
||||
/* time in millisec */
|
||||
dt = (double)(end.tv_sec - start.tv_sec)*1000. +
|
||||
((double)end.tv_usec - (double)start.tv_usec)/1000.;
|
||||
printf("[%d] did %u in %g msec for %f encode/sec size %d\n", num++,
|
||||
(unsigned)max, dt, (double)max / (dt/1000.),
|
||||
(int)ldns_buffer_limit(out));
|
||||
regional_destroy(r2);
|
||||
}
|
||||
|
||||
/** perf test a packet */
|
||||
static void
|
||||
perftestpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
const char* hex)
|
||||
{
|
||||
struct query_info qi;
|
||||
struct reply_info* rep = 0;
|
||||
int ret;
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint32_t timenow = 0;
|
||||
struct regional* region = regional_create();
|
||||
struct edns_data edns;
|
||||
|
||||
hex_to_buf(pkt, hex);
|
||||
memmove(&id, ldns_buffer_begin(pkt), sizeof(id));
|
||||
if(ldns_buffer_limit(pkt) < 2)
|
||||
flags = 0;
|
||||
else memmove(&flags, ldns_buffer_at(pkt, 2), sizeof(flags));
|
||||
flags = ntohs(flags);
|
||||
ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
|
||||
if(ret != 0) {
|
||||
if(vbmp) printf("parse code %d: %s\n", ret,
|
||||
ldns_lookup_by_id(ldns_rcodes, ret)->name);
|
||||
if(ret == LDNS_RCODE_FORMERR)
|
||||
checkformerr(pkt);
|
||||
unit_assert(ret != LDNS_RCODE_SERVFAIL);
|
||||
} else {
|
||||
perf_encode(&qi, rep, id, flags, out, timenow, &edns);
|
||||
}
|
||||
|
||||
query_info_clear(&qi);
|
||||
reply_info_parsedelete(rep, alloc);
|
||||
regional_destroy(region);
|
||||
}
|
||||
|
||||
/** test a packet */
|
||||
static void
|
||||
testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
|
||||
@@ -359,6 +429,12 @@ simpletest(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out)
|
||||
" 00 01 00 01 00 02 64 b9 00 04 c6 29 00 04 01 4a 0c 52 4f 4f ; 441- 460\n"
|
||||
" 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 01 00 01 00 02 ; 461- 480\n"
|
||||
" 64 b9 00 04 c0 3a 80 1e ");
|
||||
|
||||
/* root delegation from unbound trace with new AAAA glue */
|
||||
perftestpkt(pkt, alloc, out,
|
||||
"55BC84000001000D00000014000002000100000200010007E900001401610C726F6F742D73657276657273036E65740000000200010007E90000040162C01E00000200010007E90000040163C01E00000200010007E90000040164C01E00000200010007E90000040165C01E00000200010007E90000040166C01E00000200010007E90000040167C01E00000200010007E90000040168C01E00000200010007E90000040169C01E00000200010007E9000004016AC01E00000200010007E9000004016BC01E00000200010007E9000004016CC01E00000200010007E9000004016DC01EC01C000100010007E9000004C6290004C03B000100010007E9000004C0E44FC9C04A000100010007E9000004C021040CC059000100010007E900000480080A5AC068000100010007E9000004C0CBE60AC077000100010007E9000004C00505F1C086000100010007E9000004C0702404C095000100010007E9000004803F0235C0A4000100010007E9000004C0249411C0B3000100010007E9000004C03A801EC0C2000100010007E9000004C1000E81C0D1000100010007E9000004C707532AC0E0000100010007E9000004CA0C1B21C01C001C00010007E900001020010503BA3E00000000000000020030C077001C00010007E900001020010500002F0000000000000000000FC095001C00010007E90000102001050000010000"
|
||||
"00000000803F0235C0B3001C00010007E9000010200105030C2700000000000000020030C0C2001C00010007E9000010200107FD000000000000000000000001C0E0001C00010007E900001020010DC30000000000000000000000350000291000000000000000"
|
||||
);
|
||||
}
|
||||
|
||||
/** simple test of parsing, pcat file */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -237,7 +237,7 @@ dstest_entry(struct entry* e, struct alloc_cache* alloc,
|
||||
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");
|
||||
}
|
||||
@@ -263,6 +263,7 @@ verifytest_file(const char* fname, const char* at_date)
|
||||
struct entry* list = read_datafile(fname);
|
||||
struct module_env env;
|
||||
struct val_env ve;
|
||||
uint32_t now = time(NULL);
|
||||
|
||||
if(!list)
|
||||
fatal_exit("could not read %s: %s", fname, strerror(errno));
|
||||
@@ -271,10 +272,11 @@ verifytest_file(const char* fname, const char* at_date)
|
||||
memset(&ve, 0, sizeof(ve));
|
||||
env.scratch = region;
|
||||
env.scratch_buffer = buf;
|
||||
env.now = &now;
|
||||
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! */
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
; config options
|
||||
server:
|
||||
hide-identity: no
|
||||
hide-version: no
|
||||
identity: "test-identity"
|
||||
version: "test-version"
|
||||
access-control: 20.0.0.0/8 allow
|
||||
access-control: 20.40.0.0/16 refuse
|
||||
access-control: 20.40.80.0/24 deny
|
||||
|
||||
CONFIG_END
|
||||
SCENARIO_BEGIN Test access control list
|
||||
|
||||
; version.bind.
|
||||
; allow
|
||||
STEP 1 QUERY ADDRESS 20.1.2.3
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
version.bind. CH TXT
|
||||
ENTRY_END
|
||||
STEP 2 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA
|
||||
SECTION QUESTION
|
||||
version.bind. CH TXT
|
||||
SECTION ANSWER
|
||||
version.bind. 0 CH TXT "test-version"
|
||||
ENTRY_END
|
||||
|
||||
; refuse
|
||||
STEP 3 QUERY ADDRESS 20.40.2.3
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
version.bind. CH TXT
|
||||
ENTRY_END
|
||||
STEP 4 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR REFUSED
|
||||
ENTRY_END
|
||||
|
||||
; deny (drop)
|
||||
STEP 5 QUERY ADDRESS 20.40.80.3
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
version.bind. CH TXT
|
||||
ENTRY_END
|
||||
|
||||
; no answer must be pending
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
; config options
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test iterator donotquery of 127/8.
|
||||
; The scenario presents an iteration chain that has 127.0.0.2 and
|
||||
; 127.255.255.255 as nameserver IPs, like a spam-blocklist.
|
||||
; these are 127/8 localhost and should be blocked, causing servfail.
|
||||
; if not blocked, they cause a lookup, but this file does not specify
|
||||
; 127.* responses, so testbound will fail the test.
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. IN NS ns2.example.com.
|
||||
SECTION ADDITIONAL
|
||||
;ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. IN A 127.255.255.255
|
||||
ns2.example.com. IN A 127.0.0.2
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN A 10.20.30.40
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA SERVFAIL
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
; config options
|
||||
; The island of trust is at example.com
|
||||
server:
|
||||
local-zone: "10.in-addr.arpa" nodefault
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test local data with nodefault for as112 zone.
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
40.30.20.10.in-addr-arpa. IN PTR
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
. IN SOA invalid. invalid. 1 2 3 4 5
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD DO
|
||||
SECTION QUESTION
|
||||
40.30.20.10.in-addr-arpa. IN PTR
|
||||
ENTRY_END
|
||||
; not blocked!
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
40.30.20.10.in-addr-arpa. IN PTR
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
. IN SOA invalid. invalid. 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
+321
@@ -0,0 +1,321 @@
|
||||
; config options
|
||||
server:
|
||||
hide-identity: no
|
||||
hide-version: no
|
||||
identity: "test-identity"
|
||||
version: "test-version"
|
||||
|
||||
; implicit transparent zone should not block id.server
|
||||
local-data: "mydata.server. CH A 10.11.12.13"
|
||||
local-data: "myd2.server. CH A 10.11.12.14"
|
||||
local-data: 'myd3.server. CH TXT "a text record"'
|
||||
; together implicit CH top domain .server is created transparent.
|
||||
|
||||
; static zone
|
||||
local-zone: "local" static
|
||||
local-data: "local SOA nobody nobody 1 2 3 4 5"
|
||||
local-data: "serv.local. A 20.30.40.50"
|
||||
; multiple RRs in this RRset.
|
||||
local-data: "bla.bla.local. A 20.30.40.51"
|
||||
local-data: "bla.bla.local. A 20.30.40.52"
|
||||
local-data: "bla.bla.local. A 20.30.40.53"
|
||||
|
||||
; static zone (no soa)
|
||||
local-zone: "noso.local" static
|
||||
local-data: "bla.bla.noso.local AAAA 2001::2"
|
||||
|
||||
; deny zone (no answer)
|
||||
local-zone: "deny.top." deny
|
||||
|
||||
; refuse zone (error)
|
||||
local-zone: "refuse.top." refuse
|
||||
|
||||
; create implicit data in the IN domain as well
|
||||
local-data: "a.a.implicit. A 20.30.41.50"
|
||||
local-data: "b.a.implicit. A 20.30.42.50"
|
||||
local-data: "b.b.implicit. A 20.30.43.50"
|
||||
local-data: "b.c.implicit. A 20.30.45.50"
|
||||
local-data: "c.c.implicit. A 20.30.44.50"
|
||||
|
||||
CONFIG_END
|
||||
SCENARIO_BEGIN Test local data queries
|
||||
|
||||
; id.server.
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
id.server. CH TXT
|
||||
ENTRY_END
|
||||
STEP 2 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA
|
||||
SECTION QUESTION
|
||||
id.server. CH TXT
|
||||
SECTION ANSWER
|
||||
id.server. 0 CH TXT "test-identity"
|
||||
ENTRY_END
|
||||
|
||||
; mydata.server.
|
||||
STEP 3 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
mydata.server. CH A
|
||||
ENTRY_END
|
||||
STEP 4 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
mydata.server. CH A
|
||||
SECTION ANSWER
|
||||
mydata.server. 3600 CH A 10.11.12.13
|
||||
ENTRY_END
|
||||
|
||||
; nodata with SOA
|
||||
STEP 5 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
local. IN A
|
||||
ENTRY_END
|
||||
STEP 6 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
local. IN A
|
||||
SECTION AUTHORITY
|
||||
local. 3600 IN SOA nobody nobody 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
; positive SOA
|
||||
STEP 7 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
local. IN SOA
|
||||
ENTRY_END
|
||||
STEP 8 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
local. IN SOA
|
||||
SECTION ANSWER
|
||||
local. 3600 IN SOA nobody nobody 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
; positive subdomain
|
||||
STEP 9 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
serv.local. IN A
|
||||
ENTRY_END
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
serv.local. IN A
|
||||
SECTION ANSWER
|
||||
serv.local. IN A 20.30.40.50
|
||||
ENTRY_END
|
||||
|
||||
; no such type
|
||||
STEP 11 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
serv.local. IN MX
|
||||
ENTRY_END
|
||||
STEP 12 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
serv.local. IN MX
|
||||
SECTION AUTHORITY
|
||||
local. 3600 IN SOA nobody nobody 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
; no such type, empty nonterminal
|
||||
STEP 13 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
bla.local. IN MX
|
||||
ENTRY_END
|
||||
STEP 14 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
bla.local. IN MX
|
||||
SECTION AUTHORITY
|
||||
local. 3600 IN SOA nobody nobody 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
; nxdomain with SOA
|
||||
STEP 15 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
doing.local. IN MX
|
||||
ENTRY_END
|
||||
STEP 16 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
doing.local. IN MX
|
||||
SECTION AUTHORITY
|
||||
local. 3600 IN SOA nobody nobody 1 2 3 4 5
|
||||
ENTRY_END
|
||||
|
||||
; nxdomain without SOA
|
||||
STEP 17 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
doing.noso.local. IN MX
|
||||
ENTRY_END
|
||||
STEP 18 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
doing.noso.local. IN MX
|
||||
ENTRY_END
|
||||
|
||||
; positive multiple RR
|
||||
STEP 19 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
bla.bla.local. IN A
|
||||
ENTRY_END
|
||||
STEP 20 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
bla.bla.local. IN A
|
||||
SECTION ANSWER
|
||||
bla.bla.local. IN A 20.30.40.51
|
||||
bla.bla.local. IN A 20.30.40.52
|
||||
bla.bla.local. IN A 20.30.40.53
|
||||
ENTRY_END
|
||||
|
||||
; second implicit transparent zone.
|
||||
STEP 21 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
b.b.implicit. IN A
|
||||
ENTRY_END
|
||||
STEP 22 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
b.b.implicit. IN A
|
||||
SECTION ANSWER
|
||||
b.b.implicit. 3600 IN A 20.30.43.50
|
||||
ENTRY_END
|
||||
|
||||
; localhost A default
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
localhost. IN A
|
||||
ENTRY_END
|
||||
STEP 31 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
localhost. IN A
|
||||
SECTION ANSWER
|
||||
localhost. 10800 IN A 127.0.0.1
|
||||
ENTRY_END
|
||||
|
||||
; localhost AAAA default
|
||||
STEP 32 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
localhost. IN AAAA
|
||||
ENTRY_END
|
||||
STEP 33 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
localhost. IN AAAA
|
||||
SECTION ANSWER
|
||||
localhost. 10800 IN AAAA ::1
|
||||
ENTRY_END
|
||||
|
||||
; localhost A reverse default
|
||||
STEP 34 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
1.0.0.127.in-addr.arpa. IN PTR
|
||||
ENTRY_END
|
||||
STEP 35 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
1.0.0.127.in-addr.arpa. IN PTR
|
||||
SECTION ANSWER
|
||||
1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.
|
||||
ENTRY_END
|
||||
|
||||
; localhost AAAA reverse default
|
||||
STEP 36 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
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. IN PTR
|
||||
ENTRY_END
|
||||
STEP 37 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA
|
||||
SECTION QUESTION
|
||||
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. IN PTR
|
||||
SECTION ANSWER
|
||||
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.
|
||||
ENTRY_END
|
||||
|
||||
; blocked AS112 reverse default
|
||||
STEP 38 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
1.0.0.10.in-addr.arpa. IN PTR
|
||||
ENTRY_END
|
||||
STEP 39 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
1.0.0.10.in-addr.arpa. IN PTR
|
||||
SECTION AUTHORITY
|
||||
10.in-addr.arpa. 10800 IN SOA localhost. nobody.invalid. 1 3600 1200 604800 10800
|
||||
ENTRY_END
|
||||
|
||||
; refuse zone
|
||||
STEP 40 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
www.refuse.top. IN A
|
||||
ENTRY_END
|
||||
STEP 41 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RA AA REFUSED
|
||||
SECTION QUESTION
|
||||
www.refuse.top. IN A
|
||||
ENTRY_END
|
||||
|
||||
; deny zone
|
||||
STEP 42 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
www.deny.top. IN A
|
||||
ENTRY_END
|
||||
; no answer is checked at exit of testbound.
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
+230
@@ -0,0 +1,230 @@
|
||||
; config options
|
||||
; The island of trust is at example.com
|
||||
server:
|
||||
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
|
||||
trust-anchor: "example.net. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}"
|
||||
val-override-date: "20070916134226"
|
||||
msg-cache-size: 8
|
||||
rrset-cache-size: 8
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test cname to positive without cache
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
net. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
net. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NS ns.example.net.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.net. IN A 1.2.3.5
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qname
|
||||
ADJUST copy_id copy_query
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NS ns.example.net.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.net. IN A 1.2.3.5
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
|
||||
example.com. 3600 IN RRSIG DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN CNAME www.example.net.
|
||||
www.example.com. 3600 IN RRSIG CNAME DSA 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFGcJxnNxpWCBzXejiSdl4p1BKRMnAhUApoJrugVBRwFgAoYAhhqlZFac7fE= ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.5
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.net. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.net. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
|
||||
example.net. 3600 IN RRSIG DNSKEY RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. hiFzlQ8VoYgCuvIsfVuxC3mfJDqsTh0yc6abs5xMx5uEcIjb0dndFQx7INOM+imlzveEN73Hqp4OLFpFhsWLlw== ;{id = 30899}
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NS ns.example.net.
|
||||
example.net. 3600 IN RRSIG NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.net. IN A 1.2.3.5
|
||||
ns.example.net. 3600 IN RRSIG A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION ANSWER
|
||||
www.example.net. IN A 11.12.13.14
|
||||
www.example.net. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.net. CPxF5hK9Kg5eT7W6LgZwr0ePYEm9HMcSY4vvqCS6gDWB4X9jvXLCfBkCLhsNybPBpGWlsLi5wM6MTdJXuPpsRA== ;{id = 30899}
|
||||
SECTION AUTHORITY
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD DO
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AD NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN CNAME www.example.net.
|
||||
www.example.com. 3600 IN RRSIG CNAME DSA 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFGcJxnNxpWCBzXejiSdl4p1BKRMnAhUApoJrugVBRwFgAoYAhhqlZFac7fE= ;{id = 2854}
|
||||
www.example.net. IN A 11.12.13.14
|
||||
www.example.net. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.net. CPxF5hK9Kg5eT7W6LgZwr0ePYEm9HMcSY4vvqCS6gDWB4X9jvXLCfBkCLhsNybPBpGWlsLi5wM6MTdJXuPpsRA== ;{id = 30899}
|
||||
SECTION AUTHORITY
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+150
@@ -0,0 +1,150 @@
|
||||
; config options
|
||||
; The island of trust is at example.com
|
||||
server:
|
||||
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
|
||||
val-override-date: "20070916134226"
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test validator with cname-nxdomain for duplicate NSEC detection
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
cname.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
cname.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
|
||||
example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
cname.example.com. IN A
|
||||
SECTION ANSWER
|
||||
cname.example.com. 3600 IN CNAME www.example.com.
|
||||
cname.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFBhJC8qi+g+EOYqzT2q6RxE8Im09AhUAotz8NFnpY+cpEDNBKjM940a74/E= ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
; already includes the necessary NSECs
|
||||
example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000
|
||||
example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854}
|
||||
; wildcard denial
|
||||
example.com. IN NSEC abc.example.com. SOA NS DNSKEY NSEC RRSIG
|
||||
example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFHV2IBWyTmDJvZ+sT+WsGrJX0op/AhQkAijjnjPAtx/tNub2FAGqcexJSg== ;{id = 2854}
|
||||
; qname denial
|
||||
wab.example.com. IN NSEC wzz.example.com. A NSEC RRSIG
|
||||
wab.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFG5DZSEIZC088rjcB1e6sQx8nQz4AhUAtQ09tP1YYLJkhL/Wg1KV2pW4Ivk= ;{id = 2854}
|
||||
SECTIO ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA NXDOMAIN
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000
|
||||
example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854}
|
||||
; wildcard denial
|
||||
example.com. IN NSEC abc.example.com. SOA NS DNSKEY NSEC RRSIG
|
||||
example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFHV2IBWyTmDJvZ+sT+WsGrJX0op/AhQkAijjnjPAtx/tNub2FAGqcexJSg== ;{id = 2854}
|
||||
; qname denial
|
||||
wab.example.com. IN NSEC wzz.example.com. A NSEC RRSIG
|
||||
wab.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFG5DZSEIZC088rjcB1e6sQx8nQz4AhUAtQ09tP1YYLJkhL/Wg1KV2pW4Ivk= ;{id = 2854}
|
||||
SECTIO ADDITIONAL
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD DO
|
||||
SECTION QUESTION
|
||||
cname.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AD NOERROR
|
||||
SECTION QUESTION
|
||||
cname.example.com. IN A
|
||||
SECTION ANSWER
|
||||
cname.example.com. 3600 IN CNAME www.example.com.
|
||||
cname.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFBhJC8qi+g+EOYqzT2q6RxE8Im09AhUAotz8NFnpY+cpEDNBKjM940a74/E= ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN SOA ns.example.com. hostmaster.example.com. 2007090400 28800 7200 604800 18000
|
||||
example.com. 3600 IN RRSIG SOA 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFCNGZ+/OfElYQMCZ77O9Lw9rhk7PAhUAmDcvTAst6Bq83qPq3r6c/Dm1nFc= ;{id = 2854}
|
||||
example.com. IN NSEC abc.example.com. SOA NS DNSKEY NSEC RRSIG
|
||||
example.com. 3600 IN RRSIG NSEC 3 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFHV2IBWyTmDJvZ+sT+WsGrJX0op/AhQkAijjnjPAtx/tNub2FAGqcexJSg== ;{id = 2854}
|
||||
wab.example.com. IN NSEC wzz.example.com. A NSEC RRSIG
|
||||
wab.example.com. 3600 IN RRSIG NSEC 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFG5DZSEIZC088rjcB1e6sQx8nQz4AhUAtQ09tP1YYLJkhL/Wg1KV2pW4Ivk= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
+183
@@ -0,0 +1,183 @@
|
||||
; config options
|
||||
; The island of trust is at example.com
|
||||
server:
|
||||
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
|
||||
trust-anchor: "example.net. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}"
|
||||
val-override-date: "20070916134226"
|
||||
|
||||
stub-zone:
|
||||
name: "."
|
||||
stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET.
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test validator with cname-nxdomain with rcode nxdomain
|
||||
|
||||
; K.ROOT-SERVERS.NET.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 193.0.14.129
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
. IN NS
|
||||
SECTION ANSWER
|
||||
. IN NS K.ROOT-SERVERS.NET.
|
||||
SECTION ADDITIONAL
|
||||
K.ROOT-SERVERS.NET. IN A 193.0.14.129
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
com. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
net. IN NS a.gtld-servers.net.
|
||||
SECTION ADDITIONAL
|
||||
a.gtld-servers.net. IN A 192.5.6.30
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; a.gtld-servers.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 192.5.6.30
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NS ns.example.net.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.net. IN A 1.2.3.5
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
|
||||
example.com. 3600 IN RRSIG DNSKEY DSA 2 3600 20070926134150 20070829134150 2854 example.com. MCwCFBQRtlR4BEv9ohi+PGFjp+AHsJuHAhRCvz0shggvnvI88DFnBDCczHUcVA== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NXDOMAIN
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. 3600 IN CNAME www.example.net.
|
||||
www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFGtYzScyRnHV8U/jOIPYwrlI9t3oAhRF0PIf+IthUR7uCWIvskWp5CfReQ== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.net.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.5
|
||||
|
||||
; response to DNSKEY priming query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.net. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example.net. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b}
|
||||
example.net. 3600 IN RRSIG DNSKEY RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. hiFzlQ8VoYgCuvIsfVuxC3mfJDqsTh0yc6abs5xMx5uEcIjb0dndFQx7INOM+imlzveEN73Hqp4OLFpFhsWLlw== ;{id = 30899}
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NS ns.example.net.
|
||||
example.net. 3600 IN RRSIG NS RSASHA1 2 3600 20070926134150 20070829134150 30899 example.net. E8JX0l4B+cSR5bkHQwOJy1pBmlLMTYCJ8EwfNMU/eCv0YhKwo26rHhn52FGisgv+Nwp7/NbhHqQ+kJgoZC94XA== ;{id = 30899}
|
||||
SECTION ADDITIONAL
|
||||
ns.example.net. IN A 1.2.3.5
|
||||
ns.example.net. 3600 IN RRSIG A RSASHA1 3 3600 20070926134150 20070829134150 30899 example.net. x+tQMC9FhzT7Fcy1pM5NrOC7E8nLd7THPI3C6ie4EwL8PrxllqlR3q/DKB0d/m0qCOPcgN6HFOYURV1s4uAcsw== ;{id = 30899}
|
||||
ENTRY_END
|
||||
|
||||
; response to query of interest
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NXDOMAIN
|
||||
SECTION QUESTION
|
||||
www.example.net. IN A
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NSEC abc.example.net. SOA NS DNSKEY NSEC RRSIG
|
||||
example.net. 3600 IN RRSIG NSEC 5 2 3600 20070926134150 20070829134150 30899 example.net. SEHthmjHyqGlzaOp3Dx6Jn5Fnvvtknw/IF6YSFY8NZLe+YSh1oRJbdEkQ8G92IT08n1jSN6jvKRsFBOUoFOQAw== ;{id = 30899}
|
||||
wab.example.net. IN NSEC wzz.example.net. A NSEC RRSIG
|
||||
wab.example.net. 3600 IN RRSIG NSEC 5 3 3600 20070926134150 20070829134150 30899 example.net. gl8vkI3xfSWx4Pyv5OdOthiewE6u/13kclY7UG9ptuFBddamdJO3RQqyxM6Xcmq+ToO4kMCCyaKijp01gTDoGg== ;{id = 30899}
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD DO
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; recursion happens here.
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA AD NOERROR
|
||||
SECTION QUESTION
|
||||
www.example.com. IN A
|
||||
SECTION ANSWER
|
||||
www.example.com. IN CNAME www.example.net.
|
||||
www.example.com. 3600 IN RRSIG CNAME 3 3 3600 20070926134150 20070829134150 2854 example.com. MCwCFGtYzScyRnHV8U/jOIPYwrlI9t3oAhRF0PIf+IthUR7uCWIvskWp5CfReQ== ;{id = 2854}
|
||||
SECTION AUTHORITY
|
||||
example.net. IN NSEC abc.example.net. SOA NS DNSKEY NSEC RRSIG
|
||||
example.net. 3600 IN RRSIG NSEC 5 2 3600 20070926134150 20070829134150 30899 example.net. SEHthmjHyqGlzaOp3Dx6Jn5Fnvvtknw/IF6YSFY8NZLe+YSh1oRJbdEkQ8G92IT08n1jSN6jvKRsFBOUoFOQAw== ;{id = 30899}
|
||||
wab.example.net. IN NSEC wzz.example.net. A NSEC RRSIG
|
||||
wab.example.net. 3600 IN RRSIG NSEC 5 3 3600 20070926134150 20070829134150 30899 example.net. gl8vkI3xfSWx4Pyv5OdOthiewE6u/13kclY7UG9ptuFBddamdJO3RQqyxM6Xcmq+ToO4kMCCyaKijp01gTDoGg== ;{id = 30899}
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
||||
Vendored
+13
-13
@@ -1,6 +1,6 @@
|
||||
; config options
|
||||
server:
|
||||
trust-anchor: "example. DNSKEY 257 3 133 (AQOnsGyJvywVjYmiLbh0EwIRuWYcDiB/8blX cpkoxtpe19Oicv6Zko+8brVsTMeMOpcUeGB1 zsYKWJ7BvR2894hX )"
|
||||
trust-anchor: "example. DNSKEY 257 3 7 AwEAAcUlFV1vhmqx6NSOUOq2R/dsR7Xm3upJ ( j7IommWSpJABVfW8Q0rOvXdM6kzt+TAu92L9 AbsUdblMFin8CVF3n4s= )"
|
||||
val-override-date: "20120420235959"
|
||||
|
||||
stub-zone:
|
||||
@@ -55,9 +55,9 @@ REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example. IN DNSKEY
|
||||
SECTION ANSWER
|
||||
example. DNSKEY 256 3 133 ( AQO0gEmbZUL6xbD/xQczHbnwYnf+jQjwz/sU 5k44rHTt0Ty+3aOdYoome9TjGMhwkkGby1TL ExXT48OGGdbfIme5 )
|
||||
example. DNSKEY 257 3 133 ( AQOnsGyJvywVjYmiLbh0EwIRuWYcDiB/8blX cpkoxtpe19Oicv6Zko+8brVsTMeMOpcUeGB1 zsYKWJ7BvR2894hX )
|
||||
example. RRSIG DNSKEY 133 1 3600 20150420235959 ( 20051021000000 22088 example. Xpo9ptByXb8M1JR1i0KuRmKGc/YeOLcc6Ptn RJOx6ADLSL2mU6AYX5tAJRMTKTXk6waLIaxu liqUBOkCjLUZMw== )
|
||||
example. DNSKEY 256 3 7 AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LU ( sAD0QPWU+wzt89epO6tHzkMBVDkC7qphQO2h TY4hHn9npWFRw5BYubE= )
|
||||
example. DNSKEY 257 3 7 AwEAAcUlFV1vhmqx6NSOUOq2R/dsR7Xm3upJ ( j7IommWSpJABVfW8Q0rOvXdM6kzt+TAu92L9 AbsUdblMFin8CVF3n4s= )
|
||||
example. RRSIG DNSKEY 7 1 3600 20150420235959 ( 20051021000000 12708 example. AuU4juU9RaxescSmStrQks3Gh9FblGBlVU31 uzMZ/U/FpsUb8aC6QZS+sTsJXnLnz7flGOsm MGQZf3bH+QsCtg== )
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
@@ -68,25 +68,25 @@ SECTION QUESTION
|
||||
a.c.x.w.example. IN A
|
||||
SECTION AUTHORITY
|
||||
example. SOA ns1.example. bugs.x.w.example. 1 3600 300 ( 3600000 3600 )
|
||||
example. RRSIG SOA 133 1 3600 20150420235959 20051021000000 ( 62827 example. hNIkW1xzn+c+9P3W7PUVVptI72xEmOtn+eqQ ux0BE7Pfc6ikx4m7ivOVWETjbwHjqfY0X5G+ rynLZNqsbLm40Q== )
|
||||
example. RRSIG SOA 7 1 3600 20150420235959 20051021000000 ( 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8i q4ZLlYWfUUbbAS41pG+68z81q1xhkYAcEyHd VI2LmKusbZsT0Q== )
|
||||
|
||||
;; NSEC3 RR that covers the "next closer" name (c.x.w.example)
|
||||
;; H(c.x.w.example) = 0va5bpr2ou0vk0lbqeeljri88laipsfh
|
||||
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. NSEC3 1 1 12 aabbccdd ( 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG )
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. rn2tv99+9StXbc7JaEnjT1+8I8f2vVOMOIbF xzlrn94lQLxEOYxQR4SrxDRP4/fC54Jui0Ix 4eI9tMfaTVgehQ== )
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKL IBHYH6blRxK9rC0bMJPwQ4mLIuw85H2EY762 BOCXJZMnpuwhpA== )
|
||||
|
||||
;; NSEC3 RR that matches the closest encloser (x.w.example)
|
||||
;; H(x.w.example) = b4um86eghhds6nea196smvmlo4ors995
|
||||
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. NSEC3 1 1 12 aabbccdd ( gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG )
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. GWDmUk8Sv0dxy/UZFol4Ss7Wz3wBiongcnVy strNODWwdnoO9z6pDh8JLk58ExfEgXm79i4b Ma6C/s/bkk1LvA== )
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh 5u4m/CUiwtblEVOaAKKZd7S959OeiX43aLX3 pOv0TSTyiTxIZg== )
|
||||
|
||||
;; NSEC3 RR that covers wildcard at the closest encloser (*.x.w.example)
|
||||
;; H(*.x.w.example) = 92pqneegtaue7pjatc3l3qnk738c6v5m
|
||||
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. NSEC3 1 1 12 aabbccdd ( b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG )
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. QrjOpXVIvodCw0O8uPMNA+yEeS/o3KKkEIPX r5DoEShq2hymAsRTc/t9BvRKpcSTExyc5m3T vYN3GgN0W/0WHQ== )
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQ Aynzo8EUWH+z6hEIBlUTPGj15eZll6VhQqgZ XtAIR3chwgW+SA== )
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
@@ -108,14 +108,14 @@ SECTION QUESTION
|
||||
a.c.x.w.example. IN A
|
||||
SECTION ANSWER
|
||||
SECTION AUTHORITY
|
||||
example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 ( 3600000 3600 )
|
||||
example. RRSIG SOA 133 1 3600 20150420235959 20051021000000 ( 62827 example. hNIkW1xzn+c+9P3W7PUVVptI72xEmOtn+eqQ ux0BE7Pfc6ikx4m7ivOVWETjbwHjqfY0X5G+ rynLZNqsbLm40Q== )
|
||||
example. SOA ns1.example. bugs.x.w.example. 1 3600 300 ( 3600000 3600 )
|
||||
example. RRSIG SOA 7 1 3600 20150420235959 20051021000000 ( 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8i q4ZLlYWfUUbbAS41pG+68z81q1xhkYAcEyHd VI2LmKusbZsT0Q== )
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. NSEC3 1 1 12 aabbccdd ( 2t7b4g4vsa5smi47k61mv5bv1a22bojr MX DNSKEY NS SOA NSEC3PARAM RRSIG )
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. rn2tv99+9StXbc7JaEnjT1+8I8f2vVOMOIbF xzlrn94lQLxEOYxQR4SrxDRP4/fC54Jui0Ix 4eI9tMfaTVgehQ== )
|
||||
0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKL IBHYH6blRxK9rC0bMJPwQ4mLIuw85H2EY762 BOCXJZMnpuwhpA== )
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. NSEC3 1 1 12 aabbccdd ( gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG )
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. GWDmUk8Sv0dxy/UZFol4Ss7Wz3wBiongcnVy strNODWwdnoO9z6pDh8JLk58ExfEgXm79i4b Ma6C/s/bkk1LvA== )
|
||||
b4um86eghhds6nea196smvmlo4ors995.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh 5u4m/CUiwtblEVOaAKKZd7S959OeiX43aLX3 pOv0TSTyiTxIZg== )
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. NSEC3 1 1 12 aabbccdd ( b4um86eghhds6nea196smvmlo4ors995 NS DS RRSIG )
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. RRSIG NSEC3 133 2 3600 ( 20150420235959 20051021000000 62827 example. QrjOpXVIvodCw0O8uPMNA+yEeS/o3KKkEIPX r5DoEShq2hymAsRTc/t9BvRKpcSTExyc5m3T vYN3GgN0W/0WHQ== )
|
||||
35mthgpgcu1qg68fab165klnsnk3dpvl.example. RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 ( 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQ Aynzo8EUWH+z6hEIBlUTPGj15eZll6VhQqgZ XtAIR3chwgW+SA== )
|
||||
SECTION ADDITIONAL
|
||||
ENTRY_END
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user