summaryrefslogtreecommitdiffstats
path: root/bin/tools
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 15:59:48 +0000
commit3b9b6d0b8e7f798023c9d109c490449d528fde80 (patch)
tree2e1c188dd7b8d7475cd163de9ae02c428343669b /bin/tools
parentInitial commit. (diff)
downloadbind9-upstream/1%9.18.19.tar.xz
bind9-upstream/1%9.18.19.zip
Adding upstream version 1:9.18.19.upstream/1%9.18.19upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/tools')
-rw-r--r--bin/tools/Makefile.am58
-rw-r--r--bin/tools/Makefile.in968
-rw-r--r--bin/tools/arpaname.c48
-rw-r--r--bin/tools/arpaname.rst35
-rw-r--r--bin/tools/dnstap-read.c428
-rw-r--r--bin/tools/dnstap-read.rst58
-rw-r--r--bin/tools/mdig.c2249
-rw-r--r--bin/tools/mdig.rst375
-rw-r--r--bin/tools/named-journalprint.c134
-rw-r--r--bin/tools/named-journalprint.rst66
-rw-r--r--bin/tools/named-nzd2nzf.c102
-rw-r--r--bin/tools/named-nzd2nzf.rst45
-rw-r--r--bin/tools/named-rrchecker.c346
-rw-r--r--bin/tools/named-rrchecker.rst62
-rw-r--r--bin/tools/nsec3hash.c194
-rw-r--r--bin/tools/nsec3hash.rst70
16 files changed, 5238 insertions, 0 deletions
diff --git a/bin/tools/Makefile.am b/bin/tools/Makefile.am
new file mode 100644
index 0000000..d7b8e4a
--- /dev/null
+++ b/bin/tools/Makefile.am
@@ -0,0 +1,58 @@
+include $(top_srcdir)/Makefile.top
+
+AM_CPPFLAGS += \
+ $(LIBISC_CFLAGS) \
+ $(LIBDNS_CFLAGS)
+
+LDADD += \
+ $(LIBDNS_LIBS) \
+ $(LIBISC_LIBS)
+
+bin_PROGRAMS = \
+ arpaname \
+ mdig \
+ named-journalprint \
+ named-rrchecker \
+ nsec3hash
+
+arpaname_LDADD = \
+ $(LIBISC_LIBS)
+
+mdig_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(LIBBIND9_CFLAGS)
+
+mdig_LDADD = \
+ $(LIBBIND9_LIBS) \
+ $(LIBISCCFG_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBISC_LIBS)
+
+if HAVE_DNSTAP
+bin_PROGRAMS += \
+ dnstap-read
+
+dnstap_read_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(DNSTAP_CFLAGS) \
+ -I$(top_builddir)/lib/dns
+
+dnstap_read_LDADD = \
+ $(LIBDNS_LIBS) \
+ $(LIBISC_LIBS) \
+ $(DNSTAP_LIBS)
+endif
+
+if HAVE_LMDB
+bin_PROGRAMS += \
+ named-nzd2nzf
+
+named_nzd2nzf_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(LMDB_CFLAGS)
+
+named_nzd2nzf_LDADD = \
+ $(LIBISC_LIBS) \
+ $(LMDB_LIBS)
+
+endif
diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in
new file mode 100644
index 0000000..aa0a14b
--- /dev/null
+++ b/bin/tools/Makefile.in
@@ -0,0 +1,968 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Hey Emacs, this is -*- makefile-automake -*- file!
+# vim: filetype=automake
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HOST_MACOS_TRUE@am__append_1 = \
+@HOST_MACOS_TRUE@ -Wl,-flat_namespace
+
+bin_PROGRAMS = arpaname$(EXEEXT) mdig$(EXEEXT) \
+ named-journalprint$(EXEEXT) named-rrchecker$(EXEEXT) \
+ nsec3hash$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2)
+@HAVE_DNSTAP_TRUE@am__append_2 = \
+@HAVE_DNSTAP_TRUE@ dnstap-read
+
+@HAVE_LMDB_TRUE@am__append_3 = \
+@HAVE_LMDB_TRUE@ named-nzd2nzf
+
+subdir = bin/tools
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_check_openssl.m4 \
+ $(top_srcdir)/m4/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4/ax_jemalloc.m4 \
+ $(top_srcdir)/m4/ax_lib_lmdb.m4 \
+ $(top_srcdir)/m4/ax_perl_module.m4 \
+ $(top_srcdir)/m4/ax_posix_shell.m4 \
+ $(top_srcdir)/m4/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/ax_python_module.m4 \
+ $(top_srcdir)/m4/ax_restore_flags.m4 \
+ $(top_srcdir)/m4/ax_save_flags.m4 $(top_srcdir)/m4/ax_tls.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_DNSTAP_TRUE@am__EXEEXT_1 = dnstap-read$(EXEEXT)
+@HAVE_LMDB_TRUE@am__EXEEXT_2 = named-nzd2nzf$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+arpaname_SOURCES = arpaname.c
+arpaname_OBJECTS = arpaname.$(OBJEXT)
+arpaname_DEPENDENCIES = $(LIBISC_LIBS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+dnstap_read_SOURCES = dnstap-read.c
+dnstap_read_OBJECTS = dnstap_read-dnstap-read.$(OBJEXT)
+am__DEPENDENCIES_1 =
+@HAVE_DNSTAP_TRUE@dnstap_read_DEPENDENCIES = $(LIBDNS_LIBS) \
+@HAVE_DNSTAP_TRUE@ $(LIBISC_LIBS) $(am__DEPENDENCIES_1)
+mdig_SOURCES = mdig.c
+mdig_OBJECTS = mdig-mdig.$(OBJEXT)
+mdig_DEPENDENCIES = $(LIBBIND9_LIBS) $(LIBISCCFG_LIBS) $(LIBDNS_LIBS) \
+ $(LIBISC_LIBS)
+named_journalprint_SOURCES = named-journalprint.c
+named_journalprint_OBJECTS = named-journalprint.$(OBJEXT)
+named_journalprint_LDADD = $(LDADD)
+named_journalprint_DEPENDENCIES = $(LIBDNS_LIBS) $(LIBISC_LIBS)
+named_nzd2nzf_SOURCES = named-nzd2nzf.c
+named_nzd2nzf_OBJECTS = named_nzd2nzf-named-nzd2nzf.$(OBJEXT)
+@HAVE_LMDB_TRUE@named_nzd2nzf_DEPENDENCIES = $(LIBISC_LIBS) \
+@HAVE_LMDB_TRUE@ $(am__DEPENDENCIES_1)
+named_rrchecker_SOURCES = named-rrchecker.c
+named_rrchecker_OBJECTS = named-rrchecker.$(OBJEXT)
+named_rrchecker_LDADD = $(LDADD)
+named_rrchecker_DEPENDENCIES = $(LIBDNS_LIBS) $(LIBISC_LIBS)
+nsec3hash_SOURCES = nsec3hash.c
+nsec3hash_OBJECTS = nsec3hash.$(OBJEXT)
+nsec3hash_LDADD = $(LDADD)
+nsec3hash_DEPENDENCIES = $(LIBDNS_LIBS) $(LIBISC_LIBS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/arpaname.Po \
+ ./$(DEPDIR)/dnstap_read-dnstap-read.Po \
+ ./$(DEPDIR)/mdig-mdig.Po ./$(DEPDIR)/named-journalprint.Po \
+ ./$(DEPDIR)/named-rrchecker.Po \
+ ./$(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po \
+ ./$(DEPDIR)/nsec3hash.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = arpaname.c dnstap-read.c mdig.c named-journalprint.c \
+ named-nzd2nzf.c named-rrchecker.c nsec3hash.c
+DIST_SOURCES = arpaname.c dnstap-read.c mdig.c named-journalprint.c \
+ named-nzd2nzf.c named-rrchecker.c nsec3hash.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__extra_recursive_targets = test-recursive unit-recursive \
+ doc-recursive
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Makefile.top \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CMOCKA_CFLAGS = @CMOCKA_CFLAGS@
+CMOCKA_LIBS = @CMOCKA_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CURL = @CURL@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DEVELOPER_MODE = @DEVELOPER_MODE@
+DLLTOOL = @DLLTOOL@
+DNSTAP_CFLAGS = @DNSTAP_CFLAGS@
+DNSTAP_LIBS = @DNSTAP_LIBS@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+FSTRM_CAPTURE = @FSTRM_CAPTURE@
+FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+FUZZ_LOG_COMPILER = @FUZZ_LOG_COMPILER@
+GREP = @GREP@
+GSSAPI_CFLAGS = @GSSAPI_CFLAGS@
+GSSAPI_LIBS = @GSSAPI_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@
+JEMALLOC_LIBS = @JEMALLOC_LIBS@
+JSON_C_CFLAGS = @JSON_C_CFLAGS@
+JSON_C_LIBS = @JSON_C_LIBS@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_CONFIG = @KRB5_CONFIG@
+KRB5_LIBS = @KRB5_LIBS@
+LATEXMK = @LATEXMK@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBCAP_LIBS = @LIBCAP_LIBS@
+LIBIDN2_CFLAGS = @LIBIDN2_CFLAGS@
+LIBIDN2_LIBS = @LIBIDN2_LIBS@
+LIBNGHTTP2_CFLAGS = @LIBNGHTTP2_CFLAGS@
+LIBNGHTTP2_LIBS = @LIBNGHTTP2_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUV_CFLAGS = @LIBUV_CFLAGS@
+LIBUV_LIBS = @LIBUV_LIBS@
+LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
+LIBXML2_LIBS = @LIBXML2_LIBS@
+LIPO = @LIPO@
+LMDB_CFLAGS = @LMDB_CFLAGS@
+LMDB_LIBS = @LMDB_LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MAXMINDDB_CFLAGS = @MAXMINDDB_CFLAGS@
+MAXMINDDB_LIBS = @MAXMINDDB_LIBS@
+MAXMINDDB_PREFIX = @MAXMINDDB_PREFIX@
+MKDIR_P = @MKDIR_P@
+NC = @NC@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTEST = @PYTEST@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+READLINE_CFLAGS = @READLINE_CFLAGS@
+READLINE_LIBS = @READLINE_LIBS@
+RELEASE_DATE = @RELEASE_DATE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPHINX_BUILD = @SPHINX_BUILD@
+STD_CFLAGS = @STD_CFLAGS@
+STD_CPPFLAGS = @STD_CPPFLAGS@
+STD_LDFLAGS = @STD_LDFLAGS@
+STRIP = @STRIP@
+TEST_CFLAGS = @TEST_CFLAGS@
+VERSION = @VERSION@
+XELATEX = @XELATEX@
+XSLTPROC = @XSLTPROC@
+ZLIB_CFLAGS = @ZLIB_CFLAGS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
+AM_CFLAGS = \
+ $(STD_CFLAGS)
+
+AM_CPPFLAGS = $(STD_CPPFLAGS) -include $(top_builddir)/config.h \
+ -I$(srcdir)/include $(LIBISC_CFLAGS) $(LIBDNS_CFLAGS)
+AM_LDFLAGS = $(STD_LDFLAGS) $(am__append_1)
+LDADD = $(LIBDNS_LIBS) $(LIBISC_LIBS)
+LIBISC_CFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib/isc/include \
+ -I$(top_builddir)/lib/isc/include
+
+LIBISC_LIBS = $(top_builddir)/lib/isc/libisc.la
+LIBDNS_CFLAGS = \
+ -I$(top_srcdir)/lib/dns/include \
+ -I$(top_builddir)/lib/dns/include
+
+LIBDNS_LIBS = \
+ $(top_builddir)/lib/dns/libdns.la
+
+LIBNS_CFLAGS = \
+ -I$(top_srcdir)/lib/ns/include
+
+LIBNS_LIBS = \
+ $(top_builddir)/lib/ns/libns.la
+
+LIBIRS_CFLAGS = \
+ -I$(top_srcdir)/lib/irs/include
+
+LIBIRS_LIBS = \
+ $(top_builddir)/lib/irs/libirs.la
+
+LIBISCCFG_CFLAGS = \
+ -I$(top_srcdir)/lib/isccfg/include
+
+LIBISCCFG_LIBS = \
+ $(top_builddir)/lib/isccfg/libisccfg.la
+
+LIBISCCC_CFLAGS = \
+ -I$(top_srcdir)/lib/isccc/include/
+
+LIBISCCC_LIBS = \
+ $(top_builddir)/lib/isccc/libisccc.la
+
+LIBBIND9_CFLAGS = \
+ -I$(top_srcdir)/lib/bind9/include
+
+LIBBIND9_LIBS = \
+ $(top_builddir)/lib/bind9/libbind9.la
+
+arpaname_LDADD = \
+ $(LIBISC_LIBS)
+
+mdig_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ $(LIBBIND9_CFLAGS)
+
+mdig_LDADD = \
+ $(LIBBIND9_LIBS) \
+ $(LIBISCCFG_LIBS) \
+ $(LIBDNS_LIBS) \
+ $(LIBISC_LIBS)
+
+@HAVE_DNSTAP_TRUE@dnstap_read_CPPFLAGS = \
+@HAVE_DNSTAP_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_DNSTAP_TRUE@ $(DNSTAP_CFLAGS) \
+@HAVE_DNSTAP_TRUE@ -I$(top_builddir)/lib/dns
+
+@HAVE_DNSTAP_TRUE@dnstap_read_LDADD = \
+@HAVE_DNSTAP_TRUE@ $(LIBDNS_LIBS) \
+@HAVE_DNSTAP_TRUE@ $(LIBISC_LIBS) \
+@HAVE_DNSTAP_TRUE@ $(DNSTAP_LIBS)
+
+@HAVE_LMDB_TRUE@named_nzd2nzf_CPPFLAGS = \
+@HAVE_LMDB_TRUE@ $(AM_CPPFLAGS) \
+@HAVE_LMDB_TRUE@ $(LMDB_CFLAGS)
+
+@HAVE_LMDB_TRUE@named_nzd2nzf_LDADD = \
+@HAVE_LMDB_TRUE@ $(LIBISC_LIBS) \
+@HAVE_LMDB_TRUE@ $(LMDB_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/Makefile.top $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign bin/tools/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign bin/tools/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Makefile.top $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+arpaname$(EXEEXT): $(arpaname_OBJECTS) $(arpaname_DEPENDENCIES) $(EXTRA_arpaname_DEPENDENCIES)
+ @rm -f arpaname$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(arpaname_OBJECTS) $(arpaname_LDADD) $(LIBS)
+
+dnstap-read$(EXEEXT): $(dnstap_read_OBJECTS) $(dnstap_read_DEPENDENCIES) $(EXTRA_dnstap_read_DEPENDENCIES)
+ @rm -f dnstap-read$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dnstap_read_OBJECTS) $(dnstap_read_LDADD) $(LIBS)
+
+mdig$(EXEEXT): $(mdig_OBJECTS) $(mdig_DEPENDENCIES) $(EXTRA_mdig_DEPENDENCIES)
+ @rm -f mdig$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mdig_OBJECTS) $(mdig_LDADD) $(LIBS)
+
+named-journalprint$(EXEEXT): $(named_journalprint_OBJECTS) $(named_journalprint_DEPENDENCIES) $(EXTRA_named_journalprint_DEPENDENCIES)
+ @rm -f named-journalprint$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(named_journalprint_OBJECTS) $(named_journalprint_LDADD) $(LIBS)
+
+named-nzd2nzf$(EXEEXT): $(named_nzd2nzf_OBJECTS) $(named_nzd2nzf_DEPENDENCIES) $(EXTRA_named_nzd2nzf_DEPENDENCIES)
+ @rm -f named-nzd2nzf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(named_nzd2nzf_OBJECTS) $(named_nzd2nzf_LDADD) $(LIBS)
+
+named-rrchecker$(EXEEXT): $(named_rrchecker_OBJECTS) $(named_rrchecker_DEPENDENCIES) $(EXTRA_named_rrchecker_DEPENDENCIES)
+ @rm -f named-rrchecker$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(named_rrchecker_OBJECTS) $(named_rrchecker_LDADD) $(LIBS)
+
+nsec3hash$(EXEEXT): $(nsec3hash_OBJECTS) $(nsec3hash_DEPENDENCIES) $(EXTRA_nsec3hash_DEPENDENCIES)
+ @rm -f nsec3hash$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nsec3hash_OBJECTS) $(nsec3hash_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arpaname.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnstap_read-dnstap-read.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdig-mdig.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/named-journalprint.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/named-rrchecker.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3hash.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+dnstap_read-dnstap-read.o: dnstap-read.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_read_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dnstap_read-dnstap-read.o -MD -MP -MF $(DEPDIR)/dnstap_read-dnstap-read.Tpo -c -o dnstap_read-dnstap-read.o `test -f 'dnstap-read.c' || echo '$(srcdir)/'`dnstap-read.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dnstap_read-dnstap-read.Tpo $(DEPDIR)/dnstap_read-dnstap-read.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dnstap-read.c' object='dnstap_read-dnstap-read.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_read_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dnstap_read-dnstap-read.o `test -f 'dnstap-read.c' || echo '$(srcdir)/'`dnstap-read.c
+
+dnstap_read-dnstap-read.obj: dnstap-read.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_read_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dnstap_read-dnstap-read.obj -MD -MP -MF $(DEPDIR)/dnstap_read-dnstap-read.Tpo -c -o dnstap_read-dnstap-read.obj `if test -f 'dnstap-read.c'; then $(CYGPATH_W) 'dnstap-read.c'; else $(CYGPATH_W) '$(srcdir)/dnstap-read.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dnstap_read-dnstap-read.Tpo $(DEPDIR)/dnstap_read-dnstap-read.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dnstap-read.c' object='dnstap_read-dnstap-read.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dnstap_read_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dnstap_read-dnstap-read.obj `if test -f 'dnstap-read.c'; then $(CYGPATH_W) 'dnstap-read.c'; else $(CYGPATH_W) '$(srcdir)/dnstap-read.c'; fi`
+
+mdig-mdig.o: mdig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mdig-mdig.o -MD -MP -MF $(DEPDIR)/mdig-mdig.Tpo -c -o mdig-mdig.o `test -f 'mdig.c' || echo '$(srcdir)/'`mdig.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mdig-mdig.Tpo $(DEPDIR)/mdig-mdig.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mdig.c' object='mdig-mdig.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mdig-mdig.o `test -f 'mdig.c' || echo '$(srcdir)/'`mdig.c
+
+mdig-mdig.obj: mdig.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mdig-mdig.obj -MD -MP -MF $(DEPDIR)/mdig-mdig.Tpo -c -o mdig-mdig.obj `if test -f 'mdig.c'; then $(CYGPATH_W) 'mdig.c'; else $(CYGPATH_W) '$(srcdir)/mdig.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mdig-mdig.Tpo $(DEPDIR)/mdig-mdig.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mdig.c' object='mdig-mdig.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mdig_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mdig-mdig.obj `if test -f 'mdig.c'; then $(CYGPATH_W) 'mdig.c'; else $(CYGPATH_W) '$(srcdir)/mdig.c'; fi`
+
+named_nzd2nzf-named-nzd2nzf.o: named-nzd2nzf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(named_nzd2nzf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT named_nzd2nzf-named-nzd2nzf.o -MD -MP -MF $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Tpo -c -o named_nzd2nzf-named-nzd2nzf.o `test -f 'named-nzd2nzf.c' || echo '$(srcdir)/'`named-nzd2nzf.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Tpo $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='named-nzd2nzf.c' object='named_nzd2nzf-named-nzd2nzf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(named_nzd2nzf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o named_nzd2nzf-named-nzd2nzf.o `test -f 'named-nzd2nzf.c' || echo '$(srcdir)/'`named-nzd2nzf.c
+
+named_nzd2nzf-named-nzd2nzf.obj: named-nzd2nzf.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(named_nzd2nzf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT named_nzd2nzf-named-nzd2nzf.obj -MD -MP -MF $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Tpo -c -o named_nzd2nzf-named-nzd2nzf.obj `if test -f 'named-nzd2nzf.c'; then $(CYGPATH_W) 'named-nzd2nzf.c'; else $(CYGPATH_W) '$(srcdir)/named-nzd2nzf.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Tpo $(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='named-nzd2nzf.c' object='named_nzd2nzf-named-nzd2nzf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(named_nzd2nzf_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o named_nzd2nzf-named-nzd2nzf.obj `if test -f 'named-nzd2nzf.c'; then $(CYGPATH_W) 'named-nzd2nzf.c'; else $(CYGPATH_W) '$(srcdir)/named-nzd2nzf.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+test-local:
+unit-local:
+doc-local:
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/arpaname.Po
+ -rm -f ./$(DEPDIR)/dnstap_read-dnstap-read.Po
+ -rm -f ./$(DEPDIR)/mdig-mdig.Po
+ -rm -f ./$(DEPDIR)/named-journalprint.Po
+ -rm -f ./$(DEPDIR)/named-rrchecker.Po
+ -rm -f ./$(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po
+ -rm -f ./$(DEPDIR)/nsec3hash.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+doc: doc-am
+
+doc-am: doc-local
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/arpaname.Po
+ -rm -f ./$(DEPDIR)/dnstap_read-dnstap-read.Po
+ -rm -f ./$(DEPDIR)/mdig-mdig.Po
+ -rm -f ./$(DEPDIR)/named-journalprint.Po
+ -rm -f ./$(DEPDIR)/named-rrchecker.Po
+ -rm -f ./$(DEPDIR)/named_nzd2nzf-named-nzd2nzf.Po
+ -rm -f ./$(DEPDIR)/nsec3hash.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+test: test-am
+
+test-am: test-local
+
+uninstall-am: uninstall-binPROGRAMS
+
+unit: unit-am
+
+unit-am: unit-local
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir doc-am doc-local dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am test-am test-local uninstall \
+ uninstall-am uninstall-binPROGRAMS unit-am unit-local
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/bin/tools/arpaname.c b/bin/tools/arpaname.c
new file mode 100644
index 0000000..cfbe187
--- /dev/null
+++ b/bin/tools/arpaname.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdio.h>
+
+#include <isc/net.h>
+#include <isc/print.h>
+
+#define UNUSED(x) (void)(x)
+
+int
+main(int argc, char *argv[]) {
+ unsigned char buf[16];
+ int i;
+
+ UNUSED(argc);
+
+ while (argv[1]) {
+ if (inet_pton(AF_INET6, argv[1], buf) == 1) {
+ for (i = 15; i >= 0; i--) {
+ fprintf(stdout, "%X.%X.", buf[i] & 0xf,
+ (buf[i] >> 4) & 0xf);
+ }
+ fprintf(stdout, "IP6.ARPA\n");
+ argv++;
+ continue;
+ }
+ if (inet_pton(AF_INET, argv[1], buf) == 1) {
+ fprintf(stdout, "%u.%u.%u.%u.IN-ADDR.ARPA\n", buf[3],
+ buf[2], buf[1], buf[0]);
+ argv++;
+ continue;
+ }
+ return (1);
+ }
+ fflush(stdout);
+ return (ferror(stdout));
+}
diff --git a/bin/tools/arpaname.rst b/bin/tools/arpaname.rst
new file mode 100644
index 0000000..00ed897
--- /dev/null
+++ b/bin/tools/arpaname.rst
@@ -0,0 +1,35 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: arpaname
+.. program:: arpaname
+.. _man_arpaname:
+
+arpaname - translate IP addresses to the corresponding ARPA names
+-----------------------------------------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`arpaname` {*ipaddress* ...}
+
+Description
+~~~~~~~~~~~
+
+:program:`arpaname` translates IP addresses (IPv4 and IPv6) to the
+corresponding IN-ADDR.ARPA or IP6.ARPA names.
+
+See Also
+~~~~~~~~
+
+BIND 9 Administrator Reference Manual.
diff --git a/bin/tools/dnstap-read.c b/bin/tools/dnstap-read.c
new file mode 100644
index 0000000..f6abeeb
--- /dev/null
+++ b/bin/tools/dnstap-read.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Portions of this code were adapted from dnstap-ldns:
+ *
+ * Copyright (c) 2014 by Farsight Security, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <protobuf-c/protobuf-c.h>
+
+#include <isc/attributes.h>
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/hex.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/dnstap.h>
+#include <dns/fixedname.h>
+#include <dns/masterdump.h>
+#include <dns/message.h>
+#include <dns/name.h>
+
+#include "dnstap.pb-c.h"
+
+isc_mem_t *mctx = NULL;
+bool memrecord = false;
+bool printmessage = false;
+bool hexmessage = false;
+bool yaml = false;
+
+const char *program = "dnstap-read";
+
+#define CHECKM(op, msg) \
+ do { \
+ result = (op); \
+ if (result != ISC_R_SUCCESS) { \
+ fprintf(stderr, "%s: %s: %s\n", program, msg, \
+ isc_result_totext(result)); \
+ goto cleanup; \
+ } \
+ } while (0)
+
+noreturn static void
+fatal(const char *format, ...);
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fprintf(stderr, "%s: fatal: ", program);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+static void
+usage(void) {
+ fprintf(stderr, "dnstap-read [-mpxy] [filename]\n");
+ fprintf(stderr, "\t-m\ttrace memory allocations\n");
+ fprintf(stderr, "\t-p\tprint the full DNS message\n");
+ fprintf(stderr, "\t-x\tuse hex format to print DNS message\n");
+ fprintf(stderr, "\t-y\tprint YAML format (implies -p)\n");
+}
+
+static void
+print_dtdata(dns_dtdata_t *dt) {
+ isc_result_t result;
+ isc_buffer_t *b = NULL;
+
+ isc_buffer_allocate(mctx, &b, 2048);
+ if (b == NULL) {
+ fatal("out of memory");
+ }
+
+ CHECKM(dns_dt_datatotext(dt, &b), "dns_dt_datatotext");
+ printf("%.*s\n", (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+
+cleanup:
+ if (b != NULL) {
+ isc_buffer_free(&b);
+ }
+}
+
+static void
+print_hex(dns_dtdata_t *dt) {
+ isc_buffer_t *b = NULL;
+ isc_result_t result;
+ size_t textlen;
+
+ if (dt->msg == NULL) {
+ return;
+ }
+
+ textlen = (dt->msgdata.length * 2) + 1;
+ isc_buffer_allocate(mctx, &b, textlen);
+ if (b == NULL) {
+ fatal("out of memory");
+ }
+
+ result = isc_hex_totext(&dt->msgdata, 0, "", b);
+ CHECKM(result, "isc_hex_totext");
+
+ printf("%.*s\n", (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+
+cleanup:
+ if (b != NULL) {
+ isc_buffer_free(&b);
+ }
+}
+
+static void
+print_packet(dns_dtdata_t *dt, const dns_master_style_t *style) {
+ isc_buffer_t *b = NULL;
+ isc_result_t result;
+
+ if (dt->msg != NULL) {
+ size_t textlen = 2048;
+
+ isc_buffer_allocate(mctx, &b, textlen);
+ if (b == NULL) {
+ fatal("out of memory");
+ }
+
+ for (;;) {
+ isc_buffer_reserve(&b, textlen);
+ if (b == NULL) {
+ fatal("out of memory");
+ }
+
+ result = dns_message_totext(dt->msg, style, 0, b);
+ if (result == ISC_R_NOSPACE) {
+ isc_buffer_clear(b);
+ textlen *= 2;
+ continue;
+ } else if (result == ISC_R_SUCCESS) {
+ printf("%.*s", (int)isc_buffer_usedlength(b),
+ (char *)isc_buffer_base(b));
+ isc_buffer_free(&b);
+ } else {
+ isc_buffer_free(&b);
+ CHECKM(result, "dns_message_totext");
+ }
+ break;
+ }
+ }
+
+cleanup:
+ if (b != NULL) {
+ isc_buffer_free(&b);
+ }
+}
+
+static void
+print_yaml(dns_dtdata_t *dt) {
+ Dnstap__Dnstap *frame = dt->frame;
+ Dnstap__Message *m = frame->message;
+ const ProtobufCEnumValue *ftype, *mtype;
+ static bool first = true;
+
+ ftype = protobuf_c_enum_descriptor_get_value(
+ &dnstap__dnstap__type__descriptor, frame->type);
+ if (ftype == NULL) {
+ return;
+ }
+
+ if (!first) {
+ printf("---\n");
+ } else {
+ first = false;
+ }
+
+ printf("type: %s\n", ftype->name);
+
+ if (frame->has_identity) {
+ printf("identity: %.*s\n", (int)frame->identity.len,
+ frame->identity.data);
+ }
+
+ if (frame->has_version) {
+ printf("version: %.*s\n", (int)frame->version.len,
+ frame->version.data);
+ }
+
+ if (frame->type != DNSTAP__DNSTAP__TYPE__MESSAGE) {
+ return;
+ }
+
+ printf("message:\n");
+
+ mtype = protobuf_c_enum_descriptor_get_value(
+ &dnstap__message__type__descriptor, m->type);
+ if (mtype == NULL) {
+ return;
+ }
+
+ printf(" type: %s\n", mtype->name);
+
+ if (!isc_time_isepoch(&dt->qtime)) {
+ char buf[100];
+ isc_time_formatISO8601(&dt->qtime, buf, sizeof(buf));
+ printf(" query_time: !!timestamp %s\n", buf);
+ }
+
+ if (!isc_time_isepoch(&dt->rtime)) {
+ char buf[100];
+ isc_time_formatISO8601(&dt->rtime, buf, sizeof(buf));
+ printf(" response_time: !!timestamp %s\n", buf);
+ }
+
+ if (dt->msgdata.base != NULL) {
+ printf(" message_size: %zub\n", (size_t)dt->msgdata.length);
+ } else {
+ printf(" message_size: 0b\n");
+ }
+
+ if (m->has_socket_family) {
+ const ProtobufCEnumValue *type =
+ protobuf_c_enum_descriptor_get_value(
+ &dnstap__socket_family__descriptor,
+ m->socket_family);
+ if (type != NULL) {
+ printf(" socket_family: %s\n", type->name);
+ }
+ }
+
+ printf(" socket_protocol: %s\n", dt->tcp ? "TCP" : "UDP");
+
+ if (m->has_query_address) {
+ ProtobufCBinaryData *ip = &m->query_address;
+ char buf[100];
+
+ (void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6, ip->data,
+ buf, sizeof(buf));
+ printf(" query_address: \"%s\"\n", buf);
+ }
+
+ if (m->has_response_address) {
+ ProtobufCBinaryData *ip = &m->response_address;
+ char buf[100];
+
+ (void)inet_ntop(ip->len == 4 ? AF_INET : AF_INET6, ip->data,
+ buf, sizeof(buf));
+ printf(" response_address: \"%s\"\n", buf);
+ }
+
+ if (m->has_query_port) {
+ printf(" query_port: %u\n", m->query_port);
+ }
+
+ if (m->has_response_port) {
+ printf(" response_port: %u\n", m->response_port);
+ }
+
+ if (m->has_query_zone) {
+ isc_result_t result;
+ dns_fixedname_t fn;
+ dns_name_t *name;
+ isc_buffer_t b;
+ dns_decompress_t dctx;
+
+ name = dns_fixedname_initname(&fn);
+
+ isc_buffer_init(&b, m->query_zone.data, m->query_zone.len);
+ isc_buffer_add(&b, m->query_zone.len);
+
+ dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
+ result = dns_name_fromwire(name, &b, &dctx, 0, NULL);
+ if (result == ISC_R_SUCCESS) {
+ printf(" query_zone: ");
+ dns_name_print(name, stdout);
+ printf("\n");
+ }
+ }
+
+ if (dt->msg != NULL) {
+ dt->msg->indent.count = 2;
+ dt->msg->indent.string = " ";
+ printf(" %s:\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
+ ? "query_message_data"
+ : "response_message_data");
+
+ print_packet(dt, &dns_master_style_yaml);
+
+ printf(" %s: |\n", ((dt->type & DNS_DTTYPE_QUERY) != 0)
+ ? "query_message"
+ : "response_message");
+ print_packet(dt, &dns_master_style_indent);
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ isc_buffer_t *b = NULL;
+ dns_dtdata_t *dt = NULL;
+ dns_dthandle_t *handle = NULL;
+ int rv = 0, ch;
+
+ while ((ch = isc_commandline_parse(argc, argv, "mpxy")) != -1) {
+ switch (ch) {
+ case 'm':
+ isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
+ memrecord = true;
+ break;
+ case 'p':
+ printmessage = true;
+ break;
+ case 'x':
+ hexmessage = true;
+ break;
+ case 'y':
+ yaml = true;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ if (argc < 1) {
+ fatal("no file specified");
+ }
+
+ isc_mem_create(&mctx);
+
+ CHECKM(dns_dt_open(argv[0], dns_dtmode_file, mctx, &handle),
+ "dns_dt_openfile");
+
+ for (;;) {
+ isc_region_t input;
+ uint8_t *data;
+ size_t datalen;
+
+ result = dns_dt_getframe(handle, &data, &datalen);
+ if (result == ISC_R_NOMORE) {
+ break;
+ } else {
+ CHECKM(result, "dns_dt_getframe");
+ }
+
+ input.base = data;
+ input.length = datalen;
+
+ if (b != NULL) {
+ isc_buffer_free(&b);
+ }
+ isc_buffer_allocate(mctx, &b, 2048);
+ if (b == NULL) {
+ fatal("out of memory");
+ }
+
+ result = dns_dt_parse(mctx, &input, &dt);
+ if (result != ISC_R_SUCCESS) {
+ isc_buffer_free(&b);
+ continue;
+ }
+
+ if (yaml) {
+ print_yaml(dt);
+ } else if (hexmessage) {
+ print_dtdata(dt);
+ print_hex(dt);
+ } else if (printmessage) {
+ print_dtdata(dt);
+ print_packet(dt, &dns_master_style_debug);
+ } else {
+ print_dtdata(dt);
+ }
+
+ dns_dtdata_free(&dt);
+ }
+
+cleanup:
+ if (dt != NULL) {
+ dns_dtdata_free(&dt);
+ }
+ if (handle != NULL) {
+ dns_dt_close(&handle);
+ }
+ if (message != NULL) {
+ dns_message_detach(&message);
+ }
+ if (b != NULL) {
+ isc_buffer_free(&b);
+ }
+ isc_mem_destroy(&mctx);
+
+ exit(rv);
+}
diff --git a/bin/tools/dnstap-read.rst b/bin/tools/dnstap-read.rst
new file mode 100644
index 0000000..a595682
--- /dev/null
+++ b/bin/tools/dnstap-read.rst
@@ -0,0 +1,58 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: dnstap-read
+.. program:: dnstap-read
+.. _man_dnstap-read:
+
+dnstap-read - print dnstap data in human-readable form
+------------------------------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`dnstap-read` [**-m**] [**-p**] [**-x**] [**-y**] {file}
+
+Description
+~~~~~~~~~~~
+
+:program:`dnstap-read` reads ``dnstap`` data from a specified file and prints
+it in a human-readable format. By default, ``dnstap`` data is printed in
+a short summary format, but if the :option:`-y` option is specified, a
+longer and more detailed YAML format is used.
+
+Options
+~~~~~~~
+
+.. option:: -m
+
+ This option indicates trace memory allocations, and is used for debugging memory leaks.
+
+.. option:: -p
+
+ This option prints the text form of the DNS
+ message that was encapsulated in the ``dnstap`` frame, after printing the ``dnstap`` data.
+
+.. option:: -x
+
+ This option prints a hex dump of the wire form
+ of the DNS message that was encapsulated in the ``dnstap`` frame, after printing the ``dnstap`` data.
+
+.. option:: -y
+
+ This option prints ``dnstap`` data in a detailed YAML format.
+
+See Also
+~~~~~~~~
+
+:iscman:`named(8) <named>`, :iscman:`rndc(8) <rndc>`, BIND 9 Administrator Reference Manual.
diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c
new file mode 100644
index 0000000..ae3fd86
--- /dev/null
+++ b/bin/tools/mdig.c
@@ -0,0 +1,2249 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/attributes.h>
+#include <isc/base64.h>
+#include <isc/hash.h>
+#include <isc/hex.h>
+#include <isc/log.h>
+#include <isc/managers.h>
+#include <isc/mem.h>
+#include <isc/net.h>
+#include <isc/netmgr.h>
+#include <isc/nonce.h>
+#include <isc/parseint.h>
+#include <isc/portset.h>
+#include <isc/print.h>
+#include <isc/random.h>
+#include <isc/result.h>
+#include <isc/sockaddr.h>
+#include <isc/string.h>
+#include <isc/task.h>
+#include <isc/time.h>
+#include <isc/util.h>
+
+#include <dns/byaddr.h>
+#include <dns/dispatch.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/message.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/rdatatype.h>
+#include <dns/request.h>
+#include <dns/resolver.h>
+#include <dns/types.h>
+#include <dns/view.h>
+
+#include <bind9/getaddresses.h>
+
+#define CHECK(str, x) \
+ { \
+ if ((x) != ISC_R_SUCCESS) { \
+ fprintf(stderr, "mdig: %s failed with %s\n", (str), \
+ isc_result_totext(x)); \
+ exit(-1); \
+ } \
+ }
+
+#define RUNCHECK(x) RUNTIME_CHECK((x) == ISC_R_SUCCESS)
+
+#define ADD_STRING(b, s) \
+ { \
+ if (strlen(s) >= isc_buffer_availablelength(b)) \
+ return ((ISC_R_NOSPACE)); \
+ else \
+ isc_buffer_putstr(b, s); \
+ }
+
+#define MXNAME (DNS_NAME_MAXTEXT + 1)
+#define COMMSIZE 0xffff
+#define OUTPUTBUF 32767
+#define MAXPORT 0xffff
+#define PORT 53
+#define MAXTIMEOUT 0xffff
+#define TCPTIMEOUT 10
+#define UDPTIMEOUT 5
+#define MAXTRIES 0xffffffff
+
+static isc_mem_t *mctx = NULL;
+static dns_requestmgr_t *requestmgr = NULL;
+static const char *batchname = NULL;
+static FILE *batchfp = NULL;
+static bool burst = false;
+static bool have_ipv4 = false;
+static bool have_ipv6 = false;
+static bool have_src = false;
+static bool tcp_mode = false;
+static bool besteffort = true;
+static bool display_short_form = false;
+static bool display_headers = true;
+static bool display_comments = true;
+static int display_rrcomments = 0;
+static bool display_ttlunits = true;
+static bool display_ttl = true;
+static bool display_class = true;
+static bool display_crypto = true;
+static bool display_multiline = false;
+static bool display_question = true;
+static bool display_answer = true;
+static bool display_authority = true;
+static bool display_additional = true;
+static bool display_unknown_format = false;
+static bool yaml = false;
+static bool continue_on_error = false;
+static uint32_t display_splitwidth = 0xffffffff;
+static isc_sockaddr_t srcaddr;
+static char *server = NULL;
+static isc_sockaddr_t dstaddr;
+static in_port_t port = 53;
+static unsigned char cookie_secret[33];
+static int onfly = 0;
+static char hexcookie[81];
+
+struct query {
+ char textname[MXNAME]; /*% Name we're going to be
+ * looking up */
+ bool recurse;
+ bool have_aaonly;
+ bool have_adflag;
+ bool have_cdflag;
+ bool have_zflag;
+ bool dnssec;
+ bool expire;
+ bool send_cookie;
+ char *cookie;
+ bool nsid;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ uint16_t udpsize;
+ int16_t edns;
+ dns_ednsopt_t *ednsopts;
+ unsigned int ednsoptscnt;
+ unsigned int ednsflags;
+ isc_sockaddr_t *ecs_addr;
+ unsigned int timeout;
+ unsigned int udptimeout;
+ unsigned int udpretries;
+ ISC_LINK(struct query) link;
+};
+static struct query default_query;
+static ISC_LIST(struct query) queries;
+
+#define EDNSOPTS 100U
+/*% opcode text */
+static const char *const opcodetext[] = {
+ "QUERY", "IQUERY", "STATUS", "RESERVED3",
+ "NOTIFY", "UPDATE", "RESERVED6", "RESERVED7",
+ "RESERVED8", "RESERVED9", "RESERVED10", "RESERVED11",
+ "RESERVED12", "RESERVED13", "RESERVED14", "RESERVED15"
+};
+
+/*% return code text */
+static const char *const rcodetext[] = {
+ "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP",
+ "REFUSED", "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH",
+ "NOTZONE", "RESERVED11", "RESERVED12", "RESERVED13", "RESERVED14",
+ "RESERVED15", "BADVERS"
+};
+
+/*% safe rcodetext[] */
+static char *
+rcode_totext(dns_rcode_t rcode) {
+ static char buf[sizeof("?65535")];
+ union {
+ const char *consttext;
+ char *deconsttext;
+ } totext;
+
+ if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) {
+ snprintf(buf, sizeof(buf), "?%u", rcode);
+ totext.deconsttext = buf;
+ } else {
+ totext.consttext = rcodetext[rcode];
+ }
+ return (totext.deconsttext);
+}
+
+/* receive response event handler */
+static void
+recvresponse(isc_task_t *task, isc_event_t *event) {
+ dns_requestevent_t *reqev = (dns_requestevent_t *)event;
+ isc_result_t result;
+ dns_message_t *query = NULL, *response = NULL;
+ unsigned int parseflags = 0;
+ isc_buffer_t *msgbuf = NULL, *buf = NULL;
+ unsigned int len = OUTPUTBUF;
+ dns_master_style_t *style = NULL;
+ unsigned int styleflags = 0;
+ dns_messagetextflag_t flags;
+
+ UNUSED(task);
+
+ REQUIRE(reqev != NULL);
+ query = reqev->ev_arg;
+
+ if (reqev->result != ISC_R_SUCCESS) {
+ fprintf(stderr, "response failed with %s\n",
+ isc_result_totext(reqev->result));
+ if (continue_on_error) {
+ goto cleanup;
+ } else {
+ exit(-1);
+ }
+ }
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &response);
+
+ parseflags |= DNS_MESSAGEPARSE_PRESERVEORDER;
+ if (besteffort) {
+ parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
+ parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
+ }
+
+ msgbuf = dns_request_getanswer(reqev->request);
+ result = dns_request_getresponse(reqev->request, response, parseflags);
+ CHECK("dns_request_getresponse", result);
+
+ styleflags |= DNS_STYLEFLAG_REL_OWNER;
+ if (yaml) {
+ styleflags |= DNS_STYLEFLAG_YAML;
+ response->indent.string = " ";
+ response->indent.count = 3;
+ } else {
+ if (display_comments) {
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ }
+ if (display_unknown_format) {
+ styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
+ }
+ if (display_rrcomments > 0) {
+ styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ if (display_ttlunits) {
+ styleflags |= DNS_STYLEFLAG_TTL_UNITS;
+ }
+ if (!display_ttl) {
+ styleflags |= DNS_STYLEFLAG_NO_TTL;
+ }
+ if (!display_class) {
+ styleflags |= DNS_STYLEFLAG_NO_CLASS;
+ }
+ if (!display_crypto) {
+ styleflags |= DNS_STYLEFLAG_NOCRYPTO;
+ }
+ if (display_multiline) {
+ styleflags |= DNS_STYLEFLAG_OMIT_OWNER;
+ styleflags |= DNS_STYLEFLAG_OMIT_CLASS;
+ styleflags |= DNS_STYLEFLAG_REL_DATA;
+ styleflags |= DNS_STYLEFLAG_OMIT_TTL;
+ styleflags |= DNS_STYLEFLAG_TTL;
+ styleflags |= DNS_STYLEFLAG_MULTILINE;
+ styleflags |= DNS_STYLEFLAG_COMMENT;
+ /* Turn on rrcomments unless explicitly disabled */
+ if (display_rrcomments >= 0) {
+ styleflags |= DNS_STYLEFLAG_RRCOMMENT;
+ }
+ }
+ }
+ if (display_multiline || (!display_ttl && !display_class)) {
+ result = dns_master_stylecreate(&style, styleflags, 24, 24, 24,
+ 32, 80, 8, display_splitwidth,
+ mctx);
+ } else if (!display_ttl || !display_class) {
+ result = dns_master_stylecreate(&style, styleflags, 24, 24, 32,
+ 40, 80, 8, display_splitwidth,
+ mctx);
+ } else {
+ result = dns_master_stylecreate(&style, styleflags, 24, 32, 40,
+ 48, 80, 8, display_splitwidth,
+ mctx);
+ }
+ CHECK("dns_master_stylecreate2", result);
+
+ flags = 0;
+ if (!display_headers) {
+ flags |= DNS_MESSAGETEXTFLAG_NOHEADERS;
+ flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
+ }
+ if (!display_comments) {
+ flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS;
+ }
+
+ isc_buffer_allocate(mctx, &buf, len);
+
+ if (yaml) {
+ char sockstr[ISC_SOCKADDR_FORMATSIZE];
+ uint16_t sport;
+ char *hash;
+ int pf;
+
+ printf("-\n");
+ printf(" type: MESSAGE\n");
+ printf(" message:\n");
+
+ if (((response->flags & DNS_MESSAGEFLAG_RD) != 0) &&
+ ((response->flags & DNS_MESSAGEFLAG_RA) != 0))
+ {
+ printf(" type: RECURSIVE_RESPONSE\n");
+ } else {
+ printf(" type: AUTH_RESPONSE\n");
+ }
+
+ printf(" message_size: %ub\n",
+ isc_buffer_usedlength(msgbuf));
+
+ pf = isc_sockaddr_pf(&dstaddr);
+ if (pf == PF_INET || pf == PF_INET6) {
+ printf(" socket_family: %s\n",
+ pf == PF_INET ? "INET" : "INET6");
+
+ printf(" socket_protocol: %s\n",
+ tcp_mode ? "TCP" : "UDP");
+
+ sport = isc_sockaddr_getport(&dstaddr);
+ isc_sockaddr_format(&dstaddr, sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ printf(" response_address: \"%s\"\n", sockstr);
+ printf(" response_port: %u\n", sport);
+ }
+
+ if (have_src) {
+ sport = isc_sockaddr_getport(&srcaddr);
+ isc_sockaddr_format(&srcaddr, sockstr, sizeof(sockstr));
+ hash = strchr(sockstr, '#');
+ if (hash != NULL) {
+ *hash = '\0';
+ }
+ printf(" query_address: \"%s\"\n", sockstr);
+ printf(" query_port: %u\n", sport);
+ }
+
+ printf(" %s:\n", "response_message_data");
+ result = dns_message_headertotext(response, style, flags, buf);
+ CHECK("dns_message_headertotext", result);
+ } else if (display_comments && !display_short_form) {
+ printf(";; Got answer:\n");
+
+ if (display_headers) {
+ printf(";; ->>HEADER<<- opcode: %s, status: %s, "
+ "id: %u\n",
+ opcodetext[response->opcode],
+ rcode_totext(response->rcode), response->id);
+ printf(";; flags:");
+ if ((response->flags & DNS_MESSAGEFLAG_QR) != 0) {
+ printf(" qr");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_AA) != 0) {
+ printf(" aa");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_TC) != 0) {
+ printf(" tc");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_RD) != 0) {
+ printf(" rd");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_RA) != 0) {
+ printf(" ra");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_AD) != 0) {
+ printf(" ad");
+ }
+ if ((response->flags & DNS_MESSAGEFLAG_CD) != 0) {
+ printf(" cd");
+ }
+ if ((response->flags & 0x0040U) != 0) {
+ printf("; MBZ: 0x4");
+ }
+
+ printf("; QUERY: %u, ANSWER: %u, "
+ "AUTHORITY: %u, ADDITIONAL: %u\n",
+ response->counts[DNS_SECTION_QUESTION],
+ response->counts[DNS_SECTION_ANSWER],
+ response->counts[DNS_SECTION_AUTHORITY],
+ response->counts[DNS_SECTION_ADDITIONAL]);
+
+ if ((response->flags & DNS_MESSAGEFLAG_RD) != 0 &&
+ (response->flags & DNS_MESSAGEFLAG_RA) == 0)
+ {
+ printf(";; WARNING: recursion requested "
+ "but not available\n");
+ }
+ }
+ }
+
+repopulate_buffer:
+
+ if (display_comments && display_headers && !display_short_form) {
+ result = dns_message_pseudosectiontotext(
+ response, DNS_PSEUDOSECTION_OPT, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ buftoosmall:
+ len += OUTPUTBUF;
+ isc_buffer_free(&buf);
+ isc_buffer_allocate(mctx, &buf, len);
+ goto repopulate_buffer;
+ }
+ CHECK("dns_message_pseudosectiontotext", result);
+ }
+
+ if (display_question && display_headers && !display_short_form) {
+ result = dns_message_sectiontotext(
+ response, DNS_SECTION_QUESTION, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_sectiontotext", result);
+ }
+
+ if (display_answer && !display_short_form) {
+ result = dns_message_sectiontotext(response, DNS_SECTION_ANSWER,
+ style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_sectiontotext", result);
+ } else if (display_answer) {
+ dns_name_t *name;
+ dns_rdataset_t *rdataset;
+ isc_result_t loopresult;
+ dns_name_t empty_name;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int answerstyleflags = 0;
+
+ if (!display_crypto) {
+ answerstyleflags |= DNS_STYLEFLAG_NOCRYPTO;
+ }
+ if (display_unknown_format) {
+ answerstyleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT;
+ }
+
+ dns_name_init(&empty_name, NULL);
+ result = dns_message_firstname(response, DNS_SECTION_ANSWER);
+ if (result != ISC_R_NOMORE) {
+ CHECK("dns_message_firstname", result);
+ }
+
+ for (;;) {
+ if (result == ISC_R_NOMORE) {
+ break;
+ }
+ CHECK("dns_message_nextname", result);
+ name = NULL;
+ dns_message_currentname(response, DNS_SECTION_ANSWER,
+ &name);
+
+ for (rdataset = ISC_LIST_HEAD(name->list);
+ rdataset != NULL;
+ rdataset = ISC_LIST_NEXT(rdataset, link))
+ {
+ loopresult = dns_rdataset_first(rdataset);
+ while (loopresult == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+ result = dns_rdata_tofmttext(
+ &rdata, NULL, answerstyleflags,
+ 0, 60, " ", buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_rdata_tofmttext", result);
+ loopresult =
+ dns_rdataset_next(rdataset);
+ dns_rdata_reset(&rdata);
+ if (strlen("\n") >=
+ isc_buffer_availablelength(buf))
+ {
+ goto buftoosmall;
+ }
+ isc_buffer_putstr(buf, "\n");
+ }
+ }
+ result = dns_message_nextname(response,
+ DNS_SECTION_ANSWER);
+ }
+ }
+
+ if (display_authority && !display_short_form) {
+ result = dns_message_sectiontotext(
+ response, DNS_SECTION_AUTHORITY, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_sectiontotext", result);
+ }
+
+ if (display_additional && !display_short_form) {
+ result = dns_message_sectiontotext(
+ response, DNS_SECTION_ADDITIONAL, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_sectiontotext", result);
+ }
+
+ if (display_additional && !display_short_form && display_headers) {
+ /*
+ * Only print the signature on the first record.
+ */
+ result = dns_message_pseudosectiontotext(
+ response, DNS_PSEUDOSECTION_TSIG, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_pseudosectiontotext", result);
+ result = dns_message_pseudosectiontotext(
+ response, DNS_PSEUDOSECTION_SIG0, style, flags, buf);
+ if (result == ISC_R_NOSPACE) {
+ goto buftoosmall;
+ }
+ CHECK("dns_message_pseudosectiontotext", result);
+ }
+
+ if (display_headers && display_comments && !display_short_form && !yaml)
+ {
+ printf("\n");
+ }
+
+ printf("%.*s", (int)isc_buffer_usedlength(buf),
+ (char *)isc_buffer_base(buf));
+ isc_buffer_free(&buf);
+
+cleanup:
+ fflush(stdout);
+ if (style != NULL) {
+ dns_master_styledestroy(&style, mctx);
+ }
+ if (query != NULL) {
+ dns_message_detach(&query);
+ }
+ if (response != NULL) {
+ dns_message_detach(&response);
+ }
+ dns_request_destroy(&reqev->request);
+ isc_event_free(&event);
+
+ if (--onfly == 0) {
+ isc_app_shutdown();
+ }
+ return;
+}
+
+/*%
+ * Add EDNS0 option record to a message. Currently, the only supported
+ * options are UDP buffer size, the DO bit, and EDNS options
+ * (e.g., NSID, COOKIE, client-subnet)
+ */
+static void
+add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns, unsigned int flags,
+ dns_ednsopt_t *opts, size_t count) {
+ dns_rdataset_t *rdataset = NULL;
+ isc_result_t result;
+
+ result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
+ opts, count);
+ CHECK("dns_message_buildopt", result);
+ result = dns_message_setopt(msg, rdataset);
+ CHECK("dns_message_setopt", result);
+}
+
+static void
+compute_cookie(unsigned char *cookie, size_t len) {
+ /* XXXMPA need to fix, should be per server. */
+ INSIST(len >= 8U);
+ memmove(cookie, cookie_secret, 8);
+}
+
+static isc_result_t
+sendquery(struct query *query, isc_task_t *task) {
+ dns_request_t *request = NULL;
+ dns_message_t *message = NULL;
+ dns_name_t *qname = NULL;
+ dns_rdataset_t *qrdataset = NULL;
+ isc_result_t result;
+ dns_fixedname_t queryname;
+ isc_buffer_t buf;
+ unsigned int options;
+
+ onfly++;
+
+ dns_fixedname_init(&queryname);
+ isc_buffer_init(&buf, query->textname, strlen(query->textname));
+ isc_buffer_add(&buf, strlen(query->textname));
+ result = dns_name_fromtext(dns_fixedname_name(&queryname), &buf,
+ dns_rootname, 0, NULL);
+ CHECK("dns_name_fromtext", result);
+
+ dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &message);
+
+ message->opcode = dns_opcode_query;
+ if (query->recurse) {
+ message->flags |= DNS_MESSAGEFLAG_RD;
+ }
+ if (query->have_aaonly) {
+ message->flags |= DNS_MESSAGEFLAG_AA;
+ }
+ if (query->have_adflag) {
+ message->flags |= DNS_MESSAGEFLAG_AD;
+ }
+ if (query->have_cdflag) {
+ message->flags |= DNS_MESSAGEFLAG_CD;
+ }
+ if (query->have_zflag) {
+ message->flags |= 0x0040U;
+ }
+ message->rdclass = query->rdclass;
+ message->id = (unsigned short)(random() & 0xFFFF);
+
+ result = dns_message_gettempname(message, &qname);
+ CHECK("dns_message_gettempname", result);
+
+ result = dns_message_gettemprdataset(message, &qrdataset);
+ CHECK("dns_message_gettemprdataset", result);
+
+ dns_name_clone(dns_fixedname_name(&queryname), qname);
+ dns_rdataset_makequestion(qrdataset, query->rdclass, query->rdtype);
+ ISC_LIST_APPEND(qname->list, qrdataset, link);
+ dns_message_addname(message, qname, DNS_SECTION_QUESTION);
+
+ if (query->udpsize > 0 || query->dnssec || query->edns > -1 ||
+ query->ecs_addr != NULL)
+ {
+ dns_ednsopt_t opts[EDNSOPTS + DNS_EDNSOPTIONS];
+ unsigned int flags;
+ int i = 0;
+ char ecsbuf[20];
+ unsigned char cookie[40];
+
+ if (query->udpsize == 0) {
+ query->udpsize = 1232;
+ }
+ if (query->edns < 0) {
+ query->edns = 0;
+ }
+
+ if (query->nsid) {
+ INSIST(i < DNS_EDNSOPTIONS);
+ opts[i].code = DNS_OPT_NSID;
+ opts[i].length = 0;
+ opts[i].value = NULL;
+ i++;
+ }
+
+ if (query->ecs_addr != NULL) {
+ uint8_t addr[16], family;
+ uint32_t plen;
+ struct sockaddr *sa;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ size_t addrl;
+ isc_buffer_t b;
+
+ sa = &query->ecs_addr->type.sa;
+ plen = query->ecs_addr->length;
+
+ /* Round up prefix len to a multiple of 8 */
+ addrl = (plen + 7) / 8;
+
+ INSIST(i < DNS_EDNSOPTIONS);
+ opts[i].code = DNS_OPT_CLIENT_SUBNET;
+ opts[i].length = (uint16_t)addrl + 4;
+ CHECK("isc_buffer_allocate", result);
+ isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
+ if (sa->sa_family == AF_INET) {
+ family = 1;
+ sin = (struct sockaddr_in *)sa;
+ memmove(addr, &sin->sin_addr, 4);
+ if ((plen % 8) != 0) {
+ addr[addrl - 1] &= ~0U
+ << (8 - (plen % 8));
+ }
+ } else {
+ family = 2;
+ sin6 = (struct sockaddr_in6 *)sa;
+ memmove(addr, &sin6->sin6_addr, 16);
+ }
+
+ /* Mask off last address byte */
+ if (addrl > 0 && (plen % 8) != 0) {
+ addr[addrl - 1] &= ~0U << (8 - (plen % 8));
+ }
+
+ /* family */
+ isc_buffer_putuint16(&b, family);
+ /* source prefix-length */
+ isc_buffer_putuint8(&b, plen);
+ /* scope prefix-length */
+ isc_buffer_putuint8(&b, 0);
+ /* address */
+ if (addrl > 0) {
+ isc_buffer_putmem(&b, addr, (unsigned)addrl);
+ }
+
+ opts[i].value = (uint8_t *)ecsbuf;
+ i++;
+ }
+
+ if (query->send_cookie) {
+ INSIST(i < DNS_EDNSOPTIONS);
+ opts[i].code = DNS_OPT_COOKIE;
+ if (query->cookie != NULL) {
+ isc_buffer_t b;
+
+ isc_buffer_init(&b, cookie, sizeof(cookie));
+ result = isc_hex_decodestring(query->cookie,
+ &b);
+ CHECK("isc_hex_decodestring", result);
+ opts[i].value = isc_buffer_base(&b);
+ opts[i].length = isc_buffer_usedlength(&b);
+ } else {
+ compute_cookie(cookie, 8);
+ opts[i].length = 8;
+ opts[i].value = cookie;
+ }
+ i++;
+ }
+
+ if (query->expire) {
+ INSIST(i < DNS_EDNSOPTIONS);
+ opts[i].code = DNS_OPT_EXPIRE;
+ opts[i].length = 0;
+ opts[i].value = NULL;
+ i++;
+ }
+
+ if (query->ednsoptscnt != 0) {
+ memmove(&opts[i], query->ednsopts,
+ sizeof(dns_ednsopt_t) * query->ednsoptscnt);
+ i += query->ednsoptscnt;
+ }
+
+ flags = query->ednsflags;
+ flags &= ~DNS_MESSAGEEXTFLAG_DO;
+ if (query->dnssec) {
+ flags |= DNS_MESSAGEEXTFLAG_DO;
+ }
+ add_opt(message, query->udpsize, query->edns, flags, opts, i);
+ }
+
+ options = 0;
+ if (tcp_mode) {
+ options |= DNS_REQUESTOPT_TCP;
+ }
+
+ request = NULL;
+ result = dns_request_create(
+ requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr,
+ options, NULL, query->timeout, query->udptimeout,
+ query->udpretries, task, recvresponse, message, &request);
+ CHECK("dns_request_create", result);
+
+ return (ISC_R_SUCCESS);
+}
+
+static void
+sendqueries(isc_task_t *task, isc_event_t *event) {
+ struct query *query = (struct query *)event->ev_arg;
+
+ isc_event_free(&event);
+
+ while (query != NULL) {
+ struct query *next = ISC_LIST_NEXT(query, link);
+
+ sendquery(query, task);
+ query = next;
+ }
+
+ if (onfly == 0) {
+ isc_app_shutdown();
+ }
+ return;
+}
+
+noreturn static void
+usage(void);
+
+static void
+usage(void) {
+ fprintf(stderr, "Usage: mdig @server {global-opt} host\n"
+ " {local-opt} [ host {local-opt} [...]]\n"
+ "\nUse \"mdig -h\" (or \"mdig -h | more\") "
+ "for complete list of options\n");
+ exit(1);
+}
+
+/*% help */
+static void
+help(void) {
+ printf("Usage: mdig @server {global-opt} host\n"
+ " {local-opt} [ host {local-opt} [...]]\n"
+ "Where:\n"
+ " anywhere opt is one of:\n"
+ " -f filename (batch mode)\n"
+ " -h (print help and exit)\n"
+ " -v (print version and exit)\n"
+ " global opt is one of:\n"
+ " -4 (use IPv4 query transport "
+ "only)\n"
+ " -6 (use IPv6 query transport "
+ "only)\n"
+ " -b address[#port] (bind to source "
+ "address/port)\n"
+ " -p port (specify port number)\n"
+ " -m (enable memory usage "
+ "debugging)\n"
+ " +[no]vc (TCP mode)\n"
+ " +[no]tcp (TCP mode, alternate "
+ "syntax)\n"
+ " +[no]besteffort (Try to parse even "
+ "illegal "
+ "messages)\n"
+ " +[no]cl (Control display of class "
+ "in records)\n"
+ " +[no]comments (Control display of "
+ "comment lines)\n"
+ " +[no]rrcomments (Control display of "
+ "per-record "
+ "comments)\n"
+ " +[no]crypto (Control display of "
+ "cryptographic "
+ "fields in records)\n"
+ " +[no]question (Control display of "
+ "question)\n"
+ " +[no]answer (Control display of "
+ "answer)\n"
+ " +[no]authority (Control display of "
+ "authority)\n"
+ " +[no]additional (Control display of "
+ "additional)\n"
+ " +[no]short (Disable everything "
+ "except "
+ "short\n"
+ " form of answer)\n"
+ " +[no]ttlid (Control display of ttls "
+ "in records)\n"
+ " +[no]ttlunits (Display TTLs in "
+ "human-readable units)\n"
+ " +[no]unknownformat (Print RDATA in RFC 3597 "
+ "\"unknown\" format)\n"
+ " +[no]all (Set or clear all display "
+ "flags)\n"
+ " +[no]multiline (Print records in an "
+ "expanded format)\n"
+ " +[no]split=## (Split hex/base64 fields "
+ "into chunks)\n"
+ " local opt is one of:\n"
+ " -c class (specify query class)\n"
+ " -t type (specify query type)\n"
+ " -x dot-notation (shortcut for reverse "
+ "lookups)\n"
+ " +timeout=### (Set query timeout) "
+ "[UDP=5,TCP=10]\n"
+ " +udptimeout=### (Set timeout before UDP "
+ "retry)\n"
+ " +tries=### (Set number of UDP "
+ "attempts) [3]\n"
+ " +retry=### (Set number of UDP "
+ "retries) [2]\n"
+ " +bufsize=### (Set EDNS0 Max UDP packet "
+ "size)\n"
+ " +subnet=addr (Set edns-client-subnet "
+ "option)\n"
+ " +[no]edns[=###] (Set EDNS version) [0]\n"
+ " +ednsflags=### (Set EDNS flag bits)\n"
+ " +ednsopt=###[:value] (Send specified EDNS "
+ "option)\n"
+ " +noednsopt (Clear list of +ednsopt "
+ "options)\n"
+ " +[no]recurse (Recursive mode)\n"
+ " +[no]aaonly (Set AA flag in query "
+ "(+[no]aaflag))\n"
+ " +[no]adflag (Set AD flag in query)\n"
+ " +[no]cdflag (Set CD flag in query)\n"
+ " +[no]zflag (Set Z flag in query)\n"
+ " +[no]dnssec (Request DNSSEC records)\n"
+ " +[no]expire (Request time to expire)\n"
+ " +[no]cookie[=###] (Send a COOKIE option)\n"
+ " +[no]nsid (Request Name "
+ "Server ID)\n");
+}
+
+noreturn static void
+fatal(const char *format, ...) ISC_FORMAT_PRINTF(1, 2);
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fflush(stdout);
+ fprintf(stderr, "mdig: ");
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(-2);
+}
+
+static isc_result_t
+parse_uint_helper(uint32_t *uip, const char *value, uint32_t max,
+ const char *desc, int base) {
+ uint32_t n;
+ isc_result_t result = isc_parse_uint32(&n, value, base);
+ if (result == ISC_R_SUCCESS && n > max) {
+ result = ISC_R_RANGE;
+ }
+ if (result != ISC_R_SUCCESS) {
+ printf("invalid %s '%s': %s\n", desc, value,
+ isc_result_totext(result));
+ return (result);
+ }
+ *uip = n;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
+ return (parse_uint_helper(uip, value, max, desc, 10));
+}
+
+static isc_result_t
+parse_xint(uint32_t *uip, const char *value, uint32_t max, const char *desc) {
+ return (parse_uint_helper(uip, value, max, desc, 0));
+}
+
+static void
+newopts(struct query *query) {
+ size_t len = sizeof(query->ednsopts[0]) * EDNSOPTS;
+ size_t i;
+
+ query->ednsopts = isc_mem_allocate(mctx, len);
+
+ for (i = 0; i < EDNSOPTS; i++) {
+ query->ednsopts[i].code = 0;
+ query->ednsopts[i].length = 0;
+ query->ednsopts[i].value = NULL;
+ }
+}
+
+static void
+save_opt(struct query *query, char *code, char *value) {
+ uint32_t num;
+ isc_buffer_t b;
+ isc_result_t result;
+
+ if (query->ednsopts == NULL) {
+ newopts(query);
+ }
+
+ if (query->ednsoptscnt == EDNSOPTS) {
+ fatal("too many ednsopts");
+ }
+
+ result = parse_uint(&num, code, 65535, "ednsopt");
+ if (result != ISC_R_SUCCESS) {
+ fatal("bad edns code point: %s", code);
+ }
+
+ query->ednsopts[query->ednsoptscnt].code = num;
+ query->ednsopts[query->ednsoptscnt].length = 0;
+ query->ednsopts[query->ednsoptscnt].value = NULL;
+
+ if (value != NULL) {
+ char *buf;
+ buf = isc_mem_allocate(mctx, strlen(value) / 2 + 1);
+ isc_buffer_init(&b, buf, strlen(value) / 2 + 1);
+ result = isc_hex_decodestring(value, &b);
+ CHECK("isc_hex_decodestring", result);
+ query->ednsopts[query->ednsoptscnt].value = isc_buffer_base(&b);
+ query->ednsopts[query->ednsoptscnt].length =
+ isc_buffer_usedlength(&b);
+ }
+
+ query->ednsoptscnt++;
+}
+
+static isc_result_t
+parse_netprefix(isc_sockaddr_t **sap, const char *value) {
+ isc_sockaddr_t *sa = NULL;
+ struct in_addr in4;
+ struct in6_addr in6;
+ uint32_t netmask = 0xffffffff;
+ char *slash = NULL;
+ bool parsed = false;
+ char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
+
+ if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf)) {
+ fatal("invalid prefix '%s'\n", value);
+ }
+
+ slash = strchr(buf, '/');
+ if (slash != NULL) {
+ isc_result_t result;
+ *slash = '\0';
+ result = isc_parse_uint32(&netmask, slash + 1, 10);
+ if (result != ISC_R_SUCCESS) {
+ fatal("invalid prefix length in '%s': %s\n", value,
+ isc_result_totext(result));
+ }
+ } else if (strcmp(value, "0") == 0) {
+ netmask = 0;
+ }
+
+ sa = isc_mem_allocate(mctx, sizeof(*sa));
+ if (inet_pton(AF_INET6, buf, &in6) == 1) {
+ parsed = true;
+ isc_sockaddr_fromin6(sa, &in6, 0);
+ if (netmask > 128) {
+ netmask = 128;
+ }
+ } else if (inet_pton(AF_INET, buf, &in4) == 1) {
+ parsed = true;
+ isc_sockaddr_fromin(sa, &in4, 0);
+ if (netmask > 32) {
+ netmask = 32;
+ }
+ } else if (netmask != 0xffffffff) {
+ int i;
+
+ for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
+ strlcat(buf, ".0", sizeof(buf));
+ if (inet_pton(AF_INET, buf, &in4) == 1) {
+ parsed = true;
+ isc_sockaddr_fromin(sa, &in4, 0);
+ break;
+ }
+ }
+
+ if (netmask > 32) {
+ netmask = 32;
+ }
+ }
+
+ if (!parsed) {
+ fatal("invalid address '%s'", value);
+ }
+
+ sa->length = netmask;
+ *sap = sa;
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Append 'len' bytes of 'text' at '*p', failing with
+ * ISC_R_NOSPACE if that would advance p past 'end'.
+ */
+static isc_result_t
+append(const char *text, int len, char **p, char *end) {
+ if (len > end - *p) {
+ return (ISC_R_NOSPACE);
+ }
+ memmove(*p, text, len);
+ *p += len;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+reverse_octets(const char *in, char **p, char *end) {
+ const char *dot = strchr(in, '.');
+ int len;
+ if (dot != NULL) {
+ isc_result_t result;
+ result = reverse_octets(dot + 1, p, end);
+ CHECK("reverse_octets", result);
+ result = append(".", 1, p, end);
+ CHECK("append", result);
+ len = (int)(dot - in);
+ } else {
+ len = strlen(in);
+ }
+ return (append(in, len, p, end));
+}
+
+static void
+get_reverse(char *reverse, size_t len, const char *value) {
+ int r;
+ isc_result_t result;
+ isc_netaddr_t addr;
+
+ addr.family = AF_INET6;
+ r = inet_pton(AF_INET6, value, &addr.type.in6);
+ if (r > 0) {
+ /* This is a valid IPv6 address. */
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ unsigned int options = 0;
+
+ name = dns_fixedname_initname(&fname);
+ result = dns_byaddr_createptrname(&addr, options, name);
+ CHECK("dns_byaddr_createptrname2", result);
+ dns_name_format(name, reverse, (unsigned int)len);
+ return;
+ } else {
+ /*
+ * Not a valid IPv6 address. Assume IPv4.
+ * Construct the in-addr.arpa name by blindly
+ * reversing octets whether or not they look like
+ * integers, so that this can be used for RFC2317
+ * names and such.
+ */
+ char *p = reverse;
+ char *end = reverse + len;
+ result = reverse_octets(value, &p, end);
+ CHECK("reverse_octets", result);
+ /* Append .in-addr.arpa. and a terminating NUL. */
+ result = append(".in-addr.arpa.", 15, &p, end);
+ CHECK("append", result);
+ return;
+ }
+}
+
+/*%
+ * We're not using isc_commandline_parse() here since the command line
+ * syntax of mdig is quite a bit different from that which can be described
+ * by that routine.
+ * XXX doc options
+ */
+
+static void
+plus_option(char *option, struct query *query, bool global) {
+ isc_result_t result;
+ char *cmd, *value, *last = NULL, *code;
+ uint32_t num;
+ bool state = true;
+ size_t n;
+
+ INSIST(option != NULL);
+
+ if ((cmd = strtok_r(option, "=", &last)) == NULL) {
+ printf(";; Invalid option %s\n", option);
+ return;
+ }
+ if (strncasecmp(cmd, "no", 2) == 0) {
+ cmd += 2;
+ state = false;
+ }
+ /* parse the rest of the string */
+ value = strtok_r(NULL, "", &last);
+
+#define FULLCHECK(A) \
+ do { \
+ size_t _l = strlen(cmd); \
+ if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \
+ goto invalid_option; \
+ } while (0)
+#define FULLCHECK2(A, B) \
+ do { \
+ size_t _l = strlen(cmd); \
+ if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \
+ (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \
+ goto invalid_option; \
+ } while (0)
+#define GLOBAL() \
+ do { \
+ if (!global) \
+ goto global_option; \
+ } while (0)
+
+ switch (cmd[0]) {
+ case 'a':
+ switch (cmd[1]) {
+ case 'a': /* aaonly / aaflag */
+ FULLCHECK2("aaonly", "aaflag");
+ query->have_aaonly = state;
+ break;
+ case 'd':
+ switch (cmd[2]) {
+ case 'd': /* additional */
+ FULLCHECK("additional");
+ display_additional = state;
+ break;
+ case 'f': /* adflag */
+ case '\0': /* +ad is a synonym for +adflag */
+ FULLCHECK("adflag");
+ query->have_adflag = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'l': /* all */
+ FULLCHECK("all");
+ GLOBAL();
+ display_question = state;
+ display_answer = state;
+ display_authority = state;
+ display_additional = state;
+ display_comments = state;
+ display_rrcomments = state ? 1 : -1;
+ break;
+ case 'n': /* answer */
+ FULLCHECK("answer");
+ GLOBAL();
+ display_answer = state;
+ break;
+ case 'u': /* authority */
+ FULLCHECK("authority");
+ GLOBAL();
+ display_authority = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'b':
+ switch (cmd[1]) {
+ case 'e': /* besteffort */
+ FULLCHECK("besteffort");
+ GLOBAL();
+ besteffort = state;
+ break;
+ case 'u':
+ switch (cmd[2]) {
+ case 'f': /* bufsize */
+ FULLCHECK("bufsize");
+ if (value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ goto invalid_option;
+ }
+ result = parse_uint(&num, value, COMMSIZE,
+ "buffer size");
+ CHECK("parse_uint(buffer size)", result);
+ query->udpsize = num;
+ break;
+ case 'r': /* burst */
+ FULLCHECK("burst");
+ GLOBAL();
+ burst = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'c':
+ switch (cmd[1]) {
+ case 'd': /* cdflag */
+ switch (cmd[2]) {
+ case 'f': /* cdflag */
+ case '\0': /* +cd is a synonym for +cdflag */
+ FULLCHECK("cdflag");
+ query->have_cdflag = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'l': /* cl */
+ FULLCHECK("cl");
+ GLOBAL();
+ display_class = state;
+ break;
+ case 'o': /* comments */
+ switch (cmd[2]) {
+ case 'm':
+ FULLCHECK("comments");
+ GLOBAL();
+ display_comments = state;
+ break;
+ case 'n':
+ FULLCHECK("continue");
+ GLOBAL();
+ continue_on_error = state;
+ break;
+ case 'o':
+ FULLCHECK("cookie");
+ if (state && query->edns == -1) {
+ query->edns = 0;
+ }
+ query->send_cookie = state;
+ if (value != NULL) {
+ n = strlcpy(hexcookie, value,
+ sizeof(hexcookie));
+ if (n >= sizeof(hexcookie)) {
+ fatal("COOKIE data too large");
+ }
+ query->cookie = hexcookie;
+ } else {
+ query->cookie = NULL;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'r':
+ FULLCHECK("crypto");
+ GLOBAL();
+ display_crypto = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'd':
+ switch (cmd[1]) {
+ case 'n': /* dnssec */
+ FULLCHECK("dnssec");
+ if (state && query->edns == -1) {
+ query->edns = 0;
+ }
+ query->dnssec = state;
+ break;
+ case 's': /* dscp */
+ /* obsolete */
+ FULLCHECK("dscp");
+ fprintf(stderr, ";; +dscp option is obsolete "
+ "and has no effect");
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'e':
+ switch (cmd[1]) {
+ case 'd':
+ switch (cmd[2]) {
+ case 'n':
+ switch (cmd[3]) {
+ case 's':
+ switch (cmd[4]) {
+ case 0:
+ FULLCHECK("edns");
+ if (!state) {
+ query->edns = -1;
+ break;
+ }
+ if (value == NULL) {
+ query->edns = 0;
+ break;
+ }
+ result = parse_uint(&num, value,
+ 255,
+ "edns");
+ CHECK("parse_uint(edns)",
+ result);
+ query->edns = num;
+ break;
+ case 'f':
+ FULLCHECK("ednsflags");
+ if (!state) {
+ query->ednsflags = 0;
+ break;
+ }
+ if (value == NULL) {
+ query->ednsflags = 0;
+ break;
+ }
+ result = parse_xint(
+ &num, value, 0xffff,
+ "ednsflags");
+ CHECK("parse_xint(ednsflags)",
+ result);
+ query->ednsflags = num;
+ break;
+ case 'o':
+ FULLCHECK("ednsopt");
+ if (!state) {
+ query->ednsoptscnt = 0;
+ break;
+ }
+ code = NULL;
+ if (value != NULL) {
+ code = strtok_r(value,
+ ":",
+ &last);
+ }
+ if (code == NULL) {
+ fatal("ednsopt no "
+ "code point "
+ "specified");
+ }
+ value = strtok_r(NULL, "\0",
+ &last);
+ save_opt(query, code, value);
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'x':
+ FULLCHECK("expire");
+ query->expire = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'm': /* multiline */
+ FULLCHECK("multiline");
+ GLOBAL();
+ display_multiline = state;
+ break;
+ case 'n':
+ FULLCHECK("nsid");
+ if (state && query->edns == -1) {
+ query->edns = 0;
+ }
+ query->nsid = state;
+ break;
+ case 'q':
+ FULLCHECK("question");
+ GLOBAL();
+ display_question = state;
+ break;
+ case 'r':
+ switch (cmd[1]) {
+ case 'e':
+ switch (cmd[2]) {
+ case 'c': /* recurse */
+ FULLCHECK("recurse");
+ query->recurse = state;
+ break;
+ case 't': /* retry / retries */
+ FULLCHECK2("retry", "retries");
+ if (value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ goto invalid_option;
+ }
+ result = parse_uint(&query->udpretries, value,
+ MAXTRIES - 1, "udpretries");
+ CHECK("parse_uint(udpretries)", result);
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'r':
+ FULLCHECK("rrcomments");
+ GLOBAL();
+ display_rrcomments = state ? 1 : -1;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 's':
+ switch (cmd[1]) {
+ case 'h':
+ FULLCHECK("short");
+ GLOBAL();
+ display_short_form = state;
+ if (state) {
+ display_question = false;
+ display_answer = true;
+ display_authority = false;
+ display_additional = false;
+ display_comments = false;
+ display_rrcomments = -1;
+ }
+ break;
+ case 'p': /* split */
+ FULLCHECK("split");
+ GLOBAL();
+ if (value != NULL && !state) {
+ goto invalid_option;
+ }
+ if (!state) {
+ display_splitwidth = 0;
+ break;
+ } else if (value == NULL) {
+ break;
+ }
+
+ result = parse_uint(&display_splitwidth, value, 1023,
+ "split");
+ if ((display_splitwidth % 4) != 0) {
+ display_splitwidth =
+ ((display_splitwidth + 3) / 4) * 4;
+ fprintf(stderr,
+ ";; Warning, split must be "
+ "a multiple of 4; adjusting "
+ "to %u\n",
+ display_splitwidth);
+ }
+ /*
+ * There is an adjustment done in the
+ * totext_<rrtype>() functions which causes
+ * splitwidth to shrink. This is okay when we're
+ * using the default width but incorrect in this
+ * case, so we correct for it
+ */
+ if (display_splitwidth) {
+ display_splitwidth += 3;
+ }
+ CHECK("parse_uint(split)", result);
+ break;
+ case 'u': /* subnet */
+ FULLCHECK("subnet");
+ if (state && value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ if (query->ecs_addr != NULL) {
+ isc_mem_free(mctx, query->ecs_addr);
+ query->ecs_addr = NULL;
+ }
+ break;
+ }
+ if (query->edns == -1) {
+ query->edns = 0;
+ }
+ result = parse_netprefix(&query->ecs_addr, value);
+ CHECK("parse_netprefix", result);
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 't':
+ switch (cmd[1]) {
+ case 'c': /* tcp */
+ FULLCHECK("tcp");
+ GLOBAL();
+ tcp_mode = state;
+ break;
+ case 'i': /* timeout */
+ FULLCHECK("timeout");
+ if (value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ goto invalid_option;
+ }
+ result = parse_uint(&query->timeout, value, MAXTIMEOUT,
+ "timeout");
+ CHECK("parse_uint(timeout)", result);
+ if (query->timeout == 0) {
+ query->timeout = 1;
+ }
+ break;
+ case 'r':
+ FULLCHECK("tries");
+ if (value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ goto invalid_option;
+ }
+ result = parse_uint(&query->udpretries, value, MAXTRIES,
+ "udpretries");
+ CHECK("parse_uint(udpretries)", result);
+ if (query->udpretries > 0) {
+ query->udpretries -= 1;
+ }
+ break;
+ case 't':
+ switch (cmd[2]) {
+ case 'l':
+ switch (cmd[3]) {
+ case 0:
+ case 'i': /* ttlid */
+ FULLCHECK2("ttl", "ttlid");
+ GLOBAL();
+ display_ttl = state;
+ break;
+ case 'u': /* ttlunits */
+ FULLCHECK("ttlunits");
+ GLOBAL();
+ display_ttl = true;
+ display_ttlunits = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'u':
+ switch (cmd[1]) {
+ case 'd':
+ FULLCHECK("udptimeout");
+ if (value == NULL) {
+ goto need_value;
+ }
+ if (!state) {
+ goto invalid_option;
+ }
+ result = parse_uint(&query->udptimeout, value,
+ MAXTIMEOUT, "udptimeout");
+ CHECK("parse_uint(udptimeout)", result);
+ break;
+ case 'n':
+ FULLCHECK("unknownformat");
+ display_unknown_format = state;
+ break;
+ default:
+ goto invalid_option;
+ }
+ break;
+ case 'v':
+ FULLCHECK("vc");
+ GLOBAL();
+ tcp_mode = state;
+ break;
+ case 'y': /* yaml */
+ FULLCHECK("yaml");
+ yaml = state;
+ if (state) {
+ display_rrcomments = state;
+ }
+ break;
+ case 'z': /* zflag */
+ FULLCHECK("zflag");
+ query->have_zflag = state;
+ break;
+ global_option:
+ fprintf(stderr, "Ignored late global option: +%s\n", option);
+ break;
+ default:
+ invalid_option:
+ need_value:
+ fprintf(stderr, "Invalid option: +%s\n", option);
+ usage();
+ }
+ return;
+}
+
+/*%
+ * #true returned if value was used
+ */
+static const char *single_dash_opts = "46himv";
+static const char *dash_opts = "46bcfhiptvx";
+static bool
+dash_option(const char *option, char *next, struct query *query, bool global,
+ bool *setname) {
+ char opt;
+ const char *value;
+ isc_result_t result;
+ bool value_from_next;
+ isc_consttextregion_t tr;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ char textname[MXNAME];
+ struct in_addr in4;
+ struct in6_addr in6;
+ in_port_t srcport;
+ char *hash;
+ uint32_t num;
+
+ while (strpbrk(option, single_dash_opts) == &option[0]) {
+ /*
+ * Since the -[46hiv] options do not take an argument,
+ * account for them (in any number and/or combination)
+ * if they appear as the first character(s) of an opt.
+ */
+ opt = option[0];
+ switch (opt) {
+ case '4':
+ GLOBAL();
+ if (have_ipv4) {
+ isc_net_disableipv6();
+ have_ipv6 = false;
+ } else {
+ fatal("can't find IPv4 networking");
+ UNREACHABLE();
+ return (false);
+ }
+ break;
+ case '6':
+ GLOBAL();
+ if (have_ipv6) {
+ isc_net_disableipv4();
+ have_ipv4 = false;
+ } else {
+ fatal("can't find IPv6 networking");
+ UNREACHABLE();
+ return (false);
+ }
+ break;
+ case 'h':
+ help();
+ exit(0);
+ break;
+ case 'i':
+ /* deprecated */
+ break;
+ case 'm':
+ /*
+ * handled by preparse_args()
+ */
+ break;
+ case 'v':
+ fprintf(stderr, "mDiG %s\n", PACKAGE_VERSION);
+ exit(0);
+ break;
+ }
+ if (strlen(option) > 1U) {
+ option = &option[1];
+ } else {
+ return (false);
+ }
+ }
+ opt = option[0];
+ if (strlen(option) > 1U) {
+ value_from_next = false;
+ value = &option[1];
+ } else {
+ value_from_next = true;
+ value = next;
+ }
+ if (value == NULL) {
+ goto invalid_option;
+ }
+ switch (opt) {
+ case 'b':
+ GLOBAL();
+ hash = strchr(value, '#');
+ if (hash != NULL) {
+ result = parse_uint(&num, hash + 1, MAXPORT,
+ "port number");
+ CHECK("parse_uint(srcport)", result);
+ srcport = num;
+ *hash = '\0';
+ } else {
+ srcport = 0;
+ }
+ if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) {
+ isc_sockaddr_fromin6(&srcaddr, &in6, srcport);
+ isc_net_disableipv4();
+ } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) {
+ isc_sockaddr_fromin(&srcaddr, &in4, srcport);
+ isc_net_disableipv6();
+ } else {
+ if (hash != NULL) {
+ *hash = '#';
+ }
+ fatal("invalid address %s", value);
+ }
+ if (hash != NULL) {
+ *hash = '#';
+ }
+ have_src = true;
+ return (value_from_next);
+ case 'c':
+ tr.base = value;
+ tr.length = strlen(value);
+ result = dns_rdataclass_fromtext(&rdclass,
+ (isc_textregion_t *)&tr);
+ CHECK("dns_rdataclass_fromtext", result);
+ query->rdclass = rdclass;
+ return (value_from_next);
+ case 'f':
+ batchname = value;
+ return (value_from_next);
+ case 'p':
+ GLOBAL();
+ result = parse_uint(&num, value, MAXPORT, "port number");
+ CHECK("parse_uint(port)", result);
+ port = num;
+ return (value_from_next);
+ case 't':
+ tr.base = value;
+ tr.length = strlen(value);
+ result = dns_rdatatype_fromtext(&rdtype,
+ (isc_textregion_t *)&tr);
+ CHECK("dns_rdatatype_fromtext", result);
+ query->rdtype = rdtype;
+ return (value_from_next);
+ case 'x':
+ get_reverse(textname, sizeof(textname), value);
+ strlcpy(query->textname, textname, sizeof(query->textname));
+ query->rdtype = dns_rdatatype_ptr;
+ query->rdclass = dns_rdataclass_in;
+ *setname = true;
+ return (value_from_next);
+ global_option:
+ fprintf(stderr, "Ignored late global option: -%s\n", option);
+ usage();
+ default:
+ invalid_option:
+ fprintf(stderr, "Invalid option: -%s\n", option);
+ usage();
+ }
+ UNREACHABLE();
+ return (false);
+}
+
+static struct query *
+clone_default_query(void) {
+ struct query *query;
+
+ query = isc_mem_allocate(mctx, sizeof(struct query));
+ memmove(query, &default_query, sizeof(struct query));
+ if (default_query.ecs_addr != NULL) {
+ size_t len = sizeof(isc_sockaddr_t);
+
+ query->ecs_addr = isc_mem_allocate(mctx, len);
+ memmove(query->ecs_addr, default_query.ecs_addr, len);
+ }
+
+ if (query->timeout == 0) {
+ query->timeout = tcp_mode ? TCPTIMEOUT : UDPTIMEOUT;
+ }
+
+ return (query);
+}
+
+/*%
+ * Because we may be trying to do memory allocation recording, we're going
+ * to need to parse the arguments for the -m *before* we start the main
+ * argument parsing routine.
+ *
+ * I'd prefer not to have to do this, but I am not quite sure how else to
+ * fix the problem. Argument parsing in mdig involves memory allocation
+ * by its nature, so it can't be done in the main argument parser.
+ */
+static void
+preparse_args(int argc, char **argv) {
+ int rc;
+ char **rv;
+ char *option;
+ bool ipv4only = false, ipv6only = false;
+
+ rc = argc;
+ rv = argv;
+ for (rc--, rv++; rc > 0; rc--, rv++) {
+ if (rv[0][0] != '-') {
+ continue;
+ }
+ option = &rv[0][1];
+ while (strpbrk(option, single_dash_opts) == &option[0]) {
+ switch (option[0]) {
+ case 'm':
+ isc_mem_debugging = ISC_MEM_DEBUGTRACE |
+ ISC_MEM_DEBUGRECORD;
+ break;
+ case '4':
+ if (ipv6only) {
+ fatal("only one of -4 and -6 allowed");
+ }
+ ipv4only = true;
+ break;
+ case '6':
+ if (ipv4only) {
+ fatal("only one of -4 and -6 allowed");
+ }
+ ipv6only = true;
+ break;
+ }
+ option = &option[1];
+ }
+ if (strlen(option) == 0U) {
+ continue;
+ }
+ /* Look for dash value option. */
+ if (strpbrk(option, dash_opts) != &option[0] ||
+ strlen(option) > 1U)
+ {
+ /* Error or value in option. */
+ continue;
+ }
+ /* Dash value is next argument so we need to skip it. */
+ rc--, rv++;
+ /* Handle missing argument */
+ if (rc == 0) {
+ break;
+ }
+ }
+}
+
+static void
+parse_args(bool is_batchfile, int argc, char **argv) {
+ struct query *query = NULL;
+ char batchline[MXNAME];
+ int bargc;
+ char *bargv[64];
+ int rc;
+ char **rv;
+ bool global = true;
+ char *last;
+
+ /*
+ * The semantics for parsing the args is a bit complex; if
+ * we don't have a host yet, make the arg apply globally,
+ * otherwise make it apply to the latest host. This is
+ * a bit different than the previous versions, but should
+ * form a consistent user interface.
+ *
+ * First, create a "default query" which won't actually be used
+ * anywhere, except for cloning into new queries
+ */
+
+ if (!is_batchfile) {
+ default_query.textname[0] = 0;
+ default_query.recurse = true;
+ default_query.have_aaonly = false;
+ default_query.have_adflag = true; /*XXX*/
+ default_query.have_cdflag = false;
+ default_query.have_zflag = false;
+ default_query.dnssec = false;
+ default_query.expire = false;
+ default_query.send_cookie = false;
+ default_query.cookie = NULL;
+ default_query.nsid = false;
+ default_query.rdtype = dns_rdatatype_a;
+ default_query.rdclass = dns_rdataclass_in;
+ default_query.udpsize = 0;
+ default_query.edns = 0; /*XXX*/
+ default_query.ednsopts = NULL;
+ default_query.ednsoptscnt = 0;
+ default_query.ednsflags = 0;
+ default_query.ecs_addr = NULL;
+ default_query.timeout = 0;
+ default_query.udptimeout = 0;
+ default_query.udpretries = 2;
+ ISC_LINK_INIT(&default_query, link);
+ }
+
+ if (is_batchfile) {
+ /* Processing '-f batchfile'. */
+ query = clone_default_query();
+ global = false;
+ } else {
+ query = &default_query;
+ }
+
+ rc = argc;
+ rv = argv;
+ for (rc--, rv++; rc > 0; rc--, rv++) {
+ if (strncmp(rv[0], "%", 1) == 0) {
+ break;
+ }
+ if (rv[0][0] == '@') {
+ if (server != NULL) {
+ fatal("server already set to @%s", server);
+ }
+ server = &rv[0][1];
+ } else if (rv[0][0] == '+') {
+ plus_option(&rv[0][1], query, global);
+ } else if (rv[0][0] == '-') {
+ bool setname = false;
+
+ if (rc <= 1) {
+ if (dash_option(&rv[0][1], NULL, query, global,
+ &setname))
+ {
+ rc--;
+ rv++;
+ }
+ } else {
+ if (dash_option(&rv[0][1], rv[1], query, global,
+ &setname))
+ {
+ rc--;
+ rv++;
+ }
+ }
+ if (setname) {
+ if (query == &default_query) {
+ query = clone_default_query();
+ }
+ ISC_LIST_APPEND(queries, query, link);
+
+ default_query.textname[0] = 0;
+ query = clone_default_query();
+ global = false;
+ }
+ } else {
+ /*
+ * Anything which isn't an option
+ */
+ if (query == &default_query) {
+ query = clone_default_query();
+ }
+ strlcpy(query->textname, rv[0],
+ sizeof(query->textname));
+ ISC_LIST_APPEND(queries, query, link);
+
+ query = clone_default_query();
+ global = false;
+ /* XXX Error message */
+ }
+ }
+
+ /*
+ * If we have a batchfile, read the query list from it.
+ */
+ if ((batchname != NULL) && !is_batchfile) {
+ if (strcmp(batchname, "-") == 0) {
+ batchfp = stdin;
+ } else {
+ batchfp = fopen(batchname, "r");
+ }
+ if (batchfp == NULL) {
+ perror(batchname);
+ fatal("couldn't open batch file '%s'", batchname);
+ }
+ while (fgets(batchline, sizeof(batchline), batchfp) != 0) {
+ if (batchline[0] == '\r' || batchline[0] == '\n' ||
+ batchline[0] == '#' || batchline[0] == ';')
+ {
+ continue;
+ }
+ for (bargc = 1, bargv[bargc] = strtok_r(
+ batchline, " \t\r\n", &last);
+ (bargc < 14) && bargv[bargc]; bargc++,
+ bargv[bargc] = strtok_r(NULL, " \t\r\n", &last))
+ {
+ /* empty body */
+ }
+
+ bargv[0] = argv[0];
+ parse_args(true, bargc, (char **)bargv);
+ }
+ if (batchfp != stdin) {
+ fclose(batchfp);
+ }
+ }
+ if (query != &default_query) {
+ if (query->ecs_addr != NULL) {
+ isc_mem_free(mctx, query->ecs_addr);
+ }
+ isc_mem_free(mctx, query);
+ }
+}
+
+/*
+ * Try honoring the operating system's preferred ephemeral port range.
+ */
+static void
+set_source_ports(dns_dispatchmgr_t *manager) {
+ isc_portset_t *v4portset = NULL, *v6portset = NULL;
+ in_port_t udpport_low, udpport_high;
+ isc_result_t result;
+
+ result = isc_portset_create(mctx, &v4portset);
+ if (result != ISC_R_SUCCESS) {
+ fatal("isc_portset_create (v4) failed");
+ }
+
+ result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
+ if (result != ISC_R_SUCCESS) {
+ fatal("isc_net_getudpportrange (v4) failed");
+ }
+
+ isc_portset_addrange(v4portset, udpport_low, udpport_high);
+
+ result = isc_portset_create(mctx, &v6portset);
+ if (result != ISC_R_SUCCESS) {
+ fatal("isc_portset_create (v6) failed");
+ }
+ result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
+ if (result != ISC_R_SUCCESS) {
+ fatal("isc_net_getudpportrange (v6) failed");
+ }
+
+ isc_portset_addrange(v6portset, udpport_low, udpport_high);
+
+ result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_dispatchmgr_setavailports failed");
+ }
+
+ isc_portset_destroy(mctx, &v4portset);
+ isc_portset_destroy(mctx, &v6portset);
+}
+
+/*% Main processing routine for mdig */
+int
+main(int argc, char *argv[]) {
+ struct query *query = NULL;
+ isc_result_t result;
+ isc_sockaddr_t bind_any;
+ isc_log_t *lctx = NULL;
+ isc_logconfig_t *lcfg = NULL;
+ isc_nm_t *netmgr = NULL;
+ isc_taskmgr_t *taskmgr = NULL;
+ isc_task_t *task = NULL;
+ dns_dispatchmgr_t *dispatchmgr = NULL;
+ dns_dispatch_t *dispatchvx = NULL;
+ dns_view_t *view = NULL;
+ unsigned int i;
+ int ns;
+
+ RUNCHECK(isc_app_start());
+
+ if (isc_net_probeipv4() == ISC_R_SUCCESS) {
+ have_ipv4 = true;
+ }
+ if (isc_net_probeipv6() == ISC_R_SUCCESS) {
+ have_ipv6 = true;
+ }
+ if (!have_ipv4 && !have_ipv6) {
+ fatal("could not find either IPv4 or IPv6");
+ }
+
+ preparse_args(argc, argv);
+
+ isc_mem_create(&mctx);
+ isc_log_create(mctx, &lctx, &lcfg);
+
+ RUNCHECK(dst_lib_init(mctx, NULL));
+ isc_nonce_buf(cookie_secret, sizeof(cookie_secret));
+
+ ISC_LIST_INIT(queries);
+ parse_args(false, argc, argv);
+ if (server == NULL) {
+ fatal("a server '@xxx' is required");
+ }
+
+ ns = 0;
+ result = bind9_getaddresses(server, port, &dstaddr, 1, &ns);
+ if (result != ISC_R_SUCCESS) {
+ fatal("couldn't get address for '%s': %s", server,
+ isc_result_totext(result));
+ }
+
+ if (isc_sockaddr_pf(&dstaddr) == PF_INET && have_ipv6) {
+ isc_net_disableipv6();
+ have_ipv6 = false;
+ } else if (isc_sockaddr_pf(&dstaddr) == PF_INET6 && have_ipv4) {
+ isc_net_disableipv4();
+ have_ipv4 = false;
+ }
+ if (have_ipv4 && have_ipv6) {
+ fatal("can't choose between IPv4 and IPv6");
+ }
+
+ isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr, NULL);
+ RUNCHECK(isc_task_create(taskmgr, 0, &task));
+ RUNCHECK(dns_dispatchmgr_create(mctx, netmgr, &dispatchmgr));
+
+ set_source_ports(dispatchmgr);
+
+ if (have_ipv4) {
+ isc_sockaddr_any(&bind_any);
+ } else {
+ isc_sockaddr_any6(&bind_any);
+ }
+ RUNCHECK(dns_dispatch_createudp(
+ dispatchmgr, have_src ? &srcaddr : &bind_any, &dispatchvx));
+
+ RUNCHECK(dns_requestmgr_create(
+ mctx, taskmgr, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
+ have_ipv6 ? dispatchvx : NULL, &requestmgr));
+
+ RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
+
+ query = ISC_LIST_HEAD(queries);
+ RUNCHECK(isc_app_onrun(mctx, task, sendqueries, query));
+
+ /*
+ * Stall to the start of a new second.
+ */
+ if (burst) {
+ isc_time_t start, now;
+ RUNCHECK(isc_time_now(&start));
+ /*
+ * Sleep to 1ms of the end of the second then run a busy loop
+ * until the second changes.
+ */
+ do {
+ RUNCHECK(isc_time_now(&now));
+ if (isc_time_seconds(&start) == isc_time_seconds(&now))
+ {
+ int us = US_PER_SEC -
+ (isc_time_nanoseconds(&now) /
+ NS_PER_US);
+ if (us > US_PER_MS) {
+ usleep(us - US_PER_MS);
+ }
+ } else {
+ break;
+ }
+ } while (1);
+ }
+
+ (void)isc_app_run();
+
+ dns_view_detach(&view);
+
+ dns_requestmgr_shutdown(requestmgr);
+ dns_requestmgr_detach(&requestmgr);
+
+ dns_dispatch_detach(&dispatchvx);
+ dns_dispatchmgr_detach(&dispatchmgr);
+
+ isc_task_shutdown(task);
+ isc_task_detach(&task);
+
+ isc_managers_destroy(&netmgr, &taskmgr, NULL);
+
+ dst_lib_destroy();
+
+ isc_log_destroy(&lctx);
+
+ query = ISC_LIST_HEAD(queries);
+ while (query != NULL) {
+ struct query *next = ISC_LIST_NEXT(query, link);
+
+ if (query->ednsopts != NULL) {
+ for (i = 0; i < EDNSOPTS; i++) {
+ if (query->ednsopts[i].value != NULL) {
+ isc_mem_free(mctx,
+ query->ednsopts[i].value);
+ }
+ }
+ isc_mem_free(mctx, query->ednsopts);
+ }
+ if (query->ecs_addr != NULL) {
+ isc_mem_free(mctx, query->ecs_addr);
+ query->ecs_addr = NULL;
+ }
+ isc_mem_free(mctx, query);
+ query = next;
+ }
+
+ if (default_query.ecs_addr != NULL) {
+ isc_mem_free(mctx, default_query.ecs_addr);
+ }
+
+ isc_mem_destroy(&mctx);
+
+ isc_app_finish();
+
+ return (0);
+}
diff --git a/bin/tools/mdig.rst b/bin/tools/mdig.rst
new file mode 100644
index 0000000..33948d1
--- /dev/null
+++ b/bin/tools/mdig.rst
@@ -0,0 +1,375 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: mdig
+.. program:: mdig
+.. _man_mdig:
+
+mdig - DNS pipelined lookup utility
+-----------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`mdig` {@server} [**-f** filename] [**-h**] [**-v**] [ [**-4**] | [**-6**] ] [**-m**] [**-b** address] [**-p** port#] [**-c** class] [**-t** type] [**-i**] [**-x** addr] [plusopt...]
+
+:program:`mdig` {**-h**}
+
+:program:`mdig` [@server] {global-opt...} { {local-opt...} {query} ...}
+
+Description
+~~~~~~~~~~~
+
+:program:`mdig` is a multiple/pipelined query version of :iscman:`dig`: instead of
+waiting for a response after sending each query, it begins by sending
+all queries. Responses are displayed in the order in which they are
+received, not in the order the corresponding queries were sent.
+
+:program:`mdig` options are a subset of the :iscman:`dig` options, and are divided
+into "anywhere options," which can occur anywhere, "global options," which
+must occur before the query name (or they are ignored with a warning),
+and "local options," which apply to the next query on the command line.
+
+The ``@server`` option is a mandatory global option. It is the name or IP
+address of the name server to query. (Unlike :iscman:`dig`, this value is not
+retrieved from ``/etc/resolv.conf``.) It can be an IPv4 address in
+dotted-decimal notation, an IPv6 address in colon-delimited notation, or
+a hostname. When the supplied ``server`` argument is a hostname,
+:program:`mdig` resolves that name before querying the name server.
+
+:program:`mdig` provides a number of query options which affect the way in
+which lookups are made and the results displayed. Some of these set or
+reset flag bits in the query header, some determine which sections of
+the answer get printed, and others determine the timeout and retry
+strategies.
+
+Each query option is identified by a keyword preceded by a plus sign
+(``+``). Some keywords set or reset an option. These may be preceded by
+the string ``no`` to negate the meaning of that keyword. Other keywords
+assign values to options like the timeout interval. They have the form
+``+keyword=value``.
+
+Anywhere Options
+~~~~~~~~~~~~~~~~
+
+.. option:: -f
+
+ This option makes :program:`mdig` operate in batch mode by reading a list
+ of lookup requests to process from the file ``filename``. The file
+ contains a number of queries, one per line. Each entry in the file
+ should be organized in the same way they would be presented as queries
+ to :program:`mdig` using the command-line interface.
+
+.. option:: -h
+
+ This option causes :program:`mdig` to print detailed help information, with the full list
+ of options, and exit.
+
+.. option:: -v
+
+ This option causes :program:`mdig` to print the version number and exit.
+
+Global Options
+~~~~~~~~~~~~~~
+
+.. option:: -4
+
+ This option forces :program:`mdig` to only use IPv4 query transport.
+
+.. option:: -6
+
+ This option forces :program:`mdig` to only use IPv6 query transport.
+
+.. option:: -b address
+
+ This option sets the source IP address of the query to
+ ``address``. This must be a valid address on one of the host's network
+ interfaces or "0.0.0.0" or "::". An optional port may be specified by
+ appending "#<port>"
+
+.. option:: -m
+
+ This option enables memory usage debugging.
+
+.. option:: -p port#
+
+ This option is used when a non-standard port number is to be
+ queried. ``port#`` is the port number that :program:`mdig` sends its
+ queries to, instead of the standard DNS port number 53. This option is
+ used to test a name server that has been configured to listen for
+ queries on a non-standard port number.
+
+The global query options are:
+
+.. option:: +additional, +noadditional
+
+ This option displays [or does not display] the additional section of a reply. The
+ default is to display it.
+
+.. option:: +all, +noall
+
+ This option sets or clears all display flags.
+
+.. option:: +answer, +noanswer
+
+ This option displays [or does not display] the answer section of a reply. The default
+ is to display it.
+
+.. option:: +authority, +noauthority
+
+ This option displays [or does not display] the authority section of a reply. The
+ default is to display it.
+
+.. option:: +besteffort, +nobesteffort
+
+ This option attempts to display [or does not display] the contents of messages which are malformed. The
+ default is to not display malformed answers.
+
+.. option:: +burst
+
+ This option delays queries until the start of the next second.
+
+.. option:: +cl, +nocl
+
+ This option displays [or does not display] the CLASS when printing the record.
+
+.. option:: +comments, +nocomments
+
+ This option toggles the display of comment lines in the output. The default is to
+ print comments.
+
+.. option:: +continue, +nocontinue
+
+ This option toggles continuation on errors (e.g. timeouts).
+
+.. option:: +crypto, +nocrypto
+
+ This option toggles the display of cryptographic fields in DNSSEC records. The
+ contents of these fields are unnecessary to debug most DNSSEC
+ validation failures and removing them makes it easier to see the
+ common failures. The default is to display the fields. When omitted,
+ they are replaced by the string "[omitted]"; in the DNSKEY case, the
+ key ID is displayed as the replacement, e.g., ``[ key id = value ]``.
+
+.. option:: +dscp=value
+
+ This option formerly set the DSCP value used when sending a query.
+ It is now obsolete, and has no effect.
+
+.. option:: +multiline, +nomultiline
+
+ This option toggles printing of records, like the SOA records, in a verbose multi-line format
+ with human-readable comments. The default is to print each record on
+ a single line, to facilitate machine parsing of the :program:`mdig` output.
+
+.. option:: +question, +noquestion
+
+ This option prints [or does not print] the question section of a query when an answer
+ is returned. The default is to print the question section as a
+ comment.
+
+.. option:: +rrcomments, +norrcomments
+
+ This option toggles the display of per-record comments in the output (for example,
+ human-readable key information about DNSKEY records). The default is
+ not to print record comments unless multiline mode is active.
+
+.. option:: +short, +noshort
+
+ This option provides [or does not provide] a terse answer. The default is to print the answer in a
+ verbose form.
+
+.. option:: +split=W
+
+ This option splits long hex- or base64-formatted fields in resource records into
+ chunks of ``W`` characters (where ``W`` is rounded up to the nearest
+ multiple of 4). ``+nosplit`` or ``+split=0`` causes fields not to be
+ split. The default is 56 characters, or 44 characters when
+ multiline mode is active.
+
+.. option:: +tcp, +notcp
+
+ This option uses [or does not use] TCP when querying name servers. The default behavior
+ is to use UDP.
+
+.. option:: +ttlid, +nottlid
+
+ This option displays [or does not display] the TTL when printing the record.
+
+.. option:: +ttlunits, +nottlunits
+
+ This option displays [or does not display] the TTL in friendly human-readable time
+ units of "s", "m", "h", "d", and "w", representing seconds, minutes,
+ hours, days, and weeks. This implies +ttlid.
+
+.. option:: +vc, +novc
+
+ This option uses [or does not use] TCP when querying name servers. This alternate
+ syntax to :option:`+tcp` is provided for backwards compatibility. The
+ ``vc`` stands for "virtual circuit".
+
+Local Options
+~~~~~~~~~~~~~
+
+.. option:: -c class
+
+ This option sets the query class to ``class``. It can be any valid
+ query class which is supported in BIND 9. The default query class is
+ "IN".
+
+.. option:: -t type
+
+ This option sets the query type to ``type``. It can be any valid
+ query type which is supported in BIND 9. The default query type is "A",
+ unless the :option:`-x` option is supplied to indicate a reverse lookup with
+ the "PTR" query type.
+
+.. option:: -x addr
+
+ Reverse lookups - mapping addresses to names - are simplified by
+ this option. ``addr`` is an IPv4 address in dotted-decimal
+ notation, or a colon-delimited IPv6 address. :program:`mdig` automatically
+ performs a lookup for a query name like ``11.12.13.10.in-addr.arpa`` and
+ sets the query type and class to PTR and IN respectively. By default,
+ IPv6 addresses are looked up using nibble format under the IP6.ARPA
+ domain.
+
+The local query options are:
+
+.. option:: +aaflag, +noaaflag
+
+ This is a synonym for :option:`+aaonly`, :option:`+noaaonly`.
+
+.. option:: +aaonly, +noaaonly
+
+ This sets the ``aa`` flag in the query.
+
+.. option:: +adflag, +noadflag
+
+ This sets [or does not set] the AD (authentic data) bit in the query. This
+ requests the server to return whether all of the answer and authority
+ sections have all been validated as secure, according to the security
+ policy of the server. AD=1 indicates that all records have been
+ validated as secure and the answer is not from a OPT-OUT range. AD=0
+ indicates that some part of the answer was insecure or not validated.
+ This bit is set by default.
+
+.. option:: +bufsize=B
+
+ This sets the UDP message buffer size advertised using EDNS0 to ``B``
+ bytes. The maximum and minimum sizes of this buffer are 65535 and 0
+ respectively. Values outside this range are rounded up or down
+ appropriately. Values other than zero cause a EDNS query to be
+ sent.
+
+.. option:: +cdflag, +nocdflag
+
+ This sets [or does not set] the CD (checking disabled) bit in the query. This
+ requests the server to not perform DNSSEC validation of responses.
+
+.. option:: +cookie=####, +nocookie
+
+ This sends [or does not send] a COOKIE EDNS option, with an optional value. Replaying a COOKIE
+ from a previous response allows the server to identify a previous
+ client. The default is ``+nocookie``.
+
+.. option:: +dnssec, +nodnssec
+
+ This requests that DNSSEC records be sent by setting the DNSSEC OK (DO) bit in
+ the OPT record in the additional section of the query.
+
+.. option:: +edns[=#], +noedns
+
+ This specifies [or does not specify] the EDNS version to query with. Valid values are 0 to 255.
+ Setting the EDNS version causes an EDNS query to be sent.
+ ``+noedns`` clears the remembered EDNS version. EDNS is set to 0 by
+ default.
+
+.. option:: +ednsflags[=#], +noednsflags
+
+ This sets the must-be-zero EDNS flag bits (Z bits) to the specified value.
+ Decimal, hex, and octal encodings are accepted. Setting a named flag
+ (e.g. DO) is silently ignored. By default, no Z bits are set.
+
+.. option:: +ednsopt[=code[:value]], +noednsopt
+
+ This specifies [or does not specify] an EDNS option with code point ``code`` and an optional payload
+ of ``value`` as a hexadecimal string. ``+noednsopt`` clears the EDNS
+ options to be sent.
+
+.. option:: +expire, +noexpire
+
+ This toggles sending of an EDNS Expire option.
+
+.. option:: +nsid, +nonsid
+
+ This toggles inclusion of an EDNS name server ID request when sending a query.
+
+.. option:: +recurse, +norecurse
+
+ This toggles the setting of the RD (recursion desired) bit in the query.
+ This bit is set by default, which means :program:`mdig` normally sends
+ recursive queries.
+
+.. option:: +retry=T
+
+ This sets the number of times to retry UDP queries to server to ``T``
+ instead of the default, 2. Unlike :option:`+tries`, this does not include
+ the initial query.
+
+.. option:: +subnet=addr[/prefix-length], +nosubnet
+
+ This sends [or does not send] an EDNS Client Subnet option with the specified IP
+ address or network prefix.
+
+``mdig +subnet=0.0.0.0/0``, or simply ``mdig +subnet=0``
+ This sends an EDNS client-subnet option with an empty address and a source
+ prefix-length of zero, which signals a resolver that the client's
+ address information must *not* be used when resolving this query.
+
+.. option:: +timeout=T
+
+ This sets the timeout for a query to ``T`` seconds. The default timeout is
+ 5 seconds for UDP transport and 10 for TCP. An attempt to set ``T``
+ to less than 1 results in a query timeout of 1 second being
+ applied.
+
+.. option:: +tries=T
+
+ This sets the number of times to try UDP queries to server to ``T``
+ instead of the default, 3. If ``T`` is less than or equal to zero,
+ the number of tries is silently rounded up to 1.
+
+.. option:: +udptimeout=T
+
+ This sets the timeout between UDP query retries to ``T``.
+
+.. option:: +unknownformat, +nounknownformat
+
+ This prints [or does not print] all RDATA in unknown RR-type presentation format (see :rfc:`3597`).
+ The default is to print RDATA for known types in the type's
+ presentation format.
+
+.. option:: +yaml, +noyaml
+
+ This toggles printing of the responses in a detailed YAML format.
+
+.. option:: +zflag, +nozflag
+
+ This sets [or does not set] the last unassigned DNS header flag in a DNS query.
+ This flag is off by default.
+
+See Also
+~~~~~~~~
+
+:iscman:`dig(1) <dig>`, :rfc:`1035`.
diff --git a/bin/tools/named-journalprint.c b/bin/tools/named-journalprint.c
new file mode 100644
index 0000000..402163d
--- /dev/null
+++ b/bin/tools/named-journalprint.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*! \file */
+
+#include <stdlib.h>
+
+#include <isc/commandline.h>
+#include <isc/log.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/util.h>
+
+#include <dns/journal.h>
+#include <dns/log.h>
+#include <dns/types.h>
+
+const char *progname = NULL;
+
+static void
+usage(void) {
+ fprintf(stderr, "Usage: %s [-dux] journal\n", progname);
+ exit(1);
+}
+
+/*
+ * Setup logging to use stderr.
+ */
+static isc_result_t
+setup_logging(isc_mem_t *mctx, FILE *errout, isc_log_t **logp) {
+ isc_logdestination_t destination;
+ isc_logconfig_t *logconfig = NULL;
+ isc_log_t *log = NULL;
+
+ isc_log_create(mctx, &log, &logconfig);
+ isc_log_setcontext(log);
+ dns_log_init(log);
+ dns_log_setcontext(log);
+
+ destination.file.stream = errout;
+ destination.file.name = NULL;
+ destination.file.versions = ISC_LOG_ROLLNEVER;
+ destination.file.maximum_size = 0;
+ isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC,
+ ISC_LOG_DYNAMIC, &destination, 0);
+
+ RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) ==
+ ISC_R_SUCCESS);
+
+ *logp = log;
+ return (ISC_R_SUCCESS);
+}
+
+int
+main(int argc, char **argv) {
+ char *file;
+ isc_mem_t *mctx = NULL;
+ isc_result_t result;
+ isc_log_t *lctx = NULL;
+ uint32_t flags = 0U;
+ int ch;
+ bool compact = false;
+ bool downgrade = false;
+ bool upgrade = false;
+ unsigned int serial = 0;
+ char *endp = NULL;
+
+ progname = argv[0];
+ while ((ch = isc_commandline_parse(argc, argv, "c:dux")) != -1) {
+ switch (ch) {
+ case 'c':
+ compact = true;
+ serial = strtoul(isc_commandline_argument, &endp, 0);
+ if (endp == isc_commandline_argument || *endp != 0) {
+ fprintf(stderr, "invalid serial: %s\n",
+ isc_commandline_argument);
+ exit(1);
+ }
+ break;
+ case 'd':
+ downgrade = true;
+ break;
+ case 'u':
+ upgrade = true;
+ break;
+ case 'x':
+ flags |= DNS_JOURNAL_PRINTXHDR;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ if (argc != 1) {
+ usage();
+ }
+ file = argv[0];
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(setup_logging(mctx, stderr, &lctx) == ISC_R_SUCCESS);
+
+ if (upgrade) {
+ flags = DNS_JOURNAL_COMPACTALL;
+ result = dns_journal_compact(mctx, file, 0, flags, 0);
+ } else if (downgrade) {
+ flags = DNS_JOURNAL_COMPACTALL | DNS_JOURNAL_VERSION1;
+ result = dns_journal_compact(mctx, file, 0, flags, 0);
+ } else if (compact) {
+ flags = 0;
+ result = dns_journal_compact(mctx, file, serial, flags, 0);
+ } else {
+ result = dns_journal_print(mctx, flags, file, stdout);
+ if (result == DNS_R_NOJOURNAL) {
+ fprintf(stderr, "%s\n", isc_result_totext(result));
+ }
+ }
+ isc_log_destroy(&lctx);
+ isc_mem_detach(&mctx);
+ return (result != ISC_R_SUCCESS ? 1 : 0);
+}
diff --git a/bin/tools/named-journalprint.rst b/bin/tools/named-journalprint.rst
new file mode 100644
index 0000000..9d56801
--- /dev/null
+++ b/bin/tools/named-journalprint.rst
@@ -0,0 +1,66 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: named-journalprint
+.. program:: named-journalprint
+.. _man_named-journalprint:
+
+named-journalprint - print zone journal in human-readable form
+--------------------------------------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`named-journalprint` [-c serial] [**-dux**] {journal}
+
+Description
+~~~~~~~~~~~
+
+:program:`named-journalprint` scans the contents of a zone journal file,
+printing it in a human-readable form, or, optionally, converting it
+to a different journal file format.
+
+Journal files are automatically created by :iscman:`named` when changes are
+made to dynamic zones (e.g., by :iscman:`nsupdate`). They record each addition
+or deletion of a resource record, in binary format, allowing the changes
+to be re-applied to the zone when the server is restarted after a
+shutdown or crash. By default, the name of the journal file is formed by
+appending the extension ``.jnl`` to the name of the corresponding zone
+file.
+
+:program:`named-journalprint` converts the contents of a given journal file
+into a human-readable text format. Each line begins with ``add`` or ``del``,
+to indicate whether the record was added or deleted, and continues with
+the resource record in master-file format.
+
+The ``-c`` (compact) option provides a mechanism to reduce the size of
+a journal by removing (most/all) transactions prior to the specified
+serial number. Note: this option *must not* be used while :iscman:`named` is
+running, and can cause data loss if the zone file has not been updated
+to contain the data being removed from the journal. Use with extreme caution.
+
+The ``-x`` option causes additional data about the journal file to be
+printed at the beginning of the output and before each group of changes.
+
+The ``-u`` (upgrade) and ``-d`` (downgrade) options recreate the journal
+file with a modified format version. The existing journal file is
+replaced. ``-d`` writes out the journal in the format used by
+versions of BIND up to 9.16.11; ``-u`` writes it out in the format used
+by versions since 9.16.13. (9.16.12 is omitted due to a journal-formatting
+bug in that release.) Note that these options *must not* be used while
+:iscman:`named` is running.
+
+See Also
+~~~~~~~~
+
+:iscman:`named(8) <named>`, :iscman:`nsupdate(1) <nsupdate>`, BIND 9 Administrator Reference Manual.
diff --git a/bin/tools/named-nzd2nzf.c b/bin/tools/named-nzd2nzf.c
new file mode 100644
index 0000000..630b65b
--- /dev/null
+++ b/bin/tools/named-nzd2nzf.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#ifndef HAVE_LMDB
+#error This program requires the LMDB library.
+#endif /* ifndef HAVE_LMDB */
+
+#include <lmdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <isc/print.h>
+
+#include <dns/view.h>
+
+int
+main(int argc, char *argv[]) {
+ int status;
+ const char *path;
+ MDB_env *env = NULL;
+ MDB_txn *txn = NULL;
+ MDB_cursor *cursor = NULL;
+ MDB_dbi dbi;
+ MDB_val key, data;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: named-nzd2nzf <nzd-path>\n");
+ exit(1);
+ }
+
+ path = argv[1];
+
+ status = mdb_env_create(&env);
+ if (status != MDB_SUCCESS) {
+ fprintf(stderr, "named-nzd2nzf: mdb_env_create: %s",
+ mdb_strerror(status));
+ exit(1);
+ }
+
+ status = mdb_env_open(env, path, DNS_LMDB_FLAGS, 0600);
+ if (status != MDB_SUCCESS) {
+ fprintf(stderr, "named-nzd2nzf: mdb_env_open: %s",
+ mdb_strerror(status));
+ exit(1);
+ }
+
+ status = mdb_txn_begin(env, 0, MDB_RDONLY, &txn);
+ if (status != MDB_SUCCESS) {
+ fprintf(stderr, "named-nzd2nzf: mdb_txn_begin: %s",
+ mdb_strerror(status));
+ exit(1);
+ }
+
+ status = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (status != MDB_SUCCESS) {
+ fprintf(stderr, "named-nzd2nzf: mdb_dbi_open: %s",
+ mdb_strerror(status));
+ exit(1);
+ }
+
+ status = mdb_cursor_open(txn, dbi, &cursor);
+ if (status != MDB_SUCCESS) {
+ fprintf(stderr, "named-nzd2nzf: mdb_cursor_open: %s",
+ mdb_strerror(status));
+ exit(1);
+ }
+
+ for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
+ status == MDB_SUCCESS;
+ status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
+ {
+ if (key.mv_data == NULL || key.mv_size == 0 ||
+ data.mv_data == NULL || data.mv_size == 0)
+ {
+ fprintf(stderr,
+ "named-nzd2nzf: empty column found in "
+ "database '%s'",
+ path);
+ exit(1);
+ }
+
+ /* zone zonename { config; }; */
+ printf("zone \"%.*s\" %.*s;\n", (int)key.mv_size,
+ (char *)key.mv_data, (int)data.mv_size,
+ (char *)data.mv_data);
+ }
+
+ mdb_cursor_close(cursor);
+ mdb_txn_abort(txn);
+ mdb_env_close(env);
+ exit(0);
+}
diff --git a/bin/tools/named-nzd2nzf.rst b/bin/tools/named-nzd2nzf.rst
new file mode 100644
index 0000000..9711f8d
--- /dev/null
+++ b/bin/tools/named-nzd2nzf.rst
@@ -0,0 +1,45 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: named-nzd2nzf
+.. program:: named-nzd2nzf
+.. _man_named-nzd2nzf:
+
+named-nzd2nzf - convert an NZD database to NZF text format
+----------------------------------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`named-nzd2nzf` {filename}
+
+Description
+~~~~~~~~~~~
+
+:program:`named-nzd2nzf` converts an NZD database to NZF format and prints it
+to standard output. This can be used to review the configuration of
+zones that were added to :iscman:`named` via :option:`rndc addzone`. It can also be
+used to restore the old file format when rolling back from a newer
+version of BIND to an older version.
+
+Arguments
+~~~~~~~~~
+
+.. option:: filename
+
+ This is the name of the ``.nzd`` file whose contents should be printed.
+
+See Also
+~~~~~~~~
+
+BIND 9 Administrator Reference Manual.
diff --git a/bin/tools/named-rrchecker.c b/bin/tools/named-rrchecker.c
new file mode 100644
index 0000000..4d8a318
--- /dev/null
+++ b/bin/tools/named-rrchecker.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/attributes.h>
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+
+static isc_mem_t *mctx;
+static isc_lex_t *lex;
+
+static isc_lexspecials_t specials;
+
+noreturn static void
+usage(void);
+
+static void
+usage(void) {
+ fprintf(stderr, "usage: named-rrchecker [-o origin] [-hpCPTu]\n");
+ fprintf(stderr, "\t-h: print this help message\n");
+ fprintf(stderr, "\t-o origin: set origin to be used when "
+ "interpreting the record\n");
+ fprintf(stderr, "\t-p: print the record in canonical format\n");
+ fprintf(stderr, "\t-C: list the supported class names\n");
+ fprintf(stderr, "\t-P: list the supported private type names\n");
+ fprintf(stderr, "\t-T: list the supported standard type names\n");
+ fprintf(stderr, "\t-u: print the record in unknown record format\n");
+ exit(0);
+}
+
+static void
+cleanup(void) {
+ if (lex != NULL) {
+ isc_lex_close(lex);
+ isc_lex_destroy(&lex);
+ }
+ if (mctx != NULL) {
+ isc_mem_destroy(&mctx);
+ }
+}
+
+noreturn static void
+fatal(const char *format, ...);
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fprintf(stderr, "named-rrchecker: ");
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+ cleanup();
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_token_t token;
+ isc_result_t result;
+ int c;
+ unsigned int options = 0;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ char text[256 * 1024];
+ char data[64 * 1024];
+ isc_buffer_t tbuf;
+ isc_buffer_t dbuf;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ bool doexit = false;
+ bool once = false;
+ bool print = false;
+ bool unknown = false;
+ unsigned int t;
+ char *origin = NULL;
+ dns_fixedname_t fixed;
+ dns_name_t *name = NULL;
+
+ while ((c = isc_commandline_parse(argc, argv, "ho:puCPT")) != -1) {
+ switch (c) {
+ case 'o':
+ origin = isc_commandline_argument;
+ break;
+
+ case 'p':
+ print = true;
+ break;
+
+ case 'u':
+ unknown = true;
+ break;
+
+ case 'C':
+ for (t = 1; t <= 0xfeffu; t++) {
+ if (dns_rdataclass_ismeta(t)) {
+ continue;
+ }
+ dns_rdataclass_format(t, text, sizeof(text));
+ if (strncmp(text, "CLASS", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ exit(0);
+
+ case 'P':
+ for (t = 0xff00; t <= 0xfffeu; t++) {
+ if (dns_rdatatype_ismeta(t)) {
+ continue;
+ }
+ dns_rdatatype_format(t, text, sizeof(text));
+ if (strncmp(text, "TYPE", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ doexit = true;
+ break;
+
+ case 'T':
+ for (t = 1; t <= 0xfeffu; t++) {
+ if (dns_rdatatype_ismeta(t)) {
+ continue;
+ }
+ dns_rdatatype_format(t, text, sizeof(text));
+ if (strncmp(text, "TYPE", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ doexit = true;
+ break;
+
+ case '?':
+ case 'h':
+ /* Does not return. */
+ usage();
+
+ default:
+ fprintf(stderr, "%s: unhandled option -%c\n", argv[0],
+ isc_commandline_option);
+ exit(1);
+ }
+ }
+ if (doexit) {
+ exit(0);
+ }
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS);
+
+ /*
+ * Set up to lex DNS master file.
+ */
+
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ options = ISC_LEXOPT_EOL;
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS);
+
+ if (origin != NULL) {
+ name = dns_fixedname_initname(&fixed);
+ result = dns_name_fromstring(name, origin, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_name_fromstring: %s",
+ isc_result_totext(result));
+ }
+ }
+
+ while ((result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
+ &token)) == ISC_R_SUCCESS)
+ {
+ if (token.type == isc_tokentype_eof) {
+ break;
+ }
+ if (token.type == isc_tokentype_eol) {
+ continue;
+ }
+ if (once) {
+ fatal("extra data");
+ }
+ /*
+ * Get class.
+ */
+ if (token.type == isc_tokentype_number) {
+ rdclass = (dns_rdataclass_t)token.value.as_ulong;
+ if (token.value.as_ulong > 0xffffu) {
+ fatal("class value too big %lu",
+ token.value.as_ulong);
+ }
+ if (dns_rdataclass_ismeta(rdclass)) {
+ fatal("class %lu is a meta value",
+ token.value.as_ulong);
+ }
+ } else if (token.type == isc_tokentype_string) {
+ result = dns_rdataclass_fromtext(
+ &rdclass, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_fromtext: %s",
+ isc_result_totext(result));
+ }
+ if (dns_rdataclass_ismeta(rdclass)) {
+ fatal("class %.*s(%d) is a meta value",
+ (int)token.value.as_textregion.length,
+ token.value.as_textregion.base, rdclass);
+ }
+ } else {
+ fatal("unexpected token %u", token.type);
+ }
+
+ result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
+ &token);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ if (token.type == isc_tokentype_eol) {
+ continue;
+ }
+ if (token.type == isc_tokentype_eof) {
+ break;
+ }
+
+ /*
+ * Get type.
+ */
+ if (token.type == isc_tokentype_number) {
+ rdtype = (dns_rdatatype_t)token.value.as_ulong;
+ if (token.value.as_ulong > 0xffffu) {
+ fatal("type value too big %lu",
+ token.value.as_ulong);
+ }
+ if (dns_rdatatype_ismeta(rdtype)) {
+ fatal("type %lu is a meta value",
+ token.value.as_ulong);
+ }
+ } else if (token.type == isc_tokentype_string) {
+ result = dns_rdatatype_fromtext(
+ &rdtype, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_fromtext: %s",
+ isc_result_totext(result));
+ }
+ if (dns_rdatatype_ismeta(rdtype)) {
+ fatal("type %.*s(%d) is a meta value",
+ (int)token.value.as_textregion.length,
+ token.value.as_textregion.base, rdtype);
+ }
+ } else {
+ fatal("unexpected token %u", token.type);
+ }
+
+ isc_buffer_init(&dbuf, data, sizeof(data));
+ result = dns_rdata_fromtext(&rdata, rdclass, rdtype, lex, name,
+ 0, mctx, &dbuf, NULL);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_fromtext: %s",
+ isc_result_totext(result));
+ }
+ once = true;
+ }
+ if (result != ISC_R_EOF) {
+ fatal("eof not found");
+ }
+ if (!once) {
+ fatal("no records found");
+ }
+
+ if (print) {
+ isc_buffer_init(&tbuf, text, sizeof(text));
+ result = dns_rdataclass_totext(rdclass, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_totext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdatatype_totext(rdtype, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_totext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdata_totext(&rdata, NULL, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_totext: %s",
+ isc_result_totext(result));
+ }
+
+ printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base);
+ fflush(stdout);
+ }
+
+ if (unknown) {
+ isc_buffer_init(&tbuf, text, sizeof(text));
+ result = dns_rdataclass_tounknowntext(rdclass, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_tounknowntext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdatatype_tounknowntext(rdtype, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_tounknowntext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdata_tofmttext(&rdata, NULL,
+ DNS_STYLEFLAG_UNKNOWNFORMAT, 0, 0,
+ "", &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_tofmttext: %sn",
+ isc_result_totext(result));
+ }
+
+ printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base);
+ fflush(stdout);
+ }
+
+ cleanup();
+ return (0);
+}
diff --git a/bin/tools/named-rrchecker.rst b/bin/tools/named-rrchecker.rst
new file mode 100644
index 0000000..28da236
--- /dev/null
+++ b/bin/tools/named-rrchecker.rst
@@ -0,0 +1,62 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: named-rrchecker
+.. program:: named-rrchecker
+.. _man_named-rrchecker:
+
+named-rrchecker - syntax checker for individual DNS resource records
+--------------------------------------------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`named-rrchecker` [**-h**] [**-o** origin] [**-p**] [**-u**] [**-C**] [**-T**] [**-P**]
+
+Description
+~~~~~~~~~~~
+
+:program:`named-rrchecker` reads a individual DNS resource record from standard
+input and checks whether it is syntactically correct.
+
+Options
+~~~~~~~
+
+.. option:: -h
+
+ This option prints out the help menu.
+
+.. option:: -o origin
+
+ This option specifies the origin to be used when interpreting
+ the record.
+
+.. option:: -p
+
+ This option prints out the resulting record in canonical form. If there
+ is no canonical form defined, the record is printed in unknown
+ record format.
+
+.. option:: -u
+
+ This option prints out the resulting record in unknown record form.
+
+.. option:: -C, -T, -P
+
+ These options print out the known class, standard type,
+ and private type mnemonics, respectively.
+
+See Also
+~~~~~~~~
+
+:rfc:`1034`, :rfc:`1035`, :iscman:`named(8) <named>`.
diff --git a/bin/tools/nsec3hash.c b/bin/tools/nsec3hash.c
new file mode 100644
index 0000000..a6a5ec3
--- /dev/null
+++ b/bin/tools/nsec3hash.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/attributes.h>
+#include <isc/base32.h>
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/file.h>
+#include <isc/hex.h>
+#include <isc/iterated_hash.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/types.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/nsec3.h>
+#include <dns/types.h>
+
+const char *program = "nsec3hash";
+
+noreturn static void
+fatal(const char *format, ...);
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fprintf(stderr, "%s: ", program);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+static void
+check_result(isc_result_t result, const char *message) {
+ if (result != ISC_R_SUCCESS) {
+ fatal("%s: %s", message, isc_result_totext(result));
+ }
+}
+
+static void
+usage(void) {
+ fprintf(stderr, "Usage: %s salt algorithm iterations domain\n",
+ program);
+ fprintf(stderr, " %s -r algorithm flags iterations salt domain\n",
+ program);
+ exit(1);
+}
+
+typedef void
+nsec3printer(unsigned algo, unsigned flags, unsigned iters, const char *saltstr,
+ const char *domain, const char *digest);
+
+static void
+nsec3hash(nsec3printer *nsec3print, const char *algostr, const char *flagstr,
+ const char *iterstr, const char *saltstr, const char *domain) {
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ isc_buffer_t buffer;
+ isc_region_t region;
+ isc_result_t result;
+ unsigned char hash[NSEC3_MAX_HASH_LENGTH];
+ unsigned char salt[DNS_NSEC3_SALTSIZE];
+ unsigned char text[1024];
+ unsigned int hash_alg;
+ unsigned int flags;
+ unsigned int length;
+ unsigned int iterations;
+ unsigned int salt_length;
+ const char dash[] = "-";
+
+ if (strcmp(saltstr, "-") == 0) {
+ salt_length = 0;
+ salt[0] = 0;
+ } else {
+ isc_buffer_init(&buffer, salt, sizeof(salt));
+ result = isc_hex_decodestring(saltstr, &buffer);
+ check_result(result, "isc_hex_decodestring(salt)");
+ salt_length = isc_buffer_usedlength(&buffer);
+ if (salt_length > DNS_NSEC3_SALTSIZE) {
+ fatal("salt too long");
+ }
+ if (salt_length == 0) {
+ saltstr = dash;
+ }
+ }
+ hash_alg = atoi(algostr);
+ if (hash_alg > 255U) {
+ fatal("hash algorithm too large");
+ }
+ flags = flagstr == NULL ? 0 : atoi(flagstr);
+ if (flags > 255U) {
+ fatal("flags too large");
+ }
+ iterations = atoi(iterstr);
+ if (iterations > 0xffffU) {
+ fatal("iterations to large");
+ }
+
+ name = dns_fixedname_initname(&fixed);
+ isc_buffer_constinit(&buffer, domain, strlen(domain));
+ isc_buffer_add(&buffer, strlen(domain));
+ result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL);
+ check_result(result, "dns_name_fromtext() failed");
+
+ dns_name_downcase(name, name, NULL);
+ length = isc_iterated_hash(hash, hash_alg, iterations, salt,
+ salt_length, name->ndata, name->length);
+ if (length == 0) {
+ fatal("isc_iterated_hash failed");
+ }
+ region.base = hash;
+ region.length = length;
+ isc_buffer_init(&buffer, text, sizeof(text));
+ isc_base32hexnp_totext(&region, 1, "", &buffer);
+ isc_buffer_putuint8(&buffer, '\0');
+
+ nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text);
+}
+
+static void
+nsec3hash_print(unsigned algo, unsigned flags, unsigned iters,
+ const char *saltstr, const char *domain, const char *digest) {
+ UNUSED(flags);
+ UNUSED(domain);
+
+ fprintf(stdout, "%s (salt=%s, hash=%u, iterations=%u)\n", digest,
+ saltstr, algo, iters);
+}
+
+static void
+nsec3hash_rdata_print(unsigned algo, unsigned flags, unsigned iters,
+ const char *saltstr, const char *domain,
+ const char *digest) {
+ fprintf(stdout, "%s NSEC3 %u %u %u %s %s\n", domain, algo, flags, iters,
+ saltstr, digest);
+}
+
+int
+main(int argc, char *argv[]) {
+ bool rdata_format = false;
+ int ch;
+
+ while ((ch = isc_commandline_parse(argc, argv, "-r")) != -1) {
+ switch (ch) {
+ case 'r':
+ rdata_format = true;
+ break;
+ case '-':
+ isc_commandline_index -= 1;
+ goto skip;
+ default:
+ break;
+ }
+ }
+
+skip:
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ if (rdata_format) {
+ if (argc != 5) {
+ usage();
+ }
+ nsec3hash(nsec3hash_rdata_print, argv[0], argv[1], argv[2],
+ argv[3], argv[4]);
+ } else {
+ if (argc != 4) {
+ usage();
+ }
+ nsec3hash(nsec3hash_print, argv[1], NULL, argv[2], argv[0],
+ argv[3]);
+ }
+ return (0);
+}
diff --git a/bin/tools/nsec3hash.rst b/bin/tools/nsec3hash.rst
new file mode 100644
index 0000000..43a8d64
--- /dev/null
+++ b/bin/tools/nsec3hash.rst
@@ -0,0 +1,70 @@
+.. Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+..
+.. SPDX-License-Identifier: MPL-2.0
+..
+.. This Source Code Form is subject to the terms of the Mozilla Public
+.. License, v. 2.0. If a copy of the MPL was not distributed with this
+.. file, you can obtain one at https://mozilla.org/MPL/2.0/.
+..
+.. See the COPYRIGHT file distributed with this work for additional
+.. information regarding copyright ownership.
+
+.. highlight: console
+
+.. iscman:: nsec3hash
+.. program:: nsec3hash
+.. _man_nsec3hash:
+
+nsec3hash - generate NSEC3 hash
+-------------------------------
+
+Synopsis
+~~~~~~~~
+
+:program:`nsec3hash` {salt} {algorithm} {iterations} {domain}
+
+:program:`nsec3hash` **-r** {algorithm} {flags} {iterations} {salt} {domain}
+
+Description
+~~~~~~~~~~~
+
+:program:`nsec3hash` generates an NSEC3 hash based on a set of NSEC3
+parameters. This can be used to check the validity of NSEC3 records in a
+signed zone.
+
+If this command is invoked as ``nsec3hash -r``, it takes arguments in
+order, matching the first four fields of an NSEC3 record followed by the
+domain name: ``algorithm``, ``flags``, ``iterations``, ``salt``, ``domain``. This makes it
+convenient to copy and paste a portion of an NSEC3 or NSEC3PARAM record
+into a command line to confirm the correctness of an NSEC3 hash.
+
+Arguments
+~~~~~~~~~
+
+.. option:: salt
+
+ This is the salt provided to the hash algorithm.
+
+.. option:: algorithm
+
+ This is a number indicating the hash algorithm. Currently the only supported
+ hash algorithm for NSEC3 is SHA-1, which is indicated by the number
+ 1; consequently "1" is the only useful value for this argument.
+
+.. option:: flags
+
+ This is provided for compatibility with NSEC3 record presentation format, but
+ is ignored since the flags do not affect the hash.
+
+.. option:: iterations
+
+ This is the number of additional times the hash should be performed.
+
+.. option:: domain
+
+ This is the domain name to be hashed.
+
+See Also
+~~~~~~~~
+
+BIND 9 Administrator Reference Manual, :rfc:`5155`.