Skip to content
Snippets Groups Projects
Commit 642746c4 authored by Daniel Salzman's avatar Daniel Salzman
Browse files

knotd: merge integrity check

refs #54
parent fabc60c7
Branches
Tags
No related merge requests found
......@@ -52,7 +52,6 @@
/m4/ltsugar.m4
/m4/ltversion.m4
/m4/lt~obsolete.m4
/src/tests/unittests_xfr
/INSTALL
/src/kdig
/src/khost
......
......@@ -129,6 +129,8 @@ src/knot/stat/gatherer.h
src/knot/stat/stat-common.h
src/knot/stat/stat.c
src/knot/stat/stat.h
src/knot/zone/estimator.c
src/knot/zone/estimator.h
src/knot/zone/semantic-check.c
src/knot/zone/semantic-check.h
src/knot/zone/zone-dump.c
......@@ -239,8 +241,6 @@ src/tests/libknot/wire_tests.h
src/tests/libknot/ztree_tests.c
src/tests/libknot/ztree_tests.h
src/tests/unittests_main.c
src/tests/xfr_tests.c
src/tests/xfr_tests.h
src/tests/zscanner/zscanner_tests.c
src/tests/zscanner/zscanner_tests.h
src/utils/common/exec.c
......@@ -281,5 +281,3 @@ src/zscanner/test/processing.h
src/zscanner/test/tests.c
src/zscanner/test/tests.h
src/zscanner/test/zscanner-tool.c
src/knot/zone/estimator.c
src/knot/zone/estimator.h
......@@ -68,7 +68,7 @@ AC_PROG_INSTALL
# Check for Ragel
AC_PATH_PROG([RAGEL], [ragel], [true])
AM_CONDITIONAL([HAVE_RAGEL], test "$RAGEL" != "true")
# Set FSM type for Ragel
AC_SUBST([FSM_TYPE], [-T0])
AC_ARG_ENABLE([fastparser],
......@@ -144,6 +144,11 @@ AC_ARG_ENABLE([recvmmsg],
fi
])
# Enable integrity check
AC_ARG_ENABLE([integrity-check],
AS_HELP_STRING([--enable-integrity-check], [enable integrity check in knotd via SIGUSR1]),
[AC_DEFINE([INTEGRITY_CHECK], [1], [integrity check in knotd])])
# Check for link time optimizations support and predictive commoning
AC_ARG_ENABLE([lto],
AS_HELP_STRING([--enable-lto=yes|no], [enable link-time optimizations, enable if not broken for some extra speed [default=no]]),
......
......@@ -42,9 +42,14 @@
/* Signal flags. */
static volatile short sig_req_stop = 0;
static volatile short sig_req_reload = 0;
static volatile short sig_req_refresh = 0;
static volatile short sig_stopping = 0;
#ifdef INTEGRITY_CHECK
static volatile short sig_integrity_check = 0;
int check_iteration = 0;
char *zone = NULL;
#endif /* INTEGRITY_CHECK */
// Cleanup handler
static int do_cleanup(server_t *server, char *configf, char *pidf);
......@@ -57,12 +62,6 @@ void interrupt_handle(int s)
return;
}
// Refresh
if (s == SIGUSR2) {
sig_req_refresh = 1;
return;
}
// Stop server
if (s == SIGINT || s == SIGTERM) {
if (sig_stopping == 0) {
......@@ -72,6 +71,14 @@ void interrupt_handle(int s)
exit(1);
}
}
#ifdef INTEGRITY_CHECK
// Start zone integrity check
if (s == SIGUSR1) {
sig_integrity_check = 1;
return;
}
#endif /* INTEGRITY_CHECK */
}
void help(void)
......@@ -80,6 +87,10 @@ void help(void)
PACKAGE_NAME);
printf("\nParameters:\n"
" -c, --config [file] Select configuration file.\n"
#ifdef INTEGRITY_CHECK
" -z, --zone [zone] Set zone to check. Send SIGUSR1 to trigger\n"
" integrity check.\n"
#endif /* INTEGRITY_CHECK */
" -d, --daemonize Run server as a daemon.\n"
" -v, --verbose Verbose mode - additional runtime information.\n"
" -V, --version Print version of the server.\n"
......@@ -97,6 +108,9 @@ int main(int argc, char **argv)
/* Long options. */
struct option opts[] = {
{"config", required_argument, 0, 'c'},
#ifdef INTEGRITY_CHECK
{"zone", required_argument, 0, 'z'},
#endif /* INTEGRITY_CHECK */
{"daemonize", no_argument, 0, 'd'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
......@@ -104,7 +118,11 @@ int main(int argc, char **argv)
{0, 0, 0, 0}
};
#ifndef INTEGRITY_CHECK
while ((c = getopt_long(argc, argv, "c:dvVh", opts, &li)) != -1) {
#else
while ((c = getopt_long(argc, argv, "c:z:dvVh", opts, &li)) != -1) {
#endif /* INTEGRITY_CHECK */
switch (c)
{
case 'c':
......@@ -124,6 +142,15 @@ int main(int argc, char **argv)
free(config_fn);
help();
return 0;
#ifdef INTEGRITY_CHECK
case 'z':
if (optarg[strlen(optarg) - 1] != '.') {
zone = strcdup(optarg, ".");
} else {
zone = strdup(optarg);
}
break;
#endif /* INTEGRITY_CHECK */
default:
free(config_fn);
help();
......@@ -292,8 +319,9 @@ int main(int argc, char **argv)
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
#ifdef INTEGRITY_CHECK
sigaction(SIGUSR1, &sa, NULL);
#endif /* INTEGRITY_CHECK */
sa.sa_flags = 0;
pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
......@@ -342,17 +370,29 @@ int main(int argc, char **argv)
sig_req_reload = 0;
server_reload(server, config_fn);
}
if (sig_req_refresh) {
log_server_info("Refreshing slave zones...\n");
sig_req_reload = 0;
int cf_ret = server_refresh(server);
if (cf_ret != KNOT_EOK) {
log_server_error("Couldn't refresh "
"slave zones - %s",
knot_strerror(cf_ret));
}
#ifdef INTEGRITY_CHECK
if (zone == NULL)
sig_integrity_check = 0;
if (sig_integrity_check) {
log_server_info("Starting integrity check of "
"zone: %s\n", zone);
knot_dname_t *zdn =
knot_dname_new_from_str(zone,
strlen(zone),
NULL);
knot_zone_t *z =
knot_zonedb_find_zone(server->nameserver->zone_db,
zdn);
int ic_ret =
knot_zone_contents_integrity_check(z->contents);
log_server_info("Integrity check: %d errors "
"discovered.\n", ic_ret);
knot_dname_free(&zdn);
log_server_info("Integrity check %d finished.\n",
check_iteration);
++check_iteration;
}
#endif /* INTEGRITY_CHECK */
}
pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
......
......@@ -3,8 +3,7 @@ ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
AM_CPPFLAGS = -I$(top_srcdir)/src/libknot -I$(top_srcdir)/src -DSYSCONFDIR='"$(sysconfdir)"' -DSBINDIR='"$(sbindir)"'
check_PROGRAMS = \
unittests \
unittests_xfr
unittests
TESTS = unittests
......@@ -63,12 +62,7 @@ unittests_SOURCES = \
libknot/sign_tests.h \
unittests_main.c
unittests_xfr_SOURCES = \
xfr_tests.c \
xfr_tests.h
unittests_LDADD = ../libknotd.la ../libknots.la @LIBOBJS@
unittests_xfr_LDADD = ../libknotd.la ../libknot.la ../libknots.la @LIBOBJS@
sample_conf.rc: files/sample_conf
$(top_srcdir)/resource.sh $(srcdir)/files/sample_conf >$@
Unit testing
------------
Make assembles "unittest" binary with all of the planned tests included.
/* Copyright (C) 2011 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/>.
*/
/*
* This test is basically a copy of the whole server, with following exceptions:
* - signal handler now handles one more signal
* SIGUSR1 is used to signal this
* binary that an integrity check should be done
*/
#include <config.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <assert.h>
#include "knot/knot.h"
#include "knot/server/server.h"
#include "knot/ctl/process.h"
#include "knot/conf/conf.h"
#include "knot/conf/logconf.h"
#include "common/evqueue.h"
#include "knot/server/zones.h"
/*----------------------------------------------------------------------------*/
/* Signal flags. */
static volatile short sig_req_stop = 0;
static volatile short sig_req_reload = 0;
static volatile short sig_stopping = 0;
static volatile short sig_integrity_check = 0;
// SIGINT signal handler
void interrupt_handle(int s)
{
// Reload configuration
if (s == SIGHUP) {
sig_req_reload = 1;
return;
}
// Stop server
if (s == SIGINT || s == SIGTERM) {
if (sig_stopping == 0) {
sig_req_stop = 1;
sig_stopping = 1;
} else {
log_server_notice("OK! Exiting immediately.\n");
exit(1);
}
}
// Start zone integrity check
if (s == SIGUSR1) {
sig_integrity_check = 1;
return;
}
}
void help(int argc, char **argv)
{
printf("Usage: %sd [parameters]\n",
PACKAGE_NAME);
printf("Parameters:\n"
" -c, --config [file] Select configuration file.\n"
" -z, --zone [origin] Inspected zone origin.\n"
" -d, --daemonize Run server as a daemon.\n"
" -v, --verbose Verbose mode - additional runtime information.\n"
" -V, --version Print version of the server.\n"
" -h, --help Print help and usage.\n"
"Send SIGUSR1 to trigger integrity check.\n");
}
int main(int argc, char **argv)
{
// Parse command line arguments
int check_iteration = 0;
int c = 0, li = 0;
int verbose = 0;
int daemonize = 0;
char *config_fn = NULL;
char *zone = NULL;
/* Long options. */
struct option opts[] = {
{"config", required_argument, 0, 'c'},
{"zone", required_argument, 0, 'z'},
{"daemonize", no_argument, 0, 'd'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "c:z:dvVh", opts, &li)) != -1) {
switch (c)
{
case 'c':
config_fn = strdup(optarg);
break;
case 'd':
daemonize = 1;
break;
case 'v':
verbose = 1;
break;
case 'V':
printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
return 0;
case 'z':
if (optarg[strlen(optarg) - 1] != '.') {
zone = strcdup(optarg, ".");
} else {
zone = strdup(optarg);
}
break;
case 'h':
case '?':
default:
help(argc, argv);
return 1;
}
}
// Now check if we want to daemonize
if (daemonize) {
if (daemon(1, 0) != 0) {
free(zone);
free(config_fn);
fprintf(stderr, "Daemonization failed, "
"shutting down...\n");
return 1;
}
}
// Register service and signal handler
struct sigaction emptyset;
memset(&emptyset, 0, sizeof(struct sigaction));
emptyset.sa_handler = interrupt_handle;
sigemptyset(&emptyset.sa_mask);
emptyset.sa_flags = 0;
sigaction(SIGALRM, &emptyset, NULL); // Interrupt
// Initialize log
log_init();
// Verbose mode
if (verbose) {
int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG);
log_levels_add(LOGT_STDOUT, LOG_ANY, mask);
}
// Initialize pseudorandom number generator
srand(time(0));
// Create server
server_t *server = server_create();
// Initialize configuration
rcu_read_lock();
conf_add_hook(conf(), CONF_LOG, log_conf_hook, 0);
conf_add_hook(conf(), CONF_LOG, zones_ns_conf_hook, server->nameserver);
conf_add_hook(conf(), CONF_LOG, server_conf_hook, server);
rcu_read_unlock();
// Find implicit configuration file
if (!config_fn) {
config_fn = conf_find_default();
}
// Find absolute path for config file
if (config_fn[0] != '/')
{
// Get absolute path to cwd
size_t cwbuflen = 64;
char *cwbuf = malloc((cwbuflen + 2) * sizeof(char));
while (getcwd(cwbuf, cwbuflen) == 0) {
cwbuflen *= 2;
cwbuf = realloc(cwbuf, (cwbuflen + 2) * sizeof(char));
}
cwbuflen = strlen(cwbuf);
// Append ending slash
if (cwbuf[cwbuflen - 1] != '/') {
cwbuf = strncat(cwbuf, "/", 1);
}
// Assemble path to config file
char *abs_cfg = strcdup(cwbuf, config_fn);
free(config_fn);
free(cwbuf);
config_fn = abs_cfg;
}
// Open configuration
log_server_info("Reading configuration '%s' ...\n", config_fn);
int conf_ret = conf_open(config_fn);
if (conf_ret != KNOT_EOK) {
if (conf_ret == KNOT_ENOENT) {
log_server_error("Couldn't open configuration file "
"'%s'.\n", config_fn);
} else {
log_server_error("Failed to load configuration '%s'.\n",
config_fn);
}
server_destroy(&server);
free(config_fn);
return 1;
} else {
log_server_info("Configured %d interfaces and %d zones.\n",
conf()->ifaces_count, conf()->zones_count);
}
log_server_info("\n");
// Create server instance
char* pidfile = pid_filename();
// Run server
int res = 0;
log_server_info("Starting server...\n");
if ((res = server_start(server)) == KNOT_EOK) {
// Save PID
int has_pid = 1;
int rc = pid_write(pidfile);
if (rc < 0) {
has_pid = 0;
log_server_warning("Failed to create "
"PID file '%s'.\n", pidfile);
}
// Change directory if daemonized
if (daemonize) {
log_server_info("Server started as a daemon, "
"PID = %ld\n", (long)getpid());
res = chdir("/");
} else {
log_server_info("Server started in foreground, "
"PID = %ld\n", (long)getpid());
}
if (has_pid) {
log_server_info("PID stored in %s\n", pidfile);
} else {
log_server_warning("Server running without PID file.\n");
}
size_t zcount = server->nameserver->zone_db->zone_count;
if (!zcount) {
log_server_warning("Server started, but no zones served.\n");
}
// Setup signal handler
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = interrupt_handle;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sa.sa_flags = 0;
pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
/* Run event loop. */
evqueue_t *evq = evqueue_new();
for(;;) {
pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
int ret = evqueue_poll(evq, 0, 0);
pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
/* Interrupts. */
/*! \todo More robust way to exit evloop.
* Event loop should exit with a special
* event.
*/
if (sig_req_stop) {
sig_req_stop = 0;
server_stop(server);
break;
}
if (sig_req_reload) {
log_server_info("Reloading configuration...\n");
sig_req_reload = 0;
int cf_ret = conf_open(config_fn);
switch (cf_ret) {
case KNOT_EOK:
log_server_info("Configuration "
"reloaded.\n");
break;
case KNOT_ENOENT:
log_server_error("Configuration "
"file '%s' "
"not found.\n",
conf()->filename);
break;
default:
log_server_error("Configuration "
"reload failed.\n");
break;
}
}
if (zone == NULL) sig_integrity_check = 0;
if (sig_integrity_check) {
log_server_info("Starting integrity check of zone: %s\n", zone);
knot_dname_t* zdn = knot_dname_new_from_str(zone, strlen(zone), NULL);
assert(zdn);
knot_zone_t *z = knot_zonedb_find_zone(server->nameserver->zone_db, zdn);
int ic_ret = knot_zone_contents_integrity_check(z->contents);
log_server_info("Integrity check: %d errors discovered.\n", ic_ret);
knot_dname_free(&zdn);
log_server_info("Integrity check %d finished.\n", check_iteration);
++check_iteration;
}
/* Events. */
if (ret > 0) {
event_t ev;
if (evqueue_get(evq, &ev) == 0) {
dbg_server_verb("Event: "
"received new event.\n");
if (ev.cb) {
ev.cb(&ev);
}
}
}
}
pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
evqueue_free(&evq);
if ((res = server_wait(server)) != KNOT_EOK) {
log_server_error("An error occured while "
"waiting for server to finish.\n");
} else {
log_server_info("Server finished.\n");
}
} else {
log_server_fatal("An error occured while "
"starting the server.\n");
}
// Stop server and close log
server_destroy(&server);
// Remove PID file
if (pid_remove(pidfile) < 0) {
log_server_warning("Failed to remove PID file.\n");
}
log_server_info("Shut down.\n");
log_close();
free(pidfile);
// Free default config filename if exists
free(zone);
free(config_fn);
if (!daemonize) {
fflush(stdout);
fflush(stderr);
}
return res;
}
#ifndef XFR_TESTS_H
#define XFR_TESTS_H
class xfr_tests
{
public:
xfr_tests();
};
#endif // XFR_TESTS_H
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment