mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-02-03 18:49:28 -05:00
246 lines
5.3 KiB
C
246 lines
5.3 KiB
C
/* Copyright (C) CZ.NIC, z.s.p.o. and contributors
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* For more information, see <https://www.knot-dns.cz/>
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <pthread.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "libzscanner/processing.h"
|
|
#include "libzscanner/scanner.h"
|
|
|
|
#define DEFAULT_MODE 1
|
|
#define DEFAULT_CLASS 1
|
|
#define DEFAULT_TTL 0
|
|
|
|
static void *timestamp_worker(void *data)
|
|
{
|
|
int *ret = (int *)data;
|
|
*ret = test_date_to_timestamp();
|
|
return NULL;
|
|
}
|
|
|
|
static void help(void)
|
|
{
|
|
printf("\nZone scanner testing tool.\n"
|
|
"Usage: zscanner-tool [parameters] origin zonefile\n"
|
|
"\n"
|
|
"Parameters:\n"
|
|
" -m [0,1,2] Processing mode.\n"
|
|
" 0 Empty output.\n"
|
|
" 1 Debug output (DEFAULT).\n"
|
|
" 2 Test output.\n"
|
|
" -b <num> Divide hex string to blocks of length <num>.\n"
|
|
" -s State parsing mode.\n"
|
|
" -t Launch unit tests.\n"
|
|
" -h Print this help.\n");
|
|
}
|
|
|
|
static int time_test(void)
|
|
{
|
|
pthread_t t1, t2, t3;
|
|
int ret1, ret2, ret3;
|
|
|
|
pthread_create(&t1, NULL, timestamp_worker, &ret1);
|
|
pthread_create(&t2, NULL, timestamp_worker, &ret2);
|
|
pthread_create(&t3, NULL, timestamp_worker, &ret3);
|
|
|
|
pthread_join(t1, NULL);
|
|
pthread_join(t2, NULL);
|
|
pthread_join(t3, NULL);
|
|
|
|
if (ret1 != 0 || ret2 != 0 || ret3 != 0) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
static int include(zs_scanner_t *s);
|
|
|
|
static int state_parsing(zs_scanner_t *s)
|
|
{
|
|
while (zs_parse_record(s) == 0) {
|
|
switch (s->state) {
|
|
case ZS_STATE_DATA:
|
|
if (s->process.record != NULL) {
|
|
s->process.record(s);
|
|
}
|
|
break;
|
|
case ZS_STATE_ERROR:
|
|
if (s->process.error != NULL) {
|
|
s->process.error(s);
|
|
}
|
|
if (s->error.fatal) {
|
|
return -1;
|
|
}
|
|
break;
|
|
case ZS_STATE_INCLUDE:
|
|
if (include(s) != 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
return (s->error.counter == 0) ? 0 : -1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int include(zs_scanner_t *s)
|
|
{
|
|
zs_scanner_t *ss;
|
|
int ret = 0;
|
|
|
|
if ((ss = malloc(sizeof(zs_scanner_t))) == NULL ||
|
|
zs_init(ss, (char *)s->buffer, s->default_class, s->default_ttl) != 0 ||
|
|
zs_set_input_file(ss, (char *)(s->include_filename)) != 0 ||
|
|
zs_set_processing(ss, s->process.record, s->process.error, s->process.data) != 0 ||
|
|
state_parsing(ss) != 0) {
|
|
if (ss == NULL) {
|
|
s->error.code = ZS_ENOMEM;
|
|
} else if (ss->error.counter > 0) {
|
|
s->error.counter += ss->error.counter;
|
|
s->error.code = ZS_UNPROCESSED_INCLUDE;
|
|
} else {
|
|
s->error.code = ss->error.code;
|
|
}
|
|
|
|
if (s->process.error != NULL) {
|
|
s->buffer[0] = '\0'; // Clear unrelated content.
|
|
s->buffer_length = 0;
|
|
s->error.counter++;
|
|
s->error.fatal = true;
|
|
s->process.error(s);
|
|
}
|
|
|
|
ret = -1;
|
|
}
|
|
|
|
zs_deinit(ss);
|
|
free(ss);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int mode = DEFAULT_MODE, block = 0, state = 0, test = 0;
|
|
|
|
// Command line long options.
|
|
struct option opts[] = {
|
|
{ "mode", required_argument, NULL, 'm' },
|
|
{ "block", required_argument, NULL, 'b' },
|
|
{ "state", no_argument, NULL, 's' },
|
|
{ "test", no_argument, NULL, 't' },
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ NULL }
|
|
};
|
|
|
|
// Parsed command line arguments.
|
|
int opt = 0, li = 0;
|
|
while ((opt = getopt_long(argc, argv, "m:b:sth", opts, &li)) != -1) {
|
|
switch (opt) {
|
|
case 'm':
|
|
mode = atoi(optarg);
|
|
break;
|
|
case 'b':
|
|
block = atoi(optarg);
|
|
break;
|
|
case 's':
|
|
state = 1;
|
|
break;
|
|
case 't':
|
|
test = 1;
|
|
break;
|
|
case 'h':
|
|
help();
|
|
return EXIT_SUCCESS;
|
|
default:
|
|
help();
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
if (test == 1) {
|
|
return time_test();
|
|
}
|
|
|
|
// Check if there are 2 remaining non-options.
|
|
if (argc - optind != 2) {
|
|
help();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
const char *origin = argv[optind];
|
|
const char *zone_file = argv[optind + 1];
|
|
|
|
// Create a zone scanner.
|
|
zs_scanner_t *s = malloc(sizeof(zs_scanner_t));
|
|
if (s == NULL) {
|
|
printf("Scanner create error!\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (zs_init(s, origin, DEFAULT_CLASS, DEFAULT_TTL) != 0) {
|
|
printf("Scanner init error!\n");
|
|
free(s);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (zs_set_input_file(s, zone_file) != 0) {
|
|
printf("Scanner file error!\n");
|
|
zs_deinit(s);
|
|
free(s);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
// Set the processing mode.
|
|
int ret;
|
|
switch (mode) {
|
|
case 0:
|
|
ret = 0;
|
|
break;
|
|
case 1:
|
|
ret = zs_set_processing(s, debug_process_record, debug_process_error, &block);
|
|
ret += zs_set_processing_comment(s, debug_process_comment);
|
|
break;
|
|
case 2:
|
|
ret = zs_set_processing(s, test_process_record, test_process_error, NULL);
|
|
break;
|
|
default:
|
|
printf("Bad mode number!\n");
|
|
help();
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (ret != 0) {
|
|
printf("Processing setup error!\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
// Parse the file.
|
|
ret = state ? state_parsing(s) : zs_parse_all(s);
|
|
if (ret == 0) {
|
|
if (mode == DEFAULT_MODE) {
|
|
printf("Zone file has been processed successfully\n");
|
|
}
|
|
|
|
zs_deinit(s);
|
|
free(s);
|
|
return EXIT_SUCCESS;
|
|
} else {
|
|
if (s->error.counter > 0 && mode == DEFAULT_MODE) {
|
|
printf("Zone processing has stopped with "
|
|
"%"PRIu64" warnings/errors!\n",
|
|
s->error.counter);
|
|
} else if (mode == DEFAULT_MODE) {
|
|
printf("%s\n", zs_strerror(s->error.code));
|
|
}
|
|
|
|
zs_deinit(s);
|
|
free(s);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|