diff options
Diffstat (limited to 'bin/tools/named-rrchecker.c')
-rw-r--r-- | bin/tools/named-rrchecker.c | 346 |
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); +} |