summaryrefslogtreecommitdiffstats
path: root/bin/tools/named-rrchecker.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/tools/named-rrchecker.c')
-rw-r--r--bin/tools/named-rrchecker.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/bin/tools/named-rrchecker.c b/bin/tools/named-rrchecker.c
new file mode 100644
index 0000000..4d8a318
--- /dev/null
+++ b/bin/tools/named-rrchecker.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <isc/attributes.h>
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/print.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/fixedname.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+
+static isc_mem_t *mctx;
+static isc_lex_t *lex;
+
+static isc_lexspecials_t specials;
+
+noreturn static void
+usage(void);
+
+static void
+usage(void) {
+ fprintf(stderr, "usage: named-rrchecker [-o origin] [-hpCPTu]\n");
+ fprintf(stderr, "\t-h: print this help message\n");
+ fprintf(stderr, "\t-o origin: set origin to be used when "
+ "interpreting the record\n");
+ fprintf(stderr, "\t-p: print the record in canonical format\n");
+ fprintf(stderr, "\t-C: list the supported class names\n");
+ fprintf(stderr, "\t-P: list the supported private type names\n");
+ fprintf(stderr, "\t-T: list the supported standard type names\n");
+ fprintf(stderr, "\t-u: print the record in unknown record format\n");
+ exit(0);
+}
+
+static void
+cleanup(void) {
+ if (lex != NULL) {
+ isc_lex_close(lex);
+ isc_lex_destroy(&lex);
+ }
+ if (mctx != NULL) {
+ isc_mem_destroy(&mctx);
+ }
+}
+
+noreturn static void
+fatal(const char *format, ...);
+
+static void
+fatal(const char *format, ...) {
+ va_list args;
+
+ fprintf(stderr, "named-rrchecker: ");
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fputc('\n', stderr);
+ cleanup();
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ isc_token_t token;
+ isc_result_t result;
+ int c;
+ unsigned int options = 0;
+ dns_rdatatype_t rdtype;
+ dns_rdataclass_t rdclass;
+ char text[256 * 1024];
+ char data[64 * 1024];
+ isc_buffer_t tbuf;
+ isc_buffer_t dbuf;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ bool doexit = false;
+ bool once = false;
+ bool print = false;
+ bool unknown = false;
+ unsigned int t;
+ char *origin = NULL;
+ dns_fixedname_t fixed;
+ dns_name_t *name = NULL;
+
+ while ((c = isc_commandline_parse(argc, argv, "ho:puCPT")) != -1) {
+ switch (c) {
+ case 'o':
+ origin = isc_commandline_argument;
+ break;
+
+ case 'p':
+ print = true;
+ break;
+
+ case 'u':
+ unknown = true;
+ break;
+
+ case 'C':
+ for (t = 1; t <= 0xfeffu; t++) {
+ if (dns_rdataclass_ismeta(t)) {
+ continue;
+ }
+ dns_rdataclass_format(t, text, sizeof(text));
+ if (strncmp(text, "CLASS", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ exit(0);
+
+ case 'P':
+ for (t = 0xff00; t <= 0xfffeu; t++) {
+ if (dns_rdatatype_ismeta(t)) {
+ continue;
+ }
+ dns_rdatatype_format(t, text, sizeof(text));
+ if (strncmp(text, "TYPE", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ doexit = true;
+ break;
+
+ case 'T':
+ for (t = 1; t <= 0xfeffu; t++) {
+ if (dns_rdatatype_ismeta(t)) {
+ continue;
+ }
+ dns_rdatatype_format(t, text, sizeof(text));
+ if (strncmp(text, "TYPE", 4) != 0) {
+ fprintf(stdout, "%s\n", text);
+ }
+ }
+ doexit = true;
+ break;
+
+ case '?':
+ case 'h':
+ /* Does not return. */
+ usage();
+
+ default:
+ fprintf(stderr, "%s: unhandled option -%c\n", argv[0],
+ isc_commandline_option);
+ exit(1);
+ }
+ }
+ if (doexit) {
+ exit(0);
+ }
+
+ isc_mem_create(&mctx);
+ RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS);
+
+ /*
+ * Set up to lex DNS master file.
+ */
+
+ specials['('] = 1;
+ specials[')'] = 1;
+ specials['"'] = 1;
+ isc_lex_setspecials(lex, specials);
+ options = ISC_LEXOPT_EOL;
+ isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
+
+ RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS);
+
+ if (origin != NULL) {
+ name = dns_fixedname_initname(&fixed);
+ result = dns_name_fromstring(name, origin, 0, NULL);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_name_fromstring: %s",
+ isc_result_totext(result));
+ }
+ }
+
+ while ((result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
+ &token)) == ISC_R_SUCCESS)
+ {
+ if (token.type == isc_tokentype_eof) {
+ break;
+ }
+ if (token.type == isc_tokentype_eol) {
+ continue;
+ }
+ if (once) {
+ fatal("extra data");
+ }
+ /*
+ * Get class.
+ */
+ if (token.type == isc_tokentype_number) {
+ rdclass = (dns_rdataclass_t)token.value.as_ulong;
+ if (token.value.as_ulong > 0xffffu) {
+ fatal("class value too big %lu",
+ token.value.as_ulong);
+ }
+ if (dns_rdataclass_ismeta(rdclass)) {
+ fatal("class %lu is a meta value",
+ token.value.as_ulong);
+ }
+ } else if (token.type == isc_tokentype_string) {
+ result = dns_rdataclass_fromtext(
+ &rdclass, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_fromtext: %s",
+ isc_result_totext(result));
+ }
+ if (dns_rdataclass_ismeta(rdclass)) {
+ fatal("class %.*s(%d) is a meta value",
+ (int)token.value.as_textregion.length,
+ token.value.as_textregion.base, rdclass);
+ }
+ } else {
+ fatal("unexpected token %u", token.type);
+ }
+
+ result = isc_lex_gettoken(lex, options | ISC_LEXOPT_NUMBER,
+ &token);
+ if (result != ISC_R_SUCCESS) {
+ break;
+ }
+ if (token.type == isc_tokentype_eol) {
+ continue;
+ }
+ if (token.type == isc_tokentype_eof) {
+ break;
+ }
+
+ /*
+ * Get type.
+ */
+ if (token.type == isc_tokentype_number) {
+ rdtype = (dns_rdatatype_t)token.value.as_ulong;
+ if (token.value.as_ulong > 0xffffu) {
+ fatal("type value too big %lu",
+ token.value.as_ulong);
+ }
+ if (dns_rdatatype_ismeta(rdtype)) {
+ fatal("type %lu is a meta value",
+ token.value.as_ulong);
+ }
+ } else if (token.type == isc_tokentype_string) {
+ result = dns_rdatatype_fromtext(
+ &rdtype, &token.value.as_textregion);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_fromtext: %s",
+ isc_result_totext(result));
+ }
+ if (dns_rdatatype_ismeta(rdtype)) {
+ fatal("type %.*s(%d) is a meta value",
+ (int)token.value.as_textregion.length,
+ token.value.as_textregion.base, rdtype);
+ }
+ } else {
+ fatal("unexpected token %u", token.type);
+ }
+
+ isc_buffer_init(&dbuf, data, sizeof(data));
+ result = dns_rdata_fromtext(&rdata, rdclass, rdtype, lex, name,
+ 0, mctx, &dbuf, NULL);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_fromtext: %s",
+ isc_result_totext(result));
+ }
+ once = true;
+ }
+ if (result != ISC_R_EOF) {
+ fatal("eof not found");
+ }
+ if (!once) {
+ fatal("no records found");
+ }
+
+ if (print) {
+ isc_buffer_init(&tbuf, text, sizeof(text));
+ result = dns_rdataclass_totext(rdclass, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_totext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdatatype_totext(rdtype, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_totext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdata_totext(&rdata, NULL, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_totext: %s",
+ isc_result_totext(result));
+ }
+
+ printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base);
+ fflush(stdout);
+ }
+
+ if (unknown) {
+ isc_buffer_init(&tbuf, text, sizeof(text));
+ result = dns_rdataclass_tounknowntext(rdclass, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdataclass_tounknowntext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdatatype_tounknowntext(rdtype, &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdatatype_tounknowntext: %s",
+ isc_result_totext(result));
+ }
+ isc_buffer_putstr(&tbuf, "\t");
+ result = dns_rdata_tofmttext(&rdata, NULL,
+ DNS_STYLEFLAG_UNKNOWNFORMAT, 0, 0,
+ "", &tbuf);
+ if (result != ISC_R_SUCCESS) {
+ fatal("dns_rdata_tofmttext: %sn",
+ isc_result_totext(result));
+ }
+
+ printf("%.*s\n", (int)tbuf.used, (char *)tbuf.base);
+ fflush(stdout);
+ }
+
+ cleanup();
+ return (0);
+}