diff --git a/.gitignore b/.gitignore index e86e39068b493443198ac7dee452e5b2f207bc9a..ee9ff161d613dfe741f403736fd9f3157ffeebf2 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ /src/knsupdate /src/knsec3hash /src/rosedb_tool +/src/kzonecheck # Plugin binaries /src/rosedb_tool diff --git a/src/Makefile.am b/src/Makefile.am index b018c16f18db3f3bc2b500355929db42fbe51415..6fff85e007dbbedcc324b33fd64094a532dff0e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -224,7 +224,7 @@ libknotus_la_LIBADD = libcontrib.la libknot.la if HAVE_DAEMON -sbin_PROGRAMS = knotc knotd +sbin_PROGRAMS = knotc knotd kzonecheck libexec_PROGRAMS = knot1to2 noinst_LTLIBRARIES += libknotd.la libknotus.la @@ -406,6 +406,11 @@ knotc_CPPFLAGS = $(AM_CPPFLAGS) $(libedit_CFLAGS) knotc_LDADD = libknotd.la libknotus.la $(libedit_LIBS) knot1to2_LDADD = libcontrib.la +kzonecheck_SOURCES = \ + utils/kzonecheck/main.c + +kzonecheck_LDADD = libknotd.la + #################################### # Optional Knot DNS Daemon modules # #################################### diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index fc166bbea6c015e26b767e765f344dbe63a2f91c..16b7baababffe93dd777fd63cafb1f2582ed91f6 100644 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -31,7 +31,7 @@ #include "contrib/mempattern.h" #include "contrib/wire.h" -static char *error_messages[(-ZC_ERR_UNKNOWN) + 1] = { +const char *zonechecks_error_messages[(-ZC_ERR_UNKNOWN) + 1] = { [-ZC_ERR_MISSING_SOA] = "SOA record missing in zone", [-ZC_ERR_MISSING_NS_DEL_POINT] = @@ -167,7 +167,7 @@ void err_handler_log_errors(err_handler_t *handler) return; } - const char *errmsg = error_messages[-n->error]; + const char *errmsg = zonechecks_error_messages[-n->error]; log_zone_str_warning(n->zone_name, "semantic check, node '%s' (%s%s%s)", n->name ? n->name : "", diff --git a/src/knot/zone/semantic-check.h b/src/knot/zone/semantic-check.h index 8ea675cf8af59418ef64fbcd876bbcc3f61775d0..1ea6c106d0dc73e75547de518be9eb0d06cc2d22 100644 --- a/src/knot/zone/semantic-check.h +++ b/src/knot/zone/semantic-check.h @@ -97,9 +97,11 @@ enum zonechecks_errors { ZC_ERR_GLUE_RECORD, ZC_ERR_GLUE_GENERAL_ERROR, /* GLUE error delimiter. */ - /// \TODO ADD LAST DELIMITER + ZC_ERR_LAST = ZC_ERR_GLUE_GENERAL_ERROR, }; +extern const char *zonechecks_error_messages[]; + /*! * \brief Structure for handling semantic errors. */ diff --git a/src/utils/kzonecheck/main.c b/src/utils/kzonecheck/main.c new file mode 100644 index 0000000000000000000000000000000000000000..98236e0c78048086db1a5eaa3fdf6d13d3a99f00 --- /dev/null +++ b/src/utils/kzonecheck/main.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <unistd.h> +#include <getopt.h> +#include <stdio.h> + +#include "libknot/libknot.h" +#include "knot/zone/contents.h" +#include "knot/zone/zonefile.h" +#include "contrib/ucw/lists.h" +#include "utils/common/params.h" +#include "knot/common/log.h" + + +#define PROGRAM_NAME "kzonecheck" + +static void print_help(void) +{ + printf("Usage: %s [parameters] <action> [action_args]\n" + "\n" + "Parameters:\n" + " -o, --origin <zone origin> blabla\n" + " (default blabla)\n" + " -v, --verbose Enable debug output.\n" + " -h, --help Print the program help.\n" + " -V, --version Print the program version.\n" + "\n" + "Actions:\n", + PROGRAM_NAME); +} + +void print_errors(err_handler_t *handler) +{ + err_node_t *n; + WALK_LIST(n, handler->error_list) { + if (n->error > (int)ZC_ERR_GLUE_RECORD) { + fprintf(stderr, "zone: [%s], semantic check, unknown error\n", + n->zone_name ? n->zone_name : "?"); + return; + } + + const char *errmsg = zonechecks_error_messages[-n->error]; + + fprintf(stderr ,"node: '%s' (%s%s%s)\n", + n->name ? n->name : "?", + errmsg ? errmsg : "unknown error", + n->data ? " " : "", + n->data ? n->data : ""); + } +} + +void print_statistics(err_handler_t *handler) +{ + fprintf(stderr, "\nERRORS SUMMARY:\n\tCount\tError\n"); + for(int i = ZC_ERR_UNKNOWN; i < ZC_ERR_LAST; ++i) { + if (handler->errors[-i] > 0) { + fprintf(stderr, "\t%u\t%s\n", handler->errors[-i], zonechecks_error_messages[-i]); + } + } +} + +int zone_check(const char *zone_file, const knot_dname_t *zone_name) +{ + zloader_t zl; + int ret = zonefile_open(&zl, zone_file, zone_name, true); + if (ret != KNOT_EOK) { + return ret; + } + + zl.creator->master = true; + + zone_contents_t *contents; + contents = zonefile_load(&zl); + + print_errors(&zl.err_handler); + print_statistics(&zl.err_handler); + + zonefile_close(&zl); + if (contents == NULL) { + return KNOT_ERROR; + } + + zone_contents_deep_free(&contents); + + return KNOT_EOK; +} + + +int main(int argc, char *argv[]) +{ + char *filename; + char *zonename = ""; + bool verbose = false; + + /* Long options. */ + struct option opts[] = { + { "origin", required_argument, NULL, 'o' }, + { "verbose", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { NULL } + }; + + /* Parse command line arguments */ + int opt = 0, li = 0; + while ((opt = getopt_long(argc, argv, "o:vVh", opts, &li)) != -1) { + switch (opt) { + case 'o': + zonename = optarg; + break; + case 'v': + verbose = true; + break; + case 'h': + print_help(); + return EXIT_SUCCESS; + case 'V': + print_version(PROGRAM_NAME); + return EXIT_SUCCESS; + default: + print_help(); + return EXIT_FAILURE; + } + } + + /* Check if there's at least one remaining non-option. */ + if (optind >= argc) { + fprintf(stderr, "Expected argument after options\n"); + print_help(); + return EXIT_FAILURE; + } + filename = argv[optind]; + + + /* Set up simplified logging just to stdout/stderr. */ + log_init(); + log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_INFO) | LOG_MASK(LOG_NOTICE)); + log_levels_set(LOGT_STDERR, LOG_ANY, LOG_UPTO(LOG_WARNING)); + log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); + log_flag_set(LOG_FNO_TIMESTAMP | LOG_FNO_INFO); + if (verbose) { + log_levels_add(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG)); + } + + knot_dname_t *dname = knot_dname_from_str_alloc(zonename); + + int ret = zone_check(filename, dname); + + printf("%d", ret); + + free(dname); + + return ret; +}