From 45d6379135504814ab723b57f0eb8be23393a51d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 09:24:22 +0200 Subject: Adding upstream version 1:9.16.44. Signed-off-by: Daniel Baumann --- bin/tools/Makefile.in | 136 ++ bin/tools/arpaname.c | 48 + bin/tools/arpaname.rst | 33 + bin/tools/dnstap-read.c | 429 +++++ bin/tools/dnstap-read.rst | 52 + bin/tools/mdig.c | 2285 +++++++++++++++++++++++ bin/tools/mdig.rst | 322 ++++ bin/tools/named-journalprint.c | 134 ++ bin/tools/named-journalprint.rst | 64 + bin/tools/named-nzd2nzf.c | 103 + bin/tools/named-nzd2nzf.rst | 42 + bin/tools/named-rrchecker.c | 335 ++++ bin/tools/named-rrchecker.rst | 55 + bin/tools/nsec3hash.c | 193 ++ bin/tools/nsec3hash.rst | 63 + bin/tools/win32/arpaname.vcxproj.filters.in | 22 + bin/tools/win32/arpaname.vcxproj.in | 119 ++ bin/tools/win32/arpaname.vcxproj.user | 3 + bin/tools/win32/journalprint.vcxproj.filters.in | 18 + bin/tools/win32/journalprint.vcxproj.in | 121 ++ bin/tools/win32/journalprint.vcxproj.user | 3 + bin/tools/win32/mdig.vcxproj.filters.in | 18 + bin/tools/win32/mdig.vcxproj.in | 119 ++ bin/tools/win32/mdig.vcxproj.user | 3 + bin/tools/win32/nsec3hash.vcxproj.filters.in | 18 + bin/tools/win32/nsec3hash.vcxproj.in | 119 ++ bin/tools/win32/nsec3hash.vcxproj.user | 3 + bin/tools/win32/rrchecker.vcxproj.filters.in | 18 + bin/tools/win32/rrchecker.vcxproj.in | 121 ++ bin/tools/win32/rrchecker.vcxproj.user | 3 + 30 files changed, 5002 insertions(+) create mode 100644 bin/tools/Makefile.in create mode 100644 bin/tools/arpaname.c create mode 100644 bin/tools/arpaname.rst create mode 100644 bin/tools/dnstap-read.c create mode 100644 bin/tools/dnstap-read.rst create mode 100644 bin/tools/mdig.c create mode 100644 bin/tools/mdig.rst create mode 100644 bin/tools/named-journalprint.c create mode 100644 bin/tools/named-journalprint.rst create mode 100644 bin/tools/named-nzd2nzf.c create mode 100644 bin/tools/named-nzd2nzf.rst create mode 100644 bin/tools/named-rrchecker.c create mode 100644 bin/tools/named-rrchecker.rst create mode 100644 bin/tools/nsec3hash.c create mode 100644 bin/tools/nsec3hash.rst create mode 100644 bin/tools/win32/arpaname.vcxproj.filters.in create mode 100644 bin/tools/win32/arpaname.vcxproj.in create mode 100644 bin/tools/win32/arpaname.vcxproj.user create mode 100644 bin/tools/win32/journalprint.vcxproj.filters.in create mode 100644 bin/tools/win32/journalprint.vcxproj.in create mode 100644 bin/tools/win32/journalprint.vcxproj.user create mode 100644 bin/tools/win32/mdig.vcxproj.filters.in create mode 100644 bin/tools/win32/mdig.vcxproj.in create mode 100644 bin/tools/win32/mdig.vcxproj.user create mode 100644 bin/tools/win32/nsec3hash.vcxproj.filters.in create mode 100644 bin/tools/win32/nsec3hash.vcxproj.in create mode 100644 bin/tools/win32/nsec3hash.vcxproj.user create mode 100644 bin/tools/win32/rrchecker.vcxproj.filters.in create mode 100644 bin/tools/win32/rrchecker.vcxproj.in create mode 100644 bin/tools/win32/rrchecker.vcxproj.user (limited to 'bin/tools') diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in new file mode 100644 index 0000000..8c22340 --- /dev/null +++ b/bin/tools/Makefile.in @@ -0,0 +1,136 @@ +# 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. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ${ISCCFG_INCLUDES} \ + ${BIND9_INCLUDES} \ + ${LMDB_CFLAGS} ${OPENSSL_CFLAGS} \ + ${PROTOBUF_C_CFLAGS} \ + ${MAXMINDDB_CFLAGS} \ + ${LMDB_CFLAGS} + +CDEFINES = -DVERSION=\"${VERSION}\" +CWARNINGS = + +DNSLIBS = ../../lib/dns/libdns.@A@ @NO_LIBTOOL_DNSLIBS@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ @NO_LIBTOOL_ISCLIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ + +LIBS = ${ISCLIBS} @LIBS@ +NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@ + +SUBDIRS = + +DNSTAPTARGETS = dnstap-read@EXEEXT@ +NZDTARGETS = named-nzd2nzf@EXEEXT@ +TARGETS = arpaname@EXEEXT@ named-journalprint@EXEEXT@ \ + named-rrchecker@EXEEXT@ nsec3hash@EXEEXT@ \ + mdig@EXEEXT@ \ + @DNSTAPTARGETS@ @NZDTARGETS@ + +DNSTAPSRCS = dnstap-read.c +NZDSRCS = named-nzd2nzf.c +SRCS = arpaname.c named-journalprint.c named-rrchecker.c \ + nsec3hash.c mdig.c \ + @DNSTAPSRCS@ @NZDSRCS@ + +@BIND9_MAKE_RULES@ + +arpaname@EXEEXT@: arpaname.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} \ + -o $@ arpaname.@O@ ${ISCLIBS} ${LIBS} + +named-journalprint@EXEEXT@: named-journalprint.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + export BASEOBJS="named-journalprint.@O@"; \ + export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + +named-rrchecker@EXEEXT@: named-rrchecker.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + export BASEOBJS="named-rrchecker.@O@"; \ + export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + +nsec3hash@EXEEXT@: nsec3hash.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + export BASEOBJS="nsec3hash.@O@"; \ + export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + +mdig@EXEEXT@: mdig.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCCFGDEPLIBS} + export BASEOBJS="mdig.@O@"; \ + export LIBS0="${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + ${FINALBUILDCMD} + +dnstap-read@EXEEXT@: dnstap-read.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + export BASEOBJS="dnstap-read.@O@"; \ + export LIBS0="${DNSLIBS} ${PROTOBUF_C_LIBS}"; \ + ${FINALBUILDCMD} + +named-nzd2nzf@EXEEXT@: named-nzd2nzf.@O@ ${ISCDEPLIBS} + export BASEOBJS="named-nzd2nzf.@O@"; \ + export LIBS0="${LMDB_LIBS}"; \ + ${FINALBUILDCMD} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${bindir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + +nzd: + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-nzd2nzf@EXEEXT@ \ + ${DESTDIR}${sbindir} + +dnstap: + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} dnstap-read@EXEEXT@ \ + ${DESTDIR}${bindir} + +install:: ${TARGETS} installdirs @DNSTAP@ @NZD_TOOLS@ + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} arpaname@EXEEXT@ \ + ${DESTDIR}${bindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-journalprint@EXEEXT@ \ + ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-rrchecker@EXEEXT@ \ + ${DESTDIR}${bindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} nsec3hash@EXEEXT@ \ + ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} mdig@EXEEXT@ \ + ${DESTDIR}${bindir} + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${bindir}/mdig@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${sbindir}/nsec3hash@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${bindir}/named-rrchecker@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${sbindir}/named-journalprint@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${bindir}/arpaname@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${bindir}/dnstap-read@EXEEXT@ + ${LIBTOOL_MODE_UNINSTALL} rm -f \ + ${DESTDIR}${sbindir}/named-nzd2nzf@EXEEXT@ + +clean distclean:: + rm -f ${TARGETS} 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 + +#include +#include + +#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..c932f6e --- /dev/null +++ b/bin/tools/arpaname.rst @@ -0,0 +1,33 @@ +.. 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 + +.. _man_arpaname: + +arpaname - translate IP addresses to the corresponding ARPA names +----------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`arpaname` {*ipaddress* ...} + +Description +~~~~~~~~~~~ + +``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..50985d4 --- /dev/null +++ b/bin/tools/dnstap-read.c @@ -0,0 +1,429 @@ +/* + * 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 +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "lib/dns/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) + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST; + +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); + + dns_result_register(); + + 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..104c05f --- /dev/null +++ b/bin/tools/dnstap-read.rst @@ -0,0 +1,52 @@ +.. 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 + +.. _man_dnstap-read: + +dnstap-read - print dnstap data in human-readable form +------------------------------------------------------ + +Synopsis +~~~~~~~~ + +:program:`dnstap-read` [**-m**] [**-p**] [**-x**] [**-y**] {file} + +Description +~~~~~~~~~~~ + +``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 ``-y`` option is specified, a +longer and more detailed YAML format is used. + +Options +~~~~~~~ + +``-m`` + This option indicates trace memory allocations, and is used for debugging memory leaks. + +``-p`` + This option prints the text form of the DNS + message that was encapsulated in the ``dnstap`` frame, after printing the ``dnstap`` data. + +``-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. + +``-y`` + This option prints ``dnstap`` data in a detailed YAML format. + +See Also +~~~~~~~~ + +:manpage:`named(8)`, :manpage:`rndc(8)`, BIND 9 Administrator Reference Manual. diff --git a/bin/tools/mdig.c b/bin/tools/mdig.c new file mode 100644 index 0000000..5da9d89 --- /dev/null +++ b/bin/tools/mdig.c @@ -0,0 +1,2285 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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 + +#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ +#define US_PER_SEC 1000000 /*%< Microseconds per second. */ +#define US_PER_MS 1000 /*%< Microseconds per millisecond. */ + +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 isc_dscp_t dscp = -1; +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 = 4096; + } + 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 | DNS_REQUESTOPT_SHARE; + } + request = NULL; + result = dns_request_createvia( + requestmgr, message, have_src ? &srcaddr : NULL, &dstaddr, dscp, + options, NULL, query->timeout, query->udptimeout, + query->udpretries, task, recvresponse, message, &request); + CHECK("dns_request_createvia4", 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; +} + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +static void +usage(void) { + fputs("Usage: mdig @server {global-opt} host\n" + " {local-opt} [ host {local-opt} [...]]\n", + stderr); + fputs("\nUse \"mdig -h\" (or \"mdig -h | more\") " + "for complete list of options\n", + stderr); + exit(1); +} + +/*% help */ +static void +help(void) { + fputs("Usage: mdig @server {global-opt} host\n" + " {local-opt} [ host {local-opt} [...]]\n", + stdout); + fputs("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]dscp[=###] (Set the DSCP value to ### " + "[0..63])\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", + stdout); +} + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) + ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; + +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 */ + FULLCHECK("dscp"); + GLOBAL(); + if (!state) { + dscp = -1; + break; + } + if (value == NULL) { + goto need_value; + } + result = parse_uint(&num, value, 0x3f, "DSCP"); + CHECK("parse_uint(DSCP)", result); + dscp = num; + 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); + query->udpretries++; + 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_() 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': + fputs("mDiG " VERSION "\n", stderr); + 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() { + 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 = 3; + 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; + isc_timermgr_t *timermgr = NULL; + isc_socketmgr_t *socketmgr = NULL; + dns_dispatchmgr_t *dispatchmgr = NULL; + unsigned int attrs, attrmask; + dns_dispatch_t *dispatchvx = NULL; + dns_view_t *view = NULL; + int ns; + unsigned int i; + + RUNCHECK(isc_app_start()); + + dns_result_register(); + + 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"); + } + + RUNCHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr)); + RUNCHECK(isc_task_create(taskmgr, 0, &task)); + RUNCHECK(isc_timermgr_create(mctx, &timermgr)); + RUNCHECK(isc_socketmgr_create(mctx, &socketmgr)); + RUNCHECK(dns_dispatchmgr_create(mctx, &dispatchmgr)); + + set_source_ports(dispatchmgr); + + attrs = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_MAKEQUERY; + + if (have_ipv4) { + isc_sockaddr_any(&bind_any); + attrs |= DNS_DISPATCHATTR_IPV4; + } else { + isc_sockaddr_any6(&bind_any); + attrs |= DNS_DISPATCHATTR_IPV6; + } + attrmask = DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP | + DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; + RUNCHECK(dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, + have_src ? &srcaddr : &bind_any, 4096, 100, + 100, 17, 19, attrs, attrmask, + &dispatchvx)); + RUNCHECK(dns_requestmgr_create( + mctx, timermgr, socketmgr, 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_destroy(&dispatchmgr); + + isc_socketmgr_destroy(&socketmgr); + isc_timermgr_destroy(&timermgr); + + isc_task_shutdown(task); + isc_task_detach(&task); + isc_managers_destroy(&netmgr, &taskmgr); + + 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..50aa588 --- /dev/null +++ b/bin/tools/mdig.rst @@ -0,0 +1,322 @@ +.. 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 + +.. _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 +~~~~~~~~~~~ + +``mdig`` is a multiple/pipelined query version of ``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. + +``mdig`` options are a subset of the ``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 ``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, +``mdig`` resolves that name before querying the name server. + +``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 +~~~~~~~~~~~~~~~~ + +``-f`` + This option makes ``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 ``mdig`` using the command-line interface. + +``-h`` + This option causes ``mdig`` to print detailed help information, with the full list + of options, and exit. + +``-v`` + This option causes ``mdig`` to print the version number and exit. + +Global Options +~~~~~~~~~~~~~~ + +``-4`` + This option forces ``mdig`` to only use IPv4 query transport. + +``-6`` + This option forces ``mdig`` to only use IPv6 query transport. + +``-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 "#" + +``-m`` + This option enables memory usage debugging. + +``-p port#`` + This option is used when a non-standard port number is to be + queried. ``port#`` is the port number that ``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: + +``+[no]additional`` + This option displays [or does not display] the additional section of a reply. The + default is to display it. + +``+[no]all`` + This option sets or clears all display flags. + +``+[no]answer`` + This option displays [or does not display] the answer section of a reply. The default + is to display it. + +``+[no]authority`` + This option displays [or does not display] the authority section of a reply. The + default is to display it. + +``+[no]besteffort`` + This option attempts to display [or does not display] the contents of messages which are malformed. The + default is to not display malformed answers. + +``+burst`` + This option delays queries until the start of the next second. + +``+[no]cl`` + This option displays [or does not display] the CLASS when printing the record. + +``+[no]comments`` + This option toggles the display of comment lines in the output. The default is to + print comments. + +``+[no]continue`` + This option toggles continuation on errors (e.g. timeouts). + +``+[no]crypto`` + 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 ]``. + +``+dscp[=value]`` + This option sets the DSCP code point to be used when sending the query. Valid DSCP + code points are in the range [0...63]. By default no code point is + explicitly set. + +``+[no]multiline`` + 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 ``mdig`` output. + +``+[no]question`` + 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. + +``+[no]rrcomments`` + 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. + +``+[no]short`` + This option provides [or does not provide] a terse answer. The default is to print the answer in a + verbose form. + +``+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. + +``+[no]tcp`` + This option uses [or does not use] TCP when querying name servers. The default behavior + is to use UDP. + +``+[no]ttlid`` + This option displays [or does not display] the TTL when printing the record. + +``+[no]ttlunits`` + 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. + +``+[no]vc`` + This option uses [or does not use] TCP when querying name servers. This alternate + syntax to ``+[no]tcp`` is provided for backwards compatibility. The + ``vc`` stands for "virtual circuit". + +Local Options +~~~~~~~~~~~~~ + +``-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". + +``-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 ``-x`` option is supplied to indicate a reverse lookup with + the "PTR" query type. + +``-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. ``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: + +``+[no]aaflag`` + This is a synonym for ``+[no]aaonly``. + +``+[no]aaonly`` + This sets the ``aa`` flag in the query. + +``+[no]adflag`` + 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. + +``+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. + +``+[no]cdflag`` + 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. + +``+[no]cookie=####`` + 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``. + +``+[no]dnssec`` + 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. + +``+[no]edns[=#]`` + 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. + +``+[no]ednsflags[=#]`` + 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. + +``+[no]ednsopt[=code[:value]]`` + 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. + +``+[no]expire`` + This toggles sending of an EDNS Expire option. + +``+[no]nsid`` + This toggles inclusion of an EDNS name server ID request when sending a query. + +``+[no]recurse`` + This toggles the setting of the RD (recursion desired) bit in the query. + This bit is set by default, which means ``mdig`` normally sends + recursive queries. + +``+retry=T`` + This sets the number of times to retry UDP queries to server to ``T`` + instead of the default, 2. Unlike ``+tries``, this does not include + the initial query. + +``+[no]subnet=addr[/prefix-length]`` + 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. + +``+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. + +``+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. + +``+udptimeout=T`` + This sets the timeout between UDP query retries to ``T``. + +``+[no]unknownformat`` + 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. + +``+[no]yaml`` + This toggles printing of the responses in a detailed YAML format. + +``+[no]zflag`` + This sets [or does not set] the last unassigned DNS header flag in a DNS query. + This flag is off by default. + +See Also +~~~~~~~~ + +:manpage:`dig(1)`, :rfc:`1035`. diff --git a/bin/tools/named-journalprint.c b/bin/tools/named-journalprint.c new file mode 100644 index 0000000..61df022 --- /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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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", dns_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..1b9b057 --- /dev/null +++ b/bin/tools/named-journalprint.rst @@ -0,0 +1,64 @@ +.. 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 + +.. _man_named-journalprint: + +named-journalprint - print zone journal in human-readable form +-------------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named-journalprint` [-c serial] [**-dux**] {journal} + +Description +~~~~~~~~~~~ + +``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 ``named`` when changes are +made to dynamic zones (e.g., by ``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. + +``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 ``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 +``named`` is running. + +See Also +~~~~~~~~ + +:manpage:`named(8)`, :manpage:`nsupdate(1)`, 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..519f6fd --- /dev/null +++ b/bin/tools/named-nzd2nzf.c @@ -0,0 +1,103 @@ +/* + * 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 +#include +#include + +#include + +#include +#include + +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 \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..d20fc36 --- /dev/null +++ b/bin/tools/named-nzd2nzf.rst @@ -0,0 +1,42 @@ +.. 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 + +.. _man_named-nzd2nzf: + +named-nzd2nzf - convert an NZD database to NZF text format +---------------------------------------------------------- + +Synopsis +~~~~~~~~ + +:program:`named-nzd2nzf` {filename} + +Description +~~~~~~~~~~~ + +``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 ``named`` via ``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 +~~~~~~~~~ + +``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..d0081ca --- /dev/null +++ b/bin/tools/named-rrchecker.c @@ -0,0 +1,335 @@ +/* + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static isc_mem_t *mctx; +static isc_lex_t *lex; + +static isc_lexspecials_t specials; + +ISC_PLATFORM_NORETURN_PRE static void +usage(void) ISC_PLATFORM_NORETURN_POST; + +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); +} + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST; + +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); + 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", + dns_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", + dns_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", + dns_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", + dns_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", + dns_result_totext(result)); + } + isc_buffer_putstr(&tbuf, "\t"); + result = dns_rdatatype_totext(rdtype, &tbuf); + if (result != ISC_R_SUCCESS) { + fatal("dns_rdatatype_totext: %s", + dns_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", + dns_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", + dns_result_totext(result)); + } + isc_buffer_putstr(&tbuf, "\t"); + result = dns_rdatatype_tounknowntext(rdtype, &tbuf); + if (result != ISC_R_SUCCESS) { + fatal("dns_rdatatype_tounknowntext: %s", + dns_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", + dns_result_totext(result)); + } + + printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base); + fflush(stdout); + } + + isc_lex_close(lex); + isc_lex_destroy(&lex); + isc_mem_destroy(&mctx); + return (0); +} diff --git a/bin/tools/named-rrchecker.rst b/bin/tools/named-rrchecker.rst new file mode 100644 index 0000000..191f229 --- /dev/null +++ b/bin/tools/named-rrchecker.rst @@ -0,0 +1,55 @@ +.. 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 + +.. _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 +~~~~~~~~~~~ + +``named-rrchecker`` reads a individual DNS resource record from standard +input and checks whether it is syntactically correct. + +Options +~~~~~~~ + +``-h`` + This option prints out the help menu. + +``-o origin`` + This option specifies the origin to be used when interpreting + the record. + +``-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. + +``-u`` + This option prints out the resulting record in unknown record form. + +``-C``, ``-T``, and ``-P`` + These options print out the known class, standard type, + and private type mnemonics, respectively. + +See Also +~~~~~~~~ + +:rfc:`1034`, :rfc:`1035`, :manpage:`named(8)`. diff --git a/bin/tools/nsec3hash.c b/bin/tools/nsec3hash.c new file mode 100644 index 0000000..2441bf1 --- /dev/null +++ b/bin/tools/nsec3hash.c @@ -0,0 +1,193 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +const char *program = "nsec3hash"; + +ISC_PLATFORM_NORETURN_PRE static void +fatal(const char *format, ...) ISC_PLATFORM_NORETURN_POST; + +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() { + 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..9b174ce --- /dev/null +++ b/bin/tools/nsec3hash.rst @@ -0,0 +1,63 @@ +.. 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 + +.. _man_nsec3hash: + +nsec3hash - generate NSEC3 hash +------------------------------- + +Synopsis +~~~~~~~~ + +:program:`nsec3hash` {salt} {algorithm} {iterations} {domain} + +:program:`nsec3hash` **-r** {algorithm} {flags} {iterations} {salt} {domain} + +Description +~~~~~~~~~~~ + +``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 +~~~~~~~~~ + +``salt`` + This is the salt provided to the hash algorithm. + +``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. + +``flags`` + This is provided for compatibility with NSEC3 record presentation format, but + is ignored since the flags do not affect the hash. + +``iterations`` + This is the number of additional times the hash should be performed. + +``domain`` + This is the domain name to be hashed. + +See Also +~~~~~~~~ + +BIND 9 Administrator Reference Manual, :rfc:`5155`. diff --git a/bin/tools/win32/arpaname.vcxproj.filters.in b/bin/tools/win32/arpaname.vcxproj.filters.in new file mode 100644 index 0000000..129b93e --- /dev/null +++ b/bin/tools/win32/arpaname.vcxproj.filters.in @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/tools/win32/arpaname.vcxproj.in b/bin/tools/win32/arpaname.vcxproj.in new file mode 100644 index 0000000..45772b2 --- /dev/null +++ b/bin/tools/win32/arpaname.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {91E60FDA-E48C-4DA0-92A2-97F963348E00} + Win32Proj + arpaname + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + true + .\$(Configuration)\$(TargetName).pch + true + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;%(AdditionalIncludeDirectories) + OnlyExplicitInline + true + .\$(Configuration)\$(TargetName).pch + false + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/tools/win32/arpaname.vcxproj.user b/bin/tools/win32/arpaname.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/tools/win32/arpaname.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/tools/win32/journalprint.vcxproj.filters.in b/bin/tools/win32/journalprint.vcxproj.filters.in new file mode 100644 index 0000000..cb89470 --- /dev/null +++ b/bin/tools/win32/journalprint.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/tools/win32/journalprint.vcxproj.in b/bin/tools/win32/journalprint.vcxproj.in new file mode 100644 index 0000000..dc610b5 --- /dev/null +++ b/bin/tools/win32/journalprint.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {B19042CE-D3D9-469B-BCD2-C3140150939A} + Win32Proj + journalprint + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(ProjectName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/tools/win32/journalprint.vcxproj.user b/bin/tools/win32/journalprint.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/tools/win32/journalprint.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/tools/win32/mdig.vcxproj.filters.in b/bin/tools/win32/mdig.vcxproj.filters.in new file mode 100644 index 0000000..fbb8ba4 --- /dev/null +++ b/bin/tools/win32/mdig.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + diff --git a/bin/tools/win32/mdig.vcxproj.in b/bin/tools/win32/mdig.vcxproj.in new file mode 100644 index 0000000..abbf682 --- /dev/null +++ b/bin/tools/win32/mdig.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {3115091C-8135-481F-9757-F013A26255E0} + Win32Proj + mdig + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;..\..\..\lib\bind9\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);..\..\..\lib\bind9\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;libbind9.lib;ws2_32.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/tools/win32/mdig.vcxproj.user b/bin/tools/win32/mdig.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/tools/win32/mdig.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/tools/win32/nsec3hash.vcxproj.filters.in b/bin/tools/win32/nsec3hash.vcxproj.filters.in new file mode 100644 index 0000000..009e970 --- /dev/null +++ b/bin/tools/win32/nsec3hash.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/bin/tools/win32/nsec3hash.vcxproj.in b/bin/tools/win32/nsec3hash.vcxproj.in new file mode 100644 index 0000000..04b7b6a --- /dev/null +++ b/bin/tools/win32/nsec3hash.vcxproj.in @@ -0,0 +1,119 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {4EE91023-94C3-48C0-B71C-5333B726C2EE} + Win32Proj + nsec3hash + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@@OPENSSL_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/tools/win32/nsec3hash.vcxproj.user b/bin/tools/win32/nsec3hash.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/tools/win32/nsec3hash.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/bin/tools/win32/rrchecker.vcxproj.filters.in b/bin/tools/win32/rrchecker.vcxproj.filters.in new file mode 100644 index 0000000..d7f077d --- /dev/null +++ b/bin/tools/win32/rrchecker.vcxproj.filters.in @@ -0,0 +1,18 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + diff --git a/bin/tools/win32/rrchecker.vcxproj.in b/bin/tools/win32/rrchecker.vcxproj.in new file mode 100644 index 0000000..b878dd7 --- /dev/null +++ b/bin/tools/win32/rrchecker.vcxproj.in @@ -0,0 +1,121 @@ + + + + + Debug + @PLATFORM@ + + + Release + @PLATFORM@ + + + + {98743A7C-6AF8-467f-9911-FA69C451AF2B} + Win32Proj + rrchecker + @WINDOWS_TARGET_PLATFORM_VERSION@ + + + + Application + true + MultiByte + @PLATFORM_TOOLSET@ + + + Application + false + true + MultiByte + @PLATFORM_TOOLSET@ + + + + + + + + + + + + + true + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + false + ..\..\..\Build\$(Configuration)\ + .\$(Configuration)\ + None + named-$(ProjectName) + + + + + + Level4 + false + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + true + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + Level1 + true + + + MaxSpeed + true + @INTRINSIC@ + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + OnlyExplicitInline + false + true + .\$(Configuration)\$(TargetName).pch + .\$(Configuration)\ + .\$(Configuration)\ + $(OutDir)$(TargetName).pdb + ..\..\..\config.h + .\;..\..\..\;@LIBXML2_INC@..\..\..\lib\isc\win32;..\..\..\lib\isc\win32\include;..\..\..\lib\isc\include;..\..\..\lib\dns\include;%(AdditionalIncludeDirectories) + CompileAsC + + + Console + false + true + true + ..\..\..\Build\$(Configuration)\$(TargetName)$(TargetExt) + Default + ..\..\..\lib\isc\win32\$(Configuration);..\..\..\lib\dns\win32\$(Configuration);%(AdditionalLibraryDirectories) + @OPENSSL_LIBCRYPTO@@OPENSSL_LIBSSL@libisc.lib;libdns.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/bin/tools/win32/rrchecker.vcxproj.user b/bin/tools/win32/rrchecker.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/bin/tools/win32/rrchecker.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file -- cgit v1.2.3