diff options
Diffstat (limited to '')
-rw-r--r-- | bin/tools/Makefile.am | 58 | ||||
-rw-r--r-- | bin/tools/Makefile.in | 968 | ||||
-rw-r--r-- | bin/tools/arpaname.c | 48 | ||||
-rw-r--r-- | bin/tools/arpaname.rst | 35 | ||||
-rw-r--r-- | bin/tools/dnstap-read.c | 428 | ||||
-rw-r--r-- | bin/tools/dnstap-read.rst | 58 | ||||
-rw-r--r-- | bin/tools/mdig.c | 2249 | ||||
-rw-r--r-- | bin/tools/mdig.rst | 375 | ||||
-rw-r--r-- | bin/tools/named-journalprint.c | 134 | ||||
-rw-r--r-- | bin/tools/named-journalprint.rst | 66 | ||||
-rw-r--r-- | bin/tools/named-nzd2nzf.c | 102 | ||||
-rw-r--r-- | bin/tools/named-nzd2nzf.rst | 45 | ||||
-rw-r--r-- | bin/tools/named-rrchecker.c | 346 | ||||
-rw-r--r-- | bin/tools/named-rrchecker.rst | 62 | ||||
-rw-r--r-- | bin/tools/nsec3hash.c | 194 | ||||
-rw-r--r-- | bin/tools/nsec3hash.rst | 70 |
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(®ion, 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`. |