diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2023-12-20 17:29:03 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2023-12-20 17:29:03 +0000 |
commit | e04d16abd75a9a3349cc707ffa05b20ca0d8177b (patch) | |
tree | ad9b39eb30451b4b428fe5c417f77d9534295d8f /usr.sbin | |
parent | b0f93e179f7c2c08056743b0ccd32bf97cebee3f (diff) |
update to nsd 4.8.0
OK sthen
Diffstat (limited to 'usr.sbin')
53 files changed, 1922 insertions, 4376 deletions
diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in index 9b6c8b593a7..c13186a69f1 100644 --- a/usr.sbin/nsd/Makefile.in +++ b/usr.sbin/nsd/Makefile.in @@ -79,14 +79,14 @@ EDIT = $(SED) \ TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control-setup.sh MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 -COMMON_OBJ=answer.o axfr.o ixfr.o ixfrcreate.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o siphash.o tsig.o tsig-openssl.o udb.o udbradtree.o udbzone.o util.o bitset.o popen3.o +COMMON_OBJ=answer.o axfr.o ixfr.o ixfrcreate.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o siphash.o tsig.o tsig-openssl.o udb.o util.o bitset.o popen3.o proxy_protocol.o XFRD_OBJ=xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(DNSTAP_OBJ) NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zlexer.o zonec.o zparser.o verify.o ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o xfr-inspect.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o NSD_CHECKZONE_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o zonec.o zparser.o zlexer.o nsd-checkzone.o verify.o NSD_CONTROL_OBJ=$(COMMON_OBJ) nsd-control.o -CUTEST_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o verify.o zonec.o zparser.o zlexer.o cutest_dname.o cutest_dns.o cutest_iterated_hash.o cutest_run.o cutest_radtree.o cutest_rbtree.o cutest_namedb.o cutest_options.o cutest_region.o cutest_rrl.o cutest_udb.o cutest_udbrad.o cutest_util.o cutest_bitset.o cutest_popen3.o cutest_iter.o cutest_event.o cutest.o qtest.o +CUTEST_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o server.o verify.o zonec.o zparser.o zlexer.o cutest_dname.o cutest_dns.o cutest_iterated_hash.o cutest_run.o cutest_radtree.o cutest_rbtree.o cutest_namedb.o cutest_options.o cutest_region.o cutest_rrl.o cutest_udb.o cutest_util.o cutest_bitset.o cutest_popen3.o cutest_iter.o cutest_event.o cutest.o qtest.o NSD_MEM_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) dbaccess.o dbcreate.o difffile.o ipc.o mini_event.o netio.o verify.o server.o zonec.o zparser.o zlexer.o nsd-mem.o all: $(TARGETS) $(MANUALS) @@ -174,9 +174,6 @@ nsd-mem: $(NSD_MEM_OBJ) $(LIBOBJS) cutest: $(CUTEST_OBJ) $(LIBOBJS) popen3_echo $(LINK) -o $@ $(CUTEST_OBJ) $(LIBOBJS) $(SSL_LIBS) $(LIBS) -udb-inspect: udb-inspect.o $(COMMON_OBJ) zonec.o zparser.o zlexer.o $(LIBOBJS) - $(LINK) -o $@ udb-inspect.o $(COMMON_OBJ) zonec.o zparser.o zlexer.o $(LIBOBJS) $(LIBS) - xfr-inspect: xfr-inspect.o $(COMMON_OBJ) zonec.o zparser.o zlexer.o $(LIBOBJS) $(LINK) -o $@ xfr-inspect.o $(COMMON_OBJ) zonec.o zparser.o zlexer.o $(LIBOBJS) $(LIBS) @@ -195,7 +192,7 @@ audit: nsd nsd-checkconf nsd-checkzone nsd-control nsd-mem checksec ./checksec --file=nsd-mem clean: - rm -f *.o $(TARGETS) $(MANUALS) cutest popen3_echo udb-inspect xfr-inspect nsd-mem + rm -f *.o $(TARGETS) $(MANUALS) cutest popen3_echo xfr-inspect nsd-mem distclean: clean rm -f Makefile config.h config.log config.status dnstap/dnstap_config.h @@ -333,9 +330,6 @@ cutest.o: $(srcdir)/tpkg/cutest/cutest.c qtest.o: $(srcdir)/tpkg/cutest/qtest.c $(COMPILE) -c $(srcdir)/tpkg/cutest/qtest.c -udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c - $(COMPILE) -c $(srcdir)/tpkg/cutest/udb-inspect.c - zlexer.c: $(srcdir)/zlexer.lex if test "$(LEX)" != ":"; then rm -f $@ ;\ echo '#include "config.h"' > $@ ;\ @@ -422,6 +416,8 @@ depend: fi rm -f $(DEPEND_TMP) $(DEPEND_TMP2) +proxy_protocol.o: $(srcdir)/util/proxy_protocol.c config.h $(srcdir)/util/proxy_protocol.h + # Dependencies answer.o: $(srcdir)/answer.c config.h $(srcdir)/answer.h $(srcdir)/dns.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h \ @@ -439,14 +435,14 @@ configparser.o: configparser.c config.h $(srcdir)/options.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h configparser.h dbaccess.o: $(srcdir)/dbaccess.c config.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/options.h $(srcdir)/rdata.h \ - $(srcdir)/udb.h $(srcdir)/udbradtree.h $(srcdir)/udbzone.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h \ + $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfrcreate.h dbcreate.o: $(srcdir)/dbcreate.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h $(srcdir)/udbradtree.h \ - $(srcdir)/udbzone.h $(srcdir)/options.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h + $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h \ + $(srcdir)/options.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h difffile.o: $(srcdir)/difffile.c config.h $(srcdir)/difffile.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ - $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/udbzone.h $(srcdir)/udbradtree.h \ + $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h \ $(srcdir)/nsec3.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/zonec.h dname.o: $(srcdir)/dname.c config.h $(srcdir)/dns.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h \ @@ -457,8 +453,8 @@ edns.o: $(srcdir)/edns.c config.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buf $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h ipc.o: $(srcdir)/ipc.c config.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/region-allocator.h \ - $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h \ - $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/xfrd-notify.h \ + $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/dns.h \ + $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/xfrd-notify.h \ $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/packet.h iterated_hash.o: $(srcdir)/iterated_hash.c config.h $(srcdir)/iterated_hash.h \ $(srcdir)/util.h @@ -469,15 +465,15 @@ ixfrcreate.o: $(srcdir)/ixfrcreate.c config.h $(srcdir)/ixfrcreate.h $(srcdir)/d $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/options.h lookup3.o: $(srcdir)/lookup3.c config.h $(srcdir)/lookup3.h -mini_event.o: $(srcdir)/mini_event.c config.h $(srcdir)/mini_event.h $(srcdir)/rbtree.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h +mini_event.o: $(srcdir)/mini_event.c config.h namedb.o: $(srcdir)/namedb.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsec3.h netio.o: $(srcdir)/netio.c config.h $(srcdir)/netio.h $(srcdir)/region-allocator.h \ $(srcdir)/util.h nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h \ - $(srcdir)/remote.h $(srcdir)/xfrd-disk.h $(srcdir)/dnstap/dnstap_collector.h + $(srcdir)/remote.h $(srcdir)/xfrd-disk.h $(srcdir)/dnstap/dnstap_collector.h $(srcdir)/util/proxy_protocol.h \ + config.h nsd-checkconf.o: $(srcdir)/nsd-checkconf.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h @@ -490,11 +486,11 @@ nsd-control.o: $(srcdir)/nsd-control.c config.h $(srcdir)/util.h $(srcdir)/tsig. $(srcdir)/dns.h $(srcdir)/radtree.h nsd-mem.o: $(srcdir)/nsd-mem.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h \ - $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/udbradtree.h + $(srcdir)/namedb.h $(srcdir)/radtree.h nsec3.o: $(srcdir)/nsec3.c config.h $(srcdir)/nsec3.h $(srcdir)/iterated_hash.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/answer.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/tsig.h \ - $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/udbradtree.h $(srcdir)/options.h + $(srcdir)/udb.h $(srcdir)/options.h options.o: $(srcdir)/options.c config.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/difffile.h \ @@ -513,53 +509,48 @@ rdata.o: $(srcdir)/rdata.c config.h $(srcdir)/rdata.h $(srcdir)/dns.h $(srcdir)/ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h region-allocator.o: $(srcdir)/region-allocator.c config.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h -remote.o: $(srcdir)/remote.c config.h $(srcdir)/mini_event.h $(srcdir)/rbtree.h \ - $(srcdir)/region-allocator.h $(srcdir)/remote.h $(srcdir)/util.h $(srcdir)/xfrd.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h $(srcdir)/edns.h \ - $(srcdir)/bitset.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/netio.h +remote.o: $(srcdir)/remote.c config.h $(srcdir)/remote.h $(srcdir)/util.h $(srcdir)/xfrd.h \ + $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/radtree.h \ + $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ + $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/netio.h rrl.o: $(srcdir)/rrl.c config.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/lookup3.h $(srcdir)/options.h -server.o: $(srcdir)/server.c config.h $(srcdir)/mini_event.h $(srcdir)/rbtree.h \ - $(srcdir)/region-allocator.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/bitset.h \ - $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/netio.h $(srcdir)/xfrd.h \ - $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/nsec3.h $(srcdir)/ipc.h $(srcdir)/remote.h \ - $(srcdir)/lookup3.h $(srcdir)/rrl.h $(srcdir)/ixfr.h $(srcdir)/dnstap/dnstap_collector.h $(srcdir)/verify.h +server.o: $(srcdir)/server.c config.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ + $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ + $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/netio.h $(srcdir)/xfrd.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h \ + $(srcdir)/xfrd-disk.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/nsec3.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/lookup3.h $(srcdir)/rrl.h \ + $(srcdir)/ixfr.h $(srcdir)/dnstap/dnstap_collector.h $(srcdir)/verify.h $(srcdir)/util/proxy_protocol.h config.h siphash.o: $(srcdir)/siphash.c tsig.o: $(srcdir)/tsig.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/tsig-openssl.h $(srcdir)/dns.h $(srcdir)/packet.h $(srcdir)/namedb.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h tsig-openssl.o: $(srcdir)/tsig-openssl.c config.h $(srcdir)/tsig-openssl.h \ $(srcdir)/region-allocator.h $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dname.h -udb.o: $(srcdir)/udb.c config.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h -udbradtree.o: $(srcdir)/udbradtree.c config.h $(srcdir)/udbradtree.h $(srcdir)/udb.h \ +udb.o: $(srcdir)/udb.c config.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h \ $(srcdir)/radtree.h -udbzone.o: $(srcdir)/udbzone.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/dns.h \ - $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/iterated_hash.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h \ - $(srcdir)/difffile.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/options.h util.o: $(srcdir)/util.c config.h $(srcdir)/util.h $(srcdir)/region-allocator.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h verify.o: $(srcdir)/verify.c config.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ - $(srcdir)/options.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/verify.h $(srcdir)/mini_event.h $(srcdir)/popen3.h -xfrd.o: $(srcdir)/xfrd.c config.h $(srcdir)/xfrd.h $(srcdir)/mini_event.h $(srcdir)/rbtree.h \ + $(srcdir)/options.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/verify.h $(srcdir)/popen3.h +xfrd.o: $(srcdir)/xfrd.c config.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd-notify.h $(srcdir)/netio.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/rrl.h \ $(srcdir)/query.h $(srcdir)/dnstap/dnstap_collector.h xfrd-disk.o: $(srcdir)/xfrd-disk.c config.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd.h \ - $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h + $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ + $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h xfrd-notify.o: $(srcdir)/xfrd-notify.c config.h $(srcdir)/xfrd-notify.h \ - $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dname.h \ - $(srcdir)/xfrd.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/packet.h + $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/rbtree.h $(srcdir)/xfrd.h \ + $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h $(srcdir)/packet.h xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ - $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h \ - $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h \ - $(srcdir)/packet.h $(srcdir)/xfrd-disk.h -xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udbzone.h $(srcdir)/udb.h \ - $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/packet.h $(srcdir)/namedb.h \ + $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ + $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.h +xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udb.h \ + $(srcdir)/dns.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/packet.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/options.h zlexer.o: zlexer.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h zparser.h @@ -567,15 +558,13 @@ zonec.o: $(srcdir)/zonec.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdi $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \ zparser.h $(srcdir)/options.h $(srcdir)/nsec3.h zparser.o: zparser.c config.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h \ - zparser.h + $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h b64_ntop.o: $(srcdir)/compat/b64_ntop.c config.h b64_pton.o: $(srcdir)/compat/b64_pton.c config.h basename.o: $(srcdir)/compat/basename.c cpuset.o: $(srcdir)/compat/cpuset.c config.h explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h -fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(srcdir)/compat/fake-rfc2553.h config.h \ - +fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(srcdir)/compat/fake-rfc2553.h config.h inet_aton.o: $(srcdir)/compat/inet_aton.c config.h inet_ntop.o: $(srcdir)/compat/inet_ntop.c config.h inet_pton.o: $(srcdir)/compat/inet_pton.c config.h @@ -598,9 +587,9 @@ cutest_dname.o: $(srcdir)/tpkg/cutest/cutest_dname.c config.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h cutest_dns.o: $(srcdir)/tpkg/cutest/cutest_dns.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/dns.h -cutest_event.o: $(srcdir)/tpkg/cutest/cutest_event.c config.h \ - $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ - $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/tpkg/cutest/cutest.h +cutest_event.o: $(srcdir)/tpkg/cutest/cutest_event.c config.h $(srcdir)/nsd.h \ + $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h \ + $(srcdir)/tpkg/cutest/cutest.h cutest_iterated_hash.o: $(srcdir)/tpkg/cutest/cutest_iterated_hash.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h \ $(srcdir)/iterated_hash.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h @@ -610,7 +599,7 @@ cutest_iter.o: $(srcdir)/tpkg/cutest/cutest_iter.c config.h $(srcdir)/nsd.h \ cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsec3.h $(srcdir)/udb.h \ - $(srcdir)/udbzone.h $(srcdir)/udb.h $(srcdir)/udbradtree.h $(srcdir)/difffile.h $(srcdir)/namedb.h $(srcdir)/options.h $(srcdir)/zonec.h $(srcdir)/nsd.h \ + $(srcdir)/udb.h $(srcdir)/difffile.h $(srcdir)/namedb.h $(srcdir)/options.h $(srcdir)/zonec.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/bitset.h cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ @@ -633,18 +622,12 @@ cutest_run.o: $(srcdir)/tpkg/cutest/cutest_run.c config.h \ $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h $(srcdir)/bitset.h cutest_udb.o: $(srcdir)/tpkg/cutest/cutest_udb.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/udb.h -cutest_udbrad.o: $(srcdir)/tpkg/cutest/cutest_udbrad.c config.h \ - $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/udbradtree.h $(srcdir)/udb.h cutest_util.o: $(srcdir)/tpkg/cutest/cutest_util.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h \ - $(srcdir)/mini_event.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h + $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ + $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h popen3_echo.o: $(srcdir)/tpkg/cutest/popen3_echo.c qtest.o: $(srcdir)/tpkg/cutest/qtest.c config.h $(srcdir)/tpkg/cutest/qtest.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/namedb.h \ $(srcdir)/util.h $(srcdir)/nsec3.h $(srcdir)/options.h $(srcdir)/packet.h $(srcdir)/dname.h $(srcdir)/rdata.h -udb-inspect.o: $(srcdir)/tpkg/cutest/udb-inspect.c config.h $(srcdir)/udb.h \ - $(srcdir)/udbradtree.h $(srcdir)/udb.h $(srcdir)/udbzone.h $(srcdir)/dns.h $(srcdir)/udbradtree.h $(srcdir)/util.h $(srcdir)/buffer.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/packet.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/radtree.h \ - $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/namedb.h $(srcdir)/difffile.h $(srcdir)/options.h diff --git a/usr.sbin/nsd/answer.c b/usr.sbin/nsd/answer.c index c7b86fb2072..b99a9467e1c 100644 --- a/usr.sbin/nsd/answer.c +++ b/usr.sbin/nsd/answer.c @@ -67,7 +67,7 @@ encode_answer(query_type *q, const answer_type *answer) int done = 0; #if defined(INET6) && defined(MINIMAL_RESPONSES) - if (q->addr.ss_family == AF_INET6) + if (q->client_addr.ss_family == AF_INET6) minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE; #endif diff --git a/usr.sbin/nsd/axfr.c b/usr.sbin/nsd/axfr.c index 10f3802f1c7..ca318a3aff2 100644 --- a/usr.sbin/nsd/axfr.c +++ b/usr.sbin/nsd/axfr.c @@ -188,12 +188,35 @@ static int axfr_ixfr_can_admit_query(struct nsd* nsd, struct query* q) struct acl_options *acl = NULL; struct zone_options* zone_opt; zone_opt = zone_options_find(nsd->options, q->qname); + if(zone_opt && q->is_proxied && acl_check_incoming_block_proxy( + zone_opt->pattern->provide_xfr, q, &acl) == -1) { + /* the proxy address is blocked */ + if (verbosity >= 2) { + char address[128], proxy[128]; + addr2str(&q->client_addr, address, sizeof(address)); + addr2str(&q->remote_addr, proxy, sizeof(proxy)); + VERBOSITY(2, (LOG_INFO, "%s for %s from %s via proxy %s refused because of proxy, %s %s", + (q->qtype==TYPE_AXFR?"axfr":"ixfr"), + dname_to_string(q->qname, NULL), + address, proxy, + (acl?acl->ip_address_spec:"."), + (acl ? ( acl->nokey ? "NOKEY" + : acl->blocked ? "BLOCKED" + : acl->key_name ) + : "no acl matches"))); + } + RCODE_SET(q->packet, RCODE_REFUSE); + /* RFC8914 - Extended DNS Errors + * 4.19. Extended DNS Error Code 18 - Prohibited */ + q->edns.ede = EDE_PROHIBITED; + return 0; + } if(!zone_opt || acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1) { if (verbosity >= 2) { char a[128]; - addr2str(&q->addr, a, sizeof(a)); + addr2str(&q->client_addr, a, sizeof(a)); VERBOSITY(2, (LOG_INFO, "%s for %s from %s refused, %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches")); @@ -216,7 +239,7 @@ static int axfr_ixfr_can_admit_query(struct nsd* nsd, struct query* q) acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY")); if (verbosity >= 1) { char a[128]; - addr2str(&q->addr, a, sizeof(a)); + addr2str(&q->client_addr, a, sizeof(a)); VERBOSITY(1, (LOG_INFO, "%s for %s from %s", (q->qtype==TYPE_AXFR?"axfr":"ixfr"), dname_to_string(q->qname, NULL), a)); diff --git a/usr.sbin/nsd/config.h.in b/usr.sbin/nsd/config.h.in index 96b7fa15cad..eda3cf95bd8 100644 --- a/usr.sbin/nsd/config.h.in +++ b/usr.sbin/nsd/config.h.in @@ -28,9 +28,6 @@ */ #undef DARWIN_BROKEN_SETREUID -/* Pathname to the NSD database */ -#undef DBFILE - /* Whether ERR_load_SSL_strings is deprecated */ #undef DEPRECATED_ERR_LOAD_SSL_STRINGS @@ -863,6 +860,7 @@ #include <sys/types.h> #include <stdlib.h> #include <stddef.h> +#include <string.h> #ifdef HAVE_TIME_H #include <time.h> diff --git a/usr.sbin/nsd/configlexer.lex b/usr.sbin/nsd/configlexer.lex index 836dd8009dc..9aed0228ffe 100644 --- a/usr.sbin/nsd/configlexer.lex +++ b/usr.sbin/nsd/configlexer.lex @@ -304,6 +304,7 @@ tls-service-ocsp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCS tls-service-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;} tls-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_PORT;} tls-cert-bundle{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_CERT_BUNDLE; } +proxy-protocol-port{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_PROXY_PROTOCOL_PORT; } answer-cookie{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_ANSWER_COOKIE;} cookie-secret{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET;} cookie-secret-file{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_COOKIE_SECRET_FILE;} diff --git a/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y index 901c1ca2cc8..9af2c838264 100644 --- a/usr.sbin/nsd/configparser.y +++ b/usr.sbin/nsd/configparser.y @@ -125,6 +125,7 @@ struct component { %token VAR_TLS_SERVICE_OCSP %token VAR_TLS_PORT %token VAR_TLS_CERT_BUNDLE +%token VAR_PROXY_PROTOCOL_PORT %token VAR_CPU_AFFINITY %token VAR_XFRD_CPU_AFFINITY %token <llng> VAR_SERVER_CPU_AFFINITY @@ -280,7 +281,7 @@ server_option: | VAR_DEBUG_MODE boolean { cfg_parser->opt->debug_mode = $2; } | VAR_USE_SYSTEMD boolean - { /* ignored, deprecated */ } + { /* ignored, obsolete */ } | VAR_HIDE_VERSION boolean { cfg_parser->opt->hide_version = $2; } | VAR_HIDE_IDENTITY boolean @@ -296,14 +297,7 @@ server_option: | VAR_DO_IP6 boolean { cfg_parser->opt->do_ip6 = $2; } | VAR_DATABASE STRING - { - cfg_parser->opt->database = region_strdup(cfg_parser->opt->region, $2); - if(cfg_parser->opt->database[0] == 0 && - cfg_parser->opt->zonefiles_write == 0) - { - cfg_parser->opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; - } - } + { /* ignored, obsolete */ } | VAR_IDENTITY STRING { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); } | VAR_VERSION STRING @@ -386,7 +380,7 @@ server_option: | VAR_ZONELISTFILE STRING { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_DIFFFILE STRING - { /* ignored, deprecated */ } + { /* ignored, obsolete */ } | VAR_XFRDFILE STRING { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); } | VAR_XFRDIR STRING @@ -481,6 +475,14 @@ server_option: } | VAR_TLS_CERT_BUNDLE STRING { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); } + | VAR_PROXY_PROTOCOL_PORT number + { + struct proxy_protocol_port_list* elem = region_alloc_zero( + cfg_parser->opt->region, sizeof(*elem)); + elem->port = $2; + elem->next = cfg_parser->opt->proxy_protocol_port; + cfg_parser->opt->proxy_protocol_port = elem; + } | VAR_ANSWER_COOKIE boolean { cfg_parser->opt->answer_cookie = $2; } | VAR_COOKIE_SECRET STRING diff --git a/usr.sbin/nsd/configure b/usr.sbin/nsd/configure index 950d5849d6a..b6b378c7b24 100644 --- a/usr.sbin/nsd/configure +++ b/usr.sbin/nsd/configure @@ -1,8 +1,8 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for NSD 4.7.0. +# Generated by GNU Autoconf 2.69 for NSD 4.8.0. # -# Report bugs to <nsd-bugs@nlnetlabs.nl>. +# Report bugs to <https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl>. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -267,6 +267,7 @@ fi $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: https://github.com/NLnetLabs/nsd/issues or $0: nsd-bugs@nlnetlabs.nl about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a @@ -580,9 +581,9 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' -PACKAGE_VERSION='4.7.0' -PACKAGE_STRING='NSD 4.7.0' -PACKAGE_BUGREPORT='nsd-bugs@nlnetlabs.nl' +PACKAGE_VERSION='4.8.0' +PACKAGE_STRING='NSD 4.8.0' +PACKAGE_BUGREPORT='https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' # Factoring default headers for most tests. @@ -653,8 +654,6 @@ zonelistfile xfrdfile zonesdir piddir -dbdir -dbfile pidfile logfile nsd_conf_file @@ -1328,7 +1327,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures NSD 4.7.0 to adapt to many kinds of systems. +\`configure' configures NSD 4.8.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1390,7 +1389,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of NSD 4.7.0:";; + short | recursive ) echo "Configuration of NSD 4.8.0:";; esac cat <<\_ACEOF @@ -1441,7 +1440,7 @@ Optional Packages: Pathname to the NSD configuration file --with-logfile=path Pathname to the default log file --with-pidfile=path Pathname to the NSD pidfile - --with-dbfile=path Pathname to the NSD database + --with-dbfile=path Pathname to the NSD database (obsolete) --with-zonesdir=dir NSD default location for zone files --with-xfrdfile=path Pathname to the NSD xfrd zone timer state file --with-zonelistfile=path @@ -1500,7 +1499,7 @@ Some influential environment variables: Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. -Report bugs to <nsd-bugs@nlnetlabs.nl>. +Report bugs to <https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl>. _ACEOF ac_status=$? fi @@ -1563,7 +1562,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -NSD configure 4.7.0 +NSD configure 4.8.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1722,9 +1721,9 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## ------------------------------------ ## -## Report this to nsd-bugs@nlnetlabs.nl ## -## ------------------------------------ ##" +( $as_echo "## ------------------------------------------------------------------------------- ## +## Report this to https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl ## +## ------------------------------------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac @@ -2272,7 +2271,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by NSD $as_me 4.7.0, which was +It was created by NSD $as_me 4.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3985,25 +3984,10 @@ cat >>confdefs.h <<_ACEOF _ACEOF -# -# Determine location of nsd.db -# -dbfile=${dbdir}/nsd.db # Check whether --with-dbfile was given. if test "${with_dbfile+set}" = set; then : - withval=$with_dbfile; dbfile=$withval -fi - - - -cat >>confdefs.h <<_ACEOF -#define DBFILE "`eval echo $dbfile`" -_ACEOF - - -if test -n "$dbfile"; then - dbdir=`dirname $dbfile` + withval=$with_dbfile; fi @@ -6274,10 +6258,7 @@ fi $as_echo_n "checking whether strptime works... " >&6; } if test c${cross_compiling} = cno; then if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + eval "ac_cv_c_strptime_works=maybe" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10909,7 +10890,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by NSD $as_me 4.7.0, which was +This file was extended by NSD $as_me 4.8.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10965,13 +10946,13 @@ $config_files Configuration headers: $config_headers -Report bugs to <nsd-bugs@nlnetlabs.nl>." +Report bugs to <https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -NSD config.status 4.7.0 +NSD config.status 4.8.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/nsd/configure.ac b/usr.sbin/nsd/configure.ac index bd880566fb3..a516fc2c413 100644 --- a/usr.sbin/nsd/configure.ac +++ b/usr.sbin/nsd/configure.ac @@ -5,7 +5,7 @@ dnl sinclude(acx_nlnetlabs.m4) sinclude(dnstap/dnstap.m4) -AC_INIT([NSD],[4.7.0],[nsd-bugs@nlnetlabs.nl]) +AC_INIT([NSD],[4.8.0],[https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl]) AC_CONFIG_HEADERS([config.h]) # @@ -96,20 +96,8 @@ AC_ARG_WITH([pidfile], AC_SUBST(pidfile) AC_DEFINE_UNQUOTED(PIDFILE, ["`eval echo $pidfile`"], [Pathname to the NSD pidfile]) -# -# Determine location of nsd.db -# -dbfile=${dbdir}/nsd.db AC_ARG_WITH([dbfile], - AS_HELP_STRING([--with-dbfile=path],[Pathname to the NSD database]), - [dbfile=$withval]) -AC_SUBST(dbfile) -AC_DEFINE_UNQUOTED(DBFILE, ["`eval echo $dbfile`"], [Pathname to the NSD database]) - -if test -n "$dbfile"; then - dbdir=`dirname $dbfile` -fi -AC_SUBST(dbdir) + AS_HELP_STRING([--with-dbfile=path],[Pathname to the NSD database (obsolete)]),[]) piddir=`dirname $pidfile` AC_SUBST(piddir) @@ -569,7 +557,8 @@ AC_RUN_IFELSE([AC_LANG_SOURCE([[ int main(void) { struct tm tm; char *res; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } -]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"]) +]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"], +[eval "ac_cv_c_strptime_works=maybe"]) else eval "ac_cv_c_strptime_works=maybe" fi @@ -1261,6 +1250,7 @@ AH_BOTTOM([ #include <sys/types.h> #include <stdlib.h> #include <stddef.h> +#include <string.h> #ifdef HAVE_TIME_H #include <time.h> diff --git a/usr.sbin/nsd/dbaccess.c b/usr.sbin/nsd/dbaccess.c index da5d94003d5..5d979979c00 100644 --- a/usr.sbin/nsd/dbaccess.c +++ b/usr.sbin/nsd/dbaccess.c @@ -24,8 +24,6 @@ #include "options.h" #include "rdata.h" #include "udb.h" -#include "udbradtree.h" -#include "udbzone.h" #include "zonec.h" #include "nsec3.h" #include "difffile.h" @@ -33,37 +31,16 @@ #include "ixfr.h" #include "ixfrcreate.h" -static time_t udb_time = 0; -static unsigned long udb_rrsets = 0; -static unsigned long udb_rrset_count = 0; - void namedb_close(struct namedb* db) { if(db) { - if(db->udb) { - udb_base_close(db->udb); - udb_base_free(db->udb); - db->udb = NULL; - } zonec_desetup_parser(); region_destroy(db->region); } } void -namedb_close_udb(struct namedb* db) -{ - if(db) { - /* we cannot actually munmap the data, because other - * processes still need to access the udb, so cleanup the - * udb */ - udb_base_free_keep_mmap(db->udb); - db->udb = NULL; - } -} - -void namedb_free_ixfr(struct namedb* db) { struct radnode* n; @@ -72,148 +49,6 @@ namedb_free_ixfr(struct namedb* db) } } -/** read rr */ -static void -read_rr(namedb_type* db, rr_type* rr, udb_ptr* urr, domain_type* domain) -{ - buffer_type buffer; - ssize_t c; - assert(udb_ptr_get_type(urr) == udb_chunk_type_rr); - rr->owner = domain; - rr->type = RR(urr)->type; - rr->klass = RR(urr)->klass; - rr->ttl = RR(urr)->ttl; - - buffer_create_from(&buffer, RR(urr)->wire, RR(urr)->len); - c = rdata_wireformat_to_rdata_atoms(db->region, db->domains, - rr->type, RR(urr)->len, &buffer, &rr->rdatas); - if(c == -1) { - /* safe on error */ - rr->rdata_count = 0; - rr->rdatas = NULL; - return; - } - rr->rdata_count = c; -} - -/** calculate rr count */ -static uint16_t -calculate_rr_count(udb_base* udb, udb_ptr* rrset) -{ - udb_ptr rr; - uint16_t num = 0; - udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); - while(rr.data) { - num++; - udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); - } - udb_ptr_unlink(&rr, udb); - return num; -} - -/** read rrset */ -static void -read_rrset(udb_base* udb, namedb_type* db, zone_type* zone, - domain_type* domain, udb_ptr* urrset) -{ - rrset_type* rrset; - udb_ptr urr; - unsigned i; - assert(udb_ptr_get_type(urrset) == udb_chunk_type_rrset); - /* if no RRs, do not create anything (robust) */ - if(RRSET(urrset)->rrs.data == 0) - return; - rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); - rrset->zone = zone; - rrset->rr_count = calculate_rr_count(udb, urrset); - rrset->rrs = (rr_type *) region_alloc_array( - db->region, rrset->rr_count, sizeof(rr_type)); - /* add the RRs */ - udb_ptr_new(&urr, udb, &RRSET(urrset)->rrs); - for(i=0; i<rrset->rr_count; i++) { - read_rr(db, &rrset->rrs[i], &urr, domain); - udb_ptr_set_rptr(&urr, udb, &RR(&urr)->next); - } - udb_ptr_unlink(&urr, udb); - domain_add_rrset(domain, rrset); - if(domain == zone->apex) - apex_rrset_checks(db, rrset, domain); -} - -/** read one elem from db, of type domain_d */ -static void read_node_elem(udb_base* udb, namedb_type* db, - region_type* dname_region, zone_type* zone, struct domain_d* d) -{ - const dname_type* dname; - domain_type* domain; - udb_ptr urrset; - - dname = dname_make(dname_region, d->name, 0); - if(!dname) return; - domain = domain_table_insert(db->domains, dname); - assert(domain); /* domain_table_insert should always return non-NULL */ - - /* add rrsets */ - udb_ptr_init(&urrset, udb); - udb_ptr_set_rptr(&urrset, udb, &d->rrsets); - while(urrset.data) { - read_rrset(udb, db, zone, domain, &urrset); - udb_ptr_set_rptr(&urrset, udb, &RRSET(&urrset)->next); - - if(++udb_rrsets % ZONEC_PCT_COUNT == 0 && time(NULL) > udb_time + ZONEC_PCT_TIME) { - udb_time = time(NULL); - VERBOSITY(1, (LOG_INFO, "read %s %d %%", - zone->opts->name, - (int)(udb_rrsets*((unsigned long)100)/udb_rrset_count))); - } - } - region_free_all(dname_region); - udb_ptr_unlink(&urrset, udb); -} - -/** recurse read radix from disk. This radix tree is by domain name, so max of - * 256 depth, and thus the stack usage is small. */ -static void read_zone_recurse(udb_base* udb, namedb_type* db, - region_type* dname_region, zone_type* zone, struct udb_radnode_d* node) -{ - if(node->elem.data) { - /* pre-order process of node->elem, for radix tree this is - * also in-order processing (identical to order tree_next()) */ - read_node_elem(udb, db, dname_region, zone, (struct domain_d*) - ((char*)udb->base + node->elem.data)); - } - if(node->lookup.data) { - uint16_t i; - struct udb_radarray_d* a = (struct udb_radarray_d*) - ((char*)udb->base + node->lookup.data); - /* we do not care for what the exact radix key is, we want - * to add all of them and the read routine does not need - * the radix-key, it has it stored */ - for(i=0; i<a->len; i++) { - if(a->array[i].node.data) { - read_zone_recurse(udb, db, dname_region, zone, - (struct udb_radnode_d*)((char*)udb->base + - a->array[i].node.data)); - } - } - } -} - -/** read zone data */ -static void -read_zone_data(udb_base* udb, namedb_type* db, region_type* dname_region, - udb_ptr* z, zone_type* zone) -{ - udb_ptr dtree; - /* recursively read domains, we only read so ptrs stay valid */ - udb_ptr_new(&dtree, udb, &ZONE(z)->domains); - if(RADTREE(&dtree)->root.data) - read_zone_recurse(udb, db, dname_region, zone, - (struct udb_radnode_d*) - ((char*)udb->base + RADTREE(&dtree)->root.data)); - udb_ptr_unlink(&dtree, udb); -} - /** create a zone */ zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, @@ -294,103 +129,8 @@ namedb_zone_delete(namedb_type* db, zone_type* zone) region_recycle(db->region, zone, sizeof(zone_type)); } -#ifdef HAVE_MMAP -/** read a zone */ -static void -read_zone(udb_base* udb, namedb_type* db, struct nsd_options* opt, - region_type* dname_region, udb_ptr* z) -{ - /* construct dname */ - const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0); - struct zone_options* zo = dname?zone_options_find(opt, dname):NULL; - zone_type* zone; - if(!dname) return; - if(!zo) { - /* deleted from the options, remove it from the nsd.db too */ - VERBOSITY(2, (LOG_WARNING, "zone %s is deleted", - dname_to_string(dname, NULL))); - udb_zone_delete(udb, z); - region_free_all(dname_region); - return; - } - assert(udb_ptr_get_type(z) == udb_chunk_type_zone); - udb_rrsets = 0; - udb_rrset_count = ZONE(z)->rrset_count; - zone = namedb_zone_create(db, dname, zo); - region_free_all(dname_region); - read_zone_data(udb, db, dname_region, z, zone); - zone->is_changed = (ZONE(z)->is_changed != 0); -#ifdef NSEC3 - prehash_zone_complete(db, zone); -#endif -} -#endif /* HAVE_MMAP */ - -#ifdef HAVE_MMAP -/** read zones from nsd.db */ -static void -read_zones(udb_base* udb, namedb_type* db, struct nsd_options* opt, - region_type* dname_region) -{ - udb_ptr ztree, n, z; - udb_ptr_init(&z, udb); - udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); - udb_radix_first(udb,&ztree,&n); - udb_time = time(NULL); - while(n.data) { - udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem); - udb_radix_next(udb, &n); /* store in case n is deleted */ - read_zone(udb, db, opt, dname_region, &z); - udb_ptr_zero(&z, udb); - if(nsd.signal_hint_shutdown) break; - } - udb_ptr_unlink(&ztree, udb); - udb_ptr_unlink(&n, udb); - udb_ptr_unlink(&z, udb); -} -#endif /* HAVE_MMAP */ - -#ifdef HAVE_MMAP -/** try to read the udb file or fail */ -static int -try_read_udb(namedb_type* db, int fd, const char* filename, - struct nsd_options* opt) -{ - /* - * Temporary region used while loading domain names from the - * database. The region is freed after each time a dname is - * read from the database. - */ - region_type* dname_region; - - assert(fd != -1); - if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc, - NULL))) { - /* fd is closed by failed udb create call */ - VERBOSITY(1, (LOG_ERR, "can not use %s, " - "will create anew", filename)); - return 0; - } - /* sanity check if can be opened */ - if(udb_base_get_userflags(db->udb) != 0) { - log_msg(LOG_ERR, "%s was not closed properly, it might " - "be corrupted, will create anew", filename); - udb_base_free(db->udb); - db->udb = NULL; - return 0; - } - /* read if it can be opened */ - dname_region = region_create(xalloc, free); - /* this operation does not fail, we end up with - * something, even if that is an empty namedb */ - read_zones(db->udb, db, opt, dname_region); - region_destroy(dname_region); - return 1; -} -#endif /* HAVE_MMAP */ - struct namedb * -namedb_open (const char* filename, struct nsd_options* opt) +namedb_open (struct nsd_options* opt) { namedb_type* db; @@ -399,7 +139,8 @@ namedb_open (const char* filename, struct nsd_options* opt) * freed in namedb_close. */ region_type* db_region; - int fd; + + (void)opt; #ifdef USE_MMAP_ALLOC db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, @@ -417,54 +158,12 @@ namedb_open (const char* filename, struct nsd_options* opt) zonec_setup_parser(db); if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { - log_msg(LOG_ERR, "unable to load %s: cannot initialize" - "timestamp", filename); + log_msg(LOG_ERR, "unable to load namedb: cannot initialize timestamp"); region_destroy(db_region); return NULL; - } - - /* in dbless mode there is no file to read or mmap */ - if(filename == NULL || filename[0] == 0) { - db->udb = NULL; - return db; } -#ifndef HAVE_MMAP - /* no mmap() system call, use dbless mode */ - VERBOSITY(1, (LOG_INFO, "no mmap(), ignoring database %s", filename)); - db->udb = NULL; - (void)fd; (void)opt; - return db; -#else /* HAVE_MMAP */ - - /* attempt to open, if does not exist, create a new one */ - fd = open(filename, O_RDWR); - if(fd == -1) { - if(errno != ENOENT) { - log_msg(LOG_ERR, "%s: %s", filename, strerror(errno)); - region_destroy(db_region); - return NULL; - } - } - /* attempt to read the file (if it exists) */ - if(fd != -1) { - if(!try_read_udb(db, fd, filename, opt)) - fd = -1; - } - /* attempt to create the file (if necessary or failed read) */ - if(fd == -1) { - if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc, - NULL))) { - region_destroy(db_region); - return NULL; - } - if(!udb_dns_init_file(db->udb)) { - region_destroy(db->region); - return NULL; - } - } return db; -#endif /* HAVE_MMAP */ } /** get the file mtime stat (or nonexist or error) */ @@ -527,15 +226,6 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, } else { const char* zone_fname = zone->filename; struct timespec zone_mtime = zone->mtime; - if(nsd->db->udb) { - zone_fname = udb_zone_get_file_str(nsd->db->udb, - dname_name(domain_dname(zone->apex)), - domain_dname(zone->apex)->name_size); - udb_zone_get_mtime(nsd->db->udb, - dname_name(domain_dname(zone->apex)), - domain_dname(zone->apex)->name_size, - &zone_mtime); - } /* if no zone_fname, then it was acquired in zone transfer, * see if the file is newer than the zone transfer * (regardless if this is a different file), because the @@ -582,60 +272,29 @@ namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); - if(nsd->db->udb) { - region_type* dname_region; - udb_ptr z; - /* see if we can revert to the udb stored version */ - if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname( - zone->apex)), domain_dname(zone->apex)->name_size)) { - /* tell that zone contents has been lost */ - if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); - ixfr_create_cancel(ixfrcr); - return; - } - /* read from udb */ - dname_region = region_create(xalloc, free); - udb_rrsets = 0; - udb_rrset_count = ZONE(&z)->rrset_count; - udb_time = time(NULL); - read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone); - region_destroy(dname_region); - udb_ptr_unlink(&z, nsd->db->udb); - } else { - if(zone->filename) - region_recycle(nsd->db->region, zone->filename, - strlen(zone->filename)+1); - zone->filename = NULL; - if(zone->logstr) - region_recycle(nsd->db->region, zone->logstr, - strlen(zone->logstr)+1); - zone->logstr = NULL; - } + if(zone->filename) + region_recycle(nsd->db->region, zone->filename, + strlen(zone->filename)+1); + zone->filename = NULL; + if(zone->logstr) + region_recycle(nsd->db->region, zone->logstr, + strlen(zone->logstr)+1); + zone->logstr = NULL; } else { VERBOSITY(1, (LOG_INFO, "zone %s read with success", zone->opts->name)); zone->is_ok = 1; zone->is_changed = 0; /* store zone into udb */ - if(nsd->db->udb) { - if(!write_zone_to_udb(nsd->db->udb, zone, &mtime, - fname)) { - log_msg(LOG_ERR, "failed to store zone in db"); - } else { - VERBOSITY(2, (LOG_INFO, "zone %s written to db", - zone->opts->name)); - } - } else { - zone->mtime = mtime; - if(zone->filename) - region_recycle(nsd->db->region, zone->filename, - strlen(zone->filename)+1); - zone->filename = region_strdup(nsd->db->region, fname); - if(zone->logstr) - region_recycle(nsd->db->region, zone->logstr, - strlen(zone->logstr)+1); - zone->logstr = NULL; - } + zone->mtime = mtime; + if(zone->filename) + region_recycle(nsd->db->region, zone->filename, + strlen(zone->filename)+1); + zone->filename = region_strdup(nsd->db->region, fname); + if(zone->logstr) + region_recycle(nsd->db->region, zone->logstr, + strlen(zone->logstr)+1); + zone->logstr = NULL; if(ixfr_create_already_done) { ixfr_readup_exist(zone, nsd, fname); } else if(ixfrcr) { diff --git a/usr.sbin/nsd/dbcreate.c b/usr.sbin/nsd/dbcreate.c index 31b6b0c9b94..ceff916aad1 100644 --- a/usr.sbin/nsd/dbcreate.c +++ b/usr.sbin/nsd/dbcreate.c @@ -19,8 +19,6 @@ #include "namedb.h" #include "udb.h" -#include "udbradtree.h" -#include "udbzone.h" #include "options.h" #include "nsd.h" #include "ixfr.h" @@ -66,121 +64,6 @@ rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz) return len; } -/** delete an RR */ -void -udb_del_rr(udb_base* udb, udb_ptr* z, rr_type* rr) -{ - /* marshal the rdata (uncompressed) into a buffer */ - uint8_t rdata[MAX_RDLENGTH]; - size_t rdatalen = rr_marshal_rdata(rr, rdata, sizeof(rdata)); - assert(udb); - udb_zone_del_rr(udb, z, dname_name(domain_dname(rr->owner)), - domain_dname(rr->owner)->name_size, rr->type, rr->klass, - rdata, rdatalen); -} - -/** write rr */ -int -udb_write_rr(udb_base* udb, udb_ptr* z, rr_type* rr) -{ - /* marshal the rdata (uncompressed) into a buffer */ - uint8_t rdata[MAX_RDLENGTH]; - size_t rdatalen = 0; - unsigned i; - assert(rr); - for(i=0; i<rr->rdata_count; i++) { - rdatalen += add_rdata(rr, i, rdata+rdatalen, - sizeof(rdata)-rdatalen); - } - assert(udb); - return udb_zone_add_rr(udb, z, dname_name(domain_dname(rr->owner)), - domain_dname(rr->owner)->name_size, rr->type, rr->klass, - rr->ttl, rdata, rdatalen); -} - -/** write rrset */ -static int -write_rrset(udb_base* udb, udb_ptr* z, rrset_type* rrset) -{ - unsigned i; - for(i=0; i<rrset->rr_count; i++) { - if(!udb_write_rr(udb, z, &rrset->rrs[i])) - return 0; - } - return 1; -} - -/** write a zone */ -static int -write_zone(udb_base* udb, udb_ptr* z, zone_type* zone) -{ - /* write all domains in the zone */ - domain_type* walk; - rrset_type* rrset; - unsigned long n = 0, c = 0; - time_t t = time(NULL); - - /* count domains: for pct logging */ - for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); - walk=domain_next(walk)) { - n++; - } - /* write them */ - for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex); - walk=domain_next(walk)) { - /* write all rrsets (in the zone) for this domain */ - for(rrset=walk->rrsets; rrset; rrset=rrset->next) { - if(rrset->zone == zone) { - if(!write_rrset(udb, z, rrset)) - return 0; - } - } - /* only check every ... domains, and print pct */ - if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > t + ZONEC_PCT_TIME) { - t = time(NULL); - VERBOSITY(1, (LOG_INFO, "write %s %d %%", - zone->opts->name, (n==0)?0:(int)(c*((unsigned long)100)/n))); - } - } - return 1; -} - -/** create and write a zone */ -int -write_zone_to_udb(udb_base* udb, zone_type* zone, struct timespec* mtime, - const char* file_str) -{ - udb_ptr z; - /* make udb dirty */ - udb_base_set_userflags(udb, 1); - /* find or create zone */ - if(udb_zone_search(udb, &z, dname_name(domain_dname(zone->apex)), - domain_dname(zone->apex)->name_size)) { - /* wipe existing contents */ - udb_zone_clear(udb, &z); - } else { - if(!udb_zone_create(udb, &z, dname_name(domain_dname( - zone->apex)), domain_dname(zone->apex)->name_size)) { - udb_base_set_userflags(udb, 0); - return 0; - } - } - /* set mtime */ - ZONE(&z)->mtime = (uint64_t)mtime->tv_sec; - ZONE(&z)->mtime_nsec = (uint64_t)mtime->tv_nsec; - ZONE(&z)->is_changed = 0; - udb_zone_set_log_str(udb, &z, NULL); - udb_zone_set_file_str(udb, &z, file_str); - /* write zone */ - if(!write_zone(udb, &z, zone)) { - udb_base_set_userflags(udb, 0); - return 0; - } - udb_ptr_unlink(&z, udb); - udb_base_set_userflags(udb, 0); - return 1; -} - int print_rrs(FILE* out, struct zone* zone) { @@ -354,36 +237,21 @@ namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt) char logs[4096]; char bakfile[4096]; struct timespec mtime; - udb_ptr zudb; - if(nsd->db->udb) { - if(!udb_zone_search(nsd->db->udb, &zudb, - dname_name(domain_dname(zone->apex)), - domain_dname(zone->apex)->name_size)) - return; /* zone does not exist in db */ - } /* write to zfile~ first, then rename if that works */ snprintf(bakfile, sizeof(bakfile), "%s~", zfile); - if(nsd->db->udb && ZONE(&zudb)->log_str.data) { - udb_ptr s; - udb_ptr_new(&s, nsd->db->udb, &ZONE(&zudb)->log_str); - strlcpy(logs, (char*)udb_ptr_data(&s), sizeof(logs)); - udb_ptr_unlink(&s, nsd->db->udb); - } else if(zone->logstr) { + if(zone->logstr) strlcpy(logs, zone->logstr, sizeof(logs)); - } else logs[0] = 0; + else + logs[0] = 0; VERBOSITY(1, (LOG_INFO, "writing zone %s to file %s", zone->opts->name, zfile)); if(!write_to_zonefile(zone, bakfile, logs)) { - if(nsd->db->udb) - udb_ptr_unlink(&zudb, nsd->db->udb); (void)unlink(bakfile); /* delete failed file */ return; /* error already printed */ } if(rename(bakfile, zfile) == -1) { log_msg(LOG_ERR, "rename(%s to %s) failed: %s", bakfile, zfile, strerror(errno)); - if(nsd->db->udb) - udb_ptr_unlink(&zudb, nsd->db->udb); (void)unlink(bakfile); /* delete failed file */ return; } @@ -393,23 +261,15 @@ namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt) if(!file_get_mtime(zfile, &mtime, ¬exist)) { get_time(&mtime); } - if(nsd->db->udb) { - ZONE(&zudb)->mtime = (uint64_t)mtime.tv_sec; - ZONE(&zudb)->mtime_nsec = (uint64_t)mtime.tv_nsec; - ZONE(&zudb)->is_changed = 0; - udb_zone_set_log_str(nsd->db->udb, &zudb, NULL); - udb_ptr_unlink(&zudb, nsd->db->udb); - } else { - zone->mtime = mtime; - if(zone->filename) - region_recycle(nsd->db->region, zone->filename, - strlen(zone->filename)+1); - zone->filename = region_strdup(nsd->db->region, zfile); - if(zone->logstr) - region_recycle(nsd->db->region, zone->logstr, - strlen(zone->logstr)+1); - zone->logstr = NULL; - } + zone->mtime = mtime; + if(zone->filename) + region_recycle(nsd->db->region, zone->filename, + strlen(zone->filename)+1); + zone->filename = region_strdup(nsd->db->region, zfile); + if(zone->logstr) + region_recycle(nsd->db->region, zone->logstr, + strlen(zone->logstr)+1); + zone->logstr = NULL; if(zone_is_ixfr_enabled(zone) && zone->ixfr) ixfr_write_to_file(zone, zfile); } diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index c48c7068734..51aa2d793f2 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -19,7 +19,6 @@ #include "packet.h" #include "rdata.h" #include "udb.h" -#include "udbzone.h" #include "nsec3.h" #include "nsd.h" #include "rrl.h" @@ -462,8 +461,7 @@ find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass, #ifdef NSEC3 /* see if nsec3 deletion triggers need action */ static void -nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, - udb_ptr* udbz) +nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone) { /* the RR has not actually been deleted yet, so we can inspect it */ if(!zone->nsec3_param) @@ -494,7 +492,7 @@ nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, /* clear trees, wipe hashes, wipe precompile */ nsec3_clear_precompile(db, zone); /* pick up new nsec3param (from udb, or avoid deleted rr) */ - nsec3_find_zone_param(db, zone, udbz, rr, 0); + nsec3_find_zone_param(db, zone, rr, 0); /* if no more NSEC3, done */ if(!zone->nsec3_param) return; @@ -583,8 +581,7 @@ nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain, /* see if nsec3 addition triggers need action */ static void -nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, - udb_ptr* udbz) +nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone) { /* the RR has been added in full, also to UDB (and thus NSEC3PARAM * in the udb has been adjusted) */ @@ -606,7 +603,7 @@ nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone, prehash_add(db->domains, rr->owner); } else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) { /* see if this means NSEC3 chain can be used */ - nsec3_find_zone_param(db, zone, udbz, NULL, 0); + nsec3_find_zone_param(db, zone, NULL, 0); if(!zone->nsec3_param) return; nsec3_zone_trees_create(db->region, zone); @@ -669,7 +666,7 @@ int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, - region_type* temp_region, udb_ptr* udbz, int* softfail) + region_type* temp_region, int* softfail) { domain_type *domain; rrset_type *rrset; @@ -715,12 +712,9 @@ delete_RR(namedb_type* db, const dname_type* dname, *softfail = 1; return 1; /* not fatal error */ } - /* delete the normalized RR from the udb */ - if(db->udb) - udb_del_rr(db->udb, udbz, &rrset->rrs[rrnum]); #ifdef NSEC3 /* process triggers for RR deletions */ - nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone, udbz); + nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone); #endif /* lower usage (possibly deleting other domains, and thus * invalidating the current RR's domain pointers) */ @@ -785,7 +779,7 @@ delete_RR(namedb_type* db, const dname_type* dname, int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, - buffer_type* packet, size_t rdatalen, zone_type *zone, udb_ptr* udbz, + buffer_type* packet, size_t rdatalen, zone_type *zone, int* softfail) { domain_type* domain; @@ -879,13 +873,6 @@ add_RR(namedb_type* db, const dname_type* dname, #endif /* NSEC3 */ } - /* write the just-normalized RR to the udb */ - if(db->udb) { - if(!udb_write_rr(db->udb, udbz, &rrset->rrs[rrset->rr_count - 1])) { - log_msg(LOG_ERR, "could not add RR to nsd.db, disk-space?"); - return 0; - } - } #ifdef NSEC3 if(rrset_added) { domain_type* p = domain->parent; @@ -897,7 +884,7 @@ add_RR(namedb_type* db, const dname_type* dname, p = p->parent; } } - nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone, udbz); + nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone); #endif /* NSEC3 */ return 1; } @@ -1003,20 +990,16 @@ delete_zone_rrs(namedb_type* db, zone_type* zone) /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ static int -apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, - struct nsd_options* opt, uint32_t seq_nr, uint32_t seq_total, +apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno, + uint32_t seq_nr, uint32_t seq_total, int* is_axfr, int* delete_mode, int* rr_count, - udb_ptr* udbz, struct zone** zone_res, const char* patname, int* bytes, + struct zone* zone, int* bytes, int* softfail, struct ixfr_store* ixfr_store) { uint32_t msglen, checklen, pkttype; - int qcount, ancount, counter; + int qcount, ancount; buffer_type* packet; region_type* region; - int i; - uint16_t rrlen; - const dname_type *dname_zone, *dname; - zone_type* zone_db; /* note that errors could not really happen due to format of the * packet since xfrd has checked all dnames and RRs before commit, @@ -1066,15 +1049,6 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, } *bytes += msglen; - dname_zone = dname_parse(region, zone); - zone_db = find_or_create_zone(db, dname_zone, opt, zone, patname); - if(!zone_db) { - log_msg(LOG_ERR, "could not create zone %s %s", zone, patname); - region_destroy(region); - return 0; - } - *zone_res = zone_db; - /* only answer section is really used, question, additional and authority section RRs are skipped */ qcount = QDCOUNT(packet); @@ -1088,79 +1062,24 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, } /* skip queries */ - for(i=0; i<qcount; ++i) + for(int i=0; i < qcount; ++i) { if(!packet_skip_rr(packet, 1)) { log_msg(LOG_ERR, "bad RR in question section"); region_destroy(region); return 0; } - - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s", - dname_to_string(dname_zone, 0))); - /* first RR: check if SOA and correct zone & serialno */ - if(*rr_count == 0) { - size_t ttlpos; - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR", - dname_to_string(dname_zone, 0))); - dname = dname_make_from_packet(region, packet, 1, 1); - if(!dname) { - log_msg(LOG_ERR, "could not parse dname"); - region_destroy(region); - return 0; - } - if(dname_compare(dname_zone, dname) != 0) { - log_msg(LOG_ERR, "SOA dname %s not equal to zone", - dname_to_string(dname,0)); - log_msg(LOG_ERR, "zone dname is %s", - dname_to_string(dname_zone,0)); - region_destroy(region); - return 0; - } - if(!buffer_available(packet, 10)) { - log_msg(LOG_ERR, "bad SOA RR"); - region_destroy(region); - return 0; - } - if(buffer_read_u16(packet) != TYPE_SOA || - buffer_read_u16(packet) != CLASS_IN) { - log_msg(LOG_ERR, "first RR not SOA IN"); - region_destroy(region); - return 0; - } - ttlpos = buffer_position(packet); - buffer_skip(packet, sizeof(uint32_t)); /* ttl */ - if(!buffer_available(packet, buffer_read_u16(packet)) || - !packet_skip_dname(packet) /* skip prim_ns */ || - !packet_skip_dname(packet) /* skip email */) { - log_msg(LOG_ERR, "bad SOA RR"); - region_destroy(region); - return 0; - } - if(buffer_read_u32(packet) != serialno) { - buffer_skip(packet, -4); - log_msg(LOG_ERR, "SOA serial %u different from commit %u", - (unsigned)buffer_read_u32(packet), (unsigned)serialno); - region_destroy(region); - return 0; - } - buffer_skip(packet, sizeof(uint32_t)*4); - counter = 1; - *rr_count = 1; - *is_axfr = 0; - *delete_mode = 0; - if(ixfr_store) - ixfr_store_add_newsoa(ixfr_store, packet, ttlpos); - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d", - dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } - else counter = 0; - for(; counter < ancount; ++counter,++(*rr_count)) - { - uint16_t type, klass; + DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "diff: started packet for zone %s", + domain_to_string(zone->apex))); + + for(int i=0; i < ancount; ++i, ++(*rr_count)) { + const dname_type *owner; + uint16_t type, klass, rrlen; uint32_t ttl; - if(!(dname=dname_make_from_packet(region, packet, 1,1))) { + owner = dname_make_from_packet(region, packet, 1, 1); + if(!owner) { log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count); region_destroy(region); return 0; @@ -1180,79 +1099,119 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, region_destroy(region); return 0; } - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", - dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); - if(*rr_count == 1 && type != TYPE_SOA) { - /* second RR: if not SOA: this is an AXFR; delete all zone contents */ -#ifdef NSEC3 - nsec3_clear_precompile(db, zone_db); - zone_db->nsec3_param = NULL; -#endif - delete_zone_rrs(db, zone_db); - if(db->udb) - udb_zone_clear(db->udb, udbz); - /* add everything else (incl end SOA) */ - *delete_mode = 0; - *is_axfr = 1; - if(ixfr_store) { - ixfr_store_cancel(ixfr_store); - ixfr_store_delixfrs(zone_db); - } - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", - dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); - } - if(*rr_count == 1 && type == TYPE_SOA) { - /* if the serial no of the SOA equals the serialno, then AXFR */ - size_t bufpos = buffer_position(packet); - uint32_t thisserial; - if(!packet_skip_dname(packet) || - !packet_skip_dname(packet) || - buffer_remaining(packet) < sizeof(uint32_t)*5) + DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", + domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); + + if (type == TYPE_SOA) { + size_t position; + uint32_t serial; + position = buffer_position(packet); + if (!packet_skip_dname(packet) || + !packet_skip_dname(packet) || + buffer_remaining(packet) < sizeof(uint32_t) * 5) { log_msg(LOG_ERR, "bad xfr SOA RR formerr."); region_destroy(region); return 0; } - thisserial = buffer_read_u32(packet); - if(thisserial == serialno) { - /* AXFR */ -#ifdef NSEC3 - nsec3_clear_precompile(db, zone_db); - zone_db->nsec3_param = NULL; -#endif - delete_zone_rrs(db, zone_db); - if(db->udb) - udb_zone_clear(db->udb, udbz); - *delete_mode = 0; - *is_axfr = 1; + + serial = buffer_read_u32(packet); + buffer_set_position(packet, position); + + /* first RR: check if SOA and correct zone & serialno */ + if (*rr_count == 0) { + assert(!*is_axfr); + assert(!*delete_mode); + if (klass != CLASS_IN) { + log_msg(LOG_ERR, "first RR not SOA IN"); + region_destroy(region); + return 0; + } + if(dname_compare(domain_dname(zone->apex), owner) != 0) { + log_msg(LOG_ERR, "SOA dname not equal to zone %s", + domain_to_string(zone->apex)); + region_destroy(region); + return 0; + } + if(serial != serialno) { + log_msg(LOG_ERR, "SOA serial %u different from commit %u", + (unsigned)serial, (unsigned)serialno); + region_destroy(region); + return 0; + } + buffer_skip(packet, rrlen); + if(ixfr_store) - ixfr_store_cancel(ixfr_store); + ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); + + continue; + } else if (*rr_count == 1) { + assert(!*is_axfr); + assert(!*delete_mode); + /* if the serial no of the SOA equals the serialno, then AXFR */ + if (serial == serialno) + goto axfr; + *delete_mode = 1; + /* must have stuff in memory for a successful IXFR, + * the serial number of the SOA has been checked + * previously (by check_for_bad_serial) if it exists */ + if(!domain_find_rrset(zone->apex, zone, TYPE_SOA)) { + log_msg(LOG_ERR, "%s SOA serial %u is not " + "in memory, skip IXFR", domain_to_string(zone->apex), serialno); + region_destroy(region); + /* break out and stop the IXFR, ignore it */ + return 2; + } + + if(ixfr_store) + ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen); + } else if (!*is_axfr) { + /* do not delete final SOA RR for IXFR */ + if (i == ancount - 1 && seq_nr == seq_total - 1) { + if (ixfr_store) { + ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); + } + *delete_mode = 0; + buffer_skip(packet, rrlen); + continue; + } else + *delete_mode = !*delete_mode; + + if (ixfr_store && *delete_mode) { + ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen); + ixfr_store_finish(ixfr_store, nsd, NULL); + ixfr_store_start(zone, ixfr_store); + ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen); + } + /* switch from delete-part to add-part and back again, + just before soa - so it gets deleted and added too */ + DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", + domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); } - /* must have stuff in memory for a successful IXFR, - * the serial number of the SOA has been checked - * previously (by check_for_bad_serial) if it exists */ - if(!*is_axfr && !domain_find_rrset(zone_db->apex, - zone_db, TYPE_SOA)) { - log_msg(LOG_ERR, "%s SOA serial %u is not " - "in memory, skip IXFR", zone, serialno); + } else { + if (*rr_count == 0) { + log_msg(LOG_ERR, "first RR not SOA IN"); region_destroy(region); - /* break out and stop the IXFR, ignore it */ - return 2; + return 0; + /* second RR: if not SOA: this is an AXFR; delete all zone contents */ + } else if (*rr_count == 1) { +axfr: + *is_axfr = 1; +#ifdef NSEC3 + nsec3_clear_precompile(nsd->db, zone); + zone->nsec3_param = NULL; +#endif + delete_zone_rrs(nsd->db, zone); + if(ixfr_store) { + ixfr_store_cancel(ixfr_store); + ixfr_store_delixfrs(zone); + } + DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", + domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode)); } - buffer_set_position(packet, bufpos); - if(!*is_axfr && ixfr_store) - ixfr_store_add_oldsoa(ixfr_store, ttl, packet, - rrlen); - } - if(type == TYPE_SOA && !*is_axfr) { - /* switch from delete-part to add-part and back again, - just before soa - so it gets deleted and added too */ - /* this means we switch to delete mode for the final SOA */ - *delete_mode = !*delete_mode; - DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", - dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); } + if(type == TYPE_TSIG || type == TYPE_OPT) { /* ignore pseudo RRs */ buffer_skip(packet, rrlen); @@ -1261,30 +1220,25 @@ apply_ixfr(namedb_type* db, FILE *in, const char* zone, uint32_t serialno, DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", *delete_mode?"del":"add", - dname_to_string(dname,0), rrtype_to_string(type))); + dname_to_string(owner, 0), rrtype_to_string(type))); if(*delete_mode) { + assert(!*is_axfr); /* delete this rr */ - if(!*is_axfr && type == TYPE_SOA && counter==ancount-1 - && seq_nr == seq_total-1) { - continue; /* do not delete final SOA RR for IXFR */ - } if(ixfr_store) - ixfr_store_delrr(ixfr_store, dname, type, + ixfr_store_delrr(ixfr_store, owner, type, klass, ttl, packet, rrlen, region); - if(!delete_RR(db, dname, type, klass, packet, - rrlen, zone_db, region, udbz, softfail)) { + if(!delete_RR(nsd->db, owner, type, klass, packet, + rrlen, zone, region, softfail)) { region_destroy(region); return 0; } - } - else - { + } else { /* add this rr */ if(ixfr_store) - ixfr_store_addrr(ixfr_store, dname, type, + ixfr_store_addrr(ixfr_store, owner, type, klass, ttl, packet, rrlen, region); - if(!add_RR(db, dname, type, klass, ttl, packet, - rrlen, zone_db, udbz, softfail)) { + if(!add_RR(nsd->db, owner, type, klass, ttl, packet, + rrlen, zone, softfail)) { region_destroy(region); return 0; } @@ -1320,8 +1274,8 @@ check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) } static int -apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, - struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task, +apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, + struct nsd_options* ATTR_UNUSED(opt), udb_base* taskudb, udb_ptr* last_task, uint32_t xfrfilenr) { char zone_buf[3072]; @@ -1335,7 +1289,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, uint32_t i; int num_bytes = 0; (void)last_task; - assert(zonedb); + assert(zone); /* read zone name and serial */ if(!diff_read_32(in, &type)) { @@ -1366,9 +1320,9 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, } /* has been read in completely */ - if(strcmp(zone_buf, domain_to_string(zonedb->apex)) != 0) { + if(strcmp(zone_buf, domain_to_string(zone->apex)) != 0) { log_msg(LOG_ERR, "file %s does not match task %s", - zone_buf, domain_to_string(zonedb->apex)); + zone_buf, domain_to_string(zone->apex)); return 0; } switch(committed) { @@ -1397,50 +1351,22 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, return 1; } - if(!zonedb->is_skipped) + if(!zone->is_skipped) { int is_axfr=0, delete_mode=0, rr_count=0, softfail=0; - const dname_type* apex = domain_dname_const(zonedb->apex); - udb_ptr z; struct ixfr_store* ixfr_store = NULL, ixfr_store_mem; DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf)); - if(zone_is_ixfr_enabled(zonedb)) - ixfr_store = ixfr_store_start(zonedb, &ixfr_store_mem, - old_serial, new_serial); - memset(&z, 0, sizeof(z)); /* if udb==NULL, have &z defined */ - if(nsd->db->udb) { - if(udb_base_get_userflags(nsd->db->udb) != 0) { - diff_update_commit( - zone_buf, DIFF_CORRUPT, nsd, xfrfilenr); - log_msg(LOG_ERR, "database corrupted, cannot update"); - exit(1); - } - /* all parts were checked by xfrd before commit */ - if(!udb_zone_search(nsd->db->udb, &z, dname_name(apex), - apex->name_size)) { - /* create it */ - if(!udb_zone_create(nsd->db->udb, &z, dname_name(apex), - apex->name_size)) { - /* out of disk space perhaps */ - log_msg(LOG_ERR, "could not udb_create_zone " - "%s, disk space full?", zone_buf); - ixfr_store_free(ixfr_store); - return 0; - } - } - /* set the udb dirty until we are finished applying changes */ - udb_base_set_userflags(nsd->db->udb, 1); - } + if(zone_is_ixfr_enabled(zone)) + ixfr_store = ixfr_store_start(zone, &ixfr_store_mem); /* read and apply all of the parts */ for(i=0; i<num_parts; i++) { int ret; DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i)); - ret = apply_ixfr(nsd->db, in, zone_buf, new_serial, opt, + ret = apply_ixfr(nsd, in, new_serial, i, num_parts, &is_axfr, &delete_mode, - &rr_count, (nsd->db->udb?&z:NULL), &zonedb, - patname_buf, &num_bytes, &softfail, ixfr_store); - assert(zonedb); + &rr_count, zone, + &num_bytes, &softfail, ixfr_store); if(ret == 0) { log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf); diff_update_commit( @@ -1451,8 +1377,6 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, break; } } - if(nsd->db->udb) - udb_base_set_userflags(nsd->db->udb, 0); /* read the final log_str: but do not fail on it */ if(!diff_read_str(in, log_buf, sizeof(log_buf))) { log_msg(LOG_ERR, "could not read log for transfer %s", @@ -1460,32 +1384,21 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, snprintf(log_buf, sizeof(log_buf), "error reading log"); } #ifdef NSEC3 - if(zonedb) prehash_zone(nsd->db, zonedb); + prehash_zone(nsd->db, zone); #endif /* NSEC3 */ - zonedb->is_changed = 1; - zonedb->is_updated = 1; - zonedb->is_checked = (committed == DIFF_VERIFIED); - if(nsd->db->udb) { - assert(z.base); - ZONE(&z)->is_changed = 1; - /* FIXME: need to set is_updated here? */ - ZONE(&z)->mtime = time_end_0; - ZONE(&z)->mtime_nsec = time_end_1*1000; - udb_zone_set_log_str(nsd->db->udb, &z, log_buf); - udb_zone_set_file_str(nsd->db->udb, &z, NULL); - udb_ptr_unlink(&z, nsd->db->udb); - } else { - zonedb->mtime.tv_sec = time_end_0; - zonedb->mtime.tv_nsec = time_end_1*1000; - if(zonedb->logstr) - region_recycle(nsd->db->region, zonedb->logstr, - strlen(zonedb->logstr)+1); - zonedb->logstr = region_strdup(nsd->db->region, log_buf); - if(zonedb->filename) - region_recycle(nsd->db->region, zonedb->filename, - strlen(zonedb->filename)+1); - zonedb->filename = NULL; - } + zone->is_changed = 1; + zone->is_updated = 1; + zone->is_checked = (committed == DIFF_VERIFIED); + zone->mtime.tv_sec = time_end_0; + zone->mtime.tv_nsec = time_end_1*1000; + if(zone->logstr) + region_recycle(nsd->db->region, zone->logstr, + strlen(zone->logstr)+1); + zone->logstr = region_strdup(nsd->db->region, log_buf); + if(zone->filename) + region_recycle(nsd->db->region, zone->filename, + strlen(zone->filename)+1); + zone->filename = NULL; if(softfail && taskudb && !is_axfr) { log_msg(LOG_ERR, "Failed to apply IXFR cleanly " "(deletes nonexistent RRs, adds existing RRs). " @@ -1513,9 +1426,31 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zonedb, FILE* in, return 1; } +static void udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void *arg) +{ + struct task_list_d* p = (struct task_list_d*)d; + assert(s >= p->size); + (void)s; + (*cb)(base, &p->next, arg); +} + +void udb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, + udb_walk_relptr_cb* cb, void *arg) +{ + (void)warg; + switch(t) { + case udb_chunk_type_task: + udb_task_walk_chunk(base, d, s, cb, arg); + break; + default: + /* no rel ptrs */ + break; + } +} + struct udb_base* task_file_create(const char* file) { - return udb_base_create_new(file, &namedb_walkfunc, NULL); + return udb_base_create_new(file, &udb_walkfunc, NULL); } static int @@ -1703,26 +1638,6 @@ void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v) udb_ptr_unlink(&e, udb); } -#ifdef BIND8_STATS -void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat, - size_t child_count) -{ - void* p; - udb_ptr e; - DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task stat_info")); - if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+ - sizeof(*stat) + sizeof(stc_type)*child_count, NULL)) { - log_msg(LOG_ERR, "tasklist: out of space, cannot add stati"); - return NULL; - } - TASKLIST(&e)->task_type = task_stat_info; - p = TASKLIST(&e)->zname; - memcpy(p, stat, sizeof(*stat)); - udb_ptr_unlink(&e, udb); - return (char*)p + sizeof(*stat); -} -#endif /* BIND8_STATS */ - void task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone, const char* pattern, unsigned zonestatid) @@ -1967,7 +1882,7 @@ task_process_set_verbosity(struct task_list_d* task) } static void -task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, +task_process_checkzones(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task, struct task_list_d* task) { /* on SIGHUP check if zone-text-files changed and if so, @@ -1976,10 +1891,10 @@ task_process_checkzones(struct nsd* nsd, udb_base* udb, udb_ptr* last_task, struct zone_options* zo = zone_options_find(nsd->options, task->zname); if(zo) - namedb_check_zonefile(nsd, udb, last_task, zo); + namedb_check_zonefile(nsd, taskudb, last_task, zo); } else { /* check all zones */ - namedb_check_zonefiles(nsd, nsd->options, udb, last_task); + namedb_check_zonefiles(nsd, nsd->options, taskudb, last_task); } } @@ -2041,14 +1956,6 @@ task_process_del_zone(struct nsd* nsd, struct task_list_d* task) zone->nsec3_param = NULL; #endif delete_zone_rrs(nsd->db, zone); - if(nsd->db->udb) { - udb_ptr udbz; - if(udb_zone_search(nsd->db->udb, &udbz, dname_name(task->zname), - task->zname->name_size)) { - udb_zone_delete(nsd->db->udb, &udbz); - udb_ptr_unlink(&udbz, nsd->db->udb); - } - } /* remove from zonetree, apex, soa */ zopt = zone->opts; diff --git a/usr.sbin/nsd/difffile.h b/usr.sbin/nsd/difffile.h index 77d1dedd7ce..ba777c8a509 100644 --- a/usr.sbin/nsd/difffile.h +++ b/usr.sbin/nsd/difffile.h @@ -59,12 +59,12 @@ void delete_zone_rrs(namedb_type* db, zone_type* zone); int delete_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, buffer_type* packet, size_t rdatalen, zone_type *zone, - region_type* temp_region, struct udb_ptr* udbz, int* softfail); + region_type* temp_region, int* softfail); /* add an RR */ int add_RR(namedb_type* db, const dname_type* dname, uint16_t type, uint16_t klass, uint32_t ttl, buffer_type* packet, size_t rdatalen, zone_type *zone, - struct udb_ptr* udbz, int* softfail); + int* softfail); enum soainfo_hint { soainfo_ok, @@ -90,8 +90,6 @@ struct task_list_d { task_write_zonefiles, /** set verbosity */ task_set_verbosity, - /** statistic info */ - task_stat_info, /** add a zone */ task_add_zone, /** delete zone */ @@ -134,8 +132,6 @@ void task_clear(udb_base* udb); void task_new_soainfo(udb_base* udb, udb_ptr* last, struct zone* z, enum soainfo_hint hint); void task_new_expire(udb_base* udb, udb_ptr* last, const struct dname* z, int expired); -void* task_new_stat_info(udb_base* udb, udb_ptr* last, struct nsdst* stat, - size_t child_count); void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone); void task_new_write_zonefiles(udb_base* udb, udb_ptr* last, diff --git a/usr.sbin/nsd/dnstap/dnstap_collector.c b/usr.sbin/nsd/dnstap/dnstap_collector.c index 1578bdfb00e..1a0bc85250f 100644 --- a/usr.sbin/nsd/dnstap/dnstap_collector.c +++ b/usr.sbin/nsd/dnstap/dnstap_collector.c @@ -65,10 +65,24 @@ struct dt_collector* dt_collector_create(struct nsd* nsd) int bufsz = buffer_capacity(dt_col->send_buffer); sv[0] = -1; /* For receiving by parent (dnstap-collector) */ sv[1] = -1; /* For sending by child (server childs) */ - if(socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sv) < 0) { + if(socketpair(AF_UNIX, SOCK_DGRAM +#ifdef SOCK_NONBLOCK + | SOCK_NONBLOCK +#endif + , 0, sv) < 0) { error("dnstap_collector: cannot create communication channel: %s", strerror(errno)); } +#ifndef SOCK_NONBLOCK + if (fcntl(sv[0], F_SETFL, O_NONBLOCK) == -1) { + log_msg(LOG_ERR, "dnstap_collector receive fd fcntl " + "failed: %s", strerror(errno)); + } + if (fcntl(sv[1], F_SETFL, O_NONBLOCK) == -1) { + log_msg(LOG_ERR, "dnstap_collector send fd fcntl " + "failed: %s", strerror(errno)); + } +#endif if(setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &bufsz, sizeof(bufsz))) { log_msg(LOG_ERR, "setting dnstap_collector " "receive buffer size failed: %s", strerror(errno)); @@ -422,7 +436,6 @@ void dt_collector_start(struct dt_collector* dt_col, struct nsd* nsd) #endif udb_base_free_keep_mmap(nsd->task[0]); udb_base_free_keep_mmap(nsd->task[1]); - namedb_close_udb(nsd->db); /* keeps mmap */ namedb_close(nsd->db); dt_collector_run(dt_col, nsd); diff --git a/usr.sbin/nsd/doc/ChangeLog b/usr.sbin/nsd/doc/ChangeLog index c37f0839cac..3e50194b10c 100644 --- a/usr.sbin/nsd/doc/ChangeLog +++ b/usr.sbin/nsd/doc/ChangeLog @@ -1,6 +1,73 @@ +29 November 2023: Wouter + - Tag for 4.8.0rc1. + +28 November 2023: Wouter + - Set up doc/RELNOTES for upcoming release. + - Fix unit test kill_from_pidfile function for nonexistent files + because the argument is evaluated before the test expression. + - Fix rr-test to also convert the contents of the just written output + file. + - Fix test set to remove -f nsd.db and rm nsd.db commands. + - Fix test set to remove difffile option. + +27 November 2023: Jeroen + - Fix #14: Set timeout to 3s when servicing remaining TCP connections. + - Fix: Always instate write handler after reading queries from TCP. + - Answer first query on connections accepted just before reload. + +27 November 2023: Wouter + - Merge #305: faster stats. Statistics can be gathered while a reload + is in progress. + +27 November 2023: Willem + - Merge #302: Test package fixes. Correct Auxfiles, kill_from_pidfile + function and fix drop_updates, rr-test and xfr_update tests. + +1 November 2023: Jeroen + - Remove on-disk database. + +31 October 2023: Wouter + - Merge #301: improve the logging of ixfr fallbacks to axfr. + +30 October 2023: Jeroen + - Fix processing of consolidated IXFRs. + +30 October 2023: Wouter + - Fix for interprocess communication to set quit sync command from + main process explicitly. + +3 October 2023: Wouter + - Merge #281: Proxy protocol. An implementation of PROXYv2 for NSD. + It can be configured with proxy-protocol-port: portnum with the + port number of the interface on which proxy traffic is handled. + The interface can support proxy traffic for UDP, TCP and TLS. + +21 September 2023: Wouter + - Merge #295: Update e-mail addresses, add ref to support contracts + +31 August 2023: Wouter + - Fix autoconf 2.69 warnings in configure. + +14 July 2023: Wouter + - Merge #287: Update nsd.conf.5.in. + +11 July 2023: Wouter + - Fix unused variable warning in unit test of udb. + +22 June 2023: Wouter + - Fix #284: dnstap_collector.c: SOCK_NONBLOCK is not available on + Mac/Darwin. + +7 June 2023: Wouter + - Merge #282: Improve nsd.conf man page. + - Fix unused but set variable warning. + - Fix #283: Compile failure in remote.c when --disable-bind8-stats + and --without-ssl are specified. + 31 May 2023: Wouter - Add missing items to doc/RELNOTES. - - Tag for 4.7.0rc1. + - Tag for 4.7.0rc1. It became release 4.7.0 on 7 june 2023. The code + repository continues with 4.7.1. 30 May 2023: Jeroen - Fix #240: Prefix messages originating from verifier. diff --git a/usr.sbin/nsd/doc/README b/usr.sbin/nsd/doc/README index bb737c781ad..1fd624012d8 100644 --- a/usr.sbin/nsd/doc/README +++ b/usr.sbin/nsd/doc/README @@ -21,7 +21,7 @@ 1.0 Introduction -This is NSD Name Server Daemon (NSD) version 4.7.0. +This is NSD Name Server Daemon (NSD) version 4.8.0. The NLnet Labs Name Server Daemon (NSD) is an authoritative RFC compliant DNS nameserver. It was first conceived to allow for more genetic @@ -57,7 +57,7 @@ and uses a simple configuration file 'nsd.conf'. 1.2 Quick build and install -Step 1: Unpack the source with gtar -xzvf nsd-4.7.0.tar.gz +Step 1: Unpack the source with gtar -xzvf nsd-4.8.0.tar.gz Step 2: Create user nsd or any other unprivileged user of your choice. In case of later make sure to use @@ -111,9 +111,9 @@ Step 11: If desired add 'nsd-control write' to your superuser crontab to Use your favorite combination of tar and gnu zip to unpack the source, for example -$ gtar -xzvf nsd-4.7.0.tar.gz +$ gtar -xzvf nsd-4.8.0.tar.gz -will unpack the source into the ./nsd-4.7.0 directory... +will unpack the source into the ./nsd-4.8.0 directory... 2.2 Configuring NSD @@ -194,10 +194,6 @@ addition to standard configure options, one may use the following: Pathname to the NSD pidfile, default is platform specific, mostly /var/run/nsd.pid - --with-dbfile=path - - Pathname to the NSD database, default is /etc/nsd/nsd.db - --with-zonesdir=dir NSD default location for master zone files, default /etc/nsd/ @@ -875,7 +871,7 @@ offered through a mailing lists and the 'bugzilla' web interface. If for any reason NLnet Labs would stop community support of NSD such would be announced on our web pages at least two years in advance. -The community mailing list nsd-users@nlnetlabs.nl can be used to discuss +The community mailing list nsd-users@lists.NLnetLabs.nl can be used to discuss issues with other users of NSD. Subscribe here http://lists.nlnetlabs.nl/mailman/listinfo/nsd-users @@ -885,9 +881,7 @@ community support is not sufficient and that support needs to be codified. We therefore offer paid support contracts that come in 3 varieties. More information about these support varieties can be found at - <url on support varieties on www.nlnetlabs.nl> - -Alternatively you can contact mailto:nsd-support@nlnetlabs.nl . + https://nlnetlabs.nl/services/contracts/ Support goes two ways. By acquiring one of the support contracts you also support NLnet Labs to continue to participate in the development @@ -896,11 +890,10 @@ the (IETF) standards process and by developing and maintaining reference implementations of standards and tools to support operation and deployment of new and existing Internet technology. -We are interested in our users and in the environment you use NSD. Please -drop us a mail when you use NSD. Indicate in what kind of operation you -deploy NSD and let us know what your positive and negative experiences are. -http://www.nlnetlabs.nl/nsd and mailto:nsd-info@nlnetlabs.nl - +We are interested in our users and in the environment you use NSD. Please drop +us a mail when you use NSD at users@NLnetLabs.nl. Indicate in what kind of +operation you deploy NSD and let us know what your positive and negative +experiences are. 4.1 Your Support @@ -927,4 +920,4 @@ larger and regular donations please contact us at users@NLnetLabs.nl. Also see http://www.nlnetlabs.nl/labs/contributors/. -$Id: README,v 1.6 2023/06/29 19:38:50 florian Exp $ +$Id: README,v 1.7 2023/12/20 17:29:02 florian Exp $ diff --git a/usr.sbin/nsd/doc/RELNOTES b/usr.sbin/nsd/doc/RELNOTES index 10cfea94f1e..e5e234d7e1c 100644 --- a/usr.sbin/nsd/doc/RELNOTES +++ b/usr.sbin/nsd/doc/RELNOTES @@ -1,5 +1,42 @@ NSD RELEASE NOTES +4.8.0 +================ +FEATURES: + - Merge #281: Proxy protocol. An implementation of PROXYv2 for NSD. + It can be configured with proxy-protocol-port: portnum with the + port number of the interface on which proxy traffic is handled. + The interface can support proxy traffic for UDP, TCP and TLS. + - Merge #301: improve the logging of ixfr fallbacks to axfr. + - Merge #305: faster stats. Statistics can be gathered while a reload + is in progress. +BUG FIXES: + - Merge #282: Improve nsd.conf man page. + - Fix unused but set variable warning. + - Fix #283: Compile failure in remote.c when --disable-bind8-stats + and --without-ssl are specified. + - Fix #284: dnstap_collector.c: SOCK_NONBLOCK is not available on + Mac/Darwin. + - Fix unused variable warning in unit test of udb. + - Merge #287: Update nsd.conf.5.in. + - Fix autoconf 2.69 warnings in configure. + - Merge #295: Update e-mail addresses, add ref to support contracts + - Fix for interprocess communication to set quit sync command from + main process explicitly. + - Fix processing of consolidated IXFRs. + - Remove on-disk database. + - Answer first query for connections accepted just before reload. + - Fix: Always instate write handler after reading a query over TCP. + - Fix #14: Set timeout to 3s when servicing remaining TCP connections. + - Merge #302: Test package fixes. Correct Auxfiles, kill_from_pidfile + function and fix drop_updates, rr-test and xfr_update tests. + - Fix unit test kill_from_pidfile function for nonexistent files + because the argument is evaluated before the test expression. + - Fix rr-test to also convert the contents of the just written output + file. + - Fix test set to remove -f nsd.db and rm nsd.db commands. + - Fix test set to remove difffile option. + 4.7.0 ================ FEATURES: diff --git a/usr.sbin/nsd/edns.c b/usr.sbin/nsd/edns.c index 478ec681df5..0e1caca29b7 100644 --- a/usr.sbin/nsd/edns.c +++ b/usr.sbin/nsd/edns.c @@ -270,15 +270,15 @@ void cookie_verify(query_type *q, struct nsd* nsd, uint32_t *now_p) { memcpy(hash2verify, q->edns.cookie + 16, 8); #ifdef INET6 - if(q->addr.ss_family == AF_INET6) { - memcpy(q->edns.cookie + 16, &((struct sockaddr_in6 *)&q->addr)->sin6_addr, 16); + if(q->client_addr.ss_family == AF_INET6) { + memcpy(q->edns.cookie + 16, &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16); verify_size = 32; } else { - memcpy(q->edns.cookie + 16, &((struct sockaddr_in *)&q->addr)->sin_addr, 4); + memcpy(q->edns.cookie + 16, &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4); verify_size = 20; } #else - memcpy( q->edns.cookie + 16, &q->addr.sin_addr, 4); + memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4); verify_size = 20; #endif @@ -323,17 +323,17 @@ void cookie_create(query_type *q, struct nsd* nsd, uint32_t *now_p) q->edns.cookie[14] = (now_uint32 & 0x0000FF00) >> 8; q->edns.cookie[15] = now_uint32 & 0x000000FF; #ifdef INET6 - if (q->addr.ss_family == AF_INET6) { + if (q->client_addr.ss_family == AF_INET6) { memcpy( q->edns.cookie + 16 - , &((struct sockaddr_in6 *)&q->addr)->sin6_addr, 16); + , &((struct sockaddr_in6 *)&q->client_addr)->sin6_addr, 16); siphash(q->edns.cookie, 32, nsd->cookie_secrets[0].cookie_secret, hash, 8); } else { memcpy( q->edns.cookie + 16 - , &((struct sockaddr_in *)&q->addr)->sin_addr, 4); + , &((struct sockaddr_in *)&q->client_addr)->sin_addr, 4); siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); } #else - memcpy( q->edns.cookie + 16, &q->addr.sin_addr, 4); + memcpy( q->edns.cookie + 16, &q->client_addr.sin_addr, 4); siphash(q->edns.cookie, 20, nsd->cookie_secrets[0].cookie_secret, hash, 8); #endif memcpy(q->edns.cookie + 16, hash, 8); diff --git a/usr.sbin/nsd/ipc.c b/usr.sbin/nsd/ipc.c index 8f248122e26..44fdd426571 100644 --- a/usr.sbin/nsd/ipc.c +++ b/usr.sbin/nsd/ipc.c @@ -95,20 +95,6 @@ child_handle_parent_command(int fd, short event, void* arg) } ipc_child_quit(data->nsd); break; - case NSD_QUIT_WITH_STATS: -#ifdef BIND8_STATS - DEBUG(DEBUG_IPC, 2, (LOG_INFO, "quit QUIT_WITH_STATS")); - /* reply with ack and stats and then quit */ - if(!write_socket(fd, &mode, sizeof(mode))) { - log_msg(LOG_ERR, "cannot write quitwst to parent"); - } - if(!write_socket(fd, &data->nsd->st, sizeof(data->nsd->st))) { - log_msg(LOG_ERR, "cannot write stats to parent"); - } - fsync(fd); -#endif /* BIND8_STATS */ - ipc_child_quit(data->nsd); - break; default: log_msg(LOG_ERR, "handle_parent_command: bad mode %d", (int) mode); @@ -208,11 +194,7 @@ debug_print_fwd_name(int ATTR_UNUSED(len), buffer_type* packet, int acl_num) static void send_quit_to_child(struct main_ipc_handler_data* data, int fd) { -#ifdef BIND8_STATS - sig_atomic_t cmd = NSD_QUIT_WITH_STATS; -#else sig_atomic_t cmd = NSD_QUIT; -#endif if(write(fd, &cmd, sizeof(cmd)) == -1) { if(errno == EAGAIN || errno == EINTR) return; /* try again later */ @@ -320,26 +302,6 @@ stats_subtract(struct nsdst* total, struct nsdst* s) total->nona -= s->nona; total->rixfr -= s->rixfr; } - -#define FINAL_STATS_TIMEOUT 10 /* seconds */ -static void -read_child_stats(struct nsd* nsd, struct nsd_child* child, int fd) -{ - struct nsdst s; - errno=0; - if(block_read(nsd, fd, &s, sizeof(s), FINAL_STATS_TIMEOUT)!=sizeof(s)) { - log_msg(LOG_ERR, "problems reading finalstats from server " - "%d: %s", (int)child->pid, strerror(errno)); - } else { - stats_add(&nsd->st, &s); - child->query_count = s.qudp + s.qudp6 + s.ctcp + s.ctcp6 - + s.ctls + s.ctls6; - /* we know that the child is going to close the connection - * now (this is an ACK of the QUIT_W_STATS so we know the - * child is done, no longer sending e.g. NOTIFY contents) */ - child_is_done(nsd, fd); - } -} #endif /* BIND8_STATS */ void @@ -475,11 +437,6 @@ parent_handle_child_command(netio_type *ATTR_UNUSED(netio), case NSD_QUIT: data->nsd->mode = mode; break; -#ifdef BIND8_STATS - case NSD_QUIT_WITH_STATS: - read_child_stats(data->nsd, data->child, handler->fd); - break; -#endif /* BIND8_STATS */ case NSD_STATS: data->nsd->signal_hint_stats = 1; break; diff --git a/usr.sbin/nsd/ixfr.c b/usr.sbin/nsd/ixfr.c index 5a7efc0bf00..b4f59d6365b 100644 --- a/usr.sbin/nsd/ixfr.c +++ b/usr.sbin/nsd/ixfr.c @@ -820,6 +820,8 @@ query_state_type query_ixfr(struct nsd *nsd, struct query *query) /* we have no ixfr information for the zone, make an AXFR */ if(query->tsig_prepare_it) query->tsig_sign_it = 1; + VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, no ixfr info for zone: %s", + dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } ixfr_data = zone_ixfr_find_serial(zone->ixfr, qserial); @@ -827,6 +829,8 @@ query_state_type query_ixfr(struct nsd *nsd, struct query *query) /* the specific version is not available, make an AXFR */ if(query->tsig_prepare_it) query->tsig_sign_it = 1; + VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, no history for serial for zone: %s", + dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } /* see if the IXFRs connect to the next IXFR, and if it ends @@ -835,6 +839,8 @@ query_state_type query_ixfr(struct nsd *nsd, struct query *query) end_serial != current_serial) { if(query->tsig_prepare_it) query->tsig_sign_it = 1; + VERBOSITY(2, (LOG_INFO, "ixfr fallback to axfr, incomplete history from this serial for zone: %s", + dname_to_string(query->qname, NULL))); return query_axfr(nsd, query, 0); } @@ -942,15 +948,12 @@ size_t ixfr_data_size(struct ixfr_data* data) } struct ixfr_store* ixfr_store_start(struct zone* zone, - struct ixfr_store* ixfr_store_mem, uint32_t old_serial, - uint32_t new_serial) + struct ixfr_store* ixfr_store_mem) { struct ixfr_store* ixfr_store = ixfr_store_mem; memset(ixfr_store, 0, sizeof(*ixfr_store)); ixfr_store->zone = zone; ixfr_store->data = xalloc_zero(sizeof(*ixfr_store->data)); - ixfr_store->data->oldserial = old_serial; - ixfr_store->data->newserial = new_serial; return ixfr_store; } @@ -1139,12 +1142,12 @@ static void store_soa(uint8_t* soa, struct zone* zone, uint32_t ttl, write_uint32(sp, minimum); } -void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, - struct buffer* packet, size_t ttlpos) +void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, uint32_t ttl, + struct buffer* packet, size_t rrlen) { size_t oldpos, sz = 0; - uint32_t ttl, serial, refresh, retry, expire, minimum; - uint16_t rdlen_uncompressed, rdlen_wire; + uint32_t serial, refresh, retry, expire, minimum; + uint16_t rdlen_uncompressed; int primns_len = 0, email_len = 0; uint8_t primns[MAXDOMAINLEN + 1], email[MAXDOMAINLEN + 1]; @@ -1156,24 +1159,11 @@ void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, ixfr_store->data->newsoa_len = 0; } oldpos = buffer_position(packet); - buffer_set_position(packet, ttlpos); /* calculate the length */ sz = domain_dname(ixfr_store->zone->apex)->name_size; - sz += 2 /* type */ + 2 /* class */; - /* read ttl */ - if(!buffer_available(packet, 4/*ttl*/+2/*rdlen*/)) { - /* not possible already parsed, but fail nicely anyway */ - log_msg(LOG_ERR, "ixfr_store: not enough space in packet"); - ixfr_store_cancel(ixfr_store); - buffer_set_position(packet, oldpos); - return; - } - ttl = buffer_read_u32(packet); - sz += 4; - rdlen_wire = buffer_read_u16(packet); - sz += 2; - if(!buffer_available(packet, rdlen_wire)) { + sz += 2 /* type */ + 2 /* class */ + 4 /* ttl */ + 2 /* rdlen */; + if(!buffer_available(packet, rrlen)) { /* not possible already parsed, but fail nicely anyway */ log_msg(LOG_ERR, "ixfr_store: not enough rdata space in packet"); ixfr_store_cancel(ixfr_store); @@ -1189,6 +1179,8 @@ void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, } rdlen_uncompressed = primns_len + email_len + 4 + 4 + 4 + 4 + 4; + ixfr_store->data->newserial = serial; + /* store the soa record */ ixfr_store->data->newsoa = xalloc(sz); ixfr_store->data->newsoa_len = sz; @@ -1241,6 +1233,8 @@ void ixfr_store_add_oldsoa(struct ixfr_store* ixfr_store, uint32_t ttl, } rdlen_uncompressed = primns_len + email_len + 4 + 4 + 4 + 4 + 4; + ixfr_store->data->oldserial = serial; + /* store the soa record */ ixfr_store->data->oldsoa = xalloc(sz); ixfr_store->data->oldsoa_len = sz; @@ -1385,8 +1379,13 @@ int ixfr_store_add_newsoa_rdatas(struct ixfr_store* ixfr_store, uint32_t ttl, rdata_atom_type* rdatas, ssize_t rdata_num) { size_t capacity = 0; + uint32_t serial; if(ixfr_store->cancelled) return 1; + if(rdata_num < 2 || rdata_atom_size(rdatas[2]) < 4) + return 0; + memcpy(&serial, rdata_atom_data(rdatas[2]), sizeof(serial)); + ixfr_store->data->newserial = ntohl(serial); if(!ixfr_putrr(dname, type, klass, ttl, rdatas, rdata_num, &ixfr_store->data->newsoa, &ixfr_store->data->newsoa_len, &ixfr_store->add_capacity)) @@ -1443,6 +1442,23 @@ int ixfr_store_delrr_uncompressed(struct ixfr_store* ixfr_store, &ixfr_store->data->del_len, &ixfr_store->del_capacity); } +static size_t skip_dname(uint8_t* rdata, size_t rdata_len) +{ + for (size_t index=0; index < rdata_len; ) { + uint8_t label_size = rdata[index]; + if (label_size == 0) { + return index + 1; + } else if ((label_size & 0xc0) != 0) { + return (index + 1 < rdata_len) ? index + 2 : 0; + } else { + /* loop breaks if index exceeds rdata_len */ + index += label_size + 1; + } + } + + return 0; +} + int ixfr_store_oldsoa_uncompressed(struct ixfr_store* ixfr_store, uint8_t* dname, size_t dname_len, uint16_t type, uint16_t klass, uint32_t ttl, uint8_t* rdata, size_t rdata_len) @@ -1454,6 +1470,20 @@ int ixfr_store_oldsoa_uncompressed(struct ixfr_store* ixfr_store, ttl, rdata, rdata_len, &ixfr_store->data->oldsoa, &ixfr_store->data->oldsoa_len, &capacity)) return 0; + { + uint32_t serial; + size_t index, count = 0; + if (!(count = skip_dname(rdata, rdata_len))) + return 0; + index = count; + if (!(count = skip_dname(rdata+index, rdata_len-index))) + return 0; + index += count; + if (rdata_len - index < 4) + return 0; + memcpy(&serial, rdata+index, sizeof(serial)); + ixfr_store->data->oldserial = ntohl(serial); + } ixfr_trim_capacity(&ixfr_store->data->oldsoa, &ixfr_store->data->oldsoa_len, &capacity); return 1; diff --git a/usr.sbin/nsd/ixfr.h b/usr.sbin/nsd/ixfr.h index 0920dc132f1..eae524dc0df 100644 --- a/usr.sbin/nsd/ixfr.h +++ b/usr.sbin/nsd/ixfr.h @@ -133,8 +133,7 @@ struct ixfr_store { * IXFR with this serial number. The NULL is on error. */ struct ixfr_store* ixfr_store_start(struct zone* zone, - struct ixfr_store* ixfr_store_mem, uint32_t old_serial, - uint32_t new_serial); + struct ixfr_store* ixfr_store_mem); /* * Cancel the ixfr store in progress. The pointer remains valid, no store done. @@ -163,14 +162,13 @@ void ixfr_store_finish_data(struct ixfr_store* ixfr_store); /* * Add the new SOA record to the ixfr store. * ixfr_store: stores ixfr data that is collected. + * ttl: the TTL of the SOA record * packet: DNS packet that contains the SOA. position restored on function * exit. - * ttlpos: position, just before the ttl, rdatalen, rdata of the SOA record. - * we do not need to pass the name, because that is the zone name, or - * the type or class of the record, because we already know. + * rrlen: wire rdata length of the SOA. */ -void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, - struct buffer* packet, size_t ttlpos); +void ixfr_store_add_newsoa(struct ixfr_store* ixfr_store, uint32_t ttl, + struct buffer* packet, size_t rrlen); /* * Add the old SOA record to the ixfr store. diff --git a/usr.sbin/nsd/ixfrcreate.c b/usr.sbin/nsd/ixfrcreate.c index 33855ebbc37..5f6c463448c 100644 --- a/usr.sbin/nsd/ixfrcreate.c +++ b/usr.sbin/nsd/ixfrcreate.c @@ -945,8 +945,7 @@ static int ixfr_perform_init(struct ixfr_create* ixfrcr, struct zone* zone, return 0; } ixfrcr->new_serial = zone_get_current_serial(zone); - *store = ixfr_store_start(zone, store_mem, ixfrcr->old_serial, - ixfrcr->new_serial); + *store = ixfr_store_start(zone, store_mem); if(!ixfr_create_store_newsoa(*store, zone)) { fclose(*spool); ixfr_store_free(*store); diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index 3143e867d99..65cb1aed268 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -329,7 +329,6 @@ struct namedb region_type* region; domain_table_type* domains; struct radtree* zonetree; - struct udb_base* udb; /* the timestamp on the ixfr.db file */ struct timeval diff_timestamp; /* if diff_skip=1, diff_pos contains the nsd.diff place to continue */ @@ -369,12 +368,7 @@ zone_type *namedb_find_zone(namedb_type *db, const dname_type *dname); */ void domain_table_deldomain(namedb_type* db, domain_type* domain); - /** dbcreate.c */ -int udb_write_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr); -void udb_del_rr(struct udb_base* udb, struct udb_ptr* z, rr_type* rr); -int write_zone_to_udb(struct udb_base* udb, zone_type* zone, - struct timespec* mtime, const char* file_str); int print_rrs(FILE* out, struct zone* zone); /** marshal rdata into buffer, must be MAX_RDLENGTH in size */ size_t rr_marshal_rdata(rr_type* rr, uint8_t* rdata, size_t sz); @@ -384,8 +378,7 @@ int namedb_lookup (struct namedb* db, domain_type **closest_match, domain_type **closest_encloser); /* pass number of children (to alloc in dirty array */ -struct namedb *namedb_open(const char *filename, struct nsd_options* opt); -void namedb_close_udb(struct namedb* db); +struct namedb *namedb_open(struct nsd_options* opt); void namedb_close(struct namedb* db); /* free ixfr data stored for zones */ void namedb_free_ixfr(struct namedb* db); diff --git a/usr.sbin/nsd/nsd-checkconf.8.in b/usr.sbin/nsd/nsd-checkconf.8.in index ac23b1bb755..5e399bb7168 100644 --- a/usr.sbin/nsd/nsd-checkconf.8.in +++ b/usr.sbin/nsd/nsd-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-checkconf" "8" "Jun 7, 2023" "NLnet Labs" "nsd 4.7.0" +.TH "nsd\-checkconf" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c index 970f4014ee3..15c96cbf095 100644 --- a/usr.sbin/nsd/nsd-checkconf.c +++ b/usr.sbin/nsd/nsd-checkconf.c @@ -420,7 +420,6 @@ config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, SERV_GET_BIN(tcp_reject_overflow, o); SERV_GET_BIN(log_only_syslog, o); /* str */ - SERV_GET_PATH(final, database, o); SERV_GET_STR(identity, o); SERV_GET_STR(version, o); SERV_GET_STR(nsid, o); @@ -503,6 +502,12 @@ config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, quote(p->pname); return; } + if(strcasecmp(o, "proxy_protocol_port") == 0) { + struct proxy_protocol_port_list* p; + for(p = opt->proxy_protocol_port; p; p = p->next) + printf("%d\n", p->port); + return; + } printf("Server option not handled: %s\n", o); exit(1); } @@ -606,7 +611,6 @@ config_test_print_server(nsd_options_type* opt) printf("\tdrop-updates: %s\n", opt->drop_updates?"yes":"no"); printf("\ttcp-reject-overflow: %s\n", opt->tcp_reject_overflow ? "yes" : "no"); - print_string_var("database:", opt->database); print_string_var("identity:", opt->identity); print_string_var("version:", opt->version); print_string_var("nsid:", opt->nsid); @@ -700,6 +704,11 @@ config_test_print_server(nsd_options_type* opt) print_string_var("cookie-secret:", opt->cookie_secret); if (opt->cookie_secret_file) print_string_var("cookie-secret-file:", opt->cookie_secret_file); + if(opt->proxy_protocol_port) { + struct proxy_protocol_port_list* p; + for(p = opt->proxy_protocol_port; p; p = p->next) + printf("\tproxy-protocol-port: %d\n", p->port); + } #ifdef USE_DNSTAP printf("\ndnstap:\n"); @@ -853,11 +862,6 @@ additional_checks(nsd_options_type* opt, const char* filename) filename, opt->pidfile, opt->chroot); errors ++; } - if (!file_inside_chroot(opt->database, opt->chroot)) { - fprintf(stderr, "%s: database %s is not relative to chroot %s.\n", - filename, opt->database, opt->chroot); - errors ++; - } if (!file_inside_chroot(opt->xfrdfile, opt->chroot)) { fprintf(stderr, "%s: xfrdfile %s is not relative to chroot %s.\n", filename, opt->xfrdfile, opt->chroot); diff --git a/usr.sbin/nsd/nsd-checkzone.8.in b/usr.sbin/nsd/nsd-checkzone.8.in index 6c7b62e3a0b..555ea58e26a 100644 --- a/usr.sbin/nsd/nsd-checkzone.8.in +++ b/usr.sbin/nsd/nsd-checkzone.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-checkzone" "8" "Jun 7, 2023" "NLnet Labs" "nsd 4.7.0" +.TH "nsd\-checkzone" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" .\" Copyright (c) 2014, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-checkzone.c b/usr.sbin/nsd/nsd-checkzone.c index b7ec3fcad62..0fcf4f34202 100644 --- a/usr.sbin/nsd/nsd-checkzone.c +++ b/usr.sbin/nsd/nsd-checkzone.c @@ -54,7 +54,7 @@ check_zone(struct nsd* nsd, const char* name, const char* fname, FILE *out, struct ixfr_create* ixfrcr = NULL; /* init*/ - nsd->db = namedb_open("", nsd->options); + nsd->db = namedb_open(nsd->options); dname = dname_parse(nsd->options->region, name); if(!dname) { /* parse failure */ diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index 76734e1b336..ea3a26ea934 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Jun 7, 2023" "NLnet Labs" "nsd 4.7.0" +.TH "nsd\-control" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-mem.c b/usr.sbin/nsd/nsd-mem.c index 0cc72bdc2ba..9f7b6992aab 100644 --- a/usr.sbin/nsd/nsd-mem.c +++ b/usr.sbin/nsd/nsd-mem.c @@ -21,8 +21,7 @@ #include "tsig.h" #include "options.h" #include "namedb.h" -#include "udb.h" -#include "udbzone.h" +#include "difffile.h" #include "util.h" struct nsd nsd; @@ -45,10 +44,6 @@ struct zone_mem { size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; - /* udb data allocated */ - size_t udb_data; - /* udb overhead (chunk2**x - data) */ - size_t udb_overhead; /* count of number of domains */ size_t domaincount; @@ -60,10 +55,6 @@ struct tot_mem { size_t data; /* unused space (in db.region) due to alignment */ size_t data_unused; - /* udb data allocated */ - size_t udb_data; - /* udb overhead (chunk2**x - data) */ - size_t udb_overhead; /* count of number of domains */ size_t domaincount; @@ -81,8 +72,6 @@ struct tot_mem { /* total ram usage */ size_t ram; - /* total nsd.db disk usage */ - size_t disk; }; static void @@ -90,11 +79,6 @@ account_zone(struct namedb* db, struct zone_mem* zmem) { zmem->data = region_get_mem(db->region); zmem->data_unused = region_get_mem_unused(db->region); - if(db->udb) { - zmem->udb_data = (size_t)db->udb->alloc->disk->stat_data; - zmem->udb_overhead = (size_t)(db->udb->alloc->disk->stat_alloc - - db->udb->alloc->disk->stat_data); - } zmem->domaincount = domain_table_count(db->domains); } @@ -119,8 +103,6 @@ print_zone_mem(struct zone_mem* z) { pretty_mem(z->data, "zone data"); pretty_mem(z->data_unused, "zone unused space (due to alignment)"); - pretty_mem(z->udb_data, "data in nsd.db"); - pretty_mem(z->udb_overhead, "overhead in nsd.db"); } static void @@ -143,7 +125,6 @@ account_total(struct nsd_options* opt, struct tot_mem* t) #ifdef RATELIMIT t->ram += t->rrl; #endif - t->disk = t->udb_data + t->udb_overhead; } static void @@ -158,12 +139,9 @@ print_tot_mem(struct tot_mem* t) #ifdef RATELIMIT pretty_mem(t->rrl, "RRL table (depends on servercount)"); #endif - pretty_mem(t->udb_data, "data in nsd.db"); - pretty_mem(t->udb_overhead, "overhead in nsd.db"); printf("\nsummary\n"); pretty_mem(t->ram, "ram usage (excl space for buffers)"); - pretty_mem(t->disk, "disk usage (excl 12% space claimed for growth)"); } static void @@ -171,13 +149,11 @@ add_mem(struct tot_mem* t, struct zone_mem* z) { t->data += z->data; t->data_unused += z->data_unused; - t->udb_data += z->udb_data; - t->udb_overhead += z->udb_overhead; t->domaincount += z->domaincount; } static void -check_zone_mem(const char* tf, const char* df, struct zone_options* zo, +check_zone_mem(const char* tf, struct zone_options* zo, struct nsd_options* opt, struct tot_mem* totmem) { struct nsd nsd; @@ -193,10 +169,10 @@ check_zone_mem(const char* tf, const char* df, struct zone_options* zo, /* init*/ memset(&zmem, 0, sizeof(zmem)); memset(&nsd, 0, sizeof(nsd)); - nsd.db = db = namedb_open(df, opt); - if(!db) error("cannot open %s: %s", df, strerror(errno)); + nsd.db = db = namedb_open(opt); + if(!db) error("cannot open namedb"); zone = namedb_zone_create(db, dname, zo); - taskudb = udb_base_create_new(tf, &namedb_walkfunc, NULL); + taskudb = task_file_create(tf); udb_ptr_init(&last_task, taskudb); /* read the zone */ @@ -211,7 +187,6 @@ check_zone_mem(const char* tf, const char* df, struct zone_options* zo, /* delete the zone from memory */ namedb_close(db); udb_base_free(taskudb); - unlink(df); unlink(tf); /* add up totals */ @@ -224,30 +199,18 @@ check_mem(struct nsd_options* opt) struct tot_mem totmem; struct zone_options* zo; char tf[512]; - char df[512]; memset(&totmem, 0, sizeof(totmem)); snprintf(tf, sizeof(tf), "./nsd-mem-task-%u.db", (unsigned)getpid()); - if(opt->database == NULL || opt->database[0] == 0) - df[0] = 0; - else snprintf(df, sizeof(df), "./nsd-mem-db-%u.db", (unsigned)getpid()); /* read all zones and account memory */ RBTREE_FOR(zo, struct zone_options*, opt->zone_options) { - check_zone_mem(tf, df, zo, opt, &totmem); + check_zone_mem(tf, zo, opt, &totmem); } /* calculate more total statistics */ account_total(opt, &totmem); /* print statistics */ print_tot_mem(&totmem); - - /* final advice */ - if(opt->database != NULL && opt->database[0] != 0) { - printf("\nFinal advice estimate:\n"); - printf("(The partial mmap causes reload&AXFR to take longer(disk access))\n"); - pretty_mem(totmem.ram + totmem.disk, "data and big mmap"); - pretty_mem(totmem.ram + totmem.disk/6, "data and partial mmap"); - } } /* dummy functions to link */ diff --git a/usr.sbin/nsd/nsd.8.in b/usr.sbin/nsd/nsd.8.in index 38b36e64800..1ff566a92a2 100644 --- a/usr.sbin/nsd/nsd.8.in +++ b/usr.sbin/nsd/nsd.8.in @@ -1,9 +1,9 @@ -.TH "NSD" "8" "Jun 7, 2023" "NLnet Labs" "NSD 4.7.0" +.TH "NSD" "8" "Dec 6, 2023" "NLnet Labs" "NSD 4.8.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd -\- Name Server Daemon (NSD) version 4.7.0. +\- Name Server Daemon (NSD) version 4.8.0. .SH "SYNOPSIS" .B nsd .RB [ \-4 ] @@ -111,16 +111,6 @@ For format description see nsd.conf(5). .B \-d Do not fork, stay in the foreground. .TP -.B \-f\fI database -Use the specified -.I database -instead of the default of -.IR '@dbfile@' . -If a -.B zonesdir: -is specified in the config file this path can be relative to that -directory. -.TP .B \-h Print help information and exit. .TP @@ -224,11 +214,6 @@ SIGUSR1 Dump BIND8\-style statistics into the log. Ignored otherwise. .SH "FILES" .TP -"@dbfile@" -default -.B NSD -database -.TP @pidfile@ the process id of the name server. .TP diff --git a/usr.sbin/nsd/nsd.c b/usr.sbin/nsd/nsd.c index 81dfe2e85a6..80b4cb096e5 100644 --- a/usr.sbin/nsd/nsd.c +++ b/usr.sbin/nsd/nsd.c @@ -53,9 +53,11 @@ #include "tsig.h" #include "remote.h" #include "xfrd-disk.h" +#include "ipc.h" #ifdef USE_DNSTAP #include "dnstap/dnstap_collector.h" #endif +#include "util/proxy_protocol.h" /* The server handler... */ struct nsd nsd; @@ -83,7 +85,6 @@ usage (void) #ifndef NDEBUG " -F facilities Specify the debug facilities.\n" #endif /* NDEBUG */ - " -f database Specify the database to load.\n" " -h Print this help information.\n" , CONFIGFILE); fprintf(stderr, @@ -832,16 +833,20 @@ bind8_stats (struct nsd *nsd) char buf[MAXSYSLOGMSGLEN]; char *msg, *t; int i, len; + struct nsdst st; /* Current time... */ time_t now; - if(!nsd->st.period) + if(!nsd->st_period) return; time(&now); + memcpy(&st, nsd->st, sizeof(st)); + stats_subtract(&st, &nsd->stat_proc); + /* NSTATS */ t = msg = buf + snprintf(buf, MAXSYSLOGMSGLEN, "NSTATS %lld %lu", - (long long) now, (unsigned long) nsd->st.boot); + (long long) now, (unsigned long) st.boot); for (i = 0; i <= 255; i++) { /* How much space left? */ if ((len = buf + MAXSYSLOGMSGLEN - t) < 32) { @@ -850,8 +855,8 @@ bind8_stats (struct nsd *nsd) len = buf + MAXSYSLOGMSGLEN - t; } - if (nsd->st.qtype[i] != 0) { - t += snprintf(t, len, " %s=%lu", rrtype_to_string(i), nsd->st.qtype[i]); + if (st.qtype[i] != 0) { + t += snprintf(t, len, " %s=%lu", rrtype_to_string(i), st.qtype[i]); } } if (t > msg) @@ -860,27 +865,27 @@ bind8_stats (struct nsd *nsd) /* XSTATS */ /* Only print it if we're in the main daemon or have anything to report... */ if (nsd->server_kind == NSD_SERVER_MAIN - || nsd->st.dropped || nsd->st.raxfr || nsd->st.rixfr || (nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped) - || nsd->st.txerr || nsd->st.opcode[OPCODE_QUERY] || nsd->st.opcode[OPCODE_IQUERY] - || nsd->st.wrongzone || nsd->st.ctcp + nsd->st.ctcp6 || nsd->st.rcode[RCODE_SERVFAIL] - || nsd->st.rcode[RCODE_FORMAT] || nsd->st.nona || nsd->st.rcode[RCODE_NXDOMAIN] - || nsd->st.opcode[OPCODE_UPDATE]) { + || st.dropped || st.raxfr || st.rixfr || (st.qudp + st.qudp6 - st.dropped) + || st.txerr || st.opcode[OPCODE_QUERY] || st.opcode[OPCODE_IQUERY] + || st.wrongzone || st.ctcp + st.ctcp6 || st.rcode[RCODE_SERVFAIL] + || st.rcode[RCODE_FORMAT] || st.nona || st.rcode[RCODE_NXDOMAIN] + || st.opcode[OPCODE_UPDATE]) { log_msg(LOG_INFO, "XSTATS %lld %lu" " RR=%lu RNXD=%lu RFwdR=%lu RDupR=%lu RFail=%lu RFErr=%lu RErr=%lu RAXFR=%lu RIXFR=%lu" " RLame=%lu ROpts=%lu SSysQ=%lu SAns=%lu SFwdQ=%lu SDupQ=%lu SErr=%lu RQ=%lu" " RIQ=%lu RFwdQ=%lu RDupQ=%lu RTCP=%lu SFwdR=%lu SFail=%lu SFErr=%lu SNaAns=%lu" " SNXD=%lu RUQ=%lu RURQ=%lu RUXFR=%lu RUUpd=%lu", - (long long) now, (unsigned long) nsd->st.boot, - nsd->st.dropped, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, - (unsigned long)0, (unsigned long)0, nsd->st.raxfr, nsd->st.rixfr, (unsigned long)0, (unsigned long)0, - (unsigned long)0, nsd->st.qudp + nsd->st.qudp6 - nsd->st.dropped, (unsigned long)0, - (unsigned long)0, nsd->st.txerr, - nsd->st.opcode[OPCODE_QUERY], nsd->st.opcode[OPCODE_IQUERY], nsd->st.wrongzone, - (unsigned long)0, nsd->st.ctcp + nsd->st.ctcp6, - (unsigned long)0, nsd->st.rcode[RCODE_SERVFAIL], nsd->st.rcode[RCODE_FORMAT], - nsd->st.nona, nsd->st.rcode[RCODE_NXDOMAIN], - (unsigned long)0, (unsigned long)0, (unsigned long)0, nsd->st.opcode[OPCODE_UPDATE]); + (long long) now, (unsigned long) st.boot, + st.dropped, (unsigned long)0, (unsigned long)0, (unsigned long)0, (unsigned long)0, + (unsigned long)0, (unsigned long)0, st.raxfr, st.rixfr, (unsigned long)0, (unsigned long)0, + (unsigned long)0, st.qudp + st.qudp6 - st.dropped, (unsigned long)0, + (unsigned long)0, st.txerr, + st.opcode[OPCODE_QUERY], st.opcode[OPCODE_IQUERY], st.wrongzone, + (unsigned long)0, st.ctcp + st.ctcp6, + (unsigned long)0, st.rcode[RCODE_SERVFAIL], st.rcode[RCODE_FORMAT], + st.nona, st.rcode[RCODE_NXDOMAIN], + (unsigned long)0, (unsigned long)0, (unsigned long)0, st.opcode[OPCODE_UPDATE]); } } @@ -950,7 +955,6 @@ main(int argc, char *argv[]) /* Initialize the server handler... */ memset(&nsd, 0, sizeof(struct nsd)); nsd.region = region_create(xalloc, free); - nsd.dbfile = 0; nsd.pidfile = 0; nsd.server_kind = NSD_SERVER_MAIN; memset(&hints, 0, sizeof(hints)); @@ -1018,7 +1022,6 @@ main(int argc, char *argv[]) nsd.debug = 1; break; case 'f': - nsd.dbfile = optarg; break; case 'h': usage(); @@ -1077,7 +1080,7 @@ main(int argc, char *argv[]) break; case 's': #ifdef BIND8_STATS - nsd.st.period = atoi(optarg); + nsd.st_period = atoi(optarg); #else /* !BIND8_STATS */ error("BIND 8 statistics not enabled."); #endif /* BIND8_STATS */ @@ -1128,6 +1131,7 @@ main(int argc, char *argv[]) } if(!tsig_init(nsd.region)) error("init tsig failed"); + pp_init(&write_uint16, &write_uint32); /* Read options */ if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { @@ -1152,13 +1156,6 @@ main(int argc, char *argv[]) verbosity = nsd_debug_level; #endif /* NDEBUG */ if(nsd.options->debug_mode) nsd.debug=1; - if(!nsd.dbfile) - { - if(nsd.options->database) - nsd.dbfile = nsd.options->database; - else - nsd.dbfile = DBFILE; - } if(!nsd.pidfile) { if(nsd.options->pidfile) @@ -1215,8 +1212,8 @@ main(int argc, char *argv[]) verify_port = VERIFY_PORT; } #ifdef BIND8_STATS - if(nsd.st.period == 0) { - nsd.st.period = nsd.options->statistics; + if(nsd.st_period == 0) { + nsd.st_period = nsd.options->statistics; } #endif /* BIND8_STATS */ #ifdef HAVE_CHROOT @@ -1463,9 +1460,6 @@ main(int argc, char *argv[]) } else if (!file_inside_chroot(nsd.pidfile, nsd.chrootdir)) { error("pidfile %s is not relative to %s: chroot not possible", nsd.pidfile, nsd.chrootdir); - } else if (!file_inside_chroot(nsd.dbfile, nsd.chrootdir)) { - error("database %s is not relative to %s: chroot not possible", - nsd.dbfile, nsd.chrootdir); } else if (!file_inside_chroot(nsd.options->xfrdfile, nsd.chrootdir)) { error("xfrdfile %s is not relative to %s: chroot not possible", nsd.options->xfrdfile, nsd.chrootdir); @@ -1643,8 +1637,6 @@ main(int argc, char *argv[]) } if (nsd.pidfile && nsd.pidfile[0] == '/') nsd.pidfile += l; - if (nsd.dbfile[0] == '/') - nsd.dbfile += l; if (nsd.options->xfrdfile[0] == '/') nsd.options->xfrdfile += l; if (nsd.options->zonelistfile[0] == '/') @@ -1734,6 +1726,9 @@ main(int argc, char *argv[]) options_zonestatnames_create(nsd.options); server_zonestat_alloc(&nsd); #endif /* USE_ZONE_STATS */ +#ifdef BIND8_STATS + server_stat_alloc(&nsd); +#endif /* BIND8_STATS */ if(nsd.server_kind == NSD_SERVER_MAIN) { server_prepare_xfrd(&nsd); /* xfrd forks this before reading database, so it does not get diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in index 6780ea7e849..d9ab36d2250 100644 --- a/usr.sbin/nsd/nsd.conf.5.in +++ b/usr.sbin/nsd/nsd.conf.5.in @@ -1,4 +1,4 @@ -.TH "nsd.conf" "5" "Jun 7, 2023" "NLnet Labs" "nsd 4.7.0" +.TH "nsd.conf" "5" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -99,7 +99,7 @@ There must be whitespace between keywords. Attribute keywords end with a colon ':'. An attribute is followed by its containing attributes, or a value. .P -At the top level only +At the top level, only .BR server: , .BR verify: , .BR key: , @@ -129,7 +129,7 @@ Files can be included using the .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. If a chroot is used +were copied into the config file at that point. If a chroot is used, an absolute filename is needed (with the chroot prepended), so that the include can be parsed before and after application of the chroot (and the knowledge of what that chroot is). You can use '*' to include a @@ -207,15 +207,6 @@ If yes, NSD listens to IPv4 connections. Default yes. .B do\-ip6:\fR <yes or no> If yes, NSD listens to IPv6 connections. Default yes. .TP -.B database:\fR <filename> -By default -.I '@dbfile@' -is used. The specified file is used to store the compiled -zone information. Same as commandline option -.BR \-f. -If set to "" then no database is used. This uses less memory but -zone updates are not (immediately) spooled to disk. -.TP .B zonelistfile:\fR <filename> By default .I @zonelistfile@ @@ -570,6 +561,12 @@ interfaces configured with that port number as @number get DNS over TLS service. If null or "", the default verify locations are used. Set it to the certificate bundle file, for example "/etc/pki/tls/certs/ca-bundle.crt". These certificates are used for authenticating Transfer over TLS (XoT) connections. +.TP +.B proxy\-protocol\-port:\fR <number> +The port number for proxy protocol service. If the statement is given multiple +times, additional port numbers can be used for proxy protocol service. The +interface definitions that use this port number expect PROXYv2 proxy protocol +traffic, for UDP, TCP and for TLS service. .SS "Remote Control" The .B remote\-control: @@ -652,7 +649,7 @@ Verify zones by default. .TP .B verifier:\fR <command> When an update is received for the zone (by IXFR or AXFR) this program will be -run to assess the zone with the update. When the program exists with a status +run to assess the zone with the update. If the program exits with a status code of 0, the zone is considered good and will be served. Any other status code will designate the zone bad and the received update will be discarded. The zone will continue to be served but without the update. @@ -874,13 +871,11 @@ when sending notifies. .TP .B provide\-xfr:\fR <ip\-spec> <key\-name | NOKEY | BLOCKED> Access control list. The listed address (a secondary) is allowed to -request AXFR from this server. Zone data will be provided to the -address. The specified key is used during AXFR. For unlisted or -BLOCKED addresses no data is provided, requests are discarded. -BLOCKED supersedes other entries, other entries are scanned for a match +request XFR from this server. Zone data will be provided to the +address. The specified key is used during XFR. For unlisted or +BLOCKED addresses no data is provided and requests are discarded. +BLOCKED supersedes other entries and other entries are scanned for a match in the order of the statements. -NSD provides AXFR for its secondaries, but IXFR is not implemented (IXFR -is implemented for request\-xfr, but not for provide\-xfr). .P .RS The ip\-spec is either a plain IP address (IPv4 or IPv6), or can be @@ -903,8 +898,8 @@ A port number can be added using a suffix of @number, for example .TP .B store\-ixfr:\fR <yes or no> If enabled, IXFR contents are stored and provided to the set of clients -specified in the provide\-xfr statement. Default is no. IXFR contents is -a smaller set of changes that differ between zone versions, where an AXFR +specified in the provide\-xfr statement. Default is no. IXFR content is +a smaller set of changes that differ between zone versions, whereas an AXFR contains the full contents of the zone. .TP .B ixfr\-number:\fR <number> @@ -912,21 +907,20 @@ The number of IXFR versions to store for this zone, at most. Default is 5. .TP .B ixfr\-size:\fR <number> The max storage to use for IXFR versions for this zone, in bytes. -Default is 1048576. A value of 0 means unlimited, if you want to turn off -IXFR storage, use the store\-ixfr option. +Default is 1048576. A value of 0 means unlimited. If you want to turn off +IXFR storage, set the store\-ixfr option to no. NSD does not elide IXFR contents from versions that add and remove the same -data, that merges version changes together to shorten the data, but leaves -the data and change sequence as it was transmitted by another server. +data. It stores and transmits IXFRs as they were transmitted by the upstream server. .TP .B create\-ixfr:\fR <yes or no> If enabled, IXFR data is created when a zonefile is read by the server. -Also set store\-ixfr enabled, so that the contents are stored, when you use -this. Default is off. If the server is not running, the nsd\-checkzone \-i +This requires store\-ixfr to be set to yes, so that the IXFR contents are saved to disk. +Default is off. If the server is not running, the nsd\-checkzone \-i option can be used to create an IXFR file. When an IXFR is created, the server spools a version of the zone to a temporary file, at the location where the ixfr files are stored. This creates IXFR data when the zone is read from file, but not when a zone is read by AXFR transfer from a server, because then -the topmost server that originates the data is the one place where ixfr +the topmost server that originates the data is the one place where IXFR differences are computed and those differences are then transmitted verbatim to all the other servers. .TP diff --git a/usr.sbin/nsd/nsd.conf.sample.in b/usr.sbin/nsd/nsd.conf.sample.in index 67fdf4cb1d1..1ffeacd7b03 100644 --- a/usr.sbin/nsd/nsd.conf.sample.in +++ b/usr.sbin/nsd/nsd.conf.sample.in @@ -100,7 +100,7 @@ server: # username: @user@ # Run NSD in a chroot-jail. - # make sure to have pidfile and database reachable from there. + # make sure to have pidfile reachable from there. # by default, no chroot-jail is used. # chroot: "@configdir@" @@ -110,10 +110,6 @@ server: # the list of dynamically added zones. # zonelistfile: "@zonelistfile@" - # the database to use - # if set to "" then no disk-database is used, less memory usage. - # database: "@dbfile@" - # log messages to file. Default to stderr and syslog (with # facility LOG_DAEMON). stderr disappears when daemon goes to bg. # logfile: "@logfile@" @@ -217,7 +213,7 @@ server: # zonefiles-check: yes # write changed zonefiles to disk, every N seconds. - # default is 0(disabled) or 3600(if database is ""). + # default is 3600. # zonefiles-write: 3600 # RRLconfig @@ -264,6 +260,10 @@ server: # Transfers over TLS (XoT). Default is "" (default verify locations). # tls-cert-bundle: "path/to/ca-bundle.pem" + # The interfaces that use these listed port numbers will support and + # expect PROXYv2. For UDP and TCP/TLS interfaces. + # proxy-protocol-port: portno for each of the port numbers. + verify: # Enable zone verification. Default is no. # enable: no diff --git a/usr.sbin/nsd/nsd.h b/usr.sbin/nsd/nsd.h index 8fea49d6ddc..4bd8dcdc967 100644 --- a/usr.sbin/nsd/nsd.h +++ b/usr.sbin/nsd/nsd.h @@ -64,12 +64,6 @@ struct dt_collector; */ #define NSD_QUIT_SYNC 9 /* - * QUIT_WITH_STATS is sent during a reload when BIND8_STATS is defined, - * from parent to children. The stats are transferred too from child to - * parent with this commandvalue, when the child is exiting. - */ -#define NSD_QUIT_WITH_STATS 10 -/* * QUIT_CHILD is sent at exit, to make sure the child has exited so that * port53 is free when all of nsd's processes have exited at shutdown time */ @@ -99,11 +93,11 @@ typedef unsigned long stc_type; #define LASTELEM(arr) (sizeof(arr) / sizeof(arr[0]) - 1) -#define STATUP(nsd, stc) nsd->st.stc++ -/* #define STATUP2(nsd, stc, i) ((i) <= (LASTELEM(nsd->st.stc) - 1)) ? nsd->st.stc[(i)]++ : \ - nsd->st.stc[LASTELEM(nsd->st.stc)]++ */ +#define STATUP(nsd, stc) nsd->st->stc++ +/* #define STATUP2(nsd, stc, i) ((i) <= (LASTELEM(nsd->st->stc) - 1)) ? nsd->st->stc[(i)]++ : \ + nsd->st.stc[LASTELEM(nsd->st->stc)]++ */ -#define STATUP2(nsd, stc, i) nsd->st.stc[(i) <= (LASTELEM(nsd->st.stc) - 1) ? i : LASTELEM(nsd->st.stc)]++ +#define STATUP2(nsd, stc, i) nsd->st->stc[(i) <= (LASTELEM(nsd->st->stc) - 1) ? i : LASTELEM(nsd->st->stc)]++ #else /* BIND8_STATS */ #define STATUP(nsd, stc) /* Nothing */ @@ -126,6 +120,23 @@ typedef unsigned long stc_type; #define ZTATUP2(nsd, zone, stc, i) /* Nothing */ #endif /* USE_ZONE_STATS */ +#ifdef BIND8_STATS +/* Data structure to keep track of statistics */ +struct nsdst { + time_t boot; + stc_type qtype[257]; /* Counters per qtype */ + stc_type qclass[4]; /* Class IN or Class CH or other */ + stc_type qudp, qudp6; /* Number of queries udp and udp6 */ + stc_type ctcp, ctcp6; /* Number of tcp and tcp6 connections */ + stc_type ctls, ctls6; /* Number of tls and tls6 connections */ + stc_type rcode[17], opcode[6]; /* Rcodes & opcodes */ + /* Dropped, truncated, queries for nonconfigured zone, tx errors */ + stc_type dropped, truncated, wrongzone, txerr, rxerr; + stc_type edns, ednserr, raxfr, nona, rixfr; + uint64_t db_disk, db_mem; +}; +#endif /* BIND8_STATS */ + #define NSD_SOCKET_IS_OPTIONAL (1<<0) #define NSD_BIND_DEVICE (1<<1) @@ -244,7 +255,6 @@ struct nsd struct daemon_remote* rc; /* Configuration */ - const char *dbfile; const char *pidfile; const char *log_filename; const char *username; @@ -300,21 +310,10 @@ struct nsd size_t ipv6_edns_size; #ifdef BIND8_STATS - - struct nsdst { - time_t boot; - int period; /* Produce statistics dump every st_period seconds */ - stc_type qtype[257]; /* Counters per qtype */ - stc_type qclass[4]; /* Class IN or Class CH or other */ - stc_type qudp, qudp6; /* Number of queries udp and udp6 */ - stc_type ctcp, ctcp6; /* Number of tcp and tcp6 connections */ - stc_type ctls, ctls6; /* Number of tls and tls6 connections */ - stc_type rcode[17], opcode[6]; /* Rcodes & opcodes */ - /* Dropped, truncated, queries for nonconfigured zone, tx errors */ - stc_type dropped, truncated, wrongzone, txerr, rxerr; - stc_type edns, ednserr, raxfr, nona, rixfr; - uint64_t db_disk, db_mem; - } st; + /* statistics for this server */ + struct nsdst* st; + /* Produce statistics dump every st_period seconds */ + int st_period; /* per zone stats, each an array per zone-stat-idx, stats per zone is * add of [0][zoneidx] and [1][zoneidx]. */ struct nsdst* zonestat[2]; @@ -327,6 +326,20 @@ struct nsd size_t zonestatsize[2], zonestatdesired, zonestatsizenow; /* current zonestat array to use */ struct nsdst* zonestatnow; + /* filenames for stat file mappings */ + char* statfname; + /* fd for stat mapping (otherwise mmaps cannot be shared between + * processes and resized) */ + int statfd; + /* statistics array, of size child_count*2, twice for old and new + * server processes. */ + struct nsdst* stat_map; + /* statistics array of size child_count, twice */ + struct nsdst* stats_per_child[2]; + /* current stats_per_child array that is in use for the child set */ + int stat_current; + /* start value for per process statistics printout, to clear it */ + struct nsdst stat_proc; #endif /* BIND8_STATS */ #ifdef USE_DNSTAP /* the dnstap collector process info */ @@ -394,6 +407,10 @@ void server_zonestat_alloc(struct nsd* nsd); /* remap the mmaps for zonestat isx, to bytesize sz. Caller has to set * the zonestatsize */ void zonestat_remap(struct nsd* nsd, int idx, size_t sz); +/* allocate stat structures */ +void server_stat_alloc(struct nsd* nsd); +/* free stat mmap file, unlinks it */ +void server_stat_free(struct nsd* nsd); /* allocate and init xfrd variables */ void server_prepare_xfrd(struct nsd *nsd); /* start xfrdaemon (again) */ diff --git a/usr.sbin/nsd/nsec3.c b/usr.sbin/nsd/nsec3.c index 4ed55e68c14..9144012cebd 100644 --- a/usr.sbin/nsd/nsec3.c +++ b/usr.sbin/nsd/nsec3.c @@ -16,7 +16,6 @@ #include "namedb.h" #include "nsd.h" #include "answer.h" -#include "udbzone.h" #include "options.h" #define NSEC3_RDATA_BITMAP 5 @@ -283,60 +282,12 @@ db_find_nsec3param(struct namedb* db, struct zone* z, struct rr* avoid_rr, return NULL; } -static struct rr* -udb_zone_find_nsec3param(struct namedb* db, udb_base* udb, udb_ptr* uz, - struct zone* z, int checkchain) -{ - udb_ptr urr; - unsigned i; - rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM); - if(!rrset) /* no NSEC3PARAM in mem */ - return NULL; - udb_ptr_new(&urr, udb, &ZONE(uz)->nsec3param); - if(!urr.data || RR(&urr)->len < 5) { - /* no NSEC3PARAM in udb */ - udb_ptr_unlink(&urr, udb); - return NULL; - } - /* find matching NSEC3PARAM RR in memory */ - for(i=0; i<rrset->rr_count; i++) { - /* if this RR matches the udb RR then we are done */ - rdata_atom_type* rd = rrset->rrs[i].rdatas; - if(rrset->rrs[i].rdata_count < 4) continue; - if(RR(&urr)->wire[0] == rdata_atom_data(rd[0])[0] && /*alg*/ - RR(&urr)->wire[1] == rdata_atom_data(rd[1])[0] && /*flg*/ - RR(&urr)->wire[2] == rdata_atom_data(rd[2])[0] && /*iter*/ - RR(&urr)->wire[3] == rdata_atom_data(rd[2])[1] && - RR(&urr)->wire[4] == rdata_atom_data(rd[3])[0] && /*slen*/ - RR(&urr)->len >= 5 + RR(&urr)->wire[4] && - memcmp(RR(&urr)->wire+5, rdata_atom_data(rd[3])+1, - rdata_atom_data(rd[3])[0]) == 0) { - udb_ptr_unlink(&urr, udb); - if(checkchain) { - z->nsec3_param = &rrset->rrs[i]; - if(!check_apex_soa(db, z, 1)) - return db_find_nsec3param(db, z, - NULL, checkchain); - } - return &rrset->rrs[i]; - } - } - udb_ptr_unlink(&urr, udb); - return NULL; -} - void -nsec3_find_zone_param(struct namedb* db, struct zone* zone, udb_ptr* z, +nsec3_find_zone_param(struct namedb* db, struct zone* zone, struct rr* avoid_rr, int checkchain) { - /* get nsec3param RR from udb */ - if(db->udb) - zone->nsec3_param = udb_zone_find_nsec3param(db, db->udb, - z, zone, checkchain); - /* no db, get from memory, avoid using the rr that is going to be - * deleted, avoid_rr */ - else zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, - checkchain); + /* avoid using the rr that is going to be deleted, avoid_rr */ + zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, checkchain); } /* check params ok for one RR */ @@ -686,30 +637,17 @@ nsec3_precompile_newparam(namedb_type* db, zone_type* zone) void prehash_zone_complete(struct namedb* db, struct zone* zone) { - udb_ptr udbz; - /* robust clear it */ nsec3_clear_precompile(db, zone); /* find zone settings */ assert(db && zone); - udbz.data = 0; - if(db->udb) { - if(!udb_zone_search(db->udb, &udbz, dname_name(domain_dname( - zone->apex)), domain_dname(zone->apex)->name_size)) { - udb_ptr_init(&udbz, db->udb); /* zero the ptr */ - } - } - nsec3_find_zone_param(db, zone, &udbz, NULL, 1); + nsec3_find_zone_param(db, zone, NULL, 1); if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) { zone->nsec3_param = NULL; zone->nsec3_last = NULL; - if(udbz.data) - udb_ptr_unlink(&udbz, db->udb); return; } - if(udbz.data) - udb_ptr_unlink(&udbz, db->udb); nsec3_precompile_newparam(db, zone); } diff --git a/usr.sbin/nsd/nsec3.h b/usr.sbin/nsd/nsec3.h index 43d0dfc944d..31acd36fe3f 100644 --- a/usr.sbin/nsd/nsec3.h +++ b/usr.sbin/nsd/nsec3.h @@ -92,7 +92,7 @@ int nsec3_condition_hash(struct domain* d, struct zone* z); int nsec3_condition_dshash(struct domain* d, struct zone* z); /* set nsec3param for this zone or NULL if no NSEC3 available */ void nsec3_find_zone_param(struct namedb* db, struct zone* zone, - struct udb_ptr* z, struct rr* avoid_rr, int checkchain); + struct rr* avoid_rr, int checkchain); /* hash domain and wcchild, and lookup nsec3 in tree, and precompile */ void nsec3_precompile_domain(struct namedb* db, struct domain* domain, struct zone* zone, struct region* tmpregion); diff --git a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c index 7f435adcbe9..fb501acbfbb 100644 --- a/usr.sbin/nsd/options.c +++ b/usr.sbin/nsd/options.c @@ -66,7 +66,6 @@ nsd_options_create(region_type* region) opt->drop_updates = 0; opt->do_ip4 = 1; opt->do_ip6 = 1; - opt->database = DBFILE; opt->identity = 0; opt->version = 0; opt->nsid = 0; @@ -131,15 +130,14 @@ nsd_options_create(region_type* region) opt->dnstap_log_auth_response_messages = 0; #endif opt->zonefiles_check = 1; - if(opt->database == NULL || opt->database[0] == 0) - opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; - else opt->zonefiles_write = 0; + opt->zonefiles_write = ZONEFILES_WRITE_INTERVAL; opt->xfrd_reload_timeout = 1; opt->tls_service_key = NULL; opt->tls_service_ocsp = NULL; opt->tls_service_pem = NULL; opt->tls_port = TLS_PORT; opt->tls_cert_bundle = NULL; + opt->proxy_protocol_port = NULL; opt->answer_cookie = 1; opt->cookie_secret = NULL; opt->cookie_secret_file = CONFIGDIR"/nsd_cookiesecrets.txt"; @@ -1681,6 +1679,32 @@ key_options_add_modify(struct nsd_options* opt, struct key_options* key) } int +acl_check_incoming_block_proxy(struct acl_options* acl, struct query* q, + struct acl_options** reason) +{ + /* check each acl element. + * if it is blocked, return -1. + * return false if no matches for blocked elements. */ + if(reason) + *reason = NULL; + + while(acl) + { + DEBUG(DEBUG_XFRD,2, (LOG_INFO, "proxy testing acl %s %s", + acl->ip_address_spec, acl->nokey?"NOKEY": + (acl->blocked?"BLOCKED":acl->key_name))); + if(acl_addr_matches_proxy(acl, q) && acl->blocked) { + if(reason) + *reason = acl; + return -1; + } + acl = acl->next; + } + + return 0; +} + +int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason) { @@ -1807,7 +1831,7 @@ acl_addr_matches(struct acl_options* acl, struct query* q) if(acl->is_ipv6) { #ifdef INET6 - struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->addr; + struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->client_addr; if(addr->ss_family != AF_INET6) return 0; return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); @@ -1817,7 +1841,32 @@ acl_addr_matches(struct acl_options* acl, struct query* q) } else { - struct sockaddr_in* addr = (struct sockaddr_in*)&q->addr; + struct sockaddr_in* addr = (struct sockaddr_in*)&q->client_addr; + if(addr->sin_family != AF_INET) + return 0; + return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); + } + /* ENOTREACH */ + return 0; +} + +int +acl_addr_matches_proxy(struct acl_options* acl, struct query* q) +{ + if(acl->is_ipv6) + { +#ifdef INET6 + struct sockaddr_storage* addr = (struct sockaddr_storage*)&q->remote_addr; + if(addr->ss_family != AF_INET6) + return 0; + return acl_addr_matches_ipv6host(acl, addr, ntohs(((struct sockaddr_in6*)addr)->sin6_port)); +#else + return 0; /* no inet6, no match */ +#endif + } + else + { + struct sockaddr_in* addr = (struct sockaddr_in*)&q->remote_addr; if(addr->sin_family != AF_INET) return 0; return acl_addr_matches_ipv4host(acl, addr, ntohs(addr->sin_port)); @@ -2578,3 +2627,36 @@ resolve_interface_names(struct nsd_options* options) (void)options; #endif /* HAVE_GETIFADDRS */ } + +int +sockaddr_uses_proxy_protocol_port(struct nsd_options* options, + struct sockaddr* addr) +{ + struct proxy_protocol_port_list* p; + int port; +#ifdef INET6 + struct sockaddr_storage* ss = (struct sockaddr_storage*)addr; + if(ss->ss_family == AF_INET6) { + struct sockaddr_in6* a6 = (struct sockaddr_in6*)addr; + port = ntohs(a6->sin6_port); + } else if(ss->ss_family == AF_INET) { +#endif + struct sockaddr_in* a = (struct sockaddr_in*)addr; +#ifndef INET6 + if(a->sin_family != AF_INET) + return 0; /* unknown family */ +#endif + port = ntohs(a->sin_port); +#ifdef INET6 + } else { + return 0; /* unknown family */ + } +#endif + p = options->proxy_protocol_port; + while(p) { + if(p->port == port) + return 1; + p = p->next; + } + return 0; +} diff --git a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h index a9540911109..baf2579f5d6 100644 --- a/usr.sbin/nsd/options.h +++ b/usr.sbin/nsd/options.h @@ -18,6 +18,7 @@ struct dname; struct tsig_key; struct buffer; struct nsd; +struct proxy_protocol_port_list; typedef struct nsd_options nsd_options_type; typedef struct pattern_options pattern_options_type; @@ -81,7 +82,6 @@ struct nsd_options { int drop_updates; int do_ip4; int do_ip6; - const char* database; const char* identity; const char* version; const char* logfile; @@ -132,6 +132,9 @@ struct nsd_options { /* TLS certificate bundle */ const char* tls_cert_bundle; + /* proxy protocol port list */ + struct proxy_protocol_port_list* proxy_protocol_port; + /** remote control section. enable toggle. */ int control_enable; /** the interfaces the remote control should listen on */ @@ -396,6 +399,12 @@ struct tls_auth_options { char* client_key_pw; }; +/* proxy protocol port option list */ +struct proxy_protocol_port_list { + struct proxy_protocol_port_list* next; + int port; +}; + /** zone list free space */ struct zonelist_free { struct zonelist_free* next; @@ -513,11 +522,16 @@ int acl_check_incoming(struct acl_options* acl, struct query* q, struct acl_options** reason); int acl_addr_matches_host(struct acl_options* acl, struct acl_options* host); int acl_addr_matches(struct acl_options* acl, struct query* q); +int acl_addr_matches_proxy(struct acl_options* acl, struct query* q); int acl_key_matches(struct acl_options* acl, struct query* q); int acl_addr_match_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz); int acl_addr_match_range_v6(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz); int acl_addr_match_range_v4(uint32_t* minval, uint32_t* x, uint32_t* maxval, size_t sz); +/* check acl list for blocks on address, return 0 if none, -1 if blocked. */ +int acl_check_incoming_block_proxy(struct acl_options* acl, struct query* q, + struct acl_options** reason); + /* returns true if acls are both from the same host */ int acl_same_host(struct acl_options* a, struct acl_options* b); /* find acl by number in the list */ @@ -562,4 +576,8 @@ void warn_if_directory(const char* filetype, FILE* f, const char* fname); * names. */ void resolve_interface_names(struct nsd_options* options); +/* See if the sockaddr port number is listed in the proxy protocol ports. */ +int sockaddr_uses_proxy_protocol_port(struct nsd_options* options, + struct sockaddr* addr); + #endif /* OPTIONS_H */ diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index 9b34f029d09..3f92ffbaaa7 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -218,7 +218,9 @@ query_reset(query_type *q, size_t maxlen, int is_tcp) * one proof per wildcard and for nx domain). */ region_free_all(q->region); - q->addrlen = sizeof(q->addr); + q->remote_addrlen = (socklen_t)sizeof(q->remote_addr); + q->client_addrlen = (socklen_t)sizeof(q->client_addr); + q->is_proxied = 0; q->maxlen = maxlen; q->reserved_space = 0; buffer_clear(q->packet); @@ -342,7 +344,7 @@ process_edns(nsd_type* nsd, struct query *q) if (!q->tcp && q->edns.maxlen > UDP_MAX_MESSAGE_LEN) { size_t edns_size; #if defined(INET6) - if (q->addr.ss_family == AF_INET6) { + if (q->client_addr.ss_family == AF_INET6) { edns_size = nsd->ipv6_edns_size; } else #endif @@ -361,7 +363,7 @@ process_edns(nsd_type* nsd, struct query *q) * IPv6 will not automatically fragment in * this case (unlike IPv4). */ - if (q->addr.ss_family == AF_INET6 + if (q->client_addr.ss_family == AF_INET6 && q->maxlen > IPV6_MIN_MTU) { q->maxlen = IPV6_MIN_MTU; @@ -389,7 +391,7 @@ process_tsig(struct query* q) if(q->tsig.status == TSIG_OK) { if(!tsig_from_query(&q->tsig)) { char a[128]; - addr2str(&q->addr, a, sizeof(a)); + addr2str(&q->client_addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig (%s) for key %s from %s", tsig_error(q->tsig.error_code), dname_to_string(q->tsig.key_name, NULL), a); @@ -401,7 +403,7 @@ process_tsig(struct query* q) tsig_update(&q->tsig, q->packet, buffer_limit(q->packet)); if(!tsig_verify(&q->tsig)) { char a[128]; - addr2str(&q->addr, a, sizeof(a)); + addr2str(&q->client_addr, a, sizeof(a)); log_msg(LOG_ERR, "query: bad tsig signature for key %s from %s", dname_to_string(q->tsig.key->name, NULL), a); return NSD_RC_NOTAUTH; @@ -442,6 +444,24 @@ answer_notify(struct nsd* nsd, struct query *query) return query_error(query, rc); /* check if it passes acl */ + if(query->is_proxied && acl_check_incoming_block_proxy( + zone_opt->pattern->allow_notify, query, &why) == -1) { + /* the proxy address is blocked */ + if (verbosity >= 2) { + char address[128], proxy[128]; + addr2str(&query->client_addr, address, sizeof(address)); + addr2str(&query->remote_addr, proxy, sizeof(proxy)); + VERBOSITY(2, (LOG_INFO, "notify for %s from %s via proxy %s refused because of proxy, %s %s", + dname_to_string(query->qname, NULL), + address, proxy, + (why?why->ip_address_spec:"."), + (why ? ( why->nokey ? "NOKEY" + : why->blocked ? "BLOCKED" + : why->key_name ) + : "no acl matches"))); + } + return query_error(query, NSD_RC_REFUSE); + } if((acl_num = acl_check_incoming(zone_opt->pattern->allow_notify, query, &why)) != -1) { @@ -483,7 +503,7 @@ answer_notify(struct nsd* nsd, struct query *query) if(verbosity >= 1) { uint32_t serial = 0; char address[128]; - addr2str(&query->addr, address, sizeof(address)); + addr2str(&query->client_addr, address, sizeof(address)); if(packet_find_notify_serial(query->packet, &serial)) VERBOSITY(1, (LOG_INFO, "notify for %s from %s serial %u", dname_to_string(query->qname, NULL), address, @@ -510,12 +530,15 @@ answer_notify(struct nsd* nsd, struct query *query) if (verbosity >= 2) { char address[128]; - addr2str(&query->addr, address, sizeof(address)); - VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s%s", + addr2str(&query->client_addr, address, sizeof(address)); + VERBOSITY(2, (LOG_INFO, "notify for %s from %s refused, %s %s", dname_to_string(query->qname, NULL), address, - why?why->key_name:"no acl matches", - why?why->ip_address_spec:".")); + (why?why->ip_address_spec:"."), + (why ? ( why->nokey ? "NOKEY" + : why->blocked ? "BLOCKED" + : why->key_name ) + : "no acl matches"))); } return query_error(query, NSD_RC_REFUSE); @@ -745,7 +768,7 @@ add_rrset(struct query *query, #if defined(INET6) /* if query over IPv6, swap A and AAAA; put AAAA first */ add_additional_rrsets(query, answer, rrset, 0, 1, - (query->addr.ss_family == AF_INET6)? + (query->client_addr.ss_family == AF_INET6)? swap_aaaa_additional_rr_types: default_additional_rr_types); #else @@ -1309,6 +1332,31 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, struct acl_options *why = NULL; /* check if it passes acl */ + if(q->is_proxied && acl_check_incoming_block_proxy( + q->zone->opts->pattern->allow_query, q, &why) == -1) { + /* the proxy address is blocked */ + if (verbosity >= 2) { + char address[128], proxy[128]; + addr2str(&q->client_addr, address, sizeof(address)); + addr2str(&q->remote_addr, proxy, sizeof(proxy)); + VERBOSITY(2, (LOG_INFO, "query %s from %s via proxy %s refused because of proxy, %s %s", + dname_to_string(q->qname, NULL), + address, proxy, + (why?why->ip_address_spec:"."), + (why ? ( why->nokey ? "NOKEY" + : why->blocked ? "BLOCKED" + : why->key_name ) + : "no acl matches"))); + } + /* no zone for this */ + if(q->cname_count == 0) { + RCODE_SET(q->packet, RCODE_REFUSE); + /* RFC8914 - Extended DNS Errors + * 4.19. Extended DNS Error Code 18 - Prohibited */ + q->edns.ede = EDE_PROHIBITED; + } + return; + } if(acl_check_incoming( q->zone->opts->pattern->allow_query, q, &why) != -1) { assert(why); @@ -1317,16 +1365,16 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); - } else { + } else { if (verbosity >= 2) { char address[128]; - addr2str(&q->addr, address, sizeof(address)); + addr2str(&q->client_addr, address, sizeof(address)); VERBOSITY(2, (LOG_INFO, "query %s from %s refused, %s %s", dname_to_string(q->qname, NULL), address, why ? ( why->nokey ? "NOKEY" : why->blocked ? "BLOCKED" - : why->key_name ) + : why->key_name ) : "no acl matches", why?why->ip_address_spec:".")); } @@ -1695,7 +1743,7 @@ query_add_optional(query_type *q, nsd_type *nsd, uint32_t *now_p) { struct edns_data *edns = &nsd->edns_ipv4; #if defined(INET6) - if (q->addr.ss_family == AF_INET6) { + if (q->client_addr.ss_family == AF_INET6) { edns = &nsd->edns_ipv6; } #endif diff --git a/usr.sbin/nsd/query.h b/usr.sbin/nsd/query.h index e6822901918..89666fe2cf4 100644 --- a/usr.sbin/nsd/query.h +++ b/usr.sbin/nsd/query.h @@ -39,11 +39,22 @@ struct query { * The address the query was received from. */ #ifdef INET6 - struct sockaddr_storage addr; + struct sockaddr_storage remote_addr; #else - struct sockaddr_in addr; + struct sockaddr_in remote_addr; #endif - socklen_t addrlen; + socklen_t remote_addrlen; + + /* if set, the request came through a proxy */ + int is_proxied; + /* the client address + * the same as remote_addr if not proxied */ +#ifdef INET6 + struct sockaddr_storage client_addr; +#else + struct sockaddr_in client_addr; +#endif + socklen_t client_addrlen; /* * Maximum supported query size. diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index 5cdee68db2b..13fd20f2ebc 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -133,9 +133,6 @@ struct rc_state { struct daemon_remote* rc; /** stats list next item */ struct rc_state* stats_next; - /** stats list indicator (0 is not part of stats list, 1 is stats, - * 2 is stats_noreset. */ - int in_stats_list; }; /** @@ -165,8 +162,6 @@ struct daemon_remote { int max_active; /** current commpoints busy; double linked, malloced */ struct rc_state* busy_list; - /** commpoints waiting for stats to complete (also in busy_list) */ - struct rc_state* stats_list; /** last time stats was reported */ struct timeval stats_time, boot_time; #ifdef HAVE_SSL @@ -223,6 +218,10 @@ remote_accept_callback(int fd, short event, void* arg); static void remote_control_callback(int fd, short event, void* arg); +#ifdef BIND8_STATS +/* process the statistics and output them */ +static void process_stats(RES* ssl, xfrd_state_type* xfrd, int peek); +#endif /** ---- end of private defines ---- **/ @@ -686,7 +685,6 @@ remote_accept_callback(int fd, short event, void* arg) n->rc = rc; n->stats_next = NULL; - n->in_stats_list = 0; n->prev = NULL; n->next = rc->busy_list; if(n->next) n->next->prev = n; @@ -707,35 +705,10 @@ state_list_remove_elem(struct rc_state** list, struct rc_state* todel) if(todel->next) todel->next->prev = todel->prev; } -/** delete from stats list */ -static void -stats_list_remove_elem(struct rc_state** list, struct rc_state* todel) -{ - struct rc_state* prev = NULL; - struct rc_state* n = *list; - while(n) { - /* delete this one? */ - if(n == todel) { - if(prev) prev->next = n->next; - else (*list) = n->next; - /* go on and delete further elements */ - /* prev = prev; */ - n = n->next; - continue; - } - - /* go to the next element */ - prev = n; - n = n->next; - } -} - /** decrease active count and remove commpoint from busy list */ static void clean_point(struct daemon_remote* rc, struct rc_state* s) { - if(s->in_stats_list) - stats_list_remove_elem(&rc->stats_list, s); state_list_remove_elem(&rc->busy_list, s); rc->active --; if(s->event_added) @@ -1229,27 +1202,13 @@ do_status(RES* ssl, xfrd_state_type* xfrd) /** do the stats command */ static void -do_stats(struct daemon_remote* rc, int peek, struct rc_state* rs) +do_stats(RES* ssl, xfrd_state_type* xfrd, int peek) { #ifdef BIND8_STATS - /* queue up to get stats after a reload is done (to gather statistics - * from the servers) */ - assert(!rs->in_stats_list); - if(peek) rs->in_stats_list = 2; - else rs->in_stats_list = 1; - rs->stats_next = rc->stats_list; - rc->stats_list = rs; - /* block the tcp waiting for the reload */ - event_del(&rs->c); - rs->event_added = 0; - /* force a reload */ - xfrd_set_reload_now(xfrd); + process_stats(ssl, xfrd, peek); #else - RES res; - res.ssl = rs->ssl; - res.fd = rs->fd; - (void)rc; (void)peek; - (void)ssl_printf(&res, "error no stats enabled at compile time\n"); + (void)xfrd; (void)peek; + (void)ssl_printf(ssl, "error no stats enabled at compile time\n"); #endif /* BIND8_STATS */ } @@ -2359,7 +2318,7 @@ cmdcmp(char* p, const char* cmd, size_t len) /** execute a remote control command */ static void -execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, struct rc_state* rs) +execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd) { char* p = skipwhite(cmd); /* compare command */ @@ -2372,9 +2331,9 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, struct rc_state* rs) } else if(cmdcmp(p, "status", 6)) { do_status(ssl, rc->xfrd); } else if(cmdcmp(p, "stats_noreset", 13)) { - do_stats(rc, 1, rs); + do_stats(ssl, rc->xfrd, 1); } else if(cmdcmp(p, "stats", 5)) { - do_stats(rc, 0, rs); + do_stats(ssl, rc->xfrd, 0); } else if(cmdcmp(p, "log_reopen", 10)) { do_log_reopen(ssl, rc->xfrd); } else if(cmdcmp(p, "addzone", 7)) { @@ -2487,7 +2446,7 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) VERBOSITY(0, (LOG_INFO, "control cmd: %s", buf)); /* figure out what to do */ - execute_cmd(rc, res, buf, s); + execute_cmd(rc, res, buf); } #ifdef HAVE_SSL @@ -2590,10 +2549,8 @@ remote_control_callback(int fd, short event, void* arg) res.fd = fd; handle_req(rc, s, &res); - if(!s->in_stats_list) { - VERBOSITY(3, (LOG_INFO, "remote control operation completed")); - clean_point(rc, s); - } + VERBOSITY(3, (LOG_INFO, "remote control operation completed")); + clean_point(rc, s); } #ifdef BIND8_STATS @@ -2746,7 +2703,8 @@ resize_zonestat(xfrd_state_type* xfrd, size_t num) } static void -zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear) +zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear, + struct nsdst** zonestats) { struct zonestatname* n; struct nsdst stat0, stat1; @@ -2761,8 +2719,8 @@ zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear) * the newly forked processes get the other block to use, * these blocks are mmapped and are currently in use to * add statistics to */ - memcpy(&stat0, &xfrd->nsd->zonestat[0][n->id], sizeof(stat0)); - memcpy(&stat1, &xfrd->nsd->zonestat[1][n->id], sizeof(stat1)); + memcpy(&stat0, &zonestats[0][n->id], sizeof(stat0)); + memcpy(&stat1, &zonestats[1][n->id], sizeof(stat1)); stats_add(&stat0, &stat1); /* save a copy of current (cumulative) stats in stat1 */ @@ -2798,7 +2756,8 @@ zonestat_print(RES* ssl, xfrd_state_type* xfrd, int clear) #endif /* USE_ZONE_STATS */ static void -print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) +print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear, + struct nsdst* st, struct nsdst** zonestats) { size_t i; stc_type total = 0; @@ -2825,9 +2784,9 @@ print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) return; /* mem info, database on disksize */ - if(!print_longnum(ssl, "size.db.disk=", xfrd->nsd->st.db_disk)) + if(!print_longnum(ssl, "size.db.disk=", st->db_disk)) return; - if(!print_longnum(ssl, "size.db.mem=", xfrd->nsd->st.db_mem)) + if(!print_longnum(ssl, "size.db.mem=", st->db_mem)) return; if(!print_longnum(ssl, "size.xfrd.mem=", region_get_mem(xfrd->region))) return; @@ -2837,7 +2796,7 @@ print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) if(!print_longnum(ssl, "size.config.mem=", region_get_mem( xfrd->nsd->options->region))) return; - print_stat_block(ssl, "", "", &xfrd->nsd->st); + print_stat_block(ssl, "", "", st); /* zone statistics */ if(!ssl_printf(ssl, "zone.master=%lu\n", @@ -2846,55 +2805,137 @@ print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear) if(!ssl_printf(ssl, "zone.slave=%lu\n", (unsigned long)xfrd->zones->count)) return; #ifdef USE_ZONE_STATS - zonestat_print(ssl, xfrd, clear); /* per-zone statistics */ + zonestat_print(ssl, xfrd, clear, zonestats); /* per-zone statistics */ +#else + (void)clear; (void)zonestats; +#endif +} + +/* allocate stats temp arrays, for taking a coherent snapshot of the + * statistics values at that time. */ +static void +process_stats_alloc(xfrd_state_type* xfrd, struct nsdst** stats, + struct nsdst** zonestats) +{ + *stats = xmallocarray(xfrd->nsd->child_count*2, sizeof(struct nsdst)); +#ifdef USE_ZONE_STATS + zonestats[0] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); + zonestats[1] = xmallocarray(xfrd->zonestat_safe, sizeof(struct nsdst)); +#else + (void)zonestats; +#endif +} + +/* grab a copy of the statistics, at this particular time. */ +static void +process_stats_grab(xfrd_state_type* xfrd, struct timeval* stattime, + struct nsdst* stats, struct nsdst** zonestats) +{ + if(gettimeofday(stattime, NULL) == -1) + log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); + memcpy(stats, xfrd->nsd->stat_map, + xfrd->nsd->child_count*2*sizeof(struct nsdst)); +#ifdef USE_ZONE_STATS + memcpy(zonestats[0], xfrd->nsd->zonestat[0], + xfrd->zonestat_safe*sizeof(struct nsdst)); + memcpy(zonestats[1], xfrd->nsd->zonestat[1], + xfrd->zonestat_safe*sizeof(struct nsdst)); #else - (void)clear; + (void)zonestats; #endif } +/* add the old and new processes stat values into the first part of the + * array of stats */ static void -clear_stats(xfrd_state_type* xfrd) +process_stats_add_old_new(xfrd_state_type* xfrd, struct nsdst* stats) { size_t i; - uint64_t dbd = xfrd->nsd->st.db_disk; - uint64_t dbm = xfrd->nsd->st.db_mem; + uint64_t dbd = stats[0].db_disk; + uint64_t dbm = stats[0].db_mem; + /* The old and new server processes have separate stat blocks, + * and these are added up together. This results in the statistics + * values per server-child. The reload task briefly forks both + * old and new server processes. */ for(i=0; i<xfrd->nsd->child_count; i++) { - xfrd->nsd->children[i].query_count = 0; + stats_add(&stats[i], &stats[xfrd->nsd->child_count+i]); } - memset(&xfrd->nsd->st, 0, sizeof(struct nsdst)); - /* zonestats are cleared by storing the cumulative value that - * was last printed in the zonestat_clear array, and subtracting - * that before the next stats printout */ - xfrd->nsd->st.db_disk = dbd; - xfrd->nsd->st.db_mem = dbm; + stats[0].db_disk = dbd; + stats[0].db_mem = dbm; } -void -daemon_remote_process_stats(struct daemon_remote* rc) +/* manage clearing of stats, a cumulative count of cleared statistics */ +static void +process_stats_manage_clear(xfrd_state_type* xfrd, struct nsdst* stats, + int peek) { - RES res; - struct rc_state* s; - struct timeval now; - if(!rc) return; - if(gettimeofday(&now, NULL) == -1) - log_msg(LOG_ERR, "gettimeofday: %s", strerror(errno)); - /* pop one and give it stats */ - while((s = rc->stats_list)) { - assert(s->in_stats_list); -#ifdef HAVE_SSL - res.ssl = s->ssl; -#endif - res.fd = s->fd; - print_stats(&res, rc->xfrd, &now, (s->in_stats_list == 1)); - if(s->in_stats_list == 1) { - clear_stats(rc->xfrd); - rc->stats_time = now; + struct nsdst st; + size_t i; + if(peek) { + /* Subtract the earlier resetted values from the numbers, + * but do not reset the values that are retrieved now. */ + if(!xfrd->stat_clear) + return; /* nothing to subtract */ + for(i=0; i<xfrd->nsd->child_count; i++) { + /* subtract cumulative count that has been reset */ + stats_subtract(&stats[i], &xfrd->stat_clear[i]); } - VERBOSITY(3, (LOG_INFO, "remote control stats printed")); - rc->stats_list = s->next; - s->in_stats_list = 0; - clean_point(rc, s); + return; } + if(!xfrd->stat_clear) + xfrd->stat_clear = region_alloc_zero(xfrd->region, + sizeof(struct nsdst)*xfrd->nsd->child_count); + for(i=0; i<xfrd->nsd->child_count; i++) { + /* store cumulative count copy */ + memcpy(&st, &stats[i], sizeof(st)); + /* subtract cumulative count that has been reset */ + stats_subtract(&stats[i], &xfrd->stat_clear[i]); + /* store cumulative count in the cleared value array */ + memcpy(&xfrd->stat_clear[i], &st, sizeof(st)); + } +} + +/* add up the statistics to get the total over the server children. */ +static void +process_stats_add_total(xfrd_state_type* xfrd, struct nsdst* total, + struct nsdst* stats) +{ + size_t i; + /* copy over the first one, with also the nonadded values. */ + memcpy(total, &stats[0], sizeof(*total)); + xfrd->nsd->children[0].query_count = stats[0].qudp + stats[0].qudp6 + + stats[0].ctcp + stats[0].ctcp6 + stats[0].ctls + + stats[0].ctls6; + for(i=1; i<xfrd->nsd->child_count; i++) { + stats_add(total, &stats[i]); + xfrd->nsd->children[i].query_count = stats[i].qudp + + stats[i].qudp6 + stats[i].ctcp + stats[i].ctcp6 + + stats[i].ctls + stats[i].ctls6; + } +} + +/* process the statistics and output them */ +static void +process_stats(RES* ssl, xfrd_state_type* xfrd, int peek) +{ + struct timeval stattime; + struct nsdst* stats, *zonestats[2], total; + + process_stats_alloc(xfrd, &stats, zonestats); + process_stats_grab(xfrd, &stattime, stats, zonestats); + process_stats_add_old_new(xfrd, stats); + process_stats_manage_clear(xfrd, stats, peek); + process_stats_add_total(xfrd, &total, stats); + print_stats(ssl, xfrd, &stattime, !peek, &total, zonestats); + xfrd->nsd->rc->stats_time = stattime; + + free(stats); +#ifdef USE_ZONE_STATS + free(zonestats[0]); + free(zonestats[1]); +#endif + + VERBOSITY(3, (LOG_INFO, "remote control stats printed")); } #endif /* BIND8_STATS */ diff --git a/usr.sbin/nsd/remote.h b/usr.sbin/nsd/remote.h index fb8fd699a0f..771bf86dc36 100644 --- a/usr.sbin/nsd/remote.h +++ b/usr.sbin/nsd/remote.h @@ -93,12 +93,6 @@ int daemon_remote_open_ports(struct daemon_remote* rc, void daemon_remote_attach(struct daemon_remote* rc, struct xfrd_state* xfrd); /** - * Process statistic results and send them - * @param rc: state. - */ -void daemon_remote_process_stats(struct daemon_remote* rc); - -/** * Create and bind local listening socket * @param path: path to the socket. * @param noproto: on error, this is set true if cause is that local sockets diff --git a/usr.sbin/nsd/rrl.c b/usr.sbin/nsd/rrl.c index 69232a95f4a..93a0d392e85 100644 --- a/usr.sbin/nsd/rrl.c +++ b/usr.sbin/nsd/rrl.c @@ -153,20 +153,20 @@ static uint64_t rrl_get_source(query_type* query, uint16_t* c2) * to the same buckets as IPv4 space, but there is a flag in c2 * that makes the hash different */ #ifdef INET6 - if( ((struct sockaddr_in*)&query->addr)->sin_family == AF_INET) { + if( ((struct sockaddr_in*)&query->client_addr)->sin_family == AF_INET) { *c2 = 0; - return ((struct sockaddr_in*)&query->addr)-> + return ((struct sockaddr_in*)&query->client_addr)-> sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); } else { uint64_t s; *c2 = rrl_ip6; - memmove(&s, &((struct sockaddr_in6*)&query->addr)->sin6_addr, + memmove(&s, &((struct sockaddr_in6*)&query->client_addr)->sin6_addr, sizeof(s)); return s & rrl_ipv6_mask; } #else *c2 = 0; - return query->addr.sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); + return query->client_addr.sin_addr.s_addr & htonl(0xffffffff << (32-rrl_ipv4_prefixlen)); #endif } @@ -359,7 +359,7 @@ rrl_msg(query_type* query, const char* str) uint64_t s; char address[128]; if(verbosity < 1) return; - addr2str(&query->addr, address, sizeof(address)); + addr2str(&query->client_addr, address, sizeof(address)); s = rrl_get_source(query, &c2); c = rrl_classify(query, &d, &d_len) | c2; if(query->zone && query->zone->opts && @@ -394,7 +394,7 @@ uint32_t rrl_update(query_type* query, uint32_t hash, uint64_t source, if(verbosity >= 1 && used_to_block(b->rate, b->counter, rrl_ratelimit)) { char address[128]; - addr2str(&query->addr, address, sizeof(address)); + addr2str(&query->client_addr, address, sizeof(address)); log_msg(LOG_INFO, "ratelimit unblock ~ type %s target %s query %s %s (%s collision)", rrltype2str(b->flags), rrlsource2str(b->source, b->flags), diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index 529edcf404f..3a022b73994 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -86,6 +86,7 @@ #include "dnstap/dnstap_collector.h" #endif #include "verify.h" +#include "util/proxy_protocol.h" #define RELOAD_SYNC_TIMEOUT 25 /* seconds */ @@ -131,6 +132,16 @@ log_addr(const char* descr, #define TCP_FASTOPEN_SERVER_BIT_MASK 0x2 #endif +/* header state for the PROXYv2 header (for TCP) */ +enum pp2_header_state { + /* no header encounter yet */ + pp2_header_none = 0, + /* read the static part of the header */ + pp2_header_init, + /* read the full header */ + pp2_header_done +}; + /* * Data for the UDP handlers. */ @@ -139,6 +150,8 @@ struct udp_handler_data struct nsd *nsd; struct nsd_socket *socket; struct event event; + /* if set, PROXYv2 is expected on this connection */ + int pp2_enabled; }; struct tcp_accept_handler_data { @@ -150,6 +163,8 @@ struct tcp_accept_handler_data { /* handler accepts TLS connections on the dedicated port */ int tls_accept; #endif + /* if set, PROXYv2 is expected on this connection */ + int pp2_enabled; }; /* @@ -239,6 +254,9 @@ struct tcp_handler_data */ size_t bytes_transmitted; + /* If the query is restarted and needs a reset */ + int query_needs_reset; + /* * The number of queries handled by this specific TCP connection. */ @@ -259,6 +277,12 @@ struct tcp_handler_data struct nsd_socket *socket; #endif /* USE_DNSTAP */ + /* if set, PROXYv2 is expected on this connection */ + int pp2_enabled; + + /* header state for the PROXYv2 header (for TCP) */ + enum pp2_header_state pp2_header_state; + #ifdef HAVE_SSL /* * TLS object. @@ -465,9 +489,6 @@ restart_child_servers(struct nsd *nsd, region_type* region, netio_type* netio, nsd->children[i].handler->fd = nsd->children[i].child_fd; break; case 0: /* CHILD */ - /* the child need not be able to access the - * nsd.db file */ - namedb_close_udb(nsd->db); #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(region); #endif @@ -514,8 +535,8 @@ restart_child_servers(struct nsd *nsd, region_type* region, netio_type* netio, static void set_bind8_alarm(struct nsd* nsd) { /* resync so that the next alarm is on the next whole minute */ - if(nsd->st.period > 0) /* % by 0 gives divbyzero error */ - alarm(nsd->st.period - (time(NULL) % nsd->st.period)); + if(nsd->st_period > 0) /* % by 0 gives divbyzero error */ + alarm(nsd->st_period - (time(NULL) % nsd->st_period)); } #endif @@ -693,6 +714,69 @@ server_zonestat_switch(struct nsd* nsd) } #endif /* USE_ZONE_STATS */ +#ifdef BIND8_STATS +void +server_stat_alloc(struct nsd* nsd) +{ + char tmpfile[256]; + size_t sz = sizeof(struct nsdst) * nsd->child_count * 2; + uint8_t z = 0; + + /* file name */ + nsd->statfname = 0; + snprintf(tmpfile, sizeof(tmpfile), "%snsd-xfr-%d/nsd.%u.stat", + nsd->options->xfrdir, (int)getpid(), (unsigned)getpid()); + nsd->statfname = region_strdup(nsd->region, tmpfile); + + /* file descriptor */ + nsd->statfd = open(nsd->statfname, O_CREAT|O_RDWR, 0600); + if(nsd->statfd == -1) { + log_msg(LOG_ERR, "cannot create %s: %s", nsd->statfname, + strerror(errno)); + unlink(nsd->zonestatfname[0]); + unlink(nsd->zonestatfname[1]); + exit(1); + } + +#ifdef HAVE_MMAP + if(lseek(nsd->statfd, (off_t)sz-1, SEEK_SET) == -1) { + log_msg(LOG_ERR, "lseek %s: %s", nsd->statfname, + strerror(errno)); + goto fail_exit; + } + if(write(nsd->statfd, &z, 1) == -1) { + log_msg(LOG_ERR, "cannot extend stat file %s (%s)", + nsd->statfname, strerror(errno)); + goto fail_exit; + } + nsd->stat_map = (struct nsdst*)mmap(NULL, sz, PROT_READ|PROT_WRITE, + MAP_SHARED, nsd->statfd, 0); + if(nsd->stat_map == MAP_FAILED) { + log_msg(LOG_ERR, "mmap failed: %s", strerror(errno)); +fail_exit: + close(nsd->statfd); + unlink(nsd->statfname); + unlink(nsd->zonestatfname[0]); + unlink(nsd->zonestatfname[1]); + exit(1); + } + memset(nsd->stat_map, 0, sz); + nsd->stats_per_child[0] = nsd->stat_map; + nsd->stats_per_child[1] = &nsd->stat_map[nsd->child_count]; + nsd->stat_current = 0; + nsd->st = &nsd->stats_per_child[nsd->stat_current][0]; +#endif /* HAVE_MMAP */ +} +#endif /* BIND8_STATS */ + +#ifdef BIND8_STATS +void +server_stat_free(struct nsd* nsd) +{ + unlink(nsd->statfname); +} +#endif /* BIND8_STATS */ + static void cleanup_dname_compression_tables(void *ptr) { @@ -1405,7 +1489,7 @@ int server_prepare(struct nsd *nsd) { #ifdef RATELIMIT - /* set secret modifier for hashing (udb ptr buckets and rate limits) */ + /* set secret modifier for hashing (rate limits) */ #ifdef HAVE_GETRANDOM uint32_t v; if(getrandom(&v, sizeof(v), 0) == -1) { @@ -1434,24 +1518,24 @@ server_prepare(struct nsd *nsd) #endif /* RATELIMIT */ /* Open the database... */ - if ((nsd->db = namedb_open(nsd->dbfile, nsd->options)) == NULL) { - log_msg(LOG_ERR, "unable to open the database %s: %s", - nsd->dbfile, strerror(errno)); + if ((nsd->db = namedb_open(nsd->options)) == NULL) { + log_msg(LOG_ERR, "unable to open the database: %s", strerror(errno)); unlink(nsd->task[0]->fname); unlink(nsd->task[1]->fname); #ifdef USE_ZONE_STATS unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif +#ifdef BIND8_STATS + server_stat_free(nsd); +#endif xfrd_del_tempdir(nsd); return -1; } - /* check if zone files have been modified */ + /* check if zone files can be read */ /* NULL for taskudb because we send soainfo in a moment, batched up, * for all zones */ - if(nsd->options->zonefiles_check || (nsd->options->database == NULL || - nsd->options->database[0] == 0)) - namedb_check_zonefiles(nsd, nsd->options, NULL, NULL); + namedb_check_zonefiles(nsd, nsd->options, NULL, NULL); zonestatid_tree_set(nsd); compression_table_capacity = 0; @@ -1459,7 +1543,7 @@ server_prepare(struct nsd *nsd) #ifdef BIND8_STATS /* Initialize times... */ - time(&nsd->st.boot); + time(&nsd->st->boot); set_bind8_alarm(nsd); #endif /* BIND8_STATS */ @@ -1548,7 +1632,6 @@ server_shutdown(struct nsd *nsd) udb_base_free_keep_mmap(nsd->task[0]); udb_base_free_keep_mmap(nsd->task[1]); namedb_free_ixfr(nsd->db); - namedb_close_udb(nsd->db); /* keeps mmap */ namedb_close(nsd->db); nsd_options_destroy(nsd->options); region_destroy(nsd->region); @@ -1571,6 +1654,9 @@ server_prepare_xfrd(struct nsd* nsd) unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif +#ifdef BIND8_STATS + server_stat_free(nsd); +#endif xfrd_del_tempdir(nsd); exit(1); } @@ -1583,6 +1669,9 @@ server_prepare_xfrd(struct nsd* nsd) unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif +#ifdef BIND8_STATS + server_stat_free(nsd); +#endif xfrd_del_tempdir(nsd); exit(1); } @@ -1718,9 +1807,9 @@ server_send_soa_xfrd(struct nsd* nsd, int shortsoa) unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif - /* write the nsd.db to disk, wait for it to complete */ - udb_base_sync(nsd->db->udb, 1); - udb_base_close(nsd->db->udb); +#ifdef BIND8_STATS + server_stat_free(nsd); +#endif server_shutdown(nsd); /* ENOTREACH */ exit(0); @@ -2199,8 +2288,6 @@ reload_process_tasks(struct nsd* nsd, udb_ptr* last_task, int cmdsocket) DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", (int)cmd)); if(cmd == NSD_QUIT) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd")); - /* sync to disk (if needed) */ - udb_base_sync(nsd->db->udb, 0); /* unlink files of remainder of tasks */ while(!udb_ptr_is_null(&t)) { if(TASKLIST(&t)->task_type == task_apply_xfr) { @@ -2219,47 +2306,6 @@ reload_process_tasks(struct nsd* nsd, udb_ptr* last_task, int cmdsocket) udb_ptr_unlink(&next, u); } -#ifdef BIND8_STATS -static void -parent_send_stats(struct nsd* nsd, int cmdfd) -{ - size_t i; - if(!write_socket(cmdfd, &nsd->st, sizeof(nsd->st))) { - log_msg(LOG_ERR, "could not write stats to reload"); - return; - } - for(i=0; i<nsd->child_count; i++) - if(!write_socket(cmdfd, &nsd->children[i].query_count, - sizeof(stc_type))) { - log_msg(LOG_ERR, "could not write stats to reload"); - return; - } -} - -static void -reload_do_stats(int cmdfd, struct nsd* nsd, udb_ptr* last) -{ - struct nsdst s; - stc_type* p; - size_t i; - if(block_read(nsd, cmdfd, &s, sizeof(s), - RELOAD_SYNC_TIMEOUT) != sizeof(s)) { - log_msg(LOG_ERR, "could not read stats from oldpar"); - return; - } - s.db_disk = (nsd->db->udb?nsd->db->udb->base_size:0); - s.db_mem = region_get_mem(nsd->db->region); - p = (stc_type*)task_new_stat_info(nsd->task[nsd->mytask], last, &s, - nsd->child_count); - if(!p) return; - for(i=0; i<nsd->child_count; i++) { - if(block_read(nsd, cmdfd, p++, sizeof(stc_type), 1)!= - sizeof(stc_type)) - return; - } -} -#endif /* BIND8_STATS */ - void server_verify(struct nsd *nsd, int cmdsocket); /* @@ -2295,24 +2341,22 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, /* see what tasks we got from xfrd */ task_remap(nsd->task[nsd->mytask]); udb_ptr_init(&last_task, nsd->task[nsd->mytask]); - udb_compact_inhibited(nsd->db->udb, 1); reload_process_tasks(nsd, &last_task, cmdsocket); - udb_compact_inhibited(nsd->db->udb, 0); - udb_compact(nsd->db->udb); #ifndef NDEBUG if(nsd_debug_level >= 1) region_log_stats(nsd->db->region); #endif /* NDEBUG */ - /* sync to disk (if needed) */ - udb_base_sync(nsd->db->udb, 0); - initialize_dname_compression_tables(nsd); #ifdef BIND8_STATS /* Restart dumping stats if required. */ - time(&nsd->st.boot); + time(&nsd->st->boot); set_bind8_alarm(nsd); + /* Switch to a different set of stat array for new server processes, + * because they can briefly coexist with the old processes. They + * have their own stat structure. */ + nsd->stat_current = (nsd->stat_current==0?1:0); #endif #ifdef USE_ZONE_STATS server_zonestat_realloc(nsd); /* realloc for new children */ @@ -2399,6 +2443,7 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, /* Send quit command to parent: blocking, wait for receipt. */ do { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); + cmd = NSD_QUIT_SYNC; if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) { log_msg(LOG_ERR, "problems sending command from reload to oldnsd: %s", @@ -2423,9 +2468,6 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, exit(1); } assert(ret==-1 || ret == 0 || cmd == NSD_RELOAD); -#ifdef BIND8_STATS - reload_do_stats(cmdsocket, nsd, &last_task); -#endif udb_ptr_unlink(&last_task, nsd->task[nsd->mytask]); task_process_sync(nsd->task[nsd->mytask]); #ifdef USE_ZONE_STATS @@ -2515,6 +2557,12 @@ server_main(struct nsd *nsd) /* Add listener for the XFRD process */ netio_add_handler(netio, nsd->xfrd_listener); +#ifdef BIND8_STATS + nsd->st = &nsd->stat_map[0]; + nsd->st->db_disk = 0; + nsd->st->db_mem = region_get_mem(nsd->db->region); +#endif + /* Start the child processes that handle incoming queries */ if (server_start_children(nsd, server_region, netio, &nsd->xfrd_listener->fd) != 0) { @@ -2769,9 +2817,6 @@ server_main(struct nsd *nsd) log_msg(LOG_ERR, "server_main: " "could not ack quit: %s", strerror(errno)); } -#ifdef BIND8_STATS - parent_send_stats(nsd, reload_listener.fd); -#endif /* BIND8_STATS */ close(reload_listener.fd); } DEBUG(DEBUG_IPC,1, (LOG_INFO, "server_main: shutdown sequence")); @@ -2819,6 +2864,9 @@ server_main(struct nsd *nsd) unlink(nsd->zonestatfname[0]); unlink(nsd->zonestatfname[1]); #endif +#ifdef BIND8_STATS + server_stat_free(nsd); +#endif #ifdef USE_DNSTAP dt_collector_close(nsd->dt_collector, nsd); #endif @@ -2861,9 +2909,6 @@ server_main(struct nsd *nsd) #ifdef MEMCLEAN /* OS collects memory pages */ region_destroy(server_region); #endif - /* write the nsd.db to disk, wait for it to complete */ - udb_base_sync(nsd->db->udb, 1); - udb_base_close(nsd->db->udb); server_shutdown(nsd); } @@ -2972,6 +3017,12 @@ add_udp_handler( data->nsd = nsd; data->socket = sock; + if(nsd->options->proxy_protocol_port && + sockaddr_uses_proxy_protocol_port(nsd->options, + (struct sockaddr *)&sock->addr.ai_addr)) { + data->pp2_enabled = 1; + } + memset(handler, 0, sizeof(*handler)); event_set(handler, sock->s, EV_PERSIST|EV_READ, handle_udp, data); if(event_base_set(nsd->event_base, handler) != 0) @@ -2991,6 +3042,12 @@ add_tcp_handler( data->nsd = nsd; data->socket = sock; + if(nsd->options->proxy_protocol_port && + sockaddr_uses_proxy_protocol_port(nsd->options, + (struct sockaddr *)&sock->addr.ai_addr)) { + data->pp2_enabled = 1; + } + #ifdef HAVE_SSL if (nsd->tls_ctx && nsd->options->tls_port && @@ -3091,8 +3148,8 @@ void server_verify(struct nsd *nsd, int cmdsocket) iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; - msgs[i].msg_hdr.msg_name = &queries[i]->addr; - msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; + msgs[i].msg_hdr.msg_name = &queries[i]->remote_addr; + msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } for (size_t i = 0; i < nsd->verify_ifs; i++) { @@ -3179,6 +3236,12 @@ server_child(struct nsd *nsd) set_cpu_affinity(nsd->this_child->cpuset); } #endif +#ifdef BIND8_STATS + nsd->st = &nsd->stats_per_child[nsd->stat_current] + [nsd->this_child->child_num]; + nsd->st->boot = nsd->stat_map[0].boot; + memcpy(&nsd->stat_proc, nsd->st, sizeof(nsd->stat_proc)); +#endif if (!(nsd->server_kind & NSD_SERVER_TCP)) { server_close_all_sockets(nsd->tcp, nsd->ifs); @@ -3230,8 +3293,8 @@ server_child(struct nsd *nsd) iovecs[i].iov_len = buffer_remaining(queries[i]->packet); msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; - msgs[i].msg_hdr.msg_name = &queries[i]->addr; - msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; + msgs[i].msg_hdr.msg_name = &queries[i]->remote_addr; + msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } for (i = 0; i < nsd->ifs; i++) { @@ -3296,11 +3359,11 @@ server_child(struct nsd *nsd) /* Do we need to do the statistics... */ if (mode == NSD_STATS) { #ifdef BIND8_STATS - int p = nsd->st.period; - nsd->st.period = 1; /* force stats printout */ + int p = nsd->st_period; + nsd->st_period = 1; /* force stats printout */ /* Dump the statistics */ bind8_stats(nsd); - nsd->st.period = p; + nsd->st_period = p; #else /* !BIND8_STATS */ log_msg(LOG_NOTICE, "Statistics support not enabled at compile time."); #endif /* BIND8_STATS */ @@ -3410,9 +3473,9 @@ service_remaining_tcp(struct nsd* nsd) #endif p->tcp_no_more_queries = 1; - /* set timeout to 1/10 second */ - if(p->tcp_timeout > 100) - p->tcp_timeout = 100; + /* set timeout to 3 seconds (previously 1/10 second) */ + if(p->tcp_timeout > 3000) + p->tcp_timeout = 3000; timeout.tv_sec = p->tcp_timeout / 1000; timeout.tv_usec = (p->tcp_timeout % 1000)*1000; event_del(&p->event); @@ -3437,8 +3500,8 @@ service_remaining_tcp(struct nsd* nsd) break; } /* timer */ - /* have to do something every second */ - tv.tv_sec = 1; + /* have to do something every 3 seconds */ + tv.tv_sec = 3; tv.tv_usec = 0; memset(&timeout, 0, sizeof(timeout)); event_set(&timeout, -1, EV_TIMEOUT, remaining_tcp_timeout, @@ -3576,6 +3639,88 @@ port_is_zero( #endif } +/* Parses the PROXYv2 header from buf and updates the struct. + * Returns 1 on success, 0 on failure. */ +static int +consume_pp2_header(struct buffer* buf, struct query* q, int stream) +{ + size_t size; + struct pp2_header* header; + int err = pp2_read_header(buffer_begin(buf), buffer_remaining(buf)); + if(err) { + VERBOSITY(4, (LOG_ERR, "proxy-protocol: could not parse " + "PROXYv2 header: %s", pp_lookup_error(err))); + return 0; + } + header = (struct pp2_header*)buffer_begin(buf); + size = PP2_HEADER_SIZE + read_uint16(&header->len); + if(size > buffer_limit(buf)) { + VERBOSITY(4, (LOG_ERR, "proxy-protocol: not enough buffer " + "size to read PROXYv2 header")); + return 0; + } + if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) { + /* A connection from the proxy itself. + * No need to do anything with addresses. */ + goto done; + } + if(header->fam_prot == PP2_UNSPEC_UNSPEC) { + /* Unspecified family and protocol. This could be used for + * health checks by proxies. + * No need to do anything with addresses. */ + goto done; + } + /* Read the proxied address */ + switch(header->fam_prot) { + case PP2_INET_STREAM: + case PP2_INET_DGRAM: + { + struct sockaddr_in* addr = + (struct sockaddr_in*)&q->client_addr; + addr->sin_family = AF_INET; + memmove(&addr->sin_addr.s_addr, + &header->addr.addr4.src_addr, 4); + memmove(&addr->sin_port, &header->addr.addr4.src_port, + 2); + q->client_addrlen = (socklen_t)sizeof(struct sockaddr_in); + } + /* Ignore the destination address; it should be us. */ + break; +#ifdef INET6 + case PP2_INET6_STREAM: + case PP2_INET6_DGRAM: + { + struct sockaddr_in6* addr = + (struct sockaddr_in6*)&q->client_addr; + memset(addr, 0, sizeof(*addr)); + addr->sin6_family = AF_INET6; + memmove(&addr->sin6_addr, + header->addr.addr6.src_addr, 16); + memmove(&addr->sin6_port, &header->addr.addr6.src_port, + 2); + q->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6); + } + /* Ignore the destination address; it should be us. */ + break; +#endif /* INET6 */ + default: + VERBOSITY(2, (LOG_ERR, "proxy-protocol: unsupported " + "family and protocol 0x%x", + (int)header->fam_prot)); + return 0; + } + q->is_proxied = 1; +done: + if(!stream) { + /* We are reading a whole packet; + * Move the rest of the data to overwrite the PROXYv2 header */ + /* XXX can we do better to avoid memmove? */ + memmove(header, ((char*)header)+size, buffer_limit(buf)-size); + buffer_set_limit(buf, buffer_limit(buf)-size); + } + return 1; +} + static void handle_udp(int fd, short event, void* arg) { @@ -3602,7 +3747,9 @@ handle_udp(int fd, short event, void* arg) for (i = 0; i < recvcount; i++) { loopstart: received = msgs[i].msg_len; - queries[i]->addrlen = msgs[i].msg_hdr.msg_namelen; + queries[i]->remote_addrlen = msgs[i].msg_hdr.msg_namelen; + queries[i]->client_addrlen = (socklen_t)sizeof(queries[i]->client_addr); + queries[i]->is_proxied = 0; q = queries[i]; if (received == -1) { log_msg(LOG_ERR, "recvmmsg %d failed %s", i, strerror( @@ -3616,7 +3763,7 @@ handle_udp(int fd, short event, void* arg) /* No zone statup */ query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); - msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; + msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; goto swap_drop; } @@ -3631,13 +3778,25 @@ handle_udp(int fd, short event, void* arg) buffer_skip(q->packet, received); buffer_flip(q->packet); + if(data->pp2_enabled && !consume_pp2_header(q->packet, q, 0)) { + VERBOSITY(2, (LOG_ERR, "proxy-protocol: could not " + "consume PROXYv2 header")); + goto swap_drop; + } + if(!q->is_proxied) { + q->client_addrlen = q->remote_addrlen; + memmove(&q->client_addr, &q->remote_addr, + q->remote_addrlen); + } #ifdef USE_DNSTAP /* * sending UDP-query with server address (local) and client address to dnstap process */ - log_addr("query from client", &q->addr); + log_addr("query from client", &q->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); - dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &q->addr, q->addrlen, + if(verbosity >= 6 && q->is_proxied) + log_addr("query via proxy", &q->remote_addr); + dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &q->client_addr, q->client_addrlen, q->tcp, q->packet); #endif /* USE_DNSTAP */ @@ -3675,15 +3834,17 @@ handle_udp(int fd, short event, void* arg) * sending UDP-response with server address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); - log_addr("response to client", &q->addr); + log_addr("response to client", &q->client_addr); + if(verbosity >= 6 && q->is_proxied) + log_addr("response via proxy", &q->remote_addr); dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, - &q->addr, q->addrlen, q->tcp, q->packet, + &q->client_addr, q->client_addrlen, q->tcp, q->packet, q->zone); #endif /* USE_DNSTAP */ } else { query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(q->packet); - msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; + msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; swap_drop: STATUP(data->nsd, dropped); ZTATUP(data->nsd, q->zone, dropped); @@ -3738,11 +3899,11 @@ handle_udp(int fd, short event, void* arg) if(errno == EINVAL) { /* skip the invalid argument entry, * send the remaining packets in the list */ - if(!(port_is_zero((void*)&queries[i]->addr) && + if(!(port_is_zero((void*)&queries[i]->remote_addr) && verbosity < 3)) { const char* es = strerror(errno); char a[64]; - addrport2str((void*)&queries[i]->addr, a, sizeof(a)); + addrport2str((void*)&queries[i]->remote_addr, a, sizeof(a)); log_msg(LOG_ERR, "sendmmsg skip invalid argument [0]=%s count=%d failed: %s", a, (int)(recvcount-i), es); } i += 1; @@ -3757,11 +3918,11 @@ handle_udp(int fd, short event, void* arg) errno != EAGAIN) { const char* es = strerror(errno); char a[64]; - addrport2str((void*)&queries[i]->addr, a, sizeof(a)); + addrport2str((void*)&queries[i]->remote_addr, a, sizeof(a)); log_msg(LOG_ERR, "sendmmsg [0]=%s count=%d failed: %s", a, (int)(recvcount-i), es); } #ifdef BIND8_STATS - data->nsd->st.txerr += recvcount-i; + data->nsd->st->txerr += recvcount-i; #endif /* BIND8_STATS */ break; } @@ -3770,7 +3931,7 @@ handle_udp(int fd, short event, void* arg) for(i=0; i<recvcount; i++) { query_reset(queries[i], UDP_MAX_MESSAGE_LEN, 0); iovecs[i].iov_len = buffer_remaining(queries[i]->packet); - msgs[i].msg_hdr.msg_namelen = queries[i]->addrlen; + msgs[i].msg_hdr.msg_namelen = queries[i]->remote_addrlen; } } @@ -3810,6 +3971,7 @@ cleanup_tcp_handler(struct tcp_handler_data* data) data->tls = NULL; } #endif + data->pp2_header_state = pp2_header_none; close(data->event.ev_fd); if(data->prev) data->prev->next = data->next; @@ -3835,6 +3997,39 @@ cleanup_tcp_handler(struct tcp_handler_data* data) region_destroy(data->region); } +/* Read more data into the buffer for tcp read. Pass the amount of additional + * data required. Returns false if nothing needs to be done this event, or + * true if the additional data is in the buffer. */ +static int +more_read_buf_tcp(int fd, struct tcp_handler_data* data, void* bufpos, + size_t add_amount, ssize_t* received) +{ + *received = read(fd, bufpos, add_amount); + if (*received == -1) { + if (errno == EAGAIN || errno == EINTR) { + /* + * Read would block, wait until more + * data is available. + */ + return 0; + } else { + char buf[48]; + addr2str(&data->query->remote_addr, buf, sizeof(buf)); +#ifdef ECONNRESET + if (verbosity >= 2 || errno != ECONNRESET) +#endif /* ECONNRESET */ + log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); + cleanup_tcp_handler(data); + return 0; + } + } else if (*received == 0) { + /* EOF */ + cleanup_tcp_handler(data); + return 0; + } + return 1; +} + static void handle_tcp_reading(int fd, short event, void* arg) { @@ -3851,8 +4046,9 @@ handle_tcp_reading(int fd, short event, void* arg) } if ((data->nsd->tcp_query_count > 0 && - data->query_count >= data->nsd->tcp_query_count) || - data->tcp_no_more_queries) { + data->query_count >= data->nsd->tcp_query_count) || + (data->query_count > 0 && data->tcp_no_more_queries)) + { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(data); return; @@ -3860,41 +4056,102 @@ handle_tcp_reading(int fd, short event, void* arg) assert((event & EV_READ)); - if (data->bytes_transmitted == 0) { + if (data->bytes_transmitted == 0 && data->query_needs_reset) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); - } - - /* - * Check if we received the leading packet length bytes yet. - */ - if (data->bytes_transmitted < sizeof(uint16_t)) { - received = read(fd, - (char *) &data->query->tcplen - + data->bytes_transmitted, - sizeof(uint16_t) - data->bytes_transmitted); - if (received == -1) { - if (errno == EAGAIN || errno == EINTR) { - /* - * Read would block, wait until more - * data is available. - */ + data->query_needs_reset = 0; + } + + if(data->pp2_enabled && data->pp2_header_state != pp2_header_done) { + struct pp2_header* header = NULL; + size_t want_read_size = 0; + size_t current_read_size = 0; + if(data->pp2_header_state == pp2_header_none) { + want_read_size = PP2_HEADER_SIZE; + if(buffer_remaining(data->query->packet) < + want_read_size) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); + cleanup_tcp_handler(data); return; - } else { - char buf[48]; - addr2str(&data->query->addr, buf, sizeof(buf)); -#ifdef ECONNRESET - if (verbosity >= 2 || errno != ECONNRESET) -#endif /* ECONNRESET */ - log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); + } + VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading fixed part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); + current_read_size = want_read_size; + if(data->bytes_transmitted < current_read_size) { + if(!more_read_buf_tcp(fd, data, + (void*)buffer_at(data->query->packet, + data->bytes_transmitted), + current_read_size - data->bytes_transmitted, + &received)) + return; + data->bytes_transmitted += received; + buffer_skip(data->query->packet, received); + if(data->bytes_transmitted != current_read_size) + return; + data->pp2_header_state = pp2_header_init; + } + } + if(data->pp2_header_state == pp2_header_init) { + int err; + err = pp2_read_header(buffer_begin(data->query->packet), + buffer_limit(data->query->packet)); + if(err) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not parse PROXYv2 header: %s", pp_lookup_error(err))); cleanup_tcp_handler(data); return; } - } else if (received == 0) { - /* EOF */ + header = (struct pp2_header*)buffer_begin(data->query->packet); + want_read_size = ntohs(header->len); + if(buffer_limit(data->query->packet) < + PP2_HEADER_SIZE + want_read_size) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); + cleanup_tcp_handler(data); + return; + } + VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading variable part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); + current_read_size = PP2_HEADER_SIZE + want_read_size; + if(want_read_size == 0) { + /* nothing more to read; header is complete */ + data->pp2_header_state = pp2_header_done; + } else if(data->bytes_transmitted < current_read_size) { + if(!more_read_buf_tcp(fd, data, + (void*)buffer_at(data->query->packet, + data->bytes_transmitted), + current_read_size - data->bytes_transmitted, + &received)) + return; + data->bytes_transmitted += received; + buffer_skip(data->query->packet, received); + if(data->bytes_transmitted != current_read_size) + return; + data->pp2_header_state = pp2_header_done; + } + } + if(data->pp2_header_state != pp2_header_done || !header) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: wrong state for the PROXYv2 header")); + + cleanup_tcp_handler(data); + return; + } + buffer_flip(data->query->packet); + if(!consume_pp2_header(data->query->packet, data->query, 1)) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not consume PROXYv2 header")); + cleanup_tcp_handler(data); return; } + /* Clear and reset the buffer to read the following + * DNS packet(s). */ + buffer_clear(data->query->packet); + data->bytes_transmitted = 0; + } + /* + * Check if we received the leading packet length bytes yet. + */ + if (data->bytes_transmitted < sizeof(uint16_t)) { + if(!more_read_buf_tcp(fd, data, + (char*) &data->query->tcplen + data->bytes_transmitted, + sizeof(uint16_t) - data->bytes_transmitted, &received)) + return; data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* @@ -3903,7 +4160,6 @@ handle_tcp_reading(int fd, short event, void* arg) */ return; } - assert(data->bytes_transmitted == sizeof(uint16_t)); data->query->tcplen = ntohs(data->query->tcplen); @@ -3934,32 +4190,9 @@ handle_tcp_reading(int fd, short event, void* arg) assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ - received = read(fd, - buffer_current(data->query->packet), - buffer_remaining(data->query->packet)); - if (received == -1) { - if (errno == EAGAIN || errno == EINTR) { - /* - * Read would block, wait until more data is - * available. - */ - return; - } else { - char buf[48]; - addr2str(&data->query->addr, buf, sizeof(buf)); -#ifdef ECONNRESET - if (verbosity >= 2 || errno != ECONNRESET) -#endif /* ECONNRESET */ - log_msg(LOG_ERR, "failed reading from %s tcp: %s", buf, strerror(errno)); - cleanup_tcp_handler(data); - return; - } - } else if (received == 0) { - /* EOF */ - cleanup_tcp_handler(data); + if(!more_read_buf_tcp(fd, data, buffer_current(data->query->packet), + buffer_remaining(data->query->packet), &received)) return; - } - data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { @@ -3977,9 +4210,9 @@ handle_tcp_reading(int fd, short event, void* arg) #ifndef INET6 STATUP(data->nsd, ctcp); #else - if (data->query->addr.ss_family == AF_INET) { + if (data->query->remote_addr.ss_family == AF_INET) { STATUP(data->nsd, ctcp); - } else if (data->query->addr.ss_family == AF_INET6) { + } else if (data->query->remote_addr.ss_family == AF_INET6) { STATUP(data->nsd, ctcp6); } #endif @@ -3995,10 +4228,12 @@ handle_tcp_reading(int fd, short event, void* arg) /* * and send TCP-query with found address (local) and client address to dnstap process */ - log_addr("query from client", &data->query->addr); + log_addr("query from client", &data->query->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); - dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->addr, - data->query->addrlen, data->query->tcp, data->query->packet); + if(verbosity >= 6 && data->query->is_proxied) + log_addr("query via proxy", &data->query->remote_addr); + dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, + data->query->client_addrlen, data->query->tcp, data->query->packet); #endif /* USE_DNSTAP */ data->query_state = server_process_query(data->nsd, data->query, &now); if (data->query_state == QUERY_DISCARDED) { @@ -4022,9 +4257,9 @@ handle_tcp_reading(int fd, short event, void* arg) #ifndef INET6 ZTATUP(data->nsd, data->query->zone, ctcp); #else - if (data->query->addr.ss_family == AF_INET) { + if (data->query->remote_addr.ss_family == AF_INET) { ZTATUP(data->nsd, data->query->zone, ctcp); - } else if (data->query->addr.ss_family == AF_INET6) { + } else if (data->query->remote_addr.ss_family == AF_INET6) { ZTATUP(data->nsd, data->query->zone, ctcp6); } #endif @@ -4049,9 +4284,11 @@ handle_tcp_reading(int fd, short event, void* arg) * sending TCP-response with found (earlier) address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); - log_addr("response to client", &data->query->addr); - dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->addr, - data->query->addrlen, data->query->tcp, data->query->packet, + log_addr("response to client", &data->query->client_addr); + if(verbosity >= 6 && data->query->is_proxied) + log_addr("response via proxy", &data->query->remote_addr); + dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, + data->query->client_addrlen, data->query->tcp, data->query->packet, data->query->zone); #endif /* USE_DNSTAP */ data->bytes_transmitted = 0; @@ -4062,8 +4299,8 @@ handle_tcp_reading(int fd, short event, void* arg) ev_base = data->event.ev_base; event_del(&data->event); memset(&data->event, 0, sizeof(data->event)); - event_set(&data->event, fd, EV_PERSIST | EV_READ | EV_TIMEOUT, - handle_tcp_reading, data); + event_set(&data->event, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT, + handle_tcp_writing, data); if(event_base_set(ev_base, &data->event) != 0) log_msg(LOG_ERR, "event base set tcpr failed"); if(event_add(&data->event, &timeout) != 0) @@ -4226,6 +4463,7 @@ handle_tcp_writing(int fd, short event, void* arg) } data->bytes_transmitted = 0; + data->query_needs_reset = 1; timeout.tv_sec = data->tcp_timeout / 1000; timeout.tv_usec = (data->tcp_timeout % 1000)*1000; @@ -4309,7 +4547,7 @@ tls_handshake(struct tcp_handler_data* data, int fd, int writing) unsigned long err = ERR_get_error(); if(!squelch_err_ssl_handshake(err)) { char a[64], s[256]; - addr2str(&data->query->addr, a, sizeof(a)); + addr2str(&data->query->remote_addr, a, sizeof(a)); snprintf(s, sizeof(s), "TLS handshake failed from %s", a); log_crypto_from_err(s, err); } @@ -4331,6 +4569,36 @@ tls_handshake(struct tcp_handler_data* data, int fd, int writing) return 1; } +/* Read more data into the buffer for tls read. Pass the amount of additional + * data required. Returns false if nothing needs to be done this event, or + * true if the additional data is in the buffer. */ +static int +more_read_buf_tls(int fd, struct tcp_handler_data* data, void* bufpos, + size_t add_amount, ssize_t* received) +{ + ERR_clear_error(); + if((*received=SSL_read(data->tls, bufpos, add_amount)) <= 0) { + int want = SSL_get_error(data->tls, *received); + if(want == SSL_ERROR_ZERO_RETURN) { + cleanup_tcp_handler(data); + return 0; /* shutdown, closed */ + } else if(want == SSL_ERROR_WANT_READ) { + /* wants to be called again */ + return 0; + } + else if(want == SSL_ERROR_WANT_WRITE) { + /* switch to writing */ + data->shake_state = tls_hs_write_event; + tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); + return 0; + } + cleanup_tcp_handler(data); + log_crypto_err("could not SSL_read"); + return 0; + } + return 1; +} + /** handle TLS reading of incoming query */ static void handle_tls_reading(int fd, short event, void* arg) @@ -4346,8 +4614,9 @@ handle_tls_reading(int fd, short event, void* arg) } if ((data->nsd->tcp_query_count > 0 && - data->query_count >= data->nsd->tcp_query_count) || - data->tcp_no_more_queries) { + data->query_count >= data->nsd->tcp_query_count) || + (data->query_count > 0 && data->tcp_no_more_queries)) + { /* No more queries allowed on this tcp connection. */ cleanup_tcp_handler(data); return; @@ -4355,8 +4624,9 @@ handle_tls_reading(int fd, short event, void* arg) assert((event & EV_READ)); - if (data->bytes_transmitted == 0) { + if (data->bytes_transmitted == 0 && data->query_needs_reset) { query_reset(data->query, TCP_MAX_MESSAGE_LEN, 1); + data->query_needs_reset = 0; } if(data->shake_state != tls_hs_none) { @@ -4366,33 +4636,94 @@ handle_tls_reading(int fd, short event, void* arg) return; } - /* - * Check if we received the leading packet length bytes yet. - */ - if(data->bytes_transmitted < sizeof(uint16_t)) { - ERR_clear_error(); - if((received=SSL_read(data->tls, (char *) &data->query->tcplen - + data->bytes_transmitted, - sizeof(uint16_t) - data->bytes_transmitted)) <= 0) { - int want = SSL_get_error(data->tls, received); - if(want == SSL_ERROR_ZERO_RETURN) { + if(data->pp2_enabled && data->pp2_header_state != pp2_header_done) { + struct pp2_header* header = NULL; + size_t want_read_size = 0; + size_t current_read_size = 0; + if(data->pp2_header_state == pp2_header_none) { + want_read_size = PP2_HEADER_SIZE; + if(buffer_remaining(data->query->packet) < + want_read_size) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); cleanup_tcp_handler(data); - return; /* shutdown, closed */ - } else if(want == SSL_ERROR_WANT_READ) { - /* wants to be called again */ return; } - else if(want == SSL_ERROR_WANT_WRITE) { - /* switch to writing */ - data->shake_state = tls_hs_write_event; - tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); + VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading fixed part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); + current_read_size = want_read_size; + if(data->bytes_transmitted < current_read_size) { + if(!more_read_buf_tls(fd, data, + buffer_at(data->query->packet, + data->bytes_transmitted), + current_read_size - data->bytes_transmitted, + &received)) + return; + data->bytes_transmitted += received; + buffer_skip(data->query->packet, received); + if(data->bytes_transmitted != current_read_size) + return; + data->pp2_header_state = pp2_header_init; + } + } + if(data->pp2_header_state == pp2_header_init) { + int err; + err = pp2_read_header(buffer_begin(data->query->packet), + buffer_limit(data->query->packet)); + if(err) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not parse PROXYv2 header: %s", pp_lookup_error(err))); + cleanup_tcp_handler(data); return; } + header = (struct pp2_header*)buffer_begin(data->query->packet); + want_read_size = ntohs(header->len); + if(buffer_limit(data->query->packet) < + PP2_HEADER_SIZE + want_read_size) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: not enough buffer size to read PROXYv2 header")); + cleanup_tcp_handler(data); + return; + } + VERBOSITY(6, (LOG_INFO, "proxy-protocol: reading variable part of PROXYv2 header (len %lu)", (unsigned long)want_read_size)); + current_read_size = PP2_HEADER_SIZE + want_read_size; + if(want_read_size == 0) { + /* nothing more to read; header is complete */ + data->pp2_header_state = pp2_header_done; + } else if(data->bytes_transmitted < current_read_size) { + if(!more_read_buf_tls(fd, data, + buffer_at(data->query->packet, + data->bytes_transmitted), + current_read_size - data->bytes_transmitted, + &received)) + return; + data->bytes_transmitted += received; + buffer_skip(data->query->packet, received); + if(data->bytes_transmitted != current_read_size) + return; + data->pp2_header_state = pp2_header_done; + } + } + if(data->pp2_header_state != pp2_header_done || !header) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: wrong state for the PROXYv2 header")); cleanup_tcp_handler(data); - log_crypto_err("could not SSL_read"); return; } - + buffer_flip(data->query->packet); + if(!consume_pp2_header(data->query->packet, data->query, 1)) { + VERBOSITY(6, (LOG_ERR, "proxy-protocol: could not consume PROXYv2 header")); + cleanup_tcp_handler(data); + return; + } + /* Clear and reset the buffer to read the following + * DNS packet(s). */ + buffer_clear(data->query->packet); + data->bytes_transmitted = 0; + } + /* + * Check if we received the leading packet length bytes yet. + */ + if(data->bytes_transmitted < sizeof(uint16_t)) { + if(!more_read_buf_tls(fd, data, + (char *) &data->query->tcplen + data->bytes_transmitted, + sizeof(uint16_t) - data->bytes_transmitted, &received)) + return; data->bytes_transmitted += received; if (data->bytes_transmitted < sizeof(uint16_t)) { /* @@ -4432,29 +4763,9 @@ handle_tls_reading(int fd, short event, void* arg) assert(buffer_remaining(data->query->packet) > 0); /* Read the (remaining) query data. */ - ERR_clear_error(); - received = SSL_read(data->tls, (void*)buffer_current(data->query->packet), - (int)buffer_remaining(data->query->packet)); - if(received <= 0) { - int want = SSL_get_error(data->tls, received); - if(want == SSL_ERROR_ZERO_RETURN) { - cleanup_tcp_handler(data); - return; /* shutdown, closed */ - } else if(want == SSL_ERROR_WANT_READ) { - /* wants to be called again */ - return; - } - else if(want == SSL_ERROR_WANT_WRITE) { - /* switch back writing */ - data->shake_state = tls_hs_write_event; - tcp_handler_setup_event(data, handle_tls_writing, fd, EV_PERSIST | EV_WRITE | EV_TIMEOUT); - return; - } - cleanup_tcp_handler(data); - log_crypto_err("could not SSL_read"); + if(!more_read_buf_tls(fd, data, buffer_current(data->query->packet), + buffer_remaining(data->query->packet), &received)) return; - } - data->bytes_transmitted += received; buffer_skip(data->query->packet, received); if (buffer_remaining(data->query->packet) > 0) { @@ -4471,9 +4782,9 @@ handle_tls_reading(int fd, short event, void* arg) #ifndef INET6 STATUP(data->nsd, ctls); #else - if (data->query->addr.ss_family == AF_INET) { + if (data->query->remote_addr.ss_family == AF_INET) { STATUP(data->nsd, ctls); - } else if (data->query->addr.ss_family == AF_INET6) { + } else if (data->query->remote_addr.ss_family == AF_INET6) { STATUP(data->nsd, ctls6); } #endif @@ -4488,10 +4799,12 @@ handle_tls_reading(int fd, short event, void* arg) /* * and send TCP-query with found address (local) and client address to dnstap process */ - log_addr("query from client", &data->query->addr); + log_addr("query from client", &data->query->client_addr); log_addr("to server (local)", (void*)&data->socket->addr.ai_addr); - dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->addr, - data->query->addrlen, data->query->tcp, data->query->packet); + if(verbosity >= 6 && data->query->is_proxied) + log_addr("query via proxy", &data->query->remote_addr); + dt_collector_submit_auth_query(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, + data->query->client_addrlen, data->query->tcp, data->query->packet); #endif /* USE_DNSTAP */ data->query_state = server_process_query(data->nsd, data->query, &now); if (data->query_state == QUERY_DISCARDED) { @@ -4515,9 +4828,9 @@ handle_tls_reading(int fd, short event, void* arg) #ifndef INET6 ZTATUP(data->nsd, data->query->zone, ctls); #else - if (data->query->addr.ss_family == AF_INET) { + if (data->query->remote_addr.ss_family == AF_INET) { ZTATUP(data->nsd, data->query->zone, ctls); - } else if (data->query->addr.ss_family == AF_INET6) { + } else if (data->query->remote_addr.ss_family == AF_INET6) { ZTATUP(data->nsd, data->query->zone, ctls6); } #endif @@ -4542,9 +4855,11 @@ handle_tls_reading(int fd, short event, void* arg) * sending TCP-response with found (earlier) address (local) and client address to dnstap process */ log_addr("from server (local)", (void*)&data->socket->addr.ai_addr); - log_addr("response to client", &data->query->addr); - dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->addr, - data->query->addrlen, data->query->tcp, data->query->packet, + log_addr("response to client", &data->query->client_addr); + if(verbosity >= 6 && data->query->is_proxied) + log_addr("response via proxy", &data->query->remote_addr); + dt_collector_submit_auth_response(data->nsd, (void*)&data->socket->addr.ai_addr, &data->query->client_addr, + data->query->client_addrlen, data->query->tcp, data->query->packet, data->query->zone); #endif /* USE_DNSTAP */ data->bytes_transmitted = 0; @@ -4683,6 +4998,7 @@ handle_tls_writing(int fd, short event, void* arg) } data->bytes_transmitted = 0; + data->query_needs_reset = 1; tcp_handler_setup_event(data, handle_tls_reading, fd, EV_PERSIST | EV_READ | EV_TIMEOUT); } @@ -4814,13 +5130,21 @@ handle_tcp_accept(int fd, short event, void* arg) tcp_data->shake_state = tls_hs_none; tcp_data->tls = NULL; #endif + tcp_data->query_needs_reset = 1; + tcp_data->pp2_enabled = data->pp2_enabled; + tcp_data->pp2_header_state = pp2_header_none; tcp_data->prev = NULL; tcp_data->next = NULL; tcp_data->query_state = QUERY_PROCESSED; tcp_data->bytes_transmitted = 0; - memcpy(&tcp_data->query->addr, &addr, addrlen); - tcp_data->query->addrlen = addrlen; + memcpy(&tcp_data->query->remote_addr, &addr, addrlen); + tcp_data->query->remote_addrlen = addrlen; + /* Copy remote_address to client_address. + * Simplest way/time for streams to do that. */ + memcpy(&tcp_data->query->client_addr, &addr, addrlen); + tcp_data->query->client_addrlen = addrlen; + tcp_data->query->is_proxied = 0; tcp_data->tcp_no_more_queries = 0; tcp_data->tcp_timeout = data->nsd->tcp_timeout * 1000; diff --git a/usr.sbin/nsd/udb.h b/usr.sbin/nsd/udb.h index b3f495d9b38..dcca36754b1 100644 --- a/usr.sbin/nsd/udb.h +++ b/usr.sbin/nsd/udb.h @@ -218,14 +218,6 @@ typedef enum udb_chunk_type udb_chunk_type; enum udb_chunk_type { udb_chunk_type_free = 0, udb_chunk_type_data, /* alloced data */ - udb_chunk_type_index, - udb_chunk_type_radtree, - udb_chunk_type_radnode, - udb_chunk_type_radarray, - udb_chunk_type_zone, - udb_chunk_type_domain, - udb_chunk_type_rrset, - udb_chunk_type_rr, udb_chunk_type_task, udb_chunk_type_internal }; diff --git a/usr.sbin/nsd/udbradtree.c b/usr.sbin/nsd/udbradtree.c deleted file mode 100644 index 5de16c7bb42..00000000000 --- a/usr.sbin/nsd/udbradtree.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* - * udbradtree -- radix tree for binary strings for in udb file. - * - * Copyright (c) 2011, NLnet Labs. See LICENSE for license. - */ -#include "config.h" -#include <string.h> -#include <assert.h> -#include <stdio.h> -#include "udbradtree.h" -#include "radtree.h" -#define RADARRAY(ptr) ((struct udb_radarray_d*)UDB_PTR(ptr)) - -/** see if radarray can be reduced (by a factor of two) */ -static int udb_radarray_reduce_if_needed(udb_base* udb, udb_ptr* n); - -int udb_radix_tree_create(udb_base* udb, udb_ptr* ptr) -{ - if(!udb_ptr_alloc_space(ptr, udb, udb_chunk_type_radtree, - sizeof(struct udb_radtree_d))) - return 0; - udb_rel_ptr_init(&RADTREE(ptr)->root); - RADTREE(ptr)->count = 0; - return 1; -} - -/** size of radarray */ -static size_t size_of_radarray(struct udb_radarray_d* a) -{ - return sizeof(struct udb_radarray_d)+((size_t)a->capacity)*( - sizeof(struct udb_radsel_d)+(size_t)a->str_cap); -} - -/** size in bytes of data in the array lookup structure */ -static size_t size_of_lookup(udb_ptr* node) -{ - assert(udb_ptr_get_type(node) == udb_chunk_type_radnode); - return size_of_radarray((struct udb_radarray_d*)UDB_REL(*node->base, - RADNODE(node)->lookup.data)); -} - -/** external variant, size in bytes of data in the array lookup structure */ -size_t size_of_lookup_ext(udb_ptr* lookup) -{ - return size_of_lookup(lookup); -} - -/** size needed for a lookup array like this */ -static size_t size_of_lookup_needed(uint16_t capacity, - udb_radstrlen_type str_cap) -{ - return sizeof(struct udb_radarray_d)+ ((size_t)capacity)*( - sizeof(struct udb_radsel_d)+(size_t)str_cap); -} - -/** get the lookup array for a node */ -static struct udb_radarray_d* lookup(udb_ptr* n) -{ - assert(udb_ptr_get_type(n) == udb_chunk_type_radnode); - return (struct udb_radarray_d*)UDB_REL(*n->base, - RADNODE(n)->lookup.data); -} - -/** get a length in the lookup array */ -static udb_radstrlen_type lookup_len(udb_ptr* n, unsigned i) -{ - return lookup(n)->array[i].len; -} - -/** get a string in the lookup array */ -static uint8_t* lookup_string(udb_ptr* n, unsigned i) -{ - return ((uint8_t*)&(lookup(n)->array[lookup(n)->capacity]))+ - i*lookup(n)->str_cap; -} - -/** get a node in the lookup array */ -static struct udb_radnode_d* lookup_node(udb_ptr* n, unsigned i) -{ - return (struct udb_radnode_d*)UDB_REL(*n->base, - lookup(n)->array[i].node.data); -} - -/** zero the relptrs in radarray */ -static void udb_radarray_zero_ptrs(udb_base* udb, udb_ptr* n) -{ - unsigned i; - for(i=0; i<lookup(n)->len; i++) { - udb_rptr_zero(&lookup(n)->array[i].node, udb); - } -} - -/** delete a radnode */ -static void udb_radnode_delete(udb_base* udb, udb_ptr* n) -{ - if(udb_ptr_is_null(n)) - return; - if(RADNODE(n)->lookup.data) { - udb_radarray_zero_ptrs(udb, n); - udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, - size_of_lookup(n)); - } - udb_rptr_zero(&RADNODE(n)->lookup, udb); - udb_rptr_zero(&RADNODE(n)->parent, udb); - udb_rptr_zero(&RADNODE(n)->elem, udb); - udb_ptr_free_space(n, udb, sizeof(struct udb_radnode_d)); -} - -/** delete radnodes in postorder recursion, n is ptr to node */ -static void udb_radnode_del_postorder(udb_base* udb, udb_ptr* n) -{ - unsigned i; - udb_ptr sub; - if(udb_ptr_is_null(n)) - return; - /* clear subnodes */ - udb_ptr_init(&sub, udb); - for(i=0; i<lookup(n)->len; i++) { - udb_ptr_set_rptr(&sub, udb, &lookup(n)->array[i].node); - udb_rptr_zero(&lookup(n)->array[i].node, udb); - udb_radnode_del_postorder(udb, &sub); - } - udb_ptr_unlink(&sub, udb); - /* clear lookup */ - udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); - udb_rptr_zero(&RADNODE(n)->parent, udb); - udb_rptr_zero(&RADNODE(n)->elem, udb); - udb_ptr_free_space(n, udb, sizeof(struct udb_radnode_d)); -} - -void udb_radix_tree_clear(udb_base* udb, udb_ptr* rt) -{ - udb_ptr root; - udb_ptr_new(&root, udb, &RADTREE(rt)->root); - udb_rptr_zero(&RADTREE(rt)->root, udb); - /* free the root node (and its descendants, if any) */ - udb_radnode_del_postorder(udb, &root); - udb_ptr_unlink(&root, udb); - - RADTREE(rt)->count = 0; -} - -void udb_radix_tree_delete(udb_base* udb, udb_ptr* rt) -{ - if(rt->data == 0) return; - assert(udb_ptr_get_type(rt) == udb_chunk_type_radtree); - udb_radix_tree_clear(udb, rt); - udb_ptr_free_space(rt, udb, sizeof(struct udb_radtree_d)); -} - -/** - * Find a prefix of the key, in whole-nodes. - * Finds the longest prefix that corresponds to a whole radnode entry. - * There may be a slightly longer prefix in one of the array elements. - * @param result: the longest prefix, the entry itself if *respos==len, - * otherwise an array entry, residx. Output. - * @param respos: pos in string where next unmatched byte is, if == len an - * exact match has been found. If == 0 then a "" match was found. - * @return false if no prefix found, not even the root "" prefix. - */ -static int udb_radix_find_prefix_node(udb_base* udb, udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len, udb_ptr* result, udb_radstrlen_type* respos) -{ - udb_radstrlen_type pos = 0; - uint8_t byte; - udb_ptr n; - udb_ptr_new(&n, udb, &RADTREE(rt)->root); - - *respos = 0; - udb_ptr_set_ptr(result, udb, &n); - if(udb_ptr_is_null(&n)) { - udb_ptr_unlink(&n, udb); - return 0; - } - while(!udb_ptr_is_null(&n)) { - if(pos == len) { - break; - } - byte = k[pos]; - if(byte < RADNODE(&n)->offset) { - break; - } - byte -= RADNODE(&n)->offset; - if(byte >= lookup(&n)->len) { - break; - } - pos++; - if(lookup(&n)->array[byte].len != 0) { - /* must match additional string */ - if(pos+lookup(&n)->array[byte].len > len) { - break; - } - if(memcmp(&k[pos], lookup_string(&n, byte), - lookup(&n)->array[byte].len) != 0) { - break; - } - pos += lookup(&n)->array[byte].len; - } - udb_ptr_set_rptr(&n, udb, &lookup(&n)->array[byte].node); - if(udb_ptr_is_null(&n)) { - break; - } - *respos = pos; - udb_ptr_set_ptr(result, udb, &n); - } - udb_ptr_unlink(&n, udb); - return 1; -} - -/** grow the radnode stringcapacity, copy existing elements */ -static int udb_radnode_str_grow(udb_base* udb, udb_ptr* n, - udb_radstrlen_type want) -{ - unsigned ns = ((unsigned)lookup(n)->str_cap)*2; - unsigned i; - udb_ptr a; - if(want > ns) - ns = want; - if(ns > 65535) ns = 65535; /* MAX of udb_radstrlen_type range */ - /* if this fails, the tree is still usable */ - if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, - size_of_lookup_needed(lookup(n)->capacity, ns))) - return 0; - /* make sure to zero the newly allocated relptrs to init them */ - memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); - RADARRAY(&a)->str_cap = ns; - for(i = 0; i < lookup(n)->len; i++) { - udb_rel_ptr_init(&RADARRAY(&a)->array[i].node); - udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, - &lookup(n)->array[i].node); - RADARRAY(&a)->array[i].len = lookup_len(n, i); - memmove(((uint8_t*)(&RADARRAY(&a)->array[ - lookup(n)->capacity]))+i*ns, - lookup_string(n, i), lookup(n)->str_cap); - } - udb_radarray_zero_ptrs(udb, n); - udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); - udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); - udb_ptr_unlink(&a, udb); - return 1; -} - -/** grow the radnode array, copy existing elements to start of new array */ -static int udb_radnode_array_grow(udb_base* udb, udb_ptr* n, size_t want) -{ - unsigned i; - unsigned ns = ((unsigned)lookup(n)->capacity)*2; - udb_ptr a; - assert(want <= 256); /* cannot be more, range of uint8 */ - if(want > ns) - ns = want; - if(ns > 256) ns = 256; - /* if this fails, the tree is still usable */ - if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, - size_of_lookup_needed(ns, lookup(n)->str_cap))) - return 0; - /* zero the newly allocated rel ptrs to init them */ - memset(UDB_PTR(&a), 0, size_of_lookup_needed(ns, lookup(n)->str_cap)); - assert(lookup(n)->len <= lookup(n)->capacity); - assert(lookup(n)->capacity < ns); - memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); - RADARRAY(&a)->capacity = ns; - for(i=0; i<lookup(n)->len; i++) { - udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, - &lookup(n)->array[i].node); - RADARRAY(&a)->array[i].len = lookup_len(n, i); - } - memmove(&RADARRAY(&a)->array[ns], lookup_string(n, 0), - ((size_t)lookup(n)->len) * ((size_t)lookup(n)->str_cap)); - udb_radarray_zero_ptrs(udb, n); - udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); - udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); - udb_ptr_unlink(&a, udb); - return 1; -} - -/** make empty array in radnode */ -static int udb_radnode_array_create(udb_base* udb, udb_ptr* n) -{ - /* is there an array? */ - if(RADNODE(n)->lookup.data == 0) { - /* create array */ - udb_ptr a; - uint16_t cap = 0; - udb_radstrlen_type len = 0; - if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, - size_of_lookup_needed(cap, len))) - return 0; - memset(UDB_PTR(&a), 0, size_of_lookup_needed(cap, len)); - udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); - RADARRAY(&a)->len = cap; - RADARRAY(&a)->capacity = cap; - RADARRAY(&a)->str_cap = len; - RADNODE(n)->offset = 0; - udb_ptr_unlink(&a, udb); - } - return 1; -} - -/** make space in radnode for another byte, or longer strings */ -static int udb_radnode_array_space(udb_base* udb, udb_ptr* n, uint8_t byte, - udb_radstrlen_type len) -{ - /* is there an array? */ - if(RADNODE(n)->lookup.data == 0) { - /* create array */ - udb_ptr a; - uint16_t cap = 1; - if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, - size_of_lookup_needed(cap, len))) - return 0; - /* this memset inits the relptr that is allocated */ - memset(UDB_PTR(&a), 0, size_of_lookup_needed(cap, len)); - udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); - RADARRAY(&a)->len = cap; - RADARRAY(&a)->capacity = cap; - RADARRAY(&a)->str_cap = len; - RADNODE(n)->offset = byte; - udb_ptr_unlink(&a, udb); - return 1; - } - if(lookup(n)->capacity == 0) { - if(!udb_radnode_array_grow(udb, n, 1)) - return 0; - } - - /* make space for this stringsize */ - if(lookup(n)->str_cap < len) { - /* must resize for stringsize */ - if(!udb_radnode_str_grow(udb, n, len)) - return 0; - } - - /* other cases */ - /* is the array unused? */ - if(lookup(n)->len == 0 && lookup(n)->capacity != 0) { - lookup(n)->len = 1; - RADNODE(n)->offset = byte; - memset(&lookup(n)->array[0], 0, sizeof(struct udb_radsel_d)); - /* is it below the offset? */ - } else if(byte < RADNODE(n)->offset) { - /* is capacity enough? */ - int i; - unsigned need = RADNODE(n)->offset-byte; - if(lookup(n)->len+need > lookup(n)->capacity) { - /* grow array */ - if(!udb_radnode_array_grow(udb, n, lookup(n)->len+need)) - return 0; - } - /* take a piece of capacity into use, init the relptrs */ - for(i = lookup(n)->len; i< (int)(lookup(n)->len + need); i++) { - udb_rel_ptr_init(&lookup(n)->array[i].node); - } - /* reshuffle items to end */ - for(i = lookup(n)->len-1; i >= 0; i--) { - udb_rptr_set_rptr(&lookup(n)->array[need+i].node, - udb, &lookup(n)->array[i].node); - lookup(n)->array[need+i].len = lookup_len(n, i); - /* fixup pidx */ - if(lookup(n)->array[i+need].node.data) - lookup_node(n, i+need)->pidx = i+need; - } - memmove(lookup_string(n, need), lookup_string(n, 0), - ((size_t)lookup(n)->len)*((size_t)lookup(n)->str_cap)); - /* zero the first */ - for(i = 0; i < (int)need; i++) { - udb_rptr_zero(&lookup(n)->array[i].node, udb); - lookup(n)->array[i].len = 0; - } - lookup(n)->len += need; - RADNODE(n)->offset = byte; - /* is it above the max? */ - } else if(byte - RADNODE(n)->offset >= lookup(n)->len) { - /* is capacity enough? */ - int i; - unsigned need = (byte-RADNODE(n)->offset) - lookup(n)->len + 1; - /* grow array */ - if(lookup(n)->len + need > lookup(n)->capacity) { - if(!udb_radnode_array_grow(udb, n, lookup(n)->len+need)) - return 0; - } - /* take new entries into use, init relptrs */ - for(i = lookup(n)->len; i< (int)(lookup(n)->len + need); i++) { - udb_rel_ptr_init(&lookup(n)->array[i].node); - lookup(n)->array[i].len = 0; - } - /* grow length */ - lookup(n)->len += need; - } - return 1; -} - -/** make space for string size */ -static int udb_radnode_str_space(udb_base* udb, udb_ptr* n, - udb_radstrlen_type len) -{ - if(RADNODE(n)->lookup.data == 0) { - return udb_radnode_array_space(udb, n, 0, len); - } - if(lookup(n)->str_cap < len) { - /* must resize for stringsize */ - if(!udb_radnode_str_grow(udb, n, len)) - return 0; - } - return 1; -} - -/** copy remainder from prefixes for a split: - * plen: len prefix, l: longer bstring, llen: length of l. */ -static void udb_radsel_prefix_remainder(udb_radstrlen_type plen, - uint8_t* l, udb_radstrlen_type llen, - uint8_t* s, udb_radstrlen_type* slen) -{ - *slen = llen - plen; - /* assert(*slen <= lookup(n)->str_cap); */ - memmove(s, l+plen, llen-plen); -} - -/** create a prefix in the array strs */ -static void udb_radsel_str_create(uint8_t* s, udb_radstrlen_type* slen, - uint8_t* k, udb_radstrlen_type pos, udb_radstrlen_type len) -{ - *slen = len-pos; - /* assert(*slen <= lookup(n)->str_cap); */ - memmove(s, k+pos, len-pos); -} - -static udb_radstrlen_type -udb_bstr_common(uint8_t* x, udb_radstrlen_type xlen, - uint8_t* y, udb_radstrlen_type ylen) -{ - assert(sizeof(radstrlen_type) == sizeof(udb_radstrlen_type)); - return bstr_common_ext(x, xlen, y, ylen); -} - -static int -udb_bstr_is_prefix(uint8_t* p, udb_radstrlen_type plen, - uint8_t* x, udb_radstrlen_type xlen) -{ - assert(sizeof(radstrlen_type) == sizeof(udb_radstrlen_type)); - return bstr_is_prefix_ext(p, plen, x, xlen); -} - -/** grow array space for byte N after a string, (but if string shorter) */ -static int -udb_radnode_array_space_strremain(udb_base* udb, udb_ptr* n, - uint8_t* str, udb_radstrlen_type len, udb_radstrlen_type pos) -{ - assert(pos < len); - /* shift by one char because it goes in lookup array */ - return udb_radnode_array_space(udb, n, str[pos], len-(pos+1)); -} - - -/** radsel create a split when two nodes have shared prefix. - * @param udb: udb - * @param n: node with the radsel that gets changed, it contains a node. - * @param idx: the index of the radsel that gets changed. - * @param k: key byte string - * @param pos: position where the string enters the radsel (e.g. r.str) - * @param len: length of k. - * @param add: additional node for the string k. - * removed by called on failure. - * @return false on alloc failure, no changes made. - */ -static int udb_radsel_split(udb_base* udb, udb_ptr* n, uint8_t idx, uint8_t* k, - udb_radstrlen_type pos, udb_radstrlen_type len, udb_ptr* add) -{ - uint8_t* addstr = k+pos; - udb_radstrlen_type addlen = len-pos; - if(udb_bstr_is_prefix(addstr, addlen, lookup_string(n, idx), - lookup_len(n, idx))) { - udb_radstrlen_type split_len = 0; - /* 'add' is a prefix of r.node */ - /* also for empty addstr */ - /* set it up so that the 'add' node has r.node as child */ - /* so, r.node gets moved below the 'add' node, but we do - * this so that the r.node stays the same pointer for its - * key name */ - assert(addlen != lookup_len(n, idx)); - assert(addlen < lookup_len(n, idx)); - /* make space for new string sizes */ - if(!udb_radnode_str_space(udb, n, addlen)) - return 0; - if(lookup_len(n, idx) - addlen > 1) - /* shift one because a char is in the lookup array */ - split_len = lookup_len(n, idx) - (addlen+1); - if(!udb_radnode_array_space(udb, add, - lookup_string(n, idx)[addlen], split_len)) - return 0; - /* alloc succeeded, now link it in */ - udb_rptr_set_rptr(&RADNODE(add)->parent, udb, - &lookup_node(n, idx)->parent); - RADNODE(add)->pidx = lookup_node(n, idx)->pidx; - udb_rptr_set_rptr(&lookup(add)->array[0].node, udb, - &lookup(n)->array[idx].node); - if(lookup_len(n, idx) - addlen > 1) { - udb_radsel_prefix_remainder(addlen+1, - lookup_string(n, idx), lookup_len(n, idx), - lookup_string(add, 0), - &lookup(add)->array[0].len); - } else { - lookup(add)->array[0].len = 0; - } - udb_rptr_set_ptr(&lookup_node(n, idx)->parent, udb, add); - lookup_node(n, idx)->pidx = 0; - - udb_rptr_set_ptr(&lookup(n)->array[idx].node, udb, add); - memmove(lookup_string(n, idx), addstr, addlen); - lookup(n)->array[idx].len = addlen; - /* n's string may have become shorter */ - if(!udb_radarray_reduce_if_needed(udb, n)) { - /* ignore this, our tree has become inefficient */ - } - } else if(udb_bstr_is_prefix(lookup_string(n, idx), lookup_len(n, idx), - addstr, addlen)) { - udb_radstrlen_type split_len = 0; - udb_ptr rnode; - /* r.node is a prefix of 'add' */ - /* set it up so that the 'r.node' has 'add' as child */ - /* and basically, r.node is already completely fine, - * we only need to create a node as its child */ - assert(addlen != lookup_len(n, idx)); - assert(lookup_len(n, idx) < addlen); - udb_ptr_new(&rnode, udb, &lookup(n)->array[idx].node); - /* make space for string length */ - if(addlen-lookup_len(n, idx) > 1) { - /* shift one because a character goes into array */ - split_len = addlen - (lookup_len(n, idx)+1); - } - if(!udb_radnode_array_space(udb, &rnode, - addstr[lookup_len(n, idx)], split_len)) { - udb_ptr_unlink(&rnode, udb); - return 0; - } - /* alloc succeeded, now link it in */ - udb_rptr_set_ptr(&RADNODE(add)->parent, udb, &rnode); - RADNODE(add)->pidx = addstr[lookup_len(n, idx)] - - RADNODE(&rnode)->offset; - udb_rptr_set_ptr(&lookup(&rnode)->array[ RADNODE(add)->pidx ] - .node, udb, add); - if(addlen-lookup_len(n, idx) > 1) { - udb_radsel_prefix_remainder(lookup_len(n, idx)+1, - addstr, addlen, - lookup_string(&rnode, RADNODE(add)->pidx), - &lookup(&rnode)->array[ RADNODE(add)->pidx] - .len); - } else { - lookup(&rnode)->array[ RADNODE(add)->pidx].len = 0; - } - /* rnode's string has become shorter */ - if(!udb_radarray_reduce_if_needed(udb, &rnode)) { - /* ignore this, our tree has become inefficient */ - } - udb_ptr_unlink(&rnode, udb); - } else { - /* okay we need to create a new node that chooses between - * the nodes 'add' and r.node - * We do this so that r.node stays the same pointer for its - * key name. */ - udb_ptr com, rnode; - udb_radstrlen_type common_len = udb_bstr_common( - lookup_string(n, idx), lookup_len(n, idx), - addstr, addlen); - assert(common_len < lookup_len(n, idx)); - assert(common_len < addlen); - udb_ptr_new(&rnode, udb, &lookup(n)->array[idx].node); - - /* create the new node for choice */ - if(!udb_ptr_alloc_space(&com, udb, udb_chunk_type_radnode, - sizeof(struct udb_radnode_d))) { - udb_ptr_unlink(&rnode, udb); - return 0; /* out of space */ - } - memset(UDB_PTR(&com), 0, sizeof(struct udb_radnode_d)); - /* make stringspace for the two substring choices */ - /* this allocates the com->lookup array */ - if(!udb_radnode_array_space_strremain(udb, &com, - lookup_string(n, idx), lookup_len(n, idx), common_len) - || !udb_radnode_array_space_strremain(udb, &com, - addstr, addlen, common_len)) { - udb_ptr_unlink(&rnode, udb); - udb_radnode_delete(udb, &com); - return 0; - } - /* create stringspace for the shared prefix */ - if(common_len > 0) { - if(!udb_radnode_str_space(udb, n, common_len-1)) { - udb_ptr_unlink(&rnode, udb); - udb_radnode_delete(udb, &com); - return 0; - } - } - /* allocs succeeded, proceed to link it all up */ - udb_rptr_set_rptr(&RADNODE(&com)->parent, udb, - &RADNODE(&rnode)->parent); - RADNODE(&com)->pidx = RADNODE(&rnode)->pidx; - udb_rptr_set_ptr(&RADNODE(&rnode)->parent, udb, &com); - RADNODE(&rnode)->pidx = lookup_string(n, idx)[common_len] - - RADNODE(&com)->offset; - udb_rptr_set_ptr(&RADNODE(add)->parent, udb, &com); - RADNODE(add)->pidx = addstr[common_len] - - RADNODE(&com)->offset; - udb_rptr_set_ptr(&lookup(&com)->array[RADNODE(&rnode)->pidx] - .node, udb, &rnode); - if(lookup_len(n, idx)-common_len > 1) { - udb_radsel_prefix_remainder(common_len+1, - lookup_string(n, idx), lookup_len(n, idx), - lookup_string(&com, RADNODE(&rnode)->pidx), - &lookup(&com)->array[RADNODE(&rnode)->pidx].len); - } else { - lookup(&com)->array[RADNODE(&rnode)->pidx].len= 0; - } - udb_rptr_set_ptr(&lookup(&com)->array[RADNODE(add)->pidx] - .node, udb, add); - if(addlen-common_len > 1) { - udb_radsel_prefix_remainder(common_len+1, - addstr, addlen, - lookup_string(&com, RADNODE(add)->pidx), - &lookup(&com)->array[RADNODE(add)->pidx].len); - } else { - lookup(&com)->array[RADNODE(add)->pidx].len = 0; - } - memmove(lookup_string(n, idx), addstr, common_len); - lookup(n)->array[idx].len = common_len; - udb_rptr_set_ptr(&lookup(n)->array[idx].node, udb, &com); - udb_ptr_unlink(&rnode, udb); - udb_ptr_unlink(&com, udb); - /* n's string has become shorter */ - if(!udb_radarray_reduce_if_needed(udb, n)) { - /* ignore this, our tree has become inefficient */ - } - } - return 1; -} - -uint64_t* result_data = NULL; -udb_void udb_radix_insert(udb_base* udb, udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len, udb_ptr* elem, udb_ptr* result) -{ - udb_void ret; - udb_ptr add, n; /* type udb_radnode_d */ - udb_radstrlen_type pos = 0; - /* create new element to add */ - if(!udb_ptr_alloc_space(&add, udb, udb_chunk_type_radnode, - sizeof(struct udb_radnode_d))) { - return 0; /* alloc failure */ - } - memset(UDB_PTR(&add), 0, sizeof(struct udb_radnode_d)); - udb_rptr_set_ptr(&RADNODE(&add)->elem, udb, elem); - if(!udb_radnode_array_create(udb, &add)) { - udb_ptr_free_space(&add, udb, sizeof(struct udb_radnode_d)); - return 0; /* alloc failure */ - } - udb_ptr_init(&n, udb); - result_data = &n.data; - - /* find out where to add it */ - if(!udb_radix_find_prefix_node(udb, rt, k, len, &n, &pos)) { - /* new root */ - assert(RADTREE(rt)->root.data == 0); - if(len == 0) { - udb_rptr_set_ptr(&RADTREE(rt)->root, udb, &add); - } else { - /* add a root to point to new node */ - udb_ptr_zero(&n, udb); - if(!udb_ptr_alloc_space(&n, udb, - udb_chunk_type_radnode, - sizeof(struct udb_radnode_d))) { - udb_radnode_delete(udb, &add); - udb_ptr_unlink(&n, udb); - return 0; /* alloc failure */ - } - memset(RADNODE(&n), 0, sizeof(struct udb_radnode_d)); - /* this creates the array lookup structure for n */ - if(!udb_radnode_array_space(udb, &n, k[0], len-1)) { - udb_radnode_delete(udb, &add); - udb_ptr_free_space(&n, udb, - sizeof(struct udb_radnode_d)); - return 0; /* alloc failure */ - } - udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); - RADNODE(&add)->pidx = 0; - udb_rptr_set_ptr(&lookup(&n)->array[0].node, udb, &add); - if(len > 1) { - udb_radsel_prefix_remainder(1, k, len, - lookup_string(&n, 0), - &lookup(&n)->array[0].len); - } - udb_rptr_set_ptr(&RADTREE(rt)->root, udb, &n); - } - } else if(pos == len) { - /* found an exact match */ - if(RADNODE(&n)->elem.data) { - /* already exists, failure */ - udb_radnode_delete(udb, &add); - udb_ptr_unlink(&n, udb); - return 0; - } - udb_rptr_set_ptr(&RADNODE(&n)->elem, udb, elem); - udb_radnode_delete(udb, &add); - udb_ptr_set_ptr(&add, udb, &n); - } else { - /* n is a node which can accomodate */ - uint8_t byte; - assert(pos < len); - byte = k[pos]; - - /* see if it falls outside of array */ - if(byte < RADNODE(&n)->offset || byte-RADNODE(&n)->offset >= - lookup(&n)->len) { - /* make space in the array for it; adjusts offset */ - if(!udb_radnode_array_space(udb, &n, byte, - len-(pos+1))) { - udb_radnode_delete(udb, &add); - udb_ptr_unlink(&n, udb); - return 0; - } - assert(byte>=RADNODE(&n)->offset && byte-RADNODE(&n)-> - offset<lookup(&n)->len); - byte -= RADNODE(&n)->offset; - /* see if more prefix needs to be split off */ - if(pos+1 < len) { - udb_radsel_str_create(lookup_string(&n, byte), - &lookup(&n)->array[byte].len, - k, pos+1, len); - } - /* insert the new node in the new bucket */ - udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); - RADNODE(&add)->pidx = byte; - udb_rptr_set_ptr(&lookup(&n)->array[byte].node, udb, - &add); - /* so a bucket exists and byte falls in it */ - } else if(lookup(&n)->array[byte - RADNODE(&n)->offset] - .node.data == 0) { - /* use existing bucket */ - byte -= RADNODE(&n)->offset; - if(pos+1 < len) { - /* make space and split off more prefix */ - if(!udb_radnode_str_space(udb, &n, - len-(pos+1))) { - udb_radnode_delete(udb, &add); - udb_ptr_unlink(&n, udb); - return 0; - } - udb_radsel_str_create(lookup_string(&n, byte), - &lookup(&n)->array[byte].len, - k, pos+1, len); - } - /* insert the new node in the new bucket */ - udb_rptr_set_ptr(&RADNODE(&add)->parent, udb, &n); - RADNODE(&add)->pidx = byte; - udb_rptr_set_ptr(&lookup(&n)->array[byte].node, udb, - &add); - } else { - /* use bucket but it has a shared prefix, - * split that out and create a new intermediate - * node to split out between the two. - * One of the two might exactmatch the new - * intermediate node */ - if(!udb_radsel_split(udb, &n, byte-RADNODE(&n)->offset, - k, pos+1, len, &add)) { - udb_radnode_delete(udb, &add); - udb_ptr_unlink(&n, udb); - return 0; - } - } - } - RADTREE(rt)->count ++; - ret = add.data; - udb_ptr_init(result, udb); - udb_ptr_set_ptr(result, udb, &add); - udb_ptr_unlink(&add, udb); - udb_ptr_unlink(&n, udb); - return ret; -} - -/** Cleanup node with one child, it is removed and joined into parent[x] str */ -static int -udb_radnode_cleanup_onechild(udb_base* udb, udb_ptr* n) -{ - udb_ptr par, child; - uint8_t pidx = RADNODE(n)->pidx; - radstrlen_type joinlen; - udb_ptr_new(&par, udb, &RADNODE(n)->parent); - udb_ptr_new(&child, udb, &lookup(n)->array[0].node); - - /* node had one child, merge them into the parent. */ - /* keep the child node, so its pointers stay valid. */ - - /* at parent, append child->str to array str */ - assert(pidx < lookup(&par)->len); - joinlen = lookup_len(&par, pidx) + lookup_len(n, 0) + 1; - /* make stringspace for the joined string */ - if(!udb_radnode_str_space(udb, &par, joinlen)) { - /* cleanup failed due to out of memory */ - /* the tree is inefficient, with node n still existing */ - udb_ptr_unlink(&par, udb); - udb_ptr_unlink(&child, udb); - udb_ptr_zero(n, udb); - return 0; - } - /* the string(par, pidx) is already there */ - /* the array lookup is gone, put its character in the lookup string*/ - lookup_string(&par, pidx)[lookup_len(&par, pidx)] = - RADNODE(&child)->pidx + RADNODE(n)->offset; - memmove(lookup_string(&par, pidx)+lookup_len(&par, pidx)+1, - lookup_string(n, 0), lookup_len(n, 0)); - lookup(&par)->array[pidx].len = joinlen; - /* and set the node to our child. */ - udb_rptr_set_ptr(&lookup(&par)->array[pidx].node, udb, &child); - udb_rptr_set_ptr(&RADNODE(&child)->parent, udb, &par); - RADNODE(&child)->pidx = pidx; - /* we are unlinked, delete our node */ - udb_radnode_delete(udb, n); - udb_ptr_unlink(&par, udb); - udb_ptr_unlink(&child, udb); - udb_ptr_zero(n, udb); - return 1; -} - -/** reduce the size of radarray, does a malloc */ -static int -udb_radarray_reduce(udb_base* udb, udb_ptr* n, uint16_t cap, - udb_radstrlen_type strcap) -{ - udb_ptr a; - unsigned i; - assert(lookup(n)->len <= cap); - assert(cap <= lookup(n)->capacity); - assert(strcap <= lookup(n)->str_cap); - if(!udb_ptr_alloc_space(&a, udb, udb_chunk_type_radarray, - size_of_lookup_needed(cap, strcap))) - return 0; - memset(RADARRAY(&a), 0, size_of_lookup_needed(cap, strcap)); - memcpy(RADARRAY(&a), lookup(n), sizeof(struct udb_radarray_d)); - RADARRAY(&a)->capacity = cap; - RADARRAY(&a)->str_cap = strcap; - for(i=0; i<lookup(n)->len; i++) { - udb_rel_ptr_init(&RADARRAY(&a)->array[i].node); - udb_rptr_set_rptr(&RADARRAY(&a)->array[i].node, udb, - &lookup(n)->array[i].node); - RADARRAY(&a)->array[i].len = lookup_len(n, i); - memmove(((uint8_t*)(&RADARRAY(&a)->array[cap]))+i*strcap, - lookup_string(n, i), lookup_len(n, i)); - } - udb_radarray_zero_ptrs(udb, n); - udb_rel_ptr_free_space(&RADNODE(n)->lookup, udb, size_of_lookup(n)); - udb_rptr_set_ptr(&RADNODE(n)->lookup, udb, &a); - udb_ptr_unlink(&a, udb); - return 1; -} - -/** find the max stringlength in the array */ -static udb_radstrlen_type udb_radarray_max_len(udb_ptr* n) -{ - unsigned i; - udb_radstrlen_type maxlen = 0; - for(i=0; i<lookup(n)->len; i++) { - if(lookup(n)->array[i].node.data && - lookup(n)->array[i].len > maxlen) - maxlen = lookup(n)->array[i].len; - } - return maxlen; -} - -/** see if radarray can be reduced (by a factor of two) */ -static int -udb_radarray_reduce_if_needed(udb_base* udb, udb_ptr* n) -{ - udb_radstrlen_type maxlen = udb_radarray_max_len(n); - if((lookup(n)->len <= lookup(n)->capacity/2 || lookup(n)->len == 0 - || maxlen <= lookup(n)->str_cap/2 || maxlen == 0) && - (lookup(n)->len != lookup(n)->capacity || - lookup(n)->str_cap != maxlen)) - return udb_radarray_reduce(udb, n, lookup(n)->len, maxlen); - return 1; -} - -static int -udb_radnode_array_clean_all(udb_base* udb, udb_ptr* n) -{ - RADNODE(n)->offset = 0; - lookup(n)->len = 0; - /* reallocate lookup to a smaller capacity structure */ - return udb_radarray_reduce(udb, n, 0, 0); -} - -/** remove NULL nodes from front of array */ -static int -udb_radnode_array_clean_front(udb_base* udb, udb_ptr* n) -{ - /* move them up and adjust offset */ - unsigned idx, shuf = 0; - /* remove until a nonNULL entry */ - while(shuf < lookup(n)->len && lookup(n)->array[shuf].node.data == 0) - shuf++; - if(shuf == 0) - return 1; - if(shuf == lookup(n)->len) { - /* the array is empty, the tree is inefficient */ - return udb_radnode_array_clean_all(udb, n); - } - assert(shuf < lookup(n)->len); - assert((int)shuf <= 255-(int)RADNODE(n)->offset); - /* move them */ - for(idx=0; idx<lookup(n)->len-shuf; idx++) { - udb_rptr_set_rptr(&lookup(n)->array[idx].node, udb, - &lookup(n)->array[shuf+idx].node); - lookup(n)->array[idx].len = lookup_len(n, shuf+idx); - memmove(lookup_string(n, idx), lookup_string(n, shuf+idx), - lookup(n)->array[idx].len); - } - /* zero the to-be-unused entries */ - for(idx=lookup(n)->len-shuf; idx<lookup(n)->len; idx++) { - udb_rptr_zero(&lookup(n)->array[idx].node, udb); - memset(lookup_string(n, idx), 0, lookup(n)->array[idx].len); - lookup(n)->array[idx].len = 0; - } - RADNODE(n)->offset += shuf; - lookup(n)->len -= shuf; - for(idx=0; idx<lookup(n)->len; idx++) - if(lookup(n)->array[idx].node.data) - lookup_node(n, idx)->pidx = idx; - - /* see if capacity has to shrink */ - return udb_radarray_reduce_if_needed(udb, n); -} - -/** remove NULL nodes from end of array */ -static int -udb_radnode_array_clean_end(udb_base* udb, udb_ptr* n) -{ - /* shorten it */ - unsigned shuf = 0; - /* remove until a nonNULL entry */ - /* remove until a nonNULL entry */ - while(shuf < lookup(n)->len && lookup(n)->array[lookup(n)->len-1-shuf] - .node.data == 0) - shuf++; - if(shuf == 0) - return 1; - if(shuf == lookup(n)->len) { - /* the array is empty, the tree is inefficient */ - return udb_radnode_array_clean_all(udb, n); - } - assert(shuf < lookup(n)->len); - lookup(n)->len -= shuf; - /* array elements can stay where they are */ - /* see if capacity has to shrink */ - return udb_radarray_reduce_if_needed(udb, n); -} - -/** clean up radnode leaf, where we know it has a parent */ -static int -udb_radnode_cleanup_leaf(udb_base* udb, udb_ptr* n, udb_ptr* par) -{ - uint8_t pidx; - /* node was a leaf */ - - /* delete leaf node, but store parent+idx */ - pidx = RADNODE(n)->pidx; - assert(pidx < lookup(par)->len); - - /** set parent ptr to this node to NULL before deleting the node, - * because otherwise ptrlinks fail */ - udb_rptr_zero(&lookup(par)->array[pidx].node, udb); - - udb_radnode_delete(udb, n); - - /* set parent+idx entry to NULL str and node.*/ - lookup(par)->array[pidx].len = 0; - - /* see if par offset or len must be adjusted */ - if(lookup(par)->len == 1) { - /* removed final element from array */ - if(!udb_radnode_array_clean_all(udb, par)) - return 0; - } else if(pidx == 0) { - /* removed first element from array */ - if(!udb_radnode_array_clean_front(udb, par)) - return 0; - } else if(pidx == lookup(par)->len-1) { - /* removed last element from array */ - if(!udb_radnode_array_clean_end(udb, par)) - return 0; - } - return 1; -} - -/** - * Cleanup a radix node that was made smaller, see if it can - * be merged with others. - * @param udb: the udb - * @param rt: tree to remove root if needed. - * @param n: node to cleanup - * @return false on alloc failure. - */ -static int -udb_radnode_cleanup(udb_base* udb, udb_ptr* rt, udb_ptr* n) -{ - while(!udb_ptr_is_null(n)) { - if(RADNODE(n)->elem.data) { - /* see if if needs to be reduced in stringsize */ - if(!udb_radarray_reduce_if_needed(udb, n)) { - udb_ptr_zero(n, udb); - return 0; - } - /* cannot delete node with a data element */ - udb_ptr_zero(n, udb); - return 1; - } else if(lookup(n)->len == 1 && RADNODE(n)->parent.data) { - return udb_radnode_cleanup_onechild(udb, n); - } else if(lookup(n)->len == 0) { - udb_ptr par; - if(!RADNODE(n)->parent.data) { - /* root deleted */ - udb_rptr_zero(&RADTREE(rt)->root, udb); - udb_radnode_delete(udb, n); - return 1; - } - udb_ptr_new(&par, udb, &RADNODE(n)->parent); - /* remove and delete the leaf node */ - if(!udb_radnode_cleanup_leaf(udb, n, &par)) { - udb_ptr_unlink(&par, udb); - udb_ptr_zero(n, udb); - return 0; - } - /* see if parent can now be cleaned up */ - udb_ptr_set_ptr(n, udb, &par); - udb_ptr_unlink(&par, udb); - } else { - /* see if if needs to be reduced in stringsize */ - if(!udb_radarray_reduce_if_needed(udb, n)) { - udb_ptr_zero(n, udb); - return 0; - } - /* node cannot be cleaned up */ - udb_ptr_zero(n, udb); - return 1; - } - } - /* ENOTREACH */ - return 1; -} - -void udb_radix_delete(udb_base* udb, udb_ptr* rt, udb_ptr* n) -{ - if(udb_ptr_is_null(n)) - return; - udb_rptr_zero(&RADNODE(n)->elem, udb); - RADTREE(rt)->count --; - if(!udb_radnode_cleanup(udb, rt, n)) { - /* out of memory in cleanup. the elem ptr is NULL, but - * the radix tree could be inefficient. */ - } -} - -udb_void udb_radix_search(udb_ptr* rt, uint8_t* k, udb_radstrlen_type len) -{ - /* since we only perform reads, and no udb_mallocs or udb_frees - * we know the pointers stay the same */ - struct udb_radnode_d* n; - udb_radstrlen_type pos = 0; - uint8_t byte; - void* base = *rt->base; - - n = (struct udb_radnode_d*)UDB_REL(base, RADTREE(rt)->root.data); -#define NARRAY(n) ((struct udb_radarray_d*)UDB_REL(base, n->lookup.data)) -#define NSTR(n, byte) (((uint8_t*)(&NARRAY(n)->array[NARRAY(n)->capacity]))+byte*NARRAY(n)->str_cap) - while(n != *rt->base) { - if(pos == len) - return UDB_SYSTOREL(*rt->base, n); - byte = k[pos]; - if(byte < n->offset) - return 0; - byte -= n->offset; - if(byte >= NARRAY(n)->len) - return 0; - pos++; - if(NARRAY(n)->array[byte].len != 0) { - /* must match additional string */ - if(pos+NARRAY(n)->array[byte].len > len) - return 0; /* no match */ - if(memcmp(&k[pos], NSTR(n, byte), - NARRAY(n)->array[byte].len) != 0) - return 0; /* no match */ - pos += NARRAY(n)->array[byte].len; - } - n = (struct udb_radnode_d*)UDB_REL(base, - NARRAY(n)->array[byte].node.data); - } - return 0; -} - -/** go to last elem-containing node in this subtree (excl self) */ -static void -udb_radnode_last_in_subtree(udb_base* udb, udb_ptr* n) -{ - int idx; - /* try last entry in array first */ - for(idx=((int)lookup(n)->len)-1; idx >= 0; idx--) { - if(lookup(n)->array[idx].node.data) { - udb_ptr s; - udb_ptr_init(&s, udb); - udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); - /* does it have entries in its subtrees? */ - if(lookup(&s)->len > 0) { - udb_radnode_last_in_subtree(udb, &s); - if(!udb_ptr_is_null(&s)) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - } - udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); - /* no, does it have an entry itself? */ - if(RADNODE(&s)->elem.data) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - udb_ptr_unlink(&s, udb); - } - } - udb_ptr_zero(n, udb); -} - -/** last in subtree, incl self */ -static void -udb_radnode_last_in_subtree_incl_self(udb_base* udb, udb_ptr* n) -{ - udb_ptr self; - udb_ptr_init(&self, udb); - udb_ptr_set_ptr(&self, udb, n); - udb_radnode_last_in_subtree(udb, n); - if(!udb_ptr_is_null(n)) { - udb_ptr_unlink(&self, udb); - return; - } - if(RADNODE(&self)->elem.data) { - udb_ptr_set_ptr(n, udb, &self); - udb_ptr_unlink(&self, udb); - return; - } - udb_ptr_zero(n, udb); - udb_ptr_unlink(&self, udb); -} - -/** return first elem-containing node in this subtree (excl self) */ -static void -udb_radnode_first_in_subtree(udb_base* udb, udb_ptr* n) -{ - unsigned idx; - /* try every subnode */ - for(idx=0; idx<lookup(n)->len; idx++) { - if(lookup(n)->array[idx].node.data) { - udb_ptr s; - udb_ptr_init(&s, udb); - udb_ptr_set_rptr(&s, udb, &lookup(n)->array[idx].node); - /* does it have elem itself? */ - if(RADNODE(&s)->elem.data) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - /* try its subtrees */ - udb_radnode_first_in_subtree(udb, &s); - if(!udb_ptr_is_null(&s)) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - - } - } - udb_ptr_zero(n, udb); -} - -/** Find an entry in arrays from idx-1 to 0 */ -static void -udb_radnode_find_prev_from_idx(udb_base* udb, udb_ptr* n, unsigned from) -{ - unsigned idx = from; - while(idx > 0) { - idx --; - if(lookup(n)->array[idx].node.data) { - udb_ptr_set_rptr(n, udb, &lookup(n)->array[idx].node); - udb_radnode_last_in_subtree_incl_self(udb, n); - if(!udb_ptr_is_null(n)) - return; - } - } - udb_ptr_zero(n, udb); -} - -/** return self or a previous element */ -static int udb_ret_self_or_prev(udb_base* udb, udb_ptr* n, udb_ptr* result) -{ - if(RADNODE(n)->elem.data) { - udb_ptr_set_ptr(result, udb, n); - } else { - udb_ptr_set_ptr(result, udb, n); - udb_radix_prev(udb, result); - } - udb_ptr_unlink(n, udb); - return 0; -} - - -int udb_radix_find_less_equal(udb_base* udb, udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len, udb_ptr* result) -{ - udb_ptr n; - udb_radstrlen_type pos = 0; - uint8_t byte; - int r; - /* set result to NULL */ - udb_ptr_init(result, udb); - if(RADTREE(rt)->count == 0) { - /* empty tree */ - return 0; - } - udb_ptr_new(&n, udb, &RADTREE(rt)->root); - while(pos < len) { - byte = k[pos]; - if(byte < RADNODE(&n)->offset) { - /* so the previous is the element itself */ - /* or something before this element */ - return udb_ret_self_or_prev(udb, &n, result); - } - byte -= RADNODE(&n)->offset; - if(byte >= lookup(&n)->len) { - /* so, the previous is the last of array, or itself */ - /* or something before this element */ - udb_ptr_set_ptr(result, udb, &n); - udb_radnode_last_in_subtree_incl_self(udb, result); - if(udb_ptr_is_null(result)) { - udb_ptr_set_ptr(result, udb, &n); - udb_radix_prev(udb, result); - } - goto done_fail; - } - pos++; - if(!lookup(&n)->array[byte].node.data) { - /* no match */ - /* Find an entry in arrays from byte-1 to 0 */ - udb_ptr_set_ptr(result, udb, &n); - udb_radnode_find_prev_from_idx(udb, result, byte); - if(!udb_ptr_is_null(result)) - goto done_fail; - /* this entry or something before it */ - udb_ptr_zero(result, udb); - return udb_ret_self_or_prev(udb, &n, result); - } - if(lookup_len(&n, byte) != 0) { - /* must match additional string */ - if(pos+lookup_len(&n, byte) > len) { - /* the additional string is longer than key*/ - if( (memcmp(&k[pos], lookup_string(&n, byte), - len-pos)) <= 0) { - /* and the key is before this node */ - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radix_prev(udb, result); - } else { - /* the key is after the additional - * string, thus everything in that - * subtree is smaller. */ - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radnode_last_in_subtree_incl_self(udb, result); - /* if somehow that is NULL, - * then we have an inefficient tree: - * byte+1 is larger than us, so find - * something in byte-1 and before */ - if(udb_ptr_is_null(result)) { - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radix_prev(udb, result); - } - } - goto done_fail; /* no match */ - } - if( (r=memcmp(&k[pos], lookup_string(&n, byte), - lookup_len(&n, byte))) < 0) { - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radix_prev(udb, result); - goto done_fail; /* no match */ - } else if(r > 0) { - /* the key is larger than the additional - * string, thus everything in that subtree - * is smaller */ - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radnode_last_in_subtree_incl_self(udb, result); - /* if we have an inefficient tree */ - if(udb_ptr_is_null(result)) { - udb_ptr_set_rptr(result, udb, - &lookup(&n)->array[byte].node); - udb_radix_prev(udb, result); - } - goto done_fail; /* no match */ - } - pos += lookup_len(&n, byte); - } - udb_ptr_set_rptr(&n, udb, &lookup(&n)->array[byte].node); - } - if(RADNODE(&n)->elem.data) { - /* exact match */ - udb_ptr_set_ptr(result, udb, &n); - udb_ptr_unlink(&n, udb); - return 1; - } - /* there is a node which is an exact match, but it has no element */ - udb_ptr_set_ptr(result, udb, &n); - udb_radix_prev(udb, result); -done_fail: - udb_ptr_unlink(&n, udb); - return 0; -} - -void udb_radix_first(udb_base* udb, udb_ptr* rt, udb_ptr* p) -{ - udb_ptr_init(p, udb); - if(!rt || udb_ptr_is_null(rt) || RADTREE(rt)->count == 0) - return; - udb_ptr_set_rptr(p, udb, &RADTREE(rt)->root); - if(RADNODE(p)->elem.data) - return; - udb_radix_next(udb, p); -} - -void udb_radix_last(udb_base* udb, udb_ptr* rt, udb_ptr* p) -{ - udb_ptr_init(p, udb); - if(!rt || udb_ptr_is_null(rt) || RADTREE(rt)->count == 0) - return; - udb_ptr_set_rptr(p, udb, &RADTREE(rt)->root); - udb_radnode_last_in_subtree_incl_self(udb, p); -} - -void udb_radix_next(udb_base* udb, udb_ptr* n) -{ - udb_ptr s; - udb_ptr_init(&s, udb); - if(lookup(n)->len) { - /* go down */ - udb_ptr_set_ptr(&s, udb, n); - udb_radnode_first_in_subtree(udb, &s); - if(!udb_ptr_is_null(&s)) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - } - /* go up - the parent->elem is not useful, because it is before us */ - while(RADNODE(n)->parent.data) { - unsigned idx = RADNODE(n)->pidx; - udb_ptr_set_rptr(n, udb, &RADNODE(n)->parent); - idx++; - for(; idx < lookup(n)->len; idx++) { - /* go down the next branch */ - if(lookup(n)->array[idx].node.data) { - udb_ptr_set_rptr(&s, udb, - &lookup(n)->array[idx].node); - /* node itself */ - if(RADNODE(&s)->elem.data) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - /* or subtree */ - udb_radnode_first_in_subtree(udb, &s); - if(!udb_ptr_is_null(&s)) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - } - } - } - udb_ptr_unlink(&s, udb); - udb_ptr_zero(n, udb); -} - -void udb_radix_prev(udb_base* udb, udb_ptr* n) -{ - /* must go up, since all array nodes are after this node */ - while(RADNODE(n)->parent.data) { - uint8_t idx = RADNODE(n)->pidx; - udb_ptr s; - udb_ptr_set_rptr(n, udb, &RADNODE(n)->parent); - assert(lookup(n)->len > 0); /* since we are a child */ - /* see if there are elements in previous branches there */ - udb_ptr_init(&s, udb); - udb_ptr_set_ptr(&s, udb, n); - udb_radnode_find_prev_from_idx(udb, &s, idx); - if(!udb_ptr_is_null(&s)) { - udb_ptr_set_ptr(n, udb, &s); - udb_ptr_unlink(&s, udb); - return; - } - udb_ptr_unlink(&s, udb); - /* the current node is before the array */ - if(RADNODE(n)->elem.data) - return; - } - udb_ptr_zero(n, udb); -} - -udb_void udb_radname_insert(udb_base* udb, udb_ptr* rt, const uint8_t* dname, - size_t dlen, udb_ptr* elem, udb_ptr* result) -{ - uint8_t k[300]; - radstrlen_type klen = (radstrlen_type)sizeof(k); - radname_d2r(k, &klen, dname, dlen); - return udb_radix_insert(udb, rt, k, klen, elem, result); -} - -int udb_radname_search(udb_base* udb, udb_ptr* rt, const uint8_t* dname, - size_t dlen, udb_ptr* result) -{ - udb_void r; - uint8_t k[300]; - radstrlen_type klen = (radstrlen_type)sizeof(k); - radname_d2r(k, &klen, dname, dlen); - r = udb_radix_search(rt, k, klen); - udb_ptr_init(result, udb); - udb_ptr_set(result, udb, r); - return (r != 0); -} - -void udb_radix_tree_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg) -{ - struct udb_radtree_d* p = (struct udb_radtree_d*)d; - assert(s >= sizeof(struct udb_radtree_d)); - (void)s; - (*cb)(base, &p->root, arg); -} - -void udb_radix_node_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg) -{ - struct udb_radnode_d* p = (struct udb_radnode_d*)d; - assert(s >= sizeof(struct udb_radnode_d)); - (void)s; - (*cb)(base, &p->elem, arg); - (*cb)(base, &p->parent, arg); - (*cb)(base, &p->lookup, arg); -} - -void udb_radix_array_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg) -{ - struct udb_radarray_d* p = (struct udb_radarray_d*)d; - unsigned i; - assert(s >= sizeof(struct udb_radarray_d)+ - p->capacity*(sizeof(struct udb_radsel_d)+p->str_cap)); - (void)s; - for(i=0; i<p->len; i++) { - (*cb)(base, &p->array[i].node, arg); - } -} diff --git a/usr.sbin/nsd/udbradtree.h b/usr.sbin/nsd/udbradtree.h deleted file mode 100644 index b8e6186ae8b..00000000000 --- a/usr.sbin/nsd/udbradtree.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * udbradtree -- radix tree for binary strings for in udb file. - * - * Copyright (c) 2011, NLnet Labs. See LICENSE for license. - */ -#ifndef UDB_RADTREE_H -#define UDB_RADTREE_H -#include "udb.h" -struct udb_radnode; - -/** length of the binary string */ -typedef uint16_t udb_radstrlen_type; - -/** - * The radix tree - * - * The elements are stored based on binary strings(0-255) of a given length. - * They are sorted, a prefix is sorted before its suffixes. - * If you want to know the key string, you should store it yourself, the - * tree stores it in the parts necessary for lookup. - * For binary strings for domain names see the radname routines. - * - * This is the tree on disk representation. It has _d suffix in the name - * to help delineate disk structures from normal structures. - */ -struct udb_radtree_d { - /** root node in tree, to udb_radnode_d */ - struct udb_rel_ptr root; - /** count of number of elements */ - uint64_t count; -}; - -/** - * A radix tree lookup node. It is stored on disk, and the lookup array - * is allocated. - */ -struct udb_radnode_d { - /** data element associated with the binary string up to this node */ - struct udb_rel_ptr elem; - /** parent node (NULL for the root), to udb_radnode_d */ - struct udb_rel_ptr parent; - /** the array structure, for lookup by [byte-offset]. udb_radarray_d */ - struct udb_rel_ptr lookup; - /** index in the parent lookup array */ - uint8_t pidx; - /** offset of the lookup array, add to [i] for lookups */ - uint8_t offset; -}; - -/** - * radix select edge in array - * The string for this element is the Nth string in the stringarray. - */ -struct udb_radsel_d { - /** length of the additional string for this edge, - * additional string after the selection-byte for this edge.*/ - udb_radstrlen_type len; - /** padding for non64bit compilers to 64bit boundaries, to make - * the udb file more portable, without this the file would work - * on the system it is created on (which is what we promise), but - * with this, you have a chance of it working on other platforms */ - uint16_t padding16; - uint32_t padding32; - /** node that deals with byte+str, to udb_radnode_d */ - struct udb_rel_ptr node; -}; - -/** - * Array of radsel elements. - * This is the header, the array is allocated contiguously behind it. - * The strings (often very short) are allocated behind the array. - * All strings are given the same amount of space (str_cap), - * so there is capacity*str_cap bytes at the end. - */ -struct udb_radarray_d { - /** length of the lookup array */ - uint16_t len; - /** capacity of the lookup array (can be larger than length) */ - uint16_t capacity; - /** space capacity of for every string */ - udb_radstrlen_type str_cap; - /** padding to 64bit alignment, just in case compiler goes mad */ - uint16_t padding; - /** the elements (allocated contiguously after this structure) */ - struct udb_radsel_d array[0]; -}; - -/** - * Create new radix tree on udb storage - * @param udb: the udb to allocate space on. - * @param ptr: ptr to the udbradtree is returned here. Pass uninitialised. - * type is udb_radtree_d. - * @return 0 on alloc failure. - */ -int udb_radix_tree_create(udb_base* udb, udb_ptr* ptr); - -/** - * Delete intermediate nodes from radix tree - * @param udb: the udb. - * @param rt: radix tree to be cleared. type udb_radtree_d. - */ -void udb_radix_tree_clear(udb_base* udb, udb_ptr* rt); - -/** - * Delete radix tree. - * You must have deleted the elements, this deletes the nodes. - * @param udb: the udb. - * @param rt: radix tree to be deleted. type udb_radtree_d. - */ -void udb_radix_tree_delete(udb_base* udb, udb_ptr* rt); - -/** - * Insert element into radix tree. - * @param udb: the udb. - * @param rt: the radix tree, type udb_radtree_d. - * @param key: key string. - * @param len: length of key. - * @param elem: pointer to element data, on the udb store. - * @param result: the inserted node is set to this value. Pass uninitialised. - Not set if the routine fails. - * @return NULL on failure - out of memory. - * NULL on failure - duplicate entry. - * On success the new radix node for this element (udb_radnode_d). - */ -udb_void udb_radix_insert(udb_base* udb, udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len, udb_ptr* elem, udb_ptr* result); - -/** - * Delete element from radix tree. - * @param udb: the udb. - * @param rt: the radix tree. type udb_radtree_d - * @param n: radix node for that element. type udb_radnode_d - * if NULL, nothing is deleted. - */ -void udb_radix_delete(udb_base* udb, udb_ptr* rt, udb_ptr* n); - -/** - * Find radix element in tree. - * @param rt: the radix tree, type udb_radtree_d. - * @param key: key string. - * @param len: length of key. - * @return the radix node or NULL if not found. type udb_radnode_d - */ -udb_void udb_radix_search(udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len); - -/** - * Find radix element in tree, and if not found, find the closest smaller or - * equal element in the tree. - * @param udb: the udb. - * @param rt: the radix tree, type udb_radtree_d. - * @param key: key string. - * @param len: length of key. - * @param result: returns the radix node or closest match (NULL if key is - * smaller than the smallest key in the tree). type udb_radnode_d. - * you can pass an uninitialized ptr, an unlinked or a zeroed one. - * @return true if exact match, false if no match. - */ -int udb_radix_find_less_equal(udb_base* udb, udb_ptr* rt, uint8_t* k, - udb_radstrlen_type len, udb_ptr* result); - -/** - * Return the first (smallest) element in the tree. - * @param udb: the udb. - * @param rt: the radix tree, type udb_radtree_d. - * @param p: set to the first node in the tree, or NULL if none. - * type udb_radnode_d. - * pass uninitialised, zero or unlinked udb_ptr. - */ -void udb_radix_first(udb_base* udb, udb_ptr* rt, udb_ptr* p); - -/** - * Return the last (largest) element in the tree. - * @param udb: the udb. - * @param rt: the radix tree, type udb_radtree_d. - * @param p: last node or NULL if none, type udb_radnode_d. - * pass uninitialised, zero or unlinked udb_ptr. - */ -void udb_radix_last(udb_base* udb, udb_ptr* rt, udb_ptr* p); - -/** - * Return the next element. - * @param udb: the udb. - * @param n: adjusted to the next element, or NULL if none. type udb_radnode_d. - */ -void udb_radix_next(udb_base* udb, udb_ptr* n); - -/** - * Return the previous element. - * @param udb: the udb. - * @param n: adjusted to the prev node or NULL if none. type udb_radnode_d. - */ -void udb_radix_prev(udb_base* udb, udb_ptr* n); - -/* - * Perform a walk through all elements of the tree. - * node: variable of type struct radnode*. - * tree: pointer to the tree. - * for(udb_radix_first(tree, node); node->data; udb_radix_next(node)) -*/ - -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radtree */ -void udb_radix_tree_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); - -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radnode */ -void udb_radix_node_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); - -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_radarray */ -void udb_radix_array_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); - -/** get the memory used by the lookup structure for a radnode */ -size_t size_of_lookup_ext(udb_ptr* node); - -/** insert radtree element, key is a domain name - * @param udb: udb. - * @param rt: the tree. - * @param dname: domain name in uncompressed wireformat. - * @param dlen: length of k. - * @param elem: element to store - * @param result: the inserted node is set to this value. Pass uninitialised. - Not set if the routine fails. - * @return 0 on failure - */ -udb_void udb_radname_insert(udb_base* udb, udb_ptr* rt, const uint8_t* dname, - size_t dlen, udb_ptr* elem, udb_ptr* result); - -/** search for a radname element, key is a domain name. - * @param udb: udb - * @param rt: the tree - * @param dname: domain name in uncompressed wireformat. - * @param dlen: length of k. - * @param result: result ptr to store the node into. - * may be uninitialized. - * @return 0 if not found. - */ -int udb_radname_search(udb_base* udb, udb_ptr* rt, const uint8_t* dname, - size_t dlen, udb_ptr* result); - -#define RADNODE(ptr) ((struct udb_radnode_d*)UDB_PTR(ptr)) -#define RADTREE(ptr) ((struct udb_radtree_d*)UDB_PTR(ptr)) - -#endif /* UDB_RADTREE_H */ diff --git a/usr.sbin/nsd/udbzone.c b/usr.sbin/nsd/udbzone.c deleted file mode 100644 index 30f1c4beb61..00000000000 --- a/usr.sbin/nsd/udbzone.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - * udbzone -- store zone and rrset information in udb file. - * - * Copyright (c) 2011, NLnet Labs. See LICENSE for license. - */ -#include "config.h" -#include "udbzone.h" -#include "util.h" -#include "iterated_hash.h" -#include "dns.h" -#include "dname.h" -#include "difffile.h" -#include <string.h> - -/** delete the zone plain its own data */ -static void -udb_zone_delete_plain(udb_base* udb, udb_ptr* zone) -{ - udb_ptr dtree; - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - udb_zone_clear(udb, zone); - udb_rptr_zero(&ZONE(zone)->node, udb); - udb_rptr_zero(&ZONE(zone)->nsec3param, udb); - udb_rptr_zero(&ZONE(zone)->log_str, udb); - udb_rptr_zero(&ZONE(zone)->file_str, udb); - udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); - udb_rptr_zero(&ZONE(zone)->domains, udb); - udb_radix_tree_delete(udb, &dtree); - udb_ptr_free_space(zone, udb, - sizeof(struct zone_d)+ZONE(zone)->namelen); -} - -int -udb_dns_init_file(udb_base* udb) -{ - udb_ptr ztree; - if(!udb_radix_tree_create(udb, &ztree)) { - return 0; - } - udb_base_set_userdata(udb, ztree.data); - udb_ptr_unlink(&ztree, udb); - return 1; -} - -void -udb_dns_deinit_file(udb_base* udb) -{ - udb_ptr ztree; - udb_ptr z; - udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); - if(udb_ptr_is_null(&ztree)) { - return; - } - assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); - /* delete all zones */ - for(udb_radix_first(udb, &ztree, &z); z.data; udb_radix_next(udb, &z)){ - udb_ptr zone; - udb_ptr_new(&zone, udb, &RADNODE(&z)->elem); - udb_rptr_zero(&RADNODE(&z)->elem, udb); - udb_zone_delete_plain(udb, &zone); - } - udb_ptr_unlink(&z, udb); - - udb_base_set_userdata(udb, 0); - udb_radix_tree_delete(udb, &ztree); -} - -int -udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname, - size_t dlen) -{ - udb_ptr ztree, z, node, dtree; - udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); - assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); - udb_ptr_init(result, udb); - if(udb_zone_search(udb, &z, dname, dlen)) { - udb_ptr_unlink(&ztree, udb); - udb_ptr_unlink(&z, udb); - /* duplicate */ - return 0; - } - if(!udb_ptr_alloc_space(&z, udb, udb_chunk_type_zone, - sizeof(struct zone_d)+dlen)) { - udb_ptr_unlink(&ztree, udb); - /* failed alloc */ - return 0; - } - /* init the zone object */ - udb_rel_ptr_init(&ZONE(&z)->node); - udb_rel_ptr_init(&ZONE(&z)->domains); - udb_rel_ptr_init(&ZONE(&z)->nsec3param); - udb_rel_ptr_init(&ZONE(&z)->log_str); - udb_rel_ptr_init(&ZONE(&z)->file_str); - ZONE(&z)->rrset_count = 0; - ZONE(&z)->rr_count = 0; - ZONE(&z)->expired = 0; - ZONE(&z)->mtime = 0; - ZONE(&z)->mtime_nsec = 0; - ZONE(&z)->namelen = dlen; - memmove(ZONE(&z)->name, dname, dlen); - if(!udb_radix_tree_create(udb, &dtree)) { - udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); - udb_ptr_unlink(&ztree, udb); - /* failed alloc */ - return 0; - } - udb_rptr_set_ptr(&ZONE(&z)->domains, udb, &dtree); - - /* insert it */ - if(!udb_radname_insert(udb, &ztree, dname, dlen, &z, &node)) { - udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen); - udb_ptr_unlink(&ztree, udb); - udb_radix_tree_delete(udb, &dtree); - udb_ptr_unlink(&dtree, udb); - /* failed alloc */ - return 0; - } - udb_rptr_set_ptr(&ZONE(&z)->node, udb, &node); - udb_ptr_set_ptr(result, udb, &z); - udb_ptr_unlink(&z, udb); - udb_ptr_unlink(&dtree, udb); - udb_ptr_unlink(&ztree, udb); - udb_ptr_unlink(&node, udb); - return 1; -} - -/** delete an RR */ -static void -rr_delete(udb_base* udb, udb_ptr* rr) -{ - assert(udb_ptr_get_type(rr) == udb_chunk_type_rr); - udb_rptr_zero(&RR(rr)->next, udb); - udb_ptr_free_space(rr, udb, sizeof(struct rr_d)+RR(rr)->len); -} - -/** delete an rrset */ -static void -rrset_delete(udb_base* udb, udb_ptr* rrset) -{ - udb_ptr rr, n; - assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); - - /* free RRs */ - udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); - udb_ptr_init(&n, udb); - udb_rptr_zero(&RRSET(rrset)->rrs, udb); - while(!udb_ptr_is_null(&rr)) { - udb_ptr_set_rptr(&n, udb, &RR(&rr)->next); - rr_delete(udb, &rr); - udb_ptr_set_ptr(&rr, udb, &n); - udb_ptr_zero(&n, udb); - } - udb_ptr_unlink(&n, udb); - udb_ptr_unlink(&rr, udb); - - udb_rptr_zero(&RRSET(rrset)->next, udb); - udb_ptr_free_space(rrset, udb, sizeof(struct rrset_d)); -} - -/** clear a domain of its rrsets, rrs */ -static void -domain_clear(udb_base* udb, udb_ptr* d) -{ - udb_ptr rrset, n; - assert(udb_ptr_get_type(d) == udb_chunk_type_domain); - udb_ptr_new(&rrset, udb, &DOMAIN(d)->rrsets); - udb_ptr_init(&n, udb); - udb_rptr_zero(&DOMAIN(d)->rrsets, udb); - while(!udb_ptr_is_null(&rrset)) { - udb_ptr_set_rptr(&n, udb, &RRSET(&rrset)->next); - rrset_delete(udb, &rrset); - udb_ptr_set_ptr(&rrset, udb, &n); - udb_ptr_zero(&n, udb); - } - udb_ptr_unlink(&n, udb); - udb_ptr_unlink(&rrset, udb); -} - -/** delete a domain and all its rrsets, rrs */ -static void -domain_delete(udb_base* udb, udb_ptr* d) -{ - domain_clear(udb, d); - udb_rptr_zero(&DOMAIN(d)->node, udb); - udb_ptr_free_space(d, udb, - sizeof(struct domain_d)+DOMAIN(d)->namelen); -} - -/** delete domain but also unlink from tree at zone */ -static void -domain_delete_unlink(udb_base* udb, udb_ptr* z, udb_ptr* d) -{ - udb_ptr dtree, n; - udb_ptr_new(&dtree, udb, &ZONE(z)->domains); - udb_ptr_new(&n, udb, &DOMAIN(d)->node); - udb_rptr_zero(&DOMAIN(d)->node, udb); - udb_radix_delete(udb, &dtree, &n); - udb_ptr_unlink(&dtree, udb); - udb_ptr_unlink(&n, udb); - domain_delete(udb, d); -} - -void -udb_zone_clear(udb_base* udb, udb_ptr* zone) -{ - udb_ptr dtree, d; - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); - udb_rptr_zero(&ZONE(zone)->nsec3param, udb); - udb_zone_set_log_str(udb, zone, NULL); - udb_zone_set_file_str(udb, zone, NULL); - - /* walk and delete all domains, rrsets, rrs, but keep tree */ - for(udb_radix_first(udb, &dtree, &d); d.data; udb_radix_next(udb, &d)){ - udb_ptr domain; - udb_ptr_new(&domain, udb, &RADNODE(&d)->elem); - udb_rptr_zero(&RADNODE(&d)->elem, udb); - domain_delete(udb, &domain); - } - udb_ptr_unlink(&d, udb); - udb_radix_tree_clear(udb, &dtree); - ZONE(zone)->rrset_count = 0; - ZONE(zone)->rr_count = 0; - ZONE(zone)->expired = 0; - ZONE(zone)->mtime = 0; - ZONE(zone)->mtime_nsec = 0; - udb_ptr_unlink(&dtree, udb); -} - -void -udb_zone_delete(udb_base* udb, udb_ptr* zone) -{ - udb_ptr ztree, n; - udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); - udb_ptr_new(&n, udb, &ZONE(zone)->node); - udb_rptr_zero(&ZONE(zone)->node, udb); - udb_radix_delete(udb, &ztree, &n); - udb_ptr_unlink(&ztree, udb); - udb_ptr_unlink(&n, udb); - udb_zone_delete_plain(udb, zone); -} - -int -udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname, - size_t dname_len) -{ - udb_ptr ztree; - udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); - assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree); - if(udb_radname_search(udb, &ztree, dname, dname_len, result)) { - if(result->data) - udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); - udb_ptr_unlink(&ztree, udb); - return (result->data != 0); - } - udb_ptr_unlink(&ztree, udb); - return 0; -} - -void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen, - struct timespec* mtime) -{ - udb_ptr z; - if(udb_zone_search(udb, &z, dname, dlen)) { - mtime->tv_sec = ZONE(&z)->mtime; - mtime->tv_nsec = ZONE(&z)->mtime_nsec; - udb_ptr_unlink(&z, udb); - return; - } - mtime->tv_sec = 0; - mtime->tv_nsec = 0; -} - -void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str) -{ - /* delete original log str (if any) */ - if(ZONE(zone)->log_str.data) { - udb_ptr s; - size_t sz; - udb_ptr_new(&s, udb, &ZONE(zone)->log_str); - udb_rptr_zero(&ZONE(zone)->log_str, udb); - sz = strlen((char*)udb_ptr_data(&s))+1; - udb_ptr_free_space(&s, udb, sz); - } - - /* set new log str */ - if(str) { - udb_ptr s; - size_t sz = strlen(str)+1; - if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) { - return; /* failed to allocate log string */ - } - memmove(udb_ptr_data(&s), str, sz); - udb_rptr_set_ptr(&ZONE(zone)->log_str, udb, &s); - udb_ptr_unlink(&s, udb); - } -} - -void udb_zone_set_file_str(udb_base* udb, udb_ptr* zone, const char* str) -{ - /* delete original file str (if any) */ - if(ZONE(zone)->file_str.data) { - udb_ptr s; - size_t sz; - udb_ptr_new(&s, udb, &ZONE(zone)->file_str); - udb_rptr_zero(&ZONE(zone)->file_str, udb); - sz = strlen((char*)udb_ptr_data(&s))+1; - udb_ptr_free_space(&s, udb, sz); - } - - /* set new file str */ - if(str) { - udb_ptr s; - size_t sz = strlen(str)+1; - if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) { - return; /* failed to allocate file string */ - } - memmove(udb_ptr_data(&s), str, sz); - udb_rptr_set_ptr(&ZONE(zone)->file_str, udb, &s); - udb_ptr_unlink(&s, udb); - } -} - -const char* udb_zone_get_file_str(udb_base* udb, const uint8_t* dname, - size_t dlen) -{ - udb_ptr z; - if(udb_zone_search(udb, &z, dname, dlen)) { - const char* str; - if(ZONE(&z)->file_str.data) { - udb_ptr s; - udb_ptr_new(&s, udb, &ZONE(&z)->file_str); - str = (const char*)udb_ptr_data(&s); - udb_ptr_unlink(&s, udb); - } else str = NULL; - udb_ptr_unlink(&z, udb); - return str; - } - return NULL; -} - -#ifdef NSEC3 -/** select the nsec3param for nsec3 usage */ -static void -select_nsec3_param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) -{ - udb_ptr rr; - udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs); - while(rr.data) { - if(RR(&rr)->len >= 5 && RR(&rr)->wire[0] == NSEC3_SHA1_HASH && - RR(&rr)->wire[1] == 0) { - udb_rptr_set_ptr(&ZONE(zone)->nsec3param, udb, &rr); - udb_ptr_unlink(&rr, udb); - return; - } - udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next); - } - udb_ptr_unlink(&rr, udb); -} - -const char* -udb_nsec3param_string(udb_ptr* rr) -{ - /* max saltlenth plus first couple of numbers (3+1+5+1+3+1) */ - static char params[MAX_RDLENGTH*2+16]; - char* p; - assert(RR(rr)->len >= 5); - p = params + snprintf(params, sizeof(params), "%u %u %u ", - (unsigned)RR(rr)->wire[0], (unsigned)RR(rr)->wire[1], - (unsigned)read_uint16(&RR(rr)->wire[2])); - if(RR(rr)->wire[4] == 0) { - *p++ = '-'; - } else { - assert(RR(rr)->len >= 5+RR(rr)->wire[4]); - p += hex_ntop(&RR(rr)->wire[5], RR(rr)->wire[4], p, - sizeof(params)-strlen(params)-1); - } - *p = 0; - return params; -} - -/** look in zone for new selected nsec3param record from rrset */ -static void -zone_hash_nsec3param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset) -{ - select_nsec3_param(udb, zone, rrset); - if(ZONE(zone)->nsec3param.data == 0) - return; - /* prettyprint the nsec3 parameters we are using */ - if(2 <= verbosity) { - udb_ptr par; - udb_ptr_new(&par, udb, &ZONE(zone)->nsec3param); - VERBOSITY(1, (LOG_INFO, "rehash of zone %s with parameters %s", - wiredname2str(ZONE(zone)->name), - udb_nsec3param_string(&par))); - udb_ptr_unlink(&par, udb); - } -} -#endif /* NSEC3 */ - -/** create a new domain name */ -static int -domain_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, - udb_ptr* result) -{ - udb_ptr dtree, node; - /* create domain chunk */ - if(!udb_ptr_alloc_space(result, udb, udb_chunk_type_domain, - sizeof(struct domain_d)+nmlen)) - return 0; - udb_rel_ptr_init(&DOMAIN(result)->node); - udb_rel_ptr_init(&DOMAIN(result)->rrsets); - DOMAIN(result)->namelen = nmlen; - memmove(DOMAIN(result)->name, nm, nmlen); - - /* insert into domain tree */ - udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); - if(!udb_radname_insert(udb, &dtree, nm, nmlen, result, &node)) { - udb_ptr_free_space(result, udb, sizeof(struct domain_d)+nmlen); - udb_ptr_unlink(&dtree, udb); - return 0; - } - udb_rptr_set_ptr(&DOMAIN(result)->node, udb, &node); - udb_ptr_unlink(&dtree, udb); - udb_ptr_unlink(&node, udb); - return 1; -} - -int -udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, - udb_ptr* result) -{ - int r; - udb_ptr dtree; - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - udb_ptr_new(&dtree, udb, &ZONE(zone)->domains); - r = udb_radname_search(udb, &dtree, nm, nmlen, result); - if(result->data) - udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem); - udb_ptr_unlink(&dtree, udb); - return r && result->data; -} - -/** find or create a domain name in the zone domain tree */ -static int -domain_find_or_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, - size_t nmlen, udb_ptr* result) -{ - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - if(udb_domain_find(udb, zone, nm, nmlen, result)) - return 1; - return domain_create(udb, zone, nm, nmlen, result); -} - -/** remove rrset from the domain name rrset-list */ -static void -domain_remove_rrset(udb_base* udb, udb_ptr* domain, uint16_t t) -{ - udb_ptr p, prev; - assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); - udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); - udb_ptr_init(&prev, udb); - while(p.data) { - if(RRSET(&p)->type == t) { - /* remove it */ - if(prev.data == 0) { - /* first rrset */ - udb_rptr_set_rptr(&DOMAIN(domain)->rrsets, - udb, &RRSET(&p)->next); - } else { - udb_rptr_set_rptr(&RRSET(&prev)->next, - udb, &RRSET(&p)->next); - } - udb_ptr_unlink(&prev, udb); - rrset_delete(udb, &p); - return; - } - udb_ptr_set_ptr(&prev, udb, &p); - udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); - } - /* rrset does not exist */ - udb_ptr_unlink(&prev, udb); - udb_ptr_unlink(&p, udb); -} - -/** create rrset in the domain rrset list */ -static int -rrset_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) -{ - /* create it */ - if(!udb_ptr_alloc_space(res, udb, udb_chunk_type_rrset, - sizeof(struct rrset_d))) - return 0; - udb_rel_ptr_init(&RRSET(res)->next); - udb_rel_ptr_init(&RRSET(res)->rrs); - RRSET(res)->type = t; - -#if 0 - /* link it in, at the front */ - udb_rptr_set_rptr(&RRSET(res)->next, udb, &DOMAIN(domain)->rrsets); - udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); -#else - /* preserve RRset order, link at end */ - if(DOMAIN(domain)->rrsets.data == 0) { - udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res); - } else { - udb_ptr p; - udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets); - while(RRSET(&p)->next.data) - udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next); - udb_rptr_set_ptr(&RRSET(&p)->next, udb, res); - udb_ptr_unlink(&p, udb); - } -#endif - return 1; -} - -int -udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) -{ - assert(udb_ptr_get_type(domain) == udb_chunk_type_domain); - udb_ptr_init(res, udb); - udb_ptr_set_rptr(res, udb, &DOMAIN(domain)->rrsets); - while(res->data) { - if(RRSET(res)->type == t) - return 1; - udb_ptr_set_rptr(res, udb, &RRSET(res)->next); - } - /* rrset does not exist and res->data is conveniently zero */ - return 0; -} - -/** find or create rrset in the domain rrset list */ -static int -rrset_find_or_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res) -{ - if(udb_rrset_find(udb, domain, t, res)) - return 1; - return rrset_create(udb, domain, t, res); -} - -/** see if RR matches type, class and rdata */ -static int -rr_match(udb_ptr* rr, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) -{ - return RR(rr)->type == t && RR(rr)->klass == k && - RR(rr)->len == rdatalen && - memcmp(RR(rr)->wire, rdata, rdatalen) == 0; -} - -/** see if RR exists in the RR list that matches the rdata, and return it */ -static int -rr_search(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, - uint8_t* rdata, size_t rdatalen, udb_ptr* result) -{ - assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); - udb_ptr_init(result, udb); - udb_ptr_set_rptr(result, udb, &RRSET(rrset)->rrs); - while(result->data) { - if(rr_match(result, t, k, rdata, rdatalen)) - return 1; /* found */ - udb_ptr_set_rptr(result, udb, &RR(result)->next); - } - /* not found and result->data is conveniently zero */ - return 0; -} - -/** create RR chunk */ -static int -rr_create(udb_base* udb, uint16_t t, uint16_t k, uint32_t ttl, - uint8_t* rdata, size_t rdatalen, udb_ptr* rr) -{ - if(!udb_ptr_alloc_space(rr, udb, udb_chunk_type_rr, - sizeof(struct rr_d)+rdatalen)) - return 0; - udb_rel_ptr_init(&RR(rr)->next); - RR(rr)->type = t; - RR(rr)->klass = k; - RR(rr)->ttl = ttl; - RR(rr)->len = rdatalen; - memmove(RR(rr)->wire, rdata, rdatalen); - return 1; -} - -/** add an RR to an RRset. */ -static int -rrset_add_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, - uint32_t ttl, uint8_t* rdata, size_t rdatalen) -{ - udb_ptr rr; - assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); - /* create it */ - if(!rr_create(udb, t, k, ttl, rdata, rdatalen, &rr)) - return 0; - - /* add at end, to preserve order of RRs */ - if(RRSET(rrset)->rrs.data == 0) { - udb_rptr_set_ptr(&RRSET(rrset)->rrs, udb, &rr); - } else { - udb_ptr lastrr; - udb_ptr_new(&lastrr, udb, &RRSET(rrset)->rrs); - while(RR(&lastrr)->next.data) - udb_ptr_set_rptr(&lastrr, udb, &RR(&lastrr)->next); - udb_rptr_set_ptr(&RR(&lastrr)->next, udb, &rr); - udb_ptr_unlink(&lastrr, udb); - } - udb_ptr_unlink(&rr, udb); - return 1; -} - -/** remove an RR from an RRset. return 0 if RR did not exist. */ -static int -rrset_del_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k, - uint8_t* rdata, size_t rdatalen) -{ - udb_ptr p, prev; - assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset); - udb_ptr_new(&p, udb, &RRSET(rrset)->rrs); - udb_ptr_init(&prev, udb); - while(p.data) { - if(rr_match(&p, t, k, rdata, rdatalen)) { - /* remove it */ - if(prev.data == 0) { - /* first in list */ - udb_rptr_set_rptr(&RRSET(rrset)->rrs, udb, - &RR(&p)->next); - } else { - udb_rptr_set_rptr(&RR(&prev)->next, udb, - &RR(&p)->next); - } - udb_ptr_unlink(&prev, udb); - rr_delete(udb, &p); - return 1; - } - udb_ptr_set_ptr(&prev, udb, &p); - udb_ptr_set_rptr(&p, udb, &RR(&p)->next); - } - /* not found */ - udb_ptr_unlink(&prev, udb); - udb_ptr_unlink(&p, udb); - return 0; -} - -int -udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, - uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen) -{ - udb_ptr domain, rrset, rr; - int created_rrset = 0; - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - - /* find or create domain */ - if(!domain_find_or_create(udb, zone, nm, nmlen, &domain)) { - return 0; - } - /* find or create rrset(type) */ - if(!rrset_find_or_create(udb, &domain, t, &rrset)) { - goto exit_clean_domain; - } - if(RRSET(&rrset)->rrs.data == 0) - created_rrset = 1; - /* test for duplicate RRs */ - if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { - udb_ptr_unlink(&rr, udb); - goto exit_clean_domain_rrset; - } - /* add RR to rrset */ - if(!rrset_add_rr(udb, &rrset, t, k, ttl, rdata, rdatalen)) { - exit_clean_domain_rrset: - /* if rrset was created, remove it */ - if(RRSET(&rrset)->rrs.data == 0) { - udb_ptr_zero(&rrset, udb); - domain_remove_rrset(udb, &domain, t); - } - udb_ptr_unlink(&rrset, udb); - exit_clean_domain: - /* if domain created, delete it */ - if(DOMAIN(&domain)->rrsets.data == 0) - domain_delete_unlink(udb, zone, &domain); - udb_ptr_unlink(&domain, udb); - return 0; - } - /* success, account changes */ - if(created_rrset) - ZONE(zone)->rrset_count ++; - ZONE(zone)->rr_count ++; -#ifdef NSEC3 - if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0) - zone_hash_nsec3param(udb, zone, &rrset); -#endif /* NSEC3 */ - udb_ptr_unlink(&domain, udb); - udb_ptr_unlink(&rrset, udb); - return 1; -} - -void -udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen, - uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen) -{ - udb_ptr domain, rrset; - assert(udb_ptr_get_type(zone) == udb_chunk_type_zone); - /* find the domain */ - if(!udb_domain_find(udb, zone, nm, nmlen, &domain)) - return; - /* find the rrset */ - if(!udb_rrset_find(udb, &domain, t, &rrset)) { - udb_ptr_unlink(&domain, udb); - return; - } - /* remove the RR */ -#ifdef NSEC3 - if(t == TYPE_NSEC3PARAM) { - udb_ptr rr; - if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) { - if(rr.data == ZONE(zone)->nsec3param.data) { - udb_rptr_zero(&ZONE(zone)->nsec3param, udb); - } - udb_ptr_unlink(&rr, udb); - } - } -#endif /* NSEC3 */ - if(!rrset_del_rr(udb, &rrset, t, k, rdata, rdatalen)) { - /* rr did not exist */ - udb_ptr_unlink(&domain, udb); - udb_ptr_unlink(&rrset, udb); - return; - } - ZONE(zone)->rr_count --; -#ifdef NSEC3 - if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0 && - RRSET(&rrset)->rrs.data != 0) { - zone_hash_nsec3param(udb, zone, &rrset); - } -#endif /* NSEC3 */ - /* see we we can remove the rrset too */ - if(RRSET(&rrset)->rrs.data == 0) { - udb_ptr_zero(&rrset, udb); - domain_remove_rrset(udb, &domain, t); - ZONE(zone)->rrset_count --; - } - /* see if we can remove the domain name too */ - if(DOMAIN(&domain)->rrsets.data == 0) { - domain_delete_unlink(udb, zone, &domain); - } - udb_ptr_unlink(&rrset, udb); - udb_ptr_unlink(&domain, udb); -} - -void -udb_zone_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, - void* arg) -{ - struct zone_d* p = (struct zone_d*)d; - assert(s >= sizeof(struct zone_d)+p->namelen); - (void)s; - (*cb)(base, &p->node, arg); - (*cb)(base, &p->domains, arg); - (*cb)(base, &p->nsec3param, arg); - (*cb)(base, &p->log_str, arg); - (*cb)(base, &p->file_str, arg); -} - -void -udb_domain_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, - void* arg) -{ - struct domain_d* p = (struct domain_d*)d; - assert(s >= sizeof(struct domain_d)+p->namelen); - (void)s; - (*cb)(base, &p->node, arg); - (*cb)(base, &p->rrsets, arg); -} - -void -udb_rrset_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, - void* arg) -{ - struct rrset_d* p = (struct rrset_d*)d; - assert(s >= sizeof(struct rrset_d)); - (void)s; - (*cb)(base, &p->next, arg); - (*cb)(base, &p->rrs, arg); -} - -void -udb_rr_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, - void* arg) -{ - struct rr_d* p = (struct rr_d*)d; - assert(s >= sizeof(struct rr_d)+p->len); - (void)s; - (*cb)(base, &p->next, arg); -} - -void -udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, - void* arg) -{ - struct task_list_d* p = (struct task_list_d*)d; - assert(s >= p->size); - (void)s; - (*cb)(base, &p->next, arg); -} - -void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg) -{ - (void)warg; - switch(t) { - case udb_chunk_type_radtree: - udb_radix_tree_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_radnode: - udb_radix_node_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_radarray: - udb_radix_array_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_zone: - udb_zone_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_domain: - udb_domain_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_rrset: - udb_rrset_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_rr: - udb_rr_walk_chunk(base, d, s, cb, arg); - break; - case udb_chunk_type_task: - udb_task_walk_chunk(base, d, s, cb, arg); - break; - default: - /* no rel ptrs */ - break; - } -} diff --git a/usr.sbin/nsd/udbzone.h b/usr.sbin/nsd/udbzone.h deleted file mode 100644 index 8c5c5325581..00000000000 --- a/usr.sbin/nsd/udbzone.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * udbzone -- store zone and rrset information in udb file. - * - * Copyright (c) 2011, NLnet Labs. See LICENSE for license. - */ -#ifndef UDB_ZONE_H -#define UDB_ZONE_H -#include "udb.h" -#include "dns.h" -#include "udbradtree.h" - -/** - * Store the DNS information in udb file on disk. - * udb_global - * | - * v - * zonetree -> zone -- zone_name - * radtree |--> nsec3param - * |--> log_str - * |--> file_str - * | - * v - * domain --> rrset -> rr - * radtree list list - * |-- name - */ - -/** zone information in the nsd.udb. Name allocated after it. */ -struct zone_d { - /** radtree node in the zonetree for this zone */ - udb_rel_ptr node; - /** the radtree for the domain names in the zone */ - udb_rel_ptr domains; - /** the NSEC3PARAM rr used for hashing (or 0), rr_d pointer */ - udb_rel_ptr nsec3param; - /** the log_str for the AXFR change, or 0 */ - udb_rel_ptr log_str; - /** the file name when read from a file, or 0 */ - udb_rel_ptr file_str; - /** modification time, time when the zone data was changed */ - uint64_t mtime; - /** modification time, nsecs */ - uint64_t mtime_nsec; - /** number of RRsets in the zone */ - uint64_t rrset_count; - /** number of RRs in the zone */ - uint64_t rr_count; - /** the length of the zone name */ - udb_radstrlen_type namelen; - /** if the zone is expired */ - uint8_t expired; - /** if the zone has been changed by AXFR */ - uint8_t is_changed; - /** the zone (wire uncompressed) name in DNS format */ - uint8_t name[0]; -}; - -/** domain name in the nametree. name allocated after it */ -struct domain_d { - /** radtree node in the nametree for this domain */ - udb_rel_ptr node; - /** the list of rrsets for this name, single linked */ - udb_rel_ptr rrsets; - /** length of the domain name */ - udb_radstrlen_type namelen; - /** the domain (wire uncompressed) name in DNS format */ - uint8_t name[0]; -}; - -/** rrset information. */ -struct rrset_d { - /** next in rrset list */ - udb_rel_ptr next; - /** the singly linked list of rrs for this rrset */ - udb_rel_ptr rrs; - /** type of the RRs in this rrset (host order) */ - uint16_t type; -}; - -/** rr information; wireformat data allocated after it */ -struct rr_d { - /** next in rr list */ - udb_rel_ptr next; - /** type (host order) */ - uint16_t type; - /** class (host order) */ - uint16_t klass; - /** ttl (host order) */ - uint32_t ttl; - /** length of wireformat */ - uint16_t len; - /** wireformat of rdata (without rdatalen) */ - uint8_t wire[0]; -}; - -/** init an udb for use as DNS store */ -int udb_dns_init_file(udb_base* udb); -/** de-init an udb for use as DNS store */ -void udb_dns_deinit_file(udb_base* udb); - -/** create a zone */ -int udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname, - size_t dlen); -/** clear all RRsets from a zone */ -void udb_zone_clear(udb_base* udb, udb_ptr* zone); -/** delete a zone */ -void udb_zone_delete(udb_base* udb, udb_ptr* zone); -/** find a zone by name (exact match) */ -int udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname, - size_t dlen); -/** get modification time for zone or 0 */ -void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen, - struct timespec* mtime); -/** set log str in udb, or remove it */ -void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str); -/** set file str in udb, or remove it */ -void udb_zone_set_file_str(udb_base* udb, udb_ptr* zone, const char* str); -/** get file string for zone or NULL */ -const char* udb_zone_get_file_str(udb_base* udb, const uint8_t* dname, - size_t dlen); -/** find a domain name in the zone domain tree */ -int udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, - size_t nmlen, udb_ptr* result); -/** find rrset in domain */ -int udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res); - -/** add an RR to a zone */ -int udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, - size_t nmlen, uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, - size_t rdatalen); -/** del an RR from a zone */ -void udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, - size_t nmlen, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen); - -/** get pretty string for nsec3parameters (static buffer returned) */ -const char* udb_nsec3param_string(udb_ptr* rr); - -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_zone */ -void udb_zone_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_domain */ -void udb_domain_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_rrset */ -void udb_rrset_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); -/** for use in udb-walkfunc, walks relptrs in udb_chunk_type_rr */ -void udb_rr_walk_chunk(void* base, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); - -/** walk through relptrs in registered types */ -void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s, - udb_walk_relptr_cb* cb, void* arg); - -#define ZONE(ptr) ((struct zone_d*)UDB_PTR(ptr)) -#define DOMAIN(ptr) ((struct domain_d*)UDB_PTR(ptr)) -#define RRSET(ptr) ((struct rrset_d*)UDB_PTR(ptr)) -#define RR(ptr) ((struct rr_d*)UDB_PTR(ptr)) - -#endif /* UDB_ZONE_H */ diff --git a/usr.sbin/nsd/util/proxy_protocol.c b/usr.sbin/nsd/util/proxy_protocol.c new file mode 100644 index 00000000000..a1880497404 --- /dev/null +++ b/usr.sbin/nsd/util/proxy_protocol.c @@ -0,0 +1,199 @@ +/* + * util/proxy_protocol.c - event notification + * + * Copyright (c) 2022, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains PROXY protocol functions. + */ +#include "util/proxy_protocol.h" + +/** + * Internal struct initialized with function pointers for writing uint16 and + * uint32. + */ +struct proxy_protocol_data { + void (*write_uint16)(void* buf, uint16_t data); + void (*write_uint32)(void* buf, uint32_t data); +}; +struct proxy_protocol_data pp_data; + +/** + * Internal lookup table; could be further generic like sldns_lookup_table + * for all the future generic stuff. + */ +struct proxy_protocol_lookup_table { + int id; + const char *text; +}; + +/** + * Internal parsing error text; could be exposed with pp_lookup_error. + */ +static struct proxy_protocol_lookup_table pp_parse_errors_data[] = { + { PP_PARSE_NOERROR, "no parse error" }, + { PP_PARSE_SIZE, "not enough space for header" }, + { PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" }, + { PP_PARSE_UNKNOWN_CMD, "unknown command" }, + { PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" }, +}; + +void +pp_init(void (*write_uint16)(void* buf, uint16_t data), + void (*write_uint32)(void* buf, uint32_t data)) { + pp_data.write_uint16 = write_uint16; + pp_data.write_uint32 = write_uint32; +} + +const char* +pp_lookup_error(enum pp_parse_errors error) { + return pp_parse_errors_data[error].text; +} + +size_t +pp2_write_to_buf(uint8_t* buf, size_t buflen, +#ifdef INET6 + struct sockaddr_storage* src, +#else + struct sockaddr_in* src, +#endif + int stream) +{ + int af; + size_t expected_size; + if(!src) return 0; + af = (int)((struct sockaddr_in*)src)->sin_family; + expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36); + if(buflen < expected_size) { + return 0; + } + /* sig */ + memcpy(buf, PP2_SIG, PP2_SIG_LEN); + buf += PP2_SIG_LEN; + /* version and command */ + *buf = (PP2_VERSION << 4) | PP2_CMD_PROXY; + buf++; + switch(af) { + case AF_INET: + /* family and protocol */ + *buf = (PP2_AF_INET<<4) | + (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); + buf++; + /* length */ + (*pp_data.write_uint16)(buf, 12); + buf += 2; + /* src addr */ + memcpy(buf, + &((struct sockaddr_in*)src)->sin_addr.s_addr, 4); + buf += 4; + /* dst addr */ + (*pp_data.write_uint32)(buf, 0); + buf += 4; + /* src port */ + memcpy(buf, + &((struct sockaddr_in*)src)->sin_port, 2); + buf += 2; + /* dst addr */ + /* dst port */ + (*pp_data.write_uint16)(buf, 12); + break; +#ifdef INET6 + case AF_INET6: + /* family and protocol */ + *buf = (PP2_AF_INET6<<4) | + (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); + buf++; + /* length */ + (*pp_data.write_uint16)(buf, 36); + buf += 2; + /* src addr */ + memcpy(buf, + &((struct sockaddr_in6*)src)->sin6_addr, 16); + buf += 16; + /* dst addr */ + memset(buf, 0, 16); + buf += 16; + /* src port */ + memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2); + buf += 2; + /* dst port */ + (*pp_data.write_uint16)(buf, 0); + break; +#endif /* INET6 */ + case AF_UNIX: + /* fallthrough */ + default: + return 0; + } + return expected_size; +} + +int +pp2_read_header(uint8_t* buf, size_t buflen) +{ + size_t size; + struct pp2_header* header = (struct pp2_header*)buf; + /* Try to fail all the unsupported cases first. */ + if(buflen < PP2_HEADER_SIZE) { + return PP_PARSE_SIZE; + } + /* Check for PROXYv2 header */ + if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 || + ((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) { + return PP_PARSE_WRONG_HEADERv2; + } + /* Check the length */ + size = PP2_HEADER_SIZE + ntohs(header->len); + if(buflen < size) { + return PP_PARSE_SIZE; + } + /* Check for supported commands */ + if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL && + (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { + return PP_PARSE_UNKNOWN_CMD; + } + /* Check for supported family and protocol */ + if(header->fam_prot != PP2_UNSPEC_UNSPEC && + header->fam_prot != PP2_INET_STREAM && + header->fam_prot != PP2_INET_DGRAM && + header->fam_prot != PP2_INET6_STREAM && + header->fam_prot != PP2_INET6_DGRAM && + header->fam_prot != PP2_UNIX_STREAM && + header->fam_prot != PP2_UNIX_DGRAM) { + return PP_PARSE_UNKNOWN_FAM_PROT; + } + /* We have a correct header */ + return PP_PARSE_NOERROR; +} diff --git a/usr.sbin/nsd/util/proxy_protocol.h b/usr.sbin/nsd/util/proxy_protocol.h new file mode 100644 index 00000000000..ca81065bf49 --- /dev/null +++ b/usr.sbin/nsd/util/proxy_protocol.h @@ -0,0 +1,177 @@ +/* + * util/proxy_protocol.h - PROXY protocol + * + * Copyright (c) 2022, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains PROXY protocol structs and functions. + * Only v2 is supported. TLVs are not currently supported. + */ +#ifndef PROXY_PROTOCOL_H +#define PROXY_PROTOCOL_H + +#include "config.h" + +/** PROXYv2 minimum header size */ +#define PP2_HEADER_SIZE 16 + +/** PROXYv2 header signature */ +#define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" +#define PP2_SIG_LEN 12 + +/** PROXYv2 version (protocol value) */ +#define PP2_VERSION 0x2 + +/** + * PROXYv2 command (protocol value). + */ +enum pp2_command { + PP2_CMD_LOCAL = 0x0, + PP2_CMD_PROXY = 0x1 +}; + +/** + * PROXYv2 address family (protocol value). + */ +enum pp2_af { + PP2_AF_UNSPEC = 0x0, + PP2_AF_INET = 0x1, + PP2_AF_INET6 = 0x2, + PP2_AF_UNIX = 0x3 +}; + +/** + * PROXYv2 protocol (protocol value). + */ +enum pp2_protocol { + PP2_PROT_UNSPEC = 0x0, + PP2_PROT_STREAM = 0x1, + PP2_PROT_DGRAM = 0x2 +}; + +/** + * Expected combinations of address family and protocol values used in checks. + */ +enum pp2_af_protocol_combination { + PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC, + PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM, + PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM, + PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM, + PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM, + PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM, + PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM +}; + +/** + * PROXYv2 header. + */ +struct pp2_header { + uint8_t sig[PP2_SIG_LEN]; + uint8_t ver_cmd; + uint8_t fam_prot; + uint16_t len; + union { + struct { /* for TCP/UDP over IPv4, len = 12 */ + uint32_t src_addr; + uint32_t dst_addr; + uint16_t src_port; + uint16_t dst_port; + } addr4; + struct { /* for TCP/UDP over IPv6, len = 36 */ + uint8_t src_addr[16]; + uint8_t dst_addr[16]; + uint16_t src_port; + uint16_t dst_port; + } addr6; + struct { /* for AF_UNIX sockets, len = 216 */ + uint8_t src_addr[108]; + uint8_t dst_addr[108]; + } addru; + } addr; +}; + +/** + * PROXY parse errors. + */ +enum pp_parse_errors { + PP_PARSE_NOERROR = 0, + PP_PARSE_SIZE, + PP_PARSE_WRONG_HEADERv2, + PP_PARSE_UNKNOWN_CMD, + PP_PARSE_UNKNOWN_FAM_PROT, +}; + +/** + * Initialize the internal proxy structure. + * @param write_uint16: pointer to a function that can write uint16. + * @param write_uint32: pointer to a function that can write uint32. + */ +void pp_init(void (*write_uint16)(void* buf, uint16_t data), + void (*write_uint32)(void* buf, uint32_t data)); + +/** + * Lookup the parsing error description. + * @param error: parsing error from pp2_read_header. + * @return the description. + */ +const char* pp_lookup_error(enum pp_parse_errors error); + +/** + * Write a PROXYv2 header at the current position of the buffer. + * @param buf: pointer to the buffer to write data to. + * @param buflen: available size on the buffer. + * @param src: the source address. + * @param stream: if the protocol is stream or datagram. + * @return 1 on success, 0 on failure. + */ +size_t pp2_write_to_buf(uint8_t* buf, size_t buflen, +#ifdef INET6 + struct sockaddr_storage* src, +#else + struct sockaddr_in* src, +#endif + int stream); + +/** + * Read a PROXYv2 header from the current position of the buffer. + * It does initial validation and returns a pointer to the buffer position on + * success. + * @param buf: pointer to the buffer data to read from. + * @param buflen: available size on the buffer. + * @return parsing error, 0 on success. + */ +int pp2_read_header(uint8_t* buf, size_t buflen); + +#endif /* PROXY_PROTOCOL_H */ diff --git a/usr.sbin/nsd/xfr-inspect.c b/usr.sbin/nsd/xfr-inspect.c index c87ff47ebcc..e6a52a226d3 100644 --- a/usr.sbin/nsd/xfr-inspect.c +++ b/usr.sbin/nsd/xfr-inspect.c @@ -5,7 +5,6 @@ */ #include "config.h" -#include "udbzone.h" #include "util.h" #include "buffer.h" #include "packet.h" diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index b7e1628c725..9882e3d5be7 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/xfrd.c @@ -570,7 +570,10 @@ xfrd_process_soa_info_task(struct task_list_d* task) xfrd_xfr_type* xfr; xfrd_xfr_type* prev_xfr; enum soainfo_hint hint; - time_t before, acquired = 0; +#ifndef NDEBUG + time_t before; +#endif + time_t acquired = 0; DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: process SOAINFO %s", dname_to_string(task->zname, 0))); zone = (xfrd_zone_type*)rbtree_search(xfrd->zones, task->zname); @@ -582,7 +585,9 @@ xfrd_process_soa_info_task(struct task_list_d* task) hint == soainfo_bad ? "kept" : "lost")); soa_ptr = NULL; /* discard all updates */ +#ifndef NDEBUG before = xfrd_time(); +#endif } else { uint8_t* p = (uint8_t*)task->zname + dname_total_size( task->zname); @@ -617,7 +622,9 @@ xfrd_process_soa_info_task(struct task_list_d* task) (unsigned)ntohl(soa.serial))); /* discard all updates received before initial reload unless reload was successful */ +#ifndef NDEBUG before = xfrd->reload_cmd_first_sent; +#endif } if(!zone) { @@ -862,7 +869,6 @@ xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname) void xfrd_free_namedb(struct nsd* nsd) { - namedb_close_udb(nsd->db); namedb_close(nsd->db); nsd->db = 0; } @@ -2684,22 +2690,6 @@ xfrd_get_temp_buffer() return xfrd->packet; } -#ifdef BIND8_STATS -/** process stat info task */ -static void -xfrd_process_stat_info_task(xfrd_state_type* xfrd, struct task_list_d* task) -{ - size_t i; - stc_type* p = (void*)((char*)task->zname + sizeof(struct nsdst)); - stats_add(&xfrd->nsd->st, (struct nsdst*)task->zname); - for(i=0; i<xfrd->nsd->child_count; i++) { - xfrd->nsd->children[i].query_count += *p++; - } - /* got total, now see if users are interested in these statistics */ - daemon_remote_process_stats(xfrd->nsd->rc); -} -#endif /* BIND8_STATS */ - #ifdef USE_ZONE_STATS /** process zonestat inc task */ static void @@ -2716,18 +2706,13 @@ xfrd_process_zonestat_inc_task(xfrd_state_type* xfrd, struct task_list_d* task) static void xfrd_handle_taskresult(xfrd_state_type* xfrd, struct task_list_d* task) { -#ifndef BIND8_STATS +#ifndef USE_ZONE_STATS (void)xfrd; #endif switch(task->task_type) { case task_soa_info: xfrd_process_soa_info_task(task); break; -#ifdef BIND8_STATS - case task_stat_info: - xfrd_process_stat_info_task(xfrd, task); - break; -#endif /* BIND8_STATS */ #ifdef USE_ZONE_STATS case task_zonestat_inc: xfrd_process_zonestat_inc_task(xfrd, task); diff --git a/usr.sbin/nsd/xfrd.h b/usr.sbin/nsd/xfrd.h index b6a840f81d5..f2b82154089 100644 --- a/usr.sbin/nsd/xfrd.h +++ b/usr.sbin/nsd/xfrd.h @@ -72,6 +72,8 @@ struct xfrd_state { size_t zonestat_clear_num; /* array of malloced entries with cumulative cleared stat values */ struct nsdst** zonestat_clear; + /* array of child_count size with cumulative cleared stat values */ + struct nsdst* stat_clear; /* timer for NSD reload */ struct timeval reload_timeout; |