summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-12-10 11:48:01 +0000
committerLaurent Bercot <ska@appnovation.com>2023-12-10 11:48:01 +0000
commitb8d0f83e6cea9640a7ee4402c163ad812237355d (patch)
tree57a64ac8aa0e98c40db8c36e96e7379490e44dbf
downloadshibari-b8d0f83e6cea9640a7ee4402c163ad812237355d.tar.xz
Initial commit
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--.gitignore12
-rw-r--r--AUTHORS5
-rw-r--r--CONTRIBUTING5
-rw-r--r--COPYING13
-rw-r--r--DCO37
-rw-r--r--INSTALL175
-rw-r--r--Makefile148
-rw-r--r--NEWS6
-rw-r--r--README23
-rw-r--r--README.macos3
-rw-r--r--README.solaris11
-rwxr-xr-xconfigure459
-rw-r--r--doc/index.html181
-rw-r--r--doc/shibari-server-tcp.html213
-rw-r--r--doc/shibari-server-udp.html163
-rw-r--r--doc/upgrade.html28
-rw-r--r--package/deps-build3
-rw-r--r--package/deps.mak66
-rw-r--r--package/info4
-rw-r--r--package/modes2
-rw-r--r--package/targets.mak7
-rwxr-xr-xpatch-for-solaris21
-rw-r--r--src/cache/dcache-internal.h18
-rw-r--r--src/cache/dcache_add.c85
-rw-r--r--src/cache/dcache_clean_expired.c20
-rw-r--r--src/cache/dcache_delete.c19
-rw-r--r--src/cache/dcache_free.c22
-rw-r--r--src/cache/dcache_init.c55
-rw-r--r--src/cache/dcache_load.c81
-rw-r--r--src/cache/dcache_save.c73
-rw-r--r--src/cache/dcache_search.c15
-rw-r--r--src/cache/deps-lib/dcache8
-rw-r--r--src/common/deps-lib/shibari-common10
-rw-r--r--src/common/shibari_log_answer.c36
-rw-r--r--src/common/shibari_log_exit.c14
-rw-r--r--src/common/shibari_log_query.c18
-rw-r--r--src/common/shibari_log_queryplus.c24
-rw-r--r--src/common/shibari_log_start.c17
-rw-r--r--src/common/shibari_util_get_prefixlen.c14
-rw-r--r--src/common/shibari_util_qtype_num.c121
-rw-r--r--src/common/shibari_util_qtype_str.c285
-rw-r--r--src/common/shibari_util_rcode_str.c41
-rw-r--r--src/include/shibari/cache.h8
-rw-r--r--src/include/shibari/client.h6
-rw-r--r--src/include/shibari/common.h9
-rw-r--r--src/include/shibari/constants.h109
-rw-r--r--src/include/shibari/dcache.h54
-rw-r--r--src/include/shibari/log.h20
-rw-r--r--src/include/shibari/packet.h39
-rw-r--r--src/include/shibari/server.h10
-rw-r--r--src/include/shibari/shibari.h11
-rw-r--r--src/include/shibari/tdb.h29
-rw-r--r--src/include/shibari/util.h14
-rw-r--r--src/server/deps-exe/shibari-server-tcp4
-rw-r--r--src/server/deps-exe/shibari-server-udp6
-rw-r--r--src/server/deps-lib/shibari-server13
-rw-r--r--src/server/shibari-server-tcp.c235
-rw-r--r--src/server/shibari-server-udp.c207
-rw-r--r--src/server/shibari_packet_add_glue.c48
-rw-r--r--src/server/shibari_packet_add_rr.c46
-rw-r--r--src/server/shibari_packet_assert_authority.c18
-rw-r--r--src/server/shibari_packet_begin.c32
-rw-r--r--src/server/shibari_packet_end.c13
-rw-r--r--src/server/shibari_packet_init.c14
-rw-r--r--src/server/shibari_packet_tdb_answer_query.c93
-rw-r--r--src/server/shibari_tdb_entry_parse.c56
-rw-r--r--src/server/shibari_tdb_extract_domain.c17
-rw-r--r--src/server/shibari_tdb_find_authority.c46
-rw-r--r--src/server/shibari_tdb_read_entry.c22
-rwxr-xr-xtools/gen-deps.sh93
-rwxr-xr-xtools/install.sh64
71 files changed, 3897 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0552150
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.o
+*.lo
+/config.mak
+/src/include/shibari/config.h
+/libdcache.a.xyzzy
+/libdcache.so.xyzzy
+/libshibari-common.a.xyzzy
+/libshibari-common.so.xyzzy
+/libshibari-server.a.xyzzy
+/libshibari-server.so.xyzzy
+/shibari-server-tcp
+/shibari-server-udp
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6bbf321
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Main author:
+ Laurent Bercot <ska-skaware@skarnet.org>
+
+Thanks to:
+ Dan J. Bernstein <djb@cr.yp.to>
diff --git a/CONTRIBUTING b/CONTRIBUTING
new file mode 100644
index 0000000..6279422
--- /dev/null
+++ b/CONTRIBUTING
@@ -0,0 +1,5 @@
+ Please add a Signed-Off-By: line at the end of your commit,
+which certifies that you have the right and authority to pass
+it on as an open-source patch, as explicited in the Developer's
+Certificate of Origin available in this project's DCO file,
+or at https://developercertificate.org/
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..fe81b1d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,13 @@
+Copyright (c) 2023 Laurent Bercot <ska-skaware@skarnet.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/DCO b/DCO
new file mode 100644
index 0000000..8201f99
--- /dev/null
+++ b/DCO
@@ -0,0 +1,37 @@
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+(c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+(d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5e2d943
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,175 @@
+Build Instructions
+------------------
+
+* Requirements
+ ------------
+
+ - A POSIX-compliant C development environment
+ - GNU make version 3.81 or later
+ - skalibs version 2.14.0.1 or later: https://skarnet.org/software/skalibs/
+ - s6 version 2.12.0.2 or later: https://skarnet.org/software/s6/
+ - for now: s6-dns version 2.3.7.0 or later: https://skarnet.org/software/s6-dns/
+
+ This software will run on any operating system that implements
+POSIX.1-2008, available at:
+ https://pubs.opengroup.org/onlinepubs/9699919799/
+
+
+* Standard usage
+ --------------
+
+ ./configure && make && sudo make install
+
+ will work for most users.
+ It will install the binaries in /usr/bin and the static libraries in
+/usr/lib/shibari.
+
+ Please note that static libraries in /usr/lib/shibari *will not*
+be found by a default linker invocation: you need -L/usr/lib/shibari.
+Other skarnet.org software automatically handles that case if the
+default configuration is used, but if you change the configuration,
+remember to use the appropriate --with-lib configure option.
+
+ You can strip the binaries and libraries of their extra symbols via
+"make strip" before the "make install" phase. It will shave a few bytes
+off them.
+
+
+* Customization
+ -------------
+
+ You can customize paths via flags given to configure.
+ See ./configure --help for a list of all available configure options.
+
+
+* Environment variables
+ ---------------------
+
+ Controlling a build process via environment variables is a big and
+dangerous hammer. You should try and pass flags to configure instead;
+nevertheless, a few standard environment variables are recognized.
+
+ If the CC environment variable is set, its value will override compiler
+detection by configure. The --host=HOST option will still add a HOST-
+prefix to the value of CC.
+
+ The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags
+auto-detected by configure. To entirely override the flags set by
+configure instead, use make variables.
+
+
+* Make variables
+ --------------
+
+ You can invoke make with a few variables for more configuration.
+
+ CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and
+CROSS_COMPILE can all be overridden on the make command line. This is
+an even bigger hammer than running ./configure with environment
+variables, so it is advised to only do this when it is the only way of
+obtaining the behaviour you want.
+
+ DESTDIR can be given on the "make install" command line in order to
+install to a staging directory.
+
+
+* Shared libraries
+ ----------------
+
+ Software from skarnet.org is small enough that shared libraries are
+generally not worth using. Static linking is simpler and incurs less
+runtime overhead and less points of failure: so by default, shared
+libraries are not built and binaries are linked against the static
+versions of the skarnet.org libraries. Nevertheless, you can:
+ * build shared libraries: --enable-shared
+ * link binaries against shared libraries: --disable-allstatic
+
+
+* Static binaries
+ ---------------
+
+ By default, binaries are linked against static versions of all the
+libraries they depend on, except for the libc. You can enforce
+linking against the static libc with --enable-static-libc.
+
+ (If you are using a GNU/Linux system, be aware that the GNU libc
+behaves badly with static linking and produces huge executables,
+which is why it is not the default. Other libcs are better suited
+to static linking, for instance musl: http://musl-libc.org/)
+
+
+* Cross-compilation
+ -----------------
+
+ skarnet.org packages centralize all the difficulty of
+cross-compilation in one place: skalibs. Once you have
+cross-compiled skalibs, the rest is easy.
+
+ * Use the --host=HOST option to configure, HOST being the triplet
+for your target.
+ * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-)
+are accessible via your PATH environment variable.
+ * Make sure to use the correct version of skalibs for your target,
+and the correct sysdeps directory, making use of the
+--with-include, --with-lib, --with-dynlib and --with-sysdeps
+options as necessary.
+
+
+* The slashpackage convention
+ ---------------------------
+
+ The slashpackage convention (http://cr.yp.to/slashpackage.html)
+is a package installation scheme that provides a few guarantees
+over other conventions such as the FHS, for instance fixed
+absolute pathnames. skarnet.org packages support it: use the
+--enable-slashpackage option to configure, or
+--enable-slashpackage=DIR for a prefixed DIR/package tree.
+This option will activate slashpackage support during the build
+and set slashpackage-compatible installation directories.
+If $package_home is the home of the package, defined as
+DIR/package/$category/$package-$version with the variables
+read from the package/info file, then:
+
+ --dynlibdir is set to $package_home/library.so
+ --bindir is set to $package_home/command
+ --sbindir is also set to $package_home/command (slashpackage
+differentiates root-only binaries by their Unix rights, not their
+location in the filesystem)
+ --libexecdir is also set to $package_home/command (slashpackage
+does not need a specific directory for internal binaries)
+ --libdir is set to $package_home/library
+ --includedir is set to $package_home/include
+
+ --prefix is pretty much ignored when you use --enable-slashpackage.
+You should probably not use both --enable-slashpackage and --prefix.
+
+ When using slashpackage, two additional Makefile targets are
+available after "make install":
+ - "make update" changes the default version of the software to the
+freshly installed one. (This is useful when you have several installed
+versions of the same software, which slashpackage supports.)
+ - "make -L global-links" adds links from /command and /library.so to the
+default version of the binaries and shared libraries. The "-L" option to
+make is necessary because targets are symbolic links, and the default make
+behaviour is to check the pointed file's timestamp and not the symlink's
+timestamp.
+
+
+* Absolute pathnames
+ ------------------
+
+ You may want to use fixed absolute pathnames even if you're not
+following the slashpackage convention: for instance, the Nix packaging
+system prefers calling binaries with immutable paths rather than rely on
+PATH resolution. If you are in that case, use the --enable-absolute-paths
+option to configure. This will ensure that programs calling binaries from
+this package will call them with their full installation path (in bindir)
+without relying on a PATH search.
+
+
+* Out-of-tree builds
+ ------------------
+
+ skarnet.org packages do not support out-of-tree builds. They
+are small, so it does not cost much to duplicate the entire
+source tree if parallel builds are needed.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b82361b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,148 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+make_need := 3.81
+ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))"
+fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer)
+endif
+
+CC = $(error Please use ./configure first)
+
+STATIC_LIBS :=
+SHARED_LIBS :=
+INTERNAL_LIBS :=
+EXTRA_TARGETS :=
+LIB_DEFS :=
+
+define library_definition
+LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy
+ifdef DO_SHARED
+SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy
+endif
+ifdef DO_STATIC
+STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy
+endif
+endef
+
+-include config.mak
+include package/targets.mak
+
+$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var))))
+
+include package/deps.mak
+
+version_m := $(basename $(version))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS)
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+CFLAGS_SHARED := -fPIC
+else
+CFLAGS_SHARED :=
+endif
+LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS)
+ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS)
+ALL_INCLUDES := $(wildcard src/include/$(package)/*.h)
+
+all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES) $(EXTRA_INCLUDES)
+
+clean:
+ @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS)
+
+distclean: clean
+ @exec rm -f config.mak src/include/$(package)/config.h
+
+tgz: distclean
+ @. package/info && \
+ rm -rf /tmp/$$package-$$version && \
+ cp -a . /tmp/$$package-$$version && \
+ cd /tmp && \
+ tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \
+ exec rm -rf /tmp/$$package-$$version
+
+strip: $(ALL_LIBS) $(ALL_BINS)
+ifneq ($(strip $(STATIC_LIBS)),)
+ exec $(STRIP) -x -R .note -R .comment $(STATIC_LIBS)
+endif
+ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),)
+ exec $(STRIP) -R .note -R .comment $(ALL_BINS) $(SHARED_LIBS)
+endif
+
+install: install-dynlib install-libexec install-bin install-lib install-include
+install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
+install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
+install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a)
+install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) $(EXTRA_INCLUDES:src/include/%.h=$(DESTDIR)$(includedir)/%.h)
+
+ifneq ($(exthome),)
+
+$(DESTDIR)$(exthome): $(DESTDIR)$(home)
+ exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+update: $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+
+$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
+
+$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M)
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@
+
+.PHONY: update global-links
+
+endif
+
+$(DESTDIR)$(dynlibdir)/lib%.so $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M): lib%.so.xyzzy
+ $(INSTALL) -D -m 755 $< $@.$(version) && \
+ $(INSTALL) -l $(@F).$(version) $@.$(version_M) && \
+ exec $(INSTALL) -l $(@F).$(version_M) $@
+
+$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes
+ exec $(INSTALL) -D -m 600 $< $@
+ grep -- ^$(@F) < package/modes | { read name mode owner && \
+ if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
+ chmod $$mode $@ ; }
+
+$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/%.h: src/include/%.h
+ exec $(INSTALL) -D -m 644 $< $@
+
+%.o: %.c
+ exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $<
+
+%.lo: %.c
+ exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
+
+$(ALL_BINS):
+ exec $(CC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+lib%.a.xyzzy:
+ exec $(AR) rc $@ $^
+ exec $(RANLIB) $@
+
+lib%.so.xyzzy:
+ exec $(CC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-lib install-include
+
+.DELETE_ON_ERROR:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..c46e1c0
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,6 @@
+Changelog for shibari.
+
+In 0.0.1.0
+----------
+
+ - Initial release.
diff --git a/README b/README
new file mode 100644
index 0000000..d04245c
--- /dev/null
+++ b/README
@@ -0,0 +1,23 @@
+shibari - a collection of DNS tools
+-----------------------------------
+
+ shibari is a suite of DNS programs and libraries for
+Unix systems, as an alternative to BIND, Unbound, djbdns,
+or similar DNS software.
+
+ See https://skarnet.org/software/shibari/ for details.
+
+
+* Installation
+ ------------
+
+ See the INSTALL file.
+
+
+* Contact information
+ -------------------
+
+ Laurent Bercot <ska-skaware at skarnet.org>
+
+ Please use the <skaware at list.skarnet.org> mailing-list for
+questions about shibari.
diff --git a/README.macos b/README.macos
new file mode 100644
index 0000000..64e0742
--- /dev/null
+++ b/README.macos
@@ -0,0 +1,3 @@
+ This package will compile and run on Darwin (MacOS X), but the building of
+shared libraries is not supported.
+ Make sure you use the --disable-shared option to configure.
diff --git a/README.solaris b/README.solaris
new file mode 100644
index 0000000..0450a37
--- /dev/null
+++ b/README.solaris
@@ -0,0 +1,11 @@
+ This package assumes the existence of a POSIX shell in /bin/sh.
+ On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide
+a POSIX shell in /usr/xpg4/bin/sh.
+
+ To compile this package on Solaris, you will need to run
+
+ ./patch-for-solaris
+
+ before you run ./configure. This script will change the #! invocation
+of the configure script and various tools so that a POSIX shell is used
+for the compilation process.
diff --git a/configure b/configure
new file mode 100755
index 0000000..efee0c9
--- /dev/null
+++ b/configure
@@ -0,0 +1,459 @@
+#!/bin/sh
+
+cd `dirname "$0"`
+. package/info
+
+usage () {
+cat <<EOF
+Usage: $0 [OPTION]... [TARGET]
+
+Defaults for the options are specified in brackets.
+
+System types:
+ --target=TARGET configure to run on target TARGET [detected]
+ --host=TARGET same as --target
+
+Installation directories:
+ --prefix=PREFIX main installation prefix [/]
+ --exec-prefix=EPREFIX installation prefix for executable files [PREFIX]
+
+Fine tuning of the installation directories:
+ --dynlibdir=DIR shared library files [PREFIX/lib]
+ --bindir=BINDIR user executables [EPREFIX/bin]
+ --libexecdir=DIR package-scoped executables [EPREFIX/libexec]
+ --libdir=DIR static library files [PREFIX/lib/$package]
+ --includedir=DIR C header files [PREFIX/include]
+
+ If no --prefix option is given, by default libdir (but not dynlibdir) will be
+ /usr/lib/$package, and includedir will be /usr/include.
+
+Dependencies:
+ --with-sysdeps=DIR use sysdeps in DIR [PREFIX/lib/skalibs/sysdeps]
+ --with-include=DIR add DIR to the list of searched directories for headers
+ --with-lib=DIR add DIR to the list of searched directories for static libraries
+ --with-dynlib=DIR add DIR to the list of searched directories for shared libraries
+
+ If no --prefix option is given, by default sysdeps will be fetched from
+ /usr/lib/skalibs/sysdeps.
+
+Optional features:
+ --enable-shared build shared libraries [disabled]
+ --disable-static do not build static libraries [enabled]
+ --disable-allstatic do not prefer linking against static libraries [enabled]
+ --enable-static-libc make entirely static binaries [disabled]
+ --disable-all-pic do not build executables or static libs as PIC [enabled]
+ --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled]
+ --enable-absolute-paths do not rely on PATH to access this package's binaries,
+ hardcode absolute BINDIR/foobar paths instead [disabled]
+
+EOF
+exit 0
+}
+
+# Helper functions
+
+# If your system does not have printf, you can comment this, but it is
+# generally not a good idea to use echo.
+# See http://etalabs.net/sh_tricks.html
+echo () {
+ IFS=" "
+ printf %s\\n "$*"
+}
+
+quote () {
+ tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/dev/null 2>&1 && { echo "$1" ; return 0 ; }
+$1
+EOF
+ echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g"
+}
+
+fail () {
+ echo "$*"
+ exit 1
+}
+
+fnmatch () {
+ eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac"
+}
+
+cmdexists () {
+ type "$1" >/dev/null 2>&1
+}
+
+trycc () {
+ test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*"
+}
+
+stripdir () {
+ while eval "fnmatch '*/' \"\${$1}\"" ; do
+ eval "$1=\${$1%/}"
+ done
+}
+
+tryflag () {
+ echo "Checking whether compiler accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o "$tmpo" "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+tryldflag () {
+ echo "Checking whether linker accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o "$tmpe" "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+
+# Actual script
+
+CC_AUTO=
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include"
+CPPFLAGS_POST="$CPPFLAGS"
+CPPFLAGS=
+CFLAGS_AUTO="-pipe -Wall"
+CFLAGS_POST="$CFLAGS"
+CFLAGS=-O2
+LDFLAGS_AUTO=
+LDFLAGS_POST="$LDFLAGS"
+LDFLAGS=
+LDFLAGS_NOSHARED=
+LDFLAGS_SHARED=-shared
+prefix=/usr
+exec_prefix='$prefix'
+dynlibdir='$prefix/lib'
+libexecdir='$exec_prefix/libexec'
+bindir='$exec_prefix/bin'
+libdir='$prefix/lib/$package'
+includedir='$prefix/include'
+sysdeps='$prefix/lib/skalibs/sysdeps'
+manualsysdeps=false
+shared=false
+static=true
+allpic=true
+slashpackage=false
+abspath=false
+sproot=
+home=
+exthome=
+allstatic=true
+evenmorestatic=false
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+build=
+
+for arg ; do
+ case "$arg" in
+ --help) usage ;;
+ --prefix=*) prefix=${arg#*=} ;;
+ --exec-prefix=*) exec_prefix=${arg#*=} ;;
+ --dynlibdir=*) dynlibdir=${arg#*=} ;;
+ --libexecdir=*) libexecdir=${arg#*=} ;;
+ --bindir=*) bindir=${arg#*=} ;;
+ --libdir=*) libdir=${arg#*=} ;;
+ --includedir=*) includedir=${arg#*=} ;;
+ --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;;
+ --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;;
+ --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;;
+ --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;;
+ --enable-shared|--enable-shared=yes) shared=true ;;
+ --disable-shared|--enable-shared=no) shared=false ;;
+ --enable-static|--enable-static=yes) static=true ;;
+ --disable-static|--enable-static=no) static=false ;;
+ --enable-allstatic|--enable-allstatic=yes) allstatic=true ;;
+ --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;;
+ --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;;
+ --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;;
+ --enable-all-pic|--enable-all-pic=yes) allpic=true ;;
+ --disable-all-pic|--enable-all-pic=no) allpic=false ;;
+ --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+ --enable-slashpackage) sproot= ; slashpackage=true ;;
+ --disable-slashpackage) sproot= ; slashpackage=false ;;
+ --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;;
+ --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
+ --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
+ --host=*|--target=*) target=${arg#*=} ;;
+ --build=*) build=${arg#*=} ;;
+ -* ) echo "$0: unknown option $arg" ;;
+ *=*) eval "${arg%%=*}=\${arg#*=}" ;;
+ *) target=$arg ;;
+ esac
+done
+
+# Expand installation directories
+stripdir prefix
+for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do
+ eval tmp=\${$i}
+ eval $i=$tmp
+ stripdir $i
+done
+
+# Get usable temp filenames
+i=0
+set -C
+while : ; do
+ i=$(($i+1))
+ tmpc="./tmp-configure-$$-$PPID-$i.c"
+ tmpo="./tmp-configure-$$-$PPID-$i.o"
+ tmpe="./tmp-configure-$$-$PPID-$i.tmp"
+ 2>|/dev/null > "$tmpc" && break
+ 2>|/dev/null > "$tmpo" && break
+ 2>|/dev/null > "$tmpe" && break
+ test "$i" -gt 50 && fail "$0: cannot create temporary files"
+done
+set +C
+trap 'rm -f "$tmpc" "$tmpo" "$tmpe"' EXIT ABRT INT QUIT TERM HUP
+
+# Set slashpackage values
+if $slashpackage ; then
+ home=${sproot}/package/${category}/${package}-${version}
+ exthome=${sproot}/package/${category}/${package}
+ if $manualsysdeps ; then
+ :
+ else
+ sysdeps=${DESTDIR}${sproot}/package/prog/skalibs/sysdeps
+ fi
+ prefix=
+ extbinprefix=${exthome}/command
+ dynlibdir=${home}/library.so
+ bindir=${home}/command
+ libdir=${home}/library
+ libexecdir=$bindir
+ includedir=${home}/include
+ while read dep condvar ; do
+ if test -n "$condvar" ; then
+ eval "cond=$condvar"
+ else
+ cond=true
+ fi
+ if $cond ; then
+ addincpath="$addincpath -I${DESTDIR}${sproot}${dep}/include"
+ vpaths="$vpaths ${DESTDIR}${sproot}${dep}/library"
+ addlibspath="$addlibspath -L${DESTDIR}${sproot}${dep}/library"
+ vpathd="$vpathd ${DESTDIR}${sproot}${dep}/library.so"
+ addlibdpath="$addlibdpath -L${DESTDIR}${sproot}${dep}/library.so"
+ fi
+ done < package/deps-build
+fi
+
+# Find a C compiler to use
+if test -n "$target" && test x${build} != x${target} ; then
+ cross=${target}-
+else
+ cross=
+fi
+echo "Checking for C compiler..."
+trycc ${CC}
+if test -n "$CC_AUTO" ; then
+ b=`basename "$CC"`
+ adjust_cross=false
+ if test "$b" != "$CC" ; then
+ adjust_cross=true
+ echo "$0: warning: compiler $CC is declared with its own path. If it's not accessible via PATH, you will need to pass AR, RANLIB and STRIP make variables to the make invocation." 1>&2
+ fi
+ if test -n "$cross" ; then
+ if test "$b" = "${b##$cross}" ; then
+ echo "$0: warning: compiler $CC is declared as a cross-compiler for target $target but does not start with prefix ${cross}" 1>&2
+ elif $adjust_cross ; then
+ cross=`dirname "$CC"`/"$cross"
+ fi
+ fi
+fi
+trycc ${cross}gcc
+trycc ${cross}clang
+trycc ${cross}cc
+test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; }
+echo " ... $CC_AUTO"
+echo "Checking whether C compiler works... "
+echo "typedef int x;" > "$tmpc"
+if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o "$tmpo" "$tmpc" 2>"$tmpe" ; then
+ echo " ... yes"
+else
+ echo " ... no. Compiler output follows:"
+ cat < "$tmpe"
+ exit 1
+fi
+
+echo "Checking target system type..."
+if test -z "$target" ; then
+ if test -n "$build" ; then
+ target=$build ;
+ else
+ target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+ fi
+fi
+echo " ... $target"
+if test ! -d $sysdeps || test ! -f $sysdeps/target ; then
+ echo "$0: error: $sysdeps is not a valid sysdeps directory"
+ exit 1
+fi
+if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then
+ echo "$0: error: target $target does not match the contents of $sysdeps/target"
+ exit 1
+fi
+
+spawn_lib=$(cat $sysdeps/spawn.lib)
+socket_lib=$(cat $sysdeps/socket.lib)
+sysclock_lib=$(cat $sysdeps/sysclock.lib)
+timer_lib=$(cat $sysdeps/timer.lib)
+util_lib=$(cat $sysdeps/util.lib)
+
+if $allpic ; then
+ tryflag CPPFLAGS_AUTO -fPIC
+fi
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS -fomit-frame-pointer
+tryflag CFLAGS_AUTO -fno-exceptions
+tryflag CFLAGS_AUTO -fno-unwind-tables
+tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables
+tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration
+tryflag CPPFLAGS_AUTO -Werror=implicit-int
+tryflag CPPFLAGS_AUTO -Werror=pointer-sign
+tryflag CPPFLAGS_AUTO -Werror=pointer-arith
+tryflag CFLAGS_AUTO -ffunction-sections
+tryflag CFLAGS_AUTO -fdata-sections
+
+tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment
+tryldflag LDFLAGS_AUTO -Wl,--sort-common
+
+CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}"
+
+if $evenmorestatic ; then
+ LDFLAGS_NOSHARED=-static
+fi
+
+if $shared ; then
+ tryldflag LDFLAGS -Wl,--hash-style=both
+fi
+
+LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}"
+
+if test -z "$vpaths" ; then
+ while read dep ; do
+ base=$(basename $dep) ;
+ vpaths="$vpaths /usr/lib/$base"
+ addlibspath="$addlibspath -L/usr/lib/$base"
+ done < package/deps-build
+fi
+
+if $allstatic ; then
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}"
+ tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections
+else
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}"
+fi
+
+echo "Creating config.mak..."
+cmdline=$(quote "$0")
+for i ; do cmdline="$cmdline $(quote "$i")" ; done
+exec 3>&1 1>config.mak
+cat << EOF
+# This file was generated by:
+# $cmdline
+# Any changes made here will be lost if configure is re-run.
+
+target := $target
+package := $package
+prefix := $prefix
+exec_prefix := $exec_prefix
+dynlibdir := $dynlibdir
+libexecdir := $libexecdir
+bindir := $bindir
+libdir := $libdir
+includedir := $includedir
+sysdeps := $sysdeps
+slashpackage := $slashpackage
+sproot := $sproot
+version := $version
+home := $home
+exthome := $exthome
+SPAWN_LIB := ${spawn_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TIMER_LIB := ${timer_lib}
+UTIL_LIB := ${util_lib}
+
+CC := $CC_AUTO
+CPPFLAGS_AUTO := $CPPFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST
+CFLAGS_AUTO := $CFLAGS_AUTO
+CFLAGS := $CFLAGS $CFLAGS_POST
+LDFLAGS_AUTO := $LDFLAGS_AUTO
+LDFLAGS := $LDFLAGS $LDFLAGS_POST
+LDFLAGS_SHARED := $LDFLAGS_SHARED
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+
+vpath lib%.a$vpaths
+vpath lib%.so$vpathd
+EOF
+if $allstatic ; then
+ echo ".LIBPATTERNS := lib%.a"
+ echo "DO_ALLSTATIC := 1"
+else
+ echo ".LIBPATTERNS := lib%.so"
+fi
+if $static ; then
+ echo "DO_STATIC := 1"
+else
+ echo "DO_STATIC :="
+fi
+if $shared ; then
+ echo "DO_SHARED := 1"
+else
+ echo "DO_SHARED :="
+fi
+if $allpic ; then
+ echo "STATIC_LIBS_ARE_PIC := 1"
+else
+ echo "STATIC_LIBS_ARE_PIC :="
+fi
+
+exec 1>&3 3>&-
+echo " ... done."
+
+echo "Creating src/include/${package}/config.h..."
+mkdir -p -m 0755 src/include/${package}
+exec 3>&1 1> src/include/${package}/config.h
+cat <<EOF
+/* ISC license. */
+
+/* Generated by: $cmdline */
+
+#ifndef ${package_macro_name}_CONFIG_H
+#define ${package_macro_name}_CONFIG_H
+
+#define ${package_macro_name}_VERSION "$version"
+EOF
+if $slashpackage ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\""
+elif $abspath ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$bindir/\""
+else
+ echo "#define ${package_macro_name}_BINPREFIX \"\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
+fi
+echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+echo
+echo "#endif"
+exec 1>&3 3>&-
+echo " ... done."
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..fd59558
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,181 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>shibari - a collection of DNS tools </title>
+ <meta name="Description" content="shibari - a collection of DNS tools" />
+ <meta name="Keywords" content="shibari s6-dns DNS resolution server unix linux laurent bercot ska skarnet" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> shibari </h1>
+
+<h2> What is it&nbsp;? </h2>
+
+<p>
+ shibari is a collection of DNS tools for Unix systems, as an
+alternative to BIND, Unbound, djbdns or other similar suites of
+programs.
+</p>
+
+<p>
+ It was previously named s6-dns. The name of the project was changed to
+avoid confusion; despite being written by the same author and with the
+same mindset, it is not part of the s6 project.
+</p>
+
+<h3> Why "shibari"? </h3>
+
+<p>
+ There's a de facto tradition that DNS software has a name related to
+binding. shibari aims to be the most pleasant of all DNS software.
+</p>
+
+<hr />
+
+<h2> Installation </h2>
+
+<h3> Requirements </h3>
+
+<ul>
+ <li> A POSIX-compliant system with a standard C development environment </li>
+ <li> GNU make, version 3.81 or later </li>
+ <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> version
+2.14.0.1 or later. It's a build-time requirement. It's also a run-time
+requirement if you link against the shared version of the skalibs library. </li>
+ <li> <a href="//skarnet.org/software/s6/">s6</a> version
+2.12.0.2 or later. It's a build-time requirement. It's also a run-time
+requirement if you link against the shared version of the s6 library. That
+library is used for the access control and client location features in
+<a href="shibari-server-udp.html">shibari-server-udp</a>. </li>
+ <li> (for now) <a href="//skarnet.org/software/s6-dns/">s6-dns</a> version
+2.3.7.0 or later. It's a build-time requirement. It's also a run-time
+requirement if you link against the shared version of the s6-dns library. </li>
+</ul>
+
+<h3> Licensing </h3>
+
+<p>
+ shibari is free software. It is available under the
+<a href="https://opensource.org/licenses/ISC">ISC license</a>.
+</p>
+
+<h3> Download </h3>
+
+<ul>
+ <li> The current released version of shibari is <a href="shibari-0.0.1.0.tar.gz">0.0.1.0</a>.
+(That is a lie. shibari is currently unreleased, so that link does not work.) </li>
+ <li> You can checkout a copy of the
+<a href="//git.skarnet.org/cgi-bin/cgit.cgi/shibari/">shibari
+git repository</a>:
+<pre> git clone git://git.skarnet.org/shibari </pre> </li>
+ <li> There's also a
+<a href="https://github.com/skarnet/shibari">GitHub mirror</a>
+of the shibari git repository. </li>
+</ul>
+
+<h3> Build and installation </h3>
+
+<ul>
+ <li> See the enclosed INSTALL file for build and installation details. </li>
+</ul>
+
+<h3> Upgrade notes </h3>
+
+<ul>
+ <li> <a href="upgrade.html">This page</a> lists the differences to be aware of between
+the previous versions of shibari and the current one. </li>
+</ul>
+
+<hr />
+
+<h2> Reference </h2>
+
+<h3> Commands </h3>
+
+<p>
+ All these commands exit 111 if they encounter a temporary error or
+hardware error, and
+100 if they encounter a permanent error - such as a misuse. Short-lived
+commands exit 0 on success. Other exit codes are documented in the
+relevant page.
+</p>
+
+<h4> Command-line DNS clients programs </h4>
+
+<ul>
+</ul>
+
+<h4> Caches </h4>
+
+<ul>
+</ul>
+
+<h4> Servers </h4>
+
+<ul>
+ <li> The <a href="shibari-server-tcp.html">shibari-server-tcp</a> program </li>
+ <li> The <a href="shibari-server-udp.html">shibari-server-udp</a> program </li>
+</ul>
+
+<h4> Filtering tools </h4>
+
+<ul>
+</ul>
+
+<h4> Command-line qualification </h4>
+
+<ul>
+</ul>
+
+<h4> DNS analysis and debug tools </h4>
+
+<ul>
+</ul>
+
+<h4> Miscellaneous utilities </h4>
+
+<h3> Libraries </h3>
+
+<h4> Protocol implementation and synchronous resolution </h4>
+
+<ul>
+</ul>
+
+<h4> Asynchronous resolution </h4>
+
+<ul>
+</ul>
+
+<hr />
+
+<a name="related">
+<h2> Related resources </h2>
+</a>
+
+<h3> shibari discussion </h3>
+
+<ul>
+ <li> <tt>shibari</tt> is discussed on the
+<a href="//skarnet.org/lists/#skaware">skaware</a> mailing-list. </li>
+ <li> It can also be discussed on the
+<a href="https://cr.yp.to/lists.html#dns">cr.yp.to dns mailing-list</a>. </li>
+</ul>
+
+<h3> Similar work </h3>
+
+<ul>
+ <li> <a href="https://www.isc.org/software/bind">BIND</a> </li>
+ <li> <a href="https://nlnetlabs.nl/projects/unbound/about/">Unbound</a> </li>
+ <li> <a href="https://cr.yp.to/djbdns.html">djbdns</a> </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/shibari-server-tcp.html b/doc/shibari-server-tcp.html
new file mode 100644
index 0000000..5f36087
--- /dev/null
+++ b/doc/shibari-server-tcp.html
@@ -0,0 +1,213 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>shibari: the shibari-server-tcp program</title>
+ <meta name="Description" content="shibari: the shibari-server-tcp program" />
+ <meta name="Keywords" content="shibari DNS s6-dns server database authoritative TCP s6-networking ucspi" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">shibari</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The shibari-server-tcp program </h1>
+
+<p>
+ shibari-server-tcp reads DNS queries on its standard input, and answers them
+on its standard output.
+</p>
+
+<div id="interface">
+<h2> Interface </h2>
+</div>
+
+<pre>
+ shibari-server-tcp [ -v <em>verbosity</em> [ -f <em>tdbfile</em> ] [ -r <em>rtimeout</em> ] [ -w <em>wtimeout</em> ]
+</pre>
+
+<ul>
+ <li> shibari-server-tcp reads a stream of DNS queries on its stdin (encoded
+in the TCP DNS way, i.e. 2 bytes of length then the payload), and tries to fulfill them,
+sending answers to stdout. It logs its actions to stderr. </li>
+ <li> It supports normal queries and AXFR queries. </li>
+ <li> It reads DNS data information from a
+<a href="https://en.wikipedia.org/wiki/Cdb_(software)">cdb</a> database; the
+database must use the output format from
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a>. </li>
+</ul>
+
+<div id="commonusage">
+<h2> Common usage </h2>
+</div>
+
+<p>
+ shibari-server-tcp is intended to be run under a TCP super-server such as
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a>.
+It delegates to the super-server the job of binding and listening to
+the socket, accepting connections, and spawning a separate process to handle a
+given connection.
+</p>
+
+<p>
+ As such, a command line for shibari-server-tcp, running as user <tt>dns</tt>, listening
+on address <tt>${ip}</tt>, would typically look like this:
+</p>
+
+<pre>
+ s6-envuidgid dns s6-tcpserver -U -- ${ip} 53 s6-tcpserver-access -x rules.cdb -- shibari-server-tcp
+</pre>
+
+<p>
+ Most users will want to run these command lines as <em>services</em>, i.e. daemons
+run in the background when the machine starts. The <tt>examples/</tt> subdirectory
+of the shibari package provides service templates to help you run shibari-server-tcp under
+<a href="https://wiki.gentoo.org/wiki/OpenRC">OpenRC</a>,
+<a href="//skarnet.org/software/s6/">s6</a> and
+<a href="//skarnet.org/software/s6-rc/">s6-rc</a>.
+</p>
+
+<div id="exitcodes">
+<h2> Exit codes </h2>
+</div>
+
+<dl>
+ <dt> 0 </dt> <dd> Clean exit. There was a successful series of DNS exchanges
+and tipideed received EOF, or timed out while the client was idle. </dd>
+ <dt> 1 </dt> <dd> Invalid DNS query. The client spoke garbage. </dd>
+ <dt> 100 </dt> <dd> Bad usage. shibari-server-tcp was run in an incorrect way: bad command
+line options, or missing environment variables, etc. </dd>
+ <dt> 101 </dt> <dd> Cannot happen. This signals a bug in shibari-server-tcp, and comes with an
+error message asking you to report the bug. Please do so, on the
+<a href="//skarnet.org/lists/#skaware">skaware mailing-list</a>. </dd>
+ <dt> 102 </dt> <dd> Misconfiguration. shibari-server-tcp found something in its DNS data file
+that it does not like. </dd>
+ <dt> 111 </dt> <dd> System call failed. This usually signals an issue with the
+underlying operating system. </dd>
+</dl>
+
+<div id="environment">
+<h2> Environment variables </h2>
+</div>
+
+<p>
+ shibari-server-tcp expects the following variables in its environment, and will exit
+with an error message if they are undefined. When run under
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a>,
+these variables are automatically set by the super-server. This is the way
+shibari-server-tcp gets its network information without having to perform network
+operations itself.
+</p>
+
+<dl>
+ <dt> TCPLOCALIP </dt>
+ <dd> The local IP address that the super-server is listening on. </dd>
+
+ <dt> TCPLOCALPORT </dt>
+ <dd> The local port that the super-server is listening on. In normal usage
+this will be 53. </dd>
+
+ <dt> TCPREMOTEIP </dt>
+ <dd> The IP address of the client. </dd>
+
+ <dt> TCPREMOTEPORT </dt>
+ <dd> The remote port that the client is connecting from. </dd>
+</dl>
+
+<p>
+ The following variables are optional, but will inform shibari-server-tcp's
+behaviour. They are typically set by
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a>
+with the <tt>-i</tt> or <tt>-x</tt> option, when the access rules database
+defines environment variables depending on client IP ranges.
+</p>
+
+<dl>
+ <dt> AXFR </dt>
+ <dd> If this variable is set, it controls what zones the client is allowed
+to make AXFR queries for. A value of <tt>*</tt> (star) means the client is
+allowed to make AXFR queries for any zone, same as when the variable is not
+defined. Else, the value needs to be a space-, comma-, semicolon-, or
+slash-separated list of zones; these are the allowed zones. </dd>
+
+ <dt> LOC </dt>
+ <dd> If this variable is set, it defines a client location that is used to
+implement views. A client location is at most two charaters; if the value
+is <tt>lo</tt>, then the client will be granted access to DNS data guarded
+by a <tt>%lo</tt> location indicator in the
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a> file.
+Note that shibari-server-tcp ignores client IP prefix matching compiled in
+the database via <tt>%lo:ipprefix</tt> lines: it only takes its location
+information from the LOC variable, and will use the contents of LOC to match
+lines ending with <tt>:%lo</tt>. The idea is to only have one place centralizing
+what clients are authorized to do depending on their IP, and that place is the
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a>
+rules database. </dd>
+</dl>
+
+<div id="options">
+<h2> Options </h2>
+</div>
+
+<dl>
+ <dt> -v <em>verbosity</em> </dt>
+ <dd> Be more or less verbose.
+A <em>verbosity</em> of 0 means no warnings, no logs, only error messages. 1
+means warnings and terse logs. 2 or more means more logs.
+Default is <strong>1</strong>. </dd>
+
+ <dt> -f <em>tdbfile</em> </dt>
+ <dd> Read DNS data from <em>tdbfile</em>.
+The default is <strong><tt>data.cdb</tt></strong>, in the current working
+directory of the shibari-server-tcp process. </dd>
+
+ <dt> -r <em>rtimeout</em> </dt>
+ <dd> Read timeout. If <em>rtimeout</em> milliseconds
+elapse while shibari-server-tcp is waiting for a DNS query, just exit.
+The default is <strong>0</strong>, meaning infinite: shibari-server-tcp
+will never close the connection until it receives EOF. </dd>
+
+ <dt> -w <em>wtimeout</em> </dt>
+ <dd> Write timeout. If shibari-server-tcp is unable
+to send its answer in <em>wtimeout</em> milliseconds, which means the network is
+congested, give up and close the connection. The default is <strong>0</strong>, which
+means infinite: shibari-server-tcp will wait forever until the network decongests in
+order to send its answer. </dd>
+</dl>
+
+<div id="notes">
+<h2> Notes </h2>
+</div>
+
+<ul>
+ <li> The DNS database can be changed at any time via an invocation of
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a>.
+shibari-server-tcp will keep using the old data until its current stream
+ends and it exits. The next instance of shibari-server-tcp,
+spawned by the super-server, will use the new data. </li>
+ <li> shibari-server-tcp is a drop-in replacement for
+<a href="https://cr.yp.to/djbdns/axfrdns.html">axfrdns</a>, with one
+caveat: client location information needs to be migrated from the DNS
+database to LOC definitions in the TCP access rules database. For instance,
+if you have a <tt>%lo:1.2.3</tt> line in your text data file, you need to
+add the following entries to your TCP access rules database:
+ <ul>
+ <li> <tt>ip4/1.2.3.0_24/allow</tt> (may be empty) </li>
+ <li> <tt>ip4/1.2.3.0_24/env/LOC</tt> containing <tt>lo</tt> </li>
+ </ul> </li>
+ <li> If you are using such an access rules database via a
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a>
+invocation, make sure your
+<a href="shibari-server-udp.html">shibari-server-udp</a> service is using the
+same database via the <tt>-i</tt> or <tt>-x</tt> option. You
+don't want to give different permissions, or different location information,
+depending on whether a query is made over TCP or UDP. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/shibari-server-udp.html b/doc/shibari-server-udp.html
new file mode 100644
index 0000000..c8e46f8
--- /dev/null
+++ b/doc/shibari-server-udp.html
@@ -0,0 +1,163 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>shibari: the shibari-server-udp program</title>
+ <meta name="Description" content="shibari: the shibari-server-udp program" />
+ <meta name="Keywords" content="shibari DNS s6-dns server database authoritative UDP s6-networking tinydns" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">shibari</a><br />
+<a href="//skarnet.org/software/">Software</a><br />
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The shibari-server-udp program </h1>
+
+<p>
+ shibari-server-udp is a long-lived process. It binds to a UDP socket, then
+answers DNS queries it receives, until it is killed.
+</p>
+
+<div id="interface">
+<h2> Interface </h2>
+</div>
+
+<pre>
+ shibari-server-udp [ -v <em>verbosity</em> ] [ -d <em>notif</em> ] [ -f <em>tdbfile</em> ] [ -i <em>rulesdir</em> ] [ -x <em>rulesfile</em> ] [ -p <em>port</em> ] <em>ip</em>
+</pre>
+
+<ul>
+ <li> shibari-server-udp creates a UDP socket and binds it to address <em>ip</em>
+on port 53. <em>ip</em> can be IPv4 or IPv6. </li>
+ <li> It listens to non-recursive DNS queries, sent by DNS caches, and, if
+appropriate, answers with data it reads from its data file. </li>
+ <li> It reloads its data file on SIGHUP, and exits 0 on SIGTERM. </li>
+ <li> The data file is a
+<a href="https://en.wikipedia.org/wiki/Cdb_(software)">cdb</a> database; it
+must use the output format from
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a>. </li>
+</ul>
+
+<div id="exitcodes">
+<h2> Exit codes </h2>
+</div>
+
+<dl>
+ <dt> 0 </dt> <dd> Clean exit. shibari-server-udp received a SIGTERM and exited. <dd>
+ <dt> 100 </dt> <dd> Bad usage. shibari-server-udp was run in an incorrect way:
+typically bad command line options. </dd>
+ <dt> 101 </dt> <dd> Cannot happen. This signals a bug in shibari-server-udp, and comes with an
+error message asking you to report the bug. Please do so, on the
+<a href="//skarnet.org/lists/#skaware">skaware mailing-list</a>. </dd>
+ <dt> 102 </dt> <dd> Misconfiguration. shibari-server-udp found something in its DNS data file
+that it does not like. </dd>
+ <dt> 111 </dt> <dd> System call failed. This usually signals an issue with the
+underlying operating system. </dd>
+</dl>
+
+<div id="options">
+<h2> Options </h2>
+</div>
+
+<dl>
+ <dt> -v <em>verbosity</em> </dt>
+ <dd> Be more or less verbose.
+A <em>verbosity</em> of 0 means no warnings, no logs, only error messages. 1
+means warnings and terse logs. 2 or more means more logs.
+Default is <strong>1</strong>. </dd>
+
+ <dt> -d <em>notif</em> </dt>
+ <dd> Write a newline to file descriptor <em>notif</em>, then close it, when
+shibari-server-udp has bound its socket, opened its file, and is ready to serve.
+This is the <a href="https://skarnet.org/software/s6/notifywhenup.html">s6
+readiness notification</a> mechanism. By default, when this option isn't given
+no readiness notification is sent. </dd>
+
+ <dt> -f <em>tdbfile</em> </dt>
+ <dd> Read DNS data from <em>tdbfile</em>.
+The default is <strong><tt>data.cdb</tt></strong>, in the current working
+directory of the shibari-server-udp process. </dd>
+
+ <dt> -i <em>rulesdir</em> </dt>
+ <dd> Use <em>rulesdir</em> as a filesystem-based
+<a href="//skarnet.org/software/s6/libs6/accessrules.html">access rules
+database</a>: ignore any message whose originating IP address isn't
+explicitly allowed. The access rules database is also used to get
+<a href="#clientlocation">client location information</a>.
+If something in <em>rulesdir</em> changes while shibari-server-udp is
+running, it will immediately pick up the change. </dd>
+
+ <dt> -x <em>rulesfile</em> </dt>
+ <dd> Use <em>rulesfile</em> as a cdb
+<a href="//skarnet.org/software/s6/libs6/accessrules.html">access rules
+database</a>, see description of <tt>-i</tt> above. <tt>-i</tt> and
+<tt>-x</tt> are equivalent; you can switch between <em>rulesdir</em>
+and <em>rulesfile</em> via the
+<a href="//skarnet.org/software/s6/s6-accessrules-cdb-from-fs.html">s6-accessrules-cdb-from-fs</a> and
+<a href="//skarnet.org/software/s6/s6-accessrules-fs-from-cdb.html">s6-accessrules-fs-from-cdb</a>
+programs. The cdb format is more efficient but more static than the
+filesystem format. If <em>rulesfile</em> changes while shibari-server-udp
+is running, it will continue to use the old data until it receives a SIGHUP. </dd>
+
+ <dt> -p <em>port</em> </dt>
+ <dd> Binds to port <em>port</em>. Default is <strong>53</strong>. </dd>
+</dl>
+
+<div id="clientlocation">
+<h2> Client location </h2>
+</div>
+
+<p>
+ shibari-server-udp ignores client location information given as
+<tt>%lo:ipprefix</tt> lines in the file created by
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a>.
+Instead, it reads client location information in LOC definitions
+present in the <em>rulesdir</em> or <em>rulesfile</em>
+access rules database. For instance,
+if you have a <tt>%lo:1.2.3</tt> line in your text data file, meaning
+that clients whose IP address is in the <tt>1.2.3.0/24</tt> IPv4
+range are identified with the <tt>lo</tt> location and that DNS data
+entries ending with <tt>:lo</tt> are visible to them, you need to
+translate this information into the accessrules format. Your
+<em>rulesdir</em> must contain the following files:
+</p>
+
+<ul>
+ <li> <tt>ip4/1.2.3.0_24/allow</tt> (may be empty) </li>
+ <li> <tt>ip4/1.2.3.0_24/env/LOC</tt> containing <tt>lo</tt> </li>
+</ul>
+
+<p>
+ (To use the <tt>-x</tt> option instead, you'd do the same, then run
+<tt>s6-accessrules-cdb-from-fs <em>rulesfile</em> <em>rulesdir</em></tt>
+to compile the information into <em>rulesfile</em>.)
+</p>
+
+<div id="notes">
+<h2> Notes </h2>
+</div>
+
+<ul>
+ <li> The DNS database can be changed at any time via an invocation of
+<a href="https://cr.yp.to/djbdns/tinydns-data.html">tinydns-data</a>.
+shibari-server-udp will keep using the old data until it receives a
+SIGHUP, at which point it will reopen its database. </li>
+ <li> shibari-server-udp is a drop-in replacement for
+<a href="https://cr.yp.to/djbdns/tinydns.html">tinydns</a>, with the
+caveat of the <a href="#clientlocation">client location mechanism</a>. </li>
+ <li> If you are using the <tt>-i<tt> or <tt>-x</tt> option, the
+access rules database can, and should, be the same one that is used by the
+<a href="//skarnet.org/software/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a>
+program in your
+<a href="shibari-server-tcp.html">shibari-server-tcp</a> service. You
+don't want to give different permissions, or different location information,
+depending on whether a query is made over TCP or UDP. </li>
+</ul>
+
+</body>
+</html>
diff --git a/doc/upgrade.html b/doc/upgrade.html
new file mode 100644
index 0000000..52eeaa5
--- /dev/null
+++ b/doc/upgrade.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>shibari: how to upgrade</title>
+ <meta name="Description" content="shibari: how to upgrade" />
+ <meta name="Keywords" content="shibari installation upgrade" />
+ <!-- <link rel="stylesheet" type="text/css" href="//skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">shibari</a><br />
+<a href="//skarnet.org/software/">Software</a> <br>
+<a href="//skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> What has changed in shibari </h1>
+
+<h2> in 0.0.1.0 </h2>
+
+<ul>
+ <li> Initial release. </li>
+</ul>
+
+</body>
+</html>
diff --git a/package/deps-build b/package/deps-build
new file mode 100644
index 0000000..e2af791
--- /dev/null
+++ b/package/deps-build
@@ -0,0 +1,3 @@
+/package/prog/skalibs
+/package/admin/s6
+/package/web/s6-dns
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..5fbe083
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,66 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/include/shibari/cache.h: src/include/shibari/dcache.h
+src/include/shibari/common.h: src/include/shibari/constants.h src/include/shibari/util.h
+src/include/shibari/packet.h: src/include/shibari/tdb.h
+src/include/shibari/server.h: src/include/shibari/log.h src/include/shibari/packet.h src/include/shibari/tdb.h
+src/include/shibari/shibari.h: src/include/shibari/cache.h src/include/shibari/client.h src/include/shibari/common.h src/include/shibari/server.h
+src/cache/dcache-internal.h: src/include/shibari/dcache.h
+src/cache/dcache_add.o src/cache/dcache_add.lo: src/cache/dcache_add.c src/cache/dcache-internal.h src/include/shibari/dcache.h
+src/cache/dcache_clean_expired.o src/cache/dcache_clean_expired.lo: src/cache/dcache_clean_expired.c src/cache/dcache-internal.h src/include/shibari/dcache.h
+src/cache/dcache_delete.o src/cache/dcache_delete.lo: src/cache/dcache_delete.c src/cache/dcache-internal.h src/include/shibari/dcache.h
+src/cache/dcache_free.o src/cache/dcache_free.lo: src/cache/dcache_free.c src/include/shibari/dcache.h
+src/cache/dcache_init.o src/cache/dcache_init.lo: src/cache/dcache_init.c src/include/shibari/dcache.h
+src/cache/dcache_load.o src/cache/dcache_load.lo: src/cache/dcache_load.c src/include/shibari/dcache.h
+src/cache/dcache_save.o src/cache/dcache_save.lo: src/cache/dcache_save.c src/include/shibari/dcache.h
+src/cache/dcache_search.o src/cache/dcache_search.lo: src/cache/dcache_search.c src/cache/dcache-internal.h src/include/shibari/dcache.h
+src/common/shibari_log_answer.o src/common/shibari_log_answer.lo: src/common/shibari_log_answer.c src/include/shibari/log.h src/include/shibari/util.h
+src/common/shibari_log_exit.o src/common/shibari_log_exit.lo: src/common/shibari_log_exit.c src/include/shibari/log.h
+src/common/shibari_log_query.o src/common/shibari_log_query.lo: src/common/shibari_log_query.c src/include/shibari/log.h src/include/shibari/util.h
+src/common/shibari_log_queryplus.o src/common/shibari_log_queryplus.lo: src/common/shibari_log_queryplus.c src/include/shibari/log.h src/include/shibari/util.h
+src/common/shibari_log_start.o src/common/shibari_log_start.lo: src/common/shibari_log_start.c src/include/shibari/log.h
+src/common/shibari_util_get_prefixlen.o src/common/shibari_util_get_prefixlen.lo: src/common/shibari_util_get_prefixlen.c src/include/shibari/util.h
+src/common/shibari_util_qtype_num.o src/common/shibari_util_qtype_num.lo: src/common/shibari_util_qtype_num.c src/include/shibari/util.h
+src/common/shibari_util_qtype_str.o src/common/shibari_util_qtype_str.lo: src/common/shibari_util_qtype_str.c src/include/shibari/util.h
+src/common/shibari_util_rcode_str.o src/common/shibari_util_rcode_str.lo: src/common/shibari_util_rcode_str.c src/include/shibari/util.h
+src/server/shibari-server-tcp.o src/server/shibari-server-tcp.lo: src/server/shibari-server-tcp.c src/include/shibari/common.h src/include/shibari/server.h
+src/server/shibari-server-udp.o src/server/shibari-server-udp.lo: src/server/shibari-server-udp.c src/include/shibari/common.h src/include/shibari/server.h
+src/server/shibari_packet_add_glue.o src/server/shibari_packet_add_glue.lo: src/server/shibari_packet_add_glue.c src/include/shibari/constants.h src/include/shibari/packet.h src/include/shibari/tdb.h src/include/shibari/util.h
+src/server/shibari_packet_add_rr.o src/server/shibari_packet_add_rr.lo: src/server/shibari_packet_add_rr.c src/include/shibari/constants.h src/include/shibari/packet.h
+src/server/shibari_packet_assert_authority.o src/server/shibari_packet_assert_authority.lo: src/server/shibari_packet_assert_authority.c src/include/shibari/constants.h src/include/shibari/packet.h src/include/shibari/tdb.h src/include/shibari/util.h
+src/server/shibari_packet_begin.o src/server/shibari_packet_begin.lo: src/server/shibari_packet_begin.c src/include/shibari/constants.h src/include/shibari/packet.h
+src/server/shibari_packet_end.o src/server/shibari_packet_end.lo: src/server/shibari_packet_end.c src/include/shibari/packet.h
+src/server/shibari_packet_init.o src/server/shibari_packet_init.lo: src/server/shibari_packet_init.c src/include/shibari/packet.h
+src/server/shibari_packet_tdb_answer_query.o src/server/shibari_packet_tdb_answer_query.lo: src/server/shibari_packet_tdb_answer_query.c src/include/shibari/constants.h src/include/shibari/packet.h src/include/shibari/tdb.h
+src/server/shibari_tdb_entry_parse.o src/server/shibari_tdb_entry_parse.lo: src/server/shibari_tdb_entry_parse.c src/include/shibari/constants.h src/include/shibari/tdb.h
+src/server/shibari_tdb_extract_domain.o src/server/shibari_tdb_extract_domain.lo: src/server/shibari_tdb_extract_domain.c src/include/shibari/constants.h src/include/shibari/tdb.h
+src/server/shibari_tdb_find_authority.o src/server/shibari_tdb_find_authority.lo: src/server/shibari_tdb_find_authority.c src/include/shibari/constants.h src/include/shibari/tdb.h
+src/server/shibari_tdb_read_entry.o src/server/shibari_tdb_read_entry.lo: src/server/shibari_tdb_read_entry.c src/include/shibari/tdb.h
+
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libdcache.a.xyzzy: src/cache/dcache_add.o src/cache/dcache_clean_expired.o src/cache/dcache_delete.o src/cache/dcache_free.o src/cache/dcache_init.o src/cache/dcache_load.o src/cache/dcache_save.o src/cache/dcache_search.o
+else
+libdcache.a.xyzzy: src/cache/dcache_add.lo src/cache/dcache_clean_expired.lo src/cache/dcache_delete.lo src/cache/dcache_free.lo src/cache/dcache_init.lo src/cache/dcache_load.lo src/cache/dcache_save.lo src/cache/dcache_search.lo
+endif
+libdcache.so.xyzzy: EXTRA_LIBS :=
+libdcache.so.xyzzy: src/cache/dcache_add.lo src/cache/dcache_clean_expired.lo src/cache/dcache_delete.lo src/cache/dcache_free.lo src/cache/dcache_init.lo src/cache/dcache_load.lo src/cache/dcache_save.lo src/cache/dcache_search.lo
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libshibari-common.a.xyzzy: src/common/shibari_log_answer.o src/common/shibari_log_exit.o src/common/shibari_log_query.o src/common/shibari_log_queryplus.o src/common/shibari_log_start.o src/common/shibari_util_qtype_num.o src/common/shibari_util_qtype_str.o src/common/shibari_util_rcode_str.o src/common/shibari_util_get_prefixlen.o
+else
+libshibari-common.a.xyzzy: src/common/shibari_log_answer.lo src/common/shibari_log_exit.lo src/common/shibari_log_query.lo src/common/shibari_log_queryplus.lo src/common/shibari_log_start.lo src/common/shibari_util_qtype_num.lo src/common/shibari_util_qtype_str.lo src/common/shibari_util_rcode_str.lo src/common/shibari_util_get_prefixlen.lo
+endif
+libshibari-common.so.xyzzy: EXTRA_LIBS := -lskarnet
+libshibari-common.so.xyzzy: src/common/shibari_log_answer.lo src/common/shibari_log_exit.lo src/common/shibari_log_query.lo src/common/shibari_log_queryplus.lo src/common/shibari_log_start.lo src/common/shibari_util_qtype_num.lo src/common/shibari_util_qtype_str.lo src/common/shibari_util_rcode_str.lo src/common/shibari_util_get_prefixlen.lo
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+libshibari-server.a.xyzzy: src/server/shibari_packet_init.o src/server/shibari_packet_begin.o src/server/shibari_packet_end.o src/server/shibari_packet_add_rr.o src/server/shibari_tdb_entry_parse.o src/server/shibari_tdb_extract_domain.o src/server/shibari_tdb_find_authority.o src/server/shibari_tdb_read_entry.o src/server/shibari_packet_add_glue.o src/server/shibari_packet_assert_authority.o src/server/shibari_packet_tdb_answer_query.o
+else
+libshibari-server.a.xyzzy: src/server/shibari_packet_init.lo src/server/shibari_packet_begin.lo src/server/shibari_packet_end.lo src/server/shibari_packet_add_rr.lo src/server/shibari_tdb_entry_parse.lo src/server/shibari_tdb_extract_domain.lo src/server/shibari_tdb_find_authority.lo src/server/shibari_tdb_read_entry.lo src/server/shibari_packet_add_glue.lo src/server/shibari_packet_assert_authority.lo src/server/shibari_packet_tdb_answer_query.lo
+endif
+libshibari-server.so.xyzzy: EXTRA_LIBS := -ls6dns -lskarnet
+libshibari-server.so.xyzzy: src/server/shibari_packet_init.lo src/server/shibari_packet_begin.lo src/server/shibari_packet_end.lo src/server/shibari_packet_add_rr.lo src/server/shibari_tdb_entry_parse.lo src/server/shibari_tdb_extract_domain.lo src/server/shibari_tdb_find_authority.lo src/server/shibari_tdb_read_entry.lo src/server/shibari_packet_add_glue.lo src/server/shibari_packet_assert_authority.lo src/server/shibari_packet_tdb_answer_query.lo
+shibari-server-tcp: EXTRA_LIBS := -ls6dns -lskarnet
+shibari-server-tcp: src/server/shibari-server-tcp.o ${LIBSHIBARI_SERVER} ${LIBSHIBARI_COMMON}
+shibari-server-udp: EXTRA_LIBS := -ls6dns -ls6 -lskarnet ${SOCKET_LIB}
+shibari-server-udp: src/server/shibari-server-udp.o ${LIBSHIBARI_SERVER} ${LIBSHIBARI_COMMON}
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..d1c92dc
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=shibari
+version=0.0.1.0
+category=web
+package_macro_name=SHIBARI
diff --git a/package/modes b/package/modes
new file mode 100644
index 0000000..94bdf3e
--- /dev/null
+++ b/package/modes
@@ -0,0 +1,2 @@
+shibari-server-tcp 0755
+shibari-server-udp 0755
diff --git a/package/targets.mak b/package/targets.mak
new file mode 100644
index 0000000..0f2d479
--- /dev/null
+++ b/package/targets.mak
@@ -0,0 +1,7 @@
+BIN_TARGETS := \
+shibari-server-tcp \
+shibari-server-udp
+
+LIBEXEC_TARGETS :=
+
+LIB_DEFS := SHIBARI_SERVER=shibari-server SHIBARI_COMMON=shibari-common DCACHE=dcache
diff --git a/patch-for-solaris b/patch-for-solaris
new file mode 100755
index 0000000..2d1296b
--- /dev/null
+++ b/patch-for-solaris
@@ -0,0 +1,21 @@
+#!/usr/xpg4/bin/sh
+
+patchit () {
+ echo '#!/usr/xpg4/bin/sh' > $1.tmp
+ tail -n +2 $1 >> $1.tmp
+ mv -f $1.tmp $1
+ chmod 755 $1
+}
+
+# Solaris doesn't understand POSIX.1-2008 either.
+sed -e 's/XOPEN_SOURCE=700/XOPEN_SOURCE=600/' < configure > configure.tmp
+mv -f configure.tmp configure
+
+patchit ./configure
+patchit ./tools/install.sh
+patchit ./tools/gen-deps.sh
+
+echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp
+echo >> Makefile.tmp
+cat Makefile >> Makefile.tmp
+mv -f Makefile.tmp Makefile
diff --git a/src/cache/dcache-internal.h b/src/cache/dcache-internal.h
new file mode 100644
index 0000000..2a2e36f
--- /dev/null
+++ b/src/cache/dcache-internal.h
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#ifndef SHIBARI_DCACHE_INTERNAL_H
+#define SHIBARI_DCACHE_INTERNAL_H
+
+#include <stdint.h>
+
+#include <skalibs/avlnode.h>
+#include <skalibs/gensetdyn.h>
+
+#include <shibari/dcache.h>
+
+#define DNODE(z, i) GENSETDYN_P(dcache_node_t, &(z)->storage, i)
+#define DCACHE_NODE_OVERHEAD (32 + sizeof(dcache_node_t) + 3 * sizeof(avlnode))
+
+extern void dcache_delete (dcache_t *, uint32_t) ;
+
+#endif
diff --git a/src/cache/dcache_add.c b/src/cache/dcache_add.c
new file mode 100644
index 0000000..7260726
--- /dev/null
+++ b/src/cache/dcache_add.c
@@ -0,0 +1,85 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/alloc.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avlnode.h>
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+#include "dcache-internal.h"
+
+static void uniquify (avltree const *tree, tain *stamp)
+{
+ static tain const nano = { .sec = TAI_ZERO, .nano = 1 } ;
+ uint32_t dummy ;
+ while (avltree_search(tree, stamp, &dummy))
+ tain_add(stamp, stamp, &nano) ;
+}
+
+static inline void dcache_gc_by_entry (dcache_t *z, uint64_t max)
+{
+ while (z->size > max)
+ {
+ uint32_t oldest ;
+ if (!avltree_min(&z->by_entry, &oldest)) break ;
+ dcache_delete(z, oldest) ;
+ }
+}
+
+static inline int dcache_add_node (dcache_t *z, dcache_node_t const *node)
+{
+ uint32_t i ;
+ dcache_node_t *y ;
+ if (!gensetdyn_new(&z->storage, &i)) return 0 ;
+ y = DNODE(z, i) ; *y = *node ;
+ uniquify(&z->by_entry, &y->entry) ;
+ uniquify(&z->by_expire, &y->expire) ;
+ if (!avltree_insert(&z->by_key, i)) goto err1 ;
+ if (!avltree_insert(&z->by_entry, i)) goto err2 ;
+ if (!avltree_insert(&z->by_expire, i)) goto err3 ;
+ return 1 ;
+
+ err3:
+ avltree_delete(&z->by_entry, &y->entry) ;
+ err2:
+ avltree_delete(&z->by_key, &y->key) ;
+ err1:
+ gensetdyn_delete(&z->storage, i) ;
+ return 0 ;
+}
+
+static inline int dcache_add_unbounded (dcache_t *z, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp)
+{
+ uint32_t len = (uint32_t)keylen + (uint32_t)datalen ;
+ dcache_node_t y = { .key = { .s = alloc(len) } } ;
+ if (!y.key.s) return 0 ;
+ memcpy(y.key.s, key, keylen) ;
+ memcpy(y.key.s + keylen, data, datalen) ;
+ y.key.len = keylen ;
+ y.datalen = datalen ;
+ y.entry = *stamp ;
+ y.expire = *expire ;
+ if (!dcache_add_node(z, &y))
+ {
+ alloc_free(y.key.s) ;
+ return 0 ;
+ }
+ z->size += DCACHE_NODE_OVERHEAD + len ;
+ z->motion += DCACHE_NODE_OVERHEAD + len ;
+ return 1 ;
+}
+
+int dcache_add (dcache_t *z, uint64_t max, char const *key, uint16_t keylen, char const *data, uint16_t datalen, tain const *expire, tain const *stamp)
+{
+ uint64_t size = DCACHE_NODE_OVERHEAD + keylen + datalen ;
+ if (size > max) return (errno = EINVAL, 0) ;
+ if (z->size > max - size) dcache_clean_expired(z, stamp) ;
+ if (z->size > max - size) dcache_gc_by_entry(z, max - size) ;
+ return dcache_add_unbounded(z, key, keylen, data, datalen, expire, stamp) ;
+}
diff --git a/src/cache/dcache_clean_expired.c b/src/cache/dcache_clean_expired.c
new file mode 100644
index 0000000..0e23443
--- /dev/null
+++ b/src/cache/dcache_clean_expired.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/tai.h>
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+#include "dcache-internal.h"
+
+void dcache_clean_expired (dcache_t *z, tain const *stamp)
+{
+ for (;;)
+ {
+ uint32_t i ;
+ if (!avltree_min(&z->by_expire, &i)) break ;
+ if (tain_less(stamp, &DNODE(z, i)->expire)) break ;
+ dcache_delete(z, i) ;
+ }
+}
diff --git a/src/cache/dcache_delete.c b/src/cache/dcache_delete.c
new file mode 100644
index 0000000..92a5fcc
--- /dev/null
+++ b/src/cache/dcache_delete.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+#include "dcache-internal.h"
+
+void dcache_delete (dcache_t *z, uint32_t i)
+{
+ dcache_node_t *y = DNODE(z, i) ;
+ avltree_delete(&z->by_expire, &y->expire) ;
+ avltree_delete(&z->by_entry, &y->entry) ;
+ avltree_delete(&z->by_key, &y->key) ;
+ alloc_free(y->key.s) ;
+ z->size -= DCACHE_NODE_OVERHEAD + y->key.len + y->datalen ;
+ gensetdyn_delete(&z->storage, i) ;
+}
diff --git a/src/cache/dcache_free.c b/src/cache/dcache_free.c
new file mode 100644
index 0000000..16c074e
--- /dev/null
+++ b/src/cache/dcache_free.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+
+static void dcache_node_free (void *p)
+{
+ alloc_free(((dcache_node_t *)p)->key.s) ;
+}
+
+void dcache_free (dcache_t *z)
+{
+ static dcache_t const dcache_zero = DCACHE_ZERO ;
+ avltree_free(&z->by_expire) ;
+ avltree_free(&z->by_entry) ;
+ avltree_free(&z->by_key) ;
+ gensetdyn_deepfree(&z->storage, &dcache_node_free) ;
+ *z = dcache_zero ;
+}
diff --git a/src/cache/dcache_init.c b/src/cache/dcache_init.c
new file mode 100644
index 0000000..d42ec62
--- /dev/null
+++ b/src/cache/dcache_init.c
@@ -0,0 +1,55 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+
+static int key_cmp (void const *a, void const *b, void *x)
+{
+ dcache_key_t const *ka = a ;
+ dcache_key_t const *kb = b ;
+ if (ka->len < kb->len) return -1 ;
+ if (kb->len < ka->len) return 1 ;
+ (void)x ;
+ return memcmp(ka->s, kb->s, ka->len) ;
+}
+
+static int tain_cmp (void const *a, void const *b, void *x)
+{
+ tain const *ta = a ;
+ tain const *tb = b ;
+ (void)x ;
+ return tain_less(ta, tb) ? -1 : tain_less(tb, ta) ;
+}
+
+static void *key_dtok (uint32_t d, void *x)
+{
+ return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->key ;
+}
+
+static void *entry_dtok (uint32_t d, void *x)
+{
+ return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->entry ;
+}
+
+static void *expire_dtok (uint32_t d, void *x)
+{
+ return &GENSETDYN_P(dcache_node_t, (gensetdyn *)x, d)->expire ;
+}
+
+
+void dcache_init (dcache_t *z, uint64_t max)
+{
+ gensetdyn_init(&z->storage, sizeof(dcache_node_t), max >> 9, 3, 8) ;
+ avltree_init(&z->by_key, max >> 9, 3, 8, &key_dtok, &key_cmp, &z->storage) ;
+ avltree_init(&z->by_entry, max >> 9, 3, 8, &entry_dtok, &tain_cmp, &z->storage) ;
+ avltree_init(&z->by_expire, max >> 9, 3, 8, &expire_dtok, &tain_cmp, &z->storage) ;
+ z->size = 0 ;
+ z->motion = 0 ;
+}
diff --git a/src/cache/dcache_load.c b/src/cache/dcache_load.c
new file mode 100644
index 0000000..a0ff233
--- /dev/null
+++ b/src/cache/dcache_load.c
@@ -0,0 +1,81 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <skalibs/posixishard.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint64.h>
+#include <skalibs/buffer.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+
+#include <shibari/dcache.h>
+
+static inline int dcache_load_node (dcache_t *z, uint64_t max, buffer *b)
+{
+ tain entry = { .nano = 0 } ;
+ tain expire = { .nano = 0 } ;
+ uint16_t keylen ;
+ uint16_t datalen ;
+ char pack[TAI_PACK * 2 + 4] ;
+ ssize_t r = buffer_get(b, pack, TAI_PACK * 2 + 4) ;
+ if (!r) return 0 ;
+ if (r < TAI_PACK * 2 + 4) return -1 ;
+ tai_unpack(pack, tain_secp(&entry)) ;
+ tai_unpack(pack + TAI_PACK, tain_secp(&expire)) ;
+ uint16_unpack_big(pack + TAI_PACK * 2, &keylen) ;
+ uint16_unpack_big(pack + TAI_PACK * 2 + 2, &datalen) ;
+ {
+ uint32_t len = (uint32_t)keylen + (uint32_t)datalen ;
+ char blob[len+1] ; /* 128 kB max, it's ok */
+ r = buffer_get(b, blob, len+1) ;
+ if (!r) return (errno = EPIPE, -1) ;
+ if (r < len) return -1 ;
+ if (blob[len]) return (errno = EPROTO, -1) ;
+ if (!dcache_add(z, max, blob, keylen, blob + keylen, datalen, &expire, &entry)) return -1 ;
+ }
+ return 1 ;
+}
+
+static inline int dcache_load_from_buffer (dcache_t *z, uint64_t max, buffer *b)
+{
+ {
+ char banner[sizeof(DCACHE_MAGIC) - 1] ;
+ char pack[8] ;
+ if (buffer_get(b, banner, sizeof(DCACHE_MAGIC) - 1) < sizeof(DCACHE_MAGIC) - 1)
+ return 0 ;
+ if (memcmp(banner, DCACHE_MAGIC, sizeof(DCACHE_MAGIC) - 1)) return 0 ;
+ if (buffer_get(b, pack, 8) < 8) return 0 ;
+ uint64_unpack_big(pack, &z->size) ;
+ if (buffer_get(b, pack, 8) < 8) return 0 ;
+ uint64_unpack_big(pack, &z->motion) ;
+ }
+ for (;;)
+ {
+ int r = dcache_load_node(z, max, b) ;
+ if (r < 0) return 0 ;
+ if (!r) break ;
+ }
+ return 1 ;
+}
+
+#define N 8192
+
+int dcache_load (dcache_t *z, uint64_t max, char const *file)
+{
+ char buf[N] ;
+ buffer b ;
+ int fd = open_readb(file) ;
+ if (fd == -1) return 0 ;
+ buffer_init(&b, &buffer_read, fd, buf, N) ;
+ if (!dcache_load_from_buffer(z, max, &b)) goto err ;
+ fd_close(fd) ;
+ return 1 ;
+
+ err:
+ dcache_free(z) ;
+ fd_close(fd) ;
+ return 0 ;
+}
diff --git a/src/cache/dcache_save.c b/src/cache/dcache_save.c
new file mode 100644
index 0000000..7277771
--- /dev/null
+++ b/src/cache/dcache_save.c
@@ -0,0 +1,73 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint64.h>
+#include <skalibs/buffer.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/gensetdyn.h>
+
+#include <shibari/dcache.h>
+
+static int write_node_iter (void *data, void *aux)
+{
+ dcache_node_t *y = data ;
+ buffer *b = aux ;
+ char pack[TAI_PACK * 2 + 4] ;
+ tai_pack(pack, tain_secp(&y->entry)) ;
+ tai_pack(pack + TAI_PACK, tain_secp(&y->expire)) ;
+ uint16_pack(pack + TAI_PACK * 2, y->key.len) ;
+ uint16_pack(pack + TAI_PACK * 2 + 2, y->datalen) ;
+ if (buffer_put(b, pack, TAI_PACK * 2 + 4) == -1) return 0 ;
+ if (buffer_put(b, y->key.s, y->key.len + y->datalen) == -1) return 0 ;
+ if (buffer_put(b, "", 1) == -1) return 0 ;
+ return 1 ;
+}
+
+static inline int dcache_save_to_buffer (dcache_t const *z, buffer *b)
+{
+ char pack[16] ;
+ if (buffer_puts(b, DCACHE_MAGIC) == -1) return 0 ;
+ uint64_pack_big(pack, z->size) ;
+ uint64_pack_big(pack + 8, z->motion) ;
+ if (buffer_put(b, pack, 16) < 16) return 0 ;
+
+ /* XXX: can gensetdyn_iter blow up the stack if z->storage is huge? */
+ if (gensetdyn_iter_nocancel((gensetdyn *)&z->storage, gensetdyn_n(&z->storage), &write_node_iter, b) < gensetdyn_n(&z->storage)) return 0 ;
+
+ return buffer_flush(b) ;
+}
+
+#define N 8192
+
+int dcache_save (dcache_t const *z, char const *file)
+{
+ size_t len = strlen(file) ;
+ int fd ;
+ buffer b ;
+ char buf[N] ;
+ char tmp[len + 20] ;
+ memcpy(tmp, file, len) ;
+ memcpy(tmp + len, ":dcache_save:XXXXXX", 20) ;
+ fd = mkstemp(tmp) ;
+ if (fd == -1) return 0 ;
+ buffer_init(&b, &buffer_write, fd, buf, N) ;
+ if (!dcache_save_to_buffer(z, &b) || fsync(fd) < 0) goto err2 ;
+ fd_close(fd) ;
+ if (rename(tmp, file) == -1) goto err1 ;
+ return 1 ;
+
+ err2:
+ fd_close(fd) ;
+ err1:
+ unlink_void(tmp) ;
+ return 0 ;
+}
diff --git a/src/cache/dcache_search.c b/src/cache/dcache_search.c
new file mode 100644
index 0000000..0239b88
--- /dev/null
+++ b/src/cache/dcache_search.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/avltree.h>
+
+#include <shibari/dcache.h>
+#include "dcache-internal.h"
+
+dcache_node_t *dcache_search (dcache_t *z, char const *key, uint16_t keylen)
+{
+ uint32_t i ;
+ dcache_key_t k = { .s = (char *)key, .len = keylen } ;
+ return avltree_search(&z->by_key, &k, &i) ? DNODE(z, i) : 0 ;
+}
diff --git a/src/cache/deps-lib/dcache b/src/cache/deps-lib/dcache
new file mode 100644
index 0000000..fcc09a0
--- /dev/null
+++ b/src/cache/deps-lib/dcache
@@ -0,0 +1,8 @@
+dcache_add.o
+dcache_clean_expired.o
+dcache_delete.o
+dcache_free.o
+dcache_init.o
+dcache_load.o
+dcache_save.o
+dcache_search.o
diff --git a/src/common/deps-lib/shibari-common b/src/common/deps-lib/shibari-common
new file mode 100644
index 0000000..a5c44a4
--- /dev/null
+++ b/src/common/deps-lib/shibari-common
@@ -0,0 +1,10 @@
+shibari_log_answer.o
+shibari_log_exit.o
+shibari_log_query.o
+shibari_log_queryplus.o
+shibari_log_start.o
+shibari_util_qtype_num.o
+shibari_util_qtype_str.o
+shibari_util_rcode_str.o
+shibari_util_get_prefixlen.o
+-lskarnet
diff --git a/src/common/shibari_log_answer.c b/src/common/shibari_log_answer.c
new file mode 100644
index 0000000..f34cee5
--- /dev/null
+++ b/src/common/shibari_log_answer.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/strerr.h>
+
+#include <s6-dns/s6dns-message.h>
+
+#include <shibari/util.h>
+#include <shibari/log.h>
+
+void shibari_log_answer (uint32_t v, s6dns_message_header_t const *hdr, uint16_t len)
+{
+ if (v < 2) return ;
+ if (hdr->rcode)
+ {
+ char fmtr[UINT16_FMT] ;
+ fmtr[uint16_fmt(fmtr, hdr->rcode)] = 0 ;
+ strerr_warni4x("answer ", fmtr, " ", shibari_util_rcode_str(hdr->rcode)) ;
+ }
+ else
+ {
+ size_t pos = 0 ;
+ char fmt[UINT16_FMT << 2] ;
+ char fmtl[UINT16_FMT] ;
+ pos += uint16_fmt(fmt + pos, hdr->counts.qd) ;
+ fmt[pos++] = '+' ;
+ pos += uint16_fmt(fmt + pos, hdr->counts.an) ;
+ fmt[pos++] = '+' ;
+ pos += uint16_fmt(fmt + pos, hdr->counts.ns) ;
+ fmt[pos++] = '+' ;
+ pos += uint16_fmt(fmt + pos, hdr->counts.qd) ;
+ fmt[pos] = 0 ;
+ fmtl[uint16_fmt(fmtl, len)] = 0 ;
+ strerr_warni5x("answer 0 noerror ", fmt, " len ", fmtl, hdr->tc ? " tc" : "") ;
+ }
+}
diff --git a/src/common/shibari_log_exit.c b/src/common/shibari_log_exit.c
new file mode 100644
index 0000000..8e383c6
--- /dev/null
+++ b/src/common/shibari_log_exit.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <skalibs/types.h>
+#include <skalibs/strerr.h>
+
+#include <shibari/log.h>
+
+void shibari_log_exit (uint32_t v, int e)
+{
+ char fmt[UINT_FMT] ;
+ if (v < 2) return ;
+ fmt[uint_fmt(fmt, (unsigned int)e)] = 0 ;
+ strerr_warni2x("exit ", fmt) ;
+}
diff --git a/src/common/shibari_log_query.c b/src/common/shibari_log_query.c
new file mode 100644
index 0000000..b04ee27
--- /dev/null
+++ b/src/common/shibari_log_query.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/strerr.h>
+
+#include <s6-dns/s6dns-domain.h>
+
+#include <shibari/util.h>
+#include <shibari/log.h>
+
+void shibari_log_query (uint32_t v, s6dns_domain_t const *q, uint16_t qtype)
+{
+ char qs[256] ;
+ s6dns_domain_t qe ;
+ if (v < 2) return ;
+ qe = *q ;
+ if (!s6dns_domain_encode(&qe) || !s6dns_domain_tostring(qs, 256, &qe)) return ;
+ strerr_warni4x("query ", shibari_util_qtype_str(qtype), " ", qs) ;
+}
diff --git a/src/common/shibari_log_queryplus.c b/src/common/shibari_log_queryplus.c
new file mode 100644
index 0000000..7e7fecc
--- /dev/null
+++ b/src/common/shibari_log_queryplus.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/ip46.h>
+#include <skalibs/strerr.h>
+
+#include <s6-dns/s6dns-domain.h>
+
+#include <shibari/util.h>
+#include <shibari/log.h>
+
+void shibari_log_queryplus (uint32_t v, s6dns_domain_t const *q, uint16_t qtype, ip46 const *ip, uint16_t port)
+{
+ char qs[256] ;
+ char fmti[IP46_FMT] ;
+ char fmtp[UINT16_FMT] ;
+ s6dns_domain_t qe ;
+ if (v < 2) return ;
+ qe = *q ;
+ if (!s6dns_domain_encode(&qe) || !s6dns_domain_tostring(qs, 256, &qe)) return ;
+ fmti[ip46_fmt(fmti, ip)] = 0 ;
+ fmtp[uint16_fmt(fmtp, port)] = 0 ;
+ strerr_warni8x("query ", shibari_util_qtype_str(qtype), " ", qs, " ip ", fmti, " port ", fmtp) ;
+}
diff --git a/src/common/shibari_log_start.c b/src/common/shibari_log_start.c
new file mode 100644
index 0000000..214dc60
--- /dev/null
+++ b/src/common/shibari_log_start.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+#include <skalibs/ip46.h>
+#include <skalibs/strerr.h>
+
+#include <shibari/log.h>
+
+void shibari_log_start (uint32_t v, ip46 const *ip, uint16_t port)
+{
+ char fmti[IP46_FMT] ;
+ char fmtp[UINT16_FMT] ;
+ if (v < 2) return ;
+ fmti[ip46_fmt(fmti, ip)] = 0 ;
+ fmtp[uint16_fmt(fmtp, port)] = 0 ;
+ strerr_warni4x("start ip ", fmti, " port ", fmtp) ;
+}
diff --git a/src/common/shibari_util_get_prefixlen.c b/src/common/shibari_util_get_prefixlen.c
new file mode 100644
index 0000000..784a3ee
--- /dev/null
+++ b/src/common/shibari_util_get_prefixlen.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <shibari/util.h>
+
+int shibari_util_get_prefixlen (char const *name, uint16_t namelen, char const *zone, uint16_t zonelen)
+{
+ return
+ namelen < zonelen ? -1 :
+ memcmp(name + namelen - zonelen, zone, zonelen) ? -1 :
+ namelen - zonelen ;
+}
diff --git a/src/common/shibari_util_qtype_num.c b/src/common/shibari_util_qtype_num.c
new file mode 100644
index 0000000..350e268
--- /dev/null
+++ b/src/common/shibari_util_qtype_num.c
@@ -0,0 +1,121 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <strings.h>
+#include <stdlib.h>
+
+#include <shibari/util.h>
+
+struct map_s
+{
+ char const *s ;
+ uint16_t num ;
+} ;
+
+static int map_cmp (void const *a, void const *b)
+{
+ return strcasecmp((char const *)a, ((struct map_s const *)b)->s) ;
+}
+
+#define BSEARCH(key, array) bsearch(key, (array), sizeof(array)/sizeof(struct map_s), sizeof(struct map_s), &map_cmp)
+
+static struct map_s const qtype_table[] =
+{
+ { "*", 255 },
+ { "A", 1 },
+ { "A6", 38 },
+ { "AAAA", 28 },
+ { "AFSDB", 18 },
+ { "AMTRELAY", 260 },
+ { "ANY", 255 },
+ { "APL", 42 },
+ { "ATMA", 34 },
+ { "AVC", 258 },
+ { "AXFR", 252 },
+ { "CAA", 257 },
+ { "CDNSKEY", 60 },
+ { "CDS", 59 },
+ { "CERT", 37 },
+ { "CNAME", 5 },
+ { "CSYNC", 62 },
+ { "DHCID", 49 },
+ { "DLV", 32769 },
+ { "DNAME", 39 },
+ { "DNSKEY", 48 },
+ { "DOA", 259 },
+ { "DS", 43 },
+ { "EID", 31 },
+ { "EUI48", 108 },
+ { "EUI64", 109 },
+ { "GID", 102 },
+ { "GPOS", 27 },
+ { "HINFO", 13 },
+ { "HIP", 55 },
+ { "HTTPS", 65 },
+ { "IPSECKEY", 45 },
+ { "ISDN", 20 },
+ { "IXFR", 251 },
+ { "KEY", 25 },
+ { "KX", 36 },
+ { "L32", 105 },
+ { "L64", 106 },
+ { "LOC", 29 },
+ { "LP", 107 },
+ { "MAILA", 254 },
+ { "MAILB", 253 },
+ { "MB", 7 },
+ { "MD", 3 },
+ { "MF", 4 },
+ { "MG", 8 },
+ { "MINFO", 14 },
+ { "MR", 9 },
+ { "MX", 15 },
+ { "NAPTR", 35 },
+ { "NID", 104 },
+ { "NIMLOC", 32 },
+ { "NINFO", 56 },
+ { "NS", 2 },
+ { "NSAP", 22 },
+ { "NSAP-PTR", 23 },
+ { "NSEC", 47 },
+ { "NSEC3", 50 },
+ { "NSEC3PARAM", 51 },
+ { "NULL", 10 },
+ { "NXT", 30 },
+ { "OPENPGPKEY", 61 },
+ { "OPT", 41 },
+ { "PTR", 12 },
+ { "PX", 26 },
+ { "RESINFO", 261 },
+ { "RKEY", 57 },
+ { "RP", 17 },
+ { "RRSIG", 46 },
+ { "RT", 21 },
+ { "SIG", 24 },
+ { "SINK", 40 },
+ { "SMIMEA", 53 },
+ { "SOA", 6 },
+ { "SPF", 99 },
+ { "SRV", 33 },
+ { "SSHFP", 44 },
+ { "SVCB", 64 },
+ { "TA", 32768 },
+ { "TALINK", 58 },
+ { "TKEY", 249 },
+ { "TLSA", 52 },
+ { "TSIG", 250 },
+ { "TXT", 16 },
+ { "UID", 101 },
+ { "UINFO", 100 },
+ { "UNSPEC", 103 },
+ { "URI", 256 },
+ { "WKS", 11 },
+ { "X25", 19 },
+ { "ZONEMD", 63 }
+} ;
+
+uint16_t shibari_util_qtype_num (char const *s)
+{
+ struct map_s const *p = BSEARCH(s, qtype_table) ;
+ return p ? p->num : 0 ;
+}
diff --git a/src/common/shibari_util_qtype_str.c b/src/common/shibari_util_qtype_str.c
new file mode 100644
index 0000000..97b701d
--- /dev/null
+++ b/src/common/shibari_util_qtype_str.c
@@ -0,0 +1,285 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <shibari/util.h>
+
+static char const *const qtype_table[262] =
+{
+ "error",
+ "A",
+ "NS",
+ "MD",
+ "MF",
+ "CNAME",
+ "SOA",
+ "MB"
+ "MG",
+ "MR",
+ "NULL",
+ "WKS",
+ "PTR",
+ "HINFO",
+ "MINFO",
+ "MX",
+ "TXT",
+ "RP",
+ "AFSDB",
+ "X25",
+ "ISDN",
+ "RT",
+ "NSAP",
+ "NSAP-PTR",
+ "SIG",
+ "KEY",
+ "PX",
+ "GPOS",
+ "AAAA",
+ "LOC",
+ "NXT",
+ "EID",
+ "NIMLOC",
+ "SRV",
+ "ATMA",
+ "NAPTR",
+ "KX",
+ "CERT",
+ "A6",
+ "DNAME",
+ "SINK",
+ "OPT",
+ "APL",
+ "DS",
+ "SSHFP",
+ "IPSECKEY",
+ "RRSIG",
+ "NSEC",
+ "DNSKEY",
+ "DHCID",
+ "NSEC3",
+ "NSEC3PARAM",
+ "TLSA",
+ "SMIMEA",
+ "unassigned",
+ "HIP",
+ "NINFO",
+ "RKEY",
+ "TALINK",
+ "CDS",
+ "CDNSKEY",
+ "OPENPGPKEY",
+ "CSYNC",
+ "ZONEMD",
+ "SVCB",
+ "HTTPS",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "SPF",
+ "UINFO",
+ "UID",
+ "GID",
+ "UNSPEC",
+ "NID",
+ "L32",
+ "L64",
+ "LP",
+ "EUI48",
+ "EUI64",
+
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+
+ "TKEY",
+ "TSIG",
+ "IXFR",
+ "AXFR",
+ "MAILB",
+ "MAILA",
+ "*",
+ "URI",
+ "CAA",
+ "AVC",
+ "DOA",
+ "AMTRELAY",
+ "RESINFO"
+} ;
+
+
+char const *shibari_util_qtype_str (uint16_t qtype)
+{
+ if (qtype < 262) return qtype_table[qtype] ;
+ if (qtype < 32768) return "unassigned" ;
+ if (qtype == 32768) return "TA" ;
+ if (qtype == 32769) return "DLV" ;
+ if (qtype < 65279) return "unassigned" ;
+ if (qtype < 65535) return "private" ;
+ return "reserved" ;
+}
diff --git a/src/common/shibari_util_rcode_str.c b/src/common/shibari_util_rcode_str.c
new file mode 100644
index 0000000..142cc0e
--- /dev/null
+++ b/src/common/shibari_util_rcode_str.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <shibari/util.h>
+
+char const *shibari_util_rcode_str (uint16_t rcode)
+{
+ static char const *const rcode_table[24] =
+ {
+ "noerror",
+ "formerr",
+ "servfail",
+ "nxdomain",
+ "notimp",
+ "refused",
+ "yxdomain",
+ "yxrrset",
+ "nxrrset",
+ "notauth",
+ "notzone",
+ "dsotypeni",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "unassigned",
+ "badsig",
+ "badkey",
+ "badtime",
+ "badmode",
+ "badname",
+ "badalg",
+ "badtrunc",
+ "badcookie"
+ } ;
+ if (rcode < 24) return rcode_table[rcode] ;
+ if (rcode < 3841) return "unassigned" ;
+ if (rcode < 4096) return "private" ;
+ if (rcode < 65535) return "unassigned" ;
+ return "reserved" ;
+}
diff --git a/src/include/shibari/cache.h b/src/include/shibari/cache.h
new file mode 100644
index 0000000..d0c6004
--- /dev/null
+++ b/src/include/shibari/cache.h
@@ -0,0 +1,8 @@
+/* ISC license. */
+
+#ifndef SHIBARI_CACHE_H
+#define SHIBARI_CACHE_H
+
+#include <shibari/dcache.h>
+
+#endif
diff --git a/src/include/shibari/client.h b/src/include/shibari/client.h
new file mode 100644
index 0000000..03f8b1b
--- /dev/null
+++ b/src/include/shibari/client.h
@@ -0,0 +1,6 @@
+/* ISC license. */
+
+#ifndef SHIBARI_CLIENT_H
+#define SHIBARI_CLIENT_H
+
+#endif
diff --git a/src/include/shibari/common.h b/src/include/shibari/common.h
new file mode 100644
index 0000000..d36d055
--- /dev/null
+++ b/src/include/shibari/common.h
@@ -0,0 +1,9 @@
+/* ISC license. */
+
+#ifndef SHIBARI_COMMON_H
+#define SHIBARI_COMMON_H
+
+#include <shibari/constants.h>
+#include <shibari/util.h>
+
+#endif
diff --git a/src/include/shibari/constants.h b/src/include/shibari/constants.h
new file mode 100644
index 0000000..a4f86f3
--- /dev/null
+++ b/src/include/shibari/constants.h
@@ -0,0 +1,109 @@
+/* ISC license. */
+
+#ifndef SHIBARI_CONSTANTS_H
+#define SHIBARI_CONSTANTS_H
+
+enum shibari_qclass_e
+{
+ SHIBARI_C_IN = 1,
+ SHIBARI_C_CH = 3,
+ SHIBARI_C_HS = 4,
+ SHIBARI_C_NONE = 254,
+ SHIBARI_C_ANY = 255,
+} ;
+
+enum shibari_qtype_e
+{
+ SHIBARI_T_A = 1,
+ SHIBARI_T_NS = 2,
+ SHIBARI_T_MD = 3,
+ SHIBARI_T_MF = 4,
+ SHIBARI_T_CNAME = 5,
+ SHIBARI_T_SOA = 6,
+ SHIBARI_T_MB = 7,
+ SHIBARI_T_MG = 8,
+ SHIBARI_T_MR = 9,
+ SHIBARI_T_NULL = 10,
+ SHIBARI_T_WKS = 11,
+ SHIBARI_T_PTR = 12,
+ SHIBARI_T_HINFO = 13,
+ SHIBARI_T_MINFO = 14,
+ SHIBARI_T_MX = 15,
+ SHIBARI_T_TXT = 16,
+ SHIBARI_T_RP = 17,
+ SHIBARI_T_AFSDB = 18,
+ SHIBARI_T_X25 = 19,
+ SHIBARI_T_ISDN = 20,
+ SHIBARI_T_RT = 21,
+ SHIBARI_T_NSAP = 22,
+ SHIBARI_T_NSAP_PTR = 23,
+ SHIBARI_T_SIG = 24,
+ SHIBARI_T_KEY = 25,
+ SHIBARI_T_PX = 26,
+ SHIBARI_T_GPOS = 27,
+ SHIBARI_T_AAAA = 28,
+ SHIBARI_T_LOC = 29,
+ SHIBARI_T_NXT = 30,
+ SHIBARI_T_EID = 31,
+ SHIBARI_T_NIMLOC = 32,
+ SHIBARI_T_SRV = 33,
+ SHIBARI_T_ATMA = 34,
+ SHIBARI_T_NAPTR = 35,
+ SHIBARI_T_KX = 36,
+ SHIBARI_T_CERT = 37,
+ SHIBARI_T_A6 = 38,
+ SHIBARI_T_DNAME = 39,
+ SHIBARI_T_SINK = 40,
+ SHIBARI_T_OPT = 41,
+ SHIBARI_T_APL = 42,
+ SHIBARI_T_DS = 43,
+ SHIBARI_T_SSHFP = 44,
+ SHIBARI_T_IPSECKEY = 45,
+ SHIBARI_T_RRSIG = 46,
+ SHIBARI_T_NSEC = 47,
+ SHIBARI_T_DNSKEY = 48,
+ SHIBARI_T_DHCID = 49,
+ SHIBARI_T_NSEC3 = 50,
+ SHIBARI_T_NSEC3PARAM = 51,
+ SHIBARI_T_TLSA = 52,
+ SHIBARI_T_SMIMEA = 53,
+ SHIBARI_T_HIP = 55,
+ SHIBARI_T_NINFO = 56,
+ SHIBARI_T_RKEY = 57,
+ SHIBARI_T_TALINK = 58,
+ SHIBARI_T_CDS = 59,
+ SHIBARI_T_CDNSKEY = 60,
+ SHIBARI_T_OPENPGPKEY = 61,
+ SHIBARI_T_CSYNC = 62,
+ SHIBARI_T_ZONEMD = 63,
+ SHIBARI_T_SVCB = 64,
+ SHIBARI_T_HTTPS = 65,
+ SHIBARI_T_SPF = 99,
+ SHIBARI_T_UINFO = 100,
+ SHIBARI_T_UID = 101,
+ SHIBARI_T_GID = 102,
+ SHIBARI_T_UNSPEC = 103,
+ SHIBARI_T_NID = 104,
+ SHIBARI_T_L32 = 105,
+ SHIBARI_T_L64 = 106,
+ SHIBARI_T_LP = 107,
+ SHIBARI_T_EUI48 = 108,
+ SHIBARI_T_EUI64 = 109,
+ SHIBARI_T_TKEY = 249,
+ SHIBARI_T_TSIG = 250,
+ SHIBARI_T_IXFR = 251,
+ SHIBARI_T_AXFR = 252,
+ SHIBARI_T_MAILB = 253,
+ SHIBARI_T_MAILA = 254,
+ SHIBARI_T_ANY = 255,
+ SHIBARI_T_URI = 256,
+ SHIBARI_T_CAA = 257,
+ SHIBARI_T_AVC = 258,
+ SHIBARI_T_DOA = 259,
+ SHIBARI_T_AMIRELAY = 260,
+ SHIBARI_T_RESINFO = 261,
+ SHIBARI_T_TA = 32768,
+ SHIBARI_T_DLV = 32769
+} ;
+
+#endif
diff --git a/src/include/shibari/dcache.h b/src/include/shibari/dcache.h
new file mode 100644
index 0000000..6e0d0ab
--- /dev/null
+++ b/src/include/shibari/dcache.h
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#ifndef SHIBARI_DCACHE_H
+#define SHIBARI_DCACHE_H
+
+#include <stdint.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+#define DCACHE_MAGIC "--DCACHE--\n"
+
+typedef struct dcache_key_s dcache_key_t, *dcache_key_t_ref ;
+struct dcache_key_s
+{
+ char *s ;
+ uint16_t len ;
+} ;
+
+typedef struct dcache_node_s dcache_node_t, *dcache_node_t_ref ;
+struct dcache_node_s
+{
+ dcache_key_t key ;
+ uint16_t datalen ;
+ tain entry ;
+ tain expire ;
+} ;
+
+typedef struct dcache_s dcache_t, *dcache_t_ref ;
+struct dcache_s
+{
+ gensetdyn storage ; /* dcache_node_t */
+ avltree by_key ;
+ avltree by_entry ;
+ avltree by_expire ;
+ uint64_t size ;
+ uint64_t motion ;
+} ;
+#define DCACHE_ZERO { .storage = GENSETDYN_ZERO, .by_key = AVLTREE_ZERO, .by_entry = AVLTREE_ZERO, .by_expire = AVLTREE_ZERO, .size = 0, .motion = 0 }
+
+extern void dcache_init (dcache_t *, uint64_t) ;
+extern dcache_node_t *dcache_search (dcache_t *, char const *, uint16_t) ;
+extern int dcache_add (dcache_t *, uint64_t, char const *, uint16_t, char const *, uint16_t, tain const *, tain const *) ;
+#define dcache_add_g(d, max, key, keylen, data, datalen, expire) dcache_add(d, max, key, keylen, data, datalen, (expire), &STAMP)
+extern void dcache_clean_expired (dcache_t *, tain const *) ;
+#define dcache_clean_expired_g(d) dcache_clean_expired((d), &STAMP)
+extern void dcache_free (dcache_t *) ;
+
+extern int dcache_save (dcache_t const *, char const *) ;
+extern int dcache_load (dcache_t *, uint64_t, char const *) ;
+
+#endif
diff --git a/src/include/shibari/log.h b/src/include/shibari/log.h
new file mode 100644
index 0000000..a01e499
--- /dev/null
+++ b/src/include/shibari/log.h
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#ifndef SHIBARI_LOG_H
+#define SHIBARI_LOG_H
+
+#include <stdint.h>
+
+#include <skalibs/ip46.h>
+
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/s6dns-message.h>
+
+extern void shibari_log_start (uint32_t, ip46 const *, uint16_t) ;
+extern void shibari_log_exit (uint32_t, int) ;
+
+extern void shibari_log_query (uint32_t, s6dns_domain_t const *, uint16_t) ;
+extern void shibari_log_queryplus (uint32_t, s6dns_domain_t const *, uint16_t, ip46 const *, uint16_t) ;
+extern void shibari_log_answer (uint32_t, s6dns_message_header_t const *, uint16_t) ;
+
+#endif
diff --git a/src/include/shibari/packet.h b/src/include/shibari/packet.h
new file mode 100644
index 0000000..1f4fa93
--- /dev/null
+++ b/src/include/shibari/packet.h
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#ifndef SHIBARI_PACKET_H
+#define SHIBARI_PACKET_H
+
+#include <stdint.h>
+
+#include <skalibs/cdb.h>
+#include <skalibs/tai.h>
+
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/s6dns-message.h>
+
+#include <shibari/tdb.h>
+
+typedef struct shibari_packet_s shibari_packet, *shibari_packet_ref ;
+struct shibari_packet_s
+{
+ s6dns_message_header_t hdr ;
+ char *buf ;
+ uint16_t max ;
+ uint16_t pos ;
+ uint8_t flagtcp : 1 ;
+} ;
+#define SHIBARI_PACKET_ZERO { .hdr = S6DNS_MESSAGE_HEADER_ZERO, .buf = "", .pos = 0, .flagtcp = 0 }
+#define SHIBARI_PACKET_INIT(rbuf, rmax, tcp) { .hdr = S6DNS_MESSAGE_HEADER_ZERO, .buf = tcp ? rbuf + 2 : rbuf, .max = tcp ? rmax - 2 : rmax, .pos = 0, .flagtcp = !!tcp }
+
+extern void shibari_packet_init (shibari_packet *, char *, uint32_t, int) ;
+
+extern void shibari_packet_begin (shibari_packet *, uint16_t, s6dns_domain_t const *, uint16_t) ;
+extern void shibari_packet_end (shibari_packet *) ;
+
+extern int shibari_packet_add_rr (shibari_packet *, shibari_tdb_entry const *, int, uint16_t, unsigned int) ;
+extern unsigned int shibari_packet_add_glue (shibari_packet *, cdb const *, char const *, uint16_t, uint16_t, char const *, uint16_t, uint16_t, uint16_t, char const *, tain const *) ;
+extern unsigned int shibari_packet_assert_authority (shibari_packet *, cdb const *, char const *, uint16_t, uint16_t, char const *, tain const *) ;
+
+extern unsigned int shibari_packet_tdb_answer_query (shibari_packet *, cdb const *, s6dns_message_header_t const *, s6dns_domain_t const *, uint16_t, char const *, tain const *) ;
+
+#endif
diff --git a/src/include/shibari/server.h b/src/include/shibari/server.h
new file mode 100644
index 0000000..db5af40
--- /dev/null
+++ b/src/include/shibari/server.h
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#ifndef SHIBARI_SERVER_H
+#define SHIBARI_SERVER_H
+
+#include <shibari/log.h>
+#include <shibari/tdb.h>
+#include <shibari/packet.h>
+
+#endif
diff --git a/src/include/shibari/shibari.h b/src/include/shibari/shibari.h
new file mode 100644
index 0000000..a9242d3
--- /dev/null
+++ b/src/include/shibari/shibari.h
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#ifndef SHIBARI_H
+#define SHIBARI_H
+
+#include <shibari/common.h>
+#include <shibari/client.h>
+#include <shibari/cache.h>
+#include <shibari/server.h>
+
+#endif
diff --git a/src/include/shibari/tdb.h b/src/include/shibari/tdb.h
new file mode 100644
index 0000000..f61df5b
--- /dev/null
+++ b/src/include/shibari/tdb.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef SHIBARI_TDB_H
+#define SHIBARI_TDB_H
+
+#include <stdint.h>
+
+#include <skalibs/cdb.h>
+#include <skalibs/tai.h>
+
+#include <s6-dns/s6dns-message.h>
+
+typedef struct shibari_tdb_entry_s shibari_tdb_entry, *shibari_tdb_entry_ref ;
+struct shibari_tdb_entry_s
+{
+ uint16_t type ;
+ uint16_t len ;
+ uint32_t ttl ;
+ uint32_t flags ;
+ cdb_data key ;
+ cdb_data data ;
+} ;
+
+extern int shibari_tdb_entry_parse (shibari_tdb_entry *, char const *, uint16_t, uint16_t, unsigned int, char const *, tain const *) ;
+extern int shibari_tdb_read_entry (cdb const *, cdb_find_state *, shibari_tdb_entry *, char const *, uint16_t, uint16_t, unsigned int, char const *, tain const *, uint32_t *) ;
+extern int shibari_tdb_extract_domain (shibari_tdb_entry const *, cdb_data *) ;
+extern int shibari_tdb_find_authority (cdb const *, char const *, uint16_t, char const *, tain const *, int *) ;
+
+#endif
diff --git a/src/include/shibari/util.h b/src/include/shibari/util.h
new file mode 100644
index 0000000..82092a3
--- /dev/null
+++ b/src/include/shibari/util.h
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#ifndef SHIBARI_UTIL_H
+#define SHIBARI_UTIL_H
+
+#include <stdint.h>
+
+extern char const *shibari_util_qtype_str (uint16_t) ;
+extern uint16_t shibari_util_qtype_num (char const *) ;
+extern char const *shibari_util_rcode_str (uint16_t) ;
+
+extern int shibari_util_get_prefixlen (char const *, uint16_t, char const *, uint16_t) ;
+
+#endif
diff --git a/src/server/deps-exe/shibari-server-tcp b/src/server/deps-exe/shibari-server-tcp
new file mode 100644
index 0000000..c25f645
--- /dev/null
+++ b/src/server/deps-exe/shibari-server-tcp
@@ -0,0 +1,4 @@
+${LIBSHIBARI_SERVER}
+${LIBSHIBARI_COMMON}
+-ls6dns
+-lskarnet
diff --git a/src/server/deps-exe/shibari-server-udp b/src/server/deps-exe/shibari-server-udp
new file mode 100644
index 0000000..0c1f81d
--- /dev/null
+++ b/src/server/deps-exe/shibari-server-udp
@@ -0,0 +1,6 @@
+${LIBSHIBARI_SERVER}
+${LIBSHIBARI_COMMON}
+-ls6dns
+-ls6
+-lskarnet
+${SOCKET_LIB}
diff --git a/src/server/deps-lib/shibari-server b/src/server/deps-lib/shibari-server
new file mode 100644
index 0000000..7c5b981
--- /dev/null
+++ b/src/server/deps-lib/shibari-server
@@ -0,0 +1,13 @@
+shibari_packet_init.o
+shibari_packet_begin.o
+shibari_packet_end.o
+shibari_packet_add_rr.o
+shibari_tdb_entry_parse.o
+shibari_tdb_extract_domain.o
+shibari_tdb_find_authority.o
+shibari_tdb_read_entry.o
+shibari_packet_add_glue.o
+shibari_packet_assert_authority.o
+shibari_packet_tdb_answer_query.o
+-ls6dns
+-lskarnet
diff --git a/src/server/shibari-server-tcp.c b/src/server/shibari-server-tcp.c
new file mode 100644
index 0000000..e646a44
--- /dev/null
+++ b/src/server/shibari-server-tcp.c
@@ -0,0 +1,235 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/types.h>
+#include <skalibs/strerr.h>
+#include <skalibs/buffer.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/sig.h>
+#include <skalibs/tai.h>
+#include <skalibs/ip46.h>
+#include <skalibs/cdb.h>
+#include <skalibs/unix-timed.h>
+
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/s6dns-message.h>
+
+#include <shibari/common.h>
+#include <shibari/server.h>
+
+#define PROGNAME "shibari-server-tcp"
+#define USAGE PROGNAME " [ -v verbosity ] [ -f cdbfile ] [ -r timeout ] [ -w timeout ]"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+#define QMAX 2048
+#define RMAX 65535
+
+static uint32_t verbosity = 1 ;
+
+static inline void get_socket_info (ip46 *localip, uint16_t *localport, ip46 *remoteip, uint16_t *remoteport)
+{
+ char const *x = getenv("PROTO") ;
+ if (!x) strerr_dienotset(100, "PROTO") ;
+ {
+ size_t protolen = strlen(x) ;
+ char var[protolen + 11] ;
+ memcpy(var, x, protolen) ;
+ memcpy(var + protolen, "LOCALIP", 8) ;
+ x = getenv(var) ;
+ if (!x) strerr_dienotset(100, var) ;
+ if (!ip46_scan(x, localip)) strerr_dieinvalid(100, var) ;
+ memcpy(var + protolen + 5, "PORT", 5) ;
+ x = getenv(var) ;
+ if (!x) strerr_dienotset(100, var) ;
+ if (!uint160_scan(x, localport)) strerr_dieinvalid(100, var) ;
+ memcpy(var + protolen, "REMOTEIP", 9) ;
+ x = getenv(var) ;
+ if (!x) strerr_dienotset(100, var) ;
+ if (!ip46_scan(x, remoteip)) strerr_dieinvalid(100, var) ;
+ memcpy(var + protolen + 6, "PORT", 5) ;
+ x = getenv(var) ;
+ if (!x) strerr_dienotset(100, var) ;
+ if (!uint160_scan(x, remoteport)) strerr_dieinvalid(100, var) ;
+ }
+}
+
+static void add (shibari_packet *pkt, shibari_tdb_entry const *entry, int prefixlen, uint16_t id, s6dns_domain_t const *zone, tain const *deadline)
+{
+ if (!shibari_packet_add_rr(pkt, entry, prefixlen, 0, 2))
+ {
+ shibari_packet_end(pkt) ;
+ if (!buffer_timed_put_g(buffer_1, pkt->buf - 2, pkt->pos + 2, deadline))
+ strerr_diefu1sys(111, "write to stdout") ;
+ shibari_packet_begin(pkt, id, zone, SHIBARI_T_AXFR) ;
+ if (!shibari_packet_add_rr(pkt, entry, prefixlen, 0, 2))
+ strerr_dief1x(101, "can't happen: record too long to fit in single packet") ;
+ }
+}
+
+static inline int axfr (char const *axfrok, char const *loc, cdb const *tdb, s6dns_message_header_t const *qhdr, s6dns_domain_t const *zone, shibari_packet *pkt, tain const *deadline, tain const *wstamp)
+{
+ shibari_tdb_entry soa ;
+ shibari_tdb_entry cur ;
+ uint32_t pos = CDB_TRAVERSE_INIT() ;
+ if (!axfrok) return 5 ;
+ if (axfrok[0] != '*')
+ {
+ s6dns_domain_t decoded = *zone ;
+ unsigned int zonelen ;
+ size_t len = strlen(axfrok) + 1 ;
+ char buf[256] ;
+ if (!s6dns_domain_decode(&decoded)) return 1 ;
+ zonelen = s6dns_domain_tostring(buf, 256, &decoded) ;
+ while (len >= zonelen)
+ {
+ if (!strncmp(buf, axfrok, zonelen) && (!axfrok[zonelen] || strchr("/,; \t\n", axfrok[zonelen]))) break ;
+ axfrok += zonelen + 1 ;
+ len -= zonelen + 1 ;
+ }
+ if (len < zonelen) return 5 ;
+ }
+
+ {
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ int r = shibari_tdb_read_entry(tdb, &state, &soa, zone->s, zone->len, SHIBARI_T_SOA, 0, loc, wstamp, 0) ;
+ if (r == -1) return 2 ;
+ if (!r) return 9 ;
+ }
+
+ shibari_packet_begin(pkt, qhdr->id, zone, SHIBARI_T_AXFR) ;
+ pkt->hdr.aa = 1 ;
+ add(pkt, &soa, 0, qhdr->id, zone, deadline) ;
+
+ for (;;)
+ {
+ cdb_data data ;
+ int prefixlen ;
+ int r = cdb_traverse_next(tdb, &cur.key, &data, &pos) ;
+ if (r == -1) return 2 ;
+ if (!r) break ;
+ prefixlen = shibari_util_get_prefixlen(cur.key.s, cur.key.len, zone->s, zone->len) ;
+ if (prefixlen == -1) continue ;
+ r = shibari_tdb_entry_parse(&cur, data.s, data.len, SHIBARI_T_ANY, 2, loc, wstamp) ;
+ if (r == -1) return 2 ;
+ if (!r) continue ;
+ if (cur.type == SHIBARI_T_SOA) continue ;
+ add(pkt, &cur, prefixlen, qhdr->id, zone, deadline) ;
+ }
+
+ add(pkt, &soa, 0, qhdr->id, zone, deadline) ;
+ shibari_packet_end(pkt) ;
+ return 0 ;
+}
+
+int main (int argc, char const *const *argv)
+{
+ cdb tdb = CDB_ZERO ;
+ char const *axfrok = getenv("AXFR") ;
+ char const *loc = getenv("LOC") ;
+ tain rtto = TAIN_INFINITE_RELATIVE, wtto = TAIN_INFINITE_RELATIVE ;
+ ip46 localip, remoteip ;
+ uint16_t localport, remoteport ;
+ char progbuf[sizeof(PROGNAME) + 5 + PID_FMT] = PROGNAME ": pid " ;
+ char buf[RMAX + 2] ;
+ shibari_packet pkt = SHIBARI_PACKET_INIT(buf, RMAX + 2, 1) ;
+ PROG = "shibari-server-tcp" ;
+
+ {
+ size_t pos = sizeof(PROGNAME) + 5 ;
+ pos += pid_fmt(progbuf + pos, getpid()) ;
+ progbuf[pos++] = 0 ;
+ }
+
+ {
+ char const *tdbfile = "data.cdb" ;
+ uint32_t r = 0, w = 0 ;
+ subgetopt l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "v:f:r:w:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : if (!uint320_scan(l.arg, &verbosity)) dieusage() ; break ;
+ case 'f' : tdbfile = l.arg ; break ;
+ case 'r' : if (!uint320_scan(l.arg, &r)) dieusage() ; break ;
+ case 'w' : if (!uint320_scan(l.arg, &w)) dieusage() ; break ;
+ default : dieusage() ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ if (r) tain_from_millisecs(&rtto, r) ;
+ if (w) tain_from_millisecs(&wtto, w) ;
+ get_socket_info(&localip, &localport, &remoteip, &remoteport) ;
+ PROG = progbuf ;
+ if (!cdb_init(&tdb, tdbfile)) strerr_diefu2sys(111, "open DNS database file ", tdbfile) ;
+ }
+
+ if (!sig_altignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ;
+ tain_now_set_stopwatch_g() ;
+ shibari_log_start(verbosity, &remoteip, remoteport) ;
+
+ for (;;)
+ {
+ tain wstamp ;
+ size_t w ;
+ tain deadline ;
+ s6dns_message_header_t hdr ;
+ s6dns_message_counts_t counts ;
+ s6dns_domain_t name ;
+ unsigned int rcode ;
+ uint16_t qtype ;
+ uint16_t len ;
+ tain_add_g(&deadline, &rtto) ;
+ w = buffer_timed_get_g(buffer_0, buf, 2, &deadline) ;
+ if (w == 1) strerr_dief1x(1, "invalid request") ;
+ if (!w)
+ {
+ if (errno != EPIPE && errno != ETIMEDOUT)
+ strerr_diefu1sys(111, "read from stdin") ;
+ else break ;
+ }
+ uint16_unpack_big(buf, &len) ;
+ if (len > QMAX) strerr_dief1x(1, "request too large") ;
+ if (buffer_timed_get_g(buffer_0, buf, len, &deadline) < len)
+ strerr_diefu1sys(111, "read from stdin") ;
+
+ if (!s6dns_message_parse_init(&hdr, &counts, buf, len, &rcode))
+ strerr_diefu1sys(111, "parse message") ;
+ if (hdr.opcode) { rcode = 4 ; goto answer ; }
+ if (!s6dns_message_parse_question(&counts, &name, &qtype, buf, len, &rcode) || !s6dns_domain_encode(&name))
+ {
+ rcode = errno == ENOTSUP ? 4 : 1 ;
+ goto answer ;
+ }
+ shibari_log_query(verbosity, &name, qtype) ;
+ tain_add_g(&deadline, &wtto) ;
+ tain_wallclock_read(&wstamp) ;
+ rcode = qtype == SHIBARI_T_AXFR ?
+ axfr(axfrok, loc, &tdb, &hdr, &name, &pkt, &deadline, &wstamp) :
+ shibari_packet_tdb_answer_query(&pkt, &tdb, &hdr, &name, qtype, loc, &wstamp) ;
+
+ answer:
+ if (rcode && rcode != 3)
+ {
+ shibari_packet_begin(&pkt, hdr.id, &name, qtype) ;
+ pkt.hdr.rcode = rcode ;
+ shibari_packet_end(&pkt) ;
+ }
+ shibari_log_answer(verbosity, &pkt.hdr, pkt.pos) ;
+ if (!buffer_timed_put_g(buffer_1, buf, pkt.pos + 2, &deadline)
+ || !buffer_timed_flush_g(buffer_1, &deadline))
+ strerr_diefu1sys(111, "write to stdout") ;
+ }
+
+ shibari_log_exit(verbosity, 0) ;
+ return 0 ;
+}
diff --git a/src/server/shibari-server-udp.c b/src/server/shibari-server-udp.c
new file mode 100644
index 0000000..d834c94
--- /dev/null
+++ b/src/server/shibari-server-udp.c
@@ -0,0 +1,207 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/types.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/tai.h>
+#include <skalibs/socket.h>
+#include <skalibs/ip46.h>
+#include <skalibs/cdb.h>
+#include <skalibs/sig.h>
+
+#include <s6/accessrules.h>
+
+#include <shibari/common.h>
+#include <shibari/server.h>
+
+#define USAGE "shibari-server-udp [ -v verbosity ] [ -d notif ] [ -f cdbfile ] [ -i rulesdir | -x rulesfile ] [ -p port ] ip"
+#define dieusage() strerr_dieusage(100, USAGE)
+
+#define VAR "LOC"
+
+static char const *tdbfile = "data.cdb" ;
+static cdb tdb = CDB_ZERO ;
+static cdb rules = CDB_ZERO ;
+static char const *rulesfile = 0 ;
+static unsigned int rulestype = 0 ;
+static int cont = 1 ;
+static uint32_t verbosity = 1 ;
+
+static void on_term (int s)
+{
+ (void)s ;
+ cont = 0 ;
+}
+
+static void on_hup (int s)
+{
+ cdb newtdb = CDB_ZERO ;
+ (void)s ;
+ if (!cdb_init(&newtdb, tdbfile))
+ {
+ if (verbosity) strerr_warnwu2sys("reopen DNS data file ", tdbfile) ;
+ }
+ else
+ {
+ cdb_free(&tdb) ;
+ tdb = newtdb ;
+ }
+ if (rulestype == 2)
+ {
+ cdb newrules = CDB_ZERO ;
+ if (!cdb_init(&newrules, rulesfile))
+ {
+ if (verbosity) strerr_warnwu2sys("reopen access rules file ", rulesfile) ;
+ }
+ else
+ {
+ cdb_free(&rules) ;
+ rules = newrules ;
+ }
+ }
+}
+
+static int check_rules (ip46 const *remoteip, s6_accessrules_params_t *params, char const **loc)
+{
+ s6_accessrules_result_t r ;
+ params->env.len = 0 ;
+ params->exec.len = 0 ;
+ r = rulestype == 2 ?
+ s6_accessrules_ip46_cdb(remoteip, &rules, params) :
+ s6_accessrules_ip46_fs(remoteip, rulesfile, params) ;
+ if (r != S6_ACCESSRULES_ALLOW) return 0 ;
+
+ if (params->env.len)
+ {
+ char const *p ;
+ if (params->env.s[params->env.len - 1])
+ {
+ if (verbosity)
+ {
+ char fmt[IP46_FMT] ;
+ fmt[ip46_fmt(fmt, remoteip)] = 0 ;
+ strerr_warnw6x("invalid environment parameters in rules ", rulestype == 2 ? "cdb " : "directory ", rulesfile, " for ip ", fmt, " - denying connection") ;
+ }
+ return 0 ;
+ }
+ p = memmem(params->env.s, params->env.len - 1, VAR "=", sizeof(VAR)) ;
+ if (p && (p == params->env.s || !p[-1])) *loc = p + sizeof(VAR) ;
+ }
+ return 1 ;
+}
+
+int main (int argc, char const *const *argv)
+{
+ s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ;
+ int s ;
+ unsigned int notif = 0 ;
+ char buf[512] ;
+ shibari_packet pkt = SHIBARI_PACKET_INIT(buf, 512, 0) ;
+ uint16_t localport = 53 ;
+ ip46 localip ;
+
+ PROG = "shibari-server-udp" ;
+
+ {
+ subgetopt l = SUBGETOPT_ZERO ;
+ for (;;)
+ {
+ int opt = subgetopt_r(argc, argv, "v:d:f:i:x:p:", &l) ;
+ if (opt == -1) break ;
+ switch (opt)
+ {
+ case 'v' : if (!uint320_scan(l.arg, &verbosity)) dieusage() ; break ;
+ case 'd' : if (!uint0_scan(l.arg, &notif)) dieusage() ; break ;
+ case 'f' : tdbfile = l.arg ; break ;
+ case 'i' : rulesfile = l.arg ; rulestype = 1 ; break ;
+ case 'x' : rulesfile = l.arg ; rulestype = 2 ; break ;
+ case 'p' : if (!uint160_scan(l.arg, &localport)) dieusage() ; break ;
+ default : strerr_dieusage(10, USAGE) ;
+ }
+ }
+ argc -= l.ind ; argv += l.ind ;
+ }
+
+ if (!argc) dieusage() ;
+ if (!ip46_scan(argv[0], &localip)) dieusage() ;
+
+ if (notif)
+ {
+ if (notif < 3) strerr_dief1x(100, "notification fd cannot be 0, 1 or 2") ;
+ if (fcntl(notif, F_GETFD) == -1) strerr_diefu1sys(111, "check notification fd") ;
+ }
+
+ close(0) ;
+ close(1) ;
+ s = socket_udp46_b(ip46_is6(&localip)) ;
+ if (s == -1) strerr_diefu1sys(111, "create socket") ;
+ if (socket_bind46_reuse(s, &localip, localport) == -1) strerr_diefu1sys(111, "bind socket") ;
+
+ if (!cdb_init(&tdb, tdbfile)) strerr_diefu2sys(111, "open cdb file ", tdbfile) ;
+ if (rulestype == 2 && !cdb_init(&rules, rulesfile)) strerr_diefu2sys(111, "open rules file ", rulesfile) ;
+ if (!sig_catch(SIGHUP, &on_hup)) strerr_diefu1sys(111, "catch SIGHUP") ;
+ if (!sig_catch(SIGTERM, &on_term)) strerr_diefu1sys(111, "catch SIGTERM") ;
+
+ shibari_log_start(verbosity, &localip, localport) ;
+ if (notif)
+ {
+ write(notif, "\n", 1) ;
+ close(notif) ;
+ }
+
+ for (; cont ; sig_unblock(SIGHUP))
+ {
+ tain wstamp ;
+ char const *loc = 0 ;
+ s6dns_message_header_t hdr ;
+ s6dns_message_counts_t counts ;
+ s6dns_domain_t name ;
+ unsigned int rcode ;
+ ssize_t r ;
+ uint16_t qtype ;
+ uint16_t remoteport ;
+ ip46 remoteip ;
+
+ r = socket_recv46(s, buf, 512, &remoteip, &remoteport) ;
+ if (r == -1) strerr_diefu1sys(111, "recv from socket") ;
+ if (!r) strerr_dief1x(111, "huh? got EOF on a connection-less socket") ;
+ sig_block(SIGHUP) ;
+ if (rulestype && !check_rules(&remoteip, &params, &loc)) continue ;
+ if (!s6dns_message_parse_init(&hdr, &counts, buf, r, &rcode)) continue ;
+ if (hdr.opcode) { rcode = 4 ; goto answer ; }
+ if (!s6dns_message_parse_question(&counts, &name, &qtype, buf, r, &rcode) || !s6dns_domain_encode(&name))
+ {
+ rcode = errno == ENOTSUP ? 4 : 1 ;
+ goto answer ;
+ }
+ shibari_log_queryplus(verbosity, &name, qtype, &remoteip, remoteport) ;
+ tain_wallclock_read(&wstamp) ;
+ rcode = shibari_packet_tdb_answer_query(&pkt, &tdb, &hdr, &name, qtype, loc, &wstamp) ;
+
+ answer:
+ if (rcode && rcode != 3)
+ {
+ shibari_packet_begin(&pkt, hdr.id, &name, qtype) ;
+ pkt.hdr.rcode = rcode ;
+ shibari_packet_end(&pkt) ;
+ }
+ shibari_log_answer(verbosity, &pkt.hdr, pkt.pos) ;
+ if (socket_send46(s, buf, pkt.pos, &remoteip, remoteport) < pkt.pos && verbosity)
+ strerr_warnwu1sys("send answer") ;
+ }
+
+ shibari_log_exit(verbosity, 0) ;
+ return 0 ;
+}
diff --git a/src/server/shibari_packet_add_glue.c b/src/server/shibari_packet_add_glue.c
new file mode 100644
index 0000000..4a0abf1
--- /dev/null
+++ b/src/server/shibari_packet_add_glue.c
@@ -0,0 +1,48 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+#include <shibari/constants.h>
+#include <shibari/util.h>
+#include <shibari/tdb.h>
+#include <shibari/packet.h>
+
+static int shibari_packet_add_glue_for_rr (shibari_packet *pkt, cdb const *tdb, char const *s, uint16_t len, uint16_t prefixlen, uint16_t offset, char const *loc, tain const *stamp)
+{
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ for (;;)
+ {
+ shibari_tdb_entry entry ;
+ int r = shibari_tdb_read_entry(tdb, &state, &entry, s, len, SHIBARI_T_ANY, 0, loc, stamp, 0) ;
+ if (r == -1) return 2 ;
+ if (!r) break ;
+ if (entry.type != SHIBARI_T_A && entry.type != SHIBARI_T_AAAA) continue ;
+ if (!shibari_packet_add_rr(pkt, &entry, prefixlen, offset, 4))
+ {
+ pkt->hdr.tc = 1 ;
+ return 0 ;
+ }
+ }
+ return -1 ;
+}
+
+unsigned int shibari_packet_add_glue (shibari_packet *pkt, cdb const *tdb, char const *s, uint16_t len, uint16_t qtype, char const *z, uint16_t zlen, uint16_t zoffset, uint16_t wildpos, char const *loc, tain const *stamp)
+{
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ for (;;)
+ {
+ shibari_tdb_entry entry ;
+ cdb_data domain ;
+ int zprefixlen, sprefixlen ;
+ int r = shibari_tdb_read_entry(tdb, &state, &entry, s + wildpos, len - wildpos, qtype, !!wildpos, loc, stamp, 0) ;
+ if (r == -1) return 2 ;
+ if (!r) break ;
+ if (!shibari_tdb_extract_domain(&entry, &domain)) continue ;
+ zprefixlen = shibari_util_get_prefixlen(domain.s, domain.len, z, zlen) ;
+ if (zprefixlen == -1) continue ;
+ sprefixlen = shibari_util_get_prefixlen(domain.s, domain.len, s, len) ;
+ r = shibari_packet_add_glue_for_rr(pkt, tdb, domain.s, domain.len, sprefixlen == -1 ? zprefixlen : sprefixlen, sprefixlen == -1 ? zoffset : 0, loc, stamp) ;
+ if (r >= 0) return r ;
+ }
+ return 0 ;
+}
diff --git a/src/server/shibari_packet_add_rr.c b/src/server/shibari_packet_add_rr.c
new file mode 100644
index 0000000..b92e8dd
--- /dev/null
+++ b/src/server/shibari_packet_add_rr.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+
+#include <shibari/constants.h>
+#include <shibari/packet.h>
+
+int shibari_packet_add_rr (shibari_packet *p, shibari_tdb_entry const *entry, int prefixlen, uint16_t offset, unsigned int section)
+{
+ uint16_t *count[4] = { &p->hdr.counts.qd, &p->hdr.counts.an, &p->hdr.counts.ns, &p->hdr.counts.nr } ;
+ uint16_t rrlen = 10 + entry->data.len + (entry->flags & 1 ? 2 : 0) + (prefixlen >= 0 ? prefixlen + 2 : entry->key.len) ;
+ if (p->max - p->pos < rrlen) return 0 ;
+ if (entry->flags & 1)
+ {
+ p->buf[p->pos++] = 1 ;
+ p->buf[p->pos++] = '*' ;
+ }
+ if (prefixlen >= 0)
+ {
+ memcpy(p->buf + p->pos, entry->key.s, prefixlen) ;
+ p->pos += prefixlen ;
+ uint16_pack_big(p->buf + p->pos, 49164 + offset) ;
+ p->pos += 2 ;
+ }
+ else
+ {
+ memcpy(p->buf + p->pos, entry->key.s, entry->key.len) ;
+ p->pos += entry->key.len ;
+ }
+ uint16_pack_big(p->buf + p->pos, entry->type) ;
+ p->pos += 2 ;
+ uint16_pack_big(p->buf + p->pos, SHIBARI_C_IN) ;
+ p->pos += 2 ;
+ uint32_pack_big(p->buf + p->pos, entry->ttl) ;
+ p->pos += 4 ;
+ uint16_pack_big(p->buf + p->pos, entry->data.len) ;
+ p->pos += 2 ;
+ memcpy(p->buf + p->pos, entry->data.s, entry->data.len) ;
+ p->pos += entry->data.len ;
+ (*count[section-1])++ ;
+ return 1 ;
+}
diff --git a/src/server/shibari_packet_assert_authority.c b/src/server/shibari_packet_assert_authority.c
new file mode 100644
index 0000000..18c8299
--- /dev/null
+++ b/src/server/shibari_packet_assert_authority.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+#include <shibari/constants.h>
+#include <shibari/util.h>
+#include <shibari/tdb.h>
+#include <shibari/packet.h>
+
+unsigned int shibari_packet_assert_authority (shibari_packet *pkt, cdb const *tdb, char const *z, uint16_t zlen, uint16_t zoffset, char const *loc, tain const *stamp)
+{
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ shibari_tdb_entry soa ;
+ int r = shibari_tdb_read_entry(tdb, &state, &soa, z, zlen, SHIBARI_T_SOA, 0, loc, stamp, 0) ;
+ if (r <= 0) return 2 ;
+ if (!shibari_packet_add_rr(pkt, &soa, 0, zoffset, 3)) pkt->hdr.tc = 1 ;
+ return 0 ;
+}
diff --git a/src/server/shibari_packet_begin.c b/src/server/shibari_packet_begin.c
new file mode 100644
index 0000000..5ea7b16
--- /dev/null
+++ b/src/server/shibari_packet_begin.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <string.h>
+
+#include <skalibs/uint16.h>
+
+#include <shibari/constants.h>
+#include <shibari/packet.h>
+
+void shibari_packet_begin (shibari_packet *p, uint16_t id, s6dns_domain_t const *q, uint16_t qtype)
+{
+ p->hdr.id = id ;
+ p->hdr.qr = 1 ;
+ p->hdr.opcode = 0 ;
+ p->hdr.aa = 0 ;
+ p->hdr.tc = 0 ;
+ p->hdr.rd = 0 ;
+ p->hdr.ra = 0 ;
+ p->hdr.z = 0 ;
+ p->hdr.rcode = 0 ;
+ p->hdr.counts.qd = 1 ;
+ p->hdr.counts.an = 0 ;
+ p->hdr.counts.ns = 0 ;
+ p->hdr.counts.nr = 0 ;
+ p->pos = 12 ;
+ memcpy(p->buf + p->pos, q->s, q->len) ;
+ p->pos += q->len ;
+ uint16_pack_big(p->buf + p->pos, qtype) ;
+ p->pos += 2 ;
+ uint16_pack_big(p->buf + p->pos, SHIBARI_C_IN) ;
+ p->pos += 2 ;
+}
diff --git a/src/server/shibari_packet_end.c b/src/server/shibari_packet_end.c
new file mode 100644
index 0000000..41aca87
--- /dev/null
+++ b/src/server/shibari_packet_end.c
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+#include <skalibs/uint16.h>
+
+#include <s6-dns/s6dns-message.h>
+
+#include <shibari/packet.h>
+
+void shibari_packet_end (shibari_packet *p)
+{
+ s6dns_message_header_pack(p->buf, &p->hdr) ;
+ if (p->flagtcp) uint16_pack_big(p->buf - 2, p->pos) ;
+}
diff --git a/src/server/shibari_packet_init.c b/src/server/shibari_packet_init.c
new file mode 100644
index 0000000..a0aff97
--- /dev/null
+++ b/src/server/shibari_packet_init.c
@@ -0,0 +1,14 @@
+/* ISC license. */
+
+#include <s6-dns/s6dns-message.h>
+
+#include <shibari/packet.h>
+
+void shibari_packet_init (shibari_packet *p, char *buf, uint32_t max, int istcp)
+{
+ p->hdr = s6dns_message_header_zero ;
+ p->buf = istcp ? buf + 2 : buf ;
+ p->max = istcp ? max - 2 : max ;
+ p->pos = 0 ;
+ p->flagtcp = !!istcp ;
+}
diff --git a/src/server/shibari_packet_tdb_answer_query.c b/src/server/shibari_packet_tdb_answer_query.c
new file mode 100644
index 0000000..a22927f
--- /dev/null
+++ b/src/server/shibari_packet_tdb_answer_query.c
@@ -0,0 +1,93 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+#include <shibari/constants.h>
+#include <shibari/tdb.h>
+#include <shibari/packet.h>
+
+static unsigned int childzone (shibari_packet *pkt, cdb const *tdb, s6dns_domain_t const *q, char const *loc, tain const *stamp, uint16_t nplen, uint16_t zplen)
+{
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ unsigned int gr ;
+ for (;;)
+ {
+ shibari_tdb_entry ns ;
+ int r = shibari_tdb_read_entry(tdb, &state, &ns, q->s + nplen, q->len - nplen, SHIBARI_T_NS, 0, loc, stamp, 0) ;
+ if (r == -1) return 2 ;
+ if (!r) break ;
+ r = shibari_packet_add_rr(pkt, &ns, nplen, 0, 3) ;
+ if (!r) { pkt->hdr.tc = 1 ; goto end ; }
+ }
+ gr = shibari_packet_add_glue(pkt, tdb, q->s + nplen, q->len - nplen, SHIBARI_T_NS, q->s + zplen, q->len - zplen, zplen, 0, loc, stamp) ;
+ if (gr > 0) return gr ;
+ end:
+ shibari_packet_end(pkt) ;
+ return 0 ;
+}
+
+unsigned int shibari_packet_tdb_answer_query (shibari_packet *pkt, cdb const *tdb, s6dns_message_header_t const *qhdr, s6dns_domain_t const *q, uint16_t qtype, char const *loc, tain const *stamp)
+{
+ unsigned int rcode = 0 ;
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ uint32_t flagyxdomain = 0 ;
+ int nplen, zplen ;
+ uint16_t gluetype = 0 ;
+ uint16_t wildpos = 0 ;
+
+ shibari_packet_begin(pkt, qhdr->id, q, qtype) ;
+ pkt->hdr.rd = qhdr->rd ;
+ zplen = shibari_tdb_find_authority(tdb, q->s, q->len, loc, stamp, &nplen) ;
+ switch (zplen)
+ {
+ case -2 : return 9 ;
+ case -1 : return 2 ;
+ default : break ;
+ }
+ if (nplen >= 0 && nplen < zplen)
+ return childzone(pkt, tdb, q, loc, stamp, nplen, zplen) ;
+
+ pkt->hdr.aa = 1 ; /* we're in the zone, man */
+
+ while (wildpos <= zplen)
+ {
+ for (;;)
+ {
+ shibari_tdb_entry entry ;
+ int r = shibari_tdb_read_entry(tdb, &state, &entry, q->s + wildpos, q->len + wildpos, qtype, !!wildpos, loc, stamp, &flagyxdomain) ;
+ if (r == -1) return 2 ;
+ if (!r) break ;
+ if (!shibari_packet_add_rr(pkt, &entry, 0, 0, 2))
+ {
+ pkt->hdr.tc = 1 ;
+ return 0 ;
+ }
+ switch (entry.type)
+ {
+ case SHIBARI_T_NS :
+ case SHIBARI_T_MX :
+ case SHIBARI_T_CNAME : /* we're not supposed to but meh */
+ gluetype = entry.type ;
+ default : break ;
+ }
+ }
+ if (pkt->hdr.counts.an) break ;
+ wildpos += 1 + q->s[wildpos] ;
+ }
+
+ if (!flagyxdomain) pkt->hdr.rcode = 3 ;
+
+ if (!pkt->hdr.counts.an)
+ {
+ unsigned int r = shibari_packet_assert_authority(pkt, tdb, q->s + zplen, q->len - zplen, zplen, loc, stamp) ;
+ if (r) return r ;
+ }
+ else if (gluetype)
+ {
+ unsigned int r = shibari_packet_add_glue(pkt, tdb, q->s, q->len, gluetype, q->s + zplen, q->len - zplen, zplen, wildpos, loc, stamp) ;
+ if (r) return r ;
+ }
+
+ shibari_packet_end(pkt) ;
+ return rcode ;
+}
diff --git a/src/server/shibari_tdb_entry_parse.c b/src/server/shibari_tdb_entry_parse.c
new file mode 100644
index 0000000..61f076f
--- /dev/null
+++ b/src/server/shibari_tdb_entry_parse.c
@@ -0,0 +1,56 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/uint16.h>
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+
+#include <shibari/constants.h>
+#include <shibari/tdb.h>
+
+int shibari_tdb_entry_parse (shibari_tdb_entry *out, char const *s, uint16_t len, uint16_t qtype, unsigned int wild, char const *loc, tain const *stamp)
+{
+ tai ttd ;
+ uint32_t ttl ;
+ uint32_t flags = 0 ;
+ uint16_t type ;
+ if (len < 15) return -1 ;
+ uint16_unpack_big(s, &type) ;
+ if (qtype != SHIBARI_T_ANY && qtype != type && type != SHIBARI_T_CNAME) return 0 ;
+ s += 3 ; len -= 3 ;
+ switch (s[-1])
+ {
+ case '+' : flags |= 1 ;
+ case '>' :
+ if (len < 14) return -1 ;
+ if (loc && loc[0] && (loc[0] != s[0] || loc[1] != s[1])) return 0 ;
+ s += 2 ; len -= 2 ;
+ break ;
+ case '*' : flags |= 1 ;
+ case '=' : break ;
+ default : return -1 ;
+ }
+ if (wild < 2 && wild != (flags & 1)) return 0 ;
+ uint32_unpack_big(s, &ttl) ;
+ s += 4 ; len -= 4 ;
+ tai_unpack(s, &ttd) ;
+ s += 8 ; len -= 8 ;
+ if (tai_sec(&ttd))
+ {
+ if (!ttl == !tai_less(tain_secp(stamp), &ttd)) return 0 ;
+ if (!ttl)
+ {
+ tai t ;
+ tai_sub(&t, &ttd, tain_secp(stamp)) ;
+ if (tai_sec(&t) < 2) ttl = 2 ;
+ else if (tai_sec(&t) > 3600 && qtype != SHIBARI_T_ANY) ttl = 3600 ;
+ }
+ }
+ out->ttl = ttl ;
+ out->flags = flags ;
+ out->type = type ;
+ out->data.s = s ;
+ out->data.len = len ;
+ return 1 ;
+}
diff --git a/src/server/shibari_tdb_extract_domain.c b/src/server/shibari_tdb_extract_domain.c
new file mode 100644
index 0000000..dfa6009
--- /dev/null
+++ b/src/server/shibari_tdb_extract_domain.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <shibari/constants.h>
+#include <shibari/tdb.h>
+
+int shibari_tdb_extract_domain (shibari_tdb_entry const *entry, cdb_data *domain)
+{
+ switch (entry->type)
+ {
+ case SHIBARI_T_CNAME :
+ case SHIBARI_T_NS :
+ *domain = entry->data ; break ;
+ case SHIBARI_T_MX : domain->s = entry->data.s + 2 ; domain->len = entry->data.len - 2 ; break ;
+ default : return 0 ;
+ }
+ return 1 ;
+}
diff --git a/src/server/shibari_tdb_find_authority.c b/src/server/shibari_tdb_find_authority.c
new file mode 100644
index 0000000..5550f52
--- /dev/null
+++ b/src/server/shibari_tdb_find_authority.c
@@ -0,0 +1,46 @@
+/* ISC license. */
+
+#include <stdint.h>
+
+#include <skalibs/cdb.h>
+
+#include <shibari/constants.h>
+#include <shibari/tdb.h>
+
+static int find_ns_and_soa (cdb const *tdb, char const *s, uint16_t len, char const *loc, tain const *stamp)
+{
+ cdb_find_state state = CDB_FIND_STATE_ZERO ;
+ unsigned int flags = 0 ;
+ for (;;)
+ {
+ shibari_tdb_entry entry ;
+ cdb_data data ;
+ int r = cdb_findnext(tdb, &data, s, len, &state) ;
+ if (r == -1) return -1 ;
+ if (!r) break ;
+ r = shibari_tdb_entry_parse(&entry, data.s, data.len, SHIBARI_T_ANY, 0, loc, stamp) ;
+ if (r == -1) return -1 ;
+ if (!r) continue ;
+ if (entry.type == SHIBARI_T_SOA) flags |= 1 ;
+ else if (entry.type == SHIBARI_T_NS) flags |= 2 ;
+ }
+ return flags ;
+}
+
+int shibari_tdb_find_authority (cdb const *tdb, char const *s, uint16_t len, char const *loc, tain const *stamp, int *npl)
+{
+ uint16_t pos = 0 ;
+ uint16_t zplen = 0 ;
+ int nplen = -1 ;
+ while (pos < len)
+ {
+ int flags = find_ns_and_soa(tdb, s + pos, len - pos, loc, stamp) ;
+ if (flags == -1) return -1 ;
+ if (flags & 2) nplen = pos ;
+ if (flags & 1) { zplen = pos ; break ; }
+ pos += 1 + (uint8_t)s[pos] ;
+ }
+ if (pos >= len) return -2 ; /* out of bailiwick */
+ *npl = nplen ;
+ return zplen ;
+}
diff --git a/src/server/shibari_tdb_read_entry.c b/src/server/shibari_tdb_read_entry.c
new file mode 100644
index 0000000..b2d877c
--- /dev/null
+++ b/src/server/shibari_tdb_read_entry.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+#include <shibari/tdb.h>
+
+int shibari_tdb_read_entry (cdb const *tdb, cdb_find_state *state, shibari_tdb_entry *out, char const *s, uint16_t len, uint16_t qtype, unsigned int wild, char const *loc, tain const *stamp, uint32_t *flags)
+{
+ cdb_data data ;
+ int r = 0 ;
+ while (!r)
+ {
+ r = cdb_findnext(tdb, &data, s, len, state) ;
+ if (r <= 0) return r ;
+ if (flags) *flags |= 1 ;
+ r = shibari_tdb_entry_parse(out, data.s, data.len, qtype, wild, loc, stamp) ;
+ if (r == -1) return -1 ;
+ }
+ out->key.s = s ;
+ out->key.len = len ;
+ return 1 ;
+}
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..27e5b3e
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,93 @@
+#!/bin/sh -e
+
+. package/info
+
+echo '#'
+echo '# This file has been generated by tools/gen-deps.sh'
+echo '#'
+echo
+
+for dir in src/include/${package} src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.h$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ if test -n "$deps" ; then
+ echo "${dir}/${file}:${deps}"
+ fi
+ }
+ done
+done
+
+for dir in src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.c$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=" ${dir}/$file"
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ o=$(echo $file | sed s/\\.c$/.o/)
+ lo=$(echo $file | sed s/\\.c$/.lo/)
+ echo "${dir}/${o} ${dir}/${lo}:${deps}"
+ }
+ done
+done
+echo
+
+for dir in $(ls -1 src | grep -v ^include) ; do
+ for file in $(ls -1 src/$dir/deps-lib) ; do
+ deps=
+ libs=
+ while read dep ; do
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps src/$dir/$dep"
+ fi
+ done < src/$dir/deps-lib/$file
+ echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)'
+ echo "lib${file}.a.xyzzy:$deps"
+ echo else
+ echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ echo endif
+ echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs"
+ echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ done
+
+ for file in $(ls -1 src/$dir/deps-exe) ; do
+ deps=
+ libs=
+ while read dep ; do
+ if echo $dep | grep -q -- \\.o$ ; then
+ dep="src/$dir/$dep"
+ fi
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps $dep"
+ fi
+ done < src/$dir/deps-exe/$file
+ echo "$file: EXTRA_LIBS :=$libs"
+ echo "$file: src/$dir/$file.o$deps"
+ done
+done
diff --git a/tools/install.sh b/tools/install.sh
new file mode 100755
index 0000000..89f9428
--- /dev/null
+++ b/tools/install.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2
+ exit 1
+}
+
+mkdirp=false
+symlink=false
+mode=0755
+
+while getopts Dlm: name ; do
+ case "$name" in
+ D) mkdirp=true ;;
+ l) symlink=true ;;
+ m) mode=$OPTARG ;;
+ ?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+test "$#" -eq 2 || usage
+src=$1
+dst=$2
+tmp="$dst.tmp.$$"
+
+case "$dst" in
+ */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;;
+esac
+
+set -C
+set -e
+
+if $mkdirp ; then
+ umask 022
+ case "$2" in
+ */*) mkdir -p "${dst%/*}" ;;
+ esac
+fi
+
+trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
+
+umask 077
+
+if $symlink ; then
+ ln -s "$src" "$tmp"
+else
+ cat < "$1" > "$tmp"
+ chmod "$mode" "$tmp"
+fi
+
+mv -f "$tmp" "$dst"
+if test -d "$dst" ; then
+ rm -f "$dst/$(basename $tmp)"
+ if $symlink ; then
+ mkdir "$tmp"
+ ln -s "$src" "$tmp/$(basename $dst)"
+ mv -f "$tmp/$(basename $dst)" "${dst%/*}"
+ rmdir "$tmp"
+ else
+ echo "$0: $dst is a directory" 1>&2
+ exit 1
+ fi
+fi